From 8c0a54e54a6123d623f2530f28163e0da76e0674 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Wed, 8 Feb 2023 21:49:04 +0100 Subject: [PATCH 01/25] Add QskRadioBox --- examples/gallery/button/ButtonPage.cpp | 4 + skins/material3/QskMaterial3Skin.cpp | 37 ++++ src/controls/QskRadioBox.cpp | 201 ++++++++++++++++++++++ src/controls/QskRadioBox.h | 61 +++++++ src/controls/QskRadioBoxSkinlet.cpp | 227 +++++++++++++++++++++++++ src/controls/QskRadioBoxSkinlet.h | 57 +++++++ src/controls/QskSkin.cpp | 4 + src/graphic/QskStandardSymbol.cpp | 11 ++ src/graphic/QskStandardSymbol.h | 2 + src/src.pro | 4 + 10 files changed, 608 insertions(+) create mode 100644 src/controls/QskRadioBox.cpp create mode 100644 src/controls/QskRadioBox.h create mode 100644 src/controls/QskRadioBoxSkinlet.cpp create mode 100644 src/controls/QskRadioBoxSkinlet.h diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp index 540d4f8d..0f47ef0e 100644 --- a/examples/gallery/button/ButtonPage.cpp +++ b/examples/gallery/button/ButtonPage.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,9 @@ namespace auto button3 = new QskCheckBox( "Error", this ); button3->setSkinStateFlag( QskCheckBox::Error ); + new QskRadioBox( { "One", "Two", "Three" }, this ); + auto radios = new QskRadioBox( { "One", "Two", "Three" }, this ); + radios->setLayoutMirroring(true); } }; } diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 6265185f..816b8a39 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -139,6 +140,7 @@ namespace void setupPageIndicator(); void setupPopup(); void setupProgressBar(); + void setupRadioBox(); void setupPushButton(); void setupScrollView(); void setupSegmentedBar(); @@ -199,6 +201,7 @@ void Editor::setup() setupPopup(); setupProgressBar(); setupPushButton(); + setupRadioBox(); setupScrollView(); setupSegmentedBar(); setupSeparator(); @@ -463,6 +466,40 @@ void Editor::setupProgressBar() setGradient( Q::Bar | Q::Disabled, m_pal.onSurface38 ); } +void Editor::setupRadioBox() +{ + using Q = QskRadioBox; + using A = QskAspect; + + setStrutSize( Q::Text, {100, 20 }); + setStrutSize( Q::Radio, {20, 20 }); + setStrutSize( Q::Symbol, {10, 10 }); + setStrutSize( Q::Ripple | Q::Focused, { 40, 40 }); + + setSpacing(Q::Panel, 10); + + setColor( Q::Text, m_pal.onBackground ); + + setBoxShape(Q::Radio, 20); + setBoxBorderMetrics( Q::Radio, 2_dp ); + setBoxBorderColors( Q::Radio, m_pal.onBackground ); + setBoxBorderColors( Q::Radio | Q::Selected, m_pal.primary ); + + setBoxShape(Q::Ripple, 40); + + setColor( Q::Symbol, m_pal.primary ); + setColor( Q::Ripple | Q::Focused, + stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); + setColor( Q::Ripple | Q::Selected | Q::Focused, + // stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); + Qt::red); + + setMargin( Q::Text, QskMargins(10, 0,0,0)); + + setAlignment( Q::Text, Qt::AlignBottom ); + setAnimation(Q::Ripple | A::Metric, 1000); +} + void Editor::setupFocusIndicator() { using Q = QskFocusIndicator; diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp new file mode 100644 index 00000000..b99541af --- /dev/null +++ b/src/controls/QskRadioBox.cpp @@ -0,0 +1,201 @@ +#include "QskRadioBox.h" +#include "QskEvent.h" +#include + +QSK_SUBCONTROL( QskRadioBox, Panel ) +QSK_SUBCONTROL( QskRadioBox, Radio ) +QSK_SUBCONTROL( QskRadioBox, Symbol ) +QSK_SUBCONTROL( QskRadioBox, Text ) +QSK_SUBCONTROL( QskRadioBox, Ripple ) + +QSK_STATE( QskRadioBox, Selected, QskAspect::FirstUserState ) +QSK_STATE( QskRadioBox, Pressed, QskAspect::FirstUserState << 1) +QSK_STATE( QskRadioBox, Focused, QskAspect::FirstUserState << 2) + +class QskRadioBox::PrivateData { +public: + QStringList items; + int selectedIndex = -1; + int pressedIndex = -1; + int focusedIndex = -1; +}; + +QskRadioBox::QskRadioBox( QQuickItem* parent ) : + Inherited( parent ), + m_data( new PrivateData{} ) +{ + setFocusPolicy( Qt::NoFocus ); + setAcceptedMouseButtons( Qt::LeftButton ); + + connect(this, &QskRadioBox::itemsChanged, this, + [this]( const QStringList& items ) { + if( items.count() > 0 ) { + setFocusPolicy( Qt::StrongFocus ); + } else { + setFocusPolicy( Qt::NoFocus ); + } + }); +} + +QskRadioBox::QskRadioBox( const QStringList& list, QQuickItem* parent ) : + QskRadioBox( parent ) +{ + setItems( list ); +} + +QskRadioBox::QskRadioBox( const QStringList& items, + int selectedIndex, + QQuickItem* parent ) : + QskRadioBox( items, parent ) +{ + if( selectedIndex >= 0 && selectedIndex < items.count() ) + { + m_data->selectedIndex = selectedIndex; + } +} + +int QskRadioBox::selectedIndex() const { + return m_data->selectedIndex; +} + +const QStringList& QskRadioBox::items() const { + return m_data->items; +} + +int QskRadioBox::focusedIndex() const { + return m_data->focusedIndex; +} + +void QskRadioBox::setSelectedIndex( int index ) { + if( index == m_data->selectedIndex + || index >= m_data->items.count() ) { + return; + } + + if( index < 0 ) { + m_data->selectedIndex = -1; + } else { + m_data->selectedIndex = index; + } + + selectedIndexChanged( m_data->selectedIndex ); +} + +void QskRadioBox::setItems( const QStringList& items ){ + if( m_data->items == items ) { + return; + } + + m_data->items = items; + itemsChanged( items ); + setSelectedIndex( m_data->selectedIndex ); +} + +void QskRadioBox::keyPressEvent( QKeyEvent* event ) +{ + switch ( event->key() ) + { + case Qt::Key_Up: + case Qt::Key_Left: + m_data->selectedIndex = qMax(m_data->selectedIndex - 1, 0); + m_data->focusedIndex = m_data->selectedIndex; + setSkinStateFlag( QskRadioBox::Selected ); + event->setAccepted( true ); + update(); + return; + case Qt::Key_Down: + case Qt::Key_Right: + m_data->selectedIndex = qMin(m_data->selectedIndex + 1, items().size() - 1); + m_data->focusedIndex = m_data->selectedIndex; + setSkinStateFlag( QskRadioBox::Selected ); + event->setAccepted( true ); + update(); + return; + case Qt::Key_Select: + case Qt::Key_Return: + case Qt::Key_Space: + m_data->selectedIndex = m_data->focusedIndex; + setSkinStateFlag( QskRadioBox::Selected ); + setSkinStateFlag( QskRadioBox::Pressed ); + event->setAccepted( true ); + update(); + return; + } + + auto nextTabIndex = m_data->focusedIndex; + nextTabIndex += qskFocusChainIncrement( event ); + if( nextTabIndex >= items().size() + || nextTabIndex < 0 ) { + Inherited::keyPressEvent( event ); + } else { + m_data->focusedIndex = nextTabIndex; + setSkinStateFlag( QskRadioBox::Focused ); + event->setAccepted( true ); + update(); + } +} + +void QskRadioBox::keyReleaseEvent( QKeyEvent* e ) +{ + setSkinStateFlag( QskRadioBox::Pressed, false ); + e->setAccepted( true ); + update(); +} + +void QskRadioBox::mousePressEvent( QMouseEvent* e ) +{ + auto indexAtPosition = indexAt(e->localPos()); + + m_data->pressedIndex = indexAtPosition; + m_data->selectedIndex = -1; + + m_data->focusedIndex = indexAtPosition; + + setSkinStateFlag( QskRadioBox::Pressed ); + + e->setAccepted( true ); + update(); +} + +void QskRadioBox::mouseReleaseEvent( QMouseEvent* e ) +{ + setSkinStateFlag( QskRadioBox::Pressed, false ); + + auto index = indexAt( e->localPos() ); + if( index == m_data->pressedIndex ) { + setSelectedIndex( index ); + } + + e->setAccepted( true ); + update(); +} + +void QskRadioBox::focusInEvent( QFocusEvent* e ) { + if( e->reason() == Qt::TabFocusReason ) { + m_data->focusedIndex = 0; + } else if( e->reason() == Qt::BacktabFocusReason ) { + m_data->focusedIndex = items().size() - 1; + } + + setSkinStateFlag( Focused ); + Inherited::focusInEvent( e ); +} + +void QskRadioBox::focusOutEvent( QFocusEvent* e ) { + m_data->focusedIndex = -1; + setSkinStateFlag( Focused, false ); + update(); + Inherited::focusOutEvent( e ); +} + +int QskRadioBox::indexAt( const QPointF& target ) const { + auto itemHeight = contentsRect().height() / items().size(); + auto index = target.y() / itemHeight; + + if( index < 0 || index >= items().size() ) + return -1; + + return index; +} + +#include "moc_QskRadioBox.cpp" diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h new file mode 100644 index 00000000..4e5ef368 --- /dev/null +++ b/src/controls/QskRadioBox.h @@ -0,0 +1,61 @@ +#ifndef QSK_RADIO_BOX_H +#define QSK_RADIO_BOX_H + +#include "QskControl.h" + +#include + +class QSK_EXPORT QskRadioBox : public QskControl +{ + Q_OBJECT + + Q_PROPERTY( int selectedIndex + READ selectedIndex + WRITE setSelectedIndex + NOTIFY selectedIndexChanged FINAL ) + + Q_PROPERTY( QStringList items + READ items + WRITE setItems + NOTIFY itemsChanged FINAL ) + + using Inherited = QskControl; + + public: + QSK_SUBCONTROLS( Panel, Radio, Symbol, Text, Ripple ) + QSK_STATES( Selected, Pressed, Focused ) + + QskRadioBox( QQuickItem* parent = nullptr ); + QskRadioBox( const QStringList&, QQuickItem* parent = nullptr ); + QskRadioBox( const QStringList&, int, QQuickItem* parent = nullptr ); + + int selectedIndex() const; + const QStringList& items() const; + int focusedIndex() const; + + public Q_SLOTS: + void setSelectedIndex( int ); + void setItems( const QStringList& ); + + Q_SIGNALS: + void selectedIndexChanged( int ); + void itemsChanged( const QStringList& ); + + protected: + void keyPressEvent( QKeyEvent* ) override; + void keyReleaseEvent( QKeyEvent* ) override; + + void mousePressEvent( QMouseEvent* ) override; + void mouseReleaseEvent( QMouseEvent* ) override; + + void focusInEvent( QFocusEvent* ) override; + void focusOutEvent( QFocusEvent* ) override; + + int indexAt( const QPointF& ) const; + + private: + class PrivateData; + std::unique_ptr< PrivateData > m_data; +}; + +#endif diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp new file mode 100644 index 00000000..d0bff61b --- /dev/null +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -0,0 +1,227 @@ +#include "QskRadioBoxSkinlet.h" + +#include "QskAspect.h" +#include "QskRadioBox.h" + +#include "QskStandardSymbol.h" +#include "QskColorFilter.h" +#include "QskGraphic.h" +#include "QskFunctions.h" +#include "QskSkin.h" +#include + +namespace { + using Q = QskRadioBox; +}; + +QskRadioBoxSkinlet::QskRadioBoxSkinlet( QskSkin* ) +{ + setNodeRoles( { PanelRole, RadioRole, SymbolRole, TextRole, RippleRole } ); +} + +QskRadioBoxSkinlet::~QskRadioBoxSkinlet() +{ +} + +QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subcontrol) const +{ + auto radio = static_cast( skinnable ); + + if( subcontrol == Q::Ripple ) { + auto result = contentsRect; + auto lh = lineHeight( radio ); + auto spacing = radio->spacingHint(Q::Panel); + result.setSize( radio->strutSizeHint( subcontrol ) ); + result.moveTop( (lh + spacing) * radio->focusedIndex() + - (result.size().height() - lh ) / 2); + result.moveLeft(( radio->strutSizeHint( Q::Radio ).width() + - result.width()) /2); + return result; + } + + return contentsRect; +} + +QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable, + Qt::SizeHint, const QSizeF& ) const +{ + auto radio = static_cast( skinnable ); + + const auto font = skinnable->effectiveFont( Q::Text ); + const auto textMargins = skinnable->marginHint( Q::Text ); + const auto buttonMargins = skinnable->marginHint( Q::Radio ); + const auto symbolMargins = skinnable->marginHint( Q::Symbol ); + + qreal maxTextWidth = 0; + for(auto& item : radio->items() ) { + maxTextWidth = std::max( maxTextWidth, qskHorizontalAdvance( font, item ) ); + } + + auto radioWidth = radio->strutSizeHint(Q::Radio).width(); + auto symbolWidth = radio->strutSizeHint(Q::Symbol).width(); + + maxTextWidth += textMargins.left() + textMargins.right(); + radioWidth += buttonMargins.left() + buttonMargins.right(); + symbolWidth += symbolMargins.left() + symbolMargins.right(); + + auto spacing = radio->spacingHint(Q::Panel); + return QSizeF( maxTextWidth + qMax(radioWidth, symbolWidth), + ( lineHeight( radio ) + spacing ) * radio->items().size() + - spacing ); +} + +QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, + quint8 nodeRole, QSGNode* node) const +{ + auto radioButtons = static_cast( skinnable ); + + switch( nodeRole ) + { + case PanelRole: + return updateBoxNode( skinnable, node, Q::Panel ); + + case RadioRole: + return updateSeriesNode( radioButtons, Q::Radio, node ); + + case SymbolRole: + return updateSeriesNode( radioButtons, Q::Symbol, node ); + + case TextRole: + return updateSeriesNode( radioButtons, Q::Text, node ); + + case RippleRole: + return updateBoxNode( radioButtons, node, Q::Ripple ); + }; + + return Inherited::updateSubNode( skinnable, nodeRole, node ); +} + +qreal QskRadioBoxSkinlet::lineHeight(const QskRadioBox* target) const { + auto strutHight = qMax( target->strutSizeHint( Q::Radio ).height(), + target->strutSizeHint( Q::Text ).height() ); + const auto textMargins = target->marginHint( Q::Text ); + auto fontHeight = target->effectiveFontHeight( Q::Text ); + fontHeight += textMargins.top() + textMargins.bottom(); + + return qMax( strutHight, fontHeight ); +} + + +int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, + QskAspect::Subcontrol ) const { + const auto radio = static_cast< const QskRadioBox* >( skinnable ); + return radio->items().count(); +} + +QRectF QskRadioBoxSkinlet::radioRect( const QskRadioBox* radio, + const QskAspect::Subcontrol target, + const QRectF& rect, int index ) const { + auto result = rect; + result.setSize( radio->strutSizeHint( target ) ); + + auto spacing = radio->spacingHint(Q::Panel); + result.moveTop( ( lineHeight( radio ) + spacing ) * index + + (lineHeight(radio) - result.size().height()) / 2); + + if( radio->layoutMirroring() ) { + result.moveRight( rect.width() ); + } else { + result.moveLeft((radio->strutSizeHint( Q::Radio ).width() + - result.width()) / 2); + } + + return result; +} + +QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, + const QRectF& rect, int index ) const { + QRectF result = rect; + auto spacing = radio->spacingHint(Q::Panel); + auto lh = lineHeight( radio ); + const auto textMargins = radio->marginHint( Q::Text ); + + result.setSize( { radio->strutSizeHint( Q::Text ).width(), lh } ); + + + result.moveTop( index * ( lh + spacing ) + + lh - radio->effectiveFontHeight(Q::Text) + + textMargins.top()); + + if(!radio->layoutMirroring()) { + auto symbolWidth = radioRect( radio, Q::Symbol, rect, index ).width(); + auto radioWidth = radioRect( radio, Q::Radio, rect, index ).width(); + result.moveLeft( qMax(symbolWidth, radioWidth) + textMargins.left()); + } + + return result; +} + +QRectF QskRadioBoxSkinlet::sampleRect( const QskSkinnable* skinnable, + const QRectF& rect, QskAspect::Subcontrol subcontrol, + int index ) const { + const auto radio = static_cast< const QskRadioBox* >( skinnable ); + + if( subcontrol == Q::Text ) { + return textRect( radio, rect, index ); + } + + return radioRect( radio, subcontrol, rect, index); +} + +QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnable, + QskAspect::Subcontrol subControl, int index ) const { + auto radioButtons = static_cast( skinnable ); + auto states = Inherited::sampleStates( skinnable, subControl, index ); + + if( radioButtons->selectedIndex() == index ) { + return states | Q::Selected; + } + + return states; +} + +QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, + QskAspect::Subcontrol subcontrol, int index, QSGNode* node ) const { + auto radioButtons = static_cast( skinnable ); + + auto rect = sampleRect( skinnable, radioButtons->contentsRect(), + subcontrol, index ); + + if( subcontrol == Q::Text ) { + return QskSkinlet::updateTextNode( radioButtons, + node, + rect, + Qt::AlignLeft, + radioButtons->items()[index], + subcontrol); + } else if (subcontrol == Q::Radio) { + return QskSkinlet::updateBoxNode(radioButtons, + node, + rect, + subcontrol); + } else if( subcontrol == Q::Symbol ) { + auto symbol = QskStandardSymbol::NoSymbol; + auto color = radioButtons->color( subcontrol ).rgb(); + + if( radioButtons->selectedIndex() == index ) { + symbol = QskStandardSymbol::Bullet; + color = radioButtons->color( subcontrol | Q::Selected ).rgb(); + } + + auto graphic = radioButtons->effectiveSkin()->symbol( symbol ); + + /* + Our default skins do not have the concept of colorRoles + implemented. Until then we do the recoloring manually here + */ + QskColorFilter filter; + filter.addColorSubstitution( Qt::black, color ); + + QskGraphic::fromGraphic( graphic, filter ); + + return updateGraphicNode( radioButtons, node, graphic, filter, rect ); + } + + return node; +} diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h new file mode 100644 index 00000000..08fdb8bc --- /dev/null +++ b/src/controls/QskRadioBoxSkinlet.h @@ -0,0 +1,57 @@ +#ifndef QSK_RADIO_BOX_SKINLET_H +#define QSK_RADIO_BOX_SKINLET_H + +#include "QskSkinlet.h" + +class QskRadioBox; + +class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet +{ + Q_GADGET + + using Inherited = QskSkinlet; + + public: + enum NodeRole + { + PanelRole, + RadioRole, + SymbolRole, + TextRole, + RippleRole, + + RoleCount + }; + + Q_INVOKABLE QskRadioBoxSkinlet( QskSkin* = nullptr ); + ~QskRadioBoxSkinlet() override; + + QRectF subControlRect( const QskSkinnable*, + const QRectF&, QskAspect::Subcontrol ) const override; + + QSizeF sizeHint( const QskSkinnable*, + Qt::SizeHint, const QSizeF& ) const override; + + int sampleCount( const QskSkinnable*, QskAspect::Subcontrol ) const override; + + QRectF sampleRect( const QskSkinnable*, + const QRectF&, QskAspect::Subcontrol, int index ) const override; + + QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; + QRectF radioRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, int ) const; + + QskAspect::States sampleStates( const QskSkinnable*, + QskAspect::Subcontrol, int index ) const override; + + protected: + QSGNode* updateSubNode( const QskSkinnable*, + quint8 nodeRole, QSGNode* ) const override; + + QSGNode* updateSampleNode( const QskSkinnable*, + QskAspect::Subcontrol, int index, QSGNode* ) const override; + + private: + qreal lineHeight( const QskRadioBox* target ) const; +}; + +#endif diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index 914b8c41..47eb8f0d 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -56,6 +56,9 @@ QSK_QT_PRIVATE_END #include "QskProgressBar.h" #include "QskProgressBarSkinlet.h" +#include "QskRadioBox.h" +#include "QskRadioBoxSkinlet.h" + #include "QskPushButton.h" #include "QskPushButtonSkinlet.h" @@ -178,6 +181,7 @@ QskSkin::QskSkin( QObject* parent ) declareSkinlet< QskTextLabel, QskTextLabelSkinlet >(); declareSkinlet< QskTextInput, QskTextInputSkinlet >(); declareSkinlet< QskProgressBar, QskProgressBarSkinlet >(); + declareSkinlet< QskRadioBox, QskRadioBoxSkinlet >(); const QFont font = QGuiApplication::font(); setupFonts( font.family(), font.weight(), font.italic() ); diff --git a/src/graphic/QskStandardSymbol.cpp b/src/graphic/QskStandardSymbol.cpp index 08176cfb..0299dee1 100644 --- a/src/graphic/QskStandardSymbol.cpp +++ b/src/graphic/QskStandardSymbol.cpp @@ -206,6 +206,12 @@ static void qskCrossMarkGraphic( QPainter* painter ) painter->drawLine( 0.0, 1.0, 1.0, 0.0 ); } +static void qskBulletGraphic( QPainter* painter ) +{ + painter->setPen( QPen( Qt::black, 1.0 ) ); + painter->drawEllipse( QRectF( 0.0, 0.0, 1.0, 1.0 ) ); +} + QskGraphic QskStandardSymbol::graphic( Type symbolType ) { static QskGraphic graphics[ SymbolTypeCount ]; @@ -263,6 +269,11 @@ QskGraphic QskStandardSymbol::graphic( Type symbolType ) case QskStandardSymbol::SegmentedBarCheckMark: { qskCheckMarkGraphic( &painter ); + break; + } + case QskStandardSymbol::Bullet: + { + qskBulletGraphic( &painter ); break; } case QskStandardSymbol::NoSymbol: diff --git a/src/graphic/QskStandardSymbol.h b/src/graphic/QskStandardSymbol.h index 78f5a11d..196e340e 100644 --- a/src/graphic/QskStandardSymbol.h +++ b/src/graphic/QskStandardSymbol.h @@ -34,6 +34,8 @@ namespace QskStandardSymbol ComboBoxSymbolPopupClosed, ComboBoxSymbolPopupOpen, + Bullet, + SymbolTypeCount }; diff --git a/src/src.pro b/src/src.pro index 7ba0bd8b..eb51ddab 100644 --- a/src/src.pro +++ b/src/src.pro @@ -205,6 +205,8 @@ HEADERS += \ controls/QskQuick.h \ controls/QskQuickItem.h \ controls/QskQuickItemPrivate.h \ + controls/QskRadioBox.h \ + controls/QskRadioBoxSkinlet.h \ controls/QskScrollArea.h \ controls/QskScrollBox.h \ controls/QskScrollView.h \ @@ -297,6 +299,8 @@ SOURCES += \ controls/QskScrollArea.cpp \ controls/QskScrollBox.cpp \ controls/QskScrollView.cpp \ + controls/QskRadioBox.cpp \ + controls/QskRadioBoxSkinlet.cpp \ controls/QskScrollViewSkinlet.cpp \ controls/QskSegmentedBar.cpp \ controls/QskSegmentedBarSkinlet.cpp \ From 92ba2385db1eb8537efe920607c920039b3b1596 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 11 Feb 2023 21:13:32 +0100 Subject: [PATCH 02/25] Rename radio to button --- skins/material3/QskMaterial3Skin.cpp | 10 ++++---- src/controls/QskRadioBox.cpp | 2 +- src/controls/QskRadioBox.h | 2 +- src/controls/QskRadioBoxSkinlet.cpp | 34 ++++++++++++++-------------- src/controls/QskRadioBoxSkinlet.h | 4 ++-- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 816b8a39..deeddb90 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -472,7 +472,7 @@ void Editor::setupRadioBox() using A = QskAspect; setStrutSize( Q::Text, {100, 20 }); - setStrutSize( Q::Radio, {20, 20 }); + setStrutSize( Q::Button, {20, 20 }); setStrutSize( Q::Symbol, {10, 10 }); setStrutSize( Q::Ripple | Q::Focused, { 40, 40 }); @@ -480,10 +480,10 @@ void Editor::setupRadioBox() setColor( Q::Text, m_pal.onBackground ); - setBoxShape(Q::Radio, 20); - setBoxBorderMetrics( Q::Radio, 2_dp ); - setBoxBorderColors( Q::Radio, m_pal.onBackground ); - setBoxBorderColors( Q::Radio | Q::Selected, m_pal.primary ); + setBoxShape(Q::Button, 20); + setBoxBorderMetrics( Q::Button, 2_dp ); + setBoxBorderColors( Q::Button, m_pal.onBackground ); + setBoxBorderColors( Q::Button | Q::Selected, m_pal.primary ); setBoxShape(Q::Ripple, 40); diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index b99541af..8eb33b21 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -3,7 +3,7 @@ #include QSK_SUBCONTROL( QskRadioBox, Panel ) -QSK_SUBCONTROL( QskRadioBox, Radio ) +QSK_SUBCONTROL( QskRadioBox, Button ) QSK_SUBCONTROL( QskRadioBox, Symbol ) QSK_SUBCONTROL( QskRadioBox, Text ) QSK_SUBCONTROL( QskRadioBox, Ripple ) diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h index 4e5ef368..3a1a5fe5 100644 --- a/src/controls/QskRadioBox.h +++ b/src/controls/QskRadioBox.h @@ -22,7 +22,7 @@ class QSK_EXPORT QskRadioBox : public QskControl using Inherited = QskControl; public: - QSK_SUBCONTROLS( Panel, Radio, Symbol, Text, Ripple ) + QSK_SUBCONTROLS( Panel, Button, Symbol, Text, Ripple ) QSK_STATES( Selected, Pressed, Focused ) QskRadioBox( QQuickItem* parent = nullptr ); diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index d0bff61b..f333476e 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -16,7 +16,7 @@ namespace { QskRadioBoxSkinlet::QskRadioBoxSkinlet( QskSkin* ) { - setNodeRoles( { PanelRole, RadioRole, SymbolRole, TextRole, RippleRole } ); + setNodeRoles( { PanelRole, ButtonRole, SymbolRole, TextRole, RippleRole } ); } QskRadioBoxSkinlet::~QskRadioBoxSkinlet() @@ -35,7 +35,7 @@ QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, result.setSize( radio->strutSizeHint( subcontrol ) ); result.moveTop( (lh + spacing) * radio->focusedIndex() - (result.size().height() - lh ) / 2); - result.moveLeft(( radio->strutSizeHint( Q::Radio ).width() + result.moveLeft(( radio->strutSizeHint( Q::Button ).width() - result.width()) /2); return result; } @@ -50,7 +50,7 @@ QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable, const auto font = skinnable->effectiveFont( Q::Text ); const auto textMargins = skinnable->marginHint( Q::Text ); - const auto buttonMargins = skinnable->marginHint( Q::Radio ); + const auto buttonMargins = skinnable->marginHint( Q::Button ); const auto symbolMargins = skinnable->marginHint( Q::Symbol ); qreal maxTextWidth = 0; @@ -58,7 +58,7 @@ QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable, maxTextWidth = std::max( maxTextWidth, qskHorizontalAdvance( font, item ) ); } - auto radioWidth = radio->strutSizeHint(Q::Radio).width(); + auto radioWidth = radio->strutSizeHint(Q::Button).width(); auto symbolWidth = radio->strutSizeHint(Q::Symbol).width(); maxTextWidth += textMargins.left() + textMargins.right(); @@ -74,31 +74,31 @@ QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable, QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node) const { - auto radioButtons = static_cast( skinnable ); + auto radio = static_cast( skinnable ); switch( nodeRole ) { case PanelRole: return updateBoxNode( skinnable, node, Q::Panel ); - case RadioRole: - return updateSeriesNode( radioButtons, Q::Radio, node ); + case ButtonRole: + return updateSeriesNode( radio, Q::Button, node ); case SymbolRole: - return updateSeriesNode( radioButtons, Q::Symbol, node ); + return updateSeriesNode( radio, Q::Symbol, node ); case TextRole: - return updateSeriesNode( radioButtons, Q::Text, node ); + return updateSeriesNode( radio, Q::Text, node ); case RippleRole: - return updateBoxNode( radioButtons, node, Q::Ripple ); + return updateBoxNode( radio, node, Q::Ripple ); }; return Inherited::updateSubNode( skinnable, nodeRole, node ); } qreal QskRadioBoxSkinlet::lineHeight(const QskRadioBox* target) const { - auto strutHight = qMax( target->strutSizeHint( Q::Radio ).height(), + auto strutHight = qMax( target->strutSizeHint( Q::Button ).height(), target->strutSizeHint( Q::Text ).height() ); const auto textMargins = target->marginHint( Q::Text ); auto fontHeight = target->effectiveFontHeight( Q::Text ); @@ -114,7 +114,7 @@ int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, return radio->items().count(); } -QRectF QskRadioBoxSkinlet::radioRect( const QskRadioBox* radio, +QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, const QskAspect::Subcontrol target, const QRectF& rect, int index ) const { auto result = rect; @@ -127,7 +127,7 @@ QRectF QskRadioBoxSkinlet::radioRect( const QskRadioBox* radio, if( radio->layoutMirroring() ) { result.moveRight( rect.width() ); } else { - result.moveLeft((radio->strutSizeHint( Q::Radio ).width() + result.moveLeft((radio->strutSizeHint( Q::Button ).width() - result.width()) / 2); } @@ -149,8 +149,8 @@ QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, + textMargins.top()); if(!radio->layoutMirroring()) { - auto symbolWidth = radioRect( radio, Q::Symbol, rect, index ).width(); - auto radioWidth = radioRect( radio, Q::Radio, rect, index ).width(); + auto symbolWidth = buttonRect( radio, Q::Symbol, rect, index ).width(); + auto radioWidth = buttonRect( radio, Q::Button, rect, index ).width(); result.moveLeft( qMax(symbolWidth, radioWidth) + textMargins.left()); } @@ -166,7 +166,7 @@ QRectF QskRadioBoxSkinlet::sampleRect( const QskSkinnable* skinnable, return textRect( radio, rect, index ); } - return radioRect( radio, subcontrol, rect, index); + return buttonRect( radio, subcontrol, rect, index); } QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnable, @@ -195,7 +195,7 @@ QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, Qt::AlignLeft, radioButtons->items()[index], subcontrol); - } else if (subcontrol == Q::Radio) { + } else if (subcontrol == Q::Button) { return QskSkinlet::updateBoxNode(radioButtons, node, rect, diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h index 08fdb8bc..dcafffe2 100644 --- a/src/controls/QskRadioBoxSkinlet.h +++ b/src/controls/QskRadioBoxSkinlet.h @@ -15,7 +15,7 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet enum NodeRole { PanelRole, - RadioRole, + ButtonRole, SymbolRole, TextRole, RippleRole, @@ -38,7 +38,7 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet const QRectF&, QskAspect::Subcontrol, int index ) const override; QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; - QRectF radioRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, int ) const; + QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, int ) const; QskAspect::States sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int index ) const override; From a7dc136dcdc78c43303ec7980a07bdf15a829d04 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 11 Feb 2023 21:15:32 +0100 Subject: [PATCH 03/25] Make unified control name --- src/controls/QskRadioBoxSkinlet.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index f333476e..eb53af07 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -171,10 +171,10 @@ QRectF QskRadioBoxSkinlet::sampleRect( const QskSkinnable* skinnable, QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const { - auto radioButtons = static_cast( skinnable ); + auto radio = static_cast( skinnable ); auto states = Inherited::sampleStates( skinnable, subControl, index ); - if( radioButtons->selectedIndex() == index ) { + if( radio->selectedIndex() == index ) { return states | Q::Selected; } @@ -183,33 +183,33 @@ QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnabl QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, QskAspect::Subcontrol subcontrol, int index, QSGNode* node ) const { - auto radioButtons = static_cast( skinnable ); + auto radio = static_cast( skinnable ); - auto rect = sampleRect( skinnable, radioButtons->contentsRect(), + auto rect = sampleRect( skinnable, radio->contentsRect(), subcontrol, index ); if( subcontrol == Q::Text ) { - return QskSkinlet::updateTextNode( radioButtons, + return QskSkinlet::updateTextNode( radio, node, rect, Qt::AlignLeft, - radioButtons->items()[index], + radio->items()[index], subcontrol); } else if (subcontrol == Q::Button) { - return QskSkinlet::updateBoxNode(radioButtons, + return QskSkinlet::updateBoxNode(radio, node, rect, subcontrol); } else if( subcontrol == Q::Symbol ) { auto symbol = QskStandardSymbol::NoSymbol; - auto color = radioButtons->color( subcontrol ).rgb(); + auto color = radio->color( subcontrol ).rgb(); - if( radioButtons->selectedIndex() == index ) { + if( radio->selectedIndex() == index ) { symbol = QskStandardSymbol::Bullet; - color = radioButtons->color( subcontrol | Q::Selected ).rgb(); + color = radio->color( subcontrol | Q::Selected ).rgb(); } - auto graphic = radioButtons->effectiveSkin()->symbol( symbol ); + auto graphic = radio->effectiveSkin()->symbol( symbol ); /* Our default skins do not have the concept of colorRoles @@ -220,7 +220,7 @@ QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, QskGraphic::fromGraphic( graphic, filter ); - return updateGraphicNode( radioButtons, node, graphic, filter, rect ); + return updateGraphicNode( radio, node, graphic, filter, rect ); } return node; From 84d662979d1984b207c95e6a865533afc2aad8fd Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 11 Feb 2023 23:12:31 +0100 Subject: [PATCH 04/25] Fix user state positions --- src/controls/QskRadioBox.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index 8eb33b21..143aad36 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -8,9 +8,9 @@ QSK_SUBCONTROL( QskRadioBox, Symbol ) QSK_SUBCONTROL( QskRadioBox, Text ) QSK_SUBCONTROL( QskRadioBox, Ripple ) -QSK_STATE( QskRadioBox, Selected, QskAspect::FirstUserState ) -QSK_STATE( QskRadioBox, Pressed, QskAspect::FirstUserState << 1) -QSK_STATE( QskRadioBox, Focused, QskAspect::FirstUserState << 2) +QSK_STATE( QskRadioBox, Selected, QskAspect::FirstUserState << 1) +QSK_STATE( QskRadioBox, Pressed, QskAspect::FirstUserState << 2) +QSK_STATE( QskRadioBox, Focused, QskAspect::FirstUserState << 3) class QskRadioBox::PrivateData { public: From 4c1f60eb1c9276e3bd02bc7fc82ae24f25810f25 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 11 Feb 2023 23:14:29 +0100 Subject: [PATCH 05/25] Fix Ribble in mirrored layouts --- src/controls/QskRadioBoxSkinlet.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index eb53af07..6b235758 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -29,15 +29,7 @@ QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, auto radio = static_cast( skinnable ); if( subcontrol == Q::Ripple ) { - auto result = contentsRect; - auto lh = lineHeight( radio ); - auto spacing = radio->spacingHint(Q::Panel); - result.setSize( radio->strutSizeHint( subcontrol ) ); - result.moveTop( (lh + spacing) * radio->focusedIndex() - - (result.size().height() - lh ) / 2); - result.moveLeft(( radio->strutSizeHint( Q::Button ).width() - - result.width()) /2); - return result; + return buttonRect(radio, Q::Ripple, contentsRect, radio->focusedIndex()); } return contentsRect; @@ -124,11 +116,13 @@ QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, result.moveTop( ( lineHeight( radio ) + spacing ) * index + (lineHeight(radio) - result.size().height()) / 2); + auto maxWidth = qMax(radio->strutSizeHint( Q::Button ).width(), + radio->strutSizeHint( Q::Symbol ).width()); + if( radio->layoutMirroring() ) { - result.moveRight( rect.width() ); + result.moveRight( rect.width() - (maxWidth - result.width())/2); } else { - result.moveLeft((radio->strutSizeHint( Q::Button ).width() - - result.width()) / 2); + result.moveLeft((maxWidth - result.width()) / 2); } return result; From ffa150a5fd338c7c783e72199e76c65a31e96f55 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 11 Feb 2023 23:15:07 +0100 Subject: [PATCH 06/25] Fix text position in mirrored layouts --- src/controls/QskRadioBoxSkinlet.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 6b235758..75a4e8d3 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -134,18 +134,16 @@ QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, auto spacing = radio->spacingHint(Q::Panel); auto lh = lineHeight( radio ); const auto textMargins = radio->marginHint( Q::Text ); - - result.setSize( { radio->strutSizeHint( Q::Text ).width(), lh } ); - result.moveTop( index * ( lh + spacing ) + lh - radio->effectiveFontHeight(Q::Text) + textMargins.top()); - if(!radio->layoutMirroring()) { - auto symbolWidth = buttonRect( radio, Q::Symbol, rect, index ).width(); - auto radioWidth = buttonRect( radio, Q::Button, rect, index ).width(); - result.moveLeft( qMax(symbolWidth, radioWidth) + textMargins.left()); + if( !radio->layoutMirroring() ) { + auto maxWidth = qMax( buttonRect( radio, Q::Symbol, rect, index ).width(), + buttonRect( radio, Q::Button, rect, index ).width()); + + result.moveLeft( maxWidth + textMargins.left()); } return result; From d510570943f12a7ae3b029ae94b8e6ac785a8679 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sun, 12 Feb 2023 01:30:15 +0100 Subject: [PATCH 07/25] Return empty Rect if nothing to paint --- src/controls/QskRadioBoxSkinlet.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 75a4e8d3..60b46e18 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -109,6 +109,9 @@ int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, const QskAspect::Subcontrol target, const QRectF& rect, int index ) const { + if( index < 0 ) { + return QRectF(); + } auto result = rect; result.setSize( radio->strutSizeHint( target ) ); From bfc172c04fe501bea6197b4ed8477d36a41aee3e Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sun, 12 Feb 2023 01:32:21 +0100 Subject: [PATCH 08/25] Respect focused and pressed state in the skinlet --- src/controls/QskRadioBox.cpp | 4 ++++ src/controls/QskRadioBox.h | 3 ++- src/controls/QskRadioBoxSkinlet.cpp | 10 +++++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index 143aad36..95edfc01 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -66,6 +66,10 @@ int QskRadioBox::focusedIndex() const { return m_data->focusedIndex; } +int QskRadioBox::pressedIndex() const { + return m_data->pressedIndex; +} + void QskRadioBox::setSelectedIndex( int index ) { if( index == m_data->selectedIndex || index >= m_data->items.count() ) { diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h index 3a1a5fe5..59693698 100644 --- a/src/controls/QskRadioBox.h +++ b/src/controls/QskRadioBox.h @@ -29,9 +29,10 @@ class QSK_EXPORT QskRadioBox : public QskControl QskRadioBox( const QStringList&, QQuickItem* parent = nullptr ); QskRadioBox( const QStringList&, int, QQuickItem* parent = nullptr ); - int selectedIndex() const; const QStringList& items() const; + int selectedIndex() const; int focusedIndex() const; + int pressedIndex() const; public Q_SLOTS: void setSelectedIndex( int ); diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 60b46e18..bfafbc07 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -170,7 +170,15 @@ QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnabl auto states = Inherited::sampleStates( skinnable, subControl, index ); if( radio->selectedIndex() == index ) { - return states | Q::Selected; + states |= Q::Selected; + } + + if( radio->pressedIndex() == index ) { + states |= Q::Pressed; + } + + if( radio->focusedIndex() == index ) { + states |= Q::Focused; } return states; From f5c7f7f2b403193dce4749ef10a1c3df84787c4c Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sun, 12 Feb 2023 02:42:33 +0100 Subject: [PATCH 09/25] Add animation support for the Ripple, remove focusedItem --- skins/material3/QskMaterial3Skin.cpp | 19 ++++----- src/controls/QskRadioBox.cpp | 64 ++++++++++++++-------------- src/controls/QskRadioBox.h | 1 - src/controls/QskRadioBoxSkinlet.cpp | 51 +++++++++++++--------- src/controls/QskRadioBoxSkinlet.h | 2 +- 5 files changed, 74 insertions(+), 63 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index deeddb90..80b03b95 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -4,6 +4,7 @@ *****************************************************************************/ #include "QskMaterial3Skin.h" +#include "QskTextOptions.h" #include @@ -471,10 +472,9 @@ void Editor::setupRadioBox() using Q = QskRadioBox; using A = QskAspect; - setStrutSize( Q::Text, {100, 20 }); setStrutSize( Q::Button, {20, 20 }); setStrutSize( Q::Symbol, {10, 10 }); - setStrutSize( Q::Ripple | Q::Focused, { 40, 40 }); + setStrutSize( Q::Ripple, { 40, 40 }); setSpacing(Q::Panel, 10); @@ -486,18 +486,17 @@ void Editor::setupRadioBox() setBoxBorderColors( Q::Button | Q::Selected, m_pal.primary ); setBoxShape(Q::Ripple, 40); - - setColor( Q::Symbol, m_pal.primary ); - setColor( Q::Ripple | Q::Focused, - stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); - setColor( Q::Ripple | Q::Selected | Q::Focused, - // stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); - Qt::red); + + setColor( Q::Symbol, m_pal.primary ); + setColor( Q::Ripple, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); + setColor( Q::Ripple | Q::Selected, stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); + setMargin( Q::Text, QskMargins(10, 0,0,0)); setAlignment( Q::Text, Qt::AlignBottom ); - setAnimation(Q::Ripple | A::Metric, 1000); + + setAnimation( Q::Ripple | A::Metric | A::Position, qskDuration ); } void Editor::setupFocusIndicator() diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index 95edfc01..bad4c1fd 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -1,5 +1,7 @@ #include "QskRadioBox.h" #include "QskEvent.h" +#include "QskAnimationHint.h" + #include QSK_SUBCONTROL( QskRadioBox, Panel ) @@ -17,7 +19,6 @@ public: QStringList items; int selectedIndex = -1; int pressedIndex = -1; - int focusedIndex = -1; }; QskRadioBox::QskRadioBox( QQuickItem* parent ) : @@ -35,6 +36,8 @@ QskRadioBox::QskRadioBox( QQuickItem* parent ) : setFocusPolicy( Qt::NoFocus ); } }); + + setPositionHint( Ripple, -1 ); } QskRadioBox::QskRadioBox( const QStringList& list, QQuickItem* parent ) : @@ -62,10 +65,6 @@ const QStringList& QskRadioBox::items() const { return m_data->items; } -int QskRadioBox::focusedIndex() const { - return m_data->focusedIndex; -} - int QskRadioBox::pressedIndex() const { return m_data->pressedIndex; } @@ -102,48 +101,53 @@ void QskRadioBox::keyPressEvent( QKeyEvent* event ) case Qt::Key_Up: case Qt::Key_Left: m_data->selectedIndex = qMax(m_data->selectedIndex - 1, 0); - m_data->focusedIndex = m_data->selectedIndex; - setSkinStateFlag( QskRadioBox::Selected ); + setPositionHint( Ripple, m_data->selectedIndex ); event->setAccepted( true ); update(); return; case Qt::Key_Down: case Qt::Key_Right: m_data->selectedIndex = qMin(m_data->selectedIndex + 1, items().size() - 1); - m_data->focusedIndex = m_data->selectedIndex; - setSkinStateFlag( QskRadioBox::Selected ); + setPositionHint( Ripple, m_data->selectedIndex ); event->setAccepted( true ); update(); return; case Qt::Key_Select: case Qt::Key_Return: case Qt::Key_Space: - m_data->selectedIndex = m_data->focusedIndex; - setSkinStateFlag( QskRadioBox::Selected ); - setSkinStateFlag( QskRadioBox::Pressed ); + m_data->selectedIndex = positionHint( Ripple ); event->setAccepted( true ); update(); return; } - auto nextTabIndex = m_data->focusedIndex; - nextTabIndex += qskFocusChainIncrement( event ); + auto currentTabIndex = positionHint( Ripple ); + auto nextTabIndex = currentTabIndex + qskFocusChainIncrement( event ); if( nextTabIndex >= items().size() || nextTabIndex < 0 ) { - Inherited::keyPressEvent( event ); - } else { - m_data->focusedIndex = nextTabIndex; - setSkinStateFlag( QskRadioBox::Focused ); - event->setAccepted( true ); + Inherited::keyPressEvent( event ); + setPositionHint(Ripple, -1); update(); + } else { + event->setAccepted( true ); + setPositionHint( Ripple, (float) nextTabIndex ); + + const auto aspect = Ripple | QskAspect::Metric | QskAspect::Position; + auto hint = animationHint(aspect | skinStates()); + if( hint.isValid()) { + startTransition( aspect, + hint, + (float) currentTabIndex, (float) nextTabIndex ); + } + + update(); + } } void QskRadioBox::keyReleaseEvent( QKeyEvent* e ) { - setSkinStateFlag( QskRadioBox::Pressed, false ); e->setAccepted( true ); - update(); } void QskRadioBox::mousePressEvent( QMouseEvent* e ) @@ -153,18 +157,14 @@ void QskRadioBox::mousePressEvent( QMouseEvent* e ) m_data->pressedIndex = indexAtPosition; m_data->selectedIndex = -1; - m_data->focusedIndex = indexAtPosition; - - setSkinStateFlag( QskRadioBox::Pressed ); + setPositionHint( Ripple, indexAtPosition ); e->setAccepted( true ); - update(); + update(); } void QskRadioBox::mouseReleaseEvent( QMouseEvent* e ) { - setSkinStateFlag( QskRadioBox::Pressed, false ); - auto index = indexAt( e->localPos() ); if( index == m_data->pressedIndex ) { setSelectedIndex( index ); @@ -176,19 +176,19 @@ void QskRadioBox::mouseReleaseEvent( QMouseEvent* e ) void QskRadioBox::focusInEvent( QFocusEvent* e ) { if( e->reason() == Qt::TabFocusReason ) { - m_data->focusedIndex = 0; + setPositionHint( Ripple, 0 ); } else if( e->reason() == Qt::BacktabFocusReason ) { - m_data->focusedIndex = items().size() - 1; + setPositionHint( Ripple, items().size() - 1 ); } - setSkinStateFlag( Focused ); + update(); Inherited::focusInEvent( e ); } void QskRadioBox::focusOutEvent( QFocusEvent* e ) { - m_data->focusedIndex = -1; - setSkinStateFlag( Focused, false ); + setPositionHint(Ripple, -1); update(); + Inherited::focusOutEvent( e ); } diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h index 59693698..db9fd6ab 100644 --- a/src/controls/QskRadioBox.h +++ b/src/controls/QskRadioBox.h @@ -31,7 +31,6 @@ class QSK_EXPORT QskRadioBox : public QskControl const QStringList& items() const; int selectedIndex() const; - int focusedIndex() const; int pressedIndex() const; public Q_SLOTS: diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index bfafbc07..789367e9 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -3,6 +3,7 @@ #include "QskAspect.h" #include "QskRadioBox.h" +#include "QskSkinStateChanger.h" #include "QskStandardSymbol.h" #include "QskColorFilter.h" #include "QskGraphic.h" @@ -23,13 +24,31 @@ QskRadioBoxSkinlet::~QskRadioBoxSkinlet() { } +QskAspect::States statesForIndex(const QskRadioBox* radio, int index) { + auto states = radio->skinStates(); + + if( radio->selectedIndex() == index ) { + states |= Q::Selected; + } + + if( radio->pressedIndex() == index ) { + states |= Q::Pressed; + } + + if( radio->positionHint( Q::Ripple ) == index ) { + states |= Q::Focused; + } + + return states; +} + QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subcontrol) const { auto radio = static_cast( skinnable ); if( subcontrol == Q::Ripple ) { - return buttonRect(radio, Q::Ripple, contentsRect, radio->focusedIndex()); + return buttonRect(radio, Q::Ripple, contentsRect, radio->positionHint(Q::Ripple)); } return contentsRect; @@ -83,7 +102,12 @@ QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, return updateSeriesNode( radio, Q::Text, node ); case RippleRole: + { + QskSkinStateChanger cleaner( radio ); + cleaner.setStates( statesForIndex( radio, radio->positionHint( Q::Ripple ) ) ); + return updateBoxNode( radio, node, Q::Ripple ); + } }; return Inherited::updateSubNode( skinnable, nodeRole, node ); @@ -108,10 +132,11 @@ int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, const QskAspect::Subcontrol target, - const QRectF& rect, int index ) const { + const QRectF& rect, double index ) const { if( index < 0 ) { return QRectF(); } + auto result = rect; result.setSize( radio->strutSizeHint( target ) ); @@ -169,19 +194,7 @@ QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnabl auto radio = static_cast( skinnable ); auto states = Inherited::sampleStates( skinnable, subControl, index ); - if( radio->selectedIndex() == index ) { - states |= Q::Selected; - } - - if( radio->pressedIndex() == index ) { - states |= Q::Pressed; - } - - if( radio->focusedIndex() == index ) { - states |= Q::Focused; - } - - return states; + return states | statesForIndex( radio, index ); } QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, @@ -199,10 +212,10 @@ QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, radio->items()[index], subcontrol); } else if (subcontrol == Q::Button) { - return QskSkinlet::updateBoxNode(radio, - node, - rect, - subcontrol); + return QskSkinlet::updateBoxNode( radio, + node, + rect, + subcontrol ); } else if( subcontrol == Q::Symbol ) { auto symbol = QskStandardSymbol::NoSymbol; auto color = radio->color( subcontrol ).rgb(); diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h index dcafffe2..a258125d 100644 --- a/src/controls/QskRadioBoxSkinlet.h +++ b/src/controls/QskRadioBoxSkinlet.h @@ -38,7 +38,7 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet const QRectF&, QskAspect::Subcontrol, int index ) const override; QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; - QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, int ) const; + QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, double ) const; QskAspect::States sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int index ) const override; From 5fa060617cd518a11f303d730b976a74fefc8bef Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Tue, 14 Feb 2023 20:05:29 +0100 Subject: [PATCH 10/25] Use dpi instead of pixel --- skins/material3/QskMaterial3Skin.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 80b03b95..188bf681 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -472,27 +472,25 @@ void Editor::setupRadioBox() using Q = QskRadioBox; using A = QskAspect; - setStrutSize( Q::Button, {20, 20 }); - setStrutSize( Q::Symbol, {10, 10 }); - setStrutSize( Q::Ripple, { 40, 40 }); - - setSpacing(Q::Panel, 10); - - setColor( Q::Text, m_pal.onBackground ); + setSpacing(Q::Panel, 10_dp); - setBoxShape(Q::Button, 20); + setStrutSize( Q::Button, { 20_dp, 20_dp }); + setStrutSize( Q::Symbol, { 10_dp, 10_dp }); + setStrutSize( Q::Ripple, { 40_dp, 40_dp }); + + setBoxShape(Q::Button, 20_dp); + setBoxShape(Q::Ripple, 40_dp); setBoxBorderMetrics( Q::Button, 2_dp ); + setBoxBorderColors( Q::Button, m_pal.onBackground ); setBoxBorderColors( Q::Button | Q::Selected, m_pal.primary ); - setBoxShape(Q::Ripple, 40); - - + setColor( Q::Text, m_pal.onBackground ); setColor( Q::Symbol, m_pal.primary ); setColor( Q::Ripple, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); setColor( Q::Ripple | Q::Selected, stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); - setMargin( Q::Text, QskMargins(10, 0,0,0)); + setMargin( Q::Text, QskMargins( 10_dp, 0, 0, 0 )); setAlignment( Q::Text, Qt::AlignBottom ); From fc4a38920196b232ccd0d1748b8fa0457c416685 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Tue, 14 Feb 2023 20:06:52 +0100 Subject: [PATCH 11/25] Code cleanup --- src/controls/QskRadioBoxSkinlet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 789367e9..6e5112cc 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -103,8 +103,8 @@ QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, case RippleRole: { - QskSkinStateChanger cleaner( radio ); - cleaner.setStates( statesForIndex( radio, radio->positionHint( Q::Ripple ) ) ); + QskSkinStateChanger changer( radio ); + changer.setStates( statesForIndex( radio, radio->positionHint( Q::Ripple ) ) ); return updateBoxNode( radio, node, Q::Ripple ); } From 49cd540ce0e23d4fd799fe00474ba25b607732f7 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Tue, 14 Feb 2023 20:25:10 +0100 Subject: [PATCH 12/25] Add disabled support --- skins/material3/QskMaterial3Skin.cpp | 6 ++++++ src/controls/QskRadioBoxSkinlet.cpp | 2 ++ 2 files changed, 8 insertions(+) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 188bf681..b2385434 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -489,6 +489,12 @@ void Editor::setupRadioBox() setColor( Q::Symbol, m_pal.primary ); setColor( Q::Ripple, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); setColor( Q::Ripple | Q::Selected, stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); + + setBoxBorderColors( Q::Button | Q::Disabled, m_pal.onSurface38 ); + setBoxBorderColors( Q::Button | Q::Disabled | Q::Selected, m_pal.onSurface38 ); + setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); + + setColor( Q::Symbol | Q::Disabled, m_pal.onSurface38 ); setMargin( Q::Text, QskMargins( 10_dp, 0, 0, 0 )); diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 6e5112cc..c7b8e3a1 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -233,6 +233,8 @@ QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, */ QskColorFilter filter; filter.addColorSubstitution( Qt::black, color ); + auto colorSub = radio->color( subcontrol | statesForIndex(radio, index) ); + filter.addColorSubstitution( Qt::black, colorSub.rgb() ); QskGraphic::fromGraphic( graphic, filter ); From e4a07909ac9f33bd4e55900e0c5c15d37a173b87 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Wed, 15 Feb 2023 00:20:19 +0100 Subject: [PATCH 13/25] Add Squiek theme --- skins/material3/QskMaterial3Skin.cpp | 2 +- skins/squiek/QskSquiekSkin.cpp | 35 +++++++++++++++ src/controls/QskRadioBox.cpp | 67 +++++++++++++++++++++++----- src/controls/QskRadioBox.h | 3 ++ src/controls/QskRadioBoxSkinlet.cpp | 15 +++++-- 5 files changed, 106 insertions(+), 16 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index b2385434..9177d514 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -496,7 +496,7 @@ void Editor::setupRadioBox() setColor( Q::Symbol | Q::Disabled, m_pal.onSurface38 ); - setMargin( Q::Text, QskMargins( 10_dp, 0, 0, 0 )); + setMargin( Q::Text, QskMargins( 10_dp, 0, 10_dp, 0 )); setAlignment( Q::Text, Qt::AlignBottom ); diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 9ae9a25f..c93525e8 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,7 @@ namespace void setupPopup(); void setupProgressBar(); void setupPushButton(); + void setupRadioBox(); void setupScrollView(); void setupSegmentedBar(); void setupSeparator(); @@ -259,6 +261,7 @@ void Editor::setup() setupPopup(); setupProgressBar(); setupPushButton(); + setupRadioBox(); setupScrollView(); setupSegmentedBar(); setupSeparator(); @@ -607,6 +610,38 @@ void Editor::setupPushButton() setAlignment( Q::Graphic, Qt::AlignCenter ); } +void Editor::setupRadioBox() +{ + using Q = QskRadioBox; + + setSpacing(Q::Panel, qskDpiScaled( 10 ) ); + + setStrutSize( Q::Button, { qskDpiScaled( 20 ), qskDpiScaled( 20 ) }); + setStrutSize( Q::Symbol, { qskDpiScaled( 9 ), qskDpiScaled( 9 ) }); + + setBoxShape(Q::Button, qskDpiScaled( 20 ) ); + setBoxShape(Q::Ripple, qskDpiScaled( 40 ) ); + setBoxBorderMetrics( Q::Button, qskDpiScaled( 1 ) ); + + setBoxBorderColors( Q::Button, m_pal.darker125 ); + setBoxBorderColors( Q::Button | Q::Disabled, m_pal.theme ); + + setColor( Q::Text, m_pal.themeForeground ); + setColor( Q::Symbol, m_pal.themeForeground ); + setColor( Q::Panel, m_pal.lighter125 ); + setColor( Q::Panel | Q::Disabled, m_pal.lighter125 ); + + setColor( Q::Button | Q::Disabled, m_pal.lighter110 ); + + setColor( Q::Text | Q::Disabled, m_pal.darker200 ); + + setColor( Q::Symbol | Q::Disabled, m_pal.darker200 ); + + setMargin( Q::Text, QskMargins( qskDpiScaled( 10 ), 0, qskDpiScaled( 10 ), 0 )); + + setAlignment( Q::Text, Qt::AlignBottom ); +} + void Editor::setupDialogButtonBox() { using Q = QskDialogButtonBox; diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index bad4c1fd..b651ce77 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -1,7 +1,9 @@ #include "QskRadioBox.h" #include "QskEvent.h" #include "QskAnimationHint.h" +#include "QskSkinlet.h" +#include #include QSK_SUBCONTROL( QskRadioBox, Panel ) @@ -18,6 +20,7 @@ class QskRadioBox::PrivateData { public: QStringList items; int selectedIndex = -1; + int focusedIndex = -1; int pressedIndex = -1; }; @@ -37,7 +40,7 @@ QskRadioBox::QskRadioBox( QQuickItem* parent ) : } }); - setPositionHint( Ripple, -1 ); + setFocusedIndex( -1 ); } QskRadioBox::QskRadioBox( const QStringList& list, QQuickItem* parent ) : @@ -57,6 +60,37 @@ QskRadioBox::QskRadioBox( const QStringList& items, } } +QRectF QskRadioBox::focusIndicatorRect() const { + if( m_data->focusedIndex > -1) { + + auto textRect = effectiveSkinlet()->sampleRect( this, + contentsRect(), QskRadioBox::Text, m_data->focusedIndex ); + + auto buttonRect = effectiveSkinlet()->sampleRect( this, + contentsRect(), QskRadioBox::Button, m_data->focusedIndex ); + + auto result = QRectF( + qMin( textRect.x(), buttonRect.x() ), + qMin( textRect.y(), buttonRect.y() ), + buttonRect.width() + textRect.width(), + qMax( buttonRect.height(), textRect.height() )); + + if( layoutMirroring() ) { + result.setWidth( + result.width() + marginHint( Text ).right() + + marginHint( Button ).left() ); + } else { + result.setWidth( + result.width() + marginHint( Text ).left() + + marginHint( Button ).right() ); + } + + return result; + } + + return QRectF(); +} + int QskRadioBox::selectedIndex() const { return m_data->selectedIndex; } @@ -92,6 +126,10 @@ void QskRadioBox::setItems( const QStringList& items ){ m_data->items = items; itemsChanged( items ); setSelectedIndex( m_data->selectedIndex ); + + if( m_data->focusedIndex > items.size() ) { + setFocusedIndex( 0 ); + } } void QskRadioBox::keyPressEvent( QKeyEvent* event ) @@ -101,36 +139,36 @@ void QskRadioBox::keyPressEvent( QKeyEvent* event ) case Qt::Key_Up: case Qt::Key_Left: m_data->selectedIndex = qMax(m_data->selectedIndex - 1, 0); - setPositionHint( Ripple, m_data->selectedIndex ); + setFocusedIndex( m_data->selectedIndex ); event->setAccepted( true ); update(); return; case Qt::Key_Down: case Qt::Key_Right: m_data->selectedIndex = qMin(m_data->selectedIndex + 1, items().size() - 1); - setPositionHint( Ripple, m_data->selectedIndex ); + setFocusedIndex( m_data->selectedIndex ); event->setAccepted( true ); update(); return; case Qt::Key_Select: case Qt::Key_Return: case Qt::Key_Space: - m_data->selectedIndex = positionHint( Ripple ); + m_data->selectedIndex = m_data->focusedIndex; event->setAccepted( true ); update(); return; } - auto currentTabIndex = positionHint( Ripple ); + auto currentTabIndex = m_data->focusedIndex; auto nextTabIndex = currentTabIndex + qskFocusChainIncrement( event ); if( nextTabIndex >= items().size() || nextTabIndex < 0 ) { Inherited::keyPressEvent( event ); - setPositionHint(Ripple, -1); + setFocusedIndex( -1); update(); } else { event->setAccepted( true ); - setPositionHint( Ripple, (float) nextTabIndex ); + setFocusedIndex( (float) nextTabIndex ); const auto aspect = Ripple | QskAspect::Metric | QskAspect::Position; auto hint = animationHint(aspect | skinStates()); @@ -157,7 +195,7 @@ void QskRadioBox::mousePressEvent( QMouseEvent* e ) m_data->pressedIndex = indexAtPosition; m_data->selectedIndex = -1; - setPositionHint( Ripple, indexAtPosition ); + setFocusedIndex( indexAtPosition ); e->setAccepted( true ); update(); @@ -176,9 +214,9 @@ void QskRadioBox::mouseReleaseEvent( QMouseEvent* e ) void QskRadioBox::focusInEvent( QFocusEvent* e ) { if( e->reason() == Qt::TabFocusReason ) { - setPositionHint( Ripple, 0 ); + setFocusedIndex(0 ); } else if( e->reason() == Qt::BacktabFocusReason ) { - setPositionHint( Ripple, items().size() - 1 ); + setFocusedIndex(items().size() - 1 ); } update(); @@ -186,7 +224,7 @@ void QskRadioBox::focusInEvent( QFocusEvent* e ) { } void QskRadioBox::focusOutEvent( QFocusEvent* e ) { - setPositionHint(Ripple, -1); + setFocusedIndex( -1 ); update(); Inherited::focusOutEvent( e ); @@ -202,4 +240,11 @@ int QskRadioBox::indexAt( const QPointF& target ) const { return index; } +void QskRadioBox::setFocusedIndex( int index ) { + qDebug() << "setting index " << index; + m_data->focusedIndex = index; + setPositionHint( Ripple, index ); + focusIndicatorRectChanged(); +} + #include "moc_QskRadioBox.cpp" diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h index db9fd6ab..20510ebd 100644 --- a/src/controls/QskRadioBox.h +++ b/src/controls/QskRadioBox.h @@ -28,6 +28,8 @@ class QSK_EXPORT QskRadioBox : public QskControl QskRadioBox( QQuickItem* parent = nullptr ); QskRadioBox( const QStringList&, QQuickItem* parent = nullptr ); QskRadioBox( const QStringList&, int, QQuickItem* parent = nullptr ); + + QRectF focusIndicatorRect() const override; const QStringList& items() const; int selectedIndex() const; @@ -54,6 +56,7 @@ class QSK_EXPORT QskRadioBox : public QskControl int indexAt( const QPointF& ) const; private: + void setFocusedIndex( int index ); class PrivateData; std::unique_ptr< PrivateData > m_data; }; diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index c7b8e3a1..7c01964d 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -162,16 +162,23 @@ QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, auto spacing = radio->spacingHint(Q::Panel); auto lh = lineHeight( radio ); const auto textMargins = radio->marginHint( Q::Text ); + const auto font = radio->effectiveFont( Q::Text ); result.moveTop( index * ( lh + spacing ) + lh - radio->effectiveFontHeight(Q::Text) + textMargins.top()); - if( !radio->layoutMirroring() ) { - auto maxWidth = qMax( buttonRect( radio, Q::Symbol, rect, index ).width(), - buttonRect( radio, Q::Button, rect, index ).width()); + result.setHeight( lh ); + result.setWidth( qskHorizontalAdvance( font, radio->items()[index] ) ); - result.moveLeft( maxWidth + textMargins.left()); + auto buttonWidth = buttonRect( radio, Q::Button, rect, index ).width(); + auto buttonsMargins = radio->marginHint( Q::Button ); + if( radio->layoutMirroring() ) { + result.moveLeft( rect.width() - textMargins.right() + - result.width() - buttonWidth - buttonsMargins.left()); + } else { + result.moveLeft( buttonWidth + textMargins.left() + + radio->marginHint( Q::Button ).right()); } return result; From 2775ecc7ed36c280b46052d35b5b3e1bcf2f077d Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Wed, 15 Feb 2023 00:23:10 +0100 Subject: [PATCH 14/25] Code cleanup --- skins/material3/QskMaterial3Skin.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 9177d514..26a2401d 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -4,7 +4,6 @@ *****************************************************************************/ #include "QskMaterial3Skin.h" -#include "QskTextOptions.h" #include From 518c401ac7be4677c3184e2b80430d1f3ef26143 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sun, 19 Feb 2023 18:01:58 +0100 Subject: [PATCH 15/25] Code cleanup --- skins/material3/QskMaterial3Skin.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 26a2401d..104272d6 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -471,35 +471,37 @@ void Editor::setupRadioBox() using Q = QskRadioBox; using A = QskAspect; + setAnimation( Q::Ripple | A::Metric | A::Position, qskDuration ); + setSpacing(Q::Panel, 10_dp); setStrutSize( Q::Button, { 20_dp, 20_dp }); setStrutSize( Q::Symbol, { 10_dp, 10_dp }); setStrutSize( Q::Ripple, { 40_dp, 40_dp }); + + setMargin( Q::Button, QskMargins( 10_dp, 0, 10, 0)); + setMargin( Q::Text, QskMargins( 10_dp, 0, 0, 0 )); + setAlignment( Q::Text, Qt::AlignBottom ); setBoxShape(Q::Button, 20_dp); setBoxShape(Q::Ripple, 40_dp); setBoxBorderMetrics( Q::Button, 2_dp ); - setBoxBorderColors( Q::Button, m_pal.onBackground ); - setBoxBorderColors( Q::Button | Q::Selected, m_pal.primary ); - setColor( Q::Text, m_pal.onBackground ); setColor( Q::Symbol, m_pal.primary ); setColor( Q::Ripple, stateLayerColor( m_pal.onSurface, m_pal.focusOpacity ) ); - setColor( Q::Ripple | Q::Selected, stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); + // Selected + setColor( Q::Ripple | Q::Selected, + stateLayerColor( m_pal.primary, m_pal.focusOpacity ) ); + setBoxBorderColors( Q::Button | Q::Selected, m_pal.primary ); + + // Disabled setBoxBorderColors( Q::Button | Q::Disabled, m_pal.onSurface38 ); setBoxBorderColors( Q::Button | Q::Disabled | Q::Selected, m_pal.onSurface38 ); setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); - setColor( Q::Symbol | Q::Disabled, m_pal.onSurface38 ); - setMargin( Q::Text, QskMargins( 10_dp, 0, 10_dp, 0 )); - - setAlignment( Q::Text, Qt::AlignBottom ); - - setAnimation( Q::Ripple | A::Metric | A::Position, qskDuration ); } void Editor::setupFocusIndicator() From aee27768cdd5ccd16dd497a9fcc0c20e18935ce5 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sun, 19 Feb 2023 18:04:02 +0100 Subject: [PATCH 16/25] Code cleanup --- src/controls/QskRadioBox.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index b651ce77..64a46138 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -241,7 +241,6 @@ int QskRadioBox::indexAt( const QPointF& target ) const { } void QskRadioBox::setFocusedIndex( int index ) { - qDebug() << "setting index " << index; m_data->focusedIndex = index; setPositionHint( Ripple, index ); focusIndicatorRectChanged(); From 4d0a26d76220d17a9eb70c7e97f1b3215e2a3cb2 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Mon, 20 Feb 2023 22:13:14 +0100 Subject: [PATCH 17/25] Fix missing moc include --- src/controls/QskRadioBoxSkinlet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 7c01964d..620034a1 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -250,3 +250,5 @@ QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, return node; } + +#include "moc_QskRadioBoxSkinlet.cpp" From 6beabfcbb103a3bffd422c77f20faf67324e0f3d Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 25 Feb 2023 22:24:39 +0100 Subject: [PATCH 18/25] Return empty Rect if item is empty --- src/controls/QskRadioBox.cpp | 4 ++++ src/controls/QskRadioBoxSkinlet.cpp | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index 64a46138..cff5d29b 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -69,6 +69,10 @@ QRectF QskRadioBox::focusIndicatorRect() const { auto buttonRect = effectiveSkinlet()->sampleRect( this, contentsRect(), QskRadioBox::Button, m_data->focusedIndex ); + if( textRect == QRectF() ) { + return buttonRect; + } + auto result = QRectF( qMin( textRect.x(), buttonRect.x() ), qMin( textRect.y(), buttonRect.y() ), diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 620034a1..18091e1c 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -158,6 +158,12 @@ QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, const QRectF& rect, int index ) const { + auto text = radio->items()[index]; + + if(text.isEmpty()) { + return QRectF(); + } + QRectF result = rect; auto spacing = radio->spacingHint(Q::Panel); auto lh = lineHeight( radio ); From 72190aee9168d97369317c4208e262908b1b6861 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 25 Feb 2023 22:25:43 +0100 Subject: [PATCH 19/25] Fix alighnment if sizes of symbol and button differ --- skins/material3/QskMaterial3Skin.cpp | 7 ++- skins/squiek/QskSquiekSkin.cpp | 1 + src/controls/QskRadioBoxSkinlet.cpp | 90 +++++++++++++++++++++------- src/controls/QskRadioBoxSkinlet.h | 3 + 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 104272d6..e41a653b 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -54,6 +54,7 @@ #include #include +#include static const int qskDuration = 150; @@ -479,10 +480,11 @@ void Editor::setupRadioBox() setStrutSize( Q::Symbol, { 10_dp, 10_dp }); setStrutSize( Q::Ripple, { 40_dp, 40_dp }); - setMargin( Q::Button, QskMargins( 10_dp, 0, 10, 0)); - setMargin( Q::Text, QskMargins( 10_dp, 0, 0, 0 )); + setAlignment( Q::Symbol, Qt::AlignCenter ); setAlignment( Q::Text, Qt::AlignBottom ); + setMargin( Q::Text, QskMargins( 10_dp, 0, 10_dp, 0)); + setBoxShape(Q::Button, 20_dp); setBoxShape(Q::Ripple, 40_dp); setBoxBorderMetrics( Q::Button, 2_dp ); @@ -501,7 +503,6 @@ void Editor::setupRadioBox() setBoxBorderColors( Q::Button | Q::Disabled | Q::Selected, m_pal.onSurface38 ); setColor( Q::Text | Q::Disabled, m_pal.onSurface38 ); setColor( Q::Symbol | Q::Disabled, m_pal.onSurface38 ); - } void Editor::setupFocusIndicator() diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index c93525e8..58ca99d1 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -639,6 +639,7 @@ void Editor::setupRadioBox() setMargin( Q::Text, QskMargins( qskDpiScaled( 10 ), 0, qskDpiScaled( 10 ), 0 )); + setAlignment( Q::Symbol, Qt::AlignCenter ); setAlignment( Q::Text, Qt::AlignBottom ); } diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 18091e1c..79573679 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -9,6 +9,7 @@ #include "QskGraphic.h" #include "QskFunctions.h" #include "QskSkin.h" +#include #include namespace { @@ -48,36 +49,36 @@ QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, auto radio = static_cast( skinnable ); if( subcontrol == Q::Ripple ) { - return buttonRect(radio, Q::Ripple, contentsRect, radio->positionHint(Q::Ripple)); + return rippleRect(radio, contentsRect); } return contentsRect; } QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable, - Qt::SizeHint, const QSizeF& ) const + Qt::SizeHint, const QSizeF& ) const { auto radio = static_cast( skinnable ); - const auto font = skinnable->effectiveFont( Q::Text ); + const auto font = skinnable->effectiveFont( Q::Text ); const auto textMargins = skinnable->marginHint( Q::Text ); const auto buttonMargins = skinnable->marginHint( Q::Button ); const auto symbolMargins = skinnable->marginHint( Q::Symbol ); - + qreal maxTextWidth = 0; for(auto& item : radio->items() ) { maxTextWidth = std::max( maxTextWidth, qskHorizontalAdvance( font, item ) ); } - auto radioWidth = radio->strutSizeHint(Q::Button).width(); + auto buttonWidth = radio->strutSizeHint(Q::Button).width(); auto symbolWidth = radio->strutSizeHint(Q::Symbol).width(); maxTextWidth += textMargins.left() + textMargins.right(); - radioWidth += buttonMargins.left() + buttonMargins.right(); + buttonWidth += buttonMargins.left() + buttonMargins.right(); symbolWidth += symbolMargins.left() + symbolMargins.right(); auto spacing = radio->spacingHint(Q::Panel); - return QSizeF( maxTextWidth + qMax(radioWidth, symbolWidth), + return QSizeF( maxTextWidth + qMax(buttonWidth, symbolWidth), ( lineHeight( radio ) + spacing ) * radio->items().size() - spacing ); } @@ -123,13 +124,40 @@ qreal QskRadioBoxSkinlet::lineHeight(const QskRadioBox* target) const { return qMax( strutHight, fontHeight ); } - int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, QskAspect::Subcontrol ) const { const auto radio = static_cast< const QskRadioBox* >( skinnable ); return radio->items().count(); } +QSizeF QskRadioBoxSkinlet::buttonSymbolSize( const QskRadioBox* radio ) const { + auto buttonStrut = radio->strutSizeHint( Q::Button ); + auto symbolStrut = radio->strutSizeHint( Q::Symbol ); + + buttonStrut = buttonStrut.grownBy( radio->marginHint( Q::Button ) ); + symbolStrut = symbolStrut.grownBy( radio->marginHint( Q::Symbol ) ); + + return QSizeF( + qMax( buttonStrut.width(), symbolStrut.width() ), + qMax( buttonStrut.height(), symbolStrut.height() ) ); +} + +QRectF QskRadioBoxSkinlet::rippleRect( const QskRadioBox* radio, + const QRectF& rect ) const { + auto ripplePosition = radio->positionHint( Q::Ripple ); + + if( ripplePosition < 0 ) { + return QRectF(); + } + + auto button = buttonRect( radio, Q::Button, rect, ripplePosition ); + auto rippleSize = radio->strutSizeHint( Q::Ripple ); + button.moveLeft( button.x() - ( rippleSize.width() - button.width() ) / 2 ); + button.moveTop( button.y() - ( rippleSize.height() - button.height() ) / 2 ); + button.setSize( rippleSize ); + return button; +} + QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, const QskAspect::Subcontrol target, const QRectF& rect, double index ) const { @@ -138,19 +166,38 @@ QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, } auto result = rect; - result.setSize( radio->strutSizeHint( target ) ); + result.setSize( radio->strutSizeHint( target )); auto spacing = radio->spacingHint(Q::Panel); - result.moveTop( ( lineHeight( radio ) + spacing ) * index - + (lineHeight(radio) - result.size().height()) / 2); + result.moveTop( ( lineHeight( radio ) + spacing ) * index ); + + auto margins = radio->marginHint( target ); + auto withMargins = result.size().grownBy( margins ); + + auto maxSize = buttonSymbolSize( radio ); + auto alignment = radio->alignmentHint( target ); + + // Vertical positioning + auto alignHeight = maxSize.height() - withMargins.height(); + if( alignment.testFlag( Qt::AlignVCenter )) { + result.moveTop( result.top() + alignHeight / 2); + } else if( alignment.testFlag( Qt::AlignBottom ) ) { + result.moveTop( result.top() + alignHeight ); + } + result.moveTop( result.top() + margins.top()); + + // Horizontal positioning + auto alignWidth = 0; + if( alignment.testFlag( Qt::AlignHCenter ) ) { + alignWidth = (maxSize.width() - withMargins.width()) / 2; + } else if ( alignment.testFlag( Qt::AlignRight )) { + alignWidth = maxSize.width() - withMargins.width(); + } - auto maxWidth = qMax(radio->strutSizeHint( Q::Button ).width(), - radio->strutSizeHint( Q::Symbol ).width()); - if( radio->layoutMirroring() ) { - result.moveRight( rect.width() - (maxWidth - result.width())/2); + result.moveRight( rect.width() - (alignWidth + margins.right() )); } else { - result.moveLeft((maxWidth - result.width()) / 2); + result.moveLeft( margins.left() + alignWidth ); } return result; @@ -175,16 +222,17 @@ QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, + textMargins.top()); result.setHeight( lh ); - result.setWidth( qskHorizontalAdvance( font, radio->items()[index] ) ); + result.setWidth( qskHorizontalAdvance( font, text ) ); - auto buttonWidth = buttonRect( radio, Q::Button, rect, index ).width(); + auto button = buttonRect( radio, Q::Button, rect, index ); auto buttonsMargins = radio->marginHint( Q::Button ); + auto buttonWidth = button.marginsAdded( buttonsMargins ).width(); + if( radio->layoutMirroring() ) { result.moveLeft( rect.width() - textMargins.right() - - result.width() - buttonWidth - buttonsMargins.left()); + - result.width() - buttonWidth); } else { - result.moveLeft( buttonWidth + textMargins.left() - + radio->marginHint( Q::Button ).right()); + result.moveLeft( buttonWidth + textMargins.left() ); } return result; diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h index a258125d..831cacca 100644 --- a/src/controls/QskRadioBoxSkinlet.h +++ b/src/controls/QskRadioBoxSkinlet.h @@ -37,8 +37,11 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet QRectF sampleRect( const QskSkinnable*, const QRectF&, QskAspect::Subcontrol, int index ) const override; + QSizeF buttonSymbolSize( const QskRadioBox* radio ) const; QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, double ) const; + QRectF rippleRect( const QskRadioBox*, const QRectF& ) const; + QskAspect::States sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int index ) const override; From 4310ee3c34bac0b318fdbac682bc52e60384b0f6 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 25 Feb 2023 22:27:56 +0100 Subject: [PATCH 20/25] Remove unused imports --- skins/material3/QskMaterial3Skin.cpp | 1 - src/controls/QskRadioBox.cpp | 3 --- src/controls/QskRadioBoxSkinlet.cpp | 2 -- 3 files changed, 6 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index e41a653b..8b80fe1e 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -54,7 +54,6 @@ #include #include -#include static const int qskDuration = 150; diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index cff5d29b..96959785 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -3,9 +3,6 @@ #include "QskAnimationHint.h" #include "QskSkinlet.h" -#include -#include - QSK_SUBCONTROL( QskRadioBox, Panel ) QSK_SUBCONTROL( QskRadioBox, Button ) QSK_SUBCONTROL( QskRadioBox, Symbol ) diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 79573679..fd08712c 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -9,8 +9,6 @@ #include "QskGraphic.h" #include "QskFunctions.h" #include "QskSkin.h" -#include -#include namespace { using Q = QskRadioBox; From c3a4472587bb1b969ae7880d346511a4be2dfe96 Mon Sep 17 00:00:00 2001 From: Clemens Manert Date: Sat, 25 Feb 2023 23:31:29 +0100 Subject: [PATCH 21/25] Code cleanup --- skins/material3/QskMaterial3Skin.cpp | 14 ++-- skins/squiek/QskSquiekSkin.cpp | 10 +-- src/controls/QskRadioBox.cpp | 64 +++++++++--------- src/controls/QskRadioBox.h | 16 ++--- src/controls/QskRadioBoxSkinlet.cpp | 98 +++++++++++++--------------- src/controls/QskRadioBoxSkinlet.h | 23 +++---- 6 files changed, 107 insertions(+), 118 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index 8b80fe1e..ef08bbbd 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -473,19 +473,19 @@ void Editor::setupRadioBox() setAnimation( Q::Ripple | A::Metric | A::Position, qskDuration ); - setSpacing(Q::Panel, 10_dp); + setSpacing( Q::Panel, 10_dp ); - setStrutSize( Q::Button, { 20_dp, 20_dp }); - setStrutSize( Q::Symbol, { 10_dp, 10_dp }); - setStrutSize( Q::Ripple, { 40_dp, 40_dp }); + setStrutSize( Q::Button, { 20_dp, 20_dp } ); + setStrutSize( Q::Symbol, { 10_dp, 10_dp } ); + setStrutSize( Q::Ripple, { 40_dp, 40_dp } ); setAlignment( Q::Symbol, Qt::AlignCenter ); setAlignment( Q::Text, Qt::AlignBottom ); - setMargin( Q::Text, QskMargins( 10_dp, 0, 10_dp, 0)); + setMargin( Q::Text, QskMargins( 10_dp, 0, 10_dp, 0 ) ); - setBoxShape(Q::Button, 20_dp); - setBoxShape(Q::Ripple, 40_dp); + setBoxShape( Q::Button, 20_dp ); + setBoxShape( Q::Ripple, 40_dp ); setBoxBorderMetrics( Q::Button, 2_dp ); setBoxBorderColors( Q::Button, m_pal.onBackground ); setColor( Q::Text, m_pal.onBackground ); diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 58ca99d1..0a14e8bd 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -145,7 +145,7 @@ namespace void setupPopup(); void setupProgressBar(); void setupPushButton(); - void setupRadioBox(); + void setupRadioBox(); void setupScrollView(); void setupSegmentedBar(); void setupSeparator(); @@ -616,11 +616,11 @@ void Editor::setupRadioBox() setSpacing(Q::Panel, qskDpiScaled( 10 ) ); - setStrutSize( Q::Button, { qskDpiScaled( 20 ), qskDpiScaled( 20 ) }); - setStrutSize( Q::Symbol, { qskDpiScaled( 9 ), qskDpiScaled( 9 ) }); + setStrutSize( Q::Button, { qskDpiScaled( 20 ), qskDpiScaled( 20 ) } ); + setStrutSize( Q::Symbol, { qskDpiScaled( 9 ), qskDpiScaled( 9 ) }) ; - setBoxShape(Q::Button, qskDpiScaled( 20 ) ); - setBoxShape(Q::Ripple, qskDpiScaled( 40 ) ); + setBoxShape( Q::Button, qskDpiScaled( 20 ) ); + setBoxShape( Q::Ripple, qskDpiScaled( 40 ) ); setBoxBorderMetrics( Q::Button, qskDpiScaled( 1 ) ); setBoxBorderColors( Q::Button, m_pal.darker125 ); diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index 96959785..3ba7f174 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -9,9 +9,9 @@ QSK_SUBCONTROL( QskRadioBox, Symbol ) QSK_SUBCONTROL( QskRadioBox, Text ) QSK_SUBCONTROL( QskRadioBox, Ripple ) -QSK_STATE( QskRadioBox, Selected, QskAspect::FirstUserState << 1) -QSK_STATE( QskRadioBox, Pressed, QskAspect::FirstUserState << 2) -QSK_STATE( QskRadioBox, Focused, QskAspect::FirstUserState << 3) +QSK_STATE( QskRadioBox, Selected, QskAspect::FirstUserState << 1 ) +QSK_STATE( QskRadioBox, Pressed, QskAspect::FirstUserState << 2 ) +QSK_STATE( QskRadioBox, Focused, QskAspect::FirstUserState << 3 ) class QskRadioBox::PrivateData { public: @@ -23,34 +23,30 @@ public: QskRadioBox::QskRadioBox( QQuickItem* parent ) : Inherited( parent ), - m_data( new PrivateData{} ) -{ + m_data( new PrivateData{} ) { setFocusPolicy( Qt::NoFocus ); setAcceptedMouseButtons( Qt::LeftButton ); connect(this, &QskRadioBox::itemsChanged, this, - [this]( const QStringList& items ) { - if( items.count() > 0 ) { - setFocusPolicy( Qt::StrongFocus ); - } else { - setFocusPolicy( Qt::NoFocus ); - } - }); + [this]( const QStringList& items ) { + if( items.count() > 0 ) { + setFocusPolicy( Qt::StrongFocus ); + } else { + setFocusPolicy( Qt::NoFocus ); + } + }); setFocusedIndex( -1 ); } QskRadioBox::QskRadioBox( const QStringList& list, QQuickItem* parent ) : - QskRadioBox( parent ) -{ + QskRadioBox( parent ) { setItems( list ); } QskRadioBox::QskRadioBox( const QStringList& items, - int selectedIndex, - QQuickItem* parent ) : - QskRadioBox( items, parent ) -{ + int selectedIndex, QQuickItem* parent ) : + QskRadioBox( items, parent ) { if( selectedIndex >= 0 && selectedIndex < items.count() ) { m_data->selectedIndex = selectedIndex; @@ -59,7 +55,6 @@ QskRadioBox::QskRadioBox( const QStringList& items, QRectF QskRadioBox::focusIndicatorRect() const { if( m_data->focusedIndex > -1) { - auto textRect = effectiveSkinlet()->sampleRect( this, contentsRect(), QskRadioBox::Text, m_data->focusedIndex ); @@ -71,10 +66,10 @@ QRectF QskRadioBox::focusIndicatorRect() const { } auto result = QRectF( - qMin( textRect.x(), buttonRect.x() ), - qMin( textRect.y(), buttonRect.y() ), - buttonRect.width() + textRect.width(), - qMax( buttonRect.height(), textRect.height() )); + qMin( textRect.x(), buttonRect.x() ), + qMin( textRect.y(), buttonRect.y() ), + buttonRect.width() + textRect.width(), + qMax( buttonRect.height(), textRect.height() )); if( layoutMirroring() ) { result.setWidth( @@ -106,7 +101,7 @@ int QskRadioBox::pressedIndex() const { void QskRadioBox::setSelectedIndex( int index ) { if( index == m_data->selectedIndex - || index >= m_data->items.count() ) { + || index >= m_data->items.count() ) { return; } @@ -139,14 +134,15 @@ void QskRadioBox::keyPressEvent( QKeyEvent* event ) { case Qt::Key_Up: case Qt::Key_Left: - m_data->selectedIndex = qMax(m_data->selectedIndex - 1, 0); + m_data->selectedIndex = qMax( m_data->selectedIndex - 1, 0 ); setFocusedIndex( m_data->selectedIndex ); event->setAccepted( true ); update(); return; case Qt::Key_Down: case Qt::Key_Right: - m_data->selectedIndex = qMin(m_data->selectedIndex + 1, items().size() - 1); + m_data->selectedIndex = qMin( m_data->selectedIndex + 1, + items().size() - 1 ); setFocusedIndex( m_data->selectedIndex ); event->setAccepted( true ); update(); @@ -165,18 +161,17 @@ void QskRadioBox::keyPressEvent( QKeyEvent* event ) if( nextTabIndex >= items().size() || nextTabIndex < 0 ) { Inherited::keyPressEvent( event ); - setFocusedIndex( -1); + setFocusedIndex( -1 ); update(); } else { event->setAccepted( true ); - setFocusedIndex( (float) nextTabIndex ); + setFocusedIndex( ( float ) nextTabIndex ); const auto aspect = Ripple | QskAspect::Metric | QskAspect::Position; auto hint = animationHint(aspect | skinStates()); if( hint.isValid()) { - startTransition( aspect, - hint, - (float) currentTabIndex, (float) nextTabIndex ); + startTransition( aspect, hint, + ( float ) currentTabIndex, ( float ) nextTabIndex ); } update(); @@ -191,7 +186,7 @@ void QskRadioBox::keyReleaseEvent( QKeyEvent* e ) void QskRadioBox::mousePressEvent( QMouseEvent* e ) { - auto indexAtPosition = indexAt(e->localPos()); + auto indexAtPosition = indexAt( e->localPos() ); m_data->pressedIndex = indexAtPosition; m_data->selectedIndex = -1; @@ -217,7 +212,7 @@ void QskRadioBox::focusInEvent( QFocusEvent* e ) { if( e->reason() == Qt::TabFocusReason ) { setFocusedIndex(0 ); } else if( e->reason() == Qt::BacktabFocusReason ) { - setFocusedIndex(items().size() - 1 ); + setFocusedIndex( items().size() - 1 ); } update(); @@ -235,8 +230,9 @@ int QskRadioBox::indexAt( const QPointF& target ) const { auto itemHeight = contentsRect().height() / items().size(); auto index = target.y() / itemHeight; - if( index < 0 || index >= items().size() ) + if( index < 0 || index >= items().size() ) { return -1; + } return index; } diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h index 20510ebd..de96be13 100644 --- a/src/controls/QskRadioBox.h +++ b/src/controls/QskRadioBox.h @@ -10,14 +10,14 @@ class QSK_EXPORT QskRadioBox : public QskControl Q_OBJECT Q_PROPERTY( int selectedIndex - READ selectedIndex - WRITE setSelectedIndex - NOTIFY selectedIndexChanged FINAL ) + READ selectedIndex + WRITE setSelectedIndex + NOTIFY selectedIndexChanged FINAL ) Q_PROPERTY( QStringList items - READ items - WRITE setItems - NOTIFY itemsChanged FINAL ) + READ items + WRITE setItems + NOTIFY itemsChanged FINAL ) using Inherited = QskControl; @@ -30,7 +30,7 @@ class QSK_EXPORT QskRadioBox : public QskControl QskRadioBox( const QStringList&, int, QQuickItem* parent = nullptr ); QRectF focusIndicatorRect() const override; - + const QStringList& items() const; int selectedIndex() const; int pressedIndex() const; @@ -43,7 +43,7 @@ class QSK_EXPORT QskRadioBox : public QskControl void selectedIndexChanged( int ); void itemsChanged( const QStringList& ); - protected: + protected: void keyPressEvent( QKeyEvent* ) override; void keyReleaseEvent( QKeyEvent* ) override; diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index fd08712c..41923fe3 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -23,7 +23,7 @@ QskRadioBoxSkinlet::~QskRadioBoxSkinlet() { } -QskAspect::States statesForIndex(const QskRadioBox* radio, int index) { +QskAspect::States statesForIndex( const QskRadioBox* radio, int index ) { auto states = radio->skinStates(); if( radio->selectedIndex() == index ) { @@ -42,49 +42,48 @@ QskAspect::States statesForIndex(const QskRadioBox* radio, int index) { } QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, - const QRectF& contentsRect, QskAspect::Subcontrol subcontrol) const + const QRectF& contentsRect, QskAspect::Subcontrol subcontrol ) const { - auto radio = static_cast( skinnable ); + auto radio = static_cast< const QskRadioBox* >( skinnable ); if( subcontrol == Q::Ripple ) { - return rippleRect(radio, contentsRect); + return rippleRect( radio, contentsRect ); } return contentsRect; } QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable, - Qt::SizeHint, const QSizeF& ) const + Qt::SizeHint, const QSizeF& ) const { - auto radio = static_cast( skinnable ); + auto radio = static_cast< const QskRadioBox* >( skinnable ); - const auto font = skinnable->effectiveFont( Q::Text ); + const auto font = skinnable->effectiveFont( Q::Text ); const auto textMargins = skinnable->marginHint( Q::Text ); const auto buttonMargins = skinnable->marginHint( Q::Button ); const auto symbolMargins = skinnable->marginHint( Q::Symbol ); qreal maxTextWidth = 0; - for(auto& item : radio->items() ) { + for( auto& item : radio->items() ) { maxTextWidth = std::max( maxTextWidth, qskHorizontalAdvance( font, item ) ); } - auto buttonWidth = radio->strutSizeHint(Q::Button).width(); - auto symbolWidth = radio->strutSizeHint(Q::Symbol).width(); + auto buttonWidth = radio->strutSizeHint( Q::Button ).width(); + auto symbolWidth = radio->strutSizeHint( Q::Symbol ).width(); maxTextWidth += textMargins.left() + textMargins.right(); buttonWidth += buttonMargins.left() + buttonMargins.right(); symbolWidth += symbolMargins.left() + symbolMargins.right(); - auto spacing = radio->spacingHint(Q::Panel); - return QSizeF( maxTextWidth + qMax(buttonWidth, symbolWidth), - ( lineHeight( radio ) + spacing ) * radio->items().size() - - spacing ); + auto spacing = radio->spacingHint( Q::Panel ); + return QSizeF( maxTextWidth + qMax( buttonWidth, symbolWidth ), + ( lineHeight( radio ) + spacing ) * radio->items().size() - spacing ); } QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, - quint8 nodeRole, QSGNode* node) const + quint8 nodeRole, QSGNode* node ) const { - auto radio = static_cast( skinnable ); + auto radio = static_cast< const QskRadioBox* >( skinnable ); switch( nodeRole ) { @@ -103,7 +102,8 @@ QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, case RippleRole: { QskSkinStateChanger changer( radio ); - changer.setStates( statesForIndex( radio, radio->positionHint( Q::Ripple ) ) ); + auto ripplePosition = radio->positionHint( Q::Ripple ); + changer.setStates( statesForIndex( radio, ripplePosition ) ); return updateBoxNode( radio, node, Q::Ripple ); } @@ -114,7 +114,7 @@ QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, qreal QskRadioBoxSkinlet::lineHeight(const QskRadioBox* target) const { auto strutHight = qMax( target->strutSizeHint( Q::Button ).height(), - target->strutSizeHint( Q::Text ).height() ); + target->strutSizeHint( Q::Text ).height() ); const auto textMargins = target->marginHint( Q::Text ); auto fontHeight = target->effectiveFontHeight( Q::Text ); fontHeight += textMargins.top() + textMargins.bottom(); @@ -122,8 +122,7 @@ qreal QskRadioBoxSkinlet::lineHeight(const QskRadioBox* target) const { return qMax( strutHight, fontHeight ); } -int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, - QskAspect::Subcontrol ) const { +int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, QskAspect::Subcontrol ) const { const auto radio = static_cast< const QskRadioBox* >( skinnable ); return radio->items().count(); } @@ -140,8 +139,7 @@ QSizeF QskRadioBoxSkinlet::buttonSymbolSize( const QskRadioBox* radio ) const { qMax( buttonStrut.height(), symbolStrut.height() ) ); } -QRectF QskRadioBoxSkinlet::rippleRect( const QskRadioBox* radio, - const QRectF& rect ) const { +QRectF QskRadioBoxSkinlet::rippleRect( const QskRadioBox* radio, const QRectF& rect ) const { auto ripplePosition = radio->positionHint( Q::Ripple ); if( ripplePosition < 0 ) { @@ -157,16 +155,15 @@ QRectF QskRadioBoxSkinlet::rippleRect( const QskRadioBox* radio, } QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, - const QskAspect::Subcontrol target, - const QRectF& rect, double index ) const { + const QskAspect::Subcontrol target, const QRectF& rect, double index ) const { if( index < 0 ) { return QRectF(); } auto result = rect; - result.setSize( radio->strutSizeHint( target )); + result.setSize( radio->strutSizeHint( target ) ); - auto spacing = radio->spacingHint(Q::Panel); + auto spacing = radio->spacingHint( Q::Panel ); result.moveTop( ( lineHeight( radio ) + spacing ) * index ); auto margins = radio->marginHint( target ); @@ -177,23 +174,23 @@ QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, // Vertical positioning auto alignHeight = maxSize.height() - withMargins.height(); - if( alignment.testFlag( Qt::AlignVCenter )) { - result.moveTop( result.top() + alignHeight / 2); + if( alignment.testFlag( Qt::AlignVCenter ) ) { + result.moveTop( result.top() + alignHeight / 2 ); } else if( alignment.testFlag( Qt::AlignBottom ) ) { result.moveTop( result.top() + alignHeight ); } - result.moveTop( result.top() + margins.top()); + result.moveTop( result.top() + margins.top() ); // Horizontal positioning auto alignWidth = 0; if( alignment.testFlag( Qt::AlignHCenter ) ) { - alignWidth = (maxSize.width() - withMargins.width()) / 2; + alignWidth = ( maxSize.width() - withMargins.width() ) / 2; } else if ( alignment.testFlag( Qt::AlignRight )) { alignWidth = maxSize.width() - withMargins.width(); } if( radio->layoutMirroring() ) { - result.moveRight( rect.width() - (alignWidth + margins.right() )); + result.moveRight( rect.width() - ( alignWidth + margins.right() ) ); } else { result.moveLeft( margins.left() + alignWidth ); } @@ -202,22 +199,22 @@ QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, } QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, - const QRectF& rect, int index ) const { - auto text = radio->items()[index]; + const QRectF& rect, int index ) const { + auto text = radio->items()[ index ]; if(text.isEmpty()) { return QRectF(); } QRectF result = rect; - auto spacing = radio->spacingHint(Q::Panel); + auto spacing = radio->spacingHint( Q::Panel ); auto lh = lineHeight( radio ); const auto textMargins = radio->marginHint( Q::Text ); const auto font = radio->effectiveFont( Q::Text ); result.moveTop( index * ( lh + spacing ) - + lh - radio->effectiveFontHeight(Q::Text) - + textMargins.top()); + + lh - radio->effectiveFontHeight( Q::Text ) + + textMargins.top()); result.setHeight( lh ); result.setWidth( qskHorizontalAdvance( font, text ) ); @@ -228,7 +225,7 @@ QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, if( radio->layoutMirroring() ) { result.moveLeft( rect.width() - textMargins.right() - - result.width() - buttonWidth); + - result.width() - buttonWidth); } else { result.moveLeft( buttonWidth + textMargins.left() ); } @@ -237,8 +234,8 @@ QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, } QRectF QskRadioBoxSkinlet::sampleRect( const QskSkinnable* skinnable, - const QRectF& rect, QskAspect::Subcontrol subcontrol, - int index ) const { + const QRectF& rect, QskAspect::Subcontrol subcontrol, int index ) const { + const auto radio = static_cast< const QskRadioBox* >( skinnable ); if( subcontrol == Q::Text ) { @@ -250,7 +247,8 @@ QRectF QskRadioBoxSkinlet::sampleRect( const QskSkinnable* skinnable, QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnable, QskAspect::Subcontrol subControl, int index ) const { - auto radio = static_cast( skinnable ); + + auto radio = static_cast< const QskRadioBox* >( skinnable ); auto states = Inherited::sampleStates( skinnable, subControl, index ); return states | statesForIndex( radio, index ); @@ -258,23 +256,17 @@ QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnabl QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, QskAspect::Subcontrol subcontrol, int index, QSGNode* node ) const { - auto radio = static_cast( skinnable ); + + auto radio = static_cast< const QskRadioBox* >( skinnable ); auto rect = sampleRect( skinnable, radio->contentsRect(), subcontrol, index ); if( subcontrol == Q::Text ) { - return QskSkinlet::updateTextNode( radio, - node, - rect, - Qt::AlignLeft, - radio->items()[index], - subcontrol); - } else if (subcontrol == Q::Button) { - return QskSkinlet::updateBoxNode( radio, - node, - rect, - subcontrol ); + return QskSkinlet::updateTextNode( radio, node, rect, Qt::AlignLeft, + radio->items()[ index ], subcontrol ); + } else if ( subcontrol == Q::Button ) { + return QskSkinlet::updateBoxNode( radio, node, rect, subcontrol ); } else if( subcontrol == Q::Symbol ) { auto symbol = QskStandardSymbol::NoSymbol; auto color = radio->color( subcontrol ).rgb(); @@ -292,7 +284,7 @@ QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, */ QskColorFilter filter; filter.addColorSubstitution( Qt::black, color ); - auto colorSub = radio->color( subcontrol | statesForIndex(radio, index) ); + auto colorSub = radio->color( subcontrol | statesForIndex( radio, index ) ); filter.addColorSubstitution( Qt::black, colorSub.rgb() ); QskGraphic::fromGraphic( graphic, filter ); diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h index 831cacca..4b0be65b 100644 --- a/src/controls/QskRadioBoxSkinlet.h +++ b/src/controls/QskRadioBoxSkinlet.h @@ -7,20 +7,20 @@ class QskRadioBox; class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet { - Q_GADGET + Q_GADGET using Inherited = QskSkinlet; - public: - enum NodeRole + public: + enum NodeRole { - PanelRole, - ButtonRole, - SymbolRole, - TextRole, - RippleRole, + PanelRole, + ButtonRole, + SymbolRole, + TextRole, + RippleRole, - RoleCount + RoleCount }; Q_INVOKABLE QskRadioBoxSkinlet( QskSkin* = nullptr ); @@ -39,13 +39,14 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet QSizeF buttonSymbolSize( const QskRadioBox* radio ) const; QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; - QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, double ) const; + QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, + double ) const; QRectF rippleRect( const QskRadioBox*, const QRectF& ) const; QskAspect::States sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int index ) const override; - + protected: QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; From 90fec17a608a84009938c2757d64b5cb80f0050a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 26 Feb 2023 15:03:44 +0100 Subject: [PATCH 22/25] QskRgb::RGBAMask added --- src/common/QskRgbValue.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/QskRgbValue.h b/src/common/QskRgbValue.h index 2ff1b55e..17e78333 100644 --- a/src/common/QskRgbValue.h +++ b/src/common/QskRgbValue.h @@ -169,6 +169,7 @@ namespace QskRgb constexpr const QRgb Transparent = 0x00000000; constexpr const QRgb AlphaMask = 0xff000000; constexpr const QRgb ColorMask = 0x00ffffff; + constexpr const QRgb RGBAMask = 0xffffffff; } namespace QskRgb From 6618c914797cdeb8b0e1c84f5a6759d1eab0efb8 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 26 Feb 2023 15:07:08 +0100 Subject: [PATCH 23/25] QskColorFilter::mask --- skins/material3/QskMaterial3Skin.cpp | 56 +++++++++------------------- skins/material3/QskMaterial3Skin.h | 1 + src/graphic/QskColorFilter.cpp | 44 ++++++++-------------- src/graphic/QskColorFilter.h | 24 ++++++++++-- 4 files changed, 53 insertions(+), 72 deletions(-) diff --git a/skins/material3/QskMaterial3Skin.cpp b/skins/material3/QskMaterial3Skin.cpp index da94592e..5069c24b 100644 --- a/skins/material3/QskMaterial3Skin.cpp +++ b/skins/material3/QskMaterial3Skin.cpp @@ -1336,47 +1336,25 @@ void QskMaterial3Skin::setupFonts() setFont( M3LabelLarge, createFont( "Roboto Medium", 20_dp, 14_dp, 0.1, QFont::Medium ) ); } +void QskMaterial3Skin::setGraphicColor( GraphicRole role, QRgb rgb ) +{ + QskColorFilter colorFilter; + colorFilter.setMask( QskRgb::RGBAMask ); + colorFilter.addColorSubstitution( QskRgb::White, rgb ); + + setGraphicFilter( role, colorFilter ); +} + void QskMaterial3Skin::setupGraphicFilters( const QskMaterial3Theme& palette ) { - QskColorFilter onPrimaryFilter; - onPrimaryFilter.setSubstituteAlphaValue( true ); - onPrimaryFilter.addColorSubstitution( Qt::white, palette.onPrimary ); - setGraphicFilter( GraphicRoleOnPrimary, onPrimaryFilter ); - - QskColorFilter onSecondaryContainerFilter; - onSecondaryContainerFilter.setSubstituteAlphaValue( true ); - onSecondaryContainerFilter.addColorSubstitution( Qt::white, palette.onSecondaryContainer ); - setGraphicFilter( GraphicRoleOnSecondaryContainer, onSecondaryContainerFilter ); - - QskColorFilter onErrorFilter; - onErrorFilter.setSubstituteAlphaValue( true ); - onErrorFilter.addColorSubstitution( Qt::white, palette.onError ); - setGraphicFilter( GraphicRoleOnError, onErrorFilter ); - - QskColorFilter onSurfaceFilter; - onSurfaceFilter.setSubstituteAlphaValue( true ); - onSurfaceFilter.addColorSubstitution( Qt::white, palette.onSurface ); - setGraphicFilter( GraphicRoleOnSurface, onSurfaceFilter ); - - QskColorFilter onSurfaceFilter38; - onSurfaceFilter38.setSubstituteAlphaValue( true ); - onSurfaceFilter38.addColorSubstitution( Qt::white, palette.onSurface38 ); - setGraphicFilter( GraphicRoleOnSurface38, onSurfaceFilter38 ); - - QskColorFilter onSurfaceVariantFilter; - onSurfaceVariantFilter.setSubstituteAlphaValue( true ); - onSurfaceVariantFilter.addColorSubstitution( Qt::white, palette.onSurfaceVariant ); - setGraphicFilter( GraphicRoleOnSurfaceVariant, onSurfaceVariantFilter ); - - QskColorFilter primaryFilter; - primaryFilter.setSubstituteAlphaValue( true ); - primaryFilter.addColorSubstitution( Qt::white, palette.primary ); - setGraphicFilter( GraphicRolePrimary, primaryFilter ); - - QskColorFilter surfaceFilter; - surfaceFilter.setSubstituteAlphaValue( true ); - surfaceFilter.addColorSubstitution( Qt::white, palette.surface ); - setGraphicFilter( GraphicRoleSurface, surfaceFilter ); + setGraphicColor( GraphicRoleOnPrimary, palette.onPrimary ); + setGraphicColor( GraphicRoleOnSecondaryContainer, palette.onSecondaryContainer ); + setGraphicColor( GraphicRoleOnError, palette.onError ); + setGraphicColor( GraphicRoleOnSurface, palette.onSurface ); + setGraphicColor( GraphicRoleOnSurface38, palette.onSurface38 ); + setGraphicColor( GraphicRoleOnSurfaceVariant, palette.onSurfaceVariant ); + setGraphicColor( GraphicRolePrimary, palette.primary ); + setGraphicColor( GraphicRoleSurface, palette.surface ); } #include "moc_QskMaterial3Skin.cpp" diff --git a/skins/material3/QskMaterial3Skin.h b/skins/material3/QskMaterial3Skin.h index b41684a9..221eb538 100644 --- a/skins/material3/QskMaterial3Skin.h +++ b/skins/material3/QskMaterial3Skin.h @@ -157,6 +157,7 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin private: void setupFonts(); void setupGraphicFilters( const QskMaterial3Theme& palette ); + void setGraphicColor( GraphicRole, QRgb ); }; #endif diff --git a/src/graphic/QskColorFilter.cpp b/src/graphic/QskColorFilter.cpp index ab931545..c6f1dc73 100644 --- a/src/graphic/QskColorFilter.cpp +++ b/src/graphic/QskColorFilter.cpp @@ -11,35 +11,31 @@ #include static inline QRgb qskSubstitutedRgb( - const QVector< QPair< QRgb, QRgb > >& substitions, QRgb rgba, bool substituteAlpha ) + const QVector< QPair< QRgb, QRgb > >& substitions, QRgb rgba, QRgb mask ) { // usually we have 2-3 substitutions, so we can simply iterate // and don't need to introduce some sort of sorting or search index - const QRgb rgb = substituteAlpha ? rgba : ( rgba | QskRgb::AlphaMask ); + const QRgb rgb = rgba | ~mask; for ( const auto& s : substitions ) { - if ( rgb == s.first ) - { - const auto ret = substituteAlpha ? s.second - : ( s.second & QskRgb::ColorMask ) - | ( rgba & QskRgb::AlphaMask ); - return ret; - } + if ( rgb == ( s.first | ~mask ) ) + return ( s.second & mask ) | ( rgba & ~mask ); } return rgba; } static inline QColor qskSubstitutedColor( - const QVector< QPair< QRgb, QRgb > >& substitions, const QColor& color, bool substituteAlpha ) + const QVector< QPair< QRgb, QRgb > >& substitions, + const QColor& color, QRgb mask ) { - return QColor::fromRgba( qskSubstitutedRgb( substitions, color.rgba(), substituteAlpha ) ); + return QColor::fromRgba( qskSubstitutedRgb( substitions, color.rgba(), mask ) ); } static inline QBrush qskSubstitutedBrush( - const QVector< QPair< QRgb, QRgb > >& substitions, const QBrush& brush, bool substituteAlpha ) + const QVector< QPair< QRgb, QRgb > >& substitions, const QBrush& brush, QRgb mask ) { QBrush newBrush; @@ -50,7 +46,7 @@ static inline QBrush qskSubstitutedBrush( auto stops = gradient->stops(); for ( auto& stop : stops ) { - const QColor c = qskSubstitutedColor( substitions, stop.second, substituteAlpha ); + const QColor c = qskSubstitutedColor( substitions, stop.second, mask ); if ( c != stop.second ) { stop.second = c; @@ -68,7 +64,7 @@ static inline QBrush qskSubstitutedBrush( } else { - const QColor c = qskSubstitutedColor( substitions, brush.color(), substituteAlpha ); + const QColor c = qskSubstitutedColor( substitions, brush.color(), mask ); if ( c != brush.color() ) { newBrush = brush; @@ -168,7 +164,7 @@ QPen QskColorFilter::substituted( const QPen& pen ) const if ( m_substitutions.isEmpty() || pen.style() == Qt::NoPen ) return pen; - const auto newBrush = qskSubstitutedBrush( m_substitutions, pen.brush(), m_substituteAlphaValue ); + const auto newBrush = qskSubstitutedBrush( m_substitutions, pen.brush(), m_mask ); if ( newBrush.style() == Qt::NoBrush ) return pen; @@ -182,28 +178,18 @@ QBrush QskColorFilter::substituted( const QBrush& brush ) const if ( m_substitutions.isEmpty() || brush.style() == Qt::NoBrush ) return brush; - const auto newBrush = qskSubstitutedBrush( m_substitutions, brush, m_substituteAlphaValue ); + const auto newBrush = qskSubstitutedBrush( m_substitutions, brush, m_mask ); return ( newBrush.style() != Qt::NoBrush ) ? newBrush : brush; } QColor QskColorFilter::substituted( const QColor& color ) const { - return qskSubstitutedColor( m_substitutions, color, m_substituteAlphaValue ); + return qskSubstitutedColor( m_substitutions, color, m_mask ); } QRgb QskColorFilter::substituted( const QRgb& rgb ) const { - return qskSubstitutedRgb( m_substitutions, rgb, m_substituteAlphaValue ); -} - -bool QskColorFilter::substituteAlphaValue() const noexcept -{ - return m_substituteAlphaValue; -} - -void QskColorFilter::setSubstituteAlphaValue( bool on ) -{ - m_substituteAlphaValue = on; + return qskSubstitutedRgb( m_substitutions, rgb, m_mask ); } QskColorFilter QskColorFilter::interpolated( @@ -227,7 +213,7 @@ QDebug operator<<( QDebug debug, const QskColorFilter& filter ) QDebugStateSaver saver( debug ); debug.nospace(); - debug << "Filter" << '('; + debug << "Filter" << '[' << filter.mask() << ']' << '('; for ( const auto& s : filter.substitutions() ) debug << '[' << s.first << "->" << s.second << "]"; debug << ')'; diff --git a/src/graphic/QskColorFilter.h b/src/graphic/QskColorFilter.h index dedac055..f4553fcd 100644 --- a/src/graphic/QskColorFilter.h +++ b/src/graphic/QskColorFilter.h @@ -20,7 +20,7 @@ class QVariant; class QSK_EXPORT QskColorFilter { public: - QskColorFilter() noexcept = default; + QskColorFilter( QRgb mask = 0x00ffffff ) noexcept; void addColorSubstitution( QRgb from, QRgb to ); void addColorSubstitution( Qt::GlobalColor, QRgb ); @@ -37,8 +37,9 @@ class QSK_EXPORT QskColorFilter bool isIdentity() const noexcept; - bool substituteAlphaValue() const noexcept; - void setSubstituteAlphaValue( bool ); + // the bits to be replaced + QRgb mask() const noexcept; + void setMask( QRgb ) noexcept; bool operator==( const QskColorFilter& other ) const noexcept; bool operator!=( const QskColorFilter& other ) const noexcept; @@ -53,10 +54,15 @@ class QSK_EXPORT QskColorFilter const QskColorFilter&, const QskColorFilter&, qreal progress ); private: + QRgb m_mask; QVector< QPair< QRgb, QRgb > > m_substitutions; - bool m_substituteAlphaValue = false; }; +inline QskColorFilter::QskColorFilter( QRgb mask ) noexcept + : m_mask( mask ) +{ +} + inline bool QskColorFilter::isIdentity() const noexcept { return m_substitutions.isEmpty(); @@ -97,6 +103,16 @@ inline void QskColorFilter::addColorSubstitution( addColorSubstitution( QColor( from ).rgb(), QColor( to ).rgb() ); } +inline void QskColorFilter::setMask( QRgb mask ) noexcept +{ + m_mask = mask; +} + +inline QRgb QskColorFilter::mask() const noexcept +{ + return m_mask; +} + Q_DECLARE_METATYPE( QskColorFilter ) #ifndef QT_NO_DEBUG_STREAM From c4efbf65f022fe02b7a93cdd1a0fdedc6c37b726 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 26 Feb 2023 15:45:57 +0100 Subject: [PATCH 24/25] compiler warning fixed --- examples/gallery/button/ButtonPage.cpp | 1 + src/controls/QskRadioBoxSkinlet.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp index a952ee36..a80b79c0 100644 --- a/examples/gallery/button/ButtonPage.cpp +++ b/examples/gallery/button/ButtonPage.cpp @@ -155,6 +155,7 @@ namespace auto button3 = new QskCheckBox( "Error", this ); button3->setSkinStateFlag( QskCheckBox::Error ); + new QskRadioBox( { "One", "Two", "Three" }, this ); auto radios = new QskRadioBox( { "One", "Two", "Three" }, this ); radios->setLayoutMirroring(true); diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 41923fe3..337f00ce 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -12,7 +12,7 @@ namespace { using Q = QskRadioBox; -}; +} QskRadioBoxSkinlet::QskRadioBoxSkinlet( QskSkin* ) { From 2e667f3ff2780527bb3e3f4589d0fa722994fb9c Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Sun, 26 Feb 2023 17:04:47 +0100 Subject: [PATCH 25/25] formal adjustments --- examples/gallery/button/ButtonPage.cpp | 25 +- examples/gallery/dialog/DialogPage.cpp | 38 +-- examples/gallery/selector/SelectorPage.cpp | 2 +- src/controls/QskRadioBox.cpp | 274 ++++++++------- src/controls/QskRadioBox.h | 24 +- src/controls/QskRadioBoxSkinlet.cpp | 367 +++++++++++---------- src/controls/QskRadioBoxSkinlet.h | 20 +- 7 files changed, 412 insertions(+), 338 deletions(-) diff --git a/examples/gallery/button/ButtonPage.cpp b/examples/gallery/button/ButtonPage.cpp index a80b79c0..b62865ce 100644 --- a/examples/gallery/button/ButtonPage.cpp +++ b/examples/gallery/button/ButtonPage.cpp @@ -119,6 +119,8 @@ namespace : QskLinearBox( Qt::Horizontal, parent ) { setSpacing( 20 ); + setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed ); + setExtraSpacingAt( Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge ); for ( auto orientation : { Qt::Vertical, Qt::Horizontal } ) @@ -144,7 +146,7 @@ namespace CheckButtonBox( QQuickItem* parent = nullptr ) : QskLinearBox( Qt::Horizontal, 2, parent ) { - setSpacing( 40 ); + setSpacing( 20 ); setExtraSpacingAt( Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge ); auto button1 = new QskCheckBox( "Options 1", this ); @@ -155,10 +157,22 @@ namespace auto button3 = new QskCheckBox( "Error", this ); button3->setSkinStateFlag( QskCheckBox::Error ); + } + }; + + class RadioButtonBox : public QskLinearBox + { + public: + RadioButtonBox( QQuickItem* parent = nullptr ) + : QskLinearBox( Qt::Horizontal, parent ) + { + setSpacing( 20 ); + setExtraSpacingAt( Qt::LeftEdge | Qt::RightEdge | Qt::BottomEdge ); new QskRadioBox( { "One", "Two", "Three" }, this ); - auto radios = new QskRadioBox( { "One", "Two", "Three" }, this ); - radios->setLayoutMirroring(true); + + auto radioBox = new QskRadioBox( { "One", "Two", "Three" }, this ); + radioBox->setLayoutMirroring( true ); } }; } @@ -176,5 +190,8 @@ void ButtonPage::populate() new QskSeparator( Qt::Horizontal, this ); new SwitchButtonBox( this ); new QskSeparator( Qt::Horizontal, this ); - new CheckButtonBox( this ); + + auto hBox = new QskLinearBox( Qt::Horizontal, this ); + new CheckButtonBox( hBox ); + new RadioButtonBox( hBox ); } diff --git a/examples/gallery/dialog/DialogPage.cpp b/examples/gallery/dialog/DialogPage.cpp index 8bd36eb5..46f750d5 100644 --- a/examples/gallery/dialog/DialogPage.cpp +++ b/examples/gallery/dialog/DialogPage.cpp @@ -14,51 +14,39 @@ namespace { class Box : public QskGridBox { - public: + public: Box( QQuickItem* parent ) : QskGridBox( parent ) { auto* messageButton = new QskPushButton( "message", this ); - connect( messageButton, &QskPushButton::clicked, this, []() - { - qskDialog->message( "message", "text", QskStandardSymbol::Ok ); - } ); + connect( messageButton, &QskPushButton::clicked, this, + []() { qskDialog->message( "message", "text", QskStandardSymbol::Ok ); } ); auto* informationButton = new QskPushButton( "information", this ); - connect( informationButton, &QskPushButton::clicked, this, []() - { - qskDialog->information( "information", "text" ); - } ); + connect( informationButton, &QskPushButton::clicked, this, + []() { qskDialog->information( "information", "text" ); } ); auto* warningButton = new QskPushButton( "warning", this ); - connect( warningButton, &QskPushButton::clicked, this, []() - { - qskDialog->warning( "warning", "text" ); - } ); + connect( warningButton, &QskPushButton::clicked, this, + []() { qskDialog->warning( "warning", "text" ); } ); auto* criticalButton = new QskPushButton( "critical", this ); - connect( criticalButton, &QskPushButton::clicked, this, []() - { - qskDialog->critical( "critical", "text" ); - } ); + connect( criticalButton, &QskPushButton::clicked, this, + []() { qskDialog->critical( "critical", "text" ); } ); auto* questionButton = new QskPushButton( "question", this ); - connect( questionButton, &QskPushButton::clicked, this, []() - { - qskDialog->question( "question", "text" ); - } ); + connect( questionButton, &QskPushButton::clicked, this, + []() { qskDialog->question( "question", "text" ); } ); auto* selectButton = new QskPushButton( "select", this ); - connect( selectButton, &QskPushButton::clicked, this, []() - { - qskDialog->select( "select", "text", { "yes", "no", "maybe" } ); - } ); + connect( selectButton, &QskPushButton::clicked, this, + []() { qskDialog->select( "select", "text", { "yes", "no", "maybe" } ); } ); addItem( messageButton, 0, 0 ); addItem( informationButton, 0, 1 ); diff --git a/examples/gallery/selector/SelectorPage.cpp b/examples/gallery/selector/SelectorPage.cpp index d617641e..974a0c5d 100644 --- a/examples/gallery/selector/SelectorPage.cpp +++ b/examples/gallery/selector/SelectorPage.cpp @@ -32,7 +32,7 @@ namespace { auto bar = new QskSegmentedBar( orientation, this ); - for ( const auto text: texts ) + for ( const auto text : texts ) bar->addOption( {}, text ); } diff --git a/src/controls/QskRadioBox.cpp b/src/controls/QskRadioBox.cpp index 3ba7f174..e87835fa 100644 --- a/src/controls/QskRadioBox.cpp +++ b/src/controls/QskRadioBox.cpp @@ -1,3 +1,8 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + #include "QskRadioBox.h" #include "QskEvent.h" #include "QskAnimationHint.h" @@ -13,175 +18,194 @@ QSK_STATE( QskRadioBox, Selected, QskAspect::FirstUserState << 1 ) QSK_STATE( QskRadioBox, Pressed, QskAspect::FirstUserState << 2 ) QSK_STATE( QskRadioBox, Focused, QskAspect::FirstUserState << 3 ) -class QskRadioBox::PrivateData { -public: +class QskRadioBox::PrivateData +{ + public: QStringList items; + int selectedIndex = -1; int focusedIndex = -1; int pressedIndex = -1; }; -QskRadioBox::QskRadioBox( QQuickItem* parent ) : - Inherited( parent ), - m_data( new PrivateData{} ) { +QskRadioBox::QskRadioBox( QQuickItem* parent ) + : Inherited( parent ) + , m_data( new PrivateData() ) +{ setFocusPolicy( Qt::NoFocus ); setAcceptedMouseButtons( Qt::LeftButton ); connect(this, &QskRadioBox::itemsChanged, this, - [this]( const QStringList& items ) { - if( items.count() > 0 ) { - setFocusPolicy( Qt::StrongFocus ); - } else { - setFocusPolicy( Qt::NoFocus ); - } - }); + [this]( const QStringList& items ) + { + setFocusPolicy( items.count() > 0 ? Qt::StrongFocus : Qt::NoFocus ); + } + ); setFocusedIndex( -1 ); } -QskRadioBox::QskRadioBox( const QStringList& list, QQuickItem* parent ) : - QskRadioBox( parent ) { +QskRadioBox::QskRadioBox( const QStringList& list, QQuickItem* parent ) + : QskRadioBox( parent ) +{ setItems( list ); } QskRadioBox::QskRadioBox( const QStringList& items, - int selectedIndex, QQuickItem* parent ) : - QskRadioBox( items, parent ) { + int selectedIndex, QQuickItem* parent ) + : QskRadioBox( items, parent ) +{ if( selectedIndex >= 0 && selectedIndex < items.count() ) - { - m_data->selectedIndex = selectedIndex; - } + m_data->selectedIndex = selectedIndex; } -QRectF QskRadioBox::focusIndicatorRect() const { - if( m_data->focusedIndex > -1) { - auto textRect = effectiveSkinlet()->sampleRect( this, - contentsRect(), QskRadioBox::Text, m_data->focusedIndex ); +QskRadioBox::~QskRadioBox() +{ +} - auto buttonRect = effectiveSkinlet()->sampleRect( this, - contentsRect(), QskRadioBox::Button, m_data->focusedIndex ); +QRectF QskRadioBox::focusIndicatorRect() const +{ + if( m_data->focusedIndex > -1) + { + auto skinlet = effectiveSkinlet(); - if( textRect == QRectF() ) { - return buttonRect; - } - - auto result = QRectF( - qMin( textRect.x(), buttonRect.x() ), + auto textRect = skinlet->sampleRect( this, + contentsRect(), QskRadioBox::Text, m_data->focusedIndex ); + + auto buttonRect = skinlet->sampleRect( this, + contentsRect(), QskRadioBox::Button, m_data->focusedIndex ); + + if( textRect == QRectF() ) + return buttonRect; + + auto result = QRectF( + qMin( textRect.x(), buttonRect.x() ), qMin( textRect.y(), buttonRect.y() ), buttonRect.width() + textRect.width(), - qMax( buttonRect.height(), textRect.height() )); + qMax( buttonRect.height(), textRect.height() ) ); - if( layoutMirroring() ) { - result.setWidth( - result.width() + marginHint( Text ).right() - + marginHint( Button ).left() ); - } else { - result.setWidth( - result.width() + marginHint( Text ).left() - + marginHint( Button ).right() ); - } + if( layoutMirroring() ) + { + result.setWidth( + result.width() + marginHint( Text ).right() + + marginHint( Button ).left() ); + } + else + { + result.setWidth( + result.width() + marginHint( Text ).left() + + marginHint( Button ).right() ); + } - return result; + return result; } return QRectF(); } -int QskRadioBox::selectedIndex() const { +int QskRadioBox::selectedIndex() const +{ return m_data->selectedIndex; } -const QStringList& QskRadioBox::items() const { +const QStringList& QskRadioBox::items() const +{ return m_data->items; } -int QskRadioBox::pressedIndex() const { +int QskRadioBox::pressedIndex() const +{ return m_data->pressedIndex; } -void QskRadioBox::setSelectedIndex( int index ) { - if( index == m_data->selectedIndex - || index >= m_data->items.count() ) { - return; - } +void QskRadioBox::setSelectedIndex( int index ) +{ + if( index == m_data->selectedIndex || index >= m_data->items.count() ) + return; + + if( index < 0 ) + m_data->selectedIndex = -1; + else + m_data->selectedIndex = index; - if( index < 0 ) { - m_data->selectedIndex = -1; - } else { - m_data->selectedIndex = index; - } - selectedIndexChanged( m_data->selectedIndex ); } -void QskRadioBox::setItems( const QStringList& items ){ - if( m_data->items == items ) { - return; - } +void QskRadioBox::setItems( const QStringList& items ) +{ + if( m_data->items == items ) + return; m_data->items = items; + itemsChanged( items ); setSelectedIndex( m_data->selectedIndex ); - if( m_data->focusedIndex > items.size() ) { - setFocusedIndex( 0 ); - } + if( m_data->focusedIndex > items.size() ) + setFocusedIndex( 0 ); } void QskRadioBox::keyPressEvent( QKeyEvent* event ) { switch ( event->key() ) { - case Qt::Key_Up: - case Qt::Key_Left: - m_data->selectedIndex = qMax( m_data->selectedIndex - 1, 0 ); - setFocusedIndex( m_data->selectedIndex ); - event->setAccepted( true ); - update(); - return; - case Qt::Key_Down: - case Qt::Key_Right: - m_data->selectedIndex = qMin( m_data->selectedIndex + 1, - items().size() - 1 ); - setFocusedIndex( m_data->selectedIndex ); - event->setAccepted( true ); - update(); - return; - case Qt::Key_Select: - case Qt::Key_Return: - case Qt::Key_Space: - m_data->selectedIndex = m_data->focusedIndex; - event->setAccepted( true ); - update(); - return; + case Qt::Key_Up: + case Qt::Key_Left: + { + m_data->selectedIndex = qMax( m_data->selectedIndex - 1, 0 ); + setFocusedIndex( m_data->selectedIndex ); + update(); + + return; + } + case Qt::Key_Down: + case Qt::Key_Right: + { + m_data->selectedIndex = qMin( m_data->selectedIndex + 1, + items().size() - 1 ); + setFocusedIndex( m_data->selectedIndex ); + update(); + + return; + } + case Qt::Key_Select: + case Qt::Key_Return: + case Qt::Key_Space: + { + m_data->selectedIndex = m_data->focusedIndex; + update(); + + return; + } } - auto currentTabIndex = m_data->focusedIndex; - auto nextTabIndex = currentTabIndex + qskFocusChainIncrement( event ); - if( nextTabIndex >= items().size() - || nextTabIndex < 0 ) { - Inherited::keyPressEvent( event ); - setFocusedIndex( -1 ); - update(); - } else { - event->setAccepted( true ); + const auto currentTabIndex = m_data->focusedIndex; + const auto nextTabIndex = currentTabIndex + qskFocusChainIncrement( event ); + + if( nextTabIndex >= items().size() || nextTabIndex < 0 ) + { + Inherited::keyPressEvent( event ); + setFocusedIndex( -1 ); + } + else + { setFocusedIndex( ( float ) nextTabIndex ); - const auto aspect = Ripple | QskAspect::Metric | QskAspect::Position; - auto hint = animationHint(aspect | skinStates()); - if( hint.isValid()) { - startTransition( aspect, hint, - ( float ) currentTabIndex, ( float ) nextTabIndex ); - } - - update(); + const auto aspect = Ripple | QskAspect::Metric | QskAspect::Position; + const auto hint = animationHint( aspect | skinStates() ); + if( hint.isValid() ) + { + startTransition( aspect, hint, + ( float ) currentTabIndex, ( float ) nextTabIndex ); + } } + + update(); } -void QskRadioBox::keyReleaseEvent( QKeyEvent* e ) +void QskRadioBox::keyReleaseEvent( QKeyEvent* ) { - e->setAccepted( true ); } void QskRadioBox::mousePressEvent( QMouseEvent* e ) @@ -192,52 +216,54 @@ void QskRadioBox::mousePressEvent( QMouseEvent* e ) m_data->selectedIndex = -1; setFocusedIndex( indexAtPosition ); - - e->setAccepted( true ); update(); } void QskRadioBox::mouseReleaseEvent( QMouseEvent* e ) { - auto index = indexAt( e->localPos() ); - if( index == m_data->pressedIndex ) { - setSelectedIndex( index ); - } + const auto index = indexAt( e->localPos() ); + if( index == m_data->pressedIndex ) + setSelectedIndex( index ); - e->setAccepted( true ); update(); } -void QskRadioBox::focusInEvent( QFocusEvent* e ) { - if( e->reason() == Qt::TabFocusReason ) { - setFocusedIndex(0 ); - } else if( e->reason() == Qt::BacktabFocusReason ) { - setFocusedIndex( items().size() - 1 ); +void QskRadioBox::focusInEvent( QFocusEvent* e ) +{ + if( e->reason() == Qt::TabFocusReason ) + { + setFocusedIndex( 0 ); + } + else if( e->reason() == Qt::BacktabFocusReason ) + { + setFocusedIndex( items().size() - 1 ); } update(); Inherited::focusInEvent( e ); } -void QskRadioBox::focusOutEvent( QFocusEvent* e ) { +void QskRadioBox::focusOutEvent( QFocusEvent* e ) +{ setFocusedIndex( -1 ); update(); - + Inherited::focusOutEvent( e ); } -int QskRadioBox::indexAt( const QPointF& target ) const { - auto itemHeight = contentsRect().height() / items().size(); +int QskRadioBox::indexAt( const QPointF& target ) const +{ + const auto itemHeight = contentsRect().height() / items().size(); auto index = target.y() / itemHeight; - if( index < 0 || index >= items().size() ) { - return -1; - } + if( index < 0 || index >= items().size() ) + return -1; return index; } -void QskRadioBox::setFocusedIndex( int index ) { +void QskRadioBox::setFocusedIndex( int index ) +{ m_data->focusedIndex = index; setPositionHint( Ripple, index ); focusIndicatorRectChanged(); diff --git a/src/controls/QskRadioBox.h b/src/controls/QskRadioBox.h index de96be13..c510bb96 100644 --- a/src/controls/QskRadioBox.h +++ b/src/controls/QskRadioBox.h @@ -1,23 +1,23 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + #ifndef QSK_RADIO_BOX_H #define QSK_RADIO_BOX_H #include "QskControl.h" - -#include +#include class QSK_EXPORT QskRadioBox : public QskControl { Q_OBJECT - Q_PROPERTY( int selectedIndex - READ selectedIndex - WRITE setSelectedIndex - NOTIFY selectedIndexChanged FINAL ) + Q_PROPERTY( int selectedIndex READ selectedIndex + WRITE setSelectedIndex NOTIFY selectedIndexChanged FINAL ) - Q_PROPERTY( QStringList items - READ items - WRITE setItems - NOTIFY itemsChanged FINAL ) + Q_PROPERTY( QStringList items READ items + WRITE setItems NOTIFY itemsChanged FINAL ) using Inherited = QskControl; @@ -29,9 +29,12 @@ class QSK_EXPORT QskRadioBox : public QskControl QskRadioBox( const QStringList&, QQuickItem* parent = nullptr ); QskRadioBox( const QStringList&, int, QQuickItem* parent = nullptr ); + ~QskRadioBox() override; + QRectF focusIndicatorRect() const override; const QStringList& items() const; + int selectedIndex() const; int pressedIndex() const; @@ -57,6 +60,7 @@ class QSK_EXPORT QskRadioBox : public QskControl private: void setFocusedIndex( int index ); + class PrivateData; std::unique_ptr< PrivateData > m_data; }; diff --git a/src/controls/QskRadioBoxSkinlet.cpp b/src/controls/QskRadioBoxSkinlet.cpp index 337f00ce..13cff7e0 100644 --- a/src/controls/QskRadioBoxSkinlet.cpp +++ b/src/controls/QskRadioBoxSkinlet.cpp @@ -1,3 +1,8 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + #include "QskRadioBoxSkinlet.h" #include "QskAspect.h" @@ -10,8 +15,42 @@ #include "QskFunctions.h" #include "QskSkin.h" -namespace { - using Q = QskRadioBox; +#include + +namespace +{ + QskAspect::States statesForIndex( const QskRadioBox* radioBox, int index ) + { + using Q = QskRadioBox; + + auto states = radioBox->skinStates(); + + if( radioBox->selectedIndex() == index ) + states |= Q::Selected; + + if( radioBox->pressedIndex() == index ) + states |= Q::Pressed; + + if( radioBox->positionHint( Q::Ripple ) == index ) + states |= Q::Focused; + + return states; + } + + qreal lineHeight( const QskRadioBox* radioBox ) + { + using Q = QskRadioBox; + + auto strutHight = qMax( radioBox->strutSizeHint( Q::Button ).height(), + radioBox->strutSizeHint( Q::Text ).height() ); + + const auto textMargins = radioBox->marginHint( Q::Text ); + + auto fontHeight = radioBox->effectiveFontHeight( Q::Text ); + fontHeight += textMargins.top() + textMargins.bottom(); + + return qMax( strutHight, fontHeight ); + } } QskRadioBoxSkinlet::QskRadioBoxSkinlet( QskSkin* ) @@ -23,32 +62,13 @@ QskRadioBoxSkinlet::~QskRadioBoxSkinlet() { } -QskAspect::States statesForIndex( const QskRadioBox* radio, int index ) { - auto states = radio->skinStates(); - - if( radio->selectedIndex() == index ) { - states |= Q::Selected; - } - - if( radio->pressedIndex() == index ) { - states |= Q::Pressed; - } - - if( radio->positionHint( Q::Ripple ) == index ) { - states |= Q::Focused; - } - - return states; -} - QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subcontrol ) const { - auto radio = static_cast< const QskRadioBox* >( skinnable ); + auto radioBox = static_cast< const QskRadioBox* >( skinnable ); - if( subcontrol == Q::Ripple ) { - return rippleRect( radio, contentsRect ); - } + if( subcontrol == QskRadioBox::Ripple ) + return rippleRect( radioBox, contentsRect ); return contentsRect; } @@ -56,240 +76,255 @@ QRectF QskRadioBoxSkinlet::subControlRect( const QskSkinnable* skinnable, QSizeF QskRadioBoxSkinlet::sizeHint( const QskSkinnable* skinnable, Qt::SizeHint, const QSizeF& ) const { - auto radio = static_cast< const QskRadioBox* >( skinnable ); + using Q = QskRadioBox; + + auto radioBox = static_cast< const QskRadioBox* >( skinnable ); const auto font = skinnable->effectiveFont( Q::Text ); const auto textMargins = skinnable->marginHint( Q::Text ); const auto buttonMargins = skinnable->marginHint( Q::Button ); const auto symbolMargins = skinnable->marginHint( Q::Symbol ); - - qreal maxTextWidth = 0; - for( auto& item : radio->items() ) { - maxTextWidth = std::max( maxTextWidth, qskHorizontalAdvance( font, item ) ); - } - auto buttonWidth = radio->strutSizeHint( Q::Button ).width(); - auto symbolWidth = radio->strutSizeHint( Q::Symbol ).width(); + qreal maxTextWidth = 0; + for( const auto& item : radioBox->items() ) + maxTextWidth = std::max( maxTextWidth, qskHorizontalAdvance( font, item ) ); + + auto buttonWidth = radioBox->strutSizeHint( Q::Button ).width(); + auto symbolWidth = radioBox->strutSizeHint( Q::Symbol ).width(); maxTextWidth += textMargins.left() + textMargins.right(); buttonWidth += buttonMargins.left() + buttonMargins.right(); symbolWidth += symbolMargins.left() + symbolMargins.right(); - auto spacing = radio->spacingHint( Q::Panel ); + auto spacing = radioBox->spacingHint( Q::Panel ); return QSizeF( maxTextWidth + qMax( buttonWidth, symbolWidth ), - ( lineHeight( radio ) + spacing ) * radio->items().size() - spacing ); -} + ( lineHeight( radioBox ) + spacing ) * radioBox->items().size() - spacing ); +} QSGNode* QskRadioBoxSkinlet::updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const { - auto radio = static_cast< const QskRadioBox* >( skinnable ); + using Q = QskRadioBox; switch( nodeRole ) { case PanelRole: - return updateBoxNode( skinnable, node, Q::Panel ); + return updateBoxNode( skinnable, node, Q::Panel ); case ButtonRole: - return updateSeriesNode( radio, Q::Button, node ); + return updateSeriesNode( skinnable, Q::Button, node ); case SymbolRole: - return updateSeriesNode( radio, Q::Symbol, node ); - + return updateSeriesNode( skinnable, Q::Symbol, node ); + case TextRole: - return updateSeriesNode( radio, Q::Text, node ); + return updateSeriesNode( skinnable, Q::Text, node ); case RippleRole: - { - QskSkinStateChanger changer( radio ); - auto ripplePosition = radio->positionHint( Q::Ripple ); - changer.setStates( statesForIndex( radio, ripplePosition ) ); + { + auto radioBox = static_cast< const QskRadioBox* >( skinnable ); - return updateBoxNode( radio, node, Q::Ripple ); - } + QskSkinStateChanger changer( radioBox ); + auto ripplePosition = radioBox->positionHint( Q::Ripple ); + changer.setStates( statesForIndex( radioBox, ripplePosition ) ); + + return updateBoxNode( radioBox, node, Q::Ripple ); + } }; return Inherited::updateSubNode( skinnable, nodeRole, node ); } -qreal QskRadioBoxSkinlet::lineHeight(const QskRadioBox* target) const { - auto strutHight = qMax( target->strutSizeHint( Q::Button ).height(), - target->strutSizeHint( Q::Text ).height() ); - const auto textMargins = target->marginHint( Q::Text ); - auto fontHeight = target->effectiveFontHeight( Q::Text ); - fontHeight += textMargins.top() + textMargins.bottom(); - - return qMax( strutHight, fontHeight ); +int QskRadioBoxSkinlet::sampleCount( + const QskSkinnable* skinnable, QskAspect::Subcontrol ) const +{ + const auto radioBox = static_cast< const QskRadioBox* >( skinnable ); + return radioBox->items().count(); } -int QskRadioBoxSkinlet::sampleCount( const QskSkinnable* skinnable, QskAspect::Subcontrol ) const { - const auto radio = static_cast< const QskRadioBox* >( skinnable ); - return radio->items().count(); -} +QSizeF QskRadioBoxSkinlet::buttonSymbolSize( const QskRadioBox* radioBox ) const +{ + using Q = QskRadioBox; -QSizeF QskRadioBoxSkinlet::buttonSymbolSize( const QskRadioBox* radio ) const { - auto buttonStrut = radio->strutSizeHint( Q::Button ); - auto symbolStrut = radio->strutSizeHint( Q::Symbol ); + auto buttonStrut = radioBox->strutSizeHint( Q::Button ); + auto symbolStrut = radioBox->strutSizeHint( Q::Symbol ); - buttonStrut = buttonStrut.grownBy( radio->marginHint( Q::Button ) ); - symbolStrut = symbolStrut.grownBy( radio->marginHint( Q::Symbol ) ); + buttonStrut = buttonStrut.grownBy( radioBox->marginHint( Q::Button ) ); + symbolStrut = symbolStrut.grownBy( radioBox->marginHint( Q::Symbol ) ); - return QSizeF( - qMax( buttonStrut.width(), symbolStrut.width() ), + return QSizeF( qMax( buttonStrut.width(), symbolStrut.width() ), qMax( buttonStrut.height(), symbolStrut.height() ) ); } -QRectF QskRadioBoxSkinlet::rippleRect( const QskRadioBox* radio, const QRectF& rect ) const { - auto ripplePosition = radio->positionHint( Q::Ripple ); +QRectF QskRadioBoxSkinlet::rippleRect( + const QskRadioBox* radioBox, const QRectF& rect ) const +{ + using Q = QskRadioBox; - if( ripplePosition < 0 ) { - return QRectF(); - } - - auto button = buttonRect( radio, Q::Button, rect, ripplePosition ); - auto rippleSize = radio->strutSizeHint( Q::Ripple ); - button.moveLeft( button.x() - ( rippleSize.width() - button.width() ) / 2 ); - button.moveTop( button.y() - ( rippleSize.height() - button.height() ) / 2 ); - button.setSize( rippleSize ); - return button; + auto ripplePosition = radioBox->positionHint( Q::Ripple ); + + if( ripplePosition < 0 ) + return QRectF(); + + auto rippleSize = radioBox->strutSizeHint( Q::Ripple ); + + auto r = buttonRect( radioBox, Q::Button, rect, ripplePosition ); + + r.moveLeft( r.x() - ( rippleSize.width() - r.width() ) / 2 ); + r.moveTop( r.y() - ( rippleSize.height() - r.height() ) / 2 ); + r.setSize( rippleSize ); + + return r; } -QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radio, - const QskAspect::Subcontrol target, const QRectF& rect, double index ) const { - if( index < 0 ) { - return QRectF(); - } +QRectF QskRadioBoxSkinlet::buttonRect( const QskRadioBox* radioBox, + const QskAspect::Subcontrol target, const QRectF& rect, double index ) const +{ + using Q = QskRadioBox; + + if( index < 0 ) + return QRectF(); auto result = rect; - result.setSize( radio->strutSizeHint( target ) ); + result.setSize( radioBox->strutSizeHint( target ) ); - auto spacing = radio->spacingHint( Q::Panel ); - result.moveTop( ( lineHeight( radio ) + spacing ) * index ); + auto spacing = radioBox->spacingHint( Q::Panel ); + result.moveTop( ( lineHeight( radioBox ) + spacing ) * index ); - auto margins = radio->marginHint( target ); + auto margins = radioBox->marginHint( target ); auto withMargins = result.size().grownBy( margins ); - auto maxSize = buttonSymbolSize( radio ); - auto alignment = radio->alignmentHint( target ); + auto maxSize = buttonSymbolSize( radioBox ); + auto alignment = radioBox->alignmentHint( target ); // Vertical positioning - auto alignHeight = maxSize.height() - withMargins.height(); - if( alignment.testFlag( Qt::AlignVCenter ) ) { - result.moveTop( result.top() + alignHeight / 2 ); - } else if( alignment.testFlag( Qt::AlignBottom ) ) { - result.moveTop( result.top() + alignHeight ); - } + const auto alignHeight = maxSize.height() - withMargins.height(); + if( alignment.testFlag( Qt::AlignVCenter ) ) + result.moveTop( result.top() + alignHeight / 2 ); + else if( alignment.testFlag( Qt::AlignBottom ) ) + result.moveTop( result.top() + alignHeight ); + result.moveTop( result.top() + margins.top() ); // Horizontal positioning auto alignWidth = 0; - if( alignment.testFlag( Qt::AlignHCenter ) ) { - alignWidth = ( maxSize.width() - withMargins.width() ) / 2; - } else if ( alignment.testFlag( Qt::AlignRight )) { - alignWidth = maxSize.width() - withMargins.width(); - } + if( alignment.testFlag( Qt::AlignHCenter ) ) + alignWidth = ( maxSize.width() - withMargins.width() ) / 2; + else if ( alignment.testFlag( Qt::AlignRight ) ) + alignWidth = maxSize.width() - withMargins.width(); + + if( radioBox->layoutMirroring() ) + result.moveRight( rect.width() - ( alignWidth + margins.right() ) ); + else + result.moveLeft( margins.left() + alignWidth ); - if( radio->layoutMirroring() ) { - result.moveRight( rect.width() - ( alignWidth + margins.right() ) ); - } else { - result.moveLeft( margins.left() + alignWidth ); - } - return result; } -QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radio, - const QRectF& rect, int index ) const { - auto text = radio->items()[ index ]; +QRectF QskRadioBoxSkinlet::textRect( const QskRadioBox* radioBox, + const QRectF& rect, int index ) const +{ + using Q = QskRadioBox; - if(text.isEmpty()) { - return QRectF(); - } + const auto text = radioBox->items()[ index ]; + if( text.isEmpty() ) + return QRectF(); QRectF result = rect; - auto spacing = radio->spacingHint( Q::Panel ); - auto lh = lineHeight( radio ); - const auto textMargins = radio->marginHint( Q::Text ); - const auto font = radio->effectiveFont( Q::Text ); + auto spacing = radioBox->spacingHint( Q::Panel ); + auto lh = lineHeight( radioBox ); + const auto textMargins = radioBox->marginHint( Q::Text ); + const auto font = radioBox->effectiveFont( Q::Text ); result.moveTop( index * ( lh + spacing ) - + lh - radio->effectiveFontHeight( Q::Text ) - + textMargins.top()); + + lh - QFontMetricsF( font ).height() + textMargins.top() ); result.setHeight( lh ); result.setWidth( qskHorizontalAdvance( font, text ) ); - auto button = buttonRect( radio, Q::Button, rect, index ); - auto buttonsMargins = radio->marginHint( Q::Button ); - auto buttonWidth = button.marginsAdded( buttonsMargins ).width(); + const auto button = buttonRect( radioBox, Q::Button, rect, index ); + const auto buttonsMargins = radioBox->marginHint( Q::Button ); + const auto buttonWidth = button.marginsAdded( buttonsMargins ).width(); - if( radio->layoutMirroring() ) { - result.moveLeft( rect.width() - textMargins.right() - - result.width() - buttonWidth); - } else { - result.moveLeft( buttonWidth + textMargins.left() ); + if( radioBox->layoutMirroring() ) + { + result.moveLeft( rect.width() - textMargins.right() + - result.width() - buttonWidth); + } + else + { + result.moveLeft( buttonWidth + textMargins.left() ); } return result; } QRectF QskRadioBoxSkinlet::sampleRect( const QskSkinnable* skinnable, - const QRectF& rect, QskAspect::Subcontrol subcontrol, int index ) const { + const QRectF& rect, QskAspect::Subcontrol subcontrol, int index ) const +{ + using Q = QskRadioBox; - const auto radio = static_cast< const QskRadioBox* >( skinnable ); + auto radioBox = static_cast< const QskRadioBox* >( skinnable ); - if( subcontrol == Q::Text ) { - return textRect( radio, rect, index ); - } + if( subcontrol == Q::Text ) + return textRect( radioBox, rect, index ); - return buttonRect( radio, subcontrol, rect, index); + return buttonRect( radioBox, subcontrol, rect, index); } QskAspect::States QskRadioBoxSkinlet::sampleStates( const QskSkinnable* skinnable, - QskAspect::Subcontrol subControl, int index ) const { + QskAspect::Subcontrol subControl, int index ) const +{ + auto radioBox = static_cast< const QskRadioBox* >( skinnable ); + auto states = Inherited::sampleStates( skinnable, subControl, index ); - auto radio = static_cast< const QskRadioBox* >( skinnable ); - auto states = Inherited::sampleStates( skinnable, subControl, index ); - - return states | statesForIndex( radio, index ); + return states | statesForIndex( radioBox, index ); } -QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, - QskAspect::Subcontrol subcontrol, int index, QSGNode* node ) const { +QSGNode* QskRadioBoxSkinlet::updateSampleNode( const QskSkinnable* skinnable, + QskAspect::Subcontrol subcontrol, int index, QSGNode* node ) const +{ + using Q = QskRadioBox; - auto radio = static_cast< const QskRadioBox* >( skinnable ); + auto radioBox = static_cast< const QskRadioBox* >( skinnable ); - auto rect = sampleRect( skinnable, radio->contentsRect(), - subcontrol, index ); - - if( subcontrol == Q::Text ) { - return QskSkinlet::updateTextNode( radio, node, rect, Qt::AlignLeft, - radio->items()[ index ], subcontrol ); - } else if ( subcontrol == Q::Button ) { - return QskSkinlet::updateBoxNode( radio, node, rect, subcontrol ); - } else if( subcontrol == Q::Symbol ) { + auto rect = sampleRect( skinnable, radioBox->contentsRect(), subcontrol, index ); + + if( subcontrol == Q::Text ) + { + return QskSkinlet::updateTextNode( radioBox, node, rect, Qt::AlignLeft, + radioBox->items()[ index ], subcontrol ); + } + else if ( subcontrol == Q::Button ) + { + return QskSkinlet::updateBoxNode( radioBox, node, rect, subcontrol ); + } + else if( subcontrol == Q::Symbol ) + { auto symbol = QskStandardSymbol::NoSymbol; - auto color = radio->color( subcontrol ).rgb(); + auto color = radioBox->color( subcontrol ).rgb(); - if( radio->selectedIndex() == index ) { - symbol = QskStandardSymbol::Bullet; - color = radio->color( subcontrol | Q::Selected ).rgb(); - } - - auto graphic = radio->effectiveSkin()->symbol( symbol ); + if( radioBox->selectedIndex() == index ) + { + symbol = QskStandardSymbol::Bullet; + color = radioBox->color( subcontrol | Q::Selected ).rgb(); + } - /* - Our default skins do not have the concept of colorRoles - implemented. Until then we do the recoloring manually here - */ - QskColorFilter filter; - filter.addColorSubstitution( Qt::black, color ); - auto colorSub = radio->color( subcontrol | statesForIndex( radio, index ) ); - filter.addColorSubstitution( Qt::black, colorSub.rgb() ); + auto graphic = radioBox->effectiveSkin()->symbol( symbol ); - QskGraphic::fromGraphic( graphic, filter ); + /* + Our default skins do not have the concept of colorRoles + implemented. Until then we do the recoloring manually here + */ + QskColorFilter filter; + filter.addColorSubstitution( Qt::black, color ); - return updateGraphicNode( radio, node, graphic, filter, rect ); + auto colorSub = radioBox->color( subcontrol | statesForIndex( radioBox, index ) ); + filter.addColorSubstitution( Qt::black, colorSub.rgb() ); + + QskGraphic::fromGraphic( graphic, filter ); + + return updateGraphicNode( radioBox, node, graphic, filter, rect ); } return node; diff --git a/src/controls/QskRadioBoxSkinlet.h b/src/controls/QskRadioBoxSkinlet.h index 4b0be65b..c1c4f359 100644 --- a/src/controls/QskRadioBoxSkinlet.h +++ b/src/controls/QskRadioBoxSkinlet.h @@ -1,3 +1,8 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + #ifndef QSK_RADIO_BOX_SKINLET_H #define QSK_RADIO_BOX_SKINLET_H @@ -37,13 +42,6 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet QRectF sampleRect( const QskSkinnable*, const QRectF&, QskAspect::Subcontrol, int index ) const override; - QSizeF buttonSymbolSize( const QskRadioBox* radio ) const; - QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; - QRectF buttonRect( const QskRadioBox*, const QskAspect::Subcontrol target, const QRectF&, - double ) const; - QRectF rippleRect( const QskRadioBox*, const QRectF& ) const; - - QskAspect::States sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int index ) const override; @@ -55,7 +53,13 @@ class QSK_EXPORT QskRadioBoxSkinlet : public QskSkinlet QskAspect::Subcontrol, int index, QSGNode* ) const override; private: - qreal lineHeight( const QskRadioBox* target ) const; + QRectF textRect( const QskRadioBox*, const QRectF&, int ) const; + + QSizeF buttonSymbolSize( const QskRadioBox* ) const; + QRectF buttonRect( const QskRadioBox*, + const QskAspect::Subcontrol, const QRectF&, double ) const; + + QRectF rippleRect( const QskRadioBox*, const QRectF& ) const; }; #endif