spin box improvements

This commit is contained in:
Uwe Rathmann 2023-02-27 09:56:41 +01:00
parent deb921d579
commit 0b4de9afe7
13 changed files with 346 additions and 447 deletions

View File

@ -7,10 +7,10 @@ SOURCES += \
label/LabelPage.cpp \ label/LabelPage.cpp \
HEADERS += \ HEADERS += \
slider/SliderPage.h inputs/InputPage.h
SOURCES += \ SOURCES += \
slider/SliderPage.cpp inputs/InputPage.cpp
HEADERS += \ HEADERS += \
progressbar/ProgressBarPage.h progressbar/ProgressBarPage.h
@ -24,12 +24,6 @@ HEADERS += \
SOURCES += \ SOURCES += \
button/ButtonPage.cpp \ button/ButtonPage.cpp \
HEADERS += \
textinput/TextInputPage.h
SOURCES += \
textinput/TextInputPage.cpp \
HEADERS += \ HEADERS += \
selector/SelectorPage.h selector/SelectorPage.h
@ -42,12 +36,6 @@ HEADERS += \
SOURCES += \ SOURCES += \
dialog/DialogPage.cpp \ dialog/DialogPage.cpp \
HEADERS += \
spinbox/SpinBoxPage.h
SOURCES += \
spinbox/SpinBoxPage.cpp
HEADERS += \ HEADERS += \
Page.h Page.h

View File

@ -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 <QskGridBox.h>
#include <QskSlider.h>
#include <QskTextInput.h>
#include <QskSpinBox.h>
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 );
}

View File

@ -7,10 +7,10 @@
#include "Page.h" #include "Page.h"
class SliderPage : public Page class InputPage : public Page
{ {
public: public:
SliderPage( QQuickItem* = nullptr ); InputPage( QQuickItem* = nullptr );
private: private:
void populate(); void populate();

View File

@ -5,12 +5,10 @@
#include "label/LabelPage.h" #include "label/LabelPage.h"
#include "progressbar/ProgressBarPage.h" #include "progressbar/ProgressBarPage.h"
#include "slider/SliderPage.h" #include "inputs/InputPage.h"
#include "button/ButtonPage.h" #include "button/ButtonPage.h"
#include "textinput/TextInputPage.h"
#include "selector/SelectorPage.h" #include "selector/SelectorPage.h"
#include "dialog/DialogPage.h" #include "dialog/DialogPage.h"
#include "spinbox/SpinBoxPage.h"
#include <SkinnyShortcut.h> #include <SkinnyShortcut.h>
#include <SkinnyShapeProvider.h> #include <SkinnyShapeProvider.h>
@ -195,14 +193,10 @@ namespace
auto tabView = new TabView( this ); auto tabView = new TabView( this );
tabView->addTab( "Buttons", new ButtonPage() ); tabView->addTab( "Buttons", new ButtonPage() );
tabView->addTab( "Labels", new LabelPage() ); tabView->addTab( "Labels", new LabelPage() );
tabView->addTab( "Sliders", new SliderPage() ); tabView->addTab( "Inputs", new InputPage() );
tabView->addTab( "Progress\nBars", new ProgressBarPage() ); tabView->addTab( "Progress\nBars", new ProgressBarPage() );
tabView->addTab( "Text\nInputs", new TextInputPage() );
tabView->addTab( "Selectors", new SelectorPage() ); tabView->addTab( "Selectors", new SelectorPage() );
tabView->addTab( "Dialogs", new DialogPage() ); tabView->addTab( "Dialogs", new DialogPage() );
tabView->addTab( "SpinBoxes", new SpinBoxPage() );
tabView->setCurrentIndex(tabView->count() - 1);
connect( header, &Header::enabledToggled, connect( header, &Header::enabledToggled,
tabView, &TabView::setTabsEnabled ); tabView, &TabView::setTabsEnabled );

View File

@ -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 <QskSlider.h>
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 );
}

View File

@ -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 <QskGridBox.h>
#include <QskLinearBox.h>
#include <QskSlider.h>
#include <QskSpinBox.h>
#include <QskTextLabel.h>
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 );
}

View File

@ -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();
};

View File

@ -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 <QskLinearBox.h>
#include <QskTextInput.h>
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.
}
}

View File

@ -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();
};

View File

@ -37,14 +37,23 @@ namespace
return QskAspect::NoSubcontrol; 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 class QskSpinBox::PrivateData
{ {
public: public:
PrivateData() PrivateData()
: buttons( true ) : tracking( true )
, tracking( true )
, wrapping( false ) , wrapping( false )
, accelerating( false ) , accelerating( false )
{ {
@ -100,19 +109,19 @@ class QskSpinBox::PrivateData
int key = Qt::Key_unknown; int key = Qt::Key_unknown;
bool buttons : 1; bool tracking : 1;
bool tracking : 1; bool wrapping : 1;
bool wrapping : 1;
bool accelerating : 1; // not yet implemented: TODO ... bool accelerating : 1; // not yet implemented: TODO ...
}; };
QskSpinBox::QskSpinBox( QQuickItem* parent ) QskSpinBox::QskSpinBox( qreal min, qreal max, qreal stepSize, QQuickItem* parent )
: Inherited( parent ) : Inherited( parent )
, m_data( new PrivateData ) , m_data( new PrivateData )
{ {
initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed ); initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed );
setBoundaries( 0.0, 99.99 ); // this is what QDoubleSpinBox does setBoundaries( min, max );
setStepSize( stepSize );
setAcceptedMouseButtons( Qt::LeftButton ); setAcceptedMouseButtons( Qt::LeftButton );
setFocusPolicy( Qt::StrongFocus ); setFocusPolicy( Qt::StrongFocus );
@ -120,22 +129,50 @@ QskSpinBox::QskSpinBox( QQuickItem* parent )
connect( this, &QskSpinBox::valueChanged, this, &QskSpinBox::textChanged ); connect( this, &QskSpinBox::valueChanged, this, &QskSpinBox::textChanged );
} }
QskSpinBox::QskSpinBox( QQuickItem* parent )
: QskSpinBox( 0.0, 99.99, 0.1, parent )
{
}
QskSpinBox::~QskSpinBox() QskSpinBox::~QskSpinBox()
{ {
} }
void QskSpinBox::setButtons( bool on ) void QskSpinBox::setDecoration( Decoration decoration )
{ {
if ( on != m_data->buttons ) if ( setFlagHint( aspectDecoration(), decoration ) )
{ Q_EMIT decorationChanged( decoration );
m_data->buttons = on;
Q_EMIT buttonsChanged( on );
}
} }
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 ) void QskSpinBox::setTracking( bool on )

View File

@ -22,12 +22,15 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput
Q_PROPERTY( bool accelerating READ isAccelerating Q_PROPERTY( bool accelerating READ isAccelerating
WRITE setAccelerating NOTIFY acceleratingChanged ) WRITE setAccelerating NOTIFY acceleratingChanged )
Q_PROPERTY( bool buttons READ hasButtons Q_PROPERTY( Decoration decoration READ decoration
WRITE setButtons NOTIFY buttonsChanged ) WRITE setDecoration RESET resetDecoration NOTIFY decorationChanged )
Q_PROPERTY( int decimals READ decimals Q_PROPERTY( int decimals READ decimals
WRITE setDecimals NOTIFY decimalsChanged ) 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 ) Q_PROPERTY( QString text READ text NOTIFY textChanged )
public: public:
@ -36,11 +39,29 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput
QSK_STATES( Decreasing, Increasing ) QSK_STATES( Decreasing, Increasing )
enum Decoration
{
NoDecoration,
Buttons,
UpDownControl
};
Q_ENUM( Decoration )
QskSpinBox( QQuickItem* parent = nullptr ); QskSpinBox( QQuickItem* parent = nullptr );
QskSpinBox( qreal min, qreal max, qreal stepSize,
QQuickItem* parent = nullptr );
~QskSpinBox() override; ~QskSpinBox() override;
void setButtons( bool ); void setDecoration( Decoration );
bool hasButtons() const; 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 ); void setWrapping( bool );
bool isWrapping() const; bool isWrapping() const;
@ -55,9 +76,11 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput
int decimals() const; int decimals() const;
QString text() const; QString text() const;
virtual QString textFromValue( qreal ) const;
Q_SIGNALS: Q_SIGNALS:
void buttonsChanged( bool ); void decorationChanged( Decoration );
void textAlignmentChanged( Qt::Alignment );
void trackingChanged( bool ); void trackingChanged( bool );
void wrappingChanged( bool ); void wrappingChanged( bool );
@ -66,9 +89,6 @@ class QSK_EXPORT QskSpinBox : public QskBoundedValueInput
void decimalsChanged( int ); void decimalsChanged( int );
void textChanged(); void textChanged();
protected:
virtual QString textFromValue( qreal ) const;
private: private:
void timerEvent( QTimerEvent* ) override; void timerEvent( QTimerEvent* ) override;

View File

@ -5,8 +5,9 @@
#include "QskSpinBoxSkinlet.h" #include "QskSpinBoxSkinlet.h"
#include "QskSpinBox.h" #include "QskSpinBox.h"
#include "QskFunctions.h"
#include <array> #include <qfontmetrics.h>
QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* ) QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* )
{ {
@ -14,61 +15,6 @@ QskSpinBoxSkinlet::QskSpinBoxSkinlet( QskSkin* )
UpIndicator, DownIndicator, Text } ); 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, QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
{ {
@ -83,117 +29,11 @@ QRectF QskSpinBoxSkinlet::subControlRect( const QskSkinnable* skinnable,
if ( subControl == Q::Text ) if ( subControl == Q::Text )
return skinnable->subControlContentsRect( contentsRect, Q::TextPanel ); return skinnable->subControlContentsRect( contentsRect, Q::TextPanel );
const auto* const spinbox = static_cast< const QskSpinBox* >( skinnable ); if ( subControl == Q::DownPanel || subControl == Q::UpPanel )
return buttonRect( skinnable, contentsRect, subControl );
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::TextPanel ) if ( subControl == Q::TextPanel )
return rects[ Txt ]; return textPanelRect( skinnable, contentsRect );
if ( subControl == Q::UpPanel )
return rects[ Inc ];
return Inherited::subControlRect( skinnable, contentsRect, subControl ); return Inherited::subControlRect( skinnable, contentsRect, subControl );
} }
@ -228,10 +68,165 @@ QSGNode* QskSpinBoxSkinlet::updateSubNode(
case Text: case Text:
{ {
const auto* const spinbox = static_cast< const QskSpinBox* >( skinnable ); auto spinBox = static_cast< const QskSpinBox* >( skinnable );
return updateTextNode( skinnable, node, spinbox->text(), Q::Text );
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 ); 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;
}

View File

@ -39,6 +39,12 @@ class QSK_EXPORT QskSpinBoxSkinlet : public QskSkinlet
protected: protected:
QSGNode* updateSubNode( QSGNode* updateSubNode(
const QskSkinnable* skinnable, quint8 role, QSGNode* node ) const override; 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 #endif