Merge branch 'master' into features/menubutton

This commit is contained in:
Uwe Rathmann 2023-06-20 09:38:15 +02:00
commit ee7896e2d4
67 changed files with 1975 additions and 450 deletions

View File

@ -168,6 +168,7 @@ namespace
: ButtonBox( Qt::Horizontal, parent ) : ButtonBox( Qt::Horizontal, parent )
{ {
auto radioBox1 = new QskRadioBox( { "One", "Two", "Three" }, this ); auto radioBox1 = new QskRadioBox( { "One", "Two", "Three" }, this );
radioBox1->setSelectedIndex( 0 );
radioBox1->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed ); radioBox1->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
auto radioBox2 = new QskRadioBox( { "One", "Two", "Three" }, this ); auto radioBox2 = new QskRadioBox( { "One", "Two", "Three" }, this );

View File

@ -37,7 +37,7 @@ namespace
, m_type( type ) , m_type( type )
{ {
setShape( 10 ); setShape( 10 );
initSizePolicy( QskSizePolicy::Ignored, QskSizePolicy::Ignored ); initSizePolicy( QskSizePolicy::Preferred, QskSizePolicy::Fixed );
const int index = metaObject()->indexOfEnumerator( "ButtonType" ); const int index = metaObject()->indexOfEnumerator( "ButtonType" );
setText( metaObject()->enumerator( index ).key( m_type ) ); setText( metaObject()->enumerator( index ).key( m_type ) );
@ -84,6 +84,8 @@ DialogPage::DialogPage( QQuickItem* parent )
: Page( Qt::Horizontal, parent ) : Page( Qt::Horizontal, parent )
{ {
auto box = new QskLinearBox( Qt::Horizontal, 2, this ); auto box = new QskLinearBox( Qt::Horizontal, 2, this );
box->setSpacing( 20 );
box->setExtraSpacingAt( Qt::BottomEdge );
for ( int i = 0; i < Button::TypeCount; i++ ) for ( int i = 0; i < Button::TypeCount; i++ )
new Button( static_cast< Button::ButtonType >( i ), box ); new Button( static_cast< Button::ButtonType >( i ), box );

View File

@ -71,7 +71,7 @@ int main( int argc, char* argv[] )
qskSkinManager->setPluginPaths( QStringList() ); // no plugins qskSkinManager->setPluginPaths( QStringList() ); // no plugins
qskSkinManager->unregisterFactory( "material3factory" ); qskSkinManager->unregisterFactory( "material3factory" );
qskSkinManager->unregisterFactory( "squiekfactory" ); qskSkinManager->unregisterFactory( "squiekfactory" );
qskSkinManager->unregisterFactory( "windowsfactory" ); qskSkinManager->unregisterFactory( "fluent2factory" );
qskSkinManager->registerFactory( qskSkinManager->registerFactory(
QStringLiteral( "SampleSkinFactory" ), new SkinFactory() ); QStringLiteral( "SampleSkinFactory" ), new SkinFactory() );

View File

@ -184,7 +184,6 @@ namespace
QPainter painter( &identifier ); QPainter painter( &identifier );
painter.setPen( QPen( QskRgb::toTransparent( Qt::black, 100 ), 1 ) ); painter.setPen( QPen( QskRgb::toTransparent( Qt::black, 100 ), 1 ) );
painter.setBrush( gradient.toQGradient() );
QLinearGradient qGradient; QLinearGradient qGradient;
qGradient.setStops( qskToQGradientStops( gradient.stops() ) ); qGradient.setStops( qskToQGradientStops( gradient.stops() ) );

View File

@ -30,6 +30,31 @@
namespace namespace
{ {
QConicalGradient qskQConicalGradient(
const QskGradientStops& stops, qreal startAngle, qreal spanAngle )
{
QskGradientStops scaledStops;
scaledStops.reserve( stops.size() );
const auto ratio = qAbs( spanAngle ) / 360.0;
if ( spanAngle > 0.0 )
{
for ( auto it = stops.cbegin(); it != stops.cend(); ++it )
scaledStops += { ratio * it->position(), it->color() };
}
else
{
for ( auto it = stops.crbegin(); it != stops.crend(); ++it )
scaledStops += { 1.0 - ratio * it->position(), it->color() };
}
QConicalGradient qGradient( QPointF(), startAngle );
qGradient.setStops( qskToQGradientStops( scaledStops ) );
return qGradient;
}
class PaintedArcNode : public QskPaintedNode class PaintedArcNode : public QskPaintedNode
{ {
public: public:
@ -98,26 +123,8 @@ namespace
QBrush PaintedArcNode::fillBrush( const QskGradient& gradient, QBrush PaintedArcNode::fillBrush( const QskGradient& gradient,
const QRectF& rect, qreal startAngle, qreal spanAngle ) const const QRectF& rect, qreal startAngle, qreal spanAngle ) const
{ {
const auto stops = gradient.stops(); const auto qGradient = qskQConicalGradient(
gradient.stops(), startAngle, spanAngle );
QskGradientStops scaledStops;
scaledStops.reserve( gradient.stops().size() );
const auto ratio = qAbs( spanAngle ) / 360.0;
if ( spanAngle > 0.0 )
{
for ( auto it = stops.cbegin(); it != stops.cend(); ++it )
scaledStops += { ratio* it->position(), it->color() };
}
else
{
for ( auto it = stops.crbegin(); it != stops.crend(); ++it )
scaledStops += { 1.0 - ratio * it->position(), it->color() };
}
QConicalGradient qGradient( QPointF(), startAngle );
qGradient.setStops( qskToQGradientStops( scaledStops ) );
const qreal sz = qMax( rect.width(), rect.height() ); const qreal sz = qMax( rect.width(), rect.height() );
const qreal sx = rect.width() / sz; const qreal sx = rect.width() / sz;
@ -332,15 +339,6 @@ QSGNode* CircularChartSkinlet::updateArcSegmentNode(
QSGNode* node, qreal borderWidth, const QColor& borderColor, QSGNode* node, qreal borderWidth, const QColor& borderColor,
const QskGradient& gradient, const QskArcMetrics& metrics ) const const QskGradient& gradient, const QskArcMetrics& metrics ) const
{ {
auto fillGradient = gradient;
if ( fillGradient.type() == QskGradient::Stops )
{
fillGradient.setStretchMode( QskGradient::StretchToSize );
fillGradient.setConicDirection( 0.5, 0.5,
metrics.startAngle(), metrics.spanAngle() );
}
#if PAINTED_NODE #if PAINTED_NODE
auto arcNode = static_cast< PaintedArcNode* >( node ); auto arcNode = static_cast< PaintedArcNode* >( node );
if ( arcNode == nullptr ) if ( arcNode == nullptr )
@ -349,10 +347,19 @@ QSGNode* CircularChartSkinlet::updateArcSegmentNode(
const auto chart = static_cast< const CircularChart* >( skinnable ); const auto chart = static_cast< const CircularChart* >( skinnable );
arcNode->setArcData( m_data->closedArcRect, metrics, arcNode->setArcData( m_data->closedArcRect, metrics,
borderWidth, borderColor, fillGradient, chart->window() ); borderWidth, borderColor, gradient, chart->window() );
#else #else
Q_UNUSED( skinnable ) Q_UNUSED( skinnable )
auto fillGradient = gradient;
if ( fillGradient.type() == QskGradient::Stops )
{
fillGradient.setStretchMode( QskGradient::StretchToSize );
fillGradient.setConicDirection( 0.5, 0.5,
metrics.startAngle(), metrics.spanAngle() );
}
auto arcNode = static_cast< QskArcNode* >( node ); auto arcNode = static_cast< QskArcNode* >( node );
if ( arcNode == nullptr ) if ( arcNode == nullptr )
arcNode = new QskArcNode(); arcNode = new QskArcNode();

View File

@ -79,6 +79,7 @@ void StackedChart::setSeries( const QVector< ChartSample >& samples )
{ {
// caching the cumulated values // caching the cumulated values
m_data->cumulatedValues.clear();
m_data->cumulatedValues.reserve( samples.size() ); m_data->cumulatedValues.reserve( samples.size() );
qreal total = 0.0; qreal total = 0.0;

View File

@ -11,73 +11,14 @@
#include <QskBoxShapeMetrics.h> #include <QskBoxShapeMetrics.h>
#include <QskTextColors.h> #include <QskTextColors.h>
#include <QskTextOptions.h> #include <QskTextOptions.h>
#include <QskLinesNode.h>
#include <QskFunctions.h> #include <QskFunctions.h>
#include <QskSGNode.h>
#include <QFontMetrics> #include <QFontMetrics>
#include <QLineF> #include <QLineF>
#include <QSGFlatColorMaterial>
#include <QSGGeometryNode>
#include <QtMath> #include <QtMath>
namespace
{
class LinesNode : public QSGGeometryNode
{
public:
LinesNode( int lineCount = 0 )
: m_geometry( QSGGeometry::defaultAttributes_Point2D(), 2 * lineCount )
{
m_geometry.setDrawingMode( QSGGeometry::DrawLines );
m_geometry.setVertexDataPattern( QSGGeometry::StaticPattern );
setGeometry( &m_geometry );
setMaterial( &m_material );
}
void setColor( const QColor& color )
{
if ( color != m_material.color() )
{
m_material.setColor( color );
markDirty( QSGNode::DirtyMaterial );
}
}
private:
QSGFlatColorMaterial m_material;
QSGGeometry m_geometry;
};
class TicksNode : public LinesNode
{
public:
TicksNode()
{
}
};
class NeedleNode : public LinesNode
{
public:
NeedleNode()
: LinesNode( 1 )
{
}
void setData( const QLineF& line, qreal width )
{
auto vertexData = geometry()->vertexDataAsPoint2D();
vertexData[ 0 ].set( line.x1(), line.y1() );
vertexData[ 1 ].set( line.x2(), line.y2() );
geometry()->setLineWidth( width );
geometry()->markVertexDataDirty();
markDirty( QSGNode::DirtyGeometry );
}
};
}
DialSkinlet::DialSkinlet( QskSkin* skin ) DialSkinlet::DialSkinlet( QskSkin* skin )
: QskSkinlet( skin ) : QskSkinlet( skin )
{ {
@ -141,22 +82,14 @@ QSGNode* DialSkinlet::updateLabelsNode(
if ( labels.count() <= 1 ) if ( labels.count() <= 1 )
return nullptr; return nullptr;
auto ticksNode = static_cast< TicksNode* >( node ); auto ticksNode = QskSGNode::ensureNode< QskLinesNode >( node );
if ( ticksNode == nullptr )
ticksNode = new TicksNode();
const auto color = dial->color( Q::TickLabels ); const auto color = dial->color( Q::TickLabels );
ticksNode->setColor( color );
const auto startAngle = dial->minimum(); const auto startAngle = dial->minimum();
const auto endAngle = dial->maximum(); const auto endAngle = dial->maximum();
const auto step = ( endAngle - startAngle ) / ( labels.count() - 1 ); const auto step = ( endAngle - startAngle ) / ( labels.count() - 1 );
auto geometry = ticksNode->geometry();
geometry->allocate( labels.count() * 2 );
auto vertexData = geometry->vertexDataAsPoint2D();
auto scaleRect = this->scaleRect( dial ); auto scaleRect = this->scaleRect( dial );
const auto center = scaleRect.center(); const auto center = scaleRect.center();
@ -175,6 +108,7 @@ QSGNode* DialSkinlet::updateLabelsNode(
// Create a series of tickmarks from minimum to maximum // Create a series of tickmarks from minimum to maximum
auto labelNode = ticksNode->firstChild(); auto labelNode = ticksNode->firstChild();
QVector< QLineF > ticks;
for ( int i = 0; i < labels.count(); ++i, angle += step ) for ( int i = 0; i < labels.count(); ++i, angle += step )
{ {
@ -187,10 +121,7 @@ QSGNode* DialSkinlet::updateLabelsNode(
const auto xEnd = center.x() + needleRadius * cos; const auto xEnd = center.x() + needleRadius * cos;
const auto yEnd = center.y() + needleRadius * sin; const auto yEnd = center.y() + needleRadius * sin;
vertexData[ 0 ].set( xStart, yStart ); ticks += QLineF( xStart, yStart, xEnd, yEnd );
vertexData[ 1 ].set( xEnd, yEnd );
vertexData += 2;
const auto& text = labels.at( i ); const auto& text = labels.at( i );
@ -220,10 +151,7 @@ QSGNode* DialSkinlet::updateLabelsNode(
} }
} }
geometry->setLineWidth( tickSize.width() ); ticksNode->updateLines( color, tickSize.width(), ticks );
geometry->markVertexDataDirty();
ticksNode->markDirty( QSGNode::DirtyGeometry );
return ticksNode; return ticksNode;
} }
@ -233,15 +161,13 @@ QSGNode* DialSkinlet::updateNeedleNode(
{ {
using Q = Dial; using Q = Dial;
auto needleNode = static_cast< NeedleNode* >( node ); const auto color = dial->color( Q::Needle );
if ( needleNode == nullptr )
needleNode = new NeedleNode();
const auto line = needlePoints( dial );
const auto width = dial->metric( Q::Needle | QskAspect::Size ); const auto width = dial->metric( Q::Needle | QskAspect::Size );
needleNode->setData( line, width * 2 ); const auto line = needlePoints( dial );
needleNode->setColor( dial->color( Q::Needle ) );
auto needleNode = QskSGNode::ensureNode< QskLinesNode >( node );
needleNode->updateLine( color, width * 2, line.p1(), line.p2() );
return needleNode; return needleNode;
} }

View File

@ -1,3 +1,3 @@
add_subdirectory(squiek) add_subdirectory(squiek)
add_subdirectory(material3) add_subdirectory(material3)
add_subdirectory(windows) add_subdirectory(fluent2)

View File

@ -0,0 +1,13 @@
############################################################################
# QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
# SPDX-License-Identifier: BSD-3-Clause
############################################################################
set(SOURCES
QskFluent2Global.h QskFluent2Skin.h QskFluent2Skin.cpp
QskFluent2SkinFactory.h QskFluent2SkinFactory.cpp
)
qt_add_resources(SOURCES icons.qrc)
qsk_add_plugin(fluent2skin skins QskFluent2SkinFactory ${SOURCES})
set_target_properties(fluent2skin PROPERTIES DEFINE_SYMBOL QSK_FLUENT2_MAKEDLL )

View File

@ -1,25 +1,25 @@
/****************************************************************************** /******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/ *****************************************************************************/
#ifndef QSK_WINDOWS_GLOBAL_H #ifndef QSK_FLUENT2_GLOBAL_H
#define QSK_WINDOWS_GLOBAL_H #define QSK_FLUENT2_GLOBAL_H
#include "QskGlobal.h" #include "QskGlobal.h"
#ifdef QSK_DLL #ifdef QSK_DLL
#if defined( QSK_WINDOWS_MAKEDLL ) // create a DLL library #if defined( QSK_FLUENT2_MAKEDLL ) // create a DLL library
#define QSK_WINDOWS_EXPORT Q_DECL_EXPORT #define QSK_FLUENT2_EXPORT Q_DECL_EXPORT
#else // use a DLL library #else // use a DLL library
#define QSK_WINDOWS_EXPORT Q_DECL_IMPORT #define QSK_FLUENT2_EXPORT Q_DECL_IMPORT
#endif #endif
#endif // QSK_DLL #endif // QSK_DLL
#ifndef QSK_WINDOWS_EXPORT #ifndef QSK_FLUENT2_EXPORT
#define QSK_WINDOWS_EXPORT #define QSK_FLUENT2_EXPORT
#endif #endif
#endif #endif

View File

@ -1,9 +1,9 @@
/****************************************************************************** /******************************************************************************
* QSkinny - Copyright (C) 2022 Edelhirsch Software GmbH * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/ *****************************************************************************/
#include "QskWindowsSkin.h" #include "QskFluent2Skin.h"
#include <QskSkinHintTableEditor.h> #include <QskSkinHintTableEditor.h>
@ -54,14 +54,18 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QScreen> #include <QScreen>
static const int qskDuration = 150;
namespace namespace
{ {
inline QRgb flattenedColor( QRgb foregroundColor, QRgb backgroundColor )
{
const qreal alphaRatio = ( ( foregroundColor & QskRgb::AlphaMask ) >> 24 ) / 255.0;
return QskRgb::interpolated( backgroundColor, foregroundColor, alphaRatio );
}
class Editor : private QskSkinHintTableEditor class Editor : private QskSkinHintTableEditor
{ {
public: public:
Editor( QskSkinHintTable* table, const QskWindowsTheme& palette ) Editor( QskSkinHintTable* table, const QskFluent2Theme& palette )
: QskSkinHintTableEditor( table ) : QskSkinHintTableEditor( table )
, theme( palette ) , theme( palette )
{ {
@ -99,13 +103,21 @@ namespace
QskGraphic symbol( const char* name ) const QskGraphic symbol( const char* name ) const
{ {
const QString path = QStringLiteral( ":windows/icons/qvg/" ) const QString path = QStringLiteral( ":fluent2/icons/qvg/" )
+ name + QStringLiteral( ".qvg" ); + name + QStringLiteral( ".qvg" );
return QskGraphicIO::read( path ); return QskGraphicIO::read( path );
} }
const QskWindowsTheme& theme; void setBoxBorderGradient( QskAspect aspect, QskFluent2Theme::BorderGradient gradient, QRgb baseColor )
{
const QRgb leftTopRightColor = flattenedColor( gradient[ 0 ], baseColor );
const QRgb bottomColor = flattenedColor( gradient[ 1 ], baseColor );
setBoxBorderColors( aspect, { leftTopRightColor, leftTopRightColor, leftTopRightColor, bottomColor } );
}
const QskFluent2Theme& theme;
}; };
QFont createFont( const QString& name, qreal lineHeight, QFont createFont( const QString& name, qreal lineHeight,
@ -121,12 +133,6 @@ namespace
return font; return font;
} }
inline QRgb flattenedColor( QRgb foregroundColor, QRgb backgroundColor )
{
const qreal alphaRatio = ( ( foregroundColor & QskRgb::AlphaMask ) >> 24 ) / 255.0;
return QskRgb::interpolated( backgroundColor, foregroundColor, alphaRatio );
}
} }
void Editor::setup() void Editor::setup()
@ -189,9 +195,9 @@ void Editor::setupCheckBox()
const auto checkMark = symbol( "checkmark" ); const auto checkMark = symbol( "checkmark" );
setSymbol( Q::Indicator | Q::Checked, checkMark, { QskStateCombination::CombinationNoState, Q::Disabled } ); setSymbol( Q::Indicator | Q::Checked, checkMark, { QskStateCombination::CombinationNoState, Q::Disabled } );
setGraphicRole( Q::Indicator, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary ); setGraphicRole( Q::Indicator, QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary );
setFontRole( Q::Text, QskWindowsSkin::Body ); setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary ); setColor( Q::Text, theme.palette.fillColor.text.primary );
@ -205,26 +211,89 @@ void Editor::setupCheckBox()
setBoxBorderColors( Q::Box | Q::Pressed, theme.palette.strokeColor.controlStrongStroke.disabled ); setBoxBorderColors( Q::Box | Q::Pressed, theme.palette.strokeColor.controlStrongStroke.disabled );
setGradient( Q::Box | Q::Pressed | Q::Checked, theme.palette.fillColor.accent.tertiary ); setGradient( Q::Box | Q::Pressed | Q::Checked, theme.palette.fillColor.accent.tertiary );
setBoxBorderColors( Q::Box | Q::Pressed | Q::Checked, theme.palette.fillColor.accent.tertiary ); setBoxBorderColors( Q::Box | Q::Pressed | Q::Checked, theme.palette.fillColor.accent.tertiary );
setGraphicRole( Q::Indicator | Q::Pressed | Q::Checked, QskWindowsSkin::GraphicRoleFillColorTextOnAccentSecondary ); setGraphicRole( Q::Indicator | Q::Pressed | Q::Checked, QskFluent2Skin::GraphicRoleFillColorTextOnAccentSecondary );
setGradient( Q::Box | Q::Disabled, theme.palette.fillColor.controlAlt.disabled ); setGradient( Q::Box | Q::Disabled, theme.palette.fillColor.controlAlt.disabled );
setBoxBorderColors( Q::Box | Q::Disabled, theme.palette.strokeColor.controlStrongStroke.disabled ); setBoxBorderColors( Q::Box | Q::Disabled, theme.palette.strokeColor.controlStrongStroke.disabled );
setGradient( Q::Box | Q::Disabled | Q::Checked, theme.palette.fillColor.accent.disabled ); setGradient( Q::Box | Q::Disabled | Q::Checked, theme.palette.fillColor.accent.disabled );
setBoxBorderColors( Q::Box | Q::Disabled | Q::Checked, theme.palette.fillColor.accent.disabled ); setBoxBorderColors( Q::Box | Q::Disabled | Q::Checked, theme.palette.fillColor.accent.disabled );
setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked, QskWindowsSkin::GraphicRoleFillColorTextOnAccentDisabled ); setGraphicRole( Q::Indicator | Q::Disabled | Q::Checked, QskFluent2Skin::GraphicRoleFillColorTextOnAccentDisabled );
setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled );
} }
void Editor::setupComboBox() void Editor::setupComboBox()
{ {
using Q = QskComboBox;
setStrutSize( Q::Panel, { -1, 32 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxShape( Q::Panel, 3 );
setPadding( Q::Panel, { 11, 0, 11, 0 } );
setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor );
setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border,
theme.palette.fillColor.control.defaultColor );
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 0, 0, 8, 0 } );
setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary );
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary );
setStrutSize( Q::StatusIndicator, 12, 12 );
setSymbol( Q::StatusIndicator, symbol( "spin-box-arrow-down" ) );
setSymbol( Q::StatusIndicator | Q::PopupOpen, symbol( "spin-box-arrow-up" ) );
setGraphicRole( Q::StatusIndicator, QskFluent2Skin::GraphicRoleFillColorTextSecondary );
// Hovered:
setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary );
setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.textControl.border,
theme.palette.fillColor.control.secondary );
// Focused (Pressed doesn't exist yet):
setBoxBorderMetrics( Q::Panel | Q::Focused, { 1, 1, 1, 2 } );
setGradient( Q::Panel | Q::Focused, theme.palette.fillColor.control.inputActive );
auto gradient = theme.palette.elevation.textControl.border;
gradient.at( 1 ) = theme.palette.fillColor.accent.defaultColor;
setBoxBorderGradient( Q::Panel | Q::Focused, gradient, theme.palette.fillColor.control.inputActive );
// Disabled:
setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled );
setBoxBorderColors( Q::Panel | Q::Disabled, theme.palette.strokeColor.controlStroke.defaultColor );
setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled );
setGraphicRole( Q::Icon | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled );
setGraphicRole( Q::StatusIndicator | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled );
} }
void Editor::setupDialogButtonBox() void Editor::setupDialogButtonBox()
{ {
using Q = QskDialogButtonBox;
setPadding( Q::Panel, 24 );
setGradient( Q::Panel, theme.palette.background.fillColor.solidBackground.base );
setPadding(Q::Panel, 20 );
} }
void Editor::setupFocusIndicator() void Editor::setupFocusIndicator()
{ {
using Q = QskFocusIndicator;
setBoxBorderMetrics( Q::Panel, 2 );
setPadding( Q::Panel, 3 );
setBoxShape( Q::Panel, 4 );
setBoxBorderColors( Q::Panel, theme.palette.strokeColor.focusStroke.outer );
} }
void Editor::setupInputPanel() void Editor::setupInputPanel()
@ -239,7 +308,7 @@ void Editor::setupMenu()
{ {
using Q = QskMenu; using Q = QskMenu;
setPadding( Q::Panel, { 16, 6, 16, 6 } ); setPadding( Q::Panel, { 4, 6, 4, 6 } );
setBoxBorderMetrics( Q::Panel, 1 ); setBoxBorderMetrics( Q::Panel, 1 );
setBoxBorderColors( Q::Panel, theme.palette.strokeColor.surfaceStroke.flyout ); setBoxBorderColors( Q::Panel, theme.palette.strokeColor.surfaceStroke.flyout );
setBoxShape( Q::Panel, 7 ); setBoxShape( Q::Panel, 7 );
@ -250,8 +319,23 @@ void Editor::setupMenu()
setPadding( Q::Segment, { 0, 10, 0, 10 } ); setPadding( Q::Segment, { 0, 10, 0, 10 } );
setSpacing( Q::Segment, 15 ); setSpacing( Q::Segment, 15 );
setFontRole( Q::Text, QskWindowsSkin::Body ); setGradient( Q::Segment | Q::Selected, theme.palette.fillColor.subtle.secondary );
setBoxBorderMetrics( Q::Segment | Q::Selected, { 3, 0, 0, 0 } );
QskGradient selectedGradient( { { 0.0, theme.palette.fillColor.subtle.secondary },
{ 0.25, theme.palette.fillColor.subtle.secondary },
{ 0.25, theme.palette.fillColor.accent.defaultColor },
{ 0.75, theme.palette.fillColor.accent.defaultColor },
{ 0.75, theme.palette.fillColor.subtle.secondary },
{ 1.0, theme.palette.fillColor.subtle.secondary } } );
setBoxBorderColors( Q::Segment | Q::Selected, selectedGradient );
setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary ); setColor( Q::Text, theme.palette.fillColor.text.primary );
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 8, 8, 0, 8 } );
setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary );
} }
void Editor::setupPageIndicator() void Editor::setupPageIndicator()
@ -260,60 +344,62 @@ void Editor::setupPageIndicator()
void Editor::setupPopup() void Editor::setupPopup()
{ {
using Q = QskPopup;
setGradient( Q::Overlay, theme.palette.background.fillColor.smoke.defaultColor );
} }
void Editor::setupProgressBar() void Editor::setupProgressBar()
{ {
using Q = QskProgressBar;
using A = QskAspect;
setMetric( Q::Groove | A::Size, 1 );
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
setGradient( Q::Groove, theme.palette.strokeColor.controlStrongStroke.defaultColor );
setMetric( Q::Bar| A::Size, 3 );
setBoxShape( Q::Bar, 100, Qt::RelativeSize );
setGradient( Q::Bar, theme.palette.fillColor.accent.defaultColor );
} }
void Editor::setupPushButton() void Editor::setupPushButton()
{ {
using Q = QskPushButton; using Q = QskPushButton;
using W = QskWindowsSkin; using W = QskFluent2Skin;
setStrutSize( Q::Panel, { 120, 32 } ); setStrutSize( Q::Panel, { 120, 32 } );
setBoxShape( Q::Panel, 4 ); setBoxShape( Q::Panel, 4 );
setBoxBorderMetrics( Q::Panel, 1 ); setBoxBorderMetrics( Q::Panel, 1 );
// Windows buttons don't really have icons, // Fluent buttons don't really have icons,
// but for the sake of compatibility with the // but for the sake of compatibility with the
// gallery app, let's define their style here as well: // gallery app, let's define their style here as well:
setStrutSize( Q::Icon, 12, 12 ); setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 0, 0, 8, 0 } ); setPadding( Q::Icon, { 0, 0, 8, 0 } );
setFontRole( Q::Text, QskWindowsSkin::Body ); setFontRole( Q::Text, QskFluent2Skin::Body );
// Accent buttons: // Accent buttons:
const QRgb accentRestBorderColor1 = flattenedColor( theme.palette.elevation.accentControl.border[ 0 ], setBoxBorderGradient( Q::Panel | W::Accent, theme.palette.elevation.accentControl.border,
theme.palette.fillColor.accent.defaultColor ); theme.palette.fillColor.accent.defaultColor );
const QRgb accentRestBorderColor2 = flattenedColor( theme.palette.elevation.accentControl.border[ 1 ],
theme.palette.fillColor.accent.defaultColor );
setBoxBorderColors( Q::Panel | W::Accent, { accentRestBorderColor1, accentRestBorderColor1,
accentRestBorderColor1, accentRestBorderColor2 } );
setGradient( Q::Panel | W::Accent, theme.palette.fillColor.accent.defaultColor ); setGradient( Q::Panel | W::Accent, theme.palette.fillColor.accent.defaultColor );
setColor( Q::Text | W::Accent, theme.palette.fillColor.textOnAccent.primary ); setColor( Q::Text | W::Accent, theme.palette.fillColor.textOnAccent.primary );
setGraphicRole( Q::Icon | W::Accent, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary ); setGraphicRole( Q::Icon | W::Accent, QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary );
const QRgb accentHoveredBorderColor1 = flattenedColor( theme.palette.elevation.accentControl.border[ 0 ], setBoxBorderGradient( Q::Panel | W::Accent | Q::Hovered, theme.palette.elevation.accentControl.border,
theme.palette.fillColor.accent.secondary ); theme.palette.fillColor.accent.secondary );
const QRgb accentHoveredBorderColor2 = flattenedColor( theme.palette.elevation.accentControl.border[ 1 ],
theme.palette.fillColor.accent.secondary );
setBoxBorderColors( Q::Panel | W::Accent | Q::Hovered, { accentHoveredBorderColor1, accentHoveredBorderColor1,
accentHoveredBorderColor1, accentHoveredBorderColor2 } );
setGradient( Q::Panel | W::Accent | Q::Hovered, theme.palette.fillColor.accent.secondary ); setGradient( Q::Panel | W::Accent | Q::Hovered, theme.palette.fillColor.accent.secondary );
setGradient( Q::Panel | W::Accent | Q::Pressed, theme.palette.fillColor.accent.tertiary ); setGradient( Q::Panel | W::Accent | Q::Pressed, theme.palette.fillColor.accent.tertiary );
setColor( Q::Text | W::Accent | Q::Pressed, theme.palette.fillColor.textOnAccent.secondary ); setColor( Q::Text | W::Accent | Q::Pressed, theme.palette.fillColor.textOnAccent.secondary );
setGraphicRole( Q::Icon | W::Accent | Q::Pressed, QskWindowsSkin::GraphicRoleFillColorTextOnAccentSecondary ); setGraphicRole( Q::Icon | W::Accent | Q::Pressed, QskFluent2Skin::GraphicRoleFillColorTextOnAccentSecondary );
const QRgb accentPressedBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.onAccentDefault, const QRgb accentPressedBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.onAccentDefault,
theme.palette.fillColor.accent.tertiary ); theme.palette.fillColor.accent.tertiary );
@ -323,34 +409,24 @@ void Editor::setupPushButton()
setGradient( Q::Panel | W::Accent | Q::Disabled, theme.palette.fillColor.accent.disabled ); setGradient( Q::Panel | W::Accent | Q::Disabled, theme.palette.fillColor.accent.disabled );
setColor( Q::Text | W::Accent | Q::Disabled, theme.palette.fillColor.textOnAccent.disabled ); setColor( Q::Text | W::Accent | Q::Disabled, theme.palette.fillColor.textOnAccent.disabled );
setGraphicRole( Q::Icon | W::Accent | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextOnAccentDisabled ); setGraphicRole( Q::Icon | W::Accent | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextOnAccentDisabled );
setBoxBorderMetrics( Q::Panel | W::Accent | Q::Disabled, 0 ); setBoxBorderMetrics( Q::Panel | W::Accent | Q::Disabled, 0 );
// Standard buttons: // Standard buttons:
const QRgb standardRestBorderColor1 = flattenedColor( theme.palette.elevation.control.border[ 0 ], setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border,
theme.palette.fillColor.control.defaultColor ); theme.palette.fillColor.control.defaultColor );
const QRgb standardRestBorderColor2 = flattenedColor( theme.palette.elevation.control.border[ 1 ],
theme.palette.fillColor.control.defaultColor );
setBoxBorderColors( Q::Panel, { standardRestBorderColor1, standardRestBorderColor1,
standardRestBorderColor1, standardRestBorderColor2 } );
setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor ); setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor );
setColor( Q::Text, theme.palette.fillColor.text.primary ); setColor( Q::Text, theme.palette.fillColor.text.primary );
setGraphicRole( Q::Icon, QskWindowsSkin::GraphicRoleFillColorTextPrimary ); setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary );
const QRgb standardHoveredBorderColor1 = flattenedColor( theme.palette.elevation.control.border[ 0 ], setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.control.border,
theme.palette.fillColor.control.secondary ); theme.palette.fillColor.control.secondary );
const QRgb standardHoveredBorderColor2 = flattenedColor( theme.palette.elevation.control.border[ 1 ],
theme.palette.fillColor.control.secondary );
setBoxBorderColors( Q::Panel | Q::Hovered, { standardHoveredBorderColor1, standardHoveredBorderColor1,
standardHoveredBorderColor1, standardHoveredBorderColor2 } );
setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary ); setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary );
@ -362,7 +438,7 @@ void Editor::setupPushButton()
setGradient( Q::Panel | Q::Pressed, theme.palette.fillColor.control.tertiary ); setGradient( Q::Panel | Q::Pressed, theme.palette.fillColor.control.tertiary );
setColor( Q::Text | Q::Pressed, theme.palette.fillColor.text.secondary ); setColor( Q::Text | Q::Pressed, theme.palette.fillColor.text.secondary );
setGraphicRole( Q::Icon | Q::Pressed, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); setGraphicRole( Q::Icon | Q::Pressed, QskFluent2Skin::GraphicRoleFillColorTextSecondary );
const QRgb standardDisabledBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.defaultColor, const QRgb standardDisabledBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.defaultColor,
@ -372,7 +448,7 @@ void Editor::setupPushButton()
setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled ); setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled );
setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled ); setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled );
setGraphicRole( Q::Icon | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); setGraphicRole( Q::Icon | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled );
} }
void Editor::setupRadioBox() void Editor::setupRadioBox()
@ -385,7 +461,7 @@ void Editor::setupRadioBox()
setStrutSize( Q::CheckIndicatorPanel, { 20, 20 } ); setStrutSize( Q::CheckIndicatorPanel, { 20, 20 } );
setBoxShape( Q::CheckIndicatorPanel, 100, Qt::RelativeSize ); setBoxShape( Q::CheckIndicatorPanel, 100, Qt::RelativeSize );
setBoxBorderMetrics( Q::CheckIndicatorPanel, 1 ); setBoxBorderMetrics( Q::CheckIndicatorPanel, 1 );
setFontRole( Q::Text, QskWindowsSkin::Body ); setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary ); setColor( Q::Text, theme.palette.fillColor.text.primary );
// Rest // Rest
@ -402,14 +478,9 @@ void Editor::setupRadioBox()
setBoxBorderMetrics( Q::CheckIndicator | Q::Selected, 1 ); setBoxBorderMetrics( Q::CheckIndicator | Q::Selected, 1 );
setGradient( Q::CheckIndicator | Q::Selected, theme.palette.fillColor.textOnAccent.primary ); setGradient( Q::CheckIndicator | Q::Selected, theme.palette.fillColor.textOnAccent.primary );
const QRgb panelRestBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], setBoxBorderGradient( Q::CheckIndicator | Q::Selected, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.defaultColor ); theme.palette.fillColor.accent.defaultColor );
const QRgb panelRestBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ],
theme.palette.fillColor.accent.defaultColor );
setBoxBorderColors( Q::CheckIndicator | Q::Selected, { panelRestBorderColor1, panelRestBorderColor1,
panelRestBorderColor1, panelRestBorderColor2 } );
// Hover // Hover
@ -418,14 +489,8 @@ void Editor::setupRadioBox()
setGradient( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, theme.palette.fillColor.accent.secondary ); setGradient( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, theme.palette.fillColor.accent.secondary );
setPadding( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, { 4, 4 } ); // indicator "strut size" setPadding( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, { 4, 4 } ); // indicator "strut size"
const QRgb panelHoveredBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], setBoxBorderGradient( Q::CheckIndicator | Q::Hovered, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.secondary ); theme.palette.fillColor.accent.secondary );
const QRgb panelHoveredBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ],
theme.palette.fillColor.accent.secondary );
setBoxBorderColors( Q::CheckIndicator | Q::Selected, { panelHoveredBorderColor1, panelHoveredBorderColor1,
panelHoveredBorderColor1, panelHoveredBorderColor2 } );
// Pressed // Pressed
@ -444,14 +509,8 @@ void Editor::setupRadioBox()
setPadding( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, { 6, 6 } ); // indicator "strut size" setPadding( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, { 6, 6 } ); // indicator "strut size"
setBoxBorderMetrics( Q::CheckIndicator | Q::Pressed, 1 ); setBoxBorderMetrics( Q::CheckIndicator | Q::Pressed, 1 );
const QRgb panelPressedBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], setBoxBorderGradient( Q::CheckIndicator | Q::Pressed | Q::Selected, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.tertiary ); // ### calculate those colors at skin construction time theme.palette.fillColor.accent.tertiary );
const QRgb panelPressedBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ],
theme.palette.fillColor.accent.tertiary );
setBoxBorderColors( Q::CheckIndicator | Q::Pressed | Q::Selected, { panelPressedBorderColor1, panelPressedBorderColor1,
panelPressedBorderColor1, panelPressedBorderColor2 } );
// Disabled // Disabled
@ -476,6 +535,57 @@ void Editor::setupScrollView()
void Editor::setupSegmentedBar() void Editor::setupSegmentedBar()
{ {
using Q = QskSegmentedBar;
using A = QskAspect;
const QSizeF segmentStrutSize( 120, 32 );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border,
theme.palette.fillColor.control.defaultColor );
setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor );
setSpacing( Q::Panel, 8 );
setStrutSize( Q::Icon, { 12, 12 } );
setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary );
setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary );
setStrutSize( Q::Segment | A::Horizontal, segmentStrutSize );
setStrutSize( Q::Segment | A::Vertical, segmentStrutSize.transposed() );
setBoxShape( Q::Segment , 4 );
setPadding( Q::Segment, { 8, 0, 8, 0 } );
// Hovered:
setGradient( Q::Segment | Q::Hovered, theme.palette.fillColor.control.secondary );
setBoxBorderGradient( Q::Segment | Q::Hovered, theme.palette.elevation.control.border,
theme.palette.fillColor.control.secondary );
// Selected:
setGradient( Q::Segment | Q::Selected, theme.palette.fillColor.accent.defaultColor );
setGraphicRole( Q::Icon | Q::Selected, QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary );
setColor( Q::Text | Q::Selected, theme.palette.fillColor.textOnAccent.primary );
// Disabled:
const QRgb standardDisabledBorderColor = flattenedColor( theme.palette.strokeColor.controlStroke.defaultColor,
theme.palette.fillColor.control.disabled );
setBoxBorderColors( Q::Segment | Q::Disabled, standardDisabledBorderColor );
setGradient( Q::Segment | Q::Disabled, theme.palette.fillColor.control.disabled );
setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled );
setGraphicRole( Q::Icon | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled );
setGradient( Q::Segment | Q::Selected | Q::Disabled, theme.palette.fillColor.accent.disabled );
setColor( Q::Text | Q::Selected | Q::Disabled, theme.palette.fillColor.textOnAccent.disabled );
setGraphicRole( Q::Icon | Q::Selected | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextOnAccentDisabled );
setBoxBorderMetrics( Q::Panel | Q::Selected | Q::Disabled, 0 );
} }
void Editor::setupSeparator() void Editor::setupSeparator()
@ -484,10 +594,107 @@ void Editor::setupSeparator()
void Editor::setupSlider() void Editor::setupSlider()
{ {
using Q = QskSlider;
using A = QskAspect;
const qreal extent = 22;
setMetric( Q::Panel | A::Size, extent );
setBoxShape( Q::Panel, 0 );
setBoxBorderMetrics( Q::Panel, 0 );
setGradient( Q::Panel, {} );
setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) );
setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) );
setMetric( Q::Groove | A::Size, 4 );
setGradient( Q::Groove, theme.palette.fillColor.controlStrong.defaultColor );
setBoxShape( Q::Groove, 100, Qt::RelativeSize );
setMetric( Q::Fill | A::Size, 4 );
setGradient( Q::Fill, theme.palette.fillColor.accent.defaultColor );
setBoxShape( Q::Fill, 100, Qt::RelativeSize );
setStrutSize( Q::Handle, { 22, 22 } );
setGradient( Q::Handle, theme.palette.fillColor.controlSolid.defaultColor );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
setBoxBorderMetrics( Q::Handle, 1 );
setBoxBorderGradient( Q::Handle, theme.palette.elevation.circle.border, theme.palette.fillColor.controlSolid.defaultColor );
setStrutSize( Q::Ripple, { 12, 12 } );
setGradient( Q::Ripple, theme.palette.fillColor.accent.defaultColor );
setBoxShape( Q::Ripple, 100, Qt::RelativeSize );
setStrutSize( Q::Ripple | Q::Hovered, { 14, 14 } );
setStrutSize( Q::Ripple | Q::Pressed, { 10, 10 } );
setGradient( Q::Ripple | Q::Pressed, theme.palette.fillColor.accent.tertiary );
setGradient( Q::Groove | Q::Disabled, theme.palette.fillColor.controlStrong.disabled );
setGradient( Q::Fill | Q::Disabled, theme.palette.fillColor.accent.disabled );
setGradient( Q::Ripple | Q::Disabled, theme.palette.fillColor.controlStrong.disabled );
} }
void Editor::setupSpinBox() void Editor::setupSpinBox()
{ {
using Q = QskSpinBox;
setHint( Q::Panel | QskAspect::Style, Q::ButtonsRight );
setStrutSize( Q::Panel, { -1, 32 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxShape( Q::Panel, 3 );
setPadding( Q::Panel, { 11, 0, 11, 0 } );
setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor );
setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border,
theme.palette.fillColor.control.defaultColor );
setAlignment( Q::Text, Qt::AlignLeft );
setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary );
setPadding( Q::TextPanel, { 11, 5, 0, 0 } );
setStrutSize( Q::UpPanel, 16, 16 );
setStrutSize( Q::DownPanel, 16, 16 );
setStrutSize( Q::UpPanel, 32, 20 );
setPadding( Q::UpPanel, { 11, 7, 11, 7 } );
setStrutSize( Q::DownPanel, 34, 20 );
setPadding( Q::DownPanel, { 11, 7, 13, 7 } );
setSymbol( Q::UpIndicator, symbol( "spin-box-arrow-up" ) );
setSymbol( Q::DownIndicator, symbol( "spin-box-arrow-down" ) );
setGraphicRole( Q::UpIndicator, QskFluent2Skin::GraphicRoleFillColorTextSecondary );
setGraphicRole( Q::DownIndicator, QskFluent2Skin::GraphicRoleFillColorTextSecondary );
// Hovered:
setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary );
setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.textControl.border,
theme.palette.fillColor.control.secondary );
// Focused (Pressed doesn't exist yet):
setBoxBorderMetrics( Q::Panel | Q::Focused, { 1, 1, 1, 2 } );
setGradient( Q::Panel | Q::Focused, theme.palette.fillColor.control.inputActive );
auto gradient = theme.palette.elevation.textControl.border;
gradient.at( 1 ) = theme.palette.fillColor.accent.defaultColor;
setBoxBorderGradient( Q::Panel | Q::Focused, gradient, theme.palette.fillColor.control.inputActive );
// Disabled:
setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled );
setBoxBorderColors( Q::Panel | Q::Disabled, theme.palette.strokeColor.controlStroke.defaultColor );
setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled );
setGraphicRole( Q::UpIndicator | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled );
setGraphicRole( Q::DownIndicator | Q::Disabled, QskFluent2Skin::GraphicRoleFillColorTextDisabled );
} }
void Editor::setupTabBar() void Editor::setupTabBar()
@ -511,10 +718,10 @@ void Editor::setupTabButton()
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter ); setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
setFontRole( Q::Text, QskWindowsSkin::Body ); setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.secondary ); setColor( Q::Text, theme.palette.fillColor.text.secondary );
setFontRole( Q::Text | Q::Checked, QskWindowsSkin::BodyStrong ); setFontRole( Q::Text | Q::Checked, QskFluent2Skin::BodyStrong );
setColor( Q::Text | Q::Checked, theme.palette.fillColor.text.primary ); setColor( Q::Text | Q::Checked, theme.palette.fillColor.text.primary );
setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.subtle.secondary ); setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.subtle.secondary );
@ -535,13 +742,58 @@ void Editor::setupTextLabel()
setPadding( Q::Panel, 10 ); setPadding( Q::Panel, 10 );
setFontRole( Q::Text, QskWindowsSkin::Body ); setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary ); setColor( Q::Text, theme.palette.fillColor.text.primary );
} }
void Editor::setupTextInput() void Editor::setupTextInput()
{ {
using Q = QskTextInput;
setStrutSize( Q::Panel, { -1, 30 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxShape( Q::Panel, 3 );
setPadding( Q::Panel, { 11, 0, 11, 0 } );
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.secondary );
setGradient( Q::Panel, theme.palette.fillColor.control.defaultColor );
setBoxBorderGradient( Q::Panel, theme.palette.elevation.textControl.border,
theme.palette.fillColor.control.defaultColor );
setColor( Q::PanelSelected, theme.palette.fillColor.accent.selectedTextBackground );
setColor( Q::TextSelected, theme.palette.fillColor.textOnAccent.selectedText );
// Hovered:
setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.control.secondary );
setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.textControl.border,
theme.palette.fillColor.control.secondary );
// Pressed & Focused:
for( const auto& state : { Q::Focused, Q::Editing } )
{
setBoxBorderMetrics( Q::Panel | state, { 1, 1, 1, 2 } );
setGradient( Q::Panel | state, theme.palette.fillColor.control.inputActive );
auto gradient = theme.palette.elevation.textControl.border;
gradient.at( 1 ) = theme.palette.fillColor.accent.defaultColor;
setBoxBorderGradient( Q::Panel | state, gradient, theme.palette.fillColor.control.inputActive );
}
// Disabled:
setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.disabled );
setBoxBorderColors( Q::Panel | Q::Disabled, theme.palette.strokeColor.controlStroke.defaultColor );
setColor( Q::Text | Q::Disabled, theme.palette.fillColor.text.disabled );
} }
void Editor::setupSwitchButton() void Editor::setupSwitchButton()
@ -573,14 +825,8 @@ void Editor::setupSwitchButton()
setGradient( Q::Handle, theme.palette.strokeColor.controlStrongStroke.defaultColor ); setGradient( Q::Handle, theme.palette.strokeColor.controlStrongStroke.defaultColor );
setGradient( Q::Handle | Q::Checked, theme.palette.fillColor.textOnAccent.primary ); setGradient( Q::Handle | Q::Checked, theme.palette.fillColor.textOnAccent.primary );
const QRgb handleRestBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], setBoxBorderGradient( Q::Handle | Q::Checked, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.defaultColor ); theme.palette.fillColor.accent.defaultColor );
const QRgb handleRestBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ],
theme.palette.fillColor.accent.defaultColor );
setBoxBorderColors( Q::Handle | Q::Checked, { handleRestBorderColor1, handleRestBorderColor1,
handleRestBorderColor1, handleRestBorderColor2 } );
setGradient( Q::Groove | Q::Hovered, theme.palette.fillColor.controlAlt.tertiary ); setGradient( Q::Groove | Q::Hovered, theme.palette.fillColor.controlAlt.tertiary );
@ -591,14 +837,8 @@ void Editor::setupSwitchButton()
setGradient( Q::Handle | Q::Hovered, theme.palette.fillColor.text.secondary ); setGradient( Q::Handle | Q::Hovered, theme.palette.fillColor.text.secondary );
// Handle | Hovered | Checked is the same as in Rest state // Handle | Hovered | Checked is the same as in Rest state
const QRgb handleHoveredBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], setBoxBorderGradient( Q::Handle | Q::Hovered | Q::Checked, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.secondary ); theme.palette.fillColor.accent.secondary );
const QRgb handleHoveredBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ],
theme.palette.fillColor.accent.secondary );
setBoxBorderColors( Q::Handle | Q::Hovered | Q::Checked, { handleHoveredBorderColor1, handleHoveredBorderColor1,
handleHoveredBorderColor1, handleHoveredBorderColor2 } );
setGradient( Q::Groove | Q::Pressed, theme.palette.fillColor.controlAlt.quaternary ); setGradient( Q::Groove | Q::Pressed, theme.palette.fillColor.controlAlt.quaternary );
@ -611,14 +851,8 @@ void Editor::setupSwitchButton()
setGradient( Q::Handle | Q::Pressed, theme.palette.strokeColor.controlStrongStroke.defaultColor ); setGradient( Q::Handle | Q::Pressed, theme.palette.strokeColor.controlStrongStroke.defaultColor );
// Handle | Pressed | Checked is the same as in Rest state // Handle | Pressed | Checked is the same as in Rest state
const QRgb handlePressedBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ], setBoxBorderGradient( Q::Handle | Q::Pressed | Q::Checked, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.tertiary ); theme.palette.fillColor.accent.tertiary );
const QRgb handlePressedBorderColor2 = flattenedColor( theme.palette.elevation.circle.border[ 1 ],
theme.palette.fillColor.accent.tertiary );
setBoxBorderColors( Q::Handle | Q::Pressed | Q::Checked, { handlePressedBorderColor1, handlePressedBorderColor1,
handlePressedBorderColor1, handlePressedBorderColor2 } );
setGradient( Q::Groove | Q::Disabled, theme.palette.fillColor.controlAlt.disabled ); setGradient( Q::Groove | Q::Disabled, theme.palette.fillColor.controlAlt.disabled );
@ -634,15 +868,46 @@ void Editor::setupSwitchButton()
void Editor::setupSubWindow() void Editor::setupSubWindow()
{ {
using Q = QskSubWindow;
setPadding( Q::Panel, { 0, 31, 0, 0 } );
setBoxShape( Q::Panel, 7 );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxBorderColors( Q::Panel, theme.palette.strokeColor.surfaceStroke.defaultColor );
setGradient( Q::Panel, theme.palette.background.fillColor.layer.alt );
setShadowMetrics( Q::Panel, theme.shadow.dialog.first );
setShadowColor( Q::Panel, theme.shadow.dialog.second );
setHint( Q::TitleBarPanel | QskAspect::Style, Q::TitleBar | Q::Title );
setPadding( Q::TitleBarPanel, { 24, 31, 24, 0 } );
setFontRole( Q::TitleBarText, QskFluent2Skin::Subtitle );
setColor( Q::TitleBarText, theme.palette.fillColor.text.primary );
setAlignment( Q::TitleBarText, Qt::AlignLeft );
setTextOptions( Q::TitleBarText, Qt::ElideRight, QskTextOptions::NoWrap );
} }
void Editor::setupVirtualKeyboard() void Editor::setupVirtualKeyboard()
{ {
using Q = QskVirtualKeyboard;
setMargin( Q::ButtonPanel, 2 );
setGradient( Q::ButtonPanel, theme.palette.fillColor.control.defaultColor );
setGradient( Q::ButtonPanel | Q::Hovered, theme.palette.fillColor.control.secondary );
setGradient( Q::ButtonPanel | QskPushButton::Pressed, theme.palette.fillColor.control.tertiary );
setColor( Q::ButtonText, theme.palette.fillColor.text.primary );
setFontRole( Q::ButtonText, QskFluent2Skin::BodyLarge );
setColor( Q::ButtonText | QskPushButton::Pressed, theme.palette.fillColor.text.secondary );
setGradient( Q::Panel, theme.palette.background.fillColor.solidBackground.secondary );
setPadding( Q::Panel, 8 );
} }
QskWindowsTheme::QskWindowsTheme( Theme lightness ) QskFluent2Theme::QskFluent2Theme( Theme lightness )
: QskWindowsTheme( lightness, : QskFluent2Theme( lightness,
{ // default Windows accent colors: { // default Fluent accent colors:
0xff98ecfe, 0xff98ecfe,
0xff60ccfe, 0xff60ccfe,
0xff0093f9, 0xff0093f9,
@ -654,7 +919,7 @@ QskWindowsTheme::QskWindowsTheme( Theme lightness )
{ {
} }
QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors > accentColors ) QskFluent2Theme::QskFluent2Theme( Theme theme, std::array< QRgb, NumAccentColors > accentColors )
{ {
if( theme == Light ) if( theme == Light )
{ {
@ -727,7 +992,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors
QskRgb::toTransparentF( 0xff000000, 0.1622 ) }; QskRgb::toTransparentF( 0xff000000, 0.1622 ) };
palette.elevation.textControl.border = { QskRgb::toTransparentF( 0xff000000, 0.0578 ), palette.elevation.textControl.border = { QskRgb::toTransparentF( 0xff000000, 0.0578 ),
QskRgb::toTransparentF( 0xff000000, 0.0578 ) }; palette.fillColor.text.secondary };
palette.elevation.textControl.borderFocused = { QskRgb::toTransparentF( 0xff000000, 0.0578 ), palette.elevation.textControl.borderFocused = { QskRgb::toTransparentF( 0xff000000, 0.0578 ),
QskRgb::toTransparentF( 0xff000000, 0.0578 ) }; QskRgb::toTransparentF( 0xff000000, 0.0578 ) };
@ -765,7 +1030,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors
palette.background.fillColor.cardBackground.secondary = QskRgb::toTransparentF( 0xffF6F6F6, 0.50 ); palette.background.fillColor.cardBackground.secondary = QskRgb::toTransparentF( 0xffF6F6F6, 0.50 );
palette.background.fillColor.cardBackground.tertiary = 0xffffffff; palette.background.fillColor.cardBackground.tertiary = 0xffffffff;
palette.background.fillColor.stroke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 ); palette.background.fillColor.smoke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 );
palette.background.fillColor.layer.defaultColor = QskRgb::toTransparentF( 0xffffffff, 0.50 ); palette.background.fillColor.layer.defaultColor = QskRgb::toTransparentF( 0xffffffff, 0.50 );
palette.background.fillColor.layer.alt = 0xffffffff; palette.background.fillColor.layer.alt = 0xffffffff;
@ -868,7 +1133,8 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors
QskRgb::toTransparentF( 0xffffffff, 0.0698 ) }; QskRgb::toTransparentF( 0xffffffff, 0.0698 ) };
palette.elevation.textControl.border = { QskRgb::toTransparentF( 0xffffffff, 0.08 ), palette.elevation.textControl.border = { QskRgb::toTransparentF( 0xffffffff, 0.08 ),
QskRgb::toTransparentF( 0xffffffff, 0.08 ) }; palette.fillColor.text.secondary };
palette.elevation.textControl.borderFocused = { QskRgb::toTransparentF( 0xffffffff, 0.08 ), palette.elevation.textControl.borderFocused = { QskRgb::toTransparentF( 0xffffffff, 0.08 ),
QskRgb::toTransparentF( 0xffffffff, 0.08 ) }; QskRgb::toTransparentF( 0xffffffff, 0.08 ) };
@ -906,7 +1172,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors
palette.background.fillColor.cardBackground.secondary = QskRgb::toTransparentF( 0xffffffff, 0.0326 ); palette.background.fillColor.cardBackground.secondary = QskRgb::toTransparentF( 0xffffffff, 0.0326 );
palette.background.fillColor.cardBackground.tertiary = 0xffffffff; // not set in Figma palette.background.fillColor.cardBackground.tertiary = 0xffffffff; // not set in Figma
palette.background.fillColor.stroke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 ); palette.background.fillColor.smoke.defaultColor = QskRgb::toTransparentF( 0xff000000, 0.30 );
palette.background.fillColor.layer.defaultColor = QskRgb::toTransparentF( 0xff3A3A3A, 0.30 ); palette.background.fillColor.layer.defaultColor = QskRgb::toTransparentF( 0xff3A3A3A, 0.30 );
palette.background.fillColor.layer.alt = QskRgb::toTransparentF( 0xffffffff, 0.0538 ); palette.background.fillColor.layer.alt = QskRgb::toTransparentF( 0xffffffff, 0.0538 );
@ -940,7 +1206,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors
} }
} }
QskWindowsSkin::QskWindowsSkin( const QskWindowsTheme& palette, QObject* parent ) QskFluent2Skin::QskFluent2Skin( const QskFluent2Theme& palette, QObject* parent )
: Inherited( parent ) : Inherited( parent )
{ {
setupFonts(); setupFonts();
@ -950,11 +1216,11 @@ QskWindowsSkin::QskWindowsSkin( const QskWindowsTheme& palette, QObject* parent
editor.setup(); editor.setup();
} }
QskWindowsSkin::~QskWindowsSkin() QskFluent2Skin::~QskFluent2Skin()
{ {
} }
void QskWindowsSkin::setupFonts() void QskFluent2Skin::setupFonts()
{ {
static QString fontName( QStringLiteral( "Segoe UI Variable" ) ); static QString fontName( QStringLiteral( "Segoe UI Variable" ) );
Inherited::setupFonts( fontName ); Inherited::setupFonts( fontName );
@ -969,7 +1235,7 @@ void QskWindowsSkin::setupFonts()
setFont( Display, createFont( fontName, 68, 92, 0.0, QFont::DemiBold ) ); setFont( Display, createFont( fontName, 68, 92, 0.0, QFont::DemiBold ) );
} }
void QskWindowsSkin::setGraphicColor( GraphicRole role, QRgb rgb ) void QskFluent2Skin::setGraphicColor( GraphicRole role, QRgb rgb )
{ {
QskColorFilter colorFilter; QskColorFilter colorFilter;
colorFilter.setMask( QskRgb::RGBAMask ); colorFilter.setMask( QskRgb::RGBAMask );
@ -978,7 +1244,7 @@ void QskWindowsSkin::setGraphicColor( GraphicRole role, QRgb rgb )
setGraphicFilter( role, colorFilter ); setGraphicFilter( role, colorFilter );
} }
void QskWindowsSkin::setupGraphicFilters( const QskWindowsTheme& theme ) void QskFluent2Skin::setupGraphicFilters( const QskFluent2Theme& theme )
{ {
setGraphicColor( GraphicRoleFillColorTextDisabled, theme.palette.fillColor.text.disabled ); setGraphicColor( GraphicRoleFillColorTextDisabled, theme.palette.fillColor.text.disabled );
setGraphicColor( GraphicRoleFillColorTextOnAccentDisabled, theme.palette.fillColor.textOnAccent.disabled ); setGraphicColor( GraphicRoleFillColorTextOnAccentDisabled, theme.palette.fillColor.textOnAccent.disabled );
@ -988,4 +1254,4 @@ void QskWindowsSkin::setupGraphicFilters( const QskWindowsTheme& theme )
setGraphicColor( GraphicRoleFillColorTextSecondary, theme.palette.fillColor.text.secondary ); setGraphicColor( GraphicRoleFillColorTextSecondary, theme.palette.fillColor.text.secondary );
} }
#include "moc_QskWindowsSkin.cpp" #include "moc_QskFluent2Skin.cpp"

View File

@ -1,12 +1,12 @@
/****************************************************************************** /******************************************************************************
* QSkinny - Copyright (C) 2022 Edelhirsch Software GmbH * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/ *****************************************************************************/
#ifndef QSK_WINDOWS_SKIN_H #ifndef QSK_FLUENT2_SKIN_H
#define QSK_WINDOWS_SKIN_H #define QSK_FLUENT2_SKIN_H
#include "QskWindowsGlobal.h" #include "QskFluent2Global.h"
#include <QskBoxShapeMetrics.h> #include <QskBoxShapeMetrics.h>
#include <QskGradient.h> #include <QskGradient.h>
@ -15,7 +15,7 @@
#include <array> #include <array>
class QSK_WINDOWS_EXPORT QskWindowsTheme class QSK_FLUENT2_EXPORT QskFluent2Theme
{ {
public: public:
enum Theme enum Theme
@ -37,8 +37,10 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
NumAccentColors NumAccentColors
}; };
QskWindowsTheme( Theme ); QskFluent2Theme( Theme );
QskWindowsTheme( Theme, std::array< QRgb, NumAccentColors > ); QskFluent2Theme( Theme, std::array< QRgb, NumAccentColors > );
typedef std::array< QRgb, 2 > BorderGradient;
struct FillColor struct FillColor
{ {
@ -156,23 +158,23 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
{ {
struct Control struct Control
{ {
std::array< QRgb, 2 > border; BorderGradient border;
}; };
struct Circle struct Circle
{ {
std::array< QRgb, 2 > border; BorderGradient border;
}; };
struct TextControl struct TextControl
{ {
std::array< QRgb, 2 > border; BorderGradient border;
std::array< QRgb, 2 > borderFocused; BorderGradient borderFocused;
}; };
struct AccentControl struct AccentControl
{ {
std::array< QRgb, 2 > border; BorderGradient border;
}; };
Control control; Control control;
@ -242,7 +244,7 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
QRgb tertiary; QRgb tertiary;
}; };
struct Stroke struct Smoke
{ {
QRgb defaultColor; QRgb defaultColor;
}; };
@ -289,7 +291,7 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
}; };
CardBackground cardBackground; CardBackground cardBackground;
Stroke stroke; Smoke smoke;
Layer layer; Layer layer;
LayerOnAcrylic layerOnAcrylic; LayerOnAcrylic layerOnAcrylic;
LayerOnAccentAcrylic layerOnAccentAcrylic; LayerOnAccentAcrylic layerOnAccentAcrylic;
@ -327,15 +329,15 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
Shadow shadow; Shadow shadow;
}; };
class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin
{ {
Q_OBJECT Q_OBJECT
using Inherited = QskSkin; using Inherited = QskSkin;
public: public:
QskWindowsSkin( const QskWindowsTheme&, QObject* parent = nullptr ); QskFluent2Skin( const QskFluent2Theme&, QObject* parent = nullptr );
~QskWindowsSkin() override; ~QskFluent2Skin() override;
enum GraphicRole enum GraphicRole
{ {
@ -349,14 +351,14 @@ class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin
enum FontRole enum FontRole
{ {
Caption = QskSkin::HugeFont + 1, // ### define QskSkin enums Caption = TinyFont,
Body, Body = DefaultFont,
BodyStrong, BodyStrong = SmallFont,
BodyLarge, BodyLarge = MediumFont,
Subtitle, Subtitle = LargeFont,
Title, Title = HugeFont,
TitleLarge, TitleLarge,
Display Display,
}; };
static constexpr QskAspect::Variation Standard = QskAspect::NoVariation; static constexpr QskAspect::Variation Standard = QskAspect::NoVariation;
@ -364,7 +366,7 @@ class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin
private: private:
void setupFonts(); void setupFonts();
void setupGraphicFilters( const QskWindowsTheme& palette ); void setupGraphicFilters( const QskFluent2Theme& palette );
void setGraphicColor( GraphicRole, QRgb ); void setGraphicColor( GraphicRole, QRgb );
}; };

View File

@ -0,0 +1,42 @@
/******************************************************************************
* QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskFluent2SkinFactory.h"
#include "QskFluent2Skin.h"
static const QString fluent2LightSkinName = QStringLiteral( "Fluent2 Light" );
static const QString fluent2DarkSkinName = QStringLiteral( "Fluent2 Dark" );
QskFluent2SkinFactory::QskFluent2SkinFactory( QObject* parent )
: QskSkinFactory( parent )
{
}
QskFluent2SkinFactory::~QskFluent2SkinFactory()
{
}
QStringList QskFluent2SkinFactory::skinNames() const
{
return { fluent2LightSkinName, fluent2DarkSkinName };
}
QskSkin* QskFluent2SkinFactory::createSkin( const QString& skinName )
{
if ( QString::compare( skinName, fluent2LightSkinName, Qt::CaseInsensitive ) == 0 )
{
QskFluent2Theme theme( QskFluent2Theme::Light );
return new QskFluent2Skin( theme );
}
else if ( QString::compare( skinName, fluent2DarkSkinName, Qt::CaseInsensitive ) == 0 )
{
QskFluent2Theme theme( QskFluent2Theme::Dark );
return new QskFluent2Skin( theme );
}
return nullptr;
}
#include "moc_QskFluent2SkinFactory.cpp"

View File

@ -1,25 +1,25 @@
/****************************************************************************** /******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann * QSkinny - Copyright (C) 2023 Edelhirsch Software GmbH
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/ *****************************************************************************/
#ifndef QSK_WINDOWS_SKIN_FACTORY_H #ifndef QSK_FLUENT2_SKIN_FACTORY_H
#define QSK_WINDOWS_SKIN_FACTORY_H #define QSK_FLUENT2_SKIN_FACTORY_H
#include "QskWindowsGlobal.h" #include "QskFluent2Global.h"
#include <QskSkinFactory.h> #include <QskSkinFactory.h>
class QSK_WINDOWS_EXPORT QskWindowsSkinFactory : public QskSkinFactory class QSK_FLUENT2_EXPORT QskFluent2SkinFactory : public QskSkinFactory
{ {
Q_OBJECT Q_OBJECT
#if defined( QSK_WINDOWS_MAKEDLL ) #if defined( QSK_FLUENT2_MAKEDLL )
Q_PLUGIN_METADATA( IID QskSkinFactoryIID FILE "metadata.json" ) Q_PLUGIN_METADATA( IID QskSkinFactoryIID FILE "metadata.json" )
Q_INTERFACES( QskSkinFactory ) Q_INTERFACES( QskSkinFactory )
#endif #endif
public: public:
QskWindowsSkinFactory( QObject* parent = nullptr ); QskFluent2SkinFactory( QObject* parent = nullptr );
~QskWindowsSkinFactory() override; ~QskFluent2SkinFactory() override;
QStringList skinNames() const override; QStringList skinNames() const override;
QskSkin* createSkin( const QString& skinName ) override; QskSkin* createSkin( const QString& skinName ) override;

View File

@ -1,8 +1,10 @@
<RCC> <RCC>
<qresource prefix="/windows"> <qresource prefix="/fluent2">
<file>icons/qvg/checkmark.qvg</file> <file>icons/qvg/checkmark.qvg</file>
<file>icons/qvg/combo-box-arrow-closed.qvg</file> <file>icons/qvg/combo-box-arrow-closed.qvg</file>
<file>icons/qvg/combo-box-arrow-open.qvg</file> <file>icons/qvg/combo-box-arrow-open.qvg</file>
<file>icons/qvg/segmented-button-check.qvg</file> <file>icons/qvg/segmented-button-check.qvg</file>
<file>icons/qvg/spin-box-arrow-down.qvg</file>
<file>icons/qvg/spin-box-arrow-up.qvg</file>
</qresource> </qresource>
</RCC> </RCC>

View File

Before

Width:  |  Height:  |  Size: 777 B

After

Width:  |  Height:  |  Size: 777 B

View File

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 157 B

View File

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 246 B

After

Width:  |  Height:  |  Size: 246 B

View File

@ -0,0 +1,4 @@
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 1.125C0.5 1.02344 0.537109 0.935547 0.611328 0.861328C0.685547 0.787109 0.773438 0.75 0.875 0.75C0.976562 0.75 1.06445 0.787109 1.13867 0.861328L5 4.7168L8.86133 0.861328C8.93555 0.787109 9.02344 0.75 9.125 0.75C9.22656 0.75 9.31445 0.787109 9.38867 0.861328C9.46289 0.935547 9.5 1.02344 9.5 1.125C9.5 1.22656 9.46289 1.31445 9.38867 1.38867L5.26367 5.51367C5.18945 5.58789 5.10156 5.625 5 5.625C4.89844 5.625 4.81055 5.58789 4.73633 5.51367L0.611328 1.38867C0.537109 1.31445 0.5 1.22656 0.5 1.125Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 631 B

View File

@ -0,0 +1,4 @@
<svg width="10" height="6" viewBox="0 0 10 6" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.5 4.875C0.5 4.77344 0.537109 4.68555 0.611328 4.61133L4.73633 0.486328C4.81055 0.412109 4.89844 0.375 5 0.375C5.10156 0.375 5.18945 0.412109 5.26367 0.486328L9.38867 4.61133C9.46289 4.68555 9.5 4.77344 9.5 4.875C9.5 4.97656 9.46289 5.06445 9.38867 5.13867C9.31445 5.21289 9.22656 5.25 9.125 5.25C9.02344 5.25 8.93555 5.21289 8.86133 5.13867L5 1.2832L1.13867 5.13867C1.06445 5.21289 0.976562 5.25 0.875 5.25C0.773438 5.25 0.685547 5.21289 0.611328 5.13867C0.537109 5.06445 0.5 4.97656 0.5 4.875Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 625 B

View File

@ -0,0 +1,4 @@
{
"FactoryId": "Fluent2Factory",
"Skins": [ "Fluent2 Light", "Fluent2 Dark" ]
}

View File

@ -861,7 +861,7 @@ void Editor::setupSpinBox()
{ {
using Q = QskSpinBox; using Q = QskSpinBox;
setHint( Q::Panel | QskAspect::Style, Q::Buttons ); setHint( Q::Panel | QskAspect::Style, Q::ButtonsLeftAndRight );
setSpacing( Q::Panel, 4_dp ); setSpacing( Q::Panel, 4_dp );
setStrutSize( Q::TextPanel, 80_dp, 40_dp ); setStrutSize( Q::TextPanel, 80_dp, 40_dp );

View File

@ -127,10 +127,10 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin
enum FontRole enum FontRole
{ {
M3BodyMedium = QskSkin::HugeFont + 1, M3BodyMedium = DefaultFont,
M3BodyLarge, M3BodyLarge = LargeFont,
M3HeadlineSmall, M3HeadlineSmall = SmallFont,
M3LabelLarge, M3LabelLarge = HugeFont,
}; };
static constexpr QskAspect::Variation Filled = QskAspect::NoVariation; static constexpr QskAspect::Variation Filled = QskAspect::NoVariation;

View File

@ -1,13 +0,0 @@
############################################################################
# QSkinny - Copyright (C) 2016 Uwe Rathmann
# SPDX-License-Identifier: BSD-3-Clause
############################################################################
set(SOURCES
QskWindowsGlobal.h QskWindowsSkin.h QskWindowsSkin.cpp
QskWindowsSkinFactory.h QskWindowsSkinFactory.cpp
)
qt_add_resources(SOURCES icons.qrc)
qsk_add_plugin(windowsskin skins QskWindowsSkinFactory ${SOURCES})
set_target_properties(windowsskin PROPERTIES DEFINE_SYMBOL QSK_WINDOWS_MAKEDLL )

View File

@ -1,42 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskWindowsSkinFactory.h"
#include "QskWindowsSkin.h"
static const QString windowsLightSkinName = QStringLiteral( "Windows Light" );
static const QString windowsDarkSkinName = QStringLiteral( "Windows Dark" );
QskWindowsSkinFactory::QskWindowsSkinFactory( QObject* parent )
: QskSkinFactory( parent )
{
}
QskWindowsSkinFactory::~QskWindowsSkinFactory()
{
}
QStringList QskWindowsSkinFactory::skinNames() const
{
return { windowsLightSkinName, windowsDarkSkinName };
}
QskSkin* QskWindowsSkinFactory::createSkin( const QString& skinName )
{
if ( QString::compare( skinName, windowsLightSkinName, Qt::CaseInsensitive ) == 0 )
{
QskWindowsTheme theme( QskWindowsTheme::Light );
return new QskWindowsSkin( theme );
}
else if ( QString::compare( skinName, windowsDarkSkinName, Qt::CaseInsensitive ) == 0 )
{
QskWindowsTheme theme( QskWindowsTheme::Dark );
return new QskWindowsSkin( theme );
}
return nullptr;
}
#include "moc_QskWindowsSkinFactory.cpp"

View File

@ -1,4 +0,0 @@
{
"FactoryId": "WindowsFactory",
"Skins": [ "Windows Light", "Windows Dark" ]
}

View File

@ -32,6 +32,7 @@ list(APPEND HEADERS
common/QskShadowMetrics.h common/QskShadowMetrics.h
common/QskSizePolicy.h common/QskSizePolicy.h
common/QskStateCombination.h common/QskStateCombination.h
common/QskStippleMetrics.h
common/QskTextColors.h common/QskTextColors.h
common/QskTextOptions.h common/QskTextOptions.h
) )
@ -61,6 +62,7 @@ list(APPEND SOURCES
common/QskScaleTickmarks.cpp common/QskScaleTickmarks.cpp
common/QskShadowMetrics.cpp common/QskShadowMetrics.cpp
common/QskSizePolicy.cpp common/QskSizePolicy.cpp
common/QskStippleMetrics.cpp
common/QskTextColors.cpp common/QskTextColors.cpp
common/QskTextOptions.cpp common/QskTextOptions.cpp
) )
@ -107,12 +109,14 @@ list(APPEND HEADERS
nodes/QskBoxShadowNode.h nodes/QskBoxShadowNode.h
nodes/QskColorRamp.h nodes/QskColorRamp.h
nodes/QskGraphicNode.h nodes/QskGraphicNode.h
nodes/QskLinesNode.h
nodes/QskPaintedNode.h nodes/QskPaintedNode.h
nodes/QskPlainTextRenderer.h nodes/QskPlainTextRenderer.h
nodes/QskRichTextRenderer.h nodes/QskRichTextRenderer.h
nodes/QskScaleRenderer.h nodes/QskScaleRenderer.h
nodes/QskSGNode.h nodes/QskSGNode.h
nodes/QskStrokeNode.h nodes/QskStrokeNode.h
nodes/QskStippledLineRenderer.h
nodes/QskShapeNode.h nodes/QskShapeNode.h
nodes/QskGradientMaterial.h nodes/QskGradientMaterial.h
nodes/QskTextNode.h nodes/QskTextNode.h
@ -135,6 +139,7 @@ list(APPEND SOURCES
nodes/QskBoxShadowNode.cpp nodes/QskBoxShadowNode.cpp
nodes/QskColorRamp.cpp nodes/QskColorRamp.cpp
nodes/QskGraphicNode.cpp nodes/QskGraphicNode.cpp
nodes/QskLinesNode.cpp
nodes/QskPaintedNode.cpp nodes/QskPaintedNode.cpp
nodes/QskPlainTextRenderer.cpp nodes/QskPlainTextRenderer.cpp
nodes/QskRectangleNode.cpp nodes/QskRectangleNode.cpp
@ -142,6 +147,7 @@ list(APPEND SOURCES
nodes/QskScaleRenderer.cpp nodes/QskScaleRenderer.cpp
nodes/QskSGNode.cpp nodes/QskSGNode.cpp
nodes/QskStrokeNode.cpp nodes/QskStrokeNode.cpp
nodes/QskStippledLineRenderer.cpp
nodes/QskShapeNode.cpp nodes/QskShapeNode.cpp
nodes/QskGradientMaterial.cpp nodes/QskGradientMaterial.cpp
nodes/QskTextNode.cpp nodes/QskTextNode.cpp

View File

@ -413,7 +413,7 @@ QGradientStops qskToQGradientStops( const QskGradientStops& stops )
QGradient removes stops at the same position. So we have to insert QGradient removes stops at the same position. So we have to insert
an invisible dummy offset an invisible dummy offset
*/ */
qStop.first += 0.00001; qStop.first = qMin( qStop.first + 0.00001, 1.0 );
} }
qStops += qStop; qStops += qStop;

View File

@ -0,0 +1,147 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskStippleMetrics.h"
#include <qhashfunctions.h>
#include <qpen.h>
#include <qvariant.h>
static void qskRegisterStippleMetrics()
{
qRegisterMetaType< QskStippleMetrics >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskStippleMetrics >();
#endif
QMetaType::registerConverter< QPen, QskStippleMetrics >(
[]( const QPen& pen ) { return QskStippleMetrics( pen ); } );
QMetaType::registerConverter< Qt::PenStyle, QskStippleMetrics >(
[]( Qt::PenStyle style ) { return QskStippleMetrics( style ); } );
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterStippleMetrics )
QVector< qreal > qskDashPattern( Qt::PenStyle style )
{
static const QVector< qreal > pattern[] =
{
{}, { 1 }, { 4, 2 }, { 1, 2 },
{ 4, 2, 1, 2 }, { 4, 2, 1, 2, 1, 2 }, {}
};
return pattern[ style ];
}
static inline qreal qskInterpolated( qreal from, qreal to, qreal ratio )
{
return from + ( to - from ) * ratio;
}
static inline QVector< qreal > qskInterpolatedSpaces(
const QVector< qreal >& pattern, qreal progress )
{
QVector< qreal > interpolated;
interpolated.reserve( pattern.count() );
for ( int i = 1; i < pattern.count(); i += 2 )
interpolated[i] = progress * pattern[i];
return interpolated;
}
QskStippleMetrics::QskStippleMetrics( Qt::PenStyle penStyle )
: m_pattern( qskDashPattern( penStyle ) )
{
}
QskStippleMetrics::QskStippleMetrics( const QPen& pen )
: QskStippleMetrics( pen.style() )
{
if ( pen.style() == Qt::CustomDashLine )
{
m_offset = pen.dashOffset();
m_pattern = pen.dashPattern();
}
}
void QskStippleMetrics::setPattern( const QVector< qreal >& pattern )
{
m_pattern = pattern;
}
void QskStippleMetrics::setOffset( qreal offset ) noexcept
{
m_offset = offset;
}
QskStippleMetrics QskStippleMetrics::interpolated(
const QskStippleMetrics& to, qreal progress ) const
{
if ( *this == to )
return to;
const auto offset = qskInterpolated( m_offset, to.m_offset, progress );
QVector< qreal > pattern;
if ( isSolid() )
{
pattern = qskInterpolatedSpaces( to.m_pattern, progress );
}
else if ( to.isSolid() )
{
pattern = qskInterpolatedSpaces( m_pattern, 1.0 - progress );
}
else
{
const auto count = qMax( m_pattern.count(), to.m_pattern.count() );
pattern.reserve( count );
for ( int i = 0; i < count; i++ )
{
const auto v1 = m_pattern.value( i, 0.0 );
const auto v2 = to.m_pattern.value( i, 0.0 );
pattern += qskInterpolated( v1, v2, progress );
}
}
return QskStippleMetrics( pattern, offset );
}
QVariant QskStippleMetrics::interpolate(
const QskStippleMetrics& from, const QskStippleMetrics& to, qreal progress )
{
return QVariant::fromValue( from.interpolated( to, progress ) );
}
QskHashValue QskStippleMetrics::hash( QskHashValue seed ) const noexcept
{
auto hash = qHash( m_offset, seed );
return qHash( m_pattern, hash );
}
#ifndef QT_NO_DEBUG_STREAM
#include <qdebug.h>
QDebug operator<<( QDebug debug, const QskStippleMetrics& metrics )
{
QDebugStateSaver saver( debug );
debug.nospace();
debug << "QskStippleMetrics" << '(';
debug << metrics.offset() << ',' << metrics.pattern();
debug << ')';
return debug;
}
#endif
#include "moc_QskStippleMetrics.cpp"

View File

@ -0,0 +1,105 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_STIPPLE_METRICS_H
#define QSK_STIPPLE_METRICS_H
#include "QskGlobal.h"
#include <qmetatype.h>
#include <qvector.h>
#include <qnamespace.h>
class QPen;
class QSK_EXPORT QskStippleMetrics
{
Q_GADGET
Q_PROPERTY( qreal offset READ offset WRITE setOffset )
Q_PROPERTY( QVector< qreal > pattern READ pattern WRITE setPattern )
public:
QskStippleMetrics( Qt::PenStyle = Qt::SolidLine );
QskStippleMetrics( const QPen& );
QskStippleMetrics( const QVector< qreal >&, qreal offset = 0.0 );
bool operator==( const QskStippleMetrics& ) const noexcept;
bool operator!=( const QskStippleMetrics& ) const noexcept;
bool isValid() const noexcept;
bool isSolid() const noexcept;
void setOffset( qreal offset ) noexcept;
qreal offset() const noexcept;
void setPattern( const QVector< qreal >& );
QVector< qreal > pattern() const;
QskStippleMetrics interpolated(
const QskStippleMetrics&, qreal value ) const;
static QVariant interpolate( const QskStippleMetrics&,
const QskStippleMetrics&, qreal progress );
QskHashValue hash( QskHashValue seed = 0 ) const noexcept;
private:
qreal m_offset = 0.0;
QVector< qreal > m_pattern;
};
inline QskStippleMetrics::QskStippleMetrics(
const QVector< qreal >& pattern, qreal offset )
: m_offset( offset )
, m_pattern( pattern )
{
}
inline qreal QskStippleMetrics::offset() const noexcept
{
return m_offset;
}
inline QVector< qreal > QskStippleMetrics::pattern() const
{
return m_pattern;
}
inline bool QskStippleMetrics::operator==(
const QskStippleMetrics& other ) const noexcept
{
return ( m_offset == other.m_offset )
&& ( m_pattern == other.m_pattern );
}
inline bool QskStippleMetrics::operator!=(
const QskStippleMetrics& other ) const noexcept
{
return !( *this == other );
}
inline bool QskStippleMetrics::isValid() const noexcept
{
return !m_pattern.isEmpty();
}
inline bool QskStippleMetrics::isSolid() const noexcept
{
return m_pattern.count() == 1;
}
QSK_EXPORT QVector< qreal > qskDashPattern( Qt::PenStyle );
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
QSK_EXPORT QDebug operator<<( QDebug, const QskStippleMetrics& );
#endif
Q_DECLARE_METATYPE( QskStippleMetrics )
#endif

View File

@ -192,7 +192,9 @@ void QskProgressBar::resetExtent()
qreal QskProgressBar::extent() const qreal QskProgressBar::extent() const
{ {
return metric( Groove | QskAspect::Size ); auto grooveSize = metric( Groove | QskAspect::Size );
auto barSize = metric( Bar | QskAspect::Size );
return qMax( grooveSize, barSize );
} }
void QskProgressBar::setOrigin( qreal origin ) void QskProgressBar::setOrigin( qreal origin )

View File

@ -62,28 +62,29 @@ QRectF QskProgressBarSkinlet::subControlRect(
const QskSkinnable* skinnable, const QRectF& contentsRect, const QskSkinnable* skinnable, const QRectF& contentsRect,
QskAspect::Subcontrol subControl ) const QskAspect::Subcontrol subControl ) const
{ {
const auto bar = static_cast< const QskProgressBar* >( skinnable ); using Q = QskProgressBar;
const auto bar = static_cast< const Q* >( skinnable );
if( subControl == QskProgressBar::Groove ) if( subControl == Q::Groove )
{ {
const auto extent = bar->extent(); const auto grooveSize = bar->metric( Q::Groove | QskAspect::Size );
auto rect = contentsRect; auto rect = contentsRect;
if ( bar->orientation() == Qt::Horizontal ) if ( bar->orientation() == Qt::Horizontal )
{ {
rect.setY( rect.y() + 0.5 * ( rect.height() - extent ) ); rect.setY( rect.y() + 0.5 * ( rect.height() - grooveSize ) );
rect.setHeight( extent ); rect.setHeight( grooveSize );
} }
else else
{ {
rect.setX( rect.x() + 0.5 * ( rect.width() - extent ) ); rect.setX( rect.x() + 0.5 * ( rect.width() - grooveSize ) );
rect.setWidth( extent ); rect.setWidth( grooveSize );
} }
return rect; return rect;
} }
if( subControl == QskProgressBar::Bar ) if( subControl == Q::Bar )
{ {
return barRect( bar ); return barRect( bar );
} }
@ -154,10 +155,23 @@ QSGNode* QskProgressBarSkinlet::updateBarNode(
QRectF QskProgressBarSkinlet::barRect( const QskProgressBar* bar ) const QRectF QskProgressBarSkinlet::barRect( const QskProgressBar* bar ) const
{ {
const auto subControl = QskProgressBar::Groove; using Q = QskProgressBar;
const auto subControl = Q::Groove;
const auto barSize = bar->metric( Q::Bar | QskAspect::Size );
auto rect = bar->subControlRect( subControl ); auto rect = bar->subControlRect( subControl );
if ( bar->orientation() == Qt::Horizontal )
{
rect.setY( rect.y() + 0.5 * ( rect.height() - barSize ) );
rect.setHeight( barSize );
}
else
{
rect.setX( rect.x() + 0.5 * ( rect.width() - barSize ) );
rect.setWidth( barSize );
}
const auto borderMetrics = bar->boxBorderMetricsHint( subControl ); const auto borderMetrics = bar->boxBorderMetricsHint( subControl );
auto m = bar->paddingHint( subControl ); auto m = bar->paddingHint( subControl );

View File

@ -11,9 +11,9 @@
#include "QskSkinlet.h" #include "QskSkinlet.h"
#include "QskAspect.h" #include "QskAspect.h"
#include <QGuiApplication> #include <qguiapplication.h>
#include <QStyleHints> #include <qstylehints.h>
#include <QFontMetricsF> #include <qfontmetrics.h>
QSK_SUBCONTROL( QskSegmentedBar, Panel ) QSK_SUBCONTROL( QskSegmentedBar, Panel )
QSK_SUBCONTROL( QskSegmentedBar, Segment ) QSK_SUBCONTROL( QskSegmentedBar, Segment )

View File

@ -12,6 +12,7 @@
#include "QskBoxBorderMetrics.h" #include "QskBoxBorderMetrics.h"
#include "QskBoxBorderColors.h" #include "QskBoxBorderColors.h"
#include "QskShadowMetrics.h" #include "QskShadowMetrics.h"
#include "QskStippleMetrics.h"
#include "QskGraphic.h" #include "QskGraphic.h"
namespace namespace
@ -130,6 +131,11 @@ namespace
{ {
return aspect | QskAspect::Symbol; return aspect | QskAspect::Symbol;
} }
inline QskAspect aspectStipple( QskAspect aspect )
{
return aspect | QskAspect::Style;
}
} }
QskSkinHintTableEditor::QskSkinHintTableEditor( QskSkinHintTable* table ) QskSkinHintTableEditor::QskSkinHintTableEditor( QskSkinHintTable* table )
@ -583,8 +589,8 @@ void QskSkinHintTableEditor::setArcMetrics( QskAspect aspect,
setMetricHint( aspectShape( aspect ), arcMetrics, combination ); setMetricHint( aspectShape( aspect ), arcMetrics, combination );
} }
bool QskSkinHintTableEditor::removeArcMetrics( QskAspect aspect, bool QskSkinHintTableEditor::removeArcMetrics(
QskStateCombination combination ) QskAspect aspect, QskStateCombination combination )
{ {
return removeMetricHint( aspectShape( aspect ), combination ); return removeMetricHint( aspectShape( aspect ), combination );
} }
@ -594,6 +600,35 @@ QskArcMetrics QskSkinHintTableEditor::arcMetrics( QskAspect aspect ) const
return metricHint< QskArcMetrics >( aspectShape( aspect ) ); return metricHint< QskArcMetrics >( aspectShape( aspect ) );
} }
void QskSkinHintTableEditor::setStippleMetrics( QskAspect aspect,
Qt::PenStyle penStyle, QskStateCombination combination )
{
setStippleMetrics( aspect, QskStippleMetrics( penStyle ), combination );
}
void QskSkinHintTableEditor::setStippleMetrics( QskAspect aspect,
const QVector< qreal >& dashPattern, QskStateCombination combination )
{
setStippleMetrics( aspect, QskStippleMetrics( dashPattern ), combination );
}
void QskSkinHintTableEditor::setStippleMetrics( QskAspect aspect,
const QskStippleMetrics& metrics, QskStateCombination combination )
{
setMetricHint( aspectStipple( aspect ), metrics, combination );
}
bool QskSkinHintTableEditor::removeStippleMetrics(
QskAspect aspect, QskStateCombination combination )
{
return removeMetricHint( aspectStipple( aspect ), combination );
}
QskStippleMetrics QskSkinHintTableEditor::stippleMetrics( QskAspect aspect ) const
{
return metricHint< QskStippleMetrics >( aspectStipple( aspect ) );
}
void QskSkinHintTableEditor::setTextOptions( QskAspect aspect, void QskSkinHintTableEditor::setTextOptions( QskAspect aspect,
Qt::TextElideMode elideMode, QskTextOptions::WrapMode wrapMode, Qt::TextElideMode elideMode, QskTextOptions::WrapMode wrapMode,
QskStateCombination combination ) QskStateCombination combination )

View File

@ -14,6 +14,7 @@
#include <qcolor.h> #include <qcolor.h>
#include <qvariant.h> #include <qvariant.h>
#include <qvector.h>
class QskArcMetrics; class QskArcMetrics;
class QskMargins; class QskMargins;
@ -22,6 +23,7 @@ class QskBoxShapeMetrics;
class QskBoxBorderMetrics; class QskBoxBorderMetrics;
class QskBoxBorderColors; class QskBoxBorderColors;
class QskShadowMetrics; class QskShadowMetrics;
class QskStippleMetrics;
class QskGraphic; class QskGraphic;
class QSK_EXPORT QskSkinHintTableEditor class QSK_EXPORT QskSkinHintTableEditor
@ -265,6 +267,21 @@ class QSK_EXPORT QskSkinHintTableEditor
QskArcMetrics arcMetrics( QskAspect ) const; QskArcMetrics arcMetrics( QskAspect ) const;
// lines
void setStippleMetrics( QskAspect, Qt::PenStyle,
QskStateCombination = QskStateCombination() );
void setStippleMetrics( QskAspect, const QVector< qreal >&,
QskStateCombination = QskStateCombination() );
void setStippleMetrics( QskAspect, const QskStippleMetrics&,
QskStateCombination = QskStateCombination() );
bool removeStippleMetrics( QskAspect, QskStateCombination = QskStateCombination() );
QskStippleMetrics stippleMetrics( QskAspect ) const;
// text options flag // text options flag
void setTextOptions( QskAspect, void setTextOptions( QskAspect,

View File

@ -83,6 +83,10 @@ namespace
const auto factoryData = pluginData.value( TokenData ).toObject(); const auto factoryData = pluginData.value( TokenData ).toObject();
m_factoryId = factoryData.value( TokenFactoryId ).toString().toLower(); m_factoryId = factoryData.value( TokenFactoryId ).toString().toLower();
#if 1
if ( m_factoryId == "fluent2factory" )
return false; // we need to solve a couple of problems first
#endif
if ( m_factoryId.isEmpty() ) if ( m_factoryId.isEmpty() )
{ {
// Creating a dummy factory id // Creating a dummy factory id
@ -200,7 +204,7 @@ namespace
if ( !m_isValid ) if ( !m_isValid )
const_cast< FactoryMap* >( this )->rebuild(); const_cast< FactoryMap* >( this )->rebuild();
return m_skinMap.keys(); return m_skinNames;
} }
void insertFactory( FactoryLoader* loader ) void insertFactory( FactoryLoader* loader )
@ -269,6 +273,7 @@ namespace
void rebuild() void rebuild()
{ {
m_skinMap.clear(); m_skinMap.clear();
m_skinNames.clear();
// first we try all factories, that have been added manually // first we try all factories, that have been added manually
for ( auto it = m_factoryMap.constBegin(); it != m_factoryMap.constEnd(); ++it ) for ( auto it = m_factoryMap.constBegin(); it != m_factoryMap.constEnd(); ++it )
@ -287,7 +292,6 @@ namespace
rebuild( it.key(), data.loader->skinNames() ); rebuild( it.key(), data.loader->skinNames() );
} }
m_skinNames = m_skinMap.keys();
m_isValid = true; m_isValid = true;
} }
@ -296,7 +300,10 @@ namespace
for ( const auto& name : skinNames ) for ( const auto& name : skinNames )
{ {
if ( !m_skinMap.contains( name ) ) if ( !m_skinMap.contains( name ) )
{
m_skinMap.insert( name, factoryId ); m_skinMap.insert( name, factoryId );
m_skinNames += name;
}
} }
} }
@ -487,16 +494,10 @@ QskSkin* QskSkinManager::createSkin( const QString& skinName ) const
auto factory = map.factory( name ); auto factory = map.factory( name );
if ( factory == nullptr ) if ( factory == nullptr )
{ {
/*
Once the Fusion skin has been implemented it will be used
as fallback. For the moment we implement
another stupid fallback. TODO ...
*/
const auto names = map.skinNames(); const auto names = map.skinNames();
if ( !names.isEmpty() ) if ( !names.isEmpty() )
{ {
name = names.last(); name = names.first();
factory = map.factory( name ); factory = map.factory( name );
} }
} }

View File

@ -21,8 +21,10 @@
#include "QskGradient.h" #include "QskGradient.h"
#include "QskGraphicNode.h" #include "QskGraphicNode.h"
#include "QskGraphic.h" #include "QskGraphic.h"
#include "QskLinesNode.h"
#include "QskRectangleNode.h" #include "QskRectangleNode.h"
#include "QskSGNode.h" #include "QskSGNode.h"
#include "QskStippleMetrics.h"
#include "QskTextColors.h" #include "QskTextColors.h"
#include "QskTextNode.h" #include "QskTextNode.h"
#include "QskTextOptions.h" #include "QskTextOptions.h"
@ -161,6 +163,11 @@ static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics,
return gradient.isVisible(); return gradient.isVisible();
} }
static inline bool qskIsLineVisible( const QColor& lineColor, qreal lineWidth )
{
return ( lineWidth > 0.0 ) && lineColor.isValid() && ( lineColor.alpha() > 0 );
}
static inline QskTextColors qskTextColors( static inline QskTextColors qskTextColors(
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
{ {
@ -199,13 +206,10 @@ static inline QSGNode* qskUpdateBoxNode(
if ( qskIsBoxVisible( absoluteMetrics, borderColors, gradient ) ) if ( qskIsBoxVisible( absoluteMetrics, borderColors, gradient ) )
{ {
auto boxNode = static_cast< QskBoxNode* >( node );
if ( boxNode == nullptr )
boxNode = new QskBoxNode();
const auto absoluteShape = shape.toAbsolute( size ); const auto absoluteShape = shape.toAbsolute( size );
const auto absoluteShadowMetrics = shadowMetrics.toAbsolute( size ); const auto absoluteShadowMetrics = shadowMetrics.toAbsolute( size );
auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node );
boxNode->updateNode( rect, absoluteShape, absoluteMetrics, boxNode->updateNode( rect, absoluteShape, absoluteMetrics,
borderColors, gradient, absoluteShadowMetrics, shadowColor ); borderColors, gradient, absoluteShadowMetrics, shadowColor );
@ -226,15 +230,46 @@ static inline QSGNode* qskUpdateArcNode(
if ( !qskIsArcVisible( metrics, borderWidth, borderColor, gradient ) ) if ( !qskIsArcVisible( metrics, borderWidth, borderColor, gradient ) )
return nullptr; return nullptr;
auto arcNode = static_cast< QskArcNode* >( node ); auto arcNode = QskSGNode::ensureNode< QskArcNode >( node );
if ( arcNode == nullptr )
arcNode = new QskArcNode();
arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient ); arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient );
return arcNode; return arcNode;
} }
static inline QSGNode* qskUpdateLineNode(
const QskSkinnable*, QSGNode* node, const QColor& lineColor,
qreal lineWidth, QskStippleMetrics& lineStipple, const QLineF& line )
{
if ( line.isNull() )
return nullptr;
if ( !qskIsLineVisible( lineColor, lineWidth ) )
return nullptr;
auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node );
linesNode->updateLine( lineColor, lineWidth, lineStipple,
QTransform(), line.p1(), line.p2() );
return linesNode;
}
static inline QSGNode* qskUpdateLinesNode(
const QskSkinnable*, QSGNode* node, const QColor& lineColor,
qreal lineWidth, QskStippleMetrics& lineStipple, const QVector< QLineF >& lines )
{
if ( lines.isEmpty() )
return nullptr;
if ( !qskIsLineVisible( lineColor, lineWidth ) )
return nullptr;
auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node );
linesNode->updateLines( lineColor, lineWidth, lineStipple,
QTransform(), lines );
return linesNode;
}
class QskSkinlet::PrivateData class QskSkinlet::PrivateData
{ {
public: public:
@ -575,6 +610,34 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
borderWidth, borderColor, fillGradient, arcMetrics ); borderWidth, borderColor, fillGradient, arcMetrics );
} }
QSGNode* QskSkinlet::updateLineNode( const QskSkinnable* skinnable,
QSGNode* node, const QLineF& line, QskAspect::Subcontrol subControl )
{
auto lineStipple = skinnable->stippleMetricsHint( subControl );
if ( !lineStipple.isValid() )
lineStipple = Qt::SolidLine;
const auto lineWidth = skinnable->metric( subControl | QskAspect::Size );
const auto lineColor = skinnable->color( subControl );
return qskUpdateLineNode( skinnable, node,
lineColor, lineWidth, lineStipple, line );
}
QSGNode* QskSkinlet::updateLinesNode( const QskSkinnable* skinnable,
QSGNode* node, const QVector< QLineF >& lines, QskAspect::Subcontrol subControl )
{
auto lineStipple = skinnable->stippleMetricsHint( subControl );
if ( !lineStipple.isValid() )
lineStipple = Qt::SolidLine;
const auto lineWidth = skinnable->metric( subControl | QskAspect::Size );
const auto lineColor = skinnable->color( subControl );
return qskUpdateLinesNode( skinnable, node,
lineColor, lineWidth, lineStipple, lines );
}
QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable, QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable,
QSGNode* node, QskAspect::Subcontrol subControl ) const QSGNode* node, QskAspect::Subcontrol subControl ) const
{ {

View File

@ -111,6 +111,12 @@ class QSK_EXPORT QskSkinlet
const QRectF&, const QskGradient&, qreal startAngle, qreal spanAngle, const QRectF&, const QskGradient&, qreal startAngle, qreal spanAngle,
QskAspect::Subcontrol ); QskAspect::Subcontrol );
static QSGNode* updateLineNode( const QskSkinnable*, QSGNode*,
const QLineF&, QskAspect::Subcontrol );
static QSGNode* updateLinesNode( const QskSkinnable*,
QSGNode*, const QVector< QLineF >&, QskAspect::Subcontrol );
static QSGNode* updateTextNode( const QskSkinnable*, QSGNode*, static QSGNode* updateTextNode( const QskSkinnable*, QSGNode*,
const QRectF&, Qt::Alignment, const QString&, QskAspect::Subcontrol ); const QRectF&, Qt::Alignment, const QString&, QskAspect::Subcontrol );

View File

@ -23,6 +23,7 @@
#include "QskBoxBorderMetrics.h" #include "QskBoxBorderMetrics.h"
#include "QskBoxBorderColors.h" #include "QskBoxBorderColors.h"
#include "QskShadowMetrics.h" #include "QskShadowMetrics.h"
#include "QskStippleMetrics.h"
#include "QskBoxHints.h" #include "QskBoxHints.h"
#include "QskGradient.h" #include "QskGradient.h"
#include "QskTextOptions.h" #include "QskTextOptions.h"
@ -638,6 +639,24 @@ QskArcMetrics QskSkinnable::arcMetricsHint(
this, aspect | QskAspect::Shape, status ); this, aspect | QskAspect::Shape, status );
} }
bool QskSkinnable::setStippleMetricsHint(
QskAspect aspect, const QskStippleMetrics& metrics )
{
return qskSetMetric( this, aspect | QskAspect::Style, metrics );
}
bool QskSkinnable::resetStippleMetricsHint( QskAspect aspect )
{
return resetMetric( aspect | QskAspect::Style );
}
QskStippleMetrics QskSkinnable::stippleMetricsHint(
QskAspect aspect, QskSkinHintStatus* status ) const
{
return qskMetric< QskStippleMetrics >(
this, aspect | QskAspect::Style, status );
}
bool QskSkinnable::setSpacingHint( const QskAspect aspect, qreal spacing ) bool QskSkinnable::setSpacingHint( const QskAspect aspect, qreal spacing )
{ {
return qskSetMetric( this, aspect | QskAspect::Spacing, spacing ); return qskSetMetric( this, aspect | QskAspect::Spacing, spacing );
@ -689,14 +708,14 @@ int QskSkinnable::fontRoleHint(
return qskFlag( this, aspect | QskAspect::FontRole, status ); return qskFlag( this, aspect | QskAspect::FontRole, status );
} }
QFont QskSkinnable::effectiveFont( const QskAspect::Subcontrol subControl ) const QFont QskSkinnable::effectiveFont( const QskAspect aspect ) const
{ {
return effectiveSkin()->font( fontRoleHint( subControl ) ); return effectiveSkin()->font( fontRoleHint( aspect ) );
} }
qreal QskSkinnable::effectiveFontHeight( const QskAspect::Subcontrol subControl ) const qreal QskSkinnable::effectiveFontHeight( const QskAspect aspect ) const
{ {
const QFontMetricsF fm( effectiveFont( subControl ) ); const QFontMetricsF fm( effectiveFont( aspect ) );
return fm.height(); return fm.height();
} }

View File

@ -30,6 +30,7 @@ class QskBoxShapeMetrics;
class QskBoxBorderMetrics; class QskBoxBorderMetrics;
class QskBoxBorderColors; class QskBoxBorderColors;
class QskShadowMetrics; class QskShadowMetrics;
class QskStippleMetrics;
class QskTextOptions; class QskTextOptions;
class QskBoxHints; class QskBoxHints;
class QskGradient; class QskGradient;
@ -81,8 +82,8 @@ class QSK_EXPORT QskSkinnable
void setSkinlet( const QskSkinlet* ); void setSkinlet( const QskSkinlet* );
const QskSkinlet* skinlet() const; const QskSkinlet* skinlet() const;
QFont effectiveFont( QskAspect::Subcontrol ) const; QFont effectiveFont( QskAspect ) const;
qreal effectiveFontHeight( QskAspect::Subcontrol ) const; qreal effectiveFontHeight( QskAspect ) const;
QskColorFilter effectiveGraphicFilter( QskAspect::Subcontrol ) const; QskColorFilter effectiveGraphicFilter( QskAspect::Subcontrol ) const;
void setSubcontrolProxy( QskAspect::Subcontrol, QskAspect::Subcontrol proxy ); void setSubcontrolProxy( QskAspect::Subcontrol, QskAspect::Subcontrol proxy );
@ -228,6 +229,10 @@ class QSK_EXPORT QskSkinnable
bool resetArcMetricsHint( QskAspect ); bool resetArcMetricsHint( QskAspect );
QskArcMetrics arcMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const; QskArcMetrics arcMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
bool setStippleMetricsHint( QskAspect, const QskStippleMetrics& );
bool resetStippleMetricsHint( QskAspect );
QskStippleMetrics stippleMetricsHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
bool setSpacingHint( QskAspect, qreal ); bool setSpacingHint( QskAspect, qreal );
bool resetSpacingHint( QskAspect ); bool resetSpacingHint( QskAspect );
qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const; qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const;

View File

@ -173,7 +173,7 @@ void QskSpinBox::resetDecoration()
QskSpinBox::Decoration QskSpinBox::decoration() const QskSpinBox::Decoration QskSpinBox::decoration() const
{ {
return flagHint< QskSpinBox::Decoration >( aspectDecoration(), Buttons ); return flagHint< QskSpinBox::Decoration >( aspectDecoration(), ButtonsLeftAndRight );
} }
void QskSpinBox::setTextAlignment( Qt::Alignment alignment ) void QskSpinBox::setTextAlignment( Qt::Alignment alignment )

View File

@ -37,7 +37,8 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput
{ {
NoDecoration, NoDecoration,
Buttons, ButtonsLeftAndRight,
ButtonsRight,
UpDownControl UpDownControl
}; };
Q_ENUM( Decoration ) Q_ENUM( Decoration )

View File

@ -38,8 +38,8 @@ static inline QskAspect::States qskButtonStates(
QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* ) QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* )
{ {
setNodeRoles( { UpPanel, DownPanel, TextPanel, setNodeRoles( { PanelRole, UpPanelRole, DownPanelRole, TextPanelRole,
UpIndicator, DownIndicator, Text } ); UpIndicatorRole, DownIndicatorRole, TextRole } );
} }
QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable, QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
@ -50,6 +50,9 @@ QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
QskSkinStateChanger stateChanger( skinnable ); QskSkinStateChanger stateChanger( skinnable );
stateChanger.setStates( qskButtonStates( skinnable, subControl ) ); stateChanger.setStates( qskButtonStates( skinnable, subControl ) );
if ( subControl == Q::Panel )
return contentsRect;
if ( subControl == Q::DownIndicator ) if ( subControl == Q::DownIndicator )
return skinnable->subControlContentsRect( contentsRect, Q::DownPanel ); return skinnable->subControlContentsRect( contentsRect, Q::DownPanel );
@ -77,36 +80,41 @@ QSGNode* QskSpinBoxSkinlet::updateSubNode(
switch( nodeRole ) switch( nodeRole )
{ {
case UpPanel: case PanelRole:
{
return updateBoxNode( skinnable, node, Q::Panel );
}
case UpPanelRole:
{ {
stateChanger.setStates( qskButtonStates( skinnable, Q::UpPanel ) ); stateChanger.setStates( qskButtonStates( skinnable, Q::UpPanel ) );
return updateBoxNode( skinnable, node, Q::UpPanel ); return updateBoxNode( skinnable, node, Q::UpPanel );
} }
case DownPanel: case DownPanelRole:
{ {
stateChanger.setStates( qskButtonStates( skinnable, Q::DownPanel ) ); stateChanger.setStates( qskButtonStates( skinnable, Q::DownPanel ) );
return updateBoxNode( skinnable, node, Q::DownPanel ); return updateBoxNode( skinnable, node, Q::DownPanel );
} }
case UpIndicator: case UpIndicatorRole:
{ {
stateChanger.setStates( qskButtonStates( skinnable, Q::UpIndicator ) ); stateChanger.setStates( qskButtonStates( skinnable, Q::UpIndicator ) );
return updateSymbolNode( skinnable, node, Q::UpIndicator ); return updateSymbolNode( skinnable, node, Q::UpIndicator );
} }
case DownIndicator: case DownIndicatorRole:
{ {
stateChanger.setStates( qskButtonStates( skinnable, Q::DownIndicator ) ); stateChanger.setStates( qskButtonStates( skinnable, Q::DownIndicator ) );
return updateSymbolNode( skinnable, node, Q::DownIndicator ); return updateSymbolNode( skinnable, node, Q::DownIndicator );
} }
case TextPanel: case TextPanelRole:
{ {
return updateBoxNode( skinnable, node, Q::TextPanel ); return updateBoxNode( skinnable, node, Q::TextPanel );
} }
case Text: case TextRole:
{ {
auto spinBox = static_cast< const QskSpinBox* >( skinnable ); auto spinBox = static_cast< const QskSpinBox* >( skinnable );
@ -141,6 +149,16 @@ QRectF QskSpinBoxSkinlet::textPanelRect(
if ( w > 0.0 ) if ( w > 0.0 )
r.setRight( r.right() - spacing - w ); r.setRight( r.right() - spacing - w );
} }
else if ( decoration == Q::ButtonsRight )
{
const auto w1 = subControlRect( skinnable, rect, Q::DownPanel ).width();
if ( w1 > 0.0 )
r.setRight( r.right() - w1 - spacing );
const auto w2 = subControlRect( skinnable, rect, Q::UpPanel ).width();
if ( w2 > 0.0 )
r.setRight( r.right() - w2 - spacing );
}
else else
{ {
const auto w1 = subControlRect( skinnable, rect, Q::DownPanel ).width(); const auto w1 = subControlRect( skinnable, rect, Q::DownPanel ).width();
@ -180,6 +198,30 @@ QRectF QskSpinBoxSkinlet::buttonRect( const QskSkinnable* skinnable,
x = rect.right() - w; x = rect.right() - w;
y = ( subControl == Q::UpPanel ) ? rect.top() : rect.bottom() - h; y = ( subControl == Q::UpPanel ) ? rect.top() : rect.bottom() - h;
} }
else if ( decoration == Q::ButtonsRight )
{
const auto hint = spinBox->strutSizeHint( subControl );
h = hint.height();
if ( h <= 0.0 )
h = rect.height();
w = hint.width();
if ( w <= 0.0 )
w = h;
if( subControl == Q::UpPanel )
{
const auto downRect = buttonRect( skinnable, rect, Q::DownPanel );
x = downRect.left() - w;
}
else
{
x = rect.right() - w;
}
y = 0.5 * ( rect.height() - h );
}
else else
{ {
const auto hint = spinBox->strutSizeHint( subControl ); const auto hint = spinBox->strutSizeHint( subControl );

View File

@ -18,14 +18,15 @@ class QSK_EXPORT QskSpinBoxSkinlet : public QskSkinlet
enum NodeRole enum NodeRole
{ {
TextPanel, PanelRole,
Text, TextPanelRole,
TextRole,
UpPanel, UpPanelRole,
UpIndicator, UpIndicatorRole,
DownPanel, DownPanelRole,
DownIndicator, DownIndicatorRole,
RoleCount RoleCount
}; };

View File

@ -9,6 +9,7 @@
#include "QskBoxBorderMetrics.h" #include "QskBoxBorderMetrics.h"
#include "QskBoxShapeMetrics.h" #include "QskBoxShapeMetrics.h"
#include "QskShadowMetrics.h" #include "QskShadowMetrics.h"
#include "QskStippleMetrics.h"
#include "QskColorFilter.h" #include "QskColorFilter.h"
#include "QskGradient.h" #include "QskGradient.h"
#include "QskMargins.h" #include "QskMargins.h"
@ -46,6 +47,7 @@ static void qskRegisterInterpolator()
qRegisterAnimationInterpolator< QskBoxBorderColors >( QskBoxBorderColors::interpolate ); qRegisterAnimationInterpolator< QskBoxBorderColors >( QskBoxBorderColors::interpolate );
qRegisterAnimationInterpolator< QskTextColors >( QskTextColors::interpolate ); qRegisterAnimationInterpolator< QskTextColors >( QskTextColors::interpolate );
qRegisterAnimationInterpolator< QskShadowMetrics >( QskShadowMetrics::interpolate ); qRegisterAnimationInterpolator< QskShadowMetrics >( QskShadowMetrics::interpolate );
qRegisterAnimationInterpolator< QskStippleMetrics >( QskStippleMetrics::interpolate );
qRegisterAnimationInterpolator< QskArcMetrics >( QskArcMetrics::interpolate ); qRegisterAnimationInterpolator< QskArcMetrics >( QskArcMetrics::interpolate );
} }

View File

@ -16,7 +16,7 @@ class QQuickItem;
class QSizeF; class QSizeF;
class QRectF; class QRectF;
class QskGridLayoutEngine : public QskLayoutEngine2D class QSK_EXPORT QskGridLayoutEngine : public QskLayoutEngine2D
{ {
public: public:
QskGridLayoutEngine(); QskGridLayoutEngine();
@ -61,8 +61,8 @@ class QskGridLayoutEngine : public QskLayoutEngine2D
void invalidateElementCache() override; void invalidateElementCache() override;
void setupChain( Qt::Orientation, void setupChain( Qt::Orientation, const QskLayoutChain::Segments&,
const QskLayoutChain::Segments&, QskLayoutChain& ) const override; QskLayoutChain& ) const override final;
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;

View File

@ -13,7 +13,7 @@
class QskSizePolicy; class QskSizePolicy;
class QskLayoutMetrics; class QskLayoutMetrics;
class QskLayoutElement class QSK_EXPORT QskLayoutElement
{ {
public: public:
QskLayoutElement(); QskLayoutElement();
@ -54,7 +54,7 @@ inline qreal QskLayoutElement::widthForHeight( qreal height ) const
class QQuickItem; class QQuickItem;
class QskItemLayoutElement final : public QskLayoutElement class QSK_EXPORT QskItemLayoutElement final : public QskLayoutElement
{ {
public: public:
QskItemLayoutElement( const QQuickItem* ); QskItemLayoutElement( const QQuickItem* );

View File

@ -15,7 +15,7 @@
class QskLayoutElement; class QskLayoutElement;
class QskLayoutEngine2D class QSK_EXPORT QskLayoutEngine2D
{ {
public: public:
QskLayoutEngine2D(); QskLayoutEngine2D();

View File

@ -16,7 +16,7 @@ class QQuickItem;
class QSizeF; class QSizeF;
class QRectF; class QRectF;
class QskLinearLayoutEngine : public QskLayoutEngine2D class QSK_EXPORT QskLinearLayoutEngine : public QskLayoutEngine2D
{ {
public: public:
QskLinearLayoutEngine( Qt::Orientation, uint dimension ); QskLinearLayoutEngine( Qt::Orientation, uint dimension );
@ -58,8 +58,8 @@ class QskLinearLayoutEngine : public QskLayoutEngine2D
void invalidateElementCache() override; void invalidateElementCache() override;
virtual void setupChain( Qt::Orientation, virtual void setupChain( Qt::Orientation, const QskLayoutChain::Segments&,
const QskLayoutChain::Segments&, QskLayoutChain& ) const override; QskLayoutChain& ) const override final;
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;

View File

@ -345,31 +345,8 @@ void QskSubcontrolLayoutEngine::setGraphicTextElements( const QskSkinnable* skin
having to deal with the details of the layout classes. having to deal with the details of the layout classes.
*/ */
GraphicElement* graphicElement = nullptr; auto graphicElement = appendGraphicElement( skinnable, graphicSubControl, graphicSize );
if ( !graphicSize.isEmpty() && ( graphicSubControl != QskAspect::NoSubcontrol ) ) auto textElement = appendTextElement( skinnable, textSubcontrol, text );
{
graphicElement = dynamic_cast< GraphicElement* >( element( graphicSubControl ) );
if ( graphicElement == nullptr )
{
graphicElement = new GraphicElement( skinnable, graphicSubControl );
m_data->elements.prepend( graphicElement );
}
graphicElement->setSourceSize( graphicSize );
}
TextElement* textElement = nullptr;
if ( !text.isEmpty() && ( textSubcontrol != QskAspect::NoSubcontrol ) )
{
textElement = dynamic_cast< TextElement* >( element( textSubcontrol ) );
if ( textElement == nullptr )
{
textElement = new TextElement( skinnable, textSubcontrol );
m_data->elements.append( textElement );
}
textElement->setText( text );
}
/* /*
Now the difficult part: setting up size policies and the preferred size. Now the difficult part: setting up size policies and the preferred size.
@ -419,6 +396,46 @@ void QskSubcontrolLayoutEngine::setGraphicTextElements( const QskSkinnable* skin
} }
} }
QskSubcontrolLayoutEngine::GraphicElement* QskSubcontrolLayoutEngine::appendGraphicElement( const QskSkinnable* skinnable,
QskAspect::Subcontrol graphicSubcontrol, const QSizeF& graphicSize )
{
GraphicElement* graphicElement = nullptr;
if ( !graphicSize.isEmpty() && ( graphicSubcontrol != QskAspect::NoSubcontrol ) )
{
graphicElement = dynamic_cast< GraphicElement* >( element( graphicSubcontrol ) );
if ( graphicElement == nullptr )
{
graphicElement = new GraphicElement( skinnable, graphicSubcontrol );
m_data->elements.prepend( graphicElement );
}
graphicElement->setSourceSize( graphicSize );
}
return graphicElement;
}
QskSubcontrolLayoutEngine::TextElement* QskSubcontrolLayoutEngine::appendTextElement( const QskSkinnable* skinnable,
QskAspect::Subcontrol textSubcontrol, const QString& text )
{
TextElement* textElement = nullptr;
if ( !text.isEmpty() && ( textSubcontrol != QskAspect::NoSubcontrol ) )
{
textElement = dynamic_cast< TextElement* >( element( textSubcontrol ) );
if ( textElement == nullptr )
{
textElement = new TextElement( skinnable, textSubcontrol );
m_data->elements.append( textElement );
}
textElement->setText( text );
}
return textElement;
}
void QskSubcontrolLayoutEngine::setFixedContent( void QskSubcontrolLayoutEngine::setFixedContent(
QskAspect::Subcontrol subcontrol, Qt::Orientation orientation, Qt::Alignment alignment ) QskAspect::Subcontrol subcontrol, Qt::Orientation orientation, Qt::Alignment alignment )
{ {

View File

@ -127,6 +127,9 @@ class QskSubcontrolLayoutEngine : public QskLayoutEngine2D
QskAspect::Subcontrol, const QString& text, QskAspect::Subcontrol, const QString& text,
QskAspect::Subcontrol, const QSizeF& graphicSize ); QskAspect::Subcontrol, const QSizeF& graphicSize );
GraphicElement* appendGraphicElement( const QskSkinnable*, QskAspect::Subcontrol, const QSizeF& );
TextElement* appendTextElement( const QskSkinnable*, QskAspect::Subcontrol, const QString& );
void setFixedContent( QskAspect::Subcontrol, Qt::Orientation, Qt::Alignment ); void setFixedContent( QskAspect::Subcontrol, Qt::Orientation, Qt::Alignment );
QRectF subControlRect( QskAspect::Subcontrol ) const; QRectF subControlRect( QskAspect::Subcontrol ) const;

544
src/nodes/QskLinesNode.cpp Normal file
View File

@ -0,0 +1,544 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskLinesNode.h"
#include "QskVertex.h"
#include "QskStippleMetrics.h"
#include "QskStippledLineRenderer.h"
#include "QskSGNode.h"
#include <qsgflatcolormaterial.h>
#include <qsgvertexcolormaterial.h>
#include <qtransform.h>
#include <qquickitem.h>
#include <qquickwindow.h>
#include <qline.h>
QSK_QT_PRIVATE_BEGIN
#include <private/qsgnode_p.h>
QSK_QT_PRIVATE_END
namespace
{
inline qreal mapX( const QTransform& t, qreal x )
{
return t.dx() + t.m11() * x;
}
inline qreal mapY( const QTransform& t, qreal y )
{
return t.dy() + t.m22() * y;
}
class Renderer : public QskStippledLineRenderer
{
public:
inline Renderer( const QskStippleMetrics& metrics )
: QskStippledLineRenderer( metrics )
{
}
inline QSGGeometry::Point2D* addDashes( QSGGeometry::Point2D* points,
qreal x1, qreal y1, qreal x2, qreal y2 )
{
m_points = points;
renderLine( x1, y1, x2, y2 );
return m_points;
}
private:
void renderDash( qreal x1, qreal y1, qreal x2, qreal y2 ) override
{
m_points++->set( x1, y1 );
m_points++->set( x2, y2 );
}
QSGGeometry::Point2D* m_points;
};
}
static QSGGeometry::Point2D* qskAddDashes( const QTransform& transform,
int count, const QLineF* lines, const QskStippleMetrics& metrics,
QSGGeometry::Point2D* points )
{
if ( count <= 0 )
return points;
const bool doTransform = !transform.isIdentity();
Renderer renderer( metrics );
for ( int i = 0; i < count; i++ )
{
auto p1 = lines[i].p1();
auto p2 = lines[i].p2();
if ( doTransform )
{
p1 = transform.map( p1 );
p2 = transform.map( p2 );
}
points = renderer.addDashes( points, p1.x(), p1.y(), p2.x(), p2.y() );
}
return points;
}
static QSGGeometry::Point2D* qskAddLines( const QTransform& transform,
int count, const QLineF* lines, QSGGeometry::Point2D* points )
{
if ( count <= 0 )
return points;
const bool doTransform = !transform.isIdentity();
auto vlines = reinterpret_cast< QskVertex::Line* >( points );
for ( int i = 0; i < count; i++ )
{
auto p1 = lines[i].p1();
auto p2 = lines[i].p2();
if ( doTransform )
{
p1 = transform.map( p1 );
p2 = transform.map( p2 );
}
vlines++->setLine( p1.x(), p1.y(), p2.x(), p2.y() );
}
return reinterpret_cast< QSGGeometry::Point2D* >( vlines );
}
class QskLinesNodePrivate final : public QSGGeometryNodePrivate
{
public:
QskLinesNodePrivate()
: geometry( QSGGeometry::defaultAttributes_Point2D(), 0 )
{
geometry.setDrawingMode( QSGGeometry::DrawLines );
geometry.setVertexDataPattern( QSGGeometry::StaticPattern );
}
inline qreal round( bool isHorizontal, qreal v ) const
{
if ( !doRound )
return v;
const auto r2 = 2.0 * devicePixelRatio;
const qreal v0 = isHorizontal ? p0.x() : p0.y();
const int d = qRound( r2 * ( v + v0 ) );
const auto f = ( d % 2 ? d : d - 1 ) / r2;
return f / devicePixelRatio - v0;
}
inline void setLineAttributes( QskLinesNode* node,
const QColor& color, float lineWidth )
{
if ( color != material.color() )
{
material.setColor( color );
node->markDirty( QSGNode::DirtyMaterial );
}
if( lineWidth != geometry.lineWidth() )
geometry.setLineWidth( lineWidth );
}
QSGGeometry geometry;
QSGFlatColorMaterial material;
// position of [0,0] in device coordinates
QPointF p0;
qreal devicePixelRatio = 1.0;
QskHashValue hash = 0.0;
bool dirty = true;
bool doRound = false;
};
QskLinesNode::QskLinesNode()
: QSGGeometryNode( *new QskLinesNodePrivate )
{
Q_D( QskLinesNode );
setGeometry( &d->geometry );
setMaterial( &d->material );
}
QskLinesNode::~QskLinesNode()
{
}
void QskLinesNode::setGlobalPosition( const QQuickItem* item )
{
QPointF p0;
qreal devicePixelRatio = 1.0;
if ( item )
{
p0 = item->mapToGlobal( QPointF() );
if ( auto w = item->window() )
devicePixelRatio = w->devicePixelRatio();
}
setGlobalPosition( p0, devicePixelRatio );
}
void QskLinesNode::setGlobalPosition(
const QPointF& pos, qreal devicePixelRatio )
{
Q_D( QskLinesNode );
if ( d->doRound == false )
{
d->doRound = true;
d->dirty = true;
}
if ( pos != d->p0 || devicePixelRatio != d->devicePixelRatio )
{
d->p0 = pos;
d->devicePixelRatio = devicePixelRatio;
d->dirty = true;
}
}
void QskLinesNode::resetGlobalPosition()
{
Q_D( QskLinesNode );
if ( d->doRound == true )
{
d->doRound = false;
d->dirty = true;
}
}
void QskLinesNode::updateRect( const QColor& color,
qreal lineWidth, const QskStippleMetrics& stippleMetrics,
const QTransform& transform, const QRectF& rect )
{
// using QVarLengthArray instead. TODO ...
updateGrid( color, lineWidth, stippleMetrics, transform,
rect, { rect.left(), rect.right() }, { rect.top(), rect.bottom() } );
}
void QskLinesNode::updateLine( const QColor& color,
qreal lineWidth, const QPointF& p1, const QPointF& p2 )
{
updateLine( color, lineWidth, QskStippleMetrics(), QTransform(), p1, p2 );
}
void QskLinesNode::updateLine( const QColor& color,
qreal lineWidth, const QskStippleMetrics& stippleMetrics,
const QTransform& transform, const QPointF& p1, const QPointF& p2 )
{
if ( p1 == p2 )
{
updateLines( color, lineWidth, stippleMetrics, transform, 0, nullptr );
}
else
{
const QLineF line( p1, p2 );
updateLines( color, lineWidth, stippleMetrics, transform, 1, &line );
}
}
void QskLinesNode::updateLines( const QColor& color,
qreal lineWidth, const QVector< QLineF >& lines )
{
updateLines( color, lineWidth, QskStippleMetrics(),
QTransform(), lines.count(), lines.constData() );
}
void QskLinesNode::updateLines( const QColor& color,
qreal lineWidth, const QskStippleMetrics& stippleMetrics,
const QTransform& transform, const QVector< QLineF >& lines )
{
updateLines( color, lineWidth, stippleMetrics,
transform, lines.count(), lines.constData() );
}
void QskLinesNode::updateLines( const QColor& color,
qreal lineWidth, const QskStippleMetrics& stippleMetrics,
const QTransform& transform, int count, const QLineF* lines )
{
Q_D( QskLinesNode );
if ( !stippleMetrics.isValid() || !color.isValid()
|| color.alpha() == 0 || count == 0 )
{
QskSGNode::resetGeometry( this );
return;
}
QskHashValue hash = 9784;
hash = stippleMetrics.hash( hash );
hash = qHash( transform, hash );
hash = qHashBits( lines, count * sizeof( QLineF ) );
if ( hash != d->hash )
{
d->dirty = true;
d->hash = hash;
}
if( d->dirty )
{
updateGeometry( stippleMetrics, transform, count, lines );
markDirty( QSGNode::DirtyGeometry );
d->dirty = false;
}
d->setLineAttributes( this, color, lineWidth );
}
void QskLinesNode::updateGrid( const QColor& color,
qreal lineWidth, const QskStippleMetrics& stippleMetrics,
const QTransform& transform, const QRectF& rect,
const QVector< qreal >& xValues, const QVector< qreal >& yValues )
{
Q_D( QskLinesNode );
if ( !stippleMetrics.isValid() || !color.isValid() || color.alpha() == 0 )
{
QskSGNode::resetGeometry( this );
return;
}
QskHashValue hash = 9784;
hash = stippleMetrics.hash( hash );
hash = qHash( transform, hash );
hash = qHashBits( &rect, sizeof( QRectF ), hash );
hash = qHash( xValues, hash );
hash = qHash( yValues, hash );
if ( hash != d->hash )
{
d->dirty = true;
d->hash = hash;
}
if( d->dirty )
{
updateGeometry( stippleMetrics, transform, rect, xValues, yValues );
markDirty( QSGNode::DirtyGeometry );
d->dirty = false;
}
d->setLineAttributes( this, color, lineWidth );
}
void QskLinesNode::updateGeometry( const QskStippleMetrics& stippleMetrics,
const QTransform& transform, int count, const QLineF* lines )
{
Q_D( QskLinesNode );
auto& geom = d->geometry;
QSGGeometry::Point2D* points = nullptr;
if ( stippleMetrics.isSolid() )
{
using namespace QskVertex;
geom.allocate( 2 * count );
points = geom.vertexDataAsPoint2D();
points = qskAddLines( transform, count, lines, points );
}
else
{
const bool doTransform = !transform.isIdentity();
Renderer renderer( stippleMetrics );
int lineCount = 0;
for ( int i = 0; i < count; i++ )
{
auto p1 = lines[i].p1();
auto p2 = lines[i].p2();
if ( doTransform )
{
p1 = transform.map( p1 );
p2 = transform.map( p2 );
}
lineCount += renderer.dashCount( p1, p2 );
}
d->geometry.allocate( 2 * lineCount );
points = d->geometry.vertexDataAsPoint2D();
points = qskAddDashes( transform,
count, lines, stippleMetrics, points );
}
Q_ASSERT( geom.vertexCount() == ( points - geom.vertexDataAsPoint2D() ) );
}
void QskLinesNode::updateGeometry(
const QskStippleMetrics& stippleMetrics,
const QTransform& transform, const QRectF& rect,
const QVector< qreal >& xValues, const QVector< qreal >& yValues )
{
Q_D( QskLinesNode );
auto& geom = d->geometry;
const auto y1 = mapY( transform, rect.top() );
const auto y2 = mapY( transform, rect.bottom() );
const auto x1 = mapX( transform, rect.left() );
const auto x2 = mapX( transform, rect.right() );
QSGGeometry::Point2D* points = nullptr;
if ( stippleMetrics.isSolid() )
{
using namespace QskVertex;
geom.allocate( 2 * ( xValues.count() + yValues.count() ) );
points = geom.vertexDataAsPoint2D();
points = setSolidLines( Qt::Vertical, y1, y2,
transform, xValues.count(), xValues.constData(), points );
points = setSolidLines( Qt::Horizontal, x1, x2,
transform, yValues.count(), yValues.constData(), points );
}
else
{
Renderer renderer( stippleMetrics );
const auto countX = renderer.dashCount( 0.0, y1, 0.0, y2 );
const auto countY = renderer.dashCount( x1, 0.0, x2, 0.0 );
const auto count = xValues.count() * countX + yValues.count() * countY;
d->geometry.allocate( 2 * count );
points = d->geometry.vertexDataAsPoint2D();
points = setStippledLines( Qt::Vertical, y1, y2,
transform, xValues.count(), xValues.constData(),
stippleMetrics, points );
points = setStippledLines( Qt::Horizontal, x1, x2,
transform, yValues.count(), yValues.constData(),
stippleMetrics, points );
}
Q_ASSERT( geom.vertexCount() == ( points - geom.vertexDataAsPoint2D() ) );
}
QSGGeometry::Point2D* QskLinesNode::setStippledLines(
Qt::Orientation orientation, qreal v1, qreal v2,
const QTransform& transform, int count, const qreal* values,
const QskStippleMetrics& stippleMetrics, QSGGeometry::Point2D* points ) const
{
Q_D( const QskLinesNode );
if ( count <= 0 )
return points;
Renderer renderer( stippleMetrics );
// Calculating the dashes for the first line
const auto line0 = points;
int dashCount = 0;
if ( orientation == Qt::Vertical )
{
auto x = mapX( transform, values[0] );
x = d->round( true, x );
points = renderer.addDashes( points, x, v1, x, v2 );
dashCount = points - line0;
}
else
{
auto y = mapY( transform, values[0] );
y = d->round( false, y );
points = renderer.addDashes( points, v1, y, v2, y );
dashCount = points - line0;
}
// all other dashes are translations of the dashes of the first line
if ( orientation == Qt::Vertical )
{
for ( int i = 1; i < count; i++ )
{
auto x = mapX( transform, values[i] );
x = d->round( true, x );
for ( int j = 0; j < dashCount; j++ )
points++->set( x, line0[j].y );
}
}
else
{
for ( int i = 1; i < count; i++ )
{
auto y = mapY( transform, values[i] );
y = d->round( false, y );
for ( int j = 0; j < dashCount; j++ )
points++->set( line0[j].x, y );
}
}
return points;
}
QSGGeometry::Point2D* QskLinesNode::setSolidLines(
Qt::Orientation orientation, qreal v1, qreal v2,
const QTransform& transform, int count, const qreal* values,
QSGGeometry::Point2D* points ) const
{
Q_D( const QskLinesNode );
if ( count <= 0 )
return points;
auto lines = reinterpret_cast< QskVertex::Line* >( points );
if ( orientation == Qt::Vertical )
{
for ( int i = 0; i < count; i++ )
{
auto x = mapX( transform, values[i] );
x = d->round( true, x );
lines++->setVLine( x, v1, v2 );
}
}
else
{
for ( int i = 0; i < count; i++ )
{
auto y = mapY( transform, values[i] );
y = d->round( false, y );
lines++->setHLine( v1, v2, y );
}
}
return reinterpret_cast< QSGGeometry::Point2D* >( lines );
}

80
src/nodes/QskLinesNode.h Normal file
View File

@ -0,0 +1,80 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_LINES_NODE_H
#define QSK_LINES_NODE_H
#include "QskGlobal.h"
#include <qsgnode.h>
#include <qvector.h>
class QskIntervalF;
class QskStippleMetrics;
class QTransform;
class QPointF;
class QLineF;
class QQuickItem;
class QskLinesNodePrivate;
/*
A node for stippled or solid lines.
For the moment limited to horizontal/vertical lines: TODO
*/
class QSK_EXPORT QskLinesNode : public QSGGeometryNode
{
public:
QskLinesNode();
~QskLinesNode() override;
void setGlobalPosition( const QPointF&, qreal devicePixelRatio );
void setGlobalPosition( const QQuickItem* );
void resetGlobalPosition();
void updateGrid( const QColor&, qreal lineWidth,
const QskStippleMetrics&, const QTransform&, const QRectF&,
const QVector< qreal >&, const QVector< qreal >& );
void updateRect( const QColor&, qreal lineWidth,
const QskStippleMetrics&, const QTransform&, const QRectF& );
void updateLine( const QColor&, qreal lineWidth,
const QPointF&, const QPointF& );
void updateLine( const QColor&, qreal lineWidth,
const QskStippleMetrics&, const QTransform&,
const QPointF&, const QPointF& );
void updateLines( const QColor&, qreal lineWidth, const QVector< QLineF >& );
void updateLines( const QColor&, qreal lineWidth,
const QskStippleMetrics&, const QTransform&, const QVector< QLineF >& );
private:
void updateLines( const QColor&, qreal lineWidth, const QskStippleMetrics&,
const QTransform&, int count, const QLineF* );
void updateGeometry( const QskStippleMetrics&, const QTransform&,
int count, const QLineF* );
void updateGeometry(
const QskStippleMetrics&, const QTransform&, const QRectF&,
const QVector< qreal >&, const QVector< qreal >& );
QSGGeometry::Point2D* setSolidLines(
Qt::Orientation, qreal, qreal,
const QTransform&, int count, const qreal* values,
QSGGeometry::Point2D* ) const;
QSGGeometry::Point2D* setStippledLines(
Qt::Orientation, qreal, qreal,
const QTransform&, int count, const qreal* values,
const QskStippleMetrics&, QSGGeometry::Point2D* ) const;
Q_DECLARE_PRIVATE( QskLinesNode )
};
#endif

View File

@ -85,7 +85,7 @@ namespace QskSGNode
return static_cast< Node* >( node ); return static_cast< Node* >( node );
} }
void resetGeometry( QSGGeometryNode* ); QSK_EXPORT void resetGeometry( QSGGeometryNode* );
} }
#endif #endif

View File

@ -0,0 +1,154 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#include "QskStippledLineRenderer.h"
QSK_QT_PRIVATE_BEGIN
#include <private/qstroker_p.h>
QSK_QT_PRIVATE_END
namespace
{
/*
Thanks to the hooks of the stroker classes we can make use
of QDashStroker without having to deal with the overhead of
QPainterPaths. But it might be worth to check if this could
be done in a shader. TODO ...
*/
class DashStroker : public QDashStroker
{
public:
DashStroker( QskStippledLineRenderer* renderer )
: QDashStroker( nullptr )
, m_renderer( renderer )
{
setDashOffset( renderer->metrics().offset() );
setDashPattern( renderer->metrics().pattern() );
m_elements.reserve( 2 );
}
void renderDashes( qreal x1, qreal y1, qreal x2, qreal y2 )
{
if ( ( x1 == x2 ) && ( y1 == y2 ) )
return;
setMoveToHook( moveTo );
setLineToHook( lineTo );
begin( this );
m_elements.add( { QPainterPath::MoveToElement, x1, y1 } );
m_elements.add( { QPainterPath::LineToElement, x2, y2 } );
processCurrentSubpath();
end();
}
qsizetype dashCount( qreal x1, qreal y1, qreal x2, qreal y2 )
{
if ( ( x1 == x2 ) && ( y1 == y2 ) )
return 0;
/*
There should be a faster way to calculate the
number of points. TODO ...
*/
setMoveToHook( countMoveTo );
setLineToHook( countLineTo );
m_count = 0;
begin( this );
m_elements.add( { QPainterPath::MoveToElement, x1, y1 } );
m_elements.add( { QPainterPath::LineToElement, x2, y2 } );
processCurrentSubpath();
end();
return m_count;
}
private:
static void moveTo( qfixed x, qfixed y, void* data )
{
auto stroker = reinterpret_cast< DashStroker* >( data );
stroker->m_x = x;
stroker->m_y = y;
}
static void lineTo( qfixed x, qfixed y, void* data )
{
auto stroker = reinterpret_cast< DashStroker* >( data );
stroker->m_renderer->renderDash( stroker->m_x, stroker->m_y, x, y );
}
static void countMoveTo( qfixed, qfixed, void* )
{
}
static void countLineTo( qfixed, qfixed, void* data )
{
auto stroker = reinterpret_cast< DashStroker* >( data );
stroker->m_count++;
}
QskStippledLineRenderer* m_renderer;
qsizetype m_count = 0;
qreal m_x, m_y;
};
}
QskStippledLineRenderer::QskStippledLineRenderer( const QskStippleMetrics& metrics )
: m_metrics( metrics )
{
}
QskStippledLineRenderer::~QskStippledLineRenderer()
{
}
qsizetype QskStippledLineRenderer::dashCount(
const QPointF& p1, const QPointF& p2 ) const
{
return dashCount( p1.x(), p1.y(), p2.x(), p2.y() );
}
qsizetype QskStippledLineRenderer::dashCount( const QLineF& line ) const
{
return dashCount( line.x1(), line.y1(), line.x2(), line.y2() );
}
qsizetype QskStippledLineRenderer::dashCount(
qreal x1, qreal y1, qreal x2, qreal y2 ) const
{
auto that = const_cast< QskStippledLineRenderer* >( this );
return DashStroker( that ).dashCount( x1, y1, x2, y2 );
}
void QskStippledLineRenderer::renderLine( const QPointF& p1, const QPointF& p2 )
{
renderLine( p1.x(), p1.y(), p2.x(), p2.y() );
}
void QskStippledLineRenderer::renderLine( const QLineF& line )
{
renderLine( line.x1(), line.y1(), line.x2(), line.y2() );
}
void QskStippledLineRenderer::renderLine( qreal x1, qreal y1, qreal x2, qreal y2 )
{
DashStroker( this ).renderDashes( x1, y1, x2, y2 );
}
void QskStippledLineRenderer::renderDash( qreal, qreal, qreal, qreal )
{
// nop
}

View File

@ -0,0 +1,47 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* SPDX-License-Identifier: BSD-3-Clause
*****************************************************************************/
#ifndef QSK_STIPPLED_LINE_RENDERER_H
#define QSK_STIPPLED_LINE_RENDERER_H
#include "QskStippleMetrics.h"
class QLineF;
class QPointF;
/*
A wrapper for the non public QDashStroker class, tailored for
splitting lines into dashes/dots. It is faster than QPainterPathStroker
( no QPainterPath involved ), but supports simple lines only.
*/
class QskStippledLineRenderer
{
public:
QskStippledLineRenderer( const QskStippleMetrics& );
virtual ~QskStippledLineRenderer();
qsizetype dashCount( qreal x1, qreal y1, qreal x2, qreal y2 ) const;
qsizetype dashCount( const QPointF&, const QPointF& ) const;
qsizetype dashCount( const QLineF& ) const;
void renderLine( qreal x1, qreal y1, qreal x2, qreal y2 );
void renderLine( const QPointF&, const QPointF& );
void renderLine( const QLineF& );
const QskStippleMetrics& metrics() const;
// nop: to be overloaded
virtual void renderDash( qreal x1, qreal y1, qreal x2, qreal y2 );
private:
const QskStippleMetrics m_metrics;
};
inline const QskStippleMetrics& QskStippledLineRenderer::metrics() const
{
return m_metrics;
}
#endif

View File

@ -86,6 +86,8 @@ QskStrokeNode::QskStrokeNode()
setMaterial( qskMaterialColorVertex ); setMaterial( qskMaterialColorVertex );
} }
QskStrokeNode::~QskStrokeNode() = default;
void QskStrokeNode::setRenderHint( RenderHint renderHint ) void QskStrokeNode::setRenderHint( RenderHint renderHint )
{ {
Q_D( QskStrokeNode ); Q_D( QskStrokeNode );

View File

@ -19,6 +19,7 @@ class QSK_EXPORT QskStrokeNode : public QSGGeometryNode
{ {
public: public:
QskStrokeNode(); QskStrokeNode();
~QskStrokeNode() override;
/* /*
We only support monochrome pens ( QPen::color() ) and using a We only support monochrome pens ( QPen::color() ) and using a

View File

@ -33,7 +33,7 @@ target_include_directories(${target} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
if(ENABLE_ENSURE_SKINS) if(ENABLE_ENSURE_SKINS)
target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/skins) target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/skins)
target_compile_definitions(${target} PRIVATE ENSURE_SKINS) target_compile_definitions(${target} PRIVATE ENSURE_SKINS)
target_link_libraries(${target} PRIVATE squiekskin material3skin windowsskin) target_link_libraries(${target} PRIVATE squiekskin material3skin fluent2skin)
endif() endif()
set(HIDE_SYSTEM_FONTS ON) set(HIDE_SYSTEM_FONTS ON)

View File

@ -51,11 +51,13 @@ static bool pluginPath = initPluginPath();
#include <squiek/QskSquiekSkinFactory.h> #include <squiek/QskSquiekSkinFactory.h>
#include <material3/QskMaterial3SkinFactory.h> #include <material3/QskMaterial3SkinFactory.h>
#include <windows/QskWindowsSkinFactory.h> #include <fluent2/QskFluent2SkinFactory.h>
static void initSkins() static void initSkins()
{ {
if ( qskSkinManager->skinNames().isEmpty() ) auto skinNames = qskSkinManager->skinNames();
if ( skinNames.isEmpty() )
{ {
/* /*
To avoid having problems with not finding the skin plugins To avoid having problems with not finding the skin plugins
@ -64,20 +66,15 @@ static bool pluginPath = initPluginPath();
qskSkinManager->registerFactory( "SquiekFactory", new QskSquiekSkinFactory() ); qskSkinManager->registerFactory( "SquiekFactory", new QskSquiekSkinFactory() );
qskSkinManager->registerFactory( "Material3Factory", new QskMaterial3SkinFactory() ); qskSkinManager->registerFactory( "Material3Factory", new QskMaterial3SkinFactory() );
qskSkinManager->registerFactory( "WindowsFactory", new QskWindowsSkinFactory() ); qskSkinManager->registerFactory( "Fluent2Factory", new QskFluent2SkinFactory() );
qWarning() << "Couldn't find skin plugins, adding some manually."; qWarning() << "Couldn't find skin plugins, adding some manually.";
skinNames = qskSkinManager->skinNames();
} }
#if 1 if ( !skinNames.isEmpty() )
/* qskSetup->setSkin( skinNames[0] );
QskSkinManager is sorting in alphabetic order, but we want to have
the light material skin as initial skin. TODO ...
*/
const auto names = qskSkinManager->skinNames();
if ( names.count() > 1 )
qskSetup->setSkin( names[1] );
#endif
} }
Q_COREAPP_STARTUP_FUNCTION( initSkins ) Q_COREAPP_STARTUP_FUNCTION( initSkins )