diff --git a/playground/shadows/ShadowedBox.cpp b/playground/shadows/ShadowedBox.cpp index f9c29cd6..cc2346d0 100644 --- a/playground/shadows/ShadowedBox.cpp +++ b/playground/shadows/ShadowedBox.cpp @@ -14,40 +14,103 @@ ShadowedBox::ShadowedBox( QQuickItem* parentItem ) : QskBox( true, parentItem ) { + QColor c( Qt::darkRed ); +#if 0 + c.setAlpha( 100 ); +#endif + + setGradientHint( Panel, c ); + setBoxShapeHint( Panel, QskBoxShapeMetrics( 40, 0, 15, 0 ) ); + + setBoxBorderMetricsHint( Panel, 0 ); + +#if 0 + setBoxBorderMetricsHint( Panel, 10 ); + setBoxBorderColorsHint( Panel, Qt::blue ); +#endif + + setShadowColorHint( Panel, Qt::black ); } ShadowedBox::~ShadowedBox() { } -void ShadowedBox::setShadow( const QskShadowMetrics& shadow ) +void ShadowedBox::setOffsetX( qreal dx ) { - setShadowMetricsHint( Panel, shadow ); + auto metrics = shadowMetrics(); + metrics.setOffsetX( dx ); + + setShadowMetrics( metrics ); } -void ShadowedBox::setShadowColor( const QColor& color ) +qreal ShadowedBox::offsetX() const { + return shadowMetrics().offset().x(); +} + +void ShadowedBox::setOffsetY( qreal dy ) +{ + auto metrics = shadowMetrics(); + metrics.setOffsetY( dy ); + + setShadowMetrics( metrics ); +} + +qreal ShadowedBox::offsetY() const +{ + return shadowMetrics().offset().y(); +} + +void ShadowedBox::setSpreadRadius( qreal radius ) +{ + auto metrics = shadowMetrics(); + metrics.setSpreadRadius( radius ); + + setShadowMetrics( metrics ); +} + +qreal ShadowedBox::spreadRadius() const +{ + return shadowMetrics().spreadRadius(); +} + +void ShadowedBox::setBlurRadius( qreal radius ) +{ + auto metrics = shadowMetrics(); + metrics.setBlurRadius( radius ); + + setShadowMetrics( metrics ); +} + +qreal ShadowedBox::blurRadius() const +{ + return shadowMetrics().blurRadius(); +} + +void ShadowedBox::setOpacity( qreal opacity ) +{ + opacity = qBound( 0.0, opacity, 1.0 ); + + auto color = shadowColorHint( Panel ); + color.setAlphaF( opacity ); + setShadowColorHint( Panel, color ); } -void ShadowedBox::setGradient( const QskGradient& gradient ) +qreal ShadowedBox::opacity() const { - setGradientHint( Panel, gradient ); + return shadowColorHint( Panel ).alphaF(); } -void ShadowedBox::setShape( const QskBoxShapeMetrics& shape ) +QskShadowMetrics ShadowedBox::shadowMetrics() const { - setBoxShapeHint( Panel, shape ); + return shadowMetricsHint( Panel ); } -void ShadowedBox::setBorderWidth( qreal width ) +void ShadowedBox::setShadowMetrics( const QskShadowMetrics& metrics ) { - setBoxBorderMetricsHint( Panel, width ); -} - -void ShadowedBox::setBorderColors( const QskBoxBorderColors& colors ) -{ - setBoxBorderColorsHint( Panel, colors ); + setShadowMetricsHint( Panel, metrics ); } #include "moc_ShadowedBox.cpp" diff --git a/playground/shadows/ShadowedBox.h b/playground/shadows/ShadowedBox.h index d3232b7d..63dd0bd2 100644 --- a/playground/shadows/ShadowedBox.h +++ b/playground/shadows/ShadowedBox.h @@ -7,25 +7,34 @@ #include -class QskGradient; class QskShadowMetrics; -class QskBoxShapeMetrics; -class QskBoxBorderColors; class ShadowedBox : public QskBox { Q_OBJECT public: - ShadowedBox(QQuickItem* parent = nullptr); + ShadowedBox( QQuickItem* parent = nullptr ); ~ShadowedBox() override; - void setShape( const QskBoxShapeMetrics& ); - void setGradient( const QskGradient& ); + qreal offsetX() const; + qreal offsetY() const; - void setBorderWidth( qreal width ); - void setBorderColors( const QskBoxBorderColors& ); + qreal spreadRadius() const; + qreal blurRadius() const; - void setShadow( const QskShadowMetrics& ); - void setShadowColor( const QColor& ); + qreal opacity() const; + + public Q_SLOTS: + void setOffsetX( qreal ); + void setOffsetY( qreal ); + + void setSpreadRadius( qreal ); + void setBlurRadius( qreal ); + + void setOpacity( qreal ); + + private: + QskShadowMetrics shadowMetrics() const; + void setShadowMetrics( const QskShadowMetrics& ); }; diff --git a/playground/shadows/main.cpp b/playground/shadows/main.cpp index e1bd51a4..e57c4d83 100644 --- a/playground/shadows/main.cpp +++ b/playground/shadows/main.cpp @@ -7,43 +7,122 @@ #include #include -#include +#include +#include +#include #include -#include -#include -#include -#include - #include #include +#include -class Box : public ShadowedBox +class BoxPanel : public QskBox { public: - Box( QQuickItem* parent = nullptr ) - : ShadowedBox( parent ) + BoxPanel( QQuickItem* parent = nullptr ) + : QskBox( parent ) { - const qreal w = 10; + setAutoLayoutChildren( true ); + setPadding( 60 ); - QskShadowMetrics shadow; - //shadow.setOffset( 20.0, 20.0 ); - shadow.setSpreadRadius( w ); - shadow.setBlurRadius( w ); + setPanel( true ); + setGradientHint( QskBox::Panel, QGradient::SnowAgain ); + } +}; - setShadow( shadow ); - setShadowColor( Qt::black ); +class Slider : public QskSlider +{ + public: + Slider( qreal min, qreal max, qreal step, qreal value, QQuickItem* parent = nullptr ) + : QskSlider( parent ) + { + setBoundaries( min, max ); + setStepSize( step ); + setSnap( true ); + setValue( value ); + } +}; - QColor c( Qt::darkRed ); -#if 0 - c.setAlpha( 100 ); -#endif +class ValueLabel : public QskTextLabel +{ + public: + ValueLabel( QQuickItem* parent = nullptr ) + : QskTextLabel( parent ) + { + setFixedWidth( QFontMetrics( font() ).horizontalAdvance( "-100" ) ); + setAlignment( Qt::AlignLeft | Qt::AlignVCenter ); + } - setGradient( c ); - setShape( QskBoxShapeMetrics( 40, 10, 15, 5 ) ); + void setValue( qreal value ) + { + setText( QString::number( value ) ); + } +}; - setBorderWidth( w ); - setBorderColors( Qt::blue ); +class GridBox : public QskGridBox +{ + public: + GridBox( QQuickItem* parent = nullptr ) + : QskGridBox( parent ) + { + setMargins( 5 ); + setColumnStretchFactor( 1, 1 ); + + auto sliderX = new Slider( -50, 50, 1, 10 ); + auto sliderY = new Slider( -50, 50, 1, 10 ); + auto sliderSpread = new Slider( 0, 50, 1, 0 ); + auto sliderBlur = new Slider( 0, 50, 1, 10 ); + auto sliderOpacity = new Slider( 0, 1, 0.01, 1 ); + + auto panel = new BoxPanel(); + + int row = 0; + + addSlider( row++, "Offset X", sliderX ); + addSlider( row++, "Offset Y", sliderY ); + addSlider( row++, "Spread Radius", sliderSpread ); + addSlider( row++, "Blur Radius", sliderBlur ); + addSlider( row++, "Opacity", sliderOpacity ); + + addItem( panel, row, 0, -1, -1 ); + + auto box = new ShadowedBox( panel ); + + box->setOffsetX( sliderX->value() ); + box->setOffsetY( sliderY->value() ); + box->setSpreadRadius( sliderSpread->value() ); + box->setBlurRadius( sliderBlur->value() ); + box->setOpacity( sliderOpacity->value() ); + + connect( sliderX, &QskSlider::valueChanged, + box, &ShadowedBox::setOffsetX ); + + connect( sliderY, &QskSlider::valueChanged, + box, &ShadowedBox::setOffsetY ); + + connect( sliderSpread, &QskSlider::valueChanged, + box, &ShadowedBox::setSpreadRadius ); + + connect( sliderBlur, &QskSlider::valueChanged, + box, &ShadowedBox::setBlurRadius ); + + connect( sliderOpacity, &QskSlider::valueChanged, + box, &ShadowedBox::setOpacity ); + } + + private: + void addSlider( int row, const QString& text, QskSlider* slider ) + { + addItem( new QskTextLabel( text ), row, 0 ); + addItem( slider, row, 1 ); + + auto label = new ValueLabel(); + label->setValue( slider->value() ); + + addItem( label, row, 2 ); + + connect( slider, &QskSlider::valueChanged, + label, [label]( qreal value ) { label->setText( QString::number( value ) ); } ); } }; @@ -57,20 +136,8 @@ int main( int argc, char* argv[] ) SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts ); - auto layout = new QskLinearBox(); - layout->setPanel( true ); -#if 1 - layout->setGradientHint( QskBox::Panel, - QskGradient( Qt::Vertical, QskRgb::WhiteSmoke, QskRgb::MistyRose ) ); -#else - layout->setGradientHint( QskBox::Panel, Qt::white ); -#endif - layout->setPadding( 60 ); - (void ) new Box( layout ); - QskWindow window; - window.setColor( QskRgb::PapayaWhip ); - window.addItem( layout ); + window.addItem( new GridBox() ); window.resize( 600, 600 ); window.show(); diff --git a/skins/material/QskMaterialSkin.cpp b/skins/material/QskMaterialSkin.cpp index 4fe1fa53..3c46fd86 100644 --- a/skins/material/QskMaterialSkin.cpp +++ b/skins/material/QskMaterialSkin.cpp @@ -434,7 +434,7 @@ void Editor::setupPushButton() using A = QskAspect; using Q = QskPushButton; - setStrutSize( Q::Panel, -1, 31 ); + setFlagHint( Q::Panel | QskAspect::Direction, Qsk::LeftToRight ); setSpacing( Q::Panel, qskDpiScaled( 4 ) ); setPadding( Q::Panel, { 24, 0, 20, 0 } ); @@ -473,6 +473,8 @@ void Editor::setupPushButton() setBoxBorderMetrics( Q::Panel, 1, { QskStateCombination::CombinationNoState, Q::Outlined } ); setBoxBorderColors( Q::Panel | Q::Outlined, m_pal.outline ); + setPadding( Q::Graphic, 5 ); + setGradient( Q::Panel | Q::Disabled, Qt::transparent, combination ); setBoxBorderColors( Q::Panel | Q::Outlined | Q::Disabled, c1 ); diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 4a0d8cae..ec1405d5 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -566,7 +566,7 @@ void Editor::setupPushButton() using Q = QskPushButton; // Panel - + setFlagHint( Q::Panel | QskAspect::Direction, Qsk::TopToBottom ); setStrutSize( Q::Panel, qskDpiScaled( 75.0 ), qskDpiScaled( 23.0 ) ); setMargin( Q::Panel, 0 ); @@ -594,6 +594,9 @@ void Editor::setupPushButton() setColor( Q::Text, m_pal.themeForeground ); setColor( Q::Text | Q::Disabled, m_pal.darker200 ); + + // Graphic + setPadding( Q::Graphic, 2 ); } void Editor::setupDialogButton() diff --git a/src/common/QskAspect.h b/src/common/QskAspect.h index 4b5f03bc..2819ae2b 100644 --- a/src/common/QskAspect.h +++ b/src/common/QskAspect.h @@ -32,6 +32,7 @@ class QSK_EXPORT QskAspect NoPrimitive = 0, Alignment, + Direction, Style, GraphicRole, FontRole, diff --git a/src/common/QskShadowMetrics.h b/src/common/QskShadowMetrics.h index b1c55f16..21fe2c59 100644 --- a/src/common/QskShadowMetrics.h +++ b/src/common/QskShadowMetrics.h @@ -45,6 +45,9 @@ class QSK_EXPORT QskShadowMetrics constexpr qreal totalRadius() const noexcept; + void setOffsetX( qreal dx ) noexcept; + void setOffsetY( qreal dy ) noexcept; + void setOffset( qreal dx, qreal dy ) noexcept; void setOffset( const QPointF& ) noexcept; @@ -98,6 +101,7 @@ inline constexpr bool QskShadowMetrics::operator==( const QskShadowMetrics& other ) const noexcept { return ( m_sizeMode == other.m_sizeMode ) + && ( m_offset == other.m_offset ) && ( m_spreadRadius == other.m_spreadRadius ) && ( m_blurRadius == other.m_blurRadius ) && ( m_sizeMode == other.m_sizeMode ); @@ -144,6 +148,16 @@ inline constexpr Qt::SizeMode QskShadowMetrics::sizeMode() const noexcept return m_sizeMode; } +inline void QskShadowMetrics::setOffsetX( qreal dx ) noexcept +{ + m_offset.rx() = dx; +} + +inline void QskShadowMetrics::setOffsetY( qreal dy ) noexcept +{ + m_offset.ry() = dy; +} + inline void QskShadowMetrics::setOffset( qreal dx, qreal dy ) noexcept { m_offset.rx() = dx; diff --git a/src/controls/QskPushButtonSkinlet.cpp b/src/controls/QskPushButtonSkinlet.cpp index 6063d9eb..b7fd445c 100644 --- a/src/controls/QskPushButtonSkinlet.cpp +++ b/src/controls/QskPushButtonSkinlet.cpp @@ -77,11 +77,24 @@ QRectF QskPushButtonSkinlet::textRect( if ( button->hasGraphic() ) { - // in case of having text + graphic we put the text at the bottom + const auto orientation = button->flagHint( QskPushButton::Panel | QskAspect::Direction, Qsk::LeftToRight ); - qreal h = button->effectiveFontHeight( QskPushButton::Text ); - if ( h < r.height() ) - r.setTop( r.bottom() - h ); + switch( orientation ) + { + case Qsk::LeftToRight: + { + const auto graphicsRect = subControlRect( button, contentsRect, QskPushButton::Graphic ); + const auto spacing = button->metric( QskPushButton::Panel | QskAspect::Spacing ); + r.setX( r.x() + graphicsRect.width() + spacing ); + break; + } + default: // Qsk::TopToBottom, the other ones are not handled yet + { + qreal h = button->effectiveFontHeight( QskPushButton::Text ); + if ( h < r.height() ) + r.setTop( r.bottom() - h ); + } + } } return r; @@ -94,7 +107,10 @@ QRectF QskPushButtonSkinlet::graphicRect( auto r = button->subControlContentsRect( contentsRect, QskPushButton::Panel ); - if ( !button->text().isEmpty() ) + const auto orientation = button->flagHint( QskPushButton::Panel + | QskAspect::Direction, Qsk::LeftToRight ); + + if ( !button->text().isEmpty() && orientation == Qsk::TopToBottom ) { const auto textRect = subControlRect( button, contentsRect, QskPushButton::Text ); qreal h = textRect.height() + button->spacingHint( QskPushButton::Panel ); @@ -106,6 +122,7 @@ QRectF QskPushButtonSkinlet::graphicRect( } const auto maxSize = button->graphicSourceSize(); + if ( maxSize.width() >= 0 || maxSize.height() >= 0 ) { // limiting the size by graphicSize @@ -134,15 +151,34 @@ QRectF QskPushButtonSkinlet::graphicRect( const double scaleFactor = qMin( r.width() / sz.width(), r.height() / sz.height() ); - // early aligning to avoid pointless operations, that finally will - // have no effect, when drawing to an integer based paint device - const int w = qFloor( scaleFactor * sz.width() ); const int h = qFloor( scaleFactor * sz.height() ); - const int x = qFloor( r.center().x() - 0.5 * w ); - const int y = qFloor( r.center().y() - 0.5 * h ); + int x, y; + + const auto orientation = button->flagHint( QskPushButton::Panel + | QskAspect::Direction, Qsk::LeftToRight ); + + switch( orientation ) + { + case Qsk::LeftToRight: + { + x = r.left(); + y = r.top(); + break; + } + default: // TopToBottom + { + // early aligning to avoid pointless operations, that finally will + // have no effect, when drawing to an integer based paint device + + x = qFloor( r.center().x() - 0.5 * w ); + y = qFloor( r.center().y() - 0.5 * h ); + } + } r = QRectF( x, y, w, h ); + const auto padding = button->paddingHint( QskPushButton::Graphic ); + r = r.marginsRemoved( padding ); } return r; @@ -213,10 +249,25 @@ QSizeF QskPushButtonSkinlet::sizeHint( const QskSkinnable* skinnable, } } - const qreal padding = 2.0; // paddingHint( Graphic ) ??? + const QMarginsF padding = button->paddingHint( QskPushButton::Graphic ); - size.rheight() += 2 * padding + h; - size.rwidth() = qMax( size.width(), w ); + const auto orientation = button->flagHint( QskPushButton::Panel + | QskAspect::Direction, Qsk::LeftToRight ); + + switch( orientation ) + { + case Qsk::LeftToRight: + { + size.rwidth() += padding.left() + w + padding.right(); + size.rheight() = qMax( size.height(), h ); + break; + } + default: // TopToBottom + { + size.rheight() += padding.top() + h + padding.bottom(); + size.rwidth() = qMax( size.width(), w ); + } + } } size = size.expandedTo( button->strutSizeHint( QskPushButton::Panel ) ); diff --git a/src/nodes/QskShadedBoxNode.cpp b/src/nodes/QskShadedBoxNode.cpp index 83e0d132..31bc7db7 100644 --- a/src/nodes/QskShadedBoxNode.cpp +++ b/src/nodes/QskShadedBoxNode.cpp @@ -48,6 +48,8 @@ void QskShadedBoxNode::setShadowData( insertChildNodeBefore( m_shadowNode, &m_boxNode ); } + m_shadowNode->setColor( color ); + m_shadowNode->setRect( metrics.shadowRect( rect ) ); m_shadowNode->setShape( shape ); m_shadowNode->setBlurRadius( metrics.blurRadius() );