diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index fdbfdc8e..d0113d65 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -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 ); diff --git a/skins/windows/QskWindowsSkin.cpp b/skins/windows/QskWindowsSkin.cpp index d6169122..a171fe79 100644 --- a/skins/windows/QskWindowsSkin.cpp +++ b/skins/windows/QskWindowsSkin.cpp @@ -500,6 +500,65 @@ void Editor::setupSlider() 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, QskWindowsSkin::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, QskWindowsSkin::GraphicRoleFillColorTextSecondary ); + setGraphicRole( Q::DownIndicator, QskWindowsSkin::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, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); + setGraphicRole( Q::DownIndicator | Q::Disabled, QskWindowsSkin::GraphicRoleFillColorTextDisabled ); } void Editor::setupTabBar() diff --git a/skins/windows/icons.qrc b/skins/windows/icons.qrc index b84bca05..97c702ce 100644 --- a/skins/windows/icons.qrc +++ b/skins/windows/icons.qrc @@ -4,5 +4,7 @@ icons/qvg/combo-box-arrow-closed.qvg icons/qvg/combo-box-arrow-open.qvg icons/qvg/segmented-button-check.qvg + icons/qvg/spin-box-arrow-down.qvg + icons/qvg/spin-box-arrow-up.qvg diff --git a/skins/windows/icons/qvg/spin-box-arrow-down.qvg b/skins/windows/icons/qvg/spin-box-arrow-down.qvg new file mode 100644 index 00000000..2825e1fb Binary files /dev/null and b/skins/windows/icons/qvg/spin-box-arrow-down.qvg differ diff --git a/skins/windows/icons/qvg/spin-box-arrow-up.qvg b/skins/windows/icons/qvg/spin-box-arrow-up.qvg new file mode 100644 index 00000000..3ae75f32 Binary files /dev/null and b/skins/windows/icons/qvg/spin-box-arrow-up.qvg differ diff --git a/skins/windows/icons/spin-box-arrow-down.svg b/skins/windows/icons/spin-box-arrow-down.svg new file mode 100644 index 00000000..a3ffcd48 --- /dev/null +++ b/skins/windows/icons/spin-box-arrow-down.svg @@ -0,0 +1,4 @@ + + + + diff --git a/skins/windows/icons/spin-box-arrow-up.svg b/skins/windows/icons/spin-box-arrow-up.svg new file mode 100644 index 00000000..34301711 --- /dev/null +++ b/skins/windows/icons/spin-box-arrow-up.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/controls/QskSpinBox.cpp b/src/controls/QskSpinBox.cpp index 693d6b76..9959cac7 100644 --- a/src/controls/QskSpinBox.cpp +++ b/src/controls/QskSpinBox.cpp @@ -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 ) diff --git a/src/controls/QskSpinBox.h b/src/controls/QskSpinBox.h index d1066109..5837e951 100644 --- a/src/controls/QskSpinBox.h +++ b/src/controls/QskSpinBox.h @@ -37,7 +37,8 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput { NoDecoration, - Buttons, + ButtonsLeftAndRight, + ButtonsRight, UpDownControl }; Q_ENUM( Decoration ) diff --git a/src/controls/QskSpinBoxSkinlet.cpp b/src/controls/QskSpinBoxSkinlet.cpp index f8a5df08..b0394f30 100644 --- a/src/controls/QskSpinBoxSkinlet.cpp +++ b/src/controls/QskSpinBoxSkinlet.cpp @@ -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 ); diff --git a/src/controls/QskSpinBoxSkinlet.h b/src/controls/QskSpinBoxSkinlet.h index 72eb8840..81fc3fdb 100644 --- a/src/controls/QskSpinBoxSkinlet.h +++ b/src/controls/QskSpinBoxSkinlet.h @@ -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 };