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 )
{
auto radioBox1 = new QskRadioBox( { "One", "Two", "Three" }, this );
radioBox1->setSelectedIndex( 0 );
radioBox1->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
auto radioBox2 = new QskRadioBox( { "One", "Two", "Three" }, this );

View File

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

View File

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

View File

@ -30,6 +30,31 @@
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
{
public:
@ -98,26 +123,8 @@ namespace
QBrush PaintedArcNode::fillBrush( const QskGradient& gradient,
const QRectF& rect, qreal startAngle, qreal spanAngle ) const
{
const auto stops = gradient.stops();
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 auto qGradient = qskQConicalGradient(
gradient.stops(), startAngle, spanAngle );
const qreal sz = qMax( rect.width(), rect.height() );
const qreal sx = rect.width() / sz;
@ -332,15 +339,6 @@ QSGNode* CircularChartSkinlet::updateArcSegmentNode(
QSGNode* node, qreal borderWidth, const QColor& borderColor,
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
auto arcNode = static_cast< PaintedArcNode* >( node );
if ( arcNode == nullptr )
@ -349,10 +347,19 @@ QSGNode* CircularChartSkinlet::updateArcSegmentNode(
const auto chart = static_cast< const CircularChart* >( skinnable );
arcNode->setArcData( m_data->closedArcRect, metrics,
borderWidth, borderColor, fillGradient, chart->window() );
borderWidth, borderColor, gradient, chart->window() );
#else
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 );
if ( arcNode == nullptr )
arcNode = new QskArcNode();

View File

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

View File

@ -11,73 +11,14 @@
#include <QskBoxShapeMetrics.h>
#include <QskTextColors.h>
#include <QskTextOptions.h>
#include <QskLinesNode.h>
#include <QskFunctions.h>
#include <QskSGNode.h>
#include <QFontMetrics>
#include <QLineF>
#include <QSGFlatColorMaterial>
#include <QSGGeometryNode>
#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 )
: QskSkinlet( skin )
{
@ -141,22 +82,14 @@ QSGNode* DialSkinlet::updateLabelsNode(
if ( labels.count() <= 1 )
return nullptr;
auto ticksNode = static_cast< TicksNode* >( node );
if ( ticksNode == nullptr )
ticksNode = new TicksNode();
auto ticksNode = QskSGNode::ensureNode< QskLinesNode >( node );
const auto color = dial->color( Q::TickLabels );
ticksNode->setColor( color );
const auto startAngle = dial->minimum();
const auto endAngle = dial->maximum();
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 );
const auto center = scaleRect.center();
@ -175,6 +108,7 @@ QSGNode* DialSkinlet::updateLabelsNode(
// Create a series of tickmarks from minimum to maximum
auto labelNode = ticksNode->firstChild();
QVector< QLineF > ticks;
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 yEnd = center.y() + needleRadius * sin;
vertexData[ 0 ].set( xStart, yStart );
vertexData[ 1 ].set( xEnd, yEnd );
vertexData += 2;
ticks += QLineF( xStart, yStart, xEnd, yEnd );
const auto& text = labels.at( i );
@ -220,10 +151,7 @@ QSGNode* DialSkinlet::updateLabelsNode(
}
}
geometry->setLineWidth( tickSize.width() );
geometry->markVertexDataDirty();
ticksNode->markDirty( QSGNode::DirtyGeometry );
ticksNode->updateLines( color, tickSize.width(), ticks );
return ticksNode;
}
@ -233,15 +161,13 @@ QSGNode* DialSkinlet::updateNeedleNode(
{
using Q = Dial;
auto needleNode = static_cast< NeedleNode* >( node );
if ( needleNode == nullptr )
needleNode = new NeedleNode();
const auto line = needlePoints( dial );
const auto color = dial->color( Q::Needle );
const auto width = dial->metric( Q::Needle | QskAspect::Size );
needleNode->setData( line, width * 2 );
needleNode->setColor( dial->color( Q::Needle ) );
const auto line = needlePoints( dial );
auto needleNode = QskSGNode::ensureNode< QskLinesNode >( node );
needleNode->updateLine( color, width * 2, line.p1(), line.p2() );
return needleNode;
}

View File

@ -1,3 +1,3 @@
add_subdirectory(squiek)
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
*****************************************************************************/
#ifndef QSK_WINDOWS_GLOBAL_H
#define QSK_WINDOWS_GLOBAL_H
#ifndef QSK_FLUENT2_GLOBAL_H
#define QSK_FLUENT2_GLOBAL_H
#include "QskGlobal.h"
#ifdef QSK_DLL
#if defined( QSK_WINDOWS_MAKEDLL ) // create a DLL library
#define QSK_WINDOWS_EXPORT Q_DECL_EXPORT
#if defined( QSK_FLUENT2_MAKEDLL ) // create a DLL library
#define QSK_FLUENT2_EXPORT Q_DECL_EXPORT
#else // use a DLL library
#define QSK_WINDOWS_EXPORT Q_DECL_IMPORT
#define QSK_FLUENT2_EXPORT Q_DECL_IMPORT
#endif
#endif // QSK_DLL
#ifndef QSK_WINDOWS_EXPORT
#define QSK_WINDOWS_EXPORT
#ifndef QSK_FLUENT2_EXPORT
#define QSK_FLUENT2_EXPORT
#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
*****************************************************************************/
#include "QskWindowsSkin.h"
#include "QskFluent2Skin.h"
#include <QskSkinHintTableEditor.h>
@ -54,14 +54,18 @@
#include <QGuiApplication>
#include <QScreen>
static const int qskDuration = 150;
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
{
public:
Editor( QskSkinHintTable* table, const QskWindowsTheme& palette )
Editor( QskSkinHintTable* table, const QskFluent2Theme& palette )
: QskSkinHintTableEditor( table )
, theme( palette )
{
@ -99,13 +103,21 @@ namespace
QskGraphic symbol( const char* name ) const
{
const QString path = QStringLiteral( ":windows/icons/qvg/" )
const QString path = QStringLiteral( ":fluent2/icons/qvg/" )
+ name + QStringLiteral( ".qvg" );
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,
@ -121,12 +133,6 @@ namespace
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()
@ -189,9 +195,9 @@ void Editor::setupCheckBox()
const auto checkMark = symbol( "checkmark" );
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 );
@ -205,26 +211,89 @@ void Editor::setupCheckBox()
setBoxBorderColors( Q::Box | Q::Pressed, theme.palette.strokeColor.controlStrongStroke.disabled );
setGradient( 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 );
setBoxBorderColors( Q::Box | Q::Disabled, theme.palette.strokeColor.controlStrongStroke.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 );
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 );
}
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()
{
using Q = QskDialogButtonBox;
setPadding( Q::Panel, 24 );
setGradient( Q::Panel, theme.palette.background.fillColor.solidBackground.base );
setPadding(Q::Panel, 20 );
}
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()
@ -239,7 +308,7 @@ void Editor::setupMenu()
{
using Q = QskMenu;
setPadding( Q::Panel, { 16, 6, 16, 6 } );
setPadding( Q::Panel, { 4, 6, 4, 6 } );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxBorderColors( Q::Panel, theme.palette.strokeColor.surfaceStroke.flyout );
setBoxShape( Q::Panel, 7 );
@ -250,8 +319,23 @@ void Editor::setupMenu()
setPadding( Q::Segment, { 0, 10, 0, 10 } );
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 );
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 8, 8, 0, 8 } );
setGraphicRole( Q::Icon, QskFluent2Skin::GraphicRoleFillColorTextPrimary );
}
void Editor::setupPageIndicator()
@ -260,60 +344,62 @@ void Editor::setupPageIndicator()
void Editor::setupPopup()
{
using Q = QskPopup;
setGradient( Q::Overlay, theme.palette.background.fillColor.smoke.defaultColor );
}
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()
{
using Q = QskPushButton;
using W = QskWindowsSkin;
using W = QskFluent2Skin;
setStrutSize( Q::Panel, { 120, 32 } );
setBoxShape( Q::Panel, 4 );
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
// gallery app, let's define their style here as well:
setStrutSize( Q::Icon, 12, 12 );
setPadding( Q::Icon, { 0, 0, 8, 0 } );
setFontRole( Q::Text, QskWindowsSkin::Body );
setFontRole( Q::Text, QskFluent2Skin::Body );
// Accent buttons:
const QRgb accentRestBorderColor1 = flattenedColor( theme.palette.elevation.accentControl.border[ 0 ],
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 } );
setBoxBorderGradient( Q::Panel | W::Accent, theme.palette.elevation.accentControl.border,
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 );
setGraphicRole( Q::Icon | W::Accent, QskWindowsSkin::GraphicRoleFillColorTextOnAccentPrimary );
setGraphicRole( Q::Icon | W::Accent, QskFluent2Skin::GraphicRoleFillColorTextOnAccentPrimary );
const QRgb accentHoveredBorderColor1 = flattenedColor( theme.palette.elevation.accentControl.border[ 0 ],
theme.palette.fillColor.accent.secondary );
setBoxBorderGradient( Q::Panel | W::Accent | Q::Hovered, theme.palette.elevation.accentControl.border,
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::Pressed, theme.palette.fillColor.accent.tertiary );
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,
theme.palette.fillColor.accent.tertiary );
@ -323,34 +409,24 @@ void Editor::setupPushButton()
setGradient( Q::Panel | W::Accent | Q::Disabled, theme.palette.fillColor.accent.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 );
// Standard buttons:
const QRgb standardRestBorderColor1 = flattenedColor( theme.palette.elevation.control.border[ 0 ],
theme.palette.fillColor.control.defaultColor );
setBoxBorderGradient( Q::Panel, theme.palette.elevation.control.border,
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 );
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 ],
theme.palette.fillColor.control.secondary );
setBoxBorderGradient( Q::Panel | Q::Hovered, theme.palette.elevation.control.border,
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 );
@ -362,7 +438,7 @@ void Editor::setupPushButton()
setGradient( Q::Panel | Q::Pressed, theme.palette.fillColor.control.tertiary );
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,
@ -372,7 +448,7 @@ void Editor::setupPushButton()
setGradient( Q::Panel | Q::Disabled, theme.palette.fillColor.control.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()
@ -385,7 +461,7 @@ void Editor::setupRadioBox()
setStrutSize( Q::CheckIndicatorPanel, { 20, 20 } );
setBoxShape( Q::CheckIndicatorPanel, 100, Qt::RelativeSize );
setBoxBorderMetrics( Q::CheckIndicatorPanel, 1 );
setFontRole( Q::Text, QskWindowsSkin::Body );
setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary );
// Rest
@ -402,14 +478,9 @@ void Editor::setupRadioBox()
setBoxBorderMetrics( Q::CheckIndicator | Q::Selected, 1 );
setGradient( Q::CheckIndicator | Q::Selected, theme.palette.fillColor.textOnAccent.primary );
const QRgb panelRestBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ],
theme.palette.fillColor.accent.defaultColor );
setBoxBorderGradient( Q::CheckIndicator | Q::Selected, theme.palette.elevation.circle.border,
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
@ -418,14 +489,8 @@ void Editor::setupRadioBox()
setGradient( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, theme.palette.fillColor.accent.secondary );
setPadding( Q::CheckIndicatorPanel | Q::Hovered | Q::Selected, { 4, 4 } ); // indicator "strut size"
const QRgb panelHoveredBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ],
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 } );
setBoxBorderGradient( Q::CheckIndicator | Q::Hovered, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.secondary );
// Pressed
@ -444,14 +509,8 @@ void Editor::setupRadioBox()
setPadding( Q::CheckIndicatorPanel | Q::Pressed | Q::Selected, { 6, 6 } ); // indicator "strut size"
setBoxBorderMetrics( Q::CheckIndicator | Q::Pressed, 1 );
const QRgb panelPressedBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ],
theme.palette.fillColor.accent.tertiary ); // ### calculate those colors at skin construction time
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 } );
setBoxBorderGradient( Q::CheckIndicator | Q::Pressed | Q::Selected, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.tertiary );
// Disabled
@ -476,6 +535,57 @@ void Editor::setupScrollView()
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()
@ -484,10 +594,107 @@ void Editor::setupSeparator()
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()
{
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()
@ -511,10 +718,10 @@ void Editor::setupTabButton()
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 );
setFontRole( Q::Text | Q::Checked, QskWindowsSkin::BodyStrong );
setFontRole( Q::Text | Q::Checked, QskFluent2Skin::BodyStrong );
setColor( Q::Text | Q::Checked, theme.palette.fillColor.text.primary );
setGradient( Q::Panel | Q::Hovered, theme.palette.fillColor.subtle.secondary );
@ -535,13 +742,58 @@ void Editor::setupTextLabel()
setPadding( Q::Panel, 10 );
setFontRole( Q::Text, QskWindowsSkin::Body );
setFontRole( Q::Text, QskFluent2Skin::Body );
setColor( Q::Text, theme.palette.fillColor.text.primary );
}
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()
@ -573,14 +825,8 @@ void Editor::setupSwitchButton()
setGradient( Q::Handle, theme.palette.strokeColor.controlStrongStroke.defaultColor );
setGradient( Q::Handle | Q::Checked, theme.palette.fillColor.textOnAccent.primary );
const QRgb handleRestBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ],
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 } );
setBoxBorderGradient( Q::Handle | Q::Checked, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.defaultColor );
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 );
// Handle | Hovered | Checked is the same as in Rest state
const QRgb handleHoveredBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ],
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 } );
setBoxBorderGradient( Q::Handle | Q::Hovered | Q::Checked, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.secondary );
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 );
// Handle | Pressed | Checked is the same as in Rest state
const QRgb handlePressedBorderColor1 = flattenedColor( theme.palette.elevation.circle.border[ 0 ],
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 } );
setBoxBorderGradient( Q::Handle | Q::Pressed | Q::Checked, theme.palette.elevation.circle.border,
theme.palette.fillColor.accent.tertiary );
setGradient( Q::Groove | Q::Disabled, theme.palette.fillColor.controlAlt.disabled );
@ -634,15 +868,46 @@ void Editor::setupSwitchButton()
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()
{
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 )
: QskWindowsTheme( lightness,
{ // default Windows accent colors:
QskFluent2Theme::QskFluent2Theme( Theme lightness )
: QskFluent2Theme( lightness,
{ // default Fluent accent colors:
0xff98ecfe,
0xff60ccfe,
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 )
{
@ -727,7 +992,7 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors
QskRgb::toTransparentF( 0xff000000, 0.1622 ) };
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 ),
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.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.alt = 0xffffffff;
@ -868,7 +1133,8 @@ QskWindowsTheme::QskWindowsTheme( Theme theme, std::array< QRgb, NumAccentColors
QskRgb::toTransparentF( 0xffffffff, 0.0698 ) };
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 ),
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.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.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 )
{
setupFonts();
@ -950,11 +1216,11 @@ QskWindowsSkin::QskWindowsSkin( const QskWindowsTheme& palette, QObject* parent
editor.setup();
}
QskWindowsSkin::~QskWindowsSkin()
QskFluent2Skin::~QskFluent2Skin()
{
}
void QskWindowsSkin::setupFonts()
void QskFluent2Skin::setupFonts()
{
static QString fontName( QStringLiteral( "Segoe UI Variable" ) );
Inherited::setupFonts( fontName );
@ -969,7 +1235,7 @@ void QskWindowsSkin::setupFonts()
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;
colorFilter.setMask( QskRgb::RGBAMask );
@ -978,7 +1244,7 @@ void QskWindowsSkin::setGraphicColor( GraphicRole role, QRgb rgb )
setGraphicFilter( role, colorFilter );
}
void QskWindowsSkin::setupGraphicFilters( const QskWindowsTheme& theme )
void QskFluent2Skin::setupGraphicFilters( const QskFluent2Theme& theme )
{
setGraphicColor( GraphicRoleFillColorTextDisabled, theme.palette.fillColor.text.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 );
}
#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
*****************************************************************************/
#ifndef QSK_WINDOWS_SKIN_H
#define QSK_WINDOWS_SKIN_H
#ifndef QSK_FLUENT2_SKIN_H
#define QSK_FLUENT2_SKIN_H
#include "QskWindowsGlobal.h"
#include "QskFluent2Global.h"
#include <QskBoxShapeMetrics.h>
#include <QskGradient.h>
@ -15,7 +15,7 @@
#include <array>
class QSK_WINDOWS_EXPORT QskWindowsTheme
class QSK_FLUENT2_EXPORT QskFluent2Theme
{
public:
enum Theme
@ -37,8 +37,10 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
NumAccentColors
};
QskWindowsTheme( Theme );
QskWindowsTheme( Theme, std::array< QRgb, NumAccentColors > );
QskFluent2Theme( Theme );
QskFluent2Theme( Theme, std::array< QRgb, NumAccentColors > );
typedef std::array< QRgb, 2 > BorderGradient;
struct FillColor
{
@ -156,23 +158,23 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
{
struct Control
{
std::array< QRgb, 2 > border;
BorderGradient border;
};
struct Circle
{
std::array< QRgb, 2 > border;
BorderGradient border;
};
struct TextControl
{
std::array< QRgb, 2 > border;
std::array< QRgb, 2 > borderFocused;
BorderGradient border;
BorderGradient borderFocused;
};
struct AccentControl
{
std::array< QRgb, 2 > border;
BorderGradient border;
};
Control control;
@ -242,7 +244,7 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
QRgb tertiary;
};
struct Stroke
struct Smoke
{
QRgb defaultColor;
};
@ -289,7 +291,7 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
};
CardBackground cardBackground;
Stroke stroke;
Smoke smoke;
Layer layer;
LayerOnAcrylic layerOnAcrylic;
LayerOnAccentAcrylic layerOnAccentAcrylic;
@ -327,15 +329,15 @@ class QSK_WINDOWS_EXPORT QskWindowsTheme
Shadow shadow;
};
class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin
class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin
{
Q_OBJECT
using Inherited = QskSkin;
public:
QskWindowsSkin( const QskWindowsTheme&, QObject* parent = nullptr );
~QskWindowsSkin() override;
QskFluent2Skin( const QskFluent2Theme&, QObject* parent = nullptr );
~QskFluent2Skin() override;
enum GraphicRole
{
@ -349,14 +351,14 @@ class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin
enum FontRole
{
Caption = QskSkin::HugeFont + 1, // ### define QskSkin enums
Body,
BodyStrong,
BodyLarge,
Subtitle,
Title,
Caption = TinyFont,
Body = DefaultFont,
BodyStrong = SmallFont,
BodyLarge = MediumFont,
Subtitle = LargeFont,
Title = HugeFont,
TitleLarge,
Display
Display,
};
static constexpr QskAspect::Variation Standard = QskAspect::NoVariation;
@ -364,7 +366,7 @@ class QSK_WINDOWS_EXPORT QskWindowsSkin : public QskSkin
private:
void setupFonts();
void setupGraphicFilters( const QskWindowsTheme& palette );
void setupGraphicFilters( const QskFluent2Theme& palette );
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
*****************************************************************************/
#ifndef QSK_WINDOWS_SKIN_FACTORY_H
#define QSK_WINDOWS_SKIN_FACTORY_H
#ifndef QSK_FLUENT2_SKIN_FACTORY_H
#define QSK_FLUENT2_SKIN_FACTORY_H
#include "QskWindowsGlobal.h"
#include "QskFluent2Global.h"
#include <QskSkinFactory.h>
class QSK_WINDOWS_EXPORT QskWindowsSkinFactory : public QskSkinFactory
class QSK_FLUENT2_EXPORT QskFluent2SkinFactory : public QskSkinFactory
{
Q_OBJECT
#if defined( QSK_WINDOWS_MAKEDLL )
#if defined( QSK_FLUENT2_MAKEDLL )
Q_PLUGIN_METADATA( IID QskSkinFactoryIID FILE "metadata.json" )
Q_INTERFACES( QskSkinFactory )
#endif
public:
QskWindowsSkinFactory( QObject* parent = nullptr );
~QskWindowsSkinFactory() override;
QskFluent2SkinFactory( QObject* parent = nullptr );
~QskFluent2SkinFactory() override;
QStringList skinNames() const override;
QskSkin* createSkin( const QString& skinName ) override;

View File

@ -1,8 +1,10 @@
<RCC>
<qresource prefix="/windows">
<qresource prefix="/fluent2">
<file>icons/qvg/checkmark.qvg</file>
<file>icons/qvg/combo-box-arrow-closed.qvg</file>
<file>icons/qvg/combo-box-arrow-open.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>
</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;
setHint( Q::Panel | QskAspect::Style, Q::Buttons );
setHint( Q::Panel | QskAspect::Style, Q::ButtonsLeftAndRight );
setSpacing( Q::Panel, 4_dp );
setStrutSize( Q::TextPanel, 80_dp, 40_dp );

View File

@ -127,10 +127,10 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin
enum FontRole
{
M3BodyMedium = QskSkin::HugeFont + 1,
M3BodyLarge,
M3HeadlineSmall,
M3LabelLarge,
M3BodyMedium = DefaultFont,
M3BodyLarge = LargeFont,
M3HeadlineSmall = SmallFont,
M3LabelLarge = HugeFont,
};
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/QskSizePolicy.h
common/QskStateCombination.h
common/QskStippleMetrics.h
common/QskTextColors.h
common/QskTextOptions.h
)
@ -61,6 +62,7 @@ list(APPEND SOURCES
common/QskScaleTickmarks.cpp
common/QskShadowMetrics.cpp
common/QskSizePolicy.cpp
common/QskStippleMetrics.cpp
common/QskTextColors.cpp
common/QskTextOptions.cpp
)
@ -107,12 +109,14 @@ list(APPEND HEADERS
nodes/QskBoxShadowNode.h
nodes/QskColorRamp.h
nodes/QskGraphicNode.h
nodes/QskLinesNode.h
nodes/QskPaintedNode.h
nodes/QskPlainTextRenderer.h
nodes/QskRichTextRenderer.h
nodes/QskScaleRenderer.h
nodes/QskSGNode.h
nodes/QskStrokeNode.h
nodes/QskStippledLineRenderer.h
nodes/QskShapeNode.h
nodes/QskGradientMaterial.h
nodes/QskTextNode.h
@ -135,6 +139,7 @@ list(APPEND SOURCES
nodes/QskBoxShadowNode.cpp
nodes/QskColorRamp.cpp
nodes/QskGraphicNode.cpp
nodes/QskLinesNode.cpp
nodes/QskPaintedNode.cpp
nodes/QskPlainTextRenderer.cpp
nodes/QskRectangleNode.cpp
@ -142,6 +147,7 @@ list(APPEND SOURCES
nodes/QskScaleRenderer.cpp
nodes/QskSGNode.cpp
nodes/QskStrokeNode.cpp
nodes/QskStippledLineRenderer.cpp
nodes/QskShapeNode.cpp
nodes/QskGradientMaterial.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
an invisible dummy offset
*/
qStop.first += 0.00001;
qStop.first = qMin( qStop.first + 0.00001, 1.0 );
}
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
{
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 )

View File

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

View File

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

View File

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

View File

@ -14,6 +14,7 @@
#include <qcolor.h>
#include <qvariant.h>
#include <qvector.h>
class QskArcMetrics;
class QskMargins;
@ -22,6 +23,7 @@ class QskBoxShapeMetrics;
class QskBoxBorderMetrics;
class QskBoxBorderColors;
class QskShadowMetrics;
class QskStippleMetrics;
class QskGraphic;
class QSK_EXPORT QskSkinHintTableEditor
@ -265,6 +267,21 @@ class QSK_EXPORT QskSkinHintTableEditor
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
void setTextOptions( QskAspect,

View File

@ -83,6 +83,10 @@ namespace
const auto factoryData = pluginData.value( TokenData ).toObject();
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() )
{
// Creating a dummy factory id
@ -200,7 +204,7 @@ namespace
if ( !m_isValid )
const_cast< FactoryMap* >( this )->rebuild();
return m_skinMap.keys();
return m_skinNames;
}
void insertFactory( FactoryLoader* loader )
@ -269,6 +273,7 @@ namespace
void rebuild()
{
m_skinMap.clear();
m_skinNames.clear();
// first we try all factories, that have been added manually
for ( auto it = m_factoryMap.constBegin(); it != m_factoryMap.constEnd(); ++it )
@ -287,7 +292,6 @@ namespace
rebuild( it.key(), data.loader->skinNames() );
}
m_skinNames = m_skinMap.keys();
m_isValid = true;
}
@ -296,7 +300,10 @@ namespace
for ( const auto& name : skinNames )
{
if ( !m_skinMap.contains( name ) )
{
m_skinMap.insert( name, factoryId );
m_skinNames += name;
}
}
}
@ -487,16 +494,10 @@ QskSkin* QskSkinManager::createSkin( const QString& skinName ) const
auto factory = map.factory( name );
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();
if ( !names.isEmpty() )
{
name = names.last();
name = names.first();
factory = map.factory( name );
}
}

View File

@ -21,8 +21,10 @@
#include "QskGradient.h"
#include "QskGraphicNode.h"
#include "QskGraphic.h"
#include "QskLinesNode.h"
#include "QskRectangleNode.h"
#include "QskSGNode.h"
#include "QskStippleMetrics.h"
#include "QskTextColors.h"
#include "QskTextNode.h"
#include "QskTextOptions.h"
@ -161,6 +163,11 @@ static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics,
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(
const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
{
@ -199,13 +206,10 @@ static inline QSGNode* qskUpdateBoxNode(
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 absoluteShadowMetrics = shadowMetrics.toAbsolute( size );
auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node );
boxNode->updateNode( rect, absoluteShape, absoluteMetrics,
borderColors, gradient, absoluteShadowMetrics, shadowColor );
@ -226,15 +230,46 @@ static inline QSGNode* qskUpdateArcNode(
if ( !qskIsArcVisible( metrics, borderWidth, borderColor, gradient ) )
return nullptr;
auto arcNode = static_cast< QskArcNode* >( node );
if ( arcNode == nullptr )
arcNode = new QskArcNode();
auto arcNode = QskSGNode::ensureNode< QskArcNode >( node );
arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient );
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
{
public:
@ -575,6 +610,34 @@ QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
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* node, QskAspect::Subcontrol subControl ) const
{

View File

@ -111,6 +111,12 @@ class QSK_EXPORT QskSkinlet
const QRectF&, const QskGradient&, qreal startAngle, qreal spanAngle,
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*,
const QRectF&, Qt::Alignment, const QString&, QskAspect::Subcontrol );

View File

@ -23,6 +23,7 @@
#include "QskBoxBorderMetrics.h"
#include "QskBoxBorderColors.h"
#include "QskShadowMetrics.h"
#include "QskStippleMetrics.h"
#include "QskBoxHints.h"
#include "QskGradient.h"
#include "QskTextOptions.h"
@ -638,6 +639,24 @@ QskArcMetrics QskSkinnable::arcMetricsHint(
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 )
{
return qskSetMetric( this, aspect | QskAspect::Spacing, spacing );
@ -689,14 +708,14 @@ int QskSkinnable::fontRoleHint(
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();
}

View File

@ -30,6 +30,7 @@ class QskBoxShapeMetrics;
class QskBoxBorderMetrics;
class QskBoxBorderColors;
class QskShadowMetrics;
class QskStippleMetrics;
class QskTextOptions;
class QskBoxHints;
class QskGradient;
@ -81,8 +82,8 @@ class QSK_EXPORT QskSkinnable
void setSkinlet( const QskSkinlet* );
const QskSkinlet* skinlet() const;
QFont effectiveFont( QskAspect::Subcontrol ) const;
qreal effectiveFontHeight( QskAspect::Subcontrol ) const;
QFont effectiveFont( QskAspect ) const;
qreal effectiveFontHeight( QskAspect ) const;
QskColorFilter effectiveGraphicFilter( QskAspect::Subcontrol ) const;
void setSubcontrolProxy( QskAspect::Subcontrol, QskAspect::Subcontrol proxy );
@ -228,6 +229,10 @@ class QSK_EXPORT QskSkinnable
bool resetArcMetricsHint( QskAspect );
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 resetSpacingHint( QskAspect );
qreal spacingHint( QskAspect, QskSkinHintStatus* = nullptr ) const;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,7 +16,7 @@ class QQuickItem;
class QSizeF;
class QRectF;
class QskLinearLayoutEngine : public QskLayoutEngine2D
class QSK_EXPORT QskLinearLayoutEngine : public QskLayoutEngine2D
{
public:
QskLinearLayoutEngine( Qt::Orientation, uint dimension );
@ -58,8 +58,8 @@ class QskLinearLayoutEngine : public QskLayoutEngine2D
void invalidateElementCache() override;
virtual void setupChain( Qt::Orientation,
const QskLayoutChain::Segments&, QskLayoutChain& ) const override;
virtual void setupChain( Qt::Orientation, const QskLayoutChain::Segments&,
QskLayoutChain& ) const override final;
class PrivateData;
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.
*/
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 );
}
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 );
}
auto graphicElement = appendGraphicElement( skinnable, graphicSubControl, graphicSize );
auto textElement = appendTextElement( skinnable, textSubcontrol, text );
/*
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(
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 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 );
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 );
}
void resetGeometry( QSGGeometryNode* );
QSK_EXPORT void resetGeometry( QSGGeometryNode* );
}
#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 );
}
QskStrokeNode::~QskStrokeNode() = default;
void QskStrokeNode::setRenderHint( RenderHint renderHint )
{
Q_D( QskStrokeNode );

View File

@ -19,6 +19,7 @@ class QSK_EXPORT QskStrokeNode : public QSGGeometryNode
{
public:
QskStrokeNode();
~QskStrokeNode() override;
/*
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)
target_include_directories(${target} PRIVATE ${CMAKE_SOURCE_DIR}/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()
set(HIDE_SYSTEM_FONTS ON)

View File

@ -51,11 +51,13 @@ static bool pluginPath = initPluginPath();
#include <squiek/QskSquiekSkinFactory.h>
#include <material3/QskMaterial3SkinFactory.h>
#include <windows/QskWindowsSkinFactory.h>
#include <fluent2/QskFluent2SkinFactory.h>
static void initSkins()
{
if ( qskSkinManager->skinNames().isEmpty() )
auto skinNames = qskSkinManager->skinNames();
if ( skinNames.isEmpty() )
{
/*
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( "Material3Factory", new QskMaterial3SkinFactory() );
qskSkinManager->registerFactory( "WindowsFactory", new QskWindowsSkinFactory() );
qskSkinManager->registerFactory( "Fluent2Factory", new QskFluent2SkinFactory() );
qWarning() << "Couldn't find skin plugins, adding some manually.";
skinNames = qskSkinManager->skinNames();
}
#if 1
/*
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
if ( !skinNames.isEmpty() )
qskSetup->setSkin( skinNames[0] );
}
Q_COREAPP_STARTUP_FUNCTION( initSkins )