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
};