diff --git a/examples/gallery/gallery.pro b/examples/gallery/gallery.pro index 0d5c9042..7c7586ae 100644 --- a/examples/gallery/gallery.pro +++ b/examples/gallery/gallery.pro @@ -7,10 +7,10 @@ SOURCES += \ label/LabelPage.cpp \ HEADERS += \ - slider/SliderPage.h + inputs/InputPage.h SOURCES += \ - slider/SliderPage.cpp + inputs/InputPage.cpp HEADERS += \ progressbar/ProgressBarPage.h @@ -24,12 +24,6 @@ HEADERS += \ SOURCES += \ button/ButtonPage.cpp \ -HEADERS += \ - textinput/TextInputPage.h - -SOURCES += \ - textinput/TextInputPage.cpp \ - HEADERS += \ selector/SelectorPage.h @@ -42,12 +36,6 @@ HEADERS += \ SOURCES += \ dialog/DialogPage.cpp \ -HEADERS += \ - spinbox/SpinBoxPage.h - -SOURCES += \ - spinbox/SpinBoxPage.cpp - HEADERS += \ Page.h diff --git a/examples/gallery/inputs/InputPage.cpp b/examples/gallery/inputs/InputPage.cpp new file mode 100644 index 00000000..bb8b2685 --- /dev/null +++ b/examples/gallery/inputs/InputPage.cpp @@ -0,0 +1,92 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "InputPage.h" + +#include +#include +#include +#include + +namespace +{ + class Slider : public QskSlider + { + public: + Slider( Qt::Orientation orientation, QQuickItem* parent = nullptr ) + : QskSlider( orientation, parent ) + { + setBoundaries( 0, 1000 ); + setValue( 300 ); + + setPageSize( 10 ); + setStepSize( 10 ); + setSnap( true ); + +#if 0 + connect( this, &QskSlider::valueChanged, + []( qreal value ) { qDebug() << value; } ); +#endif + } + }; + + class InputBox : public QskLinearBox + { + public: + InputBox( QQuickItem* parent = nullptr ) + : QskLinearBox( Qt::Horizontal, 3, parent ) + { + setSpacing( 20 ); + setExtraSpacingAt( Qt::BottomEdge ); + + { + new QskTextInput( "Edit Me", this ); + } + + { + auto input = new QskTextInput( "Only Read Me", this ); + input->setReadOnly( true ); + } + + { + auto input = new QskTextInput( "12345", this ); + input->setMaxLength( 5 ); + input->setEchoMode( QskTextInput::PasswordEchoOnEdit ); + } + + { + auto spinBox = new QskSpinBox( 0.0, 100.0, 1.0, this ); + spinBox->setPageSize( 5 ); + spinBox->setValue( 35 ); + } + + { + auto spinBox = new QskSpinBox( this ); + spinBox->setDecoration( QskSpinBox::NoDecoration ); + spinBox->setValue( 50 ); + } + } + }; +} + +InputPage::InputPage( QQuickItem* parent ) + : Page( Qt::Horizontal, parent ) +{ + populate(); +} + +void InputPage::populate() +{ + auto sliderH = new Slider( Qt::Horizontal ); + auto sliderV = new Slider( Qt::Vertical ); + + auto inputBox = new InputBox(); + + auto gridBox = new QskGridBox( this ); + + gridBox->addItem( sliderV, 0, 0, -1, 1 ); + gridBox->addItem( sliderH, 0, 1, 1, -1 ); + gridBox->addItem( inputBox, 1, 1, -1, -1 ); +} diff --git a/examples/gallery/slider/SliderPage.h b/examples/gallery/inputs/InputPage.h similarity index 83% rename from examples/gallery/slider/SliderPage.h rename to examples/gallery/inputs/InputPage.h index 6af6b7fb..ce6da0b5 100644 --- a/examples/gallery/slider/SliderPage.h +++ b/examples/gallery/inputs/InputPage.h @@ -7,10 +7,10 @@ #include "Page.h" -class SliderPage : public Page +class InputPage : public Page { public: - SliderPage( QQuickItem* = nullptr ); + InputPage( QQuickItem* = nullptr ); private: void populate(); diff --git a/examples/gallery/main.cpp b/examples/gallery/main.cpp index 9bc35a0a..552054f9 100644 --- a/examples/gallery/main.cpp +++ b/examples/gallery/main.cpp @@ -5,12 +5,10 @@ #include "label/LabelPage.h" #include "progressbar/ProgressBarPage.h" -#include "slider/SliderPage.h" +#include "inputs/InputPage.h" #include "button/ButtonPage.h" -#include "textinput/TextInputPage.h" #include "selector/SelectorPage.h" #include "dialog/DialogPage.h" -#include "spinbox/SpinBoxPage.h" #include #include @@ -195,14 +193,10 @@ namespace auto tabView = new TabView( this ); tabView->addTab( "Buttons", new ButtonPage() ); tabView->addTab( "Labels", new LabelPage() ); - tabView->addTab( "Sliders", new SliderPage() ); + tabView->addTab( "Inputs", new InputPage() ); tabView->addTab( "Progress\nBars", new ProgressBarPage() ); - tabView->addTab( "Text\nInputs", new TextInputPage() ); tabView->addTab( "Selectors", new SelectorPage() ); tabView->addTab( "Dialogs", new DialogPage() ); - tabView->addTab( "SpinBoxes", new SpinBoxPage() ); - - tabView->setCurrentIndex(tabView->count() - 1); connect( header, &Header::enabledToggled, tabView, &TabView::setTabsEnabled ); diff --git a/examples/gallery/slider/SliderPage.cpp b/examples/gallery/slider/SliderPage.cpp deleted file mode 100644 index 733692d6..00000000 --- a/examples/gallery/slider/SliderPage.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#include "SliderPage.h" -#include - -namespace -{ - class Slider : public QskSlider - { - public: - Slider( Qt::Orientation orientation, QQuickItem* parent = nullptr ) - : QskSlider( orientation, parent ) - { - setBoundaries( 0, 1000 ); - - setPageSize( 10 ); - setStepSize( 10 ); - setSnap( true ); - } - }; -} - -SliderPage::SliderPage( QQuickItem* parent ) - : Page( Qt::Horizontal, parent ) -{ - setMargins( 10 ); - setSpacing( 20 ); - - populate(); - - const auto sliders = findChildren< QskSlider* >(); - - for ( auto slider : sliders ) - { - slider->setLayoutAlignmentHint( Qt::AlignCenter ); - - slider->setValue( slider->minimum() + - 0.5 * ( slider->maximum() - slider->minimum() ) ); -#if 0 - connect( slider, &QskSlider::valueChanged, - []( qreal value ) { qDebug() << value; } ); -#endif - } -} - -void SliderPage::populate() -{ - ( void ) new Slider( Qt::Horizontal, this ); - ( void ) new Slider( Qt::Vertical, this ); -} diff --git a/examples/gallery/spinbox/SpinBoxPage.cpp b/examples/gallery/spinbox/SpinBoxPage.cpp deleted file mode 100644 index e4930f1e..00000000 --- a/examples/gallery/spinbox/SpinBoxPage.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2023 Edelhirsch Software GmbH - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#include "SpinBoxPage.h" -#include -#include -#include -#include -#include - -SpinBoxPage::SpinBoxPage( QQuickItem* parent ) - : Page( Qt::Horizontal, parent ) -{ - setMargins( 10 ); - setSpacing( 20 ); - - populate(); -} - -void SpinBoxPage::populate() -{ - const QMap< Qt::Alignment, QString > layouts = { { Qt::AlignLeft, - QStringLiteral( "Qt::AlignLeft" ) }, - { Qt::AlignHCenter, QStringLiteral( "Qt::AlignHCenter" ) }, - { Qt::AlignRight, QStringLiteral( "Qt::AlignRight" ) }, - { Qt::AlignTop, QStringLiteral( "Qt::AlignTop" ) }, - { Qt::AlignVCenter, QStringLiteral( "Qt::AlignVCenter" ) }, - { Qt::AlignBottom, QStringLiteral( "Qt::AlignBottom" ) }, - { Qt::AlignLeft | Qt::AlignVCenter, QStringLiteral( "Qt::AlignLeft | Qt::AlignVCenter" ) }, - { Qt::AlignRight | Qt::AlignVCenter, - QStringLiteral( "Qt::AlignRight | Qt::AlignVCenter" ) }, - { Qt::AlignTop | Qt::AlignHCenter, QStringLiteral( "Qt::AlignTop | Qt::AlignHCenter" ) }, - { Qt::AlignBottom | Qt::AlignHCenter, - QStringLiteral( "Qt::AlignBottom | Qt::AlignHCenter" ) } }; - - auto* const grid = new QskGridBox( this ); - constexpr int cols = 5; - - QVector< QskSpinBox* > spinboxes; - for ( const auto& layout : layouts.keys() ) - { - const auto x = grid->elementCount() % cols; - const auto y = grid->elementCount() / cols; - auto* const column = new QskLinearBox( Qt::Vertical, grid ); - auto* const label = new QskTextLabel( layouts.value( layout ), column ); - auto* const spinbox = new QskSpinBox( column ); - spinbox->setAlignmentHint( QskSpinBox::Panel, layout ); - grid->addItem( column, y, x ); - column->setStretchFactor( label, 1 ); - column->setStretchFactor( spinbox, 99 ); - spinboxes << spinbox; - } - - const auto strutInc = spinboxes[ 0 ]->strutSizeHint( QskSpinBox::UpPanel ); - const auto strutDec = spinboxes[ 0 ]->strutSizeHint( QskSpinBox::DownPanel ); - - auto* const columnIncW = new QskLinearBox( Qt::Vertical, this ); - auto* const sliderIncW = new QskSlider( Qt::Vertical, columnIncW ); - new QskTextLabel( "+W", columnIncW ); - - auto* const columnIncH = new QskLinearBox( Qt::Vertical, this ); - auto* const sliderIncH = new QskSlider( Qt::Vertical, columnIncH ); - new QskTextLabel( "+H", columnIncH ); - - auto* const columnDecW = new QskLinearBox( Qt::Vertical, this ); - auto* const sliderDecW = new QskSlider( Qt::Vertical, columnDecW ); - new QskTextLabel( "-W", columnDecW ); - - auto* const columnDecH = new QskLinearBox( Qt::Vertical, this ); - auto* const sliderDecH = new QskSlider( Qt::Vertical, columnDecH ); - new QskTextLabel( "-H", columnDecH ); - - setStretchFactor( columnIncW, 1 ); - setStretchFactor( columnIncH, 1 ); - setStretchFactor( columnDecW, 1 ); - setStretchFactor( columnDecH, 1 ); - setStretchFactor( grid, 99 ); - - sliderIncW->setBoundaries( 2, strutInc.width() * 4 ); - sliderIncH->setBoundaries( 2, strutInc.height() * 4 ); - sliderDecW->setBoundaries( 2, strutDec.width() * 4 ); - sliderDecH->setBoundaries( 2, strutDec.height() * 4 ); - - sliderIncW->setValue( strutInc.width() ); - sliderIncH->setValue( strutInc.height() ); - sliderDecW->setValue( strutDec.width() ); - sliderDecH->setValue( strutDec.height() ); - - auto update = [ spinboxes, sliderIncW, sliderIncH, sliderDecW, sliderDecH ]( qreal ) { - const auto incSize = QSizeF{ sliderIncW->value(), sliderIncH->value() }; - const auto decSize = QSizeF{ sliderDecW->value(), sliderDecH->value() }; - for ( auto* spinbox : spinboxes ) - { - spinbox->setStrutSizeHint( QskSpinBox::UpPanel, incSize ); - spinbox->setStrutSizeHint( QskSpinBox::DownPanel, decSize ); - } - }; - - connect( sliderIncW, &QskSlider::valueChanged, this, update ); - connect( sliderIncH, &QskSlider::valueChanged, this, update ); - connect( sliderDecW, &QskSlider::valueChanged, this, update ); - connect( sliderDecH, &QskSlider::valueChanged, this, update ); -} diff --git a/examples/gallery/spinbox/SpinBoxPage.h b/examples/gallery/spinbox/SpinBoxPage.h deleted file mode 100644 index 2597e341..00000000 --- a/examples/gallery/spinbox/SpinBoxPage.h +++ /dev/null @@ -1,17 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2023 Edelhirsch Software GmbH - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#pragma once - -#include "Page.h" - -class SpinBoxPage : public Page -{ - public: - SpinBoxPage( QQuickItem* = nullptr ); - - private: - void populate(); -}; diff --git a/examples/gallery/textinput/TextInputPage.cpp b/examples/gallery/textinput/TextInputPage.cpp deleted file mode 100644 index 9346d4cd..00000000 --- a/examples/gallery/textinput/TextInputPage.cpp +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#include "TextInputPage.h" - -#include -#include - -TextInputPage::TextInputPage( QQuickItem* parent ) - : Page( parent ) -{ - setSpacing( 40 ); - populate(); -} - -void TextInputPage::populate() -{ - auto box = new QskLinearBox( Qt::Horizontal, 2, this ); - box->setExtraSpacingAt( Qt::BottomEdge ); - - { - new QskTextInput( "Edit Me", box ); - } - - { - auto input = new QskTextInput( "Only Read Me", box ); - input->setReadOnly( true ); - } - - { - auto input = new QskTextInput( "12345", box ); - input->setMaxLength( 5 ); - input->setEchoMode( QskTextInput::PasswordEchoOnEdit ); - } - - { - // once we have QskTextEdit it will be here too. - } -} diff --git a/examples/gallery/textinput/TextInputPage.h b/examples/gallery/textinput/TextInputPage.h deleted file mode 100644 index 879eb635..00000000 --- a/examples/gallery/textinput/TextInputPage.h +++ /dev/null @@ -1,17 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the 3-clause BSD License - *****************************************************************************/ - -#pragma once - -#include "Page.h" - -class TextInputPage : public Page -{ - public: - TextInputPage( QQuickItem* = nullptr ); - - private: - void populate(); -}; diff --git a/src/controls/QskSpinBox.cpp b/src/controls/QskSpinBox.cpp index 75a99b93..3001f666 100644 --- a/src/controls/QskSpinBox.cpp +++ b/src/controls/QskSpinBox.cpp @@ -37,14 +37,23 @@ namespace return QskAspect::NoSubcontrol; } + + inline QskAspect aspectDecoration() + { + return QskSpinBox::Panel | QskAspect::Flag | QskAspect::Style; + } + + inline QskAspect aspectTextAlignment() + { + return QskSpinBox::TextPanel | QskAspect::Flag | QskAspect::Alignment; + } } class QskSpinBox::PrivateData { public: PrivateData() - : buttons( true ) - , tracking( true ) + : tracking( true ) , wrapping( false ) , accelerating( false ) { @@ -100,19 +109,19 @@ class QskSpinBox::PrivateData int key = Qt::Key_unknown; - bool buttons : 1; - bool tracking : 1; - bool wrapping : 1; + bool tracking : 1; + bool wrapping : 1; bool accelerating : 1; // not yet implemented: TODO ... }; -QskSpinBox::QskSpinBox( QQuickItem* parent ) +QskSpinBox::QskSpinBox( qreal min, qreal max, qreal stepSize, QQuickItem* parent ) : Inherited( parent ) , m_data( new PrivateData ) { initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed ); - setBoundaries( 0.0, 99.99 ); // this is what QDoubleSpinBox does + setBoundaries( min, max ); + setStepSize( stepSize ); setAcceptedMouseButtons( Qt::LeftButton ); setFocusPolicy( Qt::StrongFocus ); @@ -120,22 +129,50 @@ QskSpinBox::QskSpinBox( QQuickItem* parent ) connect( this, &QskSpinBox::valueChanged, this, &QskSpinBox::textChanged ); } +QskSpinBox::QskSpinBox( QQuickItem* parent ) + : QskSpinBox( 0.0, 99.99, 0.1, parent ) +{ +} + QskSpinBox::~QskSpinBox() { } -void QskSpinBox::setButtons( bool on ) +void QskSpinBox::setDecoration( Decoration decoration ) { - if ( on != m_data->buttons ) - { - m_data->buttons = on; - Q_EMIT buttonsChanged( on ); - } + if ( setFlagHint( aspectDecoration(), decoration ) ) + Q_EMIT decorationChanged( decoration ); } -bool QskSpinBox::hasButtons() const +void QskSpinBox::resetDecoration() { - return m_data->buttons; + if ( resetFlagHint( aspectDecoration() ) ) + Q_EMIT decorationChanged( decoration() ); +} + +QskSpinBox::Decoration QskSpinBox::decoration() const +{ + return flagHint< QskSpinBox::Decoration >( aspectDecoration(), Buttons ); +} + +void QskSpinBox::setTextAlignment( Qt::Alignment alignment ) +{ + alignment &= Qt::AlignHorizontal_Mask; + + if ( setFlagHint( aspectTextAlignment(), alignment ) ) + Q_EMIT textAlignmentChanged( alignment ); +} + +void QskSpinBox::resetTextAlignment() +{ + if ( resetFlagHint( aspectTextAlignment() ) ) + Q_EMIT textAlignmentChanged( textAlignment() ); +} + +Qt::Alignment QskSpinBox::textAlignment() const +{ + return flagHint< Qt::Alignment >( + aspectTextAlignment(), Qt::AlignLeft ) & Qt::AlignHorizontal_Mask; } void QskSpinBox::setTracking( bool on ) diff --git a/src/controls/QskSpinBox.h b/src/controls/QskSpinBox.h index 240fa505..0a1435cf 100644 --- a/src/controls/QskSpinBox.h +++ b/src/controls/QskSpinBox.h @@ -22,12 +22,15 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput Q_PROPERTY( bool accelerating READ isAccelerating WRITE setAccelerating NOTIFY acceleratingChanged ) - Q_PROPERTY( bool buttons READ hasButtons - WRITE setButtons NOTIFY buttonsChanged ) + Q_PROPERTY( Decoration decoration READ decoration + WRITE setDecoration RESET resetDecoration NOTIFY decorationChanged ) Q_PROPERTY( int decimals READ decimals WRITE setDecimals NOTIFY decimalsChanged ) + Q_PROPERTY( Qt::Alignment textAlignment READ textAlignment + WRITE setTextAlignment RESET textAlignment NOTIFY textAlignmentChanged ) + Q_PROPERTY( QString text READ text NOTIFY textChanged ) public: @@ -36,11 +39,29 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput QSK_STATES( Decreasing, Increasing ) + enum Decoration + { + NoDecoration, + + Buttons, + UpDownControl + }; + Q_ENUM( Decoration ) + QskSpinBox( QQuickItem* parent = nullptr ); + QskSpinBox( qreal min, qreal max, qreal stepSize, + QQuickItem* parent = nullptr ); + ~QskSpinBox() override; - void setButtons( bool ); - bool hasButtons() const; + void setDecoration( Decoration ); + void resetDecoration(); + Decoration decoration() const; + + // Qt::AlignLeft, Qt::AlignRight or Qt::AlignHCenter. + void setTextAlignment( Qt::Alignment ); + void resetTextAlignment(); + Qt::Alignment textAlignment() const; void setWrapping( bool ); bool isWrapping() const; @@ -55,9 +76,11 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput int decimals() const; QString text() const; + virtual QString textFromValue( qreal ) const; Q_SIGNALS: - void buttonsChanged( bool ); + void decorationChanged( Decoration ); + void textAlignmentChanged( Qt::Alignment ); void trackingChanged( bool ); void wrappingChanged( bool ); @@ -66,9 +89,6 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput void decimalsChanged( int ); void textChanged(); - protected: - virtual QString textFromValue( qreal ) const; - private: void timerEvent( QTimerEvent* ) override; diff --git a/src/controls/QskSpinBoxSkinlet.cpp b/src/controls/QskSpinBoxSkinlet.cpp index 0414b0e1..be8bb182 100644 --- a/src/controls/QskSpinBoxSkinlet.cpp +++ b/src/controls/QskSpinBoxSkinlet.cpp @@ -5,8 +5,9 @@ #include "QskSpinBoxSkinlet.h" #include "QskSpinBox.h" +#include "QskFunctions.h" -#include +#include QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* ) { @@ -14,61 +15,6 @@ QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* ) UpIndicator, DownIndicator, Text } ); } -QSizeF QskSpinBoxSkinlet::sizeHint( const QskSkinnable* skinnable, - Qt::SizeHint which, const QSizeF& size ) const -{ - if ( which != Qt::PreferredSize ) - return QSizeF(); - - using Q = QskSpinBox; - - const auto spinbox = static_cast< const QskSpinBox* >( skinnable ); - - const auto layout = spinbox->alignmentHint( Q::Panel ); - const auto spacing = spinbox->spacingHint( Q::Panel ); - - const auto strutInc = spinbox->strutSizeHint( Q::UpPanel ); - const auto strutDec = spinbox->strutSizeHint( Q::DownPanel ); - const auto strutTxt = spinbox->strutSizeHint( Q::TextPanel ); - - if ( layout == Qt::AlignTop || layout == Qt::AlignBottom || layout == Qt::AlignVCenter ) - { - const auto w = qMax( strutDec.width(), qMax( strutTxt.width(), strutInc.width() ) ); - const auto h = strutDec.height() + strutTxt.height() + strutInc.height(); - - return QSizeF( w, h + 2.0 * spacing ); - } - - if ( layout == Qt::AlignLeft || layout == Qt::AlignRight || layout == Qt::AlignHCenter ) - { - const auto w = strutDec.width() + strutTxt.width() + strutInc.width(); - const auto h = qMax( strutDec.height(), qMax( strutTxt.height(), strutInc.height() ) ); - - return QSizeF( w + 2.0 * spacing, h ); - } - - if ( layout == ( Qt::AlignLeft | Qt::AlignVCenter ) || - layout == ( Qt::AlignRight | Qt::AlignVCenter ) ) - { - const auto w = strutTxt.width() + qMax( strutInc.width(), strutDec.width() ); - const auto h = - qMax( 2.0 * qMax( strutInc.height(), strutDec.height() ), strutTxt.height() ); - - return QSizeF( w + spacing, h + spacing ); - } - - if ( layout == ( Qt::AlignTop | Qt::AlignHCenter ) || - layout == ( Qt::AlignBottom | Qt::AlignHCenter ) ) - { - const auto w = qMax( strutTxt.width(), strutInc.width() + strutDec.width() ); - const auto h = strutTxt.height() + qMax( strutInc.height(), strutDec.height() ); - - return QSizeF( w + spacing, h + spacing ); - } - - return Inherited::sizeHint( skinnable, which, size ); -} - QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { @@ -83,117 +29,11 @@ QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable, if ( subControl == Q::Text ) return skinnable->subControlContentsRect( contentsRect, Q::TextPanel ); - const auto* const spinbox = static_cast< const QskSpinBox* >( skinnable ); - - const auto layout = spinbox->alignmentHint( Q::Panel ); - const auto spacing = spinbox->spacingHint( Q::Panel ); - - enum - { - Dec = 0, - Txt = 1, - Inc = 2, - Count - }; - - std::array< QRectF, Count > rects = { - QRectF{ QPointF(), spinbox->strutSizeHint( Q::DownPanel ) }, - QRectF{ QPointF(), spinbox->strutSizeHint( Q::TextPanel ) }, - QRectF{ QPointF(), spinbox->strutSizeHint( Q::UpPanel ) }, - }; - - const auto center = contentsRect.center(); - - if ( layout == Qt::AlignLeft ) - { - rects[ Txt ].moveTopLeft( { 0.0, center.y() - rects[ Txt ].height() * 0.5 } ); - rects[ Dec ].moveTopLeft( - { rects[ Txt ].right() + spacing, center.y() - rects[ Dec ].height() * 0.5 } ); - rects[ Inc ].moveTopLeft( - { rects[ Dec ].right() + spacing, center.y() - rects[ Inc ].height() * 0.5 } ); - } - else if ( layout == Qt::AlignRight ) - { - rects[ Dec ].moveTopLeft( { 0.0, center.y() - rects[ Dec ].height() * 0.5 } ); - rects[ Inc ].moveTopLeft( - { rects[ Dec ].right() + spacing, center.y() - rects[ Inc ].height() * 0.5 } ); - rects[ Txt ].moveTopLeft( - { rects[ Inc ].right() + spacing, center.y() - rects[ Txt ].height() * 0.5 } ); - } - else if ( layout == Qt::AlignTop ) - { - rects[ Txt ].moveTopLeft( { center.x() - rects[ Txt ].width() * 0.5, 0.0 } ); - rects[ Inc ].moveTopLeft( - { center.x() - rects[ Inc ].width() * 0.5, rects[ Txt ].bottom() + spacing } ); - rects[ Dec ].moveTopLeft( - { center.x() - rects[ Dec ].width() * 0.5, rects[ Inc ].bottom() + spacing } ); - } - else if ( layout == Qt::AlignBottom ) - { - rects[ Inc ].moveTopLeft( { center.x() - rects[ Inc ].width() * 0.5, 0.0 } ); - rects[ Dec ].moveTopLeft( - { center.x() - rects[ Dec ].width() * 0.5, rects[ Inc ].bottom() + spacing } ); - rects[ Txt ].moveTopLeft( - { center.x() - rects[ Txt ].width() * 0.5, rects[ Dec ].bottom() + spacing } ); - } - else if ( layout == Qt::AlignHCenter ) - { - rects[ Dec ].moveTopLeft( { 0.0, center.y() - rects[ Dec ].height() * 0.5 } ); - rects[ Txt ].moveTopLeft( - { rects[ Dec ].right() + spacing, center.y() - rects[ Txt ].height() * 0.5 } ); - rects[ Inc ].moveTopLeft( - { rects[ Txt ].right() + spacing, center.y() - rects[ Inc ].height() * 0.5 } ); - } - else if ( layout == Qt::AlignVCenter ) - { - rects[ Inc ].moveTopLeft( { center.x() - rects[ Inc ].width() * 0.5, 0.0 } ); - rects[ Txt ].moveTopLeft( - { center.x() - rects[ Txt ].width() * 0.5, rects[ Inc ].bottom() + spacing } ); - rects[ Dec ].moveTopLeft( - { center.x() - rects[ Dec ].width() * 0.5, rects[ Txt ].bottom() + spacing } ); - } - else if ( layout == ( Qt::AlignLeft | Qt::AlignVCenter ) ) - { - rects[ Txt ].moveTopLeft( { 0.0, center.y() - rects[ Txt ].height() * 0.5 } ); - rects[ Inc ].moveTopLeft( { rects[ Txt ].right() + spacing, - center.y() - spacing * 0.5 - rects[ Inc ].height() } ); - rects[ Dec ].moveTopLeft( { rects[ Txt ].right() + spacing, center.y() + spacing * 0.5 } ); - } - else if ( layout == ( Qt::AlignRight | Qt::AlignVCenter ) ) - { - const auto dx = qMax( rects[ Inc ].width(), rects[ Dec ].width() ); - rects[ Inc ].moveTopLeft( - { dx - rects[ Inc ].width(), center.y() - spacing * 0.5 - rects[ Inc ].height() } ); - rects[ Dec ].moveTopLeft( { dx - rects[ Dec ].width(), center.y() + spacing * 0.5 } ); - rects[ Txt ].moveTopLeft( { dx + spacing, center.y() - rects[ Txt ].height() * 0.5 } ); - } - else if ( layout == ( Qt::AlignTop | Qt::AlignHCenter ) ) - { - rects[ Txt ].moveTopLeft( { center.x() - rects[ Txt ].width() * 0.5, 0.0 } ); - rects[ Dec ].moveTopLeft( - { rects[ Txt ].center().x() - spacing * 0.5 - rects[ Dec ].width(), - rects[ Txt ].bottom() + spacing } ); - rects[ Inc ].moveTopLeft( - { rects[ Txt ].center().x() + spacing * 0.5, rects[ Txt ].bottom() + spacing } ); - } - else if ( layout == ( Qt::AlignBottom | Qt::AlignHCenter ) ) - { - rects[ Txt ].moveTopLeft( - { center.x() - rects[ Txt ].width() * 0.5, center.y() - rects[ Txt ].height() * 0.5 } ); - rects[ Dec ].moveTopLeft( { center.x() - spacing * 0.5 - rects[ Dec ].width(), - rects[ Txt ].top() - spacing - rects[ Dec ].height() } ); - rects[ Inc ].moveTopLeft( - { center.x() + spacing * 0.5, rects[ Txt ].top() - spacing - rects[ Inc ].height() } ); - } - - if ( subControl == Q::DownPanel ) - return rects[ Dec ]; + if ( subControl == Q::DownPanel || subControl == Q::UpPanel ) + return buttonRect( skinnable, contentsRect, subControl ); if ( subControl == Q::TextPanel ) - return rects[ Txt ]; - - if ( subControl == Q::UpPanel ) - return rects[ Inc ]; + return textPanelRect( skinnable, contentsRect ); return Inherited::subControlRect( skinnable, contentsRect, subControl ); } @@ -228,10 +68,165 @@ QSGNode* QskSpinBoxSkinlet::updateSubNode( case Text: { - const auto* const spinbox = static_cast< const QskSpinBox* >( skinnable ); - return updateTextNode( skinnable, node, spinbox->text(), Q::Text ); + auto spinBox = static_cast< const QskSpinBox* >( skinnable ); + + const auto rect = subControlRect( spinBox, spinBox->contentsRect(), Q::Text ); + + return updateTextNode( spinBox, node, rect, + spinBox->textAlignment(), spinBox->text(), Q::Text ); } } return Inherited::updateSubNode( skinnable, nodeRole, node ); } + +QRectF QskSpinBoxSkinlet::textPanelRect( + const QskSkinnable* skinnable, const QRectF& rect ) const +{ + using Q = QskSpinBox; + + auto spinBox = static_cast< const QskSpinBox* >( skinnable ); + + const auto decoration = spinBox->decoration(); + if ( decoration == Q::NoDecoration ) + return rect; + + auto r = rect; + + const auto spacing = spinBox->spacingHint( Q::Panel ); + + if ( decoration == Q::UpDownControl ) + { + const auto w = subControlRect( skinnable, rect, Q::UpPanel ).width(); + if ( w > 0.0 ) + r.setRight( r.right() - spacing - w ); + } + else + { + const auto w1 = subControlRect( skinnable, rect, Q::DownPanel ).width(); + if ( w1 > 0.0 ) + r.setLeft( r.left() + w1 + spacing ); + + const auto w2 = subControlRect( skinnable, rect, Q::UpPanel ).width(); + if ( w2 > 0.0 ) + r.setRight( r.right() - w2 - spacing ); + } + + return r; +} + +QRectF QskSpinBoxSkinlet::buttonRect( const QskSkinnable* skinnable, + const QRectF& rect, QskAspect::Subcontrol subControl ) const +{ + using Q = QskSpinBox; + + const auto spinBox = static_cast< const QskSpinBox* >( skinnable ); + + if ( const auto decoration = spinBox->decoration() ) + { + qreal x, y, w, h; + + if ( decoration == QskSpinBox::UpDownControl ) + { + const auto hint1 = spinBox->strutSizeHint( Q::UpPanel ); + const auto hint2 = spinBox->strutSizeHint( Q::DownPanel ); + + w = std::max( hint1.width(), hint2.width() ); + if ( w <= 0 ) + w = rect.height(); + + h = 0.5 * rect.height(); + + x = rect.right() - w; + y = ( subControl == Q::UpPanel ) ? rect.top() : rect.bottom() - h; + } + else + { + 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; + + x = ( subControl == Q::UpPanel ) ? rect.right() - w : rect.left(); + y = 0.5 * ( rect.height() - h ); + } + + return QRectF( x, y, w, h ); + } + + return QRectF(); +} + +QSizeF QskSpinBoxSkinlet::sizeHint( const QskSkinnable* skinnable, + Qt::SizeHint which, const QSizeF& ) const +{ + if ( which != Qt::PreferredSize ) + return QSizeF(); + + using Q = QskSpinBox; + + const auto spinBox = static_cast< const QskSpinBox* >( skinnable ); + + QSizeF hint; + + { + const QFontMetricsF fm( spinBox->effectiveFont( Q::Text ) ); + + // 18: QAbstractSpinBox does this + const auto w1 = qskHorizontalAdvance( fm, + spinBox->textFromValue( spinBox->minimum() ).left( 18 ) ); + + const auto w2 = qskHorizontalAdvance( fm, + spinBox->textFromValue( spinBox->maximum() ).left( 18 ) ); + + hint.setWidth( std::max( w1, w2 ) ); + hint.setHeight( fm.height() ); + + hint = hint.grownBy( spinBox->paddingHint( Q::TextPanel ) ); + hint = hint.expandedTo( spinBox->strutSizeHint( Q::TextPanel ) ); + } + + if ( const auto decoration = spinBox->decoration() ) + { + const auto spacing = spinBox->spacingHint( Q::Panel ); + const auto hintUp = spinBox->strutSizeHint( Q::UpPanel ); + const auto hintDown = spinBox->strutSizeHint( Q::DownPanel ); + + if ( decoration == QskSpinBox::UpDownControl ) + { + qreal w = std::max( hintDown.width(), hintUp.width() ); + + qreal h = 0.0; + if ( hintDown.height() >= 0.0 ) + h += hintDown.height(); + + if ( hintUp.height() >= 0.0 ) + h += hintUp.height(); + + hint.rwidth() += ( w >= 0.0 ) ? w : hint.height(); + hint.rwidth() += spacing; + + hint.rheight() = std::max( h, hint.height() ); + } + else + { + if ( hintDown.width() > 0.0 ) + hint.rwidth() += hintDown.width() + spacing; + + if ( hintUp.width() > 0.0 ) + hint.rwidth() += hintUp.width() + spacing; + + const auto h = std::max( hintUp.height(), hintDown.height() ); + hint.rheight() = qMax( h, hint.height() ); + } + } + + hint = hint.expandedTo( spinBox->strutSizeHint( Q::Panel ) ); + return hint; +} + diff --git a/src/controls/QskSpinBoxSkinlet.h b/src/controls/QskSpinBoxSkinlet.h index 83e624e2..2c26bda4 100644 --- a/src/controls/QskSpinBoxSkinlet.h +++ b/src/controls/QskSpinBoxSkinlet.h @@ -39,6 +39,12 @@ class QSK_EXPORT QskSpinBoxSkinlet : public QskSkinlet protected: QSGNode* updateSubNode( const QskSkinnable* skinnable, quint8 role, QSGNode* node ) const override; + + private: + QRectF textPanelRect( const QskSkinnable*, const QRectF& ) const; + + QRectF buttonRect( const QskSkinnable*, + const QRectF&, QskAspect::Subcontrol ) const; }; #endif