rebased from master
This commit is contained in:
parent
5c95cbd64a
commit
5da7aa8211
|
@ -3,5 +3,7 @@
|
|||
<file>icons/qvg/checkmark.qvg</file>
|
||||
<file>icons/qvg/chevron_down.qvg</file>
|
||||
<file>icons/qvg/chevron_up.qvg</file>
|
||||
<file>icons/qvg/dismiss.qvg</file>
|
||||
<file>icons/qvg/search.qvg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -1873,6 +1873,22 @@ void Editor::setupTextFieldMetrics()
|
|||
|
||||
setAlignment( Q::Placeholder, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
setFontRole( Q::Placeholder, fontRole( Q::Text ) );
|
||||
|
||||
setStrutSize( Q::Header, { -1, 30_px } );
|
||||
setFontRole( Q::Header, Fluent2::Body );
|
||||
|
||||
setAlignment( Q::Text, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
setFontRole( Q::Text, Fluent2::Body );
|
||||
|
||||
|
||||
setSymbol( Q::Icon, symbol( "search" ) );
|
||||
setSymbol( Q::Button, symbol( "dismiss" ) );
|
||||
|
||||
for ( const auto subControl : { Q::Icon, Q::Button } )
|
||||
{
|
||||
setMargin( subControl, 2_px );
|
||||
setStrutSize( subControl, 16_px, 16_px );
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::setupTextFieldColors(
|
||||
|
@ -1880,54 +1896,66 @@ void Editor::setupTextFieldColors(
|
|||
{
|
||||
using Q = QskTextField;
|
||||
using A = QskAspect;
|
||||
using W = QskFluent2Skin;
|
||||
|
||||
const auto& pal = theme.palette;
|
||||
|
||||
const auto text = Q::Text | section;
|
||||
|
||||
#if 1
|
||||
setColor( text, pal.fillColor.text.primary );
|
||||
setColor( text | Q::Selected, pal.fillColor.textOnAccent.selectedText );
|
||||
setColor( text | Q::Disabled, pal.fillColor.text.disabled );
|
||||
#endif
|
||||
setColor( Q::Text | section | Q::Selected, pal.fillColor.textOnAccent.selectedText );
|
||||
setColor( Q::TextPanel | section | Q::Selected, pal.fillColor.accent.selectedTextBackground );
|
||||
|
||||
setColor( Q::TextPanel | Q::Selected, pal.fillColor.accent.selectedTextBackground );
|
||||
setColor( Q::Placeholder, pal.fillColor.text.secondary );
|
||||
setColor( Q::Placeholder | section, pal.fillColor.text.secondary );
|
||||
|
||||
setColor( Q::Header | section, pal.fillColor.text.primary );
|
||||
|
||||
for( const auto state : { A::NoState, Q::Hovered, Q::Focused, Q::Editing, Q::Disabled } )
|
||||
{
|
||||
QRgb panelColor, borderColor1, borderColor2;
|
||||
QRgb panelColor, borderColor1, borderColor2, textColor;
|
||||
|
||||
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.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.primary;
|
||||
}
|
||||
else if ( state == Q::Disabled )
|
||||
{
|
||||
panelColor = pal.fillColor.control.disabled;
|
||||
borderColor1 = borderColor2 = pal.strokeColor.control.defaultColor;
|
||||
textColor = pal.fillColor.text.disabled;
|
||||
}
|
||||
else // A::NoState
|
||||
{
|
||||
panelColor = pal.fillColor.control.defaultColor;
|
||||
borderColor1 = pal.elevation.textControl.border[0];
|
||||
borderColor2 = pal.elevation.textControl.border[1];
|
||||
textColor = pal.fillColor.text.primary;
|
||||
}
|
||||
|
||||
const auto panel = Q::TextPanel | section | state;
|
||||
const auto text = Q::Text | section | state;
|
||||
|
||||
panelColor = rgbSolid( panelColor, pal.background.solid.base );
|
||||
|
||||
setGradient( panel, panelColor );
|
||||
setBoxBorderGradient( panel, borderColor1, borderColor2, panelColor );
|
||||
|
||||
setColor( text, textColor );
|
||||
}
|
||||
|
||||
for ( const auto subControl : { Q::Icon, Q::Button } )
|
||||
{
|
||||
const auto aspect = subControl | section;
|
||||
|
||||
setGraphicRole( aspect, W::GraphicRoleFillColorTextSecondary );
|
||||
setGraphicRole( aspect | Q::Disabled, W::GraphicRoleFillColorTextDisabled );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,13 +20,41 @@ QskFluent2TextFieldSkinlet::~QskFluent2TextFieldSkinlet()
|
|||
QRectF QskFluent2TextFieldSkinlet::subControlRect( const QskSkinnable* skinnable,
|
||||
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
if ( subControl == Q::TextPanel )
|
||||
{
|
||||
auto rect = subControlRect( skinnable, contentsRect, Q::Panel );
|
||||
rect.setY( rect.bottom() - skinnable->strutSizeHint( subControl ).height() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
if ( subControl == Q::Header )
|
||||
{
|
||||
const auto rect = subControlRect( skinnable, contentsRect, Q::TextPanel );
|
||||
const auto h = skinnable->effectiveFontHeight( Q::Header );
|
||||
|
||||
return QRectF( rect.x(), rect.y() - h, rect.width(), h );
|
||||
}
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
QSizeF QskFluent2TextFieldSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||
Qt::SizeHint which, const QSizeF& constraint ) const
|
||||
{
|
||||
return Inherited::sizeHint( skinnable, which, constraint );
|
||||
if ( which != Qt::PreferredSize )
|
||||
return QSizeF();
|
||||
|
||||
auto hint = Inherited::sizeHint( skinnable, which, constraint );
|
||||
|
||||
const auto textField = static_cast< const QskTextField* >( skinnable );
|
||||
if ( !textField->headerText().isEmpty() )
|
||||
{
|
||||
// spacing ???
|
||||
hint.rheight() += textField->strutSizeHint( Q::Header ).height();
|
||||
}
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
#include "moc_QskFluent2TextFieldSkinlet.cpp"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.08859 2.21569L2.14645 2.14645C2.32001 1.97288 2.58944 1.9536 2.78431 2.08859L2.85355 2.14645L6 5.293L9.14645 2.14645C9.34171 1.95118 9.65829 1.95118 9.85355 2.14645C10.0488 2.34171 10.0488 2.65829 9.85355 2.85355L6.707 6L9.85355 9.14645C10.0271 9.32001 10.0464 9.58944 9.91141 9.78431L9.85355 9.85355C9.67999 10.0271 9.41056 10.0464 9.21569 9.91141L9.14645 9.85355L6 6.707L2.85355 9.85355C2.65829 10.0488 2.34171 10.0488 2.14645 9.85355C1.95118 9.65829 1.95118 9.34171 2.14645 9.14645L5.293 6L2.14645 2.85355C1.97288 2.67999 1.9536 2.41056 2.08859 2.21569L2.14645 2.14645L2.08859 2.21569Z" fill="#212121"/>
|
||||
</svg>
|
After Width: | Height: | Size: 722 B |
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 1C2.79086 1 1 2.79086 1 5C1 7.20914 2.79086 9 5 9C5.92417 9 6.77513 8.68659 7.45241 8.16025L10.1455 10.8533C10.3408 11.0486 10.6574 11.0486 10.8526 10.8533C11.0479 10.6581 11.0479 10.3415 10.8526 10.1462L8.15961 7.45323C8.68633 6.77583 9 5.92454 9 5C9 2.79086 7.20914 1 5 1ZM2 5C2 3.34315 3.34315 2 5 2C6.65685 2 8 3.34315 8 5C8 6.65685 6.65685 8 5 8C3.34315 8 2 6.65685 2 5Z" fill="#212121"/>
|
||||
</svg>
|
After Width: | Height: | Size: 509 B |
|
@ -17,5 +17,8 @@
|
|||
<file>icons/qvg/arrow_drop_up.qvg</file>
|
||||
<file>icons/qvg/check.qvg</file>
|
||||
<file>icons/qvg/remove.qvg</file>
|
||||
<file>icons/qvg/text_field_search.qvg</file>
|
||||
<file>icons/qvg/text_field_cancel.qvg</file>
|
||||
<file>icons/qvg/text_field_error.qvg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -478,43 +478,161 @@ void Editor::setupTextArea()
|
|||
void Editor::setupTextField()
|
||||
{
|
||||
using Q = QskTextField;
|
||||
using M3 = QskMaterial3Skin;
|
||||
using A = QskAspect;
|
||||
|
||||
setColor( Q::Text, m_pal.onSurface );
|
||||
setFontRole( Q::Text, BodyLarge );
|
||||
setColor( Q::Text | Q::Disabled, m_pal.onSurface38 );
|
||||
|
||||
setStrutSize( Q::Panel, -1.0, 56_px );
|
||||
setPadding( Q::Panel, { 12_px, 8_px, 12_px, 8_px } );
|
||||
setGradient( Q::Panel, m_pal.surfaceVariant );
|
||||
setColor( Q::TextPanel | Q::Selected, m_pal.primary12 );
|
||||
setBoxShape( Q::Panel, m_pal.shapeExtraSmallTop );
|
||||
setBoxBorderMetrics( Q::Panel, { 0, 0, 0, 1_px } );
|
||||
setBoxBorderColors( Q::Panel, m_pal.onSurfaceVariant );
|
||||
setSpacing( Q::Panel, 8_px );
|
||||
const auto Outlined = static_cast< A::Variation >( Q::OutlinedStyle );
|
||||
const auto Filled = static_cast< A::Variation >( Q::FilledStyle );
|
||||
|
||||
const auto hoverColor = flattenedColor( m_pal.onSurfaceVariant,
|
||||
m_pal.surfaceVariant, m_pal.hoverOpacity );
|
||||
setGradient( Q::Panel | Q::Hovered, hoverColor );
|
||||
const auto activeStates = Q::Focused | Q::Editing;
|
||||
|
||||
const auto focusColor = flattenedColor( m_pal.onSurfaceVariant,
|
||||
m_pal.surfaceVariant, m_pal.focusOpacity );
|
||||
setGradient( Q::Panel | Q::Focused, focusColor );
|
||||
{
|
||||
// Text
|
||||
|
||||
// ### Also add a pressed state
|
||||
setAnimation( Q::TextPanel | A::Color, qskDuration );
|
||||
setAnimation( Q::TextPanel | A::Metric, qskDuration );
|
||||
}
|
||||
|
||||
setFontRole( Q::Text, BodyLarge );
|
||||
for ( const auto variation : { A::NoVariation, Filled, Outlined } )
|
||||
{
|
||||
const auto Panel = Q::Panel | variation;
|
||||
|
||||
setAlignment( Q::Placeholder, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
QskBoxBorderMetrics borderMetrics[2];
|
||||
|
||||
const auto disabledPanelColor = QskRgb::toTransparentF( m_pal.onSurface, 0.04 );
|
||||
setGradient( Q::Panel | Q::Disabled, disabledPanelColor );
|
||||
setBoxBorderColors( Q::Panel | Q::Disabled, m_pal.onSurface38 );
|
||||
if ( variation == Filled )
|
||||
{
|
||||
setBoxShape( Panel, m_pal.shapeExtraSmallTop );
|
||||
|
||||
// PlaceholderText
|
||||
borderMetrics[0].setBottom( 1 );
|
||||
borderMetrics[1].setBottom( 2 );
|
||||
|
||||
setColor( Q::Placeholder, color( Q::Text ) );
|
||||
setFontRole( Q::Placeholder, BodyLarge );
|
||||
setAlignment( Q::Placeholder, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
setBoxBorderColors( Panel, m_pal.onSurfaceVariant );
|
||||
|
||||
setGradient( Panel, m_pal.surfaceVariant );
|
||||
|
||||
setGradient( Panel | Q::Hovered,
|
||||
m_pal.hoverColor( m_pal.onSurfaceVariant, m_pal.surfaceVariant ),
|
||||
{ QskStateCombination::CombinationNoState, activeStates | Q::Error } );
|
||||
|
||||
setGradient( Panel | Q::Disabled,
|
||||
QskRgb::toTransparentF( m_pal.onSurface, 0.04 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
setBoxShape( Panel, m_pal.shapeExtraSmall );
|
||||
|
||||
borderMetrics[0].setWidths( 1 );
|
||||
borderMetrics[1].setWidths( 2 );
|
||||
|
||||
setBoxBorderColors( Panel, m_pal.outline );
|
||||
}
|
||||
|
||||
if ( variation != A::NoVariation )
|
||||
{
|
||||
setStrutSize( Panel, -1.0, 56_px );
|
||||
setPadding( Panel, 16_px, 8_px, 16_px, 8_px );
|
||||
}
|
||||
|
||||
setBoxBorderMetrics( Panel, borderMetrics[0] );
|
||||
setBoxBorderMetrics( Panel, borderMetrics[1], activeStates | Q::Hovered );
|
||||
setBoxBorderMetrics( Panel | Q::Error, borderMetrics[1], activeStates | Q::Hovered );
|
||||
|
||||
setBoxBorderColors( Panel, m_pal.primary, activeStates );
|
||||
setBoxBorderColors( Panel | Q::Hovered, m_pal.primary, activeStates );
|
||||
setBoxBorderColors( Panel | Q::Hovered, m_pal.onSurface );
|
||||
setBoxBorderColors( Panel | Q::Disabled, m_pal.onSurface38 );
|
||||
|
||||
setBoxBorderColors( Panel | Q::Error, m_pal.error,
|
||||
{ QskStateCombination::CombinationNoState, activeStates | Q::Hovered } );
|
||||
|
||||
setColor( Q::TextPanel | variation | Q::Selected, m_pal.primary12 );
|
||||
}
|
||||
|
||||
// Icon
|
||||
|
||||
setStrutSize( Q::Icon, { 24_px, 24_px } );
|
||||
setMargin( Q::Icon, 2_px );
|
||||
setSymbol( Q::Icon, symbol( "text_field_search" ) );
|
||||
|
||||
setGraphicRole( Q::Icon, M3::GraphicRoleOnSurface );
|
||||
setGraphicRole( Q::Icon | Q::Error, M3::GraphicRoleOnSurfaceVariant );
|
||||
|
||||
setGraphicRole( Q::Icon | Q::Disabled, M3::GraphicRoleOnSurface38 );
|
||||
|
||||
{
|
||||
setAlignment( Q::Header, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
setFontRole( Q::Header, BodySmall );
|
||||
|
||||
setColor( Q::Header, m_pal.onSurfaceVariant );
|
||||
setColor( Q::Header, m_pal.primary, activeStates );
|
||||
setColor( Q::Header | Q::Error, m_pal.error );
|
||||
setColor( Q::Header | Q::Disabled, m_pal.onSurface38 );
|
||||
}
|
||||
|
||||
#if 0
|
||||
setMargin( Q::Header | Outlined, 4_px, 0, 4_px, 0 );
|
||||
#endif
|
||||
|
||||
for ( const auto subControl : { Q::Text, Q::Placeholder } )
|
||||
{
|
||||
setAlignment( subControl, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
|
||||
setFontRole( subControl, BodyLarge );
|
||||
|
||||
setColor( subControl | Q::Disabled, m_pal.onSurface38 );
|
||||
|
||||
if ( subControl == Q::Text )
|
||||
{
|
||||
setColor( subControl, m_pal.onSurface );
|
||||
}
|
||||
else
|
||||
{
|
||||
setColor( subControl | Q::Error, m_pal.error );
|
||||
setColor( subControl | Q::Error | Q::Hovered, m_pal.onSurface );
|
||||
}
|
||||
}
|
||||
|
||||
// Button
|
||||
|
||||
setStrutSize( Q::Button, { 24_px, 24_px } );
|
||||
setMargin( Q::Button, 2_px );
|
||||
setGraphicRole( Q::Button, M3::GraphicRoleOnSurfaceVariant );
|
||||
setSymbol( Q::Button, symbol( "text_field_cancel" ) );
|
||||
|
||||
setSymbol( Q::Button | Q::Error, symbol( "text_field_error" ) );
|
||||
setGraphicRole( Q::Button | Q::Error, M3::GraphicRoleError );
|
||||
setGraphicRole( Q::Button | Q::Error | Q::Hovered, M3::GraphicRoleOnErrorContainer );
|
||||
|
||||
setGraphicRole( Q::Button | Q::Disabled, M3::GraphicRoleOnSurface38 );
|
||||
|
||||
// ButtonPanel
|
||||
|
||||
setStrutSize( Q::ButtonPanel, { 45_px, 45_px } );
|
||||
setGradient( Q::ButtonPanel | Q::Hovered, m_pal.onSurface8 );
|
||||
setBoxShape( Q::ButtonPanel, 100, Qt::RelativeSize );
|
||||
|
||||
|
||||
// SupportingText
|
||||
|
||||
setMargin( Q::Footer, { 16_px, 4_px, 16_px, 4_px } );
|
||||
setColor( Q::Footer, m_pal.onSurfaceVariant );
|
||||
setColor( Q::Footer | Q::Error, m_pal.error );
|
||||
setFontRole( Q::Footer, BodySmall );
|
||||
setAlignment( Q::Footer, Qt::AlignLeft | Qt::AlignVCenter );
|
||||
|
||||
setColor( Q::Footer | Q::Disabled, m_pal.onSurface38 );
|
||||
|
||||
// CharacterCount
|
||||
|
||||
setMargin( Q::CharacterCount, margin( Q::Footer ) );
|
||||
setColor( Q::CharacterCount, color( Q::Footer ) );
|
||||
setFontRole( Q::CharacterCount, fontRole( Q::Footer ) );
|
||||
setAlignment( Q::CharacterCount, Qt::AlignRight | Qt::AlignVCenter );
|
||||
setColor( Q::CharacterCount | Q::Disabled, color( Q::Footer | Q::Disabled ) );
|
||||
}
|
||||
|
||||
void Editor::setupProgressBar()
|
||||
|
@ -1619,6 +1737,7 @@ QskMaterial3Theme::QskMaterial3Theme( QskSkin::ColorScheme colorScheme,
|
|||
elevation2 = QskShadowMetrics( -2, 8, { 0, 2 } );
|
||||
elevation3 = QskShadowMetrics( -1, 11, { 0, 2 } );
|
||||
|
||||
shapeExtraSmall = QskBoxShapeMetrics( 4_px, 4_px, 4_px, 4_px );
|
||||
shapeExtraSmallTop = QskBoxShapeMetrics( 4_px, 4_px, 0, 0 );
|
||||
}
|
||||
|
||||
|
@ -1745,6 +1864,7 @@ void QskMaterial3Skin::setupGraphicFilters( const QskMaterial3Theme& theme )
|
|||
setGraphicColor( GraphicRoleOnPrimaryContainer, theme.onPrimaryContainer );
|
||||
setGraphicColor( GraphicRoleOnSecondaryContainer, theme.onSecondaryContainer );
|
||||
setGraphicColor( GraphicRoleOnError, theme.onError );
|
||||
setGraphicColor( GraphicRoleOnErrorContainer, theme.onErrorContainer );
|
||||
setGraphicColor( GraphicRoleOnSurface, theme.onSurface );
|
||||
setGraphicColor( GraphicRoleOnSurface38, theme.onSurface38 );
|
||||
setGraphicColor( GraphicRoleOnSurfaceVariant, theme.onSurfaceVariant );
|
||||
|
|
|
@ -107,6 +107,7 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Theme
|
|||
|
||||
qreal stateOpacity( int state ) const;
|
||||
|
||||
QskBoxShapeMetrics shapeExtraSmall;
|
||||
QskBoxShapeMetrics shapeExtraSmallTop;
|
||||
};
|
||||
|
||||
|
@ -119,7 +120,9 @@ class QSK_MATERIAL3_EXPORT QskMaterial3Skin : public QskSkin
|
|||
public:
|
||||
enum GraphicRole
|
||||
{
|
||||
GraphicRoleError,
|
||||
GraphicRoleOnError,
|
||||
GraphicRoleOnErrorContainer,
|
||||
GraphicRoleOnPrimary,
|
||||
GraphicRoleOnPrimaryContainer,
|
||||
GraphicRoleOnSecondaryContainer,
|
||||
|
|
|
@ -4,11 +4,82 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskMaterial3TextFieldSkinlet.h"
|
||||
#include "QskTextField.h"
|
||||
#include "QskMaterial3Skin.h"
|
||||
|
||||
#include <QskTextField.h>
|
||||
#include <QskBoxBorderColors.h>
|
||||
#include <QskBoxBorderMetrics.h>
|
||||
#include <QskFunctions.h>
|
||||
|
||||
#include <QFontMetricsF>
|
||||
|
||||
using Q = QskTextField;
|
||||
|
||||
namespace
|
||||
{
|
||||
const int spacingV = 0; // skin hint !
|
||||
|
||||
QString effectiveHeaderText( const QskTextField* textField )
|
||||
{
|
||||
if ( !textField->isEditing() && textField->text().isEmpty() )
|
||||
return QString();
|
||||
|
||||
return textField->headerText();
|
||||
}
|
||||
|
||||
inline bool hasCharacterCount( const QskTextField* textField )
|
||||
{
|
||||
// magic number hardcoded in qquicktextinput.cpp
|
||||
return textField->maxLength() < 32767;
|
||||
}
|
||||
|
||||
inline bool hasBottomText( const QskTextField* textField )
|
||||
{
|
||||
return !textField->footerText().isEmpty() || hasCharacterCount( textField );
|
||||
}
|
||||
|
||||
QString maxLengthString( const QskTextField* textField )
|
||||
{
|
||||
QString s = QString::number( textField->text().length() )
|
||||
+ " / " + QString::number( textField->maxLength() );
|
||||
return s;
|
||||
}
|
||||
|
||||
// We need to "cut a hole" in the upper gradient for the label text:
|
||||
QskBoxBorderColors outlineColors( const QskBoxBorderColors& colors,
|
||||
const QRectF& rect, const QRectF& clipRect )
|
||||
{
|
||||
auto gradient = colors.gradientAt( Qt::TopEdge );
|
||||
|
||||
const auto margin = 6; // ->skin
|
||||
auto s1 = ( clipRect.left() - margin - rect.left() ) / rect.width();
|
||||
auto s2 = ( clipRect.right() - rect.left() ) / rect.width();
|
||||
|
||||
s1 = qBound( 0.0, s1, 1.0 );
|
||||
s2 = qBound( 0.0, s2, 1.0 );
|
||||
|
||||
// not correct, when gradient is not monochrome !!!
|
||||
|
||||
gradient.setStops( {
|
||||
{ 0.0, gradient.startColor() },
|
||||
{ s1, gradient.startColor() },
|
||||
{ s1, Qt::transparent },
|
||||
{ s2, Qt::transparent },
|
||||
{ s2, gradient.endColor() },
|
||||
{ 1.0, gradient.endColor() }
|
||||
} );
|
||||
|
||||
auto borderColors = colors;
|
||||
borderColors.setGradientAt( Qt::TopEdge, gradient );
|
||||
|
||||
return borderColors;
|
||||
}
|
||||
}
|
||||
|
||||
QskMaterial3TextFieldSkinlet::QskMaterial3TextFieldSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
appendNodeRoles( { SupportingTextRole, CharacterCountRole } );
|
||||
}
|
||||
|
||||
QskMaterial3TextFieldSkinlet::~QskMaterial3TextFieldSkinlet()
|
||||
|
@ -18,19 +89,209 @@ QskMaterial3TextFieldSkinlet::~QskMaterial3TextFieldSkinlet()
|
|||
QRectF QskMaterial3TextFieldSkinlet::subControlRect( const QskSkinnable* skinnable,
|
||||
const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
const auto textField = static_cast< const Q* >( skinnable );
|
||||
|
||||
if ( subControl == Q::Panel )
|
||||
{
|
||||
auto rect = contentsRect;
|
||||
|
||||
if( textField->style() == QskTextField::OutlinedStyle )
|
||||
{
|
||||
const auto h = textField->effectiveFontHeight( Q::Header );
|
||||
rect.setTop( rect.top() + 0.5 * h );
|
||||
}
|
||||
|
||||
if( hasBottomText( textField ) )
|
||||
{
|
||||
const auto margins = textField->marginHint( Q::Footer );
|
||||
|
||||
const auto h = textField->effectiveFontHeight( Q::Footer )
|
||||
+ margins.top() + margins.bottom();
|
||||
|
||||
rect.setHeight( rect.height() - h );
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
if ( subControl == Q::Text )
|
||||
{
|
||||
auto rect = Inherited::subControlRect( skinnable, contentsRect, Q::Text );
|
||||
|
||||
if ( !rect.isEmpty() && ( textField->style() == QskTextField::FilledStyle ) )
|
||||
{
|
||||
const auto text = effectiveHeaderText( textField );
|
||||
if ( !text.isEmpty() )
|
||||
{
|
||||
const auto h = skinnable->effectiveFontHeight( Q::Header );
|
||||
rect.translate( 0.0, 0.5 * ( h + spacingV ) );
|
||||
}
|
||||
}
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
if ( subControl == Q::Header )
|
||||
{
|
||||
const auto text = effectiveHeaderText( textField );
|
||||
if( text.isEmpty() )
|
||||
return QRectF();
|
||||
|
||||
const QFontMetrics fm( textField->effectiveFont( Q::Header ) );
|
||||
const auto textSize = fm.size( Qt::TextSingleLine | Qt::TextExpandTabs, text );
|
||||
|
||||
qreal x, y;
|
||||
|
||||
if ( textField->style() == QskTextField::FilledStyle )
|
||||
{
|
||||
const auto r = subControlRect( skinnable, contentsRect, Q::Text );
|
||||
|
||||
x = r.left();
|
||||
y = r.top() - spacingV - textSize.height();
|
||||
}
|
||||
else if ( textField->style() == QskTextField::OutlinedStyle )
|
||||
{
|
||||
const auto r = subControlRect( skinnable, contentsRect, Q::Panel );
|
||||
|
||||
x = r.left() + skinnable->paddingHint( Q::Panel ).left();
|
||||
y = r.top() - 0.5 * textSize.height();
|
||||
}
|
||||
|
||||
return QRectF( x, y, textSize.width(), textSize.height() );
|
||||
}
|
||||
|
||||
if ( subControl == Q::Footer )
|
||||
{
|
||||
if( !textField->footerText().isEmpty() )
|
||||
{
|
||||
auto rect = contentsRect;
|
||||
|
||||
const auto margins = textField->marginHint( subControl );
|
||||
const auto h = textField->effectiveFontHeight( subControl )
|
||||
+ margins.top() + margins.bottom();
|
||||
|
||||
rect.setTop( rect.bottom() - h );
|
||||
rect.setLeft( rect.left() + margins.left() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
if ( subControl == Q::CharacterCount )
|
||||
{
|
||||
if( hasCharacterCount( textField ) )
|
||||
{
|
||||
auto rect = contentsRect;
|
||||
|
||||
const auto margins = textField->marginHint( subControl );
|
||||
const auto h = textField->effectiveFontHeight( subControl )
|
||||
+ margins.top() + margins.bottom();
|
||||
|
||||
rect.setTop( rect.bottom() - h );
|
||||
|
||||
const QFontMetricsF fm( textField->effectiveFont( subControl ) );
|
||||
const auto w = qskHorizontalAdvance( fm, maxLengthString( textField ) );
|
||||
rect.setRight( rect.right() - margins.right() );
|
||||
rect.setLeft( rect.right() - ( margins.left() + w + margins.right() ) );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
QSGNode* QskMaterial3TextFieldSkinlet::updateSubNode(
|
||||
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||
{
|
||||
const auto textField = static_cast< const Q* >( skinnable );
|
||||
|
||||
switch ( nodeRole )
|
||||
{
|
||||
case PanelRole:
|
||||
{
|
||||
if( ( textField->style() == QskTextField::OutlinedStyle ) &&
|
||||
!effectiveHeaderText( textField ).isEmpty() )
|
||||
{
|
||||
auto clipRect = textField->subControlRect( Q::Header );
|
||||
if ( !clipRect.isEmpty() )
|
||||
{
|
||||
const auto subControl = Q::Panel;
|
||||
|
||||
const auto panelRect = textField->subControlRect( subControl );
|
||||
|
||||
auto borderColors = textField->boxBorderColorsHint( subControl );
|
||||
borderColors = outlineColors( borderColors, panelRect, clipRect );
|
||||
|
||||
return updateBoxNode( skinnable, node,
|
||||
panelRect,
|
||||
skinnable->boxShapeHint( subControl ),
|
||||
skinnable->boxBorderMetricsHint( subControl ),
|
||||
borderColors,
|
||||
skinnable->gradientHint( subControl ) );
|
||||
}
|
||||
}
|
||||
|
||||
return updateBoxNode( skinnable, node, Q::Panel );
|
||||
}
|
||||
|
||||
case CharacterCountRole:
|
||||
{
|
||||
return updateTextNode( skinnable, node,
|
||||
maxLengthString( textField ), Q::CharacterCount );
|
||||
}
|
||||
|
||||
case HeaderRole:
|
||||
{
|
||||
return updateTextNode( skinnable, node,
|
||||
effectiveHeaderText( textField ), Q::Header );
|
||||
}
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
}
|
||||
|
||||
QSizeF QskMaterial3TextFieldSkinlet::sizeHint( const QskSkinnable* skinnable,
|
||||
Qt::SizeHint which, const QSizeF& constraint ) const
|
||||
{
|
||||
return Inherited::sizeHint( skinnable, which, constraint );
|
||||
if ( which != Qt::PreferredSize )
|
||||
return QSizeF();
|
||||
|
||||
auto hint = Inherited::sizeHint( skinnable, which, constraint );
|
||||
|
||||
const auto textField = static_cast< const QskTextField* >( skinnable );
|
||||
|
||||
if( textField->style() != QskTextField::PlainStyle )
|
||||
hint.rheight() += textField->effectiveFontHeight( Q::Header ) + spacingV;
|
||||
|
||||
if( hasBottomText( textField ) )
|
||||
{
|
||||
const auto margins = textField->marginHint( Q::Footer );
|
||||
hint.rheight() += textField->effectiveFontHeight( Q::Footer )
|
||||
+ margins.top() + margins.bottom();
|
||||
}
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
QString QskMaterial3TextFieldSkinlet::effectivePlaceholderText(
|
||||
const QskTextField* textField ) const
|
||||
{
|
||||
if ( textField->text().isEmpty() &&
|
||||
!( textField->isReadOnly() || textField->isEditing() ) )
|
||||
{
|
||||
auto text = textField->placeholderText();
|
||||
if ( text.isEmpty() )
|
||||
text = textField->headerText();
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
return QString();
|
||||
}
|
||||
|
||||
#include "moc_QskMaterial3TextFieldSkinlet.cpp"
|
||||
|
|
|
@ -16,6 +16,12 @@ class QSK_MATERIAL3_EXPORT QskMaterial3TextFieldSkinlet : public QskTextFieldSki
|
|||
using Inherited = QskTextFieldSkinlet;
|
||||
|
||||
public:
|
||||
enum NodeRole : quint8
|
||||
{
|
||||
SupportingTextRole = Inherited::RoleCount,
|
||||
CharacterCountRole
|
||||
};
|
||||
|
||||
Q_INVOKABLE QskMaterial3TextFieldSkinlet( QskSkin* = nullptr );
|
||||
~QskMaterial3TextFieldSkinlet() override;
|
||||
|
||||
|
@ -28,6 +34,8 @@ class QSK_MATERIAL3_EXPORT QskMaterial3TextFieldSkinlet : public QskTextFieldSki
|
|||
protected:
|
||||
QSGNode* updateSubNode( const QskSkinnable*,
|
||||
quint8 nodeRole, QSGNode* ) const override;
|
||||
|
||||
QString effectivePlaceholderText( const QskTextField* ) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 0C4.47 0 0 4.47 0 10C0 15.53 4.47 20 10 20C15.53 20 20 15.53 20 10C20 4.47 15.53 0 10 0ZM10 18C5.59 18 2 14.41 2 10C2 5.59 5.59 2 10 2C14.41 2 18 5.59 18 10C18 14.41 14.41 18 10 18ZM10 8.59L13.59 5L15 6.41L11.41 10L15 13.59L13.59 15L10 11.41L6.41 15L5 13.59L8.59 10L5 6.41L6.41 5L10 8.59Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 462 B |
|
@ -0,0 +1,4 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM9 15V13H11V15H9ZM9 5V11H11V5H9Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 294 B |
|
@ -0,0 +1,4 @@
|
|||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.76 10.27L17.49 16L16 17.49L10.27 11.76C9.2 12.53 7.91 13 6.5 13C2.91 13 0 10.09 0 6.5C0 2.91 2.91 0 6.5 0C10.09 0 13 2.91 13 6.5C13 7.91 12.53 9.2 11.76 10.27ZM6.5 2C4.01 2 2 4.01 2 6.5C2 8.99 4.01 11 6.5 11C8.99 11 11 8.99 11 6.5C11 4.01 8.99 2 6.5 2Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 426 B |
|
@ -10,6 +10,12 @@
|
|||
#include <QskTextArea.h>
|
||||
#include <QskTextField.h>
|
||||
#include <QskSpinBox.h>
|
||||
#include <QskComboBox.h>
|
||||
#include <QskSeparator.h>
|
||||
#include <QskFunctions.h>
|
||||
#include <QskFontRole.h>
|
||||
|
||||
#include <QFontMetricsF>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -66,37 +72,62 @@ namespace
|
|||
{
|
||||
public:
|
||||
TextInputBox( QQuickItem* parent = nullptr )
|
||||
: QskLinearBox( Qt::Horizontal, parent )
|
||||
: QskLinearBox( Qt::Horizontal, 3, parent )
|
||||
{
|
||||
setSpacing( 20 );
|
||||
setDefaultAlignment( Qt::AlignHCenter | Qt::AlignTop );
|
||||
|
||||
{
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setText( "John Doe" );
|
||||
field->setPlaceholderText( "<Name>" );
|
||||
|
||||
#if 0
|
||||
connect( field, &QskTextField::textChanged,
|
||||
[field]() { qDebug() << "Text:" << field->text(); } );
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setReadOnly( true );
|
||||
field->setText( "Read Only" );
|
||||
field->setSizePolicy( Qt::Horizontal, QskSizePolicy::MinimumExpanding );
|
||||
}
|
||||
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setMaxLength( 5 );
|
||||
field->setEchoMode( QskTextField::Password );
|
||||
field->setPlaceholderText( "<password>" );
|
||||
}
|
||||
auto field = new QskTextField( this );
|
||||
field->setHeaderText( "Name" );
|
||||
field->setText( "John Doe" );
|
||||
field->setPlaceholderText( "<Name>" );
|
||||
field->setFooterText( "Required *" );
|
||||
}
|
||||
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setHeaderText( "Nickname" );
|
||||
field->setPlaceholderText( "<Nickname>" );
|
||||
field->setFooterText( "Optional" );
|
||||
}
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setIcon( {} );
|
||||
field->setPlaceholderText( "<no header>" );
|
||||
}
|
||||
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setSkinStateFlag( QskTextField::Error );
|
||||
field->setText( "Error Text" );
|
||||
field->setHeaderText( "error" );
|
||||
field->setPlaceholderText( "<text>" );
|
||||
field->setFooterText( "error text" );
|
||||
}
|
||||
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setReadOnly( true );
|
||||
field->setText( "Read Only" );
|
||||
field->setHeaderText( "read only" );
|
||||
field->setSizePolicy( Qt::Horizontal, QskSizePolicy::MinimumExpanding );
|
||||
}
|
||||
|
||||
{
|
||||
auto field = new QskTextField( this );
|
||||
field->setMaxLength( 15 );
|
||||
field->setHeaderText( "password" );
|
||||
field->setEchoMode( QskTextField::Password );
|
||||
field->setPlaceholderText( "<password>" );
|
||||
}
|
||||
}
|
||||
|
||||
void setStyle( int style )
|
||||
{
|
||||
auto textFields = findChildren< QskTextField* >();
|
||||
for ( auto field : textFields )
|
||||
field->setStyle( static_cast< QskTextField::Style >( style ) );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -120,6 +151,18 @@ namespace
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
class StyleComboBox : public QskComboBox
|
||||
{
|
||||
public:
|
||||
StyleComboBox( QQuickItem* parent = nullptr )
|
||||
: QskComboBox( parent )
|
||||
{
|
||||
addOption( QString(), "Plain" );
|
||||
addOption( QString(), "Outlined" );
|
||||
addOption( QString(), "Filled" );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
InputPage::InputPage( QQuickItem* parent )
|
||||
|
@ -146,30 +189,44 @@ InputPage::InputPage( QQuickItem* parent )
|
|||
}
|
||||
|
||||
auto spinBox = new QskSpinBox( 0.0, 100.0, 1.0 );
|
||||
spinBox->setObjectName( "SliderValueSpinBox" );
|
||||
spinBox->setSizePolicy( Qt::Horizontal, QskSizePolicy::Fixed );
|
||||
spinBox->setLayoutAlignmentHint( Qt::AlignCenter );
|
||||
|
||||
auto textInputBox = new TextInputBox();
|
||||
textInputBox->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
|
||||
|
||||
auto textAreaBox = new TextAreaBox();
|
||||
|
||||
auto vBox = new QskLinearBox( Qt::Vertical );
|
||||
vBox->setSpacing( 30 );
|
||||
vBox->setExtraSpacingAt( Qt::RightEdge | Qt::BottomEdge );
|
||||
auto separator = new QskSeparator();
|
||||
separator->setMargins( 5, 20, 5, 10 );
|
||||
|
||||
auto styleBox = new StyleComboBox();
|
||||
|
||||
auto vBox = new QskLinearBox( Qt::Vertical );
|
||||
vBox->setSpacing( 20 );
|
||||
vBox->addItem( sliders[0].continous );
|
||||
vBox->addItem( sliders[0].discrete );
|
||||
vBox->addItem( sliders[0].centered );
|
||||
vBox->addItem( spinBox );
|
||||
vBox->addItem( textInputBox );
|
||||
vBox->addItem( textAreaBox );
|
||||
|
||||
auto mainBox = new QskLinearBox( Qt::Horizontal, this );
|
||||
mainBox->setSpacing( 30 );
|
||||
mainBox->addItem( sliders[1].continous );
|
||||
mainBox->addItem( sliders[1].discrete );
|
||||
mainBox->addItem( sliders[1].centered );
|
||||
mainBox->addItem( vBox );
|
||||
auto hBox = new QskLinearBox( Qt::Horizontal );
|
||||
hBox->setSpacing( 20 );
|
||||
hBox->addItem( sliders[1].continous );
|
||||
hBox->addItem( sliders[1].discrete );
|
||||
hBox->addItem( sliders[1].centered );
|
||||
|
||||
auto gridBox = new QskGridBox( this );
|
||||
gridBox->addItem( spinBox, 0, 0 );
|
||||
gridBox->addItem( hBox, 1, 0, -1, 1 );
|
||||
gridBox->addItem( vBox, 0, 1, 1, -1 );
|
||||
gridBox->addItem( separator, 1, 1 );
|
||||
gridBox->addItem( styleBox, 1, 2 );
|
||||
gridBox->addItem( textInputBox, 2, 1, 1, -1 );
|
||||
gridBox->addItem( textAreaBox, 3, 1, 1, -1 );
|
||||
gridBox->setRowStretchFactor( 3, 10 );
|
||||
gridBox->setColumnStretchFactor( 1, 10 );
|
||||
|
||||
auto inputs = findChildren< QskBoundedValueInput* >();
|
||||
|
||||
|
@ -180,6 +237,11 @@ InputPage::InputPage( QQuickItem* parent )
|
|||
}
|
||||
|
||||
spinBox->setValue( 30.0 );
|
||||
|
||||
connect( styleBox, &QskComboBox::currentIndexChanged,
|
||||
textInputBox, &TextInputBox::setStyle );
|
||||
|
||||
styleBox->setCurrentIndex( QskTextField::OutlinedStyle );
|
||||
}
|
||||
|
||||
void InputPage::syncValues( qreal value )
|
||||
|
@ -193,8 +255,7 @@ void InputPage::syncValues( qreal value )
|
|||
|
||||
if ( qobject_cast< const QskSlider* >( sender() ) )
|
||||
{
|
||||
auto spinBoxes = findChildren< QskSpinBox* >();
|
||||
for ( auto spinBox : spinBoxes )
|
||||
if ( auto spinBox = findChild< QskSpinBox* >( "SliderValueSpinBox" ) )
|
||||
spinBox->setValue( value );
|
||||
}
|
||||
else
|
||||
|
|
|
@ -4,20 +4,43 @@
|
|||
*****************************************************************************/
|
||||
|
||||
#include "QskTextField.h"
|
||||
#include "QskEvent.h"
|
||||
#include "QskFontRole.h"
|
||||
#include "QskQuick.h"
|
||||
|
||||
QSK_SUBCONTROL( QskTextField, Panel )
|
||||
|
||||
QSK_SUBCONTROL( QskTextField, Header )
|
||||
QSK_SUBCONTROL( QskTextField, Footer )
|
||||
|
||||
QSK_SUBCONTROL( QskTextField, Icon )
|
||||
QSK_SUBCONTROL( QskTextField, ButtonPanel )
|
||||
QSK_SUBCONTROL( QskTextField, Button )
|
||||
QSK_SUBCONTROL( QskTextField, Placeholder )
|
||||
|
||||
QSK_SUBCONTROL( QskTextField, CharacterCount )
|
||||
|
||||
QSK_SYSTEM_STATE( QskTextField, Pressed, QskAspect::LastUserState << 1 )
|
||||
|
||||
class QskTextField::PrivateData
|
||||
{
|
||||
public:
|
||||
QString headerText;
|
||||
QString footerText;
|
||||
QString placeholderText;
|
||||
|
||||
Style style = PlainStyle;
|
||||
QskAspect::States buttonStates;
|
||||
};
|
||||
|
||||
QskTextField::QskTextField( QQuickItem* parent )
|
||||
: Inherited( parent )
|
||||
, m_data( new PrivateData() )
|
||||
{
|
||||
#if 1
|
||||
// character count might have changed
|
||||
connect( this, &QskTextInput::textChanged, this, &QQuickItem::update );
|
||||
#endif
|
||||
}
|
||||
|
||||
QskTextField::QskTextField( const QString& text, QQuickItem* parent )
|
||||
|
@ -30,6 +53,74 @@ QskTextField::~QskTextField()
|
|||
{
|
||||
}
|
||||
|
||||
void QskTextField::setStyle( Style style )
|
||||
{
|
||||
if ( style != m_data->style )
|
||||
{
|
||||
m_data->style = style;
|
||||
|
||||
resetImplicitSize();
|
||||
update();
|
||||
|
||||
Q_EMIT styleChanged( style );
|
||||
}
|
||||
}
|
||||
|
||||
QskTextField::Style QskTextField::style() const
|
||||
{
|
||||
return m_data->style;
|
||||
}
|
||||
|
||||
QString QskTextField::headerText() const
|
||||
{
|
||||
return m_data->headerText;
|
||||
}
|
||||
|
||||
void QskTextField::setHeaderText( const QString& text )
|
||||
{
|
||||
if ( m_data->headerText != text )
|
||||
{
|
||||
m_data->headerText = text;
|
||||
|
||||
update();
|
||||
resetImplicitSize();
|
||||
|
||||
Q_EMIT headerTextChanged( text );
|
||||
}
|
||||
}
|
||||
|
||||
QString QskTextField::footerText() const
|
||||
{
|
||||
return m_data->footerText;
|
||||
}
|
||||
|
||||
void QskTextField::setFooterText( const QString& text )
|
||||
{
|
||||
if ( m_data->footerText != text )
|
||||
{
|
||||
m_data->footerText = text;
|
||||
|
||||
update();
|
||||
resetImplicitSize();
|
||||
|
||||
Q_EMIT footerTextChanged( text );
|
||||
}
|
||||
}
|
||||
|
||||
QskGraphic QskTextField::icon() const
|
||||
{
|
||||
return symbolHint( Icon );
|
||||
}
|
||||
|
||||
void QskTextField::setIcon( const QskGraphic& icon )
|
||||
{
|
||||
if ( setSymbolHint( Icon, icon ) )
|
||||
{
|
||||
update();
|
||||
resetImplicitSize();
|
||||
}
|
||||
}
|
||||
|
||||
void QskTextField::setPlaceholderText( const QString& text )
|
||||
{
|
||||
if ( m_data->placeholderText != text )
|
||||
|
@ -44,4 +135,106 @@ QString QskTextField::placeholderText() const
|
|||
return m_data->placeholderText;
|
||||
}
|
||||
|
||||
QskAspect::Variation QskTextField::effectiveVariation() const
|
||||
{
|
||||
return static_cast< QskAspect::Variation >( m_data->style );
|
||||
}
|
||||
|
||||
void QskTextField::handleButtonClick()
|
||||
{
|
||||
clear();
|
||||
setEditing( true );
|
||||
}
|
||||
|
||||
void QskTextField::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
if( !isReadOnly() )
|
||||
{
|
||||
const auto r = subControlRect( Button );
|
||||
if ( r.contains( qskMousePosition( event ) ) )
|
||||
{
|
||||
setButtonState( Pressed, true );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Inherited::mousePressEvent( event );
|
||||
}
|
||||
|
||||
void QskTextField::mouseMoveEvent( QMouseEvent* event )
|
||||
{
|
||||
if ( m_data->buttonStates & Pressed )
|
||||
{
|
||||
const auto r = subControlRect( Button );
|
||||
setButtonState( Pressed, r.contains( qskMousePosition( event ) ) );
|
||||
return;
|
||||
}
|
||||
|
||||
Inherited::mouseMoveEvent( event );
|
||||
}
|
||||
|
||||
void QskTextField::mouseReleaseEvent( QMouseEvent* event )
|
||||
{
|
||||
if ( m_data->buttonStates & Pressed )
|
||||
{
|
||||
setButtonState( Pressed, false );
|
||||
handleButtonClick();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Inherited::mouseReleaseEvent( event );
|
||||
}
|
||||
|
||||
void QskTextField::mouseUngrabEvent()
|
||||
{
|
||||
setButtonState( Pressed, false );
|
||||
Inherited::mouseUngrabEvent();
|
||||
}
|
||||
|
||||
void QskTextField::hoverEnterEvent( QHoverEvent* event )
|
||||
{
|
||||
Inherited::hoverEnterEvent( event );
|
||||
|
||||
const auto r = subControlRect( Button );
|
||||
setButtonState( Hovered, r.contains( qskHoverPosition( event ) ) );
|
||||
}
|
||||
|
||||
void QskTextField::hoverMoveEvent( QHoverEvent* event )
|
||||
{
|
||||
const auto r = subControlRect( Button );
|
||||
setButtonState( Hovered, r.contains( qskHoverPosition( event ) ) );
|
||||
|
||||
Inherited::hoverMoveEvent( event );
|
||||
}
|
||||
|
||||
void QskTextField::hoverLeaveEvent( QHoverEvent* event )
|
||||
{
|
||||
setButtonState( Hovered, false );
|
||||
Inherited::hoverLeaveEvent( event );
|
||||
}
|
||||
|
||||
QskAspect::States QskTextField::buttonStates() const
|
||||
{
|
||||
auto states = skinStates() | m_data->buttonStates;
|
||||
|
||||
if ( !( m_data->buttonStates & Hovered ) )
|
||||
states &= ~Hovered;
|
||||
|
||||
return states;
|
||||
}
|
||||
|
||||
void QskTextField::setButtonState( QskAspect::State state, bool on )
|
||||
{
|
||||
const auto oldStates = m_data->buttonStates;
|
||||
|
||||
if ( on )
|
||||
m_data->buttonStates |= state;
|
||||
else
|
||||
m_data->buttonStates &= ~state;
|
||||
|
||||
if ( oldStates != m_data->buttonStates )
|
||||
update();
|
||||
}
|
||||
|
||||
#include "moc_QskTextField.cpp"
|
||||
|
|
|
@ -7,31 +7,88 @@
|
|||
#define QSK_TEXT_FIELD_H
|
||||
|
||||
#include "QskTextInput.h"
|
||||
#include "QskGraphic.h"
|
||||
|
||||
class QSK_EXPORT QskTextField : public QskTextInput
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QString headerText READ headerText
|
||||
WRITE setHeaderText NOTIFY headerTextChanged )
|
||||
|
||||
Q_PROPERTY( QString footerText READ footerText
|
||||
WRITE setFooterText NOTIFY footerTextChanged )
|
||||
|
||||
Q_PROPERTY( QString placeholderText READ placeholderText
|
||||
WRITE setPlaceholderText NOTIFY placeholderTextChanged )
|
||||
|
||||
Q_PROPERTY( Style style READ style
|
||||
WRITE setStyle NOTIFY styleChanged )
|
||||
|
||||
using Inherited = QskTextInput;
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel, Placeholder )
|
||||
QSK_STATES( Pressed )
|
||||
|
||||
QSK_SUBCONTROLS( Panel, Header, Footer, Placeholder,
|
||||
Icon, Button, ButtonPanel, CharacterCount )
|
||||
|
||||
enum Style : quint8
|
||||
{
|
||||
PlainStyle,
|
||||
|
||||
OutlinedStyle,
|
||||
FilledStyle
|
||||
};
|
||||
Q_ENUM( Style )
|
||||
|
||||
QskTextField( QQuickItem* parent = nullptr );
|
||||
QskTextField( const QString& text, QQuickItem* parent = nullptr );
|
||||
|
||||
~QskTextField() override;
|
||||
|
||||
void setStyle( Style );
|
||||
Style style() const;
|
||||
|
||||
void setHeaderText( const QString& );
|
||||
QString headerText() const;
|
||||
|
||||
void setFooterText( const QString& );
|
||||
QString footerText() const;
|
||||
|
||||
QskGraphic icon() const;
|
||||
void setIcon( const QskGraphic& );
|
||||
|
||||
void setPlaceholderText( const QString& );
|
||||
QString placeholderText() const;
|
||||
|
||||
QskAspect::Variation effectiveVariation() const override;
|
||||
|
||||
#if 1
|
||||
QskAspect::States buttonStates() const;
|
||||
#endif
|
||||
|
||||
Q_SIGNALS:
|
||||
void headerTextChanged( const QString& );
|
||||
void footerTextChanged( const QString& );
|
||||
void placeholderTextChanged( const QString& );
|
||||
void styleChanged( Style );
|
||||
|
||||
protected:
|
||||
void hoverEnterEvent( QHoverEvent* ) override;
|
||||
void hoverMoveEvent( QHoverEvent* ) override;
|
||||
void hoverLeaveEvent( QHoverEvent* ) override;
|
||||
|
||||
void mousePressEvent( QMouseEvent* ) override;
|
||||
void mouseMoveEvent( QMouseEvent* ) override;
|
||||
void mouseReleaseEvent( QMouseEvent* ) override;
|
||||
void mouseUngrabEvent() override;
|
||||
|
||||
virtual void handleButtonClick();
|
||||
|
||||
private:
|
||||
void setButtonState( QskAspect::State, bool );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
|
|
@ -6,12 +6,16 @@
|
|||
#include "QskTextFieldSkinlet.h"
|
||||
#include "QskTextField.h"
|
||||
|
||||
#include <qfontmetrics.h>
|
||||
|
||||
using Q = QskTextField;
|
||||
|
||||
QskTextFieldSkinlet::QskTextFieldSkinlet( QskSkin* skin )
|
||||
: Inherited( skin )
|
||||
{
|
||||
setNodeRoles( { PanelRole, TextPanelRole, PlaceholderRole } );
|
||||
setNodeRoles( { PanelRole, TextPanelRole,
|
||||
IconRole, ButtonPanelRole, ButtonRole,
|
||||
PlaceholderRole, HeaderRole, FooterRole } );
|
||||
}
|
||||
|
||||
QskTextFieldSkinlet::~QskTextFieldSkinlet()
|
||||
|
@ -28,7 +32,30 @@ QRectF QskTextFieldSkinlet::subControlRect( const QskSkinnable* skinnable,
|
|||
return skinnable->subControlContentsRect( contentsRect, Q::Panel );
|
||||
|
||||
if ( subControl == Q::Text )
|
||||
return skinnable->subControlContentsRect( contentsRect, Q::TextPanel );
|
||||
{
|
||||
auto rect = skinnable->subControlContentsRect( contentsRect, Q::TextPanel );
|
||||
|
||||
if( !skinnable->symbolHint( Q::Icon ).isEmpty() )
|
||||
{
|
||||
const auto r = subControlRect( skinnable, contentsRect, Q::Icon );
|
||||
if ( !r.isEmpty() )
|
||||
rect.setLeft( r.right() );
|
||||
}
|
||||
|
||||
if( !skinnable->symbolHint( Q::Button ).isEmpty() )
|
||||
{
|
||||
const auto r = subControlRect( skinnable, contentsRect, Q::Button );
|
||||
if( !r.isEmpty() )
|
||||
rect.setRight( r.left() );
|
||||
}
|
||||
|
||||
const auto h = skinnable->effectiveFontHeight( Q::Text );
|
||||
rect.setTop( rect.center().y() - 0.5 * h );
|
||||
rect.setHeight( h );
|
||||
rect = rect.marginsAdded( skinnable->marginHint( Q::Text ) );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
if ( subControl == Q::Placeholder )
|
||||
{
|
||||
|
@ -39,6 +66,60 @@ QRectF QskTextFieldSkinlet::subControlRect( const QskSkinnable* skinnable,
|
|||
return QRectF();
|
||||
}
|
||||
|
||||
if ( subControl == Q::Icon )
|
||||
{
|
||||
if( !skinnable->symbolHint( subControl ).isEmpty() )
|
||||
{
|
||||
const auto panelRect = skinnable->subControlContentsRect(
|
||||
contentsRect, Q::TextPanel );
|
||||
|
||||
auto rect = panelRect;
|
||||
|
||||
rect.setSize( skinnable->strutSizeHint( subControl ) );
|
||||
rect.moveCenter( { rect.center().x(), panelRect.center().y() } );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
if ( subControl == Q::ButtonPanel )
|
||||
{
|
||||
const auto textField = static_cast< const QskTextField* >( skinnable );
|
||||
if ( textField->buttonStates() & Q::Hovered )
|
||||
{
|
||||
const auto r = subControlRect( skinnable, contentsRect, Q::Button );
|
||||
|
||||
QRectF rect( QPointF(), skinnable->strutSizeHint( subControl ) );
|
||||
rect.moveCenter( r.center() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
if ( subControl == Q::Button )
|
||||
{
|
||||
if( !skinnable->symbolHint( subControl ).isEmpty() )
|
||||
{
|
||||
const auto panelRect = skinnable->subControlContentsRect(
|
||||
contentsRect, Q::TextPanel );
|
||||
|
||||
auto rect = panelRect;
|
||||
|
||||
const auto size = skinnable->strutSizeHint( subControl );
|
||||
rect.setHeight( size.height() );
|
||||
rect.moveCenter( { rect.center().x(), panelRect.center().y() } );
|
||||
rect.setLeft( rect.right() - size.width() );
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
return QRectF();
|
||||
}
|
||||
|
||||
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
||||
}
|
||||
|
||||
|
@ -76,6 +157,27 @@ QSGNode* QskTextFieldSkinlet::updateSubNode(
|
|||
textField->alignmentHint( subControl, Qt::AlignLeft ),
|
||||
options, text, subControl );
|
||||
}
|
||||
|
||||
case HeaderRole:
|
||||
{
|
||||
return updateTextNode( skinnable, node,
|
||||
textField->headerText(), Q::Header );
|
||||
}
|
||||
|
||||
case FooterRole:
|
||||
{
|
||||
return updateTextNode( skinnable, node,
|
||||
textField->footerText(), Q::Footer );
|
||||
}
|
||||
|
||||
case IconRole:
|
||||
return updateSymbolNode( skinnable, node, Q::Icon );
|
||||
|
||||
case ButtonPanelRole:
|
||||
return updateBoxNode( skinnable, node, Q::ButtonPanel );
|
||||
|
||||
case ButtonRole:
|
||||
return updateSymbolNode( skinnable, node, Q::Button );
|
||||
}
|
||||
|
||||
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||
|
|
|
@ -21,7 +21,14 @@ class QSK_EXPORT QskTextFieldSkinlet : public QskSkinlet
|
|||
{
|
||||
PanelRole,
|
||||
TextPanelRole,
|
||||
|
||||
HeaderRole,
|
||||
FooterRole,
|
||||
PlaceholderRole,
|
||||
IconRole,
|
||||
ButtonPanelRole,
|
||||
ButtonRole,
|
||||
|
||||
RoleCount
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue