Uing RGB values instead of colors. QskSkinTransition reimplemented.

Ongoing work
This commit is contained in:
Uwe Rathmann 2022-03-31 18:29:39 +02:00
parent 5284880eaa
commit 570d3d2d51
41 changed files with 1178 additions and 929 deletions

View File

@ -4,29 +4,11 @@
*****************************************************************************/
#include "Page.h"
#include <QskRgbValue.h>
Page::Page( Qt::Orientation orientation, QQuickItem* parent )
: QskLinearBox( orientation, parent )
, m_gradient( QskRgb::GhostWhite )
{
setMargins( 20 );
setPadding( 10 );
setSpacing( 10 );
}
void Page::setGradient( const QskGradient& gradient )
{
if ( gradient != m_gradient )
{
m_gradient = gradient;
if ( parentItem() && isVisibleToParent() )
parentItem()->update();
}
}
QskGradient Page::gradient() const
{
return m_gradient;
}

View File

@ -6,16 +6,9 @@
#pragma once
#include <QskLinearBox.h>
#include <QskGradient.h>
class Page : public QskLinearBox
{
public:
Page( Qt::Orientation, QQuickItem* parent = nullptr );
void setGradient( const QskGradient& );
QskGradient gradient() const;
private:
QskGradient m_gradient;
};

View File

@ -67,7 +67,6 @@ namespace
LabelPage::LabelPage( QQuickItem* parent )
: Page( Qt::Vertical, parent )
{
setGradient( QskRgb::AliceBlue );
setSpacing( 40 );
(void) new TextBox( this );

View File

@ -30,27 +30,6 @@ namespace
setMargins( 10 );
setTabPosition( Qsk::Left );
setAutoFitTabs( true );
connect( this, &QskTabView::currentIndexChanged,
this, &TabView::updateViewPanel );
}
protected:
void aboutToShow() override
{
updateViewPanel();
}
private:
void updateViewPanel()
{
/*
We should have a better way to set individual colors
for each tab page background
*/
if ( auto page = dynamic_cast< const ::Page* >( currentItem() ) )
setGradientHint( QskTabView::Page, page->gradient() );
}
};
}

View File

@ -45,9 +45,7 @@ namespace
ProgressBarPage::ProgressBarPage( QQuickItem* parent )
: Page( Qt::Horizontal, parent )
{
setGradient( QskRgb::AliceBlue );
setSpacing( 40 );
populate();
}

View File

@ -13,8 +13,6 @@
SliderPage::SliderPage( QQuickItem* parentItem )
: Page( Qt::Vertical, parentItem )
{
setGradient( QskRgb::PeachPuff );
setMargins( 10 );
setSpacing( 20 );

View File

@ -15,9 +15,7 @@
SwitchButtonPage::SwitchButtonPage( QQuickItem* parent )
: Page( Qt::Horizontal, parent )
{
setGradient( QskRgb::AliceBlue );
setSpacing( 40 );
populate();
}

View File

@ -47,20 +47,12 @@ static const int ButtonFontRole = QskSkin::HugeFont + 77;
static const int qskDuration = 150;
static inline QColor qskShadedColor( const QColor color, qreal opacity )
{
QColor c = color;
c.setAlphaF( opacity );
return c;
}
namespace
{
class Editor : private QskSkinHintTableEditor
{
public:
Editor( QskSkinHintTable* table, const ColorPalette& palette )
Editor( QskSkinHintTable* table, const QskMaterialPalette& palette )
: QskSkinHintTableEditor( table )
, m_pal( palette )
{
@ -93,7 +85,7 @@ namespace
void setupTextInput();
void setupTextLabel();
const ColorPalette& m_pal;
const QskMaterialPalette& m_pal;
const uint rippleSize = 30;
};
}
@ -135,7 +127,7 @@ void Editor::setupControl()
setGradient( A::Control, m_pal.background );
setColor( A::Control | A::StyleColor, m_pal.onBackground );
setColor( A::Control | A::StyleColor | Q::Disabled,
qskShadedColor( m_pal.onBackground, 0.6 ) );
QskRgb::toTransparentF( m_pal.onBackground, 0.6 ) );
}
void Editor::setupBox()
@ -155,8 +147,8 @@ void Editor::setupPopup()
setFlagHint( Q::Overlay | A::Style, true );
const QskGradient gradient( QskGradient::Vertical,
qskShadedColor( m_pal.secondary, 0.45 ),
qskShadedColor( m_pal.secondary, 0.7 ) );
QskRgb::toTransparentF( m_pal.secondary, 0.45 ),
QskRgb::toTransparentF( m_pal.secondary, 0.7 ) );
setGradient( Q::Overlay, gradient );
}
@ -196,20 +188,16 @@ void Editor::setupTextInput()
setBoxBorderColors( Q::Panel | Q::Focused, m_pal.primary );
setColor( Q::Panel,
m_pal.elevated( m_pal.background, 1 ) );
setColor( Q::Panel | Q::Hovered,
m_pal.elevated( m_pal.background, 2 ) );
setColor( Q::Panel | Q::Focused,
m_pal.elevated( m_pal.background, 3 ) );
setColor( Q::Panel | Q::Editing,
m_pal.elevated( m_pal.background, 4 ) );
setColor( Q::Panel, m_pal.elevated( m_pal.background, 1 ) );
setColor( Q::Panel | Q::Hovered, m_pal.elevated( m_pal.background, 2 ) );
setColor( Q::Panel | Q::Focused, m_pal.elevated( m_pal.background, 3 ) );
setColor( Q::Panel | Q::Editing, m_pal.elevated( m_pal.background, 4 ) );
setColor( Q::Panel | Q::Disabled,
qskShadedColor( m_pal.secondaryVariantNoSaturation, m_pal.disabled ) );
setColor( Q::Text | Q::Disabled, qskShadedColor( m_pal.onBackground, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondaryVariantNoSaturation, m_pal.disabled ) );
setColor( Q::Text | Q::Disabled, QskRgb::toTransparentF( m_pal.onBackground, m_pal.disabled ) );
setBoxBorderColors( Q::Panel,
qskShadedColor( m_pal.onBackground, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.onBackground, m_pal.disabled ) );
}
void Editor::setupProgressBar()
@ -233,9 +221,9 @@ void Editor::setupProgressBar()
setGradient( Q::Bar, m_pal.secondary );
setGradient( Q::Groove | Q::Disabled,
qskShadedColor( m_pal.secondaryNoSaturation, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondaryNoSaturation, m_pal.disabled ) );
setGradient( Q::Bar | Q::Disabled,
qskShadedColor( m_pal.secondary, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.disabled ) );
}
void Editor::setupFocusIndicator()
@ -275,9 +263,9 @@ void Editor::setupPageIndicator()
setGradient( Q::Bullet | Q::Selected, m_pal.secondary );
setGradient( Q::Bullet | Q::Disabled,
qskShadedColor( m_pal.secondaryNoSaturation, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondaryNoSaturation, m_pal.disabled ) );
setGradient( Q::Bullet | Q::Selected | Q::Disabled,
qskShadedColor( m_pal.secondary, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.disabled ) );
setSpacing( Q::Panel, qskDpiScaled( 3 ) );
setPadding( Q::Panel, 0 );
@ -304,19 +292,19 @@ void Editor::setupPushButton()
setGradient( Q::Panel | Q::Flat, White & ColorMask );
setColor( Q::Text, m_pal.primary );
setColor( Q::Text | Q::Disabled, qskShadedColor( m_pal.primary, 0.6 ) );
setColor( Q::Text | Q::Disabled, QskRgb::toTransparentF( m_pal.primary, 0.6 ) );
setFontRole( Q::Text, ButtonFontRole );
setAlignment( Q::Text, Qt::AlignCenter );
setBoxBorderMetrics( Q::Panel, 1 );
setBoxBorderColors( Q::Panel, m_pal.primary );
setBoxBorderColors( Q::Panel | Q::Disabled, qskShadedColor( m_pal.onBackground, m_pal.disabled ) );
setColor( Q::Text | Q::Disabled, qskShadedColor( m_pal.onBackground, m_pal.disabled ) );
setBoxBorderColors( Q::Panel | Q::Disabled, QskRgb::toTransparentF( m_pal.onBackground, m_pal.disabled ) );
setColor( Q::Text | Q::Disabled, QskRgb::toTransparentF( m_pal.onBackground, m_pal.disabled ) );
setColor( Q::Panel | Q::Hovered, qskShadedColor( m_pal.primary, m_pal.hover ) );
setColor( Q::Panel | Q::Focused, qskShadedColor( m_pal.primary, m_pal.focused ) );
setColor( Q::Panel | Q::Pressed, qskShadedColor( m_pal.primary, m_pal.pressed ) );
setColor( Q::Panel | Q::Hovered, QskRgb::toTransparentF( m_pal.primary, m_pal.hover ) );
setColor( Q::Panel | Q::Focused, QskRgb::toTransparentF( m_pal.primary, m_pal.focused ) );
setColor( Q::Panel | Q::Pressed, QskRgb::toTransparentF( m_pal.primary, m_pal.pressed ) );
setAnimation( Q::Panel | A::Color, qskDuration );
setAnimation( Q::Panel | A::Metric, qskDuration );
@ -339,7 +327,7 @@ void Editor::setupDialogButton()
setGradient( Q::Panel, m_pal.primary );
setColor( Q::Text, m_pal.onBackground );
setColor( Q::Text | Q::Disabled, qskShadedColor( m_pal.onPrimary, 0.6 ) );
setColor( Q::Text | Q::Disabled, QskRgb::toTransparentF( m_pal.onPrimary, 0.6 ) );
setFontRole( Q::Text, ButtonFontRole );
setAlignment( Q::Text, Qt::AlignCenter );
@ -385,7 +373,7 @@ void Editor::setupSlider()
setMetric( Q::Panel | A::Size, extent );
setBoxShape( Q::Panel, 0 );
setBoxBorderMetrics( Q::Panel, 0 );
setGradient( Q::Panel, m_pal.background );
setGradient( Q::Panel, QskGradient() );
setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) );
setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) );
@ -399,17 +387,17 @@ void Editor::setupSlider()
setBoxShape( subControl, 0 );
setBoxBorderMetrics( subControl, 0 );
}
setMetric( Q::Groove | A::Size, qskDpiScaled( 4 ) );
setMetric( Q::Fill | A::Size, qskDpiScaled( 6 ) );
setGradient( Q::Groove, qskShadedColor( m_pal.secondary, .38 ) );
setGradient( Q::Groove, QskRgb::toTransparentF( m_pal.secondary, .38 ) );
setGradient( Q::Groove | Q::Disabled,
qskShadedColor( m_pal.secondaryNoSaturation, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondaryNoSaturation, m_pal.disabled ) );
setGradient( Q::Fill, m_pal.secondary );
setGradient( Q::Fill | Q::Disabled,
qskShadedColor( m_pal.secondaryNoSaturation, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondaryNoSaturation, m_pal.disabled ) );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
setBoxBorderMetrics( Q::Handle, 0 );
@ -425,11 +413,13 @@ void Editor::setupSlider()
setBoxBorderMetrics( Q::Handle, qskDpiScaled( rippleSize / 2 ) );
setBoxBorderColors( Q::Handle | Q::Hovered,
qskShadedColor( m_pal.secondary, m_pal.hover ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.hover ) );
setBoxBorderColors( Q::Handle | Q::Focused,
qskShadedColor( m_pal.secondary, m_pal.focused ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.focused ) );
setBoxBorderColors( Q::Handle | Q::Pressed,
qskShadedColor( m_pal.secondary, m_pal.pressed ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.pressed ) );
// move the handle smoothly, when using keys
setAnimation( Q::Handle | A::Metric | A::Position, 2 * qskDuration );
@ -451,17 +441,17 @@ void Editor::setupSwitchButton()
setColor( Q::Groove, m_pal.secondaryNoSaturation );
setGradient( Q::Groove | Q::Disabled,
qskShadedColor( m_pal.secondaryNoSaturation, m_pal.disabled ) );
QskRgb::toTransparentF( m_pal.secondaryNoSaturation, m_pal.disabled ) );
setGradient( Q::Groove | Q::Checked,
m_pal.secondaryVariant );
setGradient( Q::Groove | Q::Checked | Q::Disabled,
qskShadedColor( m_pal.secondaryVariant, m_pal.disabledOccupancy ) );
QskRgb::toTransparentF( m_pal.secondaryVariant, m_pal.disabledOccupancy ) );
setBoxShape( Q::Handle, 100, Qt::RelativeSize );
setStrutSize( Q::Handle, qskDpiScaled( 2 * radius + rippleSize ),
qskDpiScaled( 2 * radius + rippleSize ) );
setGradient( Q::Handle, m_pal.background.lighter( 900 ) );
setGradient( Q::Handle, QskRgb::lighter( m_pal.background, 900 ) );
setGradient( Q::Handle | Q::Checked, m_pal.secondary );
@ -474,20 +464,20 @@ void Editor::setupSwitchButton()
setBoxBorderMetrics( Q::Handle, qskDpiScaled( rippleSize / 2 ) );
setBoxBorderColors( Q::Handle | Q::Checked | Q::Hovered,
qskShadedColor( m_pal.secondary, m_pal.hover ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.hover ) );
setBoxBorderColors( Q::Handle | Q::Checked | Q::Focused,
qskShadedColor( m_pal.secondary, m_pal.focused ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.focused ) );
setBoxBorderColors( Q::Handle | Q::Checked | Q::Pressed,
qskShadedColor( m_pal.secondary, m_pal.pressed ) );
QskRgb::toTransparentF( m_pal.secondary, m_pal.pressed ) );
setBoxBorderColors( Q::Handle | Q::Hovered,
qskShadedColor( m_pal.secondaryVariantNoSaturation,
QskRgb::toTransparentF( m_pal.secondaryVariantNoSaturation,
m_pal.hover ) );
setBoxBorderColors( Q::Handle | Q::Focused,
qskShadedColor( m_pal.secondaryVariantNoSaturation,
QskRgb::toTransparentF( m_pal.secondaryVariantNoSaturation,
m_pal.focused ) );
setBoxBorderColors( Q::Handle | Q::Pressed,
qskShadedColor( m_pal.secondaryVariantNoSaturation,
QskRgb::toTransparentF( m_pal.secondaryVariantNoSaturation,
m_pal.pressed ) );
for ( auto state : { A::NoState, Q::Disabled } )
@ -556,15 +546,15 @@ void Editor::setupTabButton()
setColor( Q::Text, m_pal.onBackground );
setColor( Q::Text | Q::Disabled,
qskShadedColor( m_pal.onBackground,
QskRgb::toTransparentF( m_pal.onBackground,
m_pal.widgetBackgroundDisabled ) );
setColor( Q::Text | Q::Checked, m_pal.primary );
setColor( Q::Text | Q::Hovered, m_pal.primary );
setColor( Q::Panel, m_pal.elevated( m_pal.background ) );
setColor( Q::Panel | Q::Hovered, qskShadedColor( m_pal.primary, m_pal.hover ) );
setColor( Q::Panel | Q::Focused, qskShadedColor( m_pal.primary, m_pal.focused ) );
setColor( Q::Panel | Q::Pressed, qskShadedColor( m_pal.primary, m_pal.pressed ) );
setColor( Q::Panel | Q::Hovered, QskRgb::toTransparentF( m_pal.primary, m_pal.hover ) );
setColor( Q::Panel | Q::Focused, QskRgb::toTransparentF( m_pal.primary, m_pal.focused ) );
setColor( Q::Panel | Q::Pressed, QskRgb::toTransparentF( m_pal.primary, m_pal.pressed ) );
setAnimation( Q::Panel | A::Color, qskDuration );
@ -587,9 +577,11 @@ void Editor::setupTabBar()
setAnimation( Q::Panel | A::Metric, QskAnimationHint( 200, QEasingCurve::InCubic ) );
}
void Editor::setupTabView() {
void Editor::setupTabView()
{
using Q = QskTabView;
setGradient( Q::Page, m_pal.background );
setAnimation( Q::Page, qskDuration );
}
@ -654,7 +646,7 @@ void Editor::setupScrollView()
{
setBoxShape( subControl, 3 );
setBoxBorderMetrics( subControl, 0 );
setColor( subControl, qskShadedColor( m_pal.onBackground, m_pal.hover ) );
setColor( subControl, QskRgb::toTransparentF( m_pal.onBackground, m_pal.hover ) );
setAnimation( subControl | A::Color, qskDuration );
}
@ -663,7 +655,7 @@ void Editor::setupScrollView()
Q::VerticalScrollHandle | Q::VerticalHandlePressed } )
{
setColor( subControl,
qskShadedColor( m_pal.onBackground, m_pal.pressed ) );
QskRgb::toTransparentF( m_pal.onBackground, m_pal.pressed ) );
}
// when changing the position by QskScrollView::scrollTo
@ -679,7 +671,7 @@ void Editor::setupListView()
setColor( Q::Cell, m_pal.background );
setColor( Q::Text, m_pal.onBackground );
setColor( Q::Cell | Q::Selected, qskShadedColor( m_pal.onBackground, m_pal.focused ) );
setColor( Q::Cell | Q::Selected, QskRgb::toTransparentF( m_pal.onBackground, m_pal.focused ) );
setColor( Q::Text | Q::Selected, m_pal.onBackground );
}
@ -713,15 +705,8 @@ void Editor::setupSubWindow()
}
class QskMaterialSkin::PrivateData
{
public:
ColorPalette palette;
};
QskMaterialSkin::QskMaterialSkin( ColorPalette colors, QObject* parent )
QskMaterialSkin::QskMaterialSkin( const QskMaterialPalette& palette, QObject* parent )
: Inherited( parent )
, m_data( new PrivateData { colors } )
{
// Default theme colors
setupFonts( QStringLiteral( "Roboto" ) );
@ -730,7 +715,7 @@ QskMaterialSkin::QskMaterialSkin( ColorPalette colors, QObject* parent )
buttonFont.setCapitalization( QFont::AllUppercase );
setFont( ButtonFontRole, buttonFont );
Editor editor( &hintTable(), m_data->palette );
Editor editor( &hintTable(), palette );
editor.setup();
}

View File

@ -9,86 +9,56 @@
#include "QskMaterialGlobal.h"
#include <QskSkin.h>
#include <QskRgbValue.h>
#include <memory>
struct ColorPalette
class QSK_MATERIAL_EXPORT QskMaterialPalette
{
enum Lightness { light, dark } lightness;
QColor primary;
QColor primaryVariant;
QColor onPrimary;
QColor secondary;
QColor secondaryVariant;
QColor onSecondary;
QColor background;
QColor onBackground;
QColor error;
QColor onError;
QColor primaryNoSaturation = QColor::fromHsl( primary.hslHue(), 0,
primary.lightness() );
QColor secondaryNoSaturation =
QColor::fromHsl( secondary.hslHue(), 0,
secondary.lightness() );
QColor secondaryVariantNoSaturation =
QColor::fromHsl( secondaryVariant.hslHue(), 0,
secondaryVariant.lightness() +
secondaryVariant.hslSaturation() );
qreal disabledOccupancy = 0.2;
qreal widgetBackgroundDisabled = 0.6;
qreal hover = 0.1;
qreal focused = 0.4;
qreal pressed = 0.5;
qreal disabled = 0.3;
ColorPalette(
Lightness lightness = light,
QColor primary = QColor::fromRgb( 0x6200EE ),
QColor primaryVariant = QColor::fromRgb( 0x3700B3 ),
QColor onPrimary = Qt::white,
QColor secondary = QColor::fromRgb( 0x03DAC6 ),
QColor secondaryVariant = QColor::fromRgb( 0x018786 ),
QColor onSecondary = Qt::white,
QColor background = QColor::fromRgba( QskRgb::Grey100 ),
QColor onBackground = Qt::black,
QColor error = QColor::fromRgb( 0xB00020 ),
QColor onError = Qt::white ):
lightness( lightness ),
primary( primary ),
primaryVariant( primaryVariant ),
onPrimary( onPrimary ),
secondary( secondary ),
secondaryVariant( secondaryVariant ),
onSecondary( onSecondary ),
background( background ),
onBackground( onBackground ),
error( error ),
onError( onError )
public:
enum Lightness
{
primaryNoSaturation = QColor::fromHsl( primary.hslHue(), 0,
primary.lightness() );
Light,
Dark
};
secondaryNoSaturation = QColor::fromHsl( secondary.hslHue(),
0,
secondary.lightness() );
secondaryVariantNoSaturation =
QColor::fromHsl( secondaryVariant.hslHue(), 0,
secondaryVariant.lightness() );
QskMaterialPalette( Lightness lightness )
: m_lightness( lightness )
{
}
inline QColor elevated( const QColor target, const float level = 1 ) const {
return ( lightness == light ) ? target.darker( 100 + level * 15 )
: target.lighter( 130 + level * 30 );
inline QRgb elevated( const QRgb rgb, const float level = 1 ) const
{
return ( m_lightness == Light )
? QskRgb::darker( rgb, 100 + level * 15 )
: QskRgb::lighter( rgb, 130 + level * 30 );
}
public:
QRgb primary;
QRgb primaryVariant;
QRgb onPrimary;
QRgb secondary;
QRgb secondaryVariant;
QRgb onSecondary;
QRgb background;
QRgb onBackground;
QRgb error;
QRgb onError;
QRgb primaryNoSaturation;
QRgb secondaryNoSaturation;
QRgb secondaryVariantNoSaturation;
const qreal disabledOccupancy = 0.2;
const qreal widgetBackgroundDisabled = 0.6;
const qreal hover = 0.1;
const qreal focused = 0.4;
const qreal pressed = 0.5;
const qreal disabled = 0.3;
const Lightness m_lightness;
};
class QSK_MATERIAL_EXPORT QskMaterialSkin : public QskSkin
@ -98,12 +68,8 @@ class QSK_MATERIAL_EXPORT QskMaterialSkin : public QskSkin
using Inherited = QskSkin;
public:
QskMaterialSkin( ColorPalette, QObject* parent = nullptr );
QskMaterialSkin( const QskMaterialPalette&, QObject* parent = nullptr );
~QskMaterialSkin() override;
private:
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -9,6 +9,42 @@
static const QString materialLightSkinName = QStringLiteral( "materialLight" );
static const QString materialDarkSkinName = QStringLiteral( "materialDark" );
namespace
{
inline int lightnessRgb( QRgb rgb )
{
const int red = qRed( rgb );
const int green = qGreen( rgb );
const int blue = qBlue( rgb );
int min, max;
if ( red > green )
{
max = qMax( red, blue );
min = qMin( green, blue );
}
else
{
max = qMax( green, blue );
min = qMin( red, blue );
}
return ( max + min ) / 2;
}
inline QRgb toUnsaturated( QRgb rgb )
{
/*
a saturation of 0 results in having the lightness as r,g,b
Is this intended ?
*/
const auto l = lightnessRgb( rgb );
return qRgba( l, l, l, qAlpha( rgb ) );
}
}
QskMaterialSkinFactory::QskMaterialSkinFactory( QObject* parent )
: QskSkinFactory( parent )
{
@ -25,24 +61,48 @@ QStringList QskMaterialSkinFactory::skinNames() const
QskSkin* QskMaterialSkinFactory::createSkin( const QString& skinName )
{
if ( QString::compare( skinName, materialLightSkinName, Qt::CaseInsensitive ) )
return new QskMaterialSkin( ColorPalette() );
if ( QString::compare( skinName, materialDarkSkinName, Qt::CaseInsensitive ) )
if ( QString::compare( skinName, materialLightSkinName, Qt::CaseInsensitive ) == 0 )
{
return new QskMaterialSkin( ColorPalette(
ColorPalette::dark, // lightness
QColor::fromRgb( 0xBB86FC ), // primary
QColor::fromRgb( 0x3700B3 ), // primaryVariant
Qt::black, // onPrimary
QColor::fromRgb( 0x03DAC6 ), // secondary
QColor::fromRgb( 0x018786 ), // secondaryVariant
Qt::black, // onSecondary
QColor::fromRgb( 0x121212 ), // background
Qt::white, // onBackground
QColor::fromRgb( 0xCF6679 ), // error
Qt::black // onError
) );
QskMaterialPalette pal( QskMaterialPalette::Light );;
pal.primary = 0xff6200ee;
pal.primaryVariant = 0xff3700b3;
pal.onPrimary = QskRgb::White;
pal.secondary = 0xff03dac6;
pal.secondaryVariant = 0xff018786;
pal.onSecondary = QskRgb::White;
pal.background = QskRgb::Grey100;
pal.onBackground = QskRgb::Black;
pal.error = 0xffb00020;
pal.onError = QskRgb::White;
pal.primaryNoSaturation = toUnsaturated( pal.primary );
pal.secondaryNoSaturation = toUnsaturated( pal.secondary );
pal.secondaryVariantNoSaturation = toUnsaturated( pal.secondaryVariant );
return new QskMaterialSkin( pal );
}
if ( QString::compare( skinName, materialDarkSkinName, Qt::CaseInsensitive ) == 0 )
{
QskMaterialPalette pal( QskMaterialPalette::Dark );
pal.primary = 0xffbb86fc;
pal.primaryVariant = 0xff3700b3;
pal.onPrimary = QskRgb::Black;
pal.secondary = 0xff03dac6;
pal.secondaryVariant = 0xff018786;
pal.onSecondary = QskRgb::Black;
pal.background = 0xff121212;
pal.onBackground = QskRgb::White;
pal.error = 0xffcf6679;
pal.onError = QskRgb::Black;
pal.primaryNoSaturation = toUnsaturated( pal.primary );
pal.secondaryNoSaturation = toUnsaturated( pal.secondary );
pal.secondaryVariantNoSaturation = toUnsaturated( pal.secondaryVariant );
return new QskMaterialSkin( pal );
}
return nullptr;

View File

@ -647,51 +647,38 @@ void Editor::setupSlider()
// Panel
for ( auto placement : { A::Horizontal, A::Vertical } )
{
const auto aspect = Q::Panel | placement;
setMetric( aspect | A::Size, extent );
setBoxBorderMetrics( aspect, 0 );
setBoxShape( aspect, 0 );
setGradient( aspect, QskGradient() );
}
setMetric( Q::Panel | A::Size, extent );
setBoxBorderMetrics( Q::Panel, 0 );
setBoxShape( Q::Panel, 0 );
setGradient( Q::Panel, QskGradient() );
setPadding( Q::Panel | A::Horizontal, QskMargins( 0.5 * extent, 0 ) );
setPadding( Q::Panel | A::Vertical, QskMargins( 0, 0.5 * extent ) );
// Groove, Fill
for ( auto placement : { A::Horizontal, A::Vertical } )
for ( auto subControl : { Q::Groove, Q::Fill } )
{
for ( auto subControl : { Q::Groove, Q::Fill } )
{
const auto aspect = subControl | placement;
const auto aspect = subControl;
setMetric( aspect | A::Size, 0.3 * extent );
setPadding( aspect, 0 );
setMetric( aspect | A::Size, 0.3 * extent );
setPadding( aspect, 0 );
setBoxBorderMetrics( aspect, 0 );
setBoxShape( aspect, 0.1 * extent );
}
setGradient( Q::Groove | placement, m_pal.darker200 );
setGradient( Q::Fill | placement, QskGradient() ); // no filling
setBoxBorderMetrics( aspect, 0 );
setBoxShape( aspect, 0.1 * extent );
}
setGradient( Q::Groove, m_pal.darker200 );
setGradient( Q::Fill, QskGradient() ); // no filling
// Handle
for ( auto placement : { A::Horizontal, A::Vertical } )
{
const auto aspect = Q::Handle | placement;
setButton( Q::Handle, Raised, 1 );
setBoxShape( Q::Handle, 20.0, Qt::RelativeSize );
setButton( Q::Handle | Q::Pressed, Sunken, 1 );
setButton( aspect, Raised, 1 );
setBoxShape( aspect, 20.0, Qt::RelativeSize );
setButton( aspect | Q::Pressed, Sunken, 1 );
const qreal sz = 0.75 * extent;
setStrutSize( aspect, sz, sz );
}
const qreal sz = 0.75 * extent;
setStrutSize( Q::Handle, sz, sz );
setAnimation( Q::Handle | A::Color, qskDuration );
}

View File

@ -24,7 +24,7 @@ QStringList QskSquiekSkinFactory::skinNames() const
QskSkin* QskSquiekSkinFactory::createSkin( const QString& skinName )
{
if ( skinName.toLower() == squiekSkinName )
if ( QString::compare( skinName, squiekSkinName, Qt::CaseInsensitive ) == 0 )
return new QskSquiekSkin();
return nullptr;

View File

@ -11,6 +11,10 @@
static void qskRegisterArcMetrics()
{
qRegisterMetaType< QskArcMetrics >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskArcMetrics >();
#endif
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterArcMetrics )

View File

@ -109,8 +109,18 @@ class QSK_EXPORT QskAspect
constexpr QskAspect operator|( Type ) const noexcept;
constexpr QskAspect operator|( Primitive ) const noexcept;
constexpr QskAspect operator|( Placement ) const noexcept;
constexpr QskAspect operator|( State ) const noexcept;
QskAspect& operator|=( State ) noexcept;
constexpr QskAspect operator&( State ) const noexcept;
QskAspect& operator&=( State ) noexcept;
constexpr QskAspect operator|( States ) const noexcept;
QskAspect& operator|=( States ) noexcept;
constexpr QskAspect operator&( States ) const noexcept;
QskAspect& operator&=( States ) noexcept;
constexpr QskAspect stateless() const noexcept;
constexpr QskAspect trunk() const noexcept;
@ -283,12 +293,48 @@ inline constexpr QskAspect QskAspect::operator|( State state ) const noexcept
m_bits.primitive, m_bits.placement, m_bits.states | state );
}
inline QskAspect& QskAspect::operator|=( State state ) noexcept
{
m_bits.states |= state;
return *this;
}
inline constexpr QskAspect QskAspect::operator&( State state ) const noexcept
{
return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator,
m_bits.primitive, m_bits.placement, m_bits.states & state );
}
inline QskAspect& QskAspect::operator&=( State state ) noexcept
{
m_bits.states &= state;
return *this;
}
inline constexpr QskAspect QskAspect::operator|( States states ) const noexcept
{
return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator,
m_bits.primitive, m_bits.placement, m_bits.states | states );
}
inline QskAspect& QskAspect::operator|=( States states ) noexcept
{
m_bits.states |= states;
return *this;
}
inline constexpr QskAspect QskAspect::operator&( States states ) const noexcept
{
return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator,
m_bits.primitive, m_bits.placement, m_bits.states & states );
}
inline QskAspect& QskAspect::operator&=( States states ) noexcept
{
m_bits.states &= states;
return *this;
}
inline constexpr QskAspect QskAspect::stateless() const noexcept
{
return QskAspect( m_bits.subControl, m_bits.type, m_bits.isAnimator,
@ -538,6 +584,11 @@ namespace std
};
}
inline QskHashValue qHash( const QskAspect aspect, QskHashValue seed = 0 ) noexcept
{
return qHash( aspect.value(), seed );
}
#ifndef QT_NO_DEBUG_STREAM
class QDebug;

View File

@ -13,6 +13,10 @@ static void qskRegisterBoxBorderColors()
{
qRegisterMetaType< QskBoxBorderColors >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskBoxBorderColors >();
#endif
QMetaType::registerConverter< QColor, QskBoxBorderColors >(
[]( const QColor& color ) { return QskBoxBorderColors( color ); } );
@ -110,6 +114,26 @@ void QskBoxBorderColors::setGradientAt( Qt::Edges edges, const QskGradient& grad
m_gradients[ Qsk::Bottom ] = gradient;
}
void QskBoxBorderColors::setLeft( const QskGradient& gradient )
{
m_gradients[ Qsk::Left ] = gradient;
}
void QskBoxBorderColors::setTop( const QskGradient& gradient )
{
m_gradients[ Qsk::Top ] = gradient;
}
void QskBoxBorderColors::setRight( const QskGradient& gradient )
{
m_gradients[ Qsk::Right ] = gradient;
}
void QskBoxBorderColors::setBottom( const QskGradient& gradient )
{
m_gradients[ Qsk::Bottom ] = gradient;
}
const QskGradient& QskBoxBorderColors::gradientAt( Qt::Edge edge ) const
{
switch ( edge )
@ -165,6 +189,14 @@ bool QskBoxBorderColors::isMonochrome() const
&& m_gradients[ 3 ].isMonochrome();
}
bool QskBoxBorderColors::isValid() const
{
return m_gradients[ 0 ].isValid()
|| m_gradients[ 1 ].isValid()
|| m_gradients[ 2 ].isValid()
|| m_gradients[ 3 ].isValid();
}
QskBoxBorderColors QskBoxBorderColors::interpolated(
const QskBoxBorderColors& to, qreal ratio ) const
{
@ -172,8 +204,14 @@ QskBoxBorderColors QskBoxBorderColors::interpolated(
for ( size_t i = 0; i < 4; i++ )
{
colors.m_gradients[ i ] = colors.m_gradients[ i ].interpolated(
to.m_gradients[ i ], ratio );
#if 1
/*
When one border has a width of 0 we would prefer to ignore
the color and use always use the other color. TODO ...
*/
#endif
auto& gradient = colors.m_gradients[ i ];
gradient = gradient.interpolated( to.m_gradients[ i ], ratio );
}
return colors;
@ -204,14 +242,44 @@ QDebug operator<<( QDebug debug, const QskBoxBorderColors& colors )
QDebugStateSaver saver( debug );
debug.nospace();
debug << "BoxBorderColors" << '(';
debug << "BoxBorderColors";
debug << " L" << colors.gradient( Qsk::Left );
debug << ", T" << colors.gradient( Qsk::Top );
debug << ", R" << colors.gradient( Qsk::Right );
debug << ", B" << colors.gradient( Qsk::Bottom );
if ( !colors.isValid() )
{
debug << "()";
}
else
{
debug << "( ";
debug << " )";
if ( colors.isMonochrome() )
{
const auto& gradient = colors.gradient( Qsk::Left );
QskRgb::debugColor( debug, gradient.startColor() );
}
else
{
const char prompts[] = { 'L', 'T', 'R', 'B' };
for ( int i = 0; i <= Qsk::Bottom; i++ )
{
if ( i != 0 )
debug << ", ";
const auto& gradient = colors.gradient(
static_cast< Qsk::Position >( i ) );
debug << prompts[ i ] << ": ";
if ( gradient.isValid() && gradient.isMonochrome() )
QskRgb::debugColor( debug, gradient.startColor() );
else
debug << gradient;
}
}
debug << " )";
}
return debug;
}

View File

@ -12,10 +12,15 @@
#include <qcolor.h>
#include <qmetatype.h>
class QDebug;
class QSK_EXPORT QskBoxBorderColors
{
Q_GADGET
Q_PROPERTY( QskGradient left READ left WRITE setLeft )
Q_PROPERTY( QskGradient top READ top WRITE setTop )
Q_PROPERTY( QskGradient right READ right WRITE setRight )
Q_PROPERTY( QskGradient bottom READ bottom WRITE setBottom )
public:
QskBoxBorderColors();
@ -44,6 +49,18 @@ class QSK_EXPORT QskBoxBorderColors
void setGradientAt( Qt::Edges, const QskGradient& );
const QskGradient& gradientAt( Qt::Edge ) const;
void setLeft( const QskGradient& );
const QskGradient& left() const;
void setTop( const QskGradient& );
const QskGradient& top() const;
void setRight( const QskGradient& );
const QskGradient& right() const;
void setBottom( const QskGradient& );
const QskGradient& bottom() const;
QskBoxBorderColors interpolated( const QskBoxBorderColors&, qreal value ) const;
static QVariant interpolate( const QskBoxBorderColors&,
@ -53,6 +70,7 @@ class QSK_EXPORT QskBoxBorderColors
bool isMonochrome() const;
bool isVisible() const;
bool isValid() const;
private:
QskGradient m_gradients[ 4 ];
@ -78,8 +96,29 @@ inline const QskGradient& QskBoxBorderColors::gradient( Qsk::Position position )
return m_gradients[ position ];
}
inline const QskGradient& QskBoxBorderColors::left() const
{
return m_gradients[ Qsk::Left ];
}
inline const QskGradient& QskBoxBorderColors::top() const
{
return m_gradients[ Qsk::Top ];
}
inline const QskGradient& QskBoxBorderColors::right() const
{
return m_gradients[ Qsk::Right ];
}
inline const QskGradient& QskBoxBorderColors::bottom() const
{
return m_gradients[ Qsk::Bottom ];
}
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
QSK_EXPORT QDebug operator<<( QDebug, const QskBoxBorderColors& );
#endif

View File

@ -12,6 +12,10 @@ static void qskRegisterBoxBorderMetrics()
{
qRegisterMetaType< QskBoxBorderMetrics >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskBoxBorderMetrics >();
#endif
QMetaType::registerConverter< QskMargins, QskBoxBorderMetrics >(
[]( const QskMargins& margins ) { return QskBoxBorderMetrics( margins ); } );
@ -109,9 +113,24 @@ QDebug operator<<( QDebug debug, const QskBoxBorderMetrics& metrics )
QDebugStateSaver saver( debug );
debug.nospace();
debug << "BoxBorder" << '(';
debug << metrics.sizeMode() << ',' << metrics.widths();
debug << ')';
debug << "BoxBorder" << "( ";
if ( metrics.sizeMode() != Qt::AbsoluteSize )
debug << metrics.sizeMode() << ", ";
const auto& w = metrics.widths();
if ( metrics.isEquidistant() )
{
debug << w.left();
}
else
{
const char s[] = ", ";
debug << w.left() << s << w.top() << s << w.right() << s << w.bottom();
}
debug << " )";
return debug;
}

View File

@ -60,6 +60,8 @@ class QSK_EXPORT QskBoxBorderMetrics
static QVariant interpolate( const QskBoxBorderMetrics&,
const QskBoxBorderMetrics&, qreal progress );
constexpr bool isEquidistant() const noexcept;
private:
QskMargins m_widths;
Qt::SizeMode m_sizeMode;
@ -115,6 +117,11 @@ inline constexpr bool QskBoxBorderMetrics::isNull() const noexcept
return m_widths.isNull();
}
inline constexpr bool QskBoxBorderMetrics::isEquidistant() const noexcept
{
return m_widths.isEquidistant();
}
inline constexpr const QskMargins& QskBoxBorderMetrics::widths() const noexcept
{
return m_widths;

View File

@ -14,6 +14,10 @@ static void qskRegisterBoxShapeMetrics()
{
qRegisterMetaType< QskBoxShapeMetrics >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskBoxShapeMetrics >();
#endif
QMetaType::registerConverter< int, QskBoxShapeMetrics >(
[]( int radius ) { return QskBoxShapeMetrics( radius ); } );

View File

@ -15,6 +15,10 @@ static void qskRegisterGradient()
{
qRegisterMetaType< QskGradient >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskGradient >();
#endif
QMetaType::registerConverter< QColor, QskGradient >(
[]( const QColor& color ) { return QskGradient( color ); } );
}
@ -229,6 +233,11 @@ QskGradient::QskGradient( Orientation orientation, const QskGradientStops& stops
setStops( stops );
}
QskGradient::QskGradient( Qt::Orientation orientation, QGradient::Preset preset )
: QskGradient( qskOrientation( orientation ), preset )
{
}
QskGradient::QskGradient( Orientation orientation, QGradient::Preset preset )
: QskGradient( orientation )
{
@ -499,6 +508,14 @@ QskGradient QskGradient::interpolated(
return QskGradient( gradient->orientation(), stops );
}
if ( isMonochrome() && to.isMonochrome() )
{
const auto c = QskRgb::interpolated(
m_stops[ 0 ].color(), to.m_stops[ 0 ].color(), value );
return QskGradient( to.orientation(), c, c );
}
if ( isMonochrome() )
{
// we can ignore our stops
@ -624,7 +641,49 @@ void QskGradient::updateStatusBits() const
QDebug operator<<( QDebug debug, const QskGradient& gradient )
{
debug << "GR:" << gradient.orientation() << gradient.stops().count();
QDebugStateSaver saver( debug );
debug.nospace();
debug << "Gradient";
if ( !gradient.isValid() )
{
debug << "()";
}
else
{
debug << "( ";
if ( gradient.isMonochrome() )
{
QskRgb::debugColor( debug, gradient.startColor() );
}
else
{
const char o[] = { 'H', 'V', 'D' };
debug << o[ gradient.orientation() ] << ", ";
if ( gradient.stops().count() == 2 )
{
QskRgb::debugColor( debug, gradient.startColor() );
debug << ", ";
QskRgb::debugColor( debug, gradient.endColor() );
}
else
{
const auto& s = gradient.stops();
for ( int i = 0; i < s.count(); i++ )
{
if ( i != 0 )
debug << ", ";
debug << s[i];
}
}
}
debug << " )";
}
return debug;
}

View File

@ -52,6 +52,7 @@ class QSK_EXPORT QskGradient
QskGradient( Qt::Orientation, const QVector< QskGradientStop >& );
QskGradient( Qt::Orientation, const QColor&, const QColor& );
QskGradient( Qt::Orientation, QGradient::Preset );
QskGradient( Orientation, const QVector< QskGradientStop >& );
QskGradient( Orientation, const QColor&, const QColor& );

View File

@ -14,6 +14,10 @@
static void qskRegisterGradientStop()
{
qRegisterMetaType< QskGradientStop >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskGradientStop >();
#endif
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterGradientStop )
@ -78,7 +82,12 @@ QColor QskGradientStop::interpolated(
QDebug operator<<( QDebug debug, const QskGradientStop& stop )
{
debug << stop.position() << ": " << stop.color();
QDebugStateSaver saver( debug );
debug.nospace();
debug << stop.position() << ": ";
QskRgb::debugColor( debug, stop.color() );
return debug;
}

View File

@ -12,6 +12,10 @@
static void qskRegisterIntervalF()
{
qRegisterMetaType< QskIntervalF >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskIntervalF >();
#endif
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterIntervalF )

View File

@ -61,6 +61,7 @@ class QSK_EXPORT QskMargins : public QMarginsF
QskMargins interpolated( const QskMargins&, qreal progress ) const noexcept;
constexpr bool isExpanding() const noexcept;
constexpr bool isEquidistant() const noexcept;
static QVariant interpolate( const QskMargins&,
const QskMargins&, qreal progress ) noexcept;
@ -181,6 +182,11 @@ constexpr inline qreal QskMargins::height() const noexcept
return top() + bottom();
}
inline constexpr bool QskMargins::isEquidistant() const noexcept
{
return ( left() == top() ) && ( left() == right() ) && ( left() == bottom() );
}
Q_DECLARE_TYPEINFO( QskMargins, Q_MOVABLE_TYPE );
Q_DECLARE_METATYPE( QskMargins )

View File

@ -172,3 +172,29 @@ QRgb QskRgb::darker( QRgb rgb, int factor ) noexcept
return QColor::fromRgba( rgb ).darker( factor ).rgba();
}
#ifndef QT_NO_DEBUG_STREAM
#include <qdebug.h>
void QskRgb::debugColor( QDebug debug, const QColor& color )
{
debugColor( debug, color.rgba() );
}
void QskRgb::debugColor( QDebug debug, QRgb rgb )
{
QDebugStateSaver saver( debug );
debug.nospace();
debug << '[';
debug << qRed( rgb ) << "r," << qGreen( rgb ) << "g,"
<< qBlue( rgb ) << 'b';
if ( qAlpha( rgb ) != 255 )
debug << ',' << qAlpha( rgb ) << 'a';
debug << ']';
}
#endif

View File

@ -461,23 +461,35 @@ namespace QskRgb
return ( rgb & ColorMask ) | ( ( static_cast< uint >( alpha ) & 0xffu ) << 24 );
}
inline QColor toTransparentF( const QColor& color, qreal alpha )
inline QColor toTransparentF( const QColor& color, qreal opacity )
{
return toTransparent( color, qRound( alpha * 255 ) );
return toTransparent( color, qRound( opacity * 255 ) );
}
inline QColor toTransparentF( Qt::GlobalColor color, qreal alpha )
inline QColor toTransparentF( Qt::GlobalColor color, qreal opacity )
{
return toTransparent( QColor( color ), qRound( alpha * 255 ) );
return toTransparent( QColor( color ), qRound( opacity * 255 ) );
}
inline constexpr QRgb toTransparentF( QRgb rgb, qreal alpha ) noexcept
inline constexpr QRgb toTransparentF( QRgb rgb, qreal opacity ) noexcept
{
return toTransparent( rgb, qRound( alpha * 255 ) );
return toTransparent( rgb, qRound( opacity * 255 ) );
}
QSK_EXPORT QRgb lighter( QRgb, int factor = 150 ) noexcept;
QSK_EXPORT QRgb darker( QRgb, int factor = 200 ) noexcept;
}
#ifndef QT_NO_DEBUG_STREAM
class QDebug;
namespace QskRgb
{
QSK_EXPORT void debugColor( QDebug, const QColor& );
QSK_EXPORT void debugColor( QDebug, QRgb );
}
#endif
#endif

View File

@ -9,6 +9,10 @@
static void qskRegisterTickmarks()
{
qRegisterMetaType< QskScaleTickmarks >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskScaleTickmarks >();
#endif
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterTickmarks )

View File

@ -12,6 +12,10 @@
static void qskRegisterShadowMetrics()
{
qRegisterMetaType< QskShadowMetrics >();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QMetaType::registerEqualsComparator< QskShadowMetrics >();
#endif
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterShadowMetrics )

View File

@ -1,14 +0,0 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskStateCombination.h"
static void qskRegisterStateCombination()
{
qRegisterMetaType< QskStateCombination >();
}
Q_CONSTRUCTOR_FUNCTION( qskRegisterStateCombination )

View File

@ -21,6 +21,9 @@ class QSK_EXPORT QskStateCombination
constexpr QskStateCombination( QskAspect::States = QskAspect::States() ) noexcept;
constexpr QskStateCombination( Type, QskAspect::States = QskAspect::States() ) noexcept;
constexpr bool operator==( QskStateCombination ) const noexcept;
constexpr bool operator!=( QskStateCombination ) const noexcept;
constexpr bool isNull() const noexcept;
void setType( Type ) noexcept;
@ -36,7 +39,6 @@ class QSK_EXPORT QskStateCombination
};
Q_DECLARE_TYPEINFO( QskStateCombination, Q_MOVABLE_TYPE );
Q_DECLARE_METATYPE( QskStateCombination )
constexpr inline QskStateCombination::QskStateCombination(
QskAspect::State state ) noexcept
@ -90,4 +92,14 @@ constexpr inline QskAspect::States QskStateCombination::states() const noexcept
return m_states;
}
constexpr bool QskStateCombination::operator==( QskStateCombination other ) const noexcept
{
return ( m_type == other.m_type ) && ( m_states == other.m_states );
}
constexpr bool QskStateCombination::operator!=( QskStateCombination other ) const noexcept
{
return !( *this == other );
}
#endif

View File

@ -128,7 +128,6 @@ class QskSkin::PrivateData
std::unordered_map< const QMetaObject*, SkinletData > skinletMap;
QskSkinHintTable hintTable;
QskAspect::States stateMask = QskAspect::AllStates;
std::unordered_map< int, QFont > fonts;
std::unordered_map< int, QskColorFilter > graphicFilters;
@ -345,22 +344,6 @@ const int* QskSkin::dialogButtonLayout( Qt::Orientation orientation ) const
return QPlatformDialogHelper::buttonLayout( orientation, policy );
}
void QskSkin::setStateMask( QskAspect::States mask )
{
for ( auto state : { QskControl::Disabled, QskControl::Hovered, QskControl::Focused } )
{
if ( mask & state )
m_data->stateMask |= state;
else
m_data->stateMask &= ~state;
}
}
QskAspect::States QskSkin::stateMask() const
{
return m_data->stateMask;
}
QskSkinlet* QskSkin::skinlet( const QMetaObject* metaObject )
{
while ( metaObject )

View File

@ -77,9 +77,6 @@ class QSK_EXPORT QskSkin : public QObject
virtual const int* dialogButtonLayout( Qt::Orientation ) const;
virtual QString dialogButtonText( int button ) const;
void setStateMask( QskAspect::States );
QskAspect::States stateMask() const;
QskSkinlet* skinlet( const QMetaObject* );
const QskSkinHintTable& hintTable() const;

View File

@ -64,41 +64,11 @@ QskSkinHintTable::QskSkinHintTable()
{
}
QskSkinHintTable::QskSkinHintTable( const QskSkinHintTable& other )
: m_hints( nullptr )
, m_animatorCount( other.m_animatorCount )
, m_statefulCount( other.m_statefulCount )
{
if ( other.m_hints )
m_hints = new HintMap( *( other.m_hints ) );
}
QskSkinHintTable::~QskSkinHintTable()
{
delete m_hints;
}
QskSkinHintTable& QskSkinHintTable::operator=( const QskSkinHintTable& other )
{
m_animatorCount = other.m_animatorCount;
m_statefulCount = other.m_statefulCount;
if ( other.m_hints )
{
if ( m_hints == nullptr )
m_hints = new HintMap();
*m_hints = *other.m_hints;
}
else
{
delete m_hints;
m_hints = nullptr;
}
return *this;
}
const std::unordered_map< QskAspect, QVariant >& QskSkinHintTable::hints() const
{
if ( m_hints )
@ -126,11 +96,7 @@ bool QskSkinHintTable::setHint( QskAspect aspect, const QVariant& skinHint )
QSK_ASSERT_COUNTER( m_animatorCount );
}
if ( aspect.hasStates() )
{
m_statefulCount++;
QSK_ASSERT_COUNTER( m_statefulCount );
}
m_states |= aspect.states();
return true;
}
@ -158,8 +124,7 @@ bool QskSkinHintTable::removeHint( QskAspect aspect )
if ( aspect.isAnimator() )
m_animatorCount--;
if ( aspect.hasStates() )
m_statefulCount--;
// how to clear m_states ? TODO ...
if ( m_hints->empty() )
{
@ -184,8 +149,7 @@ QVariant QskSkinHintTable::takeHint( QskAspect aspect )
if ( aspect.isAnimator() )
m_animatorCount--;
if ( aspect.hasStates() )
m_statefulCount--;
// how to clear m_states ? TODO ...
if ( m_hints->empty() )
{
@ -206,14 +170,14 @@ void QskSkinHintTable::clear()
m_hints = nullptr;
m_animatorCount = 0;
m_statefulCount = 0;
m_states = QskAspect::NoState;
}
const QVariant* QskSkinHintTable::resolvedHint(
QskAspect aspect, QskAspect* resolvedAspect ) const
{
if ( m_hints != nullptr )
return qskResolvedHint( aspect, *m_hints, resolvedAspect );
return qskResolvedHint( aspect & m_states, *m_hints, resolvedAspect );
return nullptr;
}
@ -223,7 +187,7 @@ QskAspect QskSkinHintTable::resolvedAspect( QskAspect aspect ) const
QskAspect a;
if ( m_hints != nullptr )
qskResolvedHint( aspect, *m_hints, &a );
qskResolvedHint( aspect & m_states, *m_hints, &a );
return a;
}
@ -233,6 +197,8 @@ QskAspect QskSkinHintTable::resolvedAnimator(
{
if ( m_hints && m_animatorCount > 0 )
{
aspect &= m_states;
Q_FOREVER
{
auto it = m_hints->find( aspect );
@ -268,15 +234,16 @@ bool QskSkinHintTable::setAnimation(
bool QskSkinHintTable::isResolutionMatching(
QskAspect aspect1, QskAspect aspect2 ) const
{
// remove states we do not have early
aspect1 &= m_states;
aspect2 &= m_states;
if ( aspect1 == aspect2 )
return true;
if ( aspect1.trunk() != aspect2.trunk() )
return false;
if ( !hasStates() )
return false;
const auto a1 = aspect1;
const auto a2 = aspect2;

View File

@ -17,12 +17,8 @@ class QSK_EXPORT QskSkinHintTable
{
public:
QskSkinHintTable();
QskSkinHintTable( const QskSkinHintTable& other );
~QskSkinHintTable();
QskSkinHintTable& operator=( const QskSkinHintTable& );
bool setAnimation( QskAspect, QskAnimationHint );
QskAnimationHint animation( QskAspect ) const;
@ -40,9 +36,10 @@ class QSK_EXPORT QskSkinHintTable
const std::unordered_map< QskAspect, QVariant >& hints() const;
bool hasAnimators() const;
bool hasStates() const;
bool hasHints() const;
QskAspect::States states() const;
void clear();
const QVariant* resolvedHint( QskAspect,
@ -56,13 +53,15 @@ class QSK_EXPORT QskSkinHintTable
bool isResolutionMatching( QskAspect, QskAspect ) const;
private:
Q_DISABLE_COPY( QskSkinHintTable )
static const QVariant invalidHint;
typedef std::unordered_map< QskAspect, QVariant > HintMap;
HintMap* m_hints = nullptr;
unsigned short m_animatorCount = 0;
unsigned short m_statefulCount = 0;
QskAspect::States m_states;
};
inline bool QskSkinHintTable::hasHints() const
@ -70,9 +69,9 @@ inline bool QskSkinHintTable::hasHints() const
return m_hints != nullptr;
}
inline bool QskSkinHintTable::hasStates() const
inline QskAspect::States QskSkinHintTable::states() const
{
return m_statefulCount > 0;
return m_states;
}
inline bool QskSkinHintTable::hasAnimators() const

File diff suppressed because it is too large Load Diff

View File

@ -38,17 +38,6 @@ static inline bool qskIsControl( const QskSkinnable* skinnable )
return skinnable->metaObject()->inherits( &QskControl::staticMetaObject );
}
static inline QVariant qskTypedNullValue( const QVariant& value )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
const auto vType = static_cast< QMetaType >( value.userType() );
#else
const auto vType = value.userType();
#endif
return QVariant( vType, nullptr );
}
static inline bool qskSetFlag( QskSkinnable* skinnable,
const QskAspect aspect, int flag )
{
@ -940,23 +929,12 @@ const QVariant& QskSkinnable::storedHint(
{
const auto skin = effectiveSkin();
// clearing all state bits not being handled from the skin
aspect.clearStates( ~skin->stateMask() );
QskAspect resolvedAspect;
const auto& localTable = m_data->hintTable;
if ( localTable.hasHints() )
{
auto a = aspect;
if ( !localTable.hasStates() )
{
// we don't need to clear the state bits stepwise
a.clearStates();
}
if ( const QVariant* value = localTable.resolvedHint( a, &resolvedAspect ) )
if ( const auto value = localTable.resolvedHint( aspect, &resolvedAspect ) )
{
if ( status )
{
@ -972,10 +950,7 @@ const QVariant& QskSkinnable::storedHint(
const auto& skinTable = skin->hintTable();
if ( skinTable.hasHints() )
{
auto a = aspect;
const QVariant* value = skinTable.resolvedHint( a, &resolvedAspect );
if ( value )
if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
{
if ( status )
{
@ -993,8 +968,7 @@ const QVariant& QskSkinnable::storedHint(
aspect.setSubControl( QskAspect::Control );
aspect.clearStates();
value = skinTable.resolvedHint( aspect, &resolvedAspect );
if ( value )
if ( const auto value = skinTable.resolvedHint( aspect, &resolvedAspect ) )
{
if ( status )
{
@ -1171,27 +1145,11 @@ void QskSkinnable::startHintTransition( QskAspect aspect,
if ( control->window() == nullptr || !isTransitionAccepted( aspect ) )
return;
/*
We might be invalid for one of the values, when an aspect
has not been defined for all states ( f.e. metrics are expected
to fallback to 0.0 ). In this case we create a default one.
*/
auto v1 = from;
auto v2 = to;
if ( !v1.isValid() )
{
v1 = qskTypedNullValue( v2 );
}
else if ( !v2.isValid() )
{
v2 = qskTypedNullValue( v1 );
}
else if ( v1.userType() != v2.userType() )
{
if ( !QskVariantAnimator::convertValues( v1, v2 ) )
return;
}
if ( aspect.flagPrimitive() == QskAspect::GraphicRole )
{
@ -1257,7 +1215,8 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates )
if ( skin )
{
const auto mask = skin->stateMask();
const auto mask = skin->hintTable().states() | m_data->hintTable.states();
if ( ( newStates & mask ) == ( m_data->skinStates & mask ) )
{
// the modified bits are not handled by the skin
@ -1297,24 +1256,13 @@ void QskSkinnable::setSkinStates( QskAspect::States newStates )
const auto primitive = static_cast< QskAspect::Primitive >( i );
aspect.setPrimitive( type, primitive );
auto a1 = aspect | m_data->skinStates;
auto a2 = aspect | newStates;
const auto a1 = aspect | m_data->skinStates;
const auto a2 = aspect | newStates;
bool doTransition = true;
if ( !m_data->hintTable.hasStates() )
{
/*
The hints are found by stripping the state bits one by
one until a lookup into the hint table is successful.
So for deciding whether two aspects lead to the same hint
we can stop as soon as the aspects have the same state bits.
This way we can reduce the number of lookups significantly
for skinnables with many state bits.
*/
if ( m_data->hintTable.states() == QskAspect::NoState )
doTransition = !skinTable.isResolutionMatching( a1, a2 );
}
if ( doTransition )
{
@ -1343,12 +1291,7 @@ QskSkin* QskSkinnable::effectiveSkin() const
if ( skin == nullptr )
{
if ( const auto control = owningControl() )
{
if ( auto window = qobject_cast< const QskWindow* >( control->window() ) )
{
skin = window->skin();
}
}
skin = qskEffectiveSkin( control->window() );
}
return skin ? skin : qskSetup->skin();

View File

@ -230,6 +230,8 @@ class QSK_EXPORT QskSkinnable
bool resetGraphicRoleHint( QskAspect );
int graphicRoleHint( QskAspect, QskSkinHintStatus* = nullptr ) const;
const QskSkinHintTable& hintTable() const;
protected:
virtual void updateNode( QSGNode* );
virtual bool isTransitionAccepted( QskAspect ) const;
@ -237,7 +239,6 @@ class QSK_EXPORT QskSkinnable
virtual QskAspect::Subcontrol substitutedSubcontrol( QskAspect::Subcontrol ) const;
QskSkinHintTable& hintTable();
const QskSkinHintTable& hintTable() const;
private:
Q_DISABLE_COPY( QskSkinnable )

View File

@ -76,6 +76,31 @@ QSK_DECL_INSANE static inline QVariant qskInterpolate(
return f( from.constData(), to.constData(), progress );
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
using QskMetaType = int;
static inline QskMetaType qskMetaType( const QVariant& v ) { return v.userType(); }
#else
using QskMetaType = QMetaType;
static inline QskMetaType qskMetaType( const QVariant& v ) { return v.metaType(); }
#endif
static inline QVariant qskDefaultVariant( QskMetaType type )
{
return QVariant( type, nullptr );
}
static inline QVariant qskConvertedVariant( const QVariant& from, QskMetaType type )
{
auto v = from;
v.convert( type );
return v;
}
QskVariantAnimator::QskVariantAnimator()
: m_interpolator( nullptr )
{
@ -100,16 +125,60 @@ void QskVariantAnimator::setCurrentValue( const QVariant& value )
m_currentValue = value;
}
bool QskVariantAnimator::convertValues( QVariant& v1, QVariant& v2 )
{
if ( !v1.isValid() && !v2.isValid() )
return false;
const auto type1 = qskMetaType( v1 );
const auto type2 = qskMetaType( v2 );
if ( !v1.isValid() )
{
v1 = qskDefaultVariant( type2 );
return true;
}
if ( !v2.isValid() )
{
v2 = qskDefaultVariant( type1 );
return true;
}
if ( type1 != type2 )
{
if ( v1.canConvert( type2 ) )
{
v1.convert( type2 );
return true;
}
if ( v2.canConvert( type1 ) )
{
v2.convert( type1 );
return true;
}
return false;
}
return true;
}
void QskVariantAnimator::setup()
{
m_interpolator = nullptr;
const auto type = m_startValue.userType();
if ( type == m_endValue.userType() )
if ( convertValues( m_startValue, m_endValue ) )
{
// all what has been registered by qRegisterAnimationInterpolator
m_interpolator = reinterpret_cast< void ( * )() >(
QVariantAnimationPrivate::getInterpolator( type ) );
if ( m_startValue != m_endValue )
{
const auto id = m_startValue.userType();
// all what has been registered by qRegisterAnimationInterpolator
m_interpolator = reinterpret_cast< void ( * )() >(
QVariantAnimationPrivate::getInterpolator( id ) );
}
}
m_currentValue = m_interpolator ? m_startValue : m_endValue;
@ -131,3 +200,32 @@ void QskVariantAnimator::done()
{
m_interpolator = nullptr;
}
bool QskVariantAnimator::maybeInterpolate(
const QVariant& value1, const QVariant& value2 )
{
if ( !value1.isValid() && !value2.isValid() )
return false;
const auto type1 = qskMetaType( value1 );
const auto type2 = qskMetaType( value2 );
if ( !value1.isValid() )
return value2 != qskDefaultVariant( type2 );
if ( !value2.isValid() )
return value1 != qskDefaultVariant( type1 );
if ( type1 != type2 )
{
if ( value1.canConvert( type2 ) )
return value2 != qskConvertedVariant( value1, type2 );
if ( value2.canConvert( type1 ) )
return value1 != qskConvertedVariant( value2, type1 );
return false;
}
return value1 != value2;
}

View File

@ -24,6 +24,9 @@ class QSK_EXPORT QskVariantAnimator : public QskAnimator
void setEndValue( const QVariant& );
QVariant endValue() const;
static bool maybeInterpolate( const QVariant&, const QVariant& );
static bool convertValues( QVariant&, QVariant& );
protected:
void setup() override;
void advance( qreal value ) override;

View File

@ -63,7 +63,6 @@ SOURCES += \
common/QskScaleTickmarks.cpp \
common/QskShadowMetrics.cpp \
common/QskSizePolicy.cpp \
common/QskStateCombination.cpp \
common/QskTextColors.cpp \
common/QskTextOptions.cpp

View File

@ -77,30 +77,31 @@ void SkinnyShortcut::enable( Types types )
void SkinnyShortcut::rotateSkin()
{
const QStringList names = qskSkinManager->skinNames();
const auto names = qskSkinManager->skinNames();
if ( names.size() <= 1 )
return;
int index = names.indexOf( qskSetup->skinName() );
index = ( index + 1 ) % names.size();
QskSkin* oldSkin = qskSetup->skin();
auto oldSkin = qskSetup->skin();
if ( oldSkin->parent() == qskSetup )
oldSkin->setParent( nullptr ); // otherwise setSkin deletes it
QskSkin* newSkin = qskSetup->setSkin( names[ index ] );
if ( auto newSkin = qskSetup->setSkin( names[ index ] ) )
{
QskSkinTransition transition;
QskSkinTransition transition;
//transition.setMask( QskAspect::Color ); // Metrics are flickering -> TODO
transition.setSourceSkin( oldSkin );
transition.setTargetSkin( newSkin );
transition.setAnimation( 500 );
//transition.setMask( QskAspect::Color ); // Metrics are flickering -> TODO
transition.setSourceSkin( oldSkin );
transition.setTargetSkin( newSkin );
transition.setAnimation( 500 );
transition.process();
transition.process();
if ( oldSkin->parent() == nullptr )
delete oldSkin;
if ( oldSkin->parent() == nullptr )
delete oldSkin;
}
}
void SkinnyShortcut::showBackground()