From a0642cfde994097456c1aba1aad9c90a3b823447 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 14 Oct 2024 16:07:35 +0200 Subject: [PATCH] input text: Add skinlets for different design systems --- designsystems/fluent2/CMakeLists.txt | 1 + designsystems/fluent2/QskFluent2Skin.cpp | 22 +- designsystems/fluent2/QskFluent2Skin.h | 1 + .../fluent2/QskFluent2TextInputSkinlet.cpp | 75 ++++ .../fluent2/QskFluent2TextInputSkinlet.h | 28 ++ designsystems/fusion/QskFusionSkin.cpp | 2 +- designsystems/material3/CMakeLists.txt | 1 + designsystems/material3/QskMaterial3Skin.cpp | 8 + designsystems/material3/QskMaterial3Skin.h | 1 + .../QskMaterial3TextInputSkinlet.cpp | 332 ++++++++++++++++++ .../material3/QskMaterial3TextInputSkinlet.h | 41 +++ examples/gallery/inputs/InputPage.cpp | 2 +- src/controls/QskTextInput.cpp | 16 +- src/controls/QskTextInputSkinlet.cpp | 254 +------------- src/controls/QskTextInputSkinlet.h | 8 +- 15 files changed, 522 insertions(+), 270 deletions(-) create mode 100644 designsystems/fluent2/QskFluent2TextInputSkinlet.cpp create mode 100644 designsystems/fluent2/QskFluent2TextInputSkinlet.h create mode 100644 designsystems/material3/QskMaterial3TextInputSkinlet.cpp create mode 100644 designsystems/material3/QskMaterial3TextInputSkinlet.h diff --git a/designsystems/fluent2/CMakeLists.txt b/designsystems/fluent2/CMakeLists.txt index 4fb73177..ce0d222c 100644 --- a/designsystems/fluent2/CMakeLists.txt +++ b/designsystems/fluent2/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES QskFluent2Theme.h QskFluent2Theme.cpp QskFluent2Skin.h QskFluent2Skin.cpp QskFluent2SkinFactory.h QskFluent2SkinFactory.cpp + QskFluent2TextInputSkinlet.h QskFluent2TextInputSkinlet.cpp ) qt_add_resources(SOURCES QskFluent2Icons.qrc) diff --git a/designsystems/fluent2/QskFluent2Skin.cpp b/designsystems/fluent2/QskFluent2Skin.cpp index caf41258..9f7dbc1f 100644 --- a/designsystems/fluent2/QskFluent2Skin.cpp +++ b/designsystems/fluent2/QskFluent2Skin.cpp @@ -48,6 +48,8 @@ #include "QskFluent2Skin.h" #include "QskFluent2Theme.h" +#include "QskFluent2TextInputSkinlet.h" + #include #include @@ -1773,8 +1775,14 @@ void Editor::setupTextInputMetrics() setBoxShape( Q::Panel, 3_px ); + setStrutSize( Q::LabelText, { -1, 30_px } ); + setFontRole( Q::LabelText, Fluent2::Body ); + setAlignment( Q::InputText, Qt::AlignLeft | Qt::AlignVCenter ); setFontRole( Q::InputText, Fluent2::Body ); + + setAlignment( Q::HintText, alignment( Q::InputText ) ); + setFontRole( Q::HintText, fontRole( Q::InputText ) ); } void Editor::setupTextInputColors( @@ -1786,7 +1794,9 @@ void Editor::setupTextInputColors( const auto& pal = theme.palette; setColor( Q::Panel | Q::Selected, pal.fillColor.accent.selectedTextBackground ); + setColor( Q::LabelText, pal.fillColor.text.primary ); setColor( Q::InputText | Q::Selected, pal.fillColor.textOnAccent.selectedText ); + setColor( Q::HintText, pal.fillColor.text.secondary ); for( const auto state : { A::NoState, Q::Hovered, Q::Focused, Q::Editing, Q::Disabled } ) { @@ -1797,21 +1807,21 @@ void Editor::setupTextInputColors( panelColor = pal.fillColor.control.defaultColor; borderColor1 = pal.elevation.textControl.border[0]; borderColor2 = pal.elevation.textControl.border[1]; - textColor = pal.fillColor.text.secondary; + textColor = pal.fillColor.text.primary; } else if ( state == Q::Hovered ) { panelColor = pal.fillColor.control.secondary; borderColor1 = pal.elevation.textControl.border[0]; borderColor2 = pal.elevation.textControl.border[1]; - textColor = pal.fillColor.text.secondary; + textColor = pal.fillColor.text.primary; } else if ( ( state == Q::Focused ) || ( state == Q::Editing ) ) { panelColor = pal.fillColor.control.inputActive; borderColor1 = pal.elevation.textControl.border[0]; borderColor2 = pal.fillColor.accent.defaultColor; - textColor = pal.fillColor.text.secondary; + textColor = pal.fillColor.text.primary; } else if ( state == Q::Disabled ) { @@ -2016,6 +2026,7 @@ void Editor::setupVirtualKeyboardColors( QskFluent2Skin::QskFluent2Skin( QObject* parent ) : Inherited( parent ) { + setupSkinlets(); setupFonts(); Editor editor( &hintTable() ); @@ -2103,6 +2114,11 @@ static inline QFont createFont( qreal size, int lineHeight, QFont::Weight weight return font; } +void QskFluent2Skin::setupSkinlets() +{ + declareSkinlet< QskTextInput, QskFluent2TextInputSkinlet >(); +} + void QskFluent2Skin::setupFonts() { // see: https://fluent2.microsoft.design/typography ( Windows ) diff --git a/designsystems/fluent2/QskFluent2Skin.h b/designsystems/fluent2/QskFluent2Skin.h index 5a72c481..2d919a84 100644 --- a/designsystems/fluent2/QskFluent2Skin.h +++ b/designsystems/fluent2/QskFluent2Skin.h @@ -40,6 +40,7 @@ class QSK_FLUENT2_EXPORT QskFluent2Skin : public QskSkin private: void addTheme( QskAspect::Section, const QskFluent2Theme& ); + void setupSkinlets(); void setupFonts(); void setupGraphicFilters( const QskFluent2Theme& ); void setGraphicColor( GraphicRole, QRgb ); diff --git a/designsystems/fluent2/QskFluent2TextInputSkinlet.cpp b/designsystems/fluent2/QskFluent2TextInputSkinlet.cpp new file mode 100644 index 00000000..656028c8 --- /dev/null +++ b/designsystems/fluent2/QskFluent2TextInputSkinlet.cpp @@ -0,0 +1,75 @@ +/****************************************************************************** + * QSkinny - Copyright (C) The authors + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskFluent2TextInputSkinlet.h" +#include "QskTextInput.h" + +using Q = QskTextInput; + +QskFluent2TextInputSkinlet::QskFluent2TextInputSkinlet( QskSkin* skin ) + : Inherited( skin ) +{ +} + +QskFluent2TextInputSkinlet::~QskFluent2TextInputSkinlet() +{ +} + +QRectF QskFluent2TextInputSkinlet::subControlRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const +{ + const auto input = static_cast< const Q* >( skinnable ); + + if ( subControl == Q::Panel ) + { + auto rect = contentsRect; + + const auto h = input->strutSizeHint( subControl ).height(); + rect.setY( rect.bottom() - h ); + + return rect; + } + else if ( subControl == Q::LabelText ) + { + auto rect = contentsRect; + + const auto h = input->strutSizeHint( subControl ).height(); + rect.setHeight( h ); + + return rect; + } + else if ( subControl == Q::HintText ) + { + if( input->hasSkinState( Q::TextPopulated ) ) + { + return {}; + } + else + { + return input->subControlRect( Q::InputText ); + } + } + + return Inherited::subControlRect( skinnable, contentsRect, subControl ); +} + +QSizeF QskFluent2TextInputSkinlet::adjustSizeHint( const QskSkinnable* skinnable, Qt::SizeHint which, const QSizeF& oldHint ) const +{ + if ( which != Qt::PreferredSize ) + return QSizeF(); + + const auto input = static_cast< const Q* >( skinnable ); + + const auto labelHeight = input->labelText().isEmpty() ? 0 : input->strutSizeHint( Q::LabelText ).height(); + const auto panelHeight = input->strutSizeHint( Q::Panel ).height(); + + const auto h = labelHeight + panelHeight; + + QSizeF hint( oldHint.width(), h ); + + return hint; +} + +#include "moc_QskFluent2TextInputSkinlet.cpp" diff --git a/designsystems/fluent2/QskFluent2TextInputSkinlet.h b/designsystems/fluent2/QskFluent2TextInputSkinlet.h new file mode 100644 index 00000000..79e9cd26 --- /dev/null +++ b/designsystems/fluent2/QskFluent2TextInputSkinlet.h @@ -0,0 +1,28 @@ +/****************************************************************************** + * QSkinny - Copyright (C) The authors + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_MATERIAL3_INPUT_SKINLET_H +#define QSK_MATERIAL3_INPUT_SKINLET_H + +#include "QskTextInputSkinlet.h" + +class QSK_EXPORT QskFluent2TextInputSkinlet : public QskTextInputSkinlet +{ + Q_GADGET + + using Inherited = QskTextInputSkinlet; + + public: + Q_INVOKABLE QskFluent2TextInputSkinlet( QskSkin* = nullptr ); + ~QskFluent2TextInputSkinlet() override; + + QRectF subControlRect( const QskSkinnable*, + const QRectF& rect, QskAspect::Subcontrol ) const override; + + QSizeF adjustSizeHint( const QskSkinnable*, + Qt::SizeHint, const QSizeF& ) const override; +}; + +#endif diff --git a/designsystems/fusion/QskFusionSkin.cpp b/designsystems/fusion/QskFusionSkin.cpp index 1ad74048..358fb8df 100644 --- a/designsystems/fusion/QskFusionSkin.cpp +++ b/designsystems/fusion/QskFusionSkin.cpp @@ -386,7 +386,7 @@ void Editor::setupTextInput() using A = QskAspect; using P = QPalette; - setAlignment( Q::InputText, Qt::AlignLeft | Qt::AlignTop ); + setAlignment( Q::InputText, Qt::AlignLeft | Qt::AlignVCenter ); for ( auto state : { A::NoState, Q::Disabled } ) { diff --git a/designsystems/material3/CMakeLists.txt b/designsystems/material3/CMakeLists.txt index 051e8ed9..da9f1862 100644 --- a/designsystems/material3/CMakeLists.txt +++ b/designsystems/material3/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES QskMaterial3Global.h QskMaterial3Skin.h QskMaterial3Skin.cpp QskMaterial3SkinFactory.h QskMaterial3SkinFactory.cpp + QskMaterial3TextInputSkinlet.h QskMaterial3TextInputSkinlet.cpp ) qt_add_resources(SOURCES QskMaterial3Icons.qrc) diff --git a/designsystems/material3/QskMaterial3Skin.cpp b/designsystems/material3/QskMaterial3Skin.cpp index 0f63c219..b47b2e24 100644 --- a/designsystems/material3/QskMaterial3Skin.cpp +++ b/designsystems/material3/QskMaterial3Skin.cpp @@ -10,6 +10,8 @@ #include "QskMaterial3Skin.h" +#include "QskMaterial3TextInputSkinlet.h" + #include #include @@ -1736,6 +1738,11 @@ static inline QFont createFont( qreal size, int lineHeight, return font; } +void QskMaterial3Skin::setupSkinlets() +{ + declareSkinlet< QskTextInput, QskMaterial3TextInputSkinlet >(); +} + void QskMaterial3Skin::setupFonts() { /* @@ -1801,6 +1808,7 @@ void QskMaterial3Skin::initHints() { const QskMaterial3Theme theme( colorScheme() ); + setupSkinlets(); setupFonts(); setupGraphicFilters( theme ); diff --git a/designsystems/material3/QskMaterial3Skin.h b/designsystems/material3/QskMaterial3Skin.h index f6e7dcaf..6a02dce2 100644 --- a/designsystems/material3/QskMaterial3Skin.h +++ b/designsystems/material3/QskMaterial3Skin.h @@ -143,6 +143,7 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin void initHints() override; private: + void setupSkinlets(); void setupFonts(); void setupGraphicFilters( const QskMaterial3Theme& ); void setGraphicColor( GraphicRole, QRgb ); diff --git a/designsystems/material3/QskMaterial3TextInputSkinlet.cpp b/designsystems/material3/QskMaterial3TextInputSkinlet.cpp new file mode 100644 index 00000000..040d506d --- /dev/null +++ b/designsystems/material3/QskMaterial3TextInputSkinlet.cpp @@ -0,0 +1,332 @@ +/****************************************************************************** + * QSkinny - Copyright (C) The authors + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#include "QskMaterial3TextInputSkinlet.h" +#include "QskTextInput.h" + +#include "QskBoxBorderColors.h" +#include "QskBoxBorderMetrics.h" +#include "QskBoxShapeMetrics.h" +#include "QskFunctions.h" + +#include + +using Q = QskTextInput; + +namespace +{ + QString maxLengthString( const QskTextInput* input ) + { + QString s = QString::number( input->inputText().length() ) + + " / " + QString::number( input->maxLength() ); + return s; + } + + // We need to "cut a hole" in the upper gradient for the label text: + QskBoxBorderColors outlineColors( const QskTextInput* input ) + { + auto borderColors = input->boxBorderColorsHint( Q::Panel ); + auto topGradient = borderColors.gradientAt( Qt::TopEdge ); + + const auto panelRect = input->subControlRect( Q::Panel ); + + const auto margins = input->marginHint( Q::LabelText ); + const auto iconMargins = input->marginHint( Q::LeadingIcon ); + + const auto x1 = iconMargins.left() - margins.left(); + const auto r1 = x1 / panelRect.width(); + + const auto w = qskHorizontalAdvance( input->effectiveFont( Q::LabelText ), input->labelText() ); + + const auto x2 = x1 + w + margins.right(); + const auto r2 = x2 / panelRect.width(); + + topGradient.setStops( { + { 0.0, topGradient.startColor() }, + { r1, topGradient.startColor() }, + { r1, Qt::transparent }, + { r2, Qt::transparent }, + { r2, topGradient.startColor() }, + { 1.0, topGradient.startColor() } + } ); + + borderColors.setGradientAt( Qt::TopEdge, topGradient ); + + return borderColors; + } +} + +QskMaterial3TextInputSkinlet::QskMaterial3TextInputSkinlet( QskSkin* skin ) + : Inherited( skin ) +{ + setNodeRoles( { + PanelRole, + LeadingIconRole, + LabelTextRole, + HintTextRole, + SupportingTextRole, + CharacterCountRole, + TrailingIconRippleRole, + TrailingIconRole, + } ); +} + +QskMaterial3TextInputSkinlet::~QskMaterial3TextInputSkinlet() +{ +} + +QRectF QskMaterial3TextInputSkinlet::subControlRect( const QskSkinnable* skinnable, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const +{ + const auto input = static_cast< const Q* >( skinnable ); + + if ( subControl == Q::Panel ) + { + auto rect = contentsRect; + + if( input->emphasis() == Q::LowEmphasis ) + { + const auto fontHeight = input->effectiveFontHeight( Q::LabelText | Q::Focused ); + rect.setY( fontHeight / 2 ); + } + + const auto h = input->strutSizeHint( subControl ).height(); + rect.setHeight( h ); + + return rect; + } + else if ( subControl == Q::LabelText ) + { + const auto inputRect = input->subControlRect( Q::InputText ); + + if( !input->inputText().isEmpty() + || input->hasSkinState( Q::Focused ) + || input->hasSkinState( Q::Editing ) ) + { + const auto margins = input->marginHint( subControl ); + auto rect = inputRect; + const QFontMetricsF fm( input->effectiveFont( subControl ) ); + + if( input->emphasis() == Q::LowEmphasis ) + { + const auto iconMargins = input->marginHint( Q::LeadingIcon ); + rect.setX( iconMargins.left() ); + rect.setY( 0 ); + } + else + { + rect.setY( contentsRect.y() + margins.top() ); + } + + rect.setHeight( fm.height() ); + + return rect; + } + else + { + return inputRect; + } + } + else if ( subControl == Q::LeadingIcon ) + { + if( input->symbolHint( subControl ).isEmpty() ) + { + return {}; + } + else + { + const auto margins = input->marginHint( subControl ); + const auto panelRect = input->subControlRect( Q::Panel ); + auto rect = panelRect.marginsRemoved( margins ); + + const auto size = input->strutSizeHint( subControl ); + rect.setSize( size ); + rect.moveCenter( { rect.center().x(), panelRect.center().y() } ); + + return rect; + } + } + else if ( subControl == Q::HintText ) + { + if( !input->hasSkinState( Q::TextPopulated ) + && ( input->hasSkinState( Q::Focused ) || input->hasSkinState( Q::Editing ) ) ) + { + return input->subControlRect( Q::InputText ); + } + else + { + return {}; + } + } + else if ( subControl == Q::SupportingText ) + { + if( input->supportingText().isEmpty() ) + { + return {}; + } + else + { + auto rect = contentsRect; + + const auto margins = input->marginHint( subControl ); + const auto h = margins.top() + input->effectiveFontHeight( subControl ) + margins.bottom(); + rect.setTop( rect.bottom() - h ); + + rect.setLeft( rect.left() + margins.left() ); + + return rect; + } + } + else if ( subControl == Q::CharacterCount ) + { + if( input->maxLength() == 32767 ) // magic number hardcoded in qquicktextinput.cpp + { + return {}; + } + else + { + auto rect = contentsRect; + + const auto margins = input->marginHint( subControl ); + const auto h = margins.top() + input->effectiveFontHeight( subControl ) + margins.bottom(); + rect.setTop( rect.bottom() - h ); + + const QFontMetricsF fm( input->effectiveFont( subControl ) ); + const auto w = qskHorizontalAdvance( fm, maxLengthString( input ) ); + rect.setRight( rect.right() - margins.right() ); + rect.setLeft( rect.right() - ( margins.left() + w + margins.right() ) ); + + return rect; + } + } + else if ( subControl == Q::TrailingIconRipple ) + { + const auto cursorPos = input->effectiveSkinHint( + Q::TrailingIconRipple | Q::Hovered | QskAspect::Metric | QskAspect::Position ).toPointF(); + const auto trailingIconRect = input->subControlRect( Q::TrailingIcon ); + + if( !cursorPos.isNull() && trailingIconRect.contains( cursorPos ) ) + { + const auto size = input->strutSizeHint( subControl ); + QRectF rect( { 0, 0 }, size ); + + rect.moveCenter( trailingIconRect.center() ); + + return rect; + } + else + { + return {}; + } + } + else if ( subControl == Q::TrailingIcon ) + { + if( input->symbolHint( subControl ).isEmpty() ) + { + return {}; + } + else + { + const auto margins = input->marginHint( subControl ); + const auto panelRect = input->subControlRect( Q::Panel ); + auto rect = panelRect.marginsRemoved( margins ); + + const auto size = input->strutSizeHint( subControl ); + rect.setHeight( size.height() ); + rect.moveCenter( { rect.center().x(), panelRect.center().y() } ); + rect.setLeft( rect.right() - size.width() ); + + return rect; + } + } + + return Inherited::subControlRect( skinnable, contentsRect, subControl ); +} + +QSizeF QskMaterial3TextInputSkinlet::adjustSizeHint( const QskSkinnable* skinnable, Qt::SizeHint which, const QSizeF& oldHint ) const +{ + if ( which != Qt::PreferredSize ) + return QSizeF(); + + auto hint = oldHint; + + const auto input = static_cast< const Q* >( skinnable ); + + if( input->emphasis() == Q::LowEmphasis ) + { + const auto fontHeight = input->effectiveFontHeight( Q::LabelText | Q::Focused ); + hint.rheight() += fontHeight / 2; + } + + if( !input->supportingText().isEmpty() || input->maxLength() != 32767 ) // magic number hardcoded in qquicktextinput.cpp + { + const auto margins = input->marginHint( Q::SupportingText ); + hint.rheight() += margins.top() + input->effectiveFontHeight( Q::SupportingText ) + margins.bottom(); + } + + return hint; +} + +QSGNode* QskMaterial3TextInputSkinlet::updateSubNode( + const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const +{ + const auto input = static_cast< const Q* >( skinnable ); + + switch ( nodeRole ) + { + case PanelRole: + { + if ( !input->hasPanel() ) + return nullptr; + + if( input->emphasis() == Q::LowEmphasis + && ( input->hasSkinState( Q::TextPopulated ) + || input->hasSkinState( Q::Focused ) + || input->hasSkinState( Q::Editing ) ) ) + { + const auto shape = skinnable->boxShapeHint( Q::Panel ); + const auto borderMetrics = skinnable->boxBorderMetricsHint( Q::Panel ); + const auto borderColors = outlineColors( input ); + const auto gradient = input->gradientHint( Q::Panel ); + + return updateBoxNode( skinnable, node, input->subControlRect( Q::Panel ), + shape, borderMetrics, borderColors, gradient ); + } + else + { + return updateBoxNode( skinnable, node, Q::Panel ); + } + } + + case LeadingIconRole: + { + return updateSymbolNode( skinnable, node, Q::LeadingIcon ); + } + + case SupportingTextRole: + { + return updateTextNode( skinnable, node, input->supportingText(), Q::SupportingText ); + } + + case CharacterCountRole: + { + return updateTextNode( skinnable, node, maxLengthString( input ), Q::CharacterCount ); + } + + case TrailingIconRippleRole: + { + return updateBoxNode( skinnable, node, Q::TrailingIconRipple ); + } + + case TrailingIconRole: + { + return updateSymbolNode( skinnable, node, Q::TrailingIcon ); + } + } + + return Inherited::updateSubNode( skinnable, nodeRole, node ); +} + +#include "moc_QskMaterial3TextInputSkinlet.cpp" diff --git a/designsystems/material3/QskMaterial3TextInputSkinlet.h b/designsystems/material3/QskMaterial3TextInputSkinlet.h new file mode 100644 index 00000000..54bc47c7 --- /dev/null +++ b/designsystems/material3/QskMaterial3TextInputSkinlet.h @@ -0,0 +1,41 @@ +/****************************************************************************** + * QSkinny - Copyright (C) The authors + * SPDX-License-Identifier: BSD-3-Clause + *****************************************************************************/ + +#ifndef QSK_MATERIAL3_INPUT_SKINLET_H +#define QSK_MATERIAL3_INPUT_SKINLET_H + +#include "QskTextInputSkinlet.h" + +class QSK_EXPORT QskMaterial3TextInputSkinlet : public QskTextInputSkinlet +{ + Q_GADGET + + using Inherited = QskTextInputSkinlet; + + public: + enum NodeRole + { + LeadingIconRole = Inherited::RoleCount, + SupportingTextRole, + TrailingIconRippleRole, + TrailingIconRole, + CharacterCountRole + }; + + Q_INVOKABLE QskMaterial3TextInputSkinlet( QskSkin* = nullptr ); + ~QskMaterial3TextInputSkinlet() override; + + QRectF subControlRect( const QskSkinnable*, + const QRectF& rect, QskAspect::Subcontrol ) const override; + + QSizeF adjustSizeHint( const QskSkinnable*, + Qt::SizeHint, const QSizeF& ) const override; + + protected: + QSGNode* updateSubNode( const QskSkinnable*, + quint8 nodeRole, QSGNode* ) const override; +}; + +#endif diff --git a/examples/gallery/inputs/InputPage.cpp b/examples/gallery/inputs/InputPage.cpp index d539433f..c87ec609 100644 --- a/examples/gallery/inputs/InputPage.cpp +++ b/examples/gallery/inputs/InputPage.cpp @@ -96,7 +96,7 @@ namespace auto input = new QskTextInput( this ); input->setEmphasis( emphasis ); input->setLeadingIcon( {} ); - input->setLabelText( "no hint text" ); + input->setHintText( "no label text" ); } { diff --git a/src/controls/QskTextInput.cpp b/src/controls/QskTextInput.cpp index 3971545e..e821bf4e 100644 --- a/src/controls/QskTextInput.cpp +++ b/src/controls/QskTextInput.cpp @@ -7,6 +7,7 @@ #include "QskEvent.h" #include "QskFontRole.h" #include "QskQuick.h" +#include "QskTextInputSkinlet.h" QSK_QT_PRIVATE_BEGIN #include @@ -567,19 +568,8 @@ QSizeF QskTextInput::layoutSizeHint( Qt::SizeHint which, const QSizeF& ) const hint = hint.expandedTo( strutSizeHint( Panel ) ); } - if( emphasis() == LowEmphasis ) - { - const auto fontHeight = effectiveFontHeight( LabelText | Focused ); - hint.rheight() += fontHeight / 2; - } - - if( !supportingText().isEmpty() || maxLength() != 32767 ) // magic number hardcoded in qquicktextinput.cpp - { - const auto margins = marginHint( SupportingText ); - hint.rheight() += margins.top() + effectiveFontHeight( SupportingText ) + margins.bottom(); - } - - return hint; + const auto textInputSkinlet = static_cast< const QskTextInputSkinlet* >( effectiveSkinlet() ); + return textInputSkinlet->adjustSizeHint( this, which, hint ); } void QskTextInput::updateLayout() diff --git a/src/controls/QskTextInputSkinlet.cpp b/src/controls/QskTextInputSkinlet.cpp index 2e48074b..8f56bca6 100644 --- a/src/controls/QskTextInputSkinlet.cpp +++ b/src/controls/QskTextInputSkinlet.cpp @@ -15,61 +15,13 @@ using Q = QskTextInput; -namespace -{ - QString maxLengthString( const QskTextInput* input ) - { - QString s = QString::number( input->inputText().length() ) - + " / " + QString::number( input->maxLength() ); - return s; - } - - // We need to "cut a hole" in the upper gradient for the label text: - QskBoxBorderColors outlineColors( const QskTextInput* input ) - { - auto borderColors = input->boxBorderColorsHint( Q::Panel ); - auto topGradient = borderColors.gradientAt( Qt::TopEdge ); - - const auto panelRect = input->subControlRect( Q::Panel ); - - const auto margins = input->marginHint( Q::LabelText ); - const auto iconMargins = input->marginHint( Q::LeadingIcon ); - - const auto x1 = iconMargins.left() - margins.left(); - const auto r1 = x1 / panelRect.width(); - - const auto w = qskHorizontalAdvance( input->effectiveFont( Q::LabelText ), input->labelText() ); - - const auto x2 = x1 + w + margins.right(); - const auto r2 = x2 / panelRect.width(); - - topGradient.setStops( { - { 0.0, topGradient.startColor() }, - { r1, topGradient.startColor() }, - { r1, Qt::transparent }, - { r2, Qt::transparent }, - { r2, topGradient.startColor() }, - { 1.0, topGradient.startColor() } - } ); - - borderColors.setGradientAt( Qt::TopEdge, topGradient ); - - return borderColors; - } -} - QskTextInputSkinlet::QskTextInputSkinlet( QskSkin* skin ) : Inherited( skin ) { setNodeRoles( { PanelRole, - LeadingIconRole, LabelTextRole, HintTextRole, - SupportingTextRole, - CharacterCountRole, - TrailingIconRippleRole, - TrailingIconRole, } ); } @@ -84,70 +36,7 @@ QRectF QskTextInputSkinlet::subControlRect( const QskSkinnable* skinnable, if ( subControl == Q::Panel ) { - auto rect = contentsRect; - - if( input->emphasis() == Q::LowEmphasis ) - { - const auto fontHeight = input->effectiveFontHeight( Q::LabelText | Q::Focused ); - rect.setY( fontHeight / 2 ); - } - - - const auto h = input->strutSizeHint( subControl ).height(); - rect.setHeight( h ); - - return rect; - } - else if ( subControl == Q::LeadingIcon ) - { - if( input->symbolHint( subControl ).isEmpty() ) - { - return {}; - } - else - { - const auto margins = input->marginHint( subControl ); - const auto panelRect = input->subControlRect( Q::Panel ); - auto rect = panelRect.marginsRemoved( margins ); - - const auto size = input->strutSizeHint( subControl ); - rect.setSize( size ); - rect.moveCenter( { rect.center().x(), panelRect.center().y() } ); - - return rect; - } - } - else if ( subControl == Q::LabelText ) - { - const auto inputRect = input->subControlRect( Q::InputText ); - - if( !input->inputText().isEmpty() - || input->hasSkinState( Q::Focused ) - || input->hasSkinState( Q::Editing ) ) - { - const auto margins = input->marginHint( subControl ); - auto rect = inputRect; - const QFontMetricsF fm( input->effectiveFont( subControl ) ); - - if( input->emphasis() == Q::LowEmphasis ) - { - const auto iconMargins = input->marginHint( Q::LeadingIcon ); - rect.setX( iconMargins.left() ); - rect.setY( 0 ); - } - else - { - rect.setY( contentsRect.y() + margins.top() ); - } - - rect.setHeight( fm.height() ); - - return rect; - } - else - { - return inputRect; - } + return contentsRect; } else if ( subControl == Q::InputText ) { @@ -173,103 +62,15 @@ QRectF QskTextInputSkinlet::subControlRect( const QskSkinnable* skinnable, return rect; } - else if ( subControl == Q::HintText ) - { - if( !input->hasSkinState( Q::TextPopulated ) - && ( input->hasSkinState( Q::Focused ) || input->hasSkinState( Q::Editing ) ) ) - { - return input->subControlRect( Q::InputText ); - } - else - { - return {}; - } - } - else if ( subControl == Q::SupportingText ) - { - if( input->supportingText().isEmpty() ) - { - return {}; - } - else - { - auto rect = contentsRect; - - const auto margins = input->marginHint( subControl ); - const auto h = margins.top() + input->effectiveFontHeight( subControl ) + margins.bottom(); - rect.setTop( rect.bottom() - h ); - - rect.setLeft( rect.left() + margins.left() ); - - return rect; - } - } - else if ( subControl == Q::CharacterCount ) - { - if( input->maxLength() == 32767 ) // magic number hardcoded in qquicktextinput.cpp - { - return {}; - } - else - { - auto rect = contentsRect; - - const auto margins = input->marginHint( subControl ); - const auto h = margins.top() + input->effectiveFontHeight( subControl ) + margins.bottom(); - rect.setTop( rect.bottom() - h ); - - const QFontMetricsF fm( input->effectiveFont( subControl ) ); - const auto w = qskHorizontalAdvance( fm, maxLengthString( input ) ); - rect.setRight( rect.right() - margins.right() ); - rect.setLeft( rect.right() - ( margins.left() + w + margins.right() ) ); - - return rect; - } - } - else if ( subControl == Q::TrailingIconRipple ) - { - const auto cursorPos = input->effectiveSkinHint( - Q::TrailingIconRipple | Q::Hovered | QskAspect::Metric | QskAspect::Position ).toPointF(); - const auto trailingIconRect = input->subControlRect( Q::TrailingIcon ); - - if( !cursorPos.isNull() && trailingIconRect.contains( cursorPos ) ) - { - const auto size = input->strutSizeHint( subControl ); - QRectF rect( { 0, 0 }, size ); - - rect.moveCenter( trailingIconRect.center() ); - - return rect; - } - else - { - return {}; - } - } - else if ( subControl == Q::TrailingIcon ) - { - if( input->symbolHint( subControl ).isEmpty() ) - { - return {}; - } - else - { - const auto margins = input->marginHint( subControl ); - const auto panelRect = input->subControlRect( Q::Panel ); - auto rect = panelRect.marginsRemoved( margins ); - - const auto size = input->strutSizeHint( subControl ); - rect.setHeight( size.height() ); - rect.moveCenter( { rect.center().x(), panelRect.center().y() } ); - rect.setLeft( rect.right() - size.width() ); - - return rect; - } - } return Inherited::subControlRect( skinnable, contentsRect, subControl ); } +QSizeF QskTextInputSkinlet::adjustSizeHint( const QskSkinnable*, Qt::SizeHint, const QSizeF& hint ) const +{ + return hint; +} + QSGNode* QskTextInputSkinlet::updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const { @@ -282,28 +83,7 @@ QSGNode* QskTextInputSkinlet::updateSubNode( if ( !input->hasPanel() ) return nullptr; - if( input->emphasis() == Q::LowEmphasis - && ( input->hasSkinState( Q::TextPopulated ) - || input->hasSkinState( Q::Focused ) - || input->hasSkinState( Q::Editing ) ) ) - { - const auto shape = skinnable->boxShapeHint( Q::Panel ); - const auto borderMetrics = skinnable->boxBorderMetricsHint( Q::Panel ); - const auto borderColors = outlineColors( input ); - const auto gradient = input->gradientHint( Q::Panel ); - - return updateBoxNode( skinnable, node, input->subControlRect( Q::Panel ), - shape, borderMetrics, borderColors, gradient ); - } - else - { - return updateBoxNode( skinnable, node, Q::Panel ); - } - } - - case LeadingIconRole: - { - return updateSymbolNode( skinnable, node, Q::LeadingIcon ); + return updateBoxNode( skinnable, node, Q::Panel ); } case LabelTextRole: @@ -315,26 +95,6 @@ QSGNode* QskTextInputSkinlet::updateSubNode( { return updateTextNode( skinnable, node, input->hintText(), Q::HintText ); } - - case SupportingTextRole: - { - return updateTextNode( skinnable, node, input->supportingText(), Q::SupportingText ); - } - - case CharacterCountRole: - { - return updateTextNode( skinnable, node, maxLengthString( input ), Q::CharacterCount ); - } - - case TrailingIconRippleRole: - { - return updateBoxNode( skinnable, node, Q::TrailingIconRipple ); - } - - case TrailingIconRole: - { - return updateSymbolNode( skinnable, node, Q::TrailingIcon ); - } } return Inherited::updateSubNode( skinnable, nodeRole, node ); diff --git a/src/controls/QskTextInputSkinlet.h b/src/controls/QskTextInputSkinlet.h index 904bb05c..eec8dbc1 100644 --- a/src/controls/QskTextInputSkinlet.h +++ b/src/controls/QskTextInputSkinlet.h @@ -18,13 +18,8 @@ class QSK_EXPORT QskTextInputSkinlet : public QskSkinlet enum NodeRole { PanelRole, - LeadingIconRole, LabelTextRole, HintTextRole, - SupportingTextRole, - TrailingIconRippleRole, - TrailingIconRole, - CharacterCountRole, RoleCount }; @@ -34,6 +29,9 @@ class QSK_EXPORT QskTextInputSkinlet : public QskSkinlet QRectF subControlRect( const QskSkinnable*, const QRectF& rect, QskAspect::Subcontrol ) const override; + virtual QSizeF adjustSizeHint( const QskSkinnable*, + Qt::SizeHint, const QSizeF& ) const; + protected: QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override;