diff --git a/examples/gallery/inputs/InputPage.cpp b/examples/gallery/inputs/InputPage.cpp index ed0c9367..7cf72289 100644 --- a/examples/gallery/inputs/InputPage.cpp +++ b/examples/gallery/inputs/InputPage.cpp @@ -76,8 +76,10 @@ namespace field->setText( "John Doe" ); field->setPlaceholderText( "" ); -connect( field, &QskTextField::textChanged, - [field]() { qDebug() << "Text:" << field->text(); } ); +#if 0 + connect( field, &QskTextField::textChanged, + [field]() { qDebug() << "Text:" << field->text(); } ); +#endif } @@ -107,11 +109,11 @@ connect( field, &QskTextField::textChanged, setSpacing( 20 ); { - auto textArea = new QskTextArea( "here enter longer text", this ); + auto textArea = new QskTextArea( "here enter longer text\nwith multiple lines", this ); textArea->setWrapMode( QskTextOptions::Wrap ); textArea->setPlaceholderText( "placeholder text" ); -#if 1 +#if 0 connect( textArea, &QskTextArea::textChanged, this, [textArea]() { qDebug() << "Text:" << textArea->text(); } ); #endif @@ -200,12 +202,6 @@ void InputPage::syncValues( qreal value ) auto sliders = findChildren< QskSlider* >(); for ( auto slider : sliders ) slider->setValue( value ); - -#if 1 - auto textEdits = findChildren< QskTextEdit* >(); - for ( auto edit : textEdits ) - edit->setText( QString::number( value ) ); -#endif } blockUpdates = false; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 94684cd6..63c5dd30 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -198,6 +198,7 @@ endif() list(APPEND HEADERS controls/QskAbstractButton.h controls/QskAbstractTextInput.h + controls/QskAbstractTextInputSkinlet.h controls/QskAnimationHint.h controls/QskAnimator.h controls/QskMainView.h @@ -287,11 +288,9 @@ list(APPEND HEADERS controls/QskTextArea.h controls/QskTextAreaSkinlet.h controls/QskTextEdit.h - controls/QskTextEditSkinlet.h controls/QskTextField.h controls/QskTextFieldSkinlet.h controls/QskTextInput.h - controls/QskTextInputSkinlet.h controls/QskTextLabel.h controls/QskTextLabelSkinlet.h controls/QskVariantAnimator.h @@ -308,6 +307,7 @@ list(APPEND PRIVATE_HEADERS list(APPEND SOURCES controls/QskAbstractButton.cpp controls/QskAbstractTextInput.cpp + controls/QskAbstractTextInputSkinlet.cpp controls/QskAnimator.cpp controls/QskAnimationHint.cpp controls/QskMainView.cpp @@ -400,11 +400,9 @@ list(APPEND SOURCES controls/QskTextArea.cpp controls/QskTextAreaSkinlet.cpp controls/QskTextEdit.cpp - controls/QskTextEditSkinlet.cpp controls/QskTextField.cpp controls/QskTextFieldSkinlet.cpp controls/QskTextInput.cpp - controls/QskTextInputSkinlet.cpp controls/QskTextLabel.cpp controls/QskTextLabelSkinlet.cpp controls/QskVariantAnimator.cpp diff --git a/src/controls/QskAbstractTextInput.cpp b/src/controls/QskAbstractTextInput.cpp index c4040ceb..da22e3ea 100644 --- a/src/controls/QskAbstractTextInput.cpp +++ b/src/controls/QskAbstractTextInput.cpp @@ -24,11 +24,24 @@ QSK_QT_PRIVATE_BEGIN QSK_QT_PRIVATE_END QSK_SUBCONTROL( QskAbstractTextInput, Text ) +QSK_SUBCONTROL( QskAbstractTextInput, TextPanel ) QSK_SYSTEM_STATE( QskAbstractTextInput, ReadOnly, QskAspect::FirstSystemState << 1 ) QSK_SYSTEM_STATE( QskAbstractTextInput, Editing, QskAspect::FirstSystemState << 2 ) QSK_SYSTEM_STATE( QskAbstractTextInput, Selected, QskAspect::FirstSystemState << 3 ) +/* + QQuickText-Edit/Input are beasts of several thousands lines of code, + we can't ( and don't want to ) reimplement them. + Instead we implement wrappers with some extra functionality to + have it in line with the QSkinny framework. + + For some reason Qt development decided not to introduce a common + base class for QQuickText-Edit/input and implemented large parts + of the API twice. To avoid that we also have to copy those parts to our + wrappers we need the ugly implementation you find in this file. + */ + static inline QVariant qskInputMethodQuery( const QQuickItem* item, Qt::InputMethodQuery query, QVariant argument ) { @@ -109,12 +122,14 @@ class QskAbstractTextInput::PrivateData #define INPUT_INVOKE_ARG(func, arg) \ ( m_data->textInput ? m_data->textInput->func( arg ) : m_data->textEdit->func( arg ) ) -#define INPUT_CONNECT( func ) \ +#define INPUT_CONNECT2( func1, func2 ) \ m_data->textInput \ - ? connect( m_data->textInput, &QQuickTextInput::func, this, &QskAbstractTextInput::func ) \ - : connect( m_data->textEdit, &QQuickTextEdit::func, this, &QskAbstractTextInput::func ) + ? connect( m_data->textInput, &QQuickTextInput::func1, this, &QskAbstractTextInput::func2 ) \ + : connect( m_data->textEdit, &QQuickTextEdit::func1, this, &QskAbstractTextInput::func2 ) -#define INPUT_CONNECT1( func, get ) \ +#define INPUT_CONNECT1( func ) INPUT_CONNECT2( func, func ) + +#define INPUT_CONNECT_ARG( func, get ) \ do \ { \ auto f = [this]() { Q_EMIT func( get() ); }; \ @@ -148,22 +163,24 @@ void QskAbstractTextInput::setup( QQuickItem* wrappedInput ) m_data->textInput = qobject_cast< QQuickTextInput* >( wrappedInput ); m_data->textEdit = qobject_cast< QQuickTextEdit* >( wrappedInput ); - INPUT_CONNECT( textChanged ); - INPUT_CONNECT( preeditTextChanged ); - INPUT_CONNECT( readOnlyChanged ); - INPUT_CONNECT( overwriteModeChanged ); - INPUT_CONNECT( cursorVisibleChanged ); - INPUT_CONNECT1( cursorPositionChanged, cursorPosition ); - INPUT_CONNECT( selectByMouseChanged ); - INPUT_CONNECT1( persistentSelectionChanged, persistentSelection ); - INPUT_CONNECT1( wrapModeChanged, wrapMode ); + INPUT_CONNECT1( textChanged ); + INPUT_CONNECT1( preeditTextChanged ); + INPUT_CONNECT1( selectedTextChanged ); + INPUT_CONNECT1( readOnlyChanged ); + INPUT_CONNECT1( overwriteModeChanged ); + INPUT_CONNECT1( cursorVisibleChanged ); + INPUT_CONNECT_ARG( cursorPositionChanged, cursorPosition ); + INPUT_CONNECT1( selectByMouseChanged ); + INPUT_CONNECT_ARG( persistentSelectionChanged, persistentSelection ); + INPUT_CONNECT_ARG( wrapModeChanged, wrapMode ); + INPUT_CONNECT2( contentSizeChanged, resetImplicitSize ); - INPUT_CONNECT1( canUndoChanged, canUndo ); - INPUT_CONNECT1( canRedoChanged, canRedo ); - INPUT_CONNECT1( canPasteChanged, canPaste ); + INPUT_CONNECT_ARG( canUndoChanged, canUndo ); + INPUT_CONNECT_ARG( canRedoChanged, canRedo ); + INPUT_CONNECT_ARG( canPasteChanged, canPaste ); - INPUT_CONNECT1( inputMethodHintsChanged, inputMethodHints ); - INPUT_CONNECT1( inputMethodComposingChanged, isInputMethodComposing ); + INPUT_CONNECT_ARG( inputMethodHintsChanged, inputMethodHints ); + INPUT_CONNECT_ARG( inputMethodComposingChanged, isInputMethodComposing ); /* Other properties offered from QQuickTextInput/QQuickTextEdit: @@ -196,9 +213,8 @@ void QskAbstractTextInput::setup( QQuickItem* wrappedInput ) - selectionStartChanged; - selectionEndChanged; - - selectedTextChanged; - Maybe there is a better API for the selection TODO ... + Do we need this ? - mouseSelectionModeChanged @@ -208,7 +224,7 @@ void QskAbstractTextInput::setup( QQuickItem* wrappedInput ) This signal should never be emitted as it happens on events ( focusOut, commit keys ) that are handled in - QskAbstractTextInput and indicated with editicgChanged( bool ); + QskAbstractTextInput and are indicated with editingChanged( bool ); ( Maybe having an assertion TODO ... ) - contentSizeChanged @@ -239,46 +255,59 @@ void QskAbstractTextInput::setActivationModes( ActivationModes modes ) } } +#if 1 + +// stupid code forwarding calls 1:1 to the wrapped item + bool QskAbstractTextInput::selectByMouse() const -{ - return INPUT_INVOKE( selectByMouse ); -} + { return INPUT_INVOKE( selectByMouse ); } void QskAbstractTextInput::setSelectByMouse( bool on ) -{ - INPUT_INVOKE_ARG( setSelectByMouse, on ); -} + { INPUT_INVOKE_ARG( setSelectByMouse, on ); } bool QskAbstractTextInput::persistentSelection() const -{ - return INPUT_INVOKE( persistentSelection ); -} + { return INPUT_INVOKE( persistentSelection ); } void QskAbstractTextInput::setPersistentSelection( bool on ) -{ - INPUT_INVOKE_ARG( setPersistentSelection, on ); -} + { INPUT_INVOKE_ARG( setPersistentSelection, on ); } int QskAbstractTextInput::length() const -{ - return INPUT_INVOKE( length ); -} + { return INPUT_INVOKE( length ); } QString QskAbstractTextInput::text() const -{ - return INPUT_INVOKE( text ); -} + { return INPUT_INVOKE( text ); } void QskAbstractTextInput::setText( const QString& text ) -{ - INPUT_INVOKE_ARG( setText, text ); -} + { INPUT_INVOKE_ARG( setText, text ); } QString QskAbstractTextInput::preeditText() const -{ - return INPUT_INVOKE( preeditText ); -} + { return INPUT_INVOKE( preeditText ); } +QString QskAbstractTextInput::selectedText() const + { return INPUT_INVOKE( selectedText ); } + +bool QskAbstractTextInput::isInputMethodComposing() const + { return INPUT_INVOKE( isInputMethodComposing ); } + +bool QskAbstractTextInput::overwriteMode() const + { return INPUT_INVOKE( overwriteMode ); } + +void QskAbstractTextInput::setOverwriteMode( bool on ) + { INPUT_INVOKE_ARG( setOverwriteMode, on ); } + +int QskAbstractTextInput::cursorPosition() const + { return INPUT_INVOKE( cursorPosition ); } + +void QskAbstractTextInput::setCursorPosition( int pos ) + { INPUT_INVOKE_ARG( setCursorPosition, pos ); } + +bool QskAbstractTextInput::isCursorVisible() const + { return INPUT_INVOKE( isCursorVisible ); } + +void QskAbstractTextInput::setCursorVisible( bool on ) + { INPUT_INVOKE_ARG( setCursorVisible, on ); } + +bool QskAbstractTextInput::isReadOnly() const { return INPUT_INVOKE( isReadOnly ); } bool QskAbstractTextInput::canUndo() const { return INPUT_INVOKE( canUndo ); } bool QskAbstractTextInput::canRedo() const { return INPUT_INVOKE( canRedo ); } bool QskAbstractTextInput::canPaste() const { return INPUT_INVOKE( canPaste ); } @@ -292,6 +321,14 @@ void QskAbstractTextInput::paste() { INPUT_INVOKE( paste ); } void QskAbstractTextInput::undo() { INPUT_INVOKE( undo ); } void QskAbstractTextInput::redo() { INPUT_INVOKE( redo ); } +#endif + +bool QskAbstractTextInput::hasSelectedText() const +{ + return INPUT_INVOKE( selectionEnd ) > INPUT_INVOKE( selectionStart ); +} + + void QskAbstractTextInput::setFontRole( const QskFontRole& role ) { if ( setFontRoleHint( Text, role ) ) @@ -546,11 +583,6 @@ void QskAbstractTextInput::inputMethodEvent( QInputMethodEvent* event ) } } -bool QskAbstractTextInput::isReadOnly() const -{ - return INPUT_INVOKE( isReadOnly ); -} - void QskAbstractTextInput::setReadOnly( bool on ) { if ( on == isReadOnly() ) @@ -575,11 +607,6 @@ void QskAbstractTextInput::setReadOnly( bool on ) setSkinStateFlag( ReadOnly, on ); } -bool QskAbstractTextInput::isInputMethodComposing() const -{ - return INPUT_INVOKE( isInputMethodComposing ); -} - bool QskAbstractTextInput::isEditing() const { return hasSkinState( Editing ); @@ -599,36 +626,6 @@ void QskAbstractTextInput::setEditing( bool on ) Q_EMIT editingChanged( on ); } -bool QskAbstractTextInput::overwriteMode() const -{ - return INPUT_INVOKE( overwriteMode ); -} - -void QskAbstractTextInput::setOverwriteMode( bool on ) -{ - INPUT_INVOKE_ARG( setOverwriteMode, on ); -} - -int QskAbstractTextInput::cursorPosition() const -{ - return INPUT_INVOKE( cursorPosition ); -} - -void QskAbstractTextInput::setCursorPosition( int pos ) -{ - INPUT_INVOKE_ARG( setCursorPosition, pos ); -} - -bool QskAbstractTextInput::isCursorVisible() const -{ - return INPUT_INVOKE( isCursorVisible ); -} - -void QskAbstractTextInput::setCursorVisible( bool on ) -{ - INPUT_INVOKE_ARG( setCursorVisible, on ); -} - void QskAbstractTextInput::setWrapMode( QskTextOptions::WrapMode wrapMode ) { if ( m_data->textInput ) @@ -664,12 +661,12 @@ void QskAbstractTextInput::setTextColor( const QColor& color ) if ( setColor( Text, color ) ) Q_EMIT textColorChanged( color ); } - + void QskAbstractTextInput::resetTextColor() { if ( resetColor( Text ) ) Q_EMIT textColorChanged( color( Text ) ); -} +} QColor QskAbstractTextInput::textColor() const { diff --git a/src/controls/QskAbstractTextInput.h b/src/controls/QskAbstractTextInput.h index 6dad1534..7167ab56 100644 --- a/src/controls/QskAbstractTextInput.h +++ b/src/controls/QskAbstractTextInput.h @@ -23,6 +23,9 @@ class QSK_EXPORT QskAbstractTextInput : public QskControl Q_PROPERTY( QString preeditText READ preeditText NOTIFY preeditTextChanged ) + Q_PROPERTY( QString selectedText READ selectedText + NOTIFY selectedTextChanged ) + Q_PROPERTY( bool editing READ isEditing WRITE setEditing NOTIFY editingChanged ) @@ -71,7 +74,7 @@ class QSK_EXPORT QskAbstractTextInput : public QskControl using Inherited = QskControl; public: - QSK_SUBCONTROLS( Text ) + QSK_SUBCONTROLS( Text, TextPanel ) QSK_STATES( ReadOnly, Editing, Selected ) enum ActivationMode @@ -93,6 +96,8 @@ class QSK_EXPORT QskAbstractTextInput : public QskControl QString text() const; QString preeditText() const; + QString selectedText() const; + bool hasSelectedText() const; int length() const; @@ -182,6 +187,7 @@ class QSK_EXPORT QskAbstractTextInput : public QskControl void inputMethodComposingChanged( bool ); void textChanged(); + void selectedTextChanged(); void textEdited( const QString& ); void preeditTextChanged(); diff --git a/src/controls/QskTextInputSkinlet.cpp b/src/controls/QskAbstractTextInputSkinlet.cpp similarity index 51% rename from src/controls/QskTextInputSkinlet.cpp rename to src/controls/QskAbstractTextInputSkinlet.cpp index edb41bc3..e06bec98 100644 --- a/src/controls/QskTextInputSkinlet.cpp +++ b/src/controls/QskAbstractTextInputSkinlet.cpp @@ -3,24 +3,22 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#include "QskTextInputSkinlet.h" -#include "QskTextInput.h" +#include "QskAbstractTextInputSkinlet.h" +#include "QskAbstractTextInput.h" -#include +using Q = QskAbstractTextInput; -using Q = QskTextInput; - -QskTextInputSkinlet::QskTextInputSkinlet( QskSkin* skin ) +QskAbstractTextInputSkinlet::QskAbstractTextInputSkinlet( QskSkin* skin ) : Inherited( skin ) { setNodeRoles( { TextPanelRole } ); } -QskTextInputSkinlet::~QskTextInputSkinlet() +QskAbstractTextInputSkinlet::~QskAbstractTextInputSkinlet() { } -QRectF QskTextInputSkinlet::subControlRect( const QskSkinnable* skinnable, +QRectF QskAbstractTextInputSkinlet::subControlRect( const QskSkinnable* skinnable, const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const { if ( subControl == Q::TextPanel ) @@ -29,10 +27,6 @@ QRectF QskTextInputSkinlet::subControlRect( const QskSkinnable* skinnable, if ( subControl == Q::Text ) { auto rect = skinnable->subControlContentsRect( contentsRect, Q::TextPanel ); - - 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; @@ -41,7 +35,7 @@ QRectF QskTextInputSkinlet::subControlRect( const QskSkinnable* skinnable, return Inherited::subControlRect( skinnable, contentsRect, subControl ); } -QSGNode* QskTextInputSkinlet::updateSubNode( +QSGNode* QskAbstractTextInputSkinlet::updateSubNode( const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const { switch ( nodeRole ) @@ -53,24 +47,21 @@ QSGNode* QskTextInputSkinlet::updateSubNode( return Inherited::updateSubNode( skinnable, nodeRole, node ); } -QSizeF QskTextInputSkinlet::sizeHint( const QskSkinnable* skinnable, - Qt::SizeHint which, const QSizeF& ) const +QSizeF QskAbstractTextInputSkinlet::sizeHint( const QskSkinnable* skinnable, + Qt::SizeHint which, const QSizeF& constraint ) const { if ( which != Qt::PreferredSize ) return QSizeF(); - const auto textInput = static_cast< const QskTextInput* >( skinnable ); + Q_UNUSED( constraint ); // TODO ... - const QFontMetricsF fm( skinnable->effectiveFont( Q::Text ) ); + const auto input = static_cast< const QskAbstractTextInput* >( skinnable ); -#if 0 - auto hint = QSizeF( textInput->unwrappedTextSize().width(), fm.height() ); -#else - auto hint = fm.size( Qt::TextSingleLine | Qt::TextExpandTabs, textInput->text() ); -#endif - - hint = skinnable->outerBoxSize( Q::TextPanel, hint ); - hint = hint.expandedTo( skinnable->strutSizeHint( Q::TextPanel ) ); + auto hint = input->unwrappedTextSize(); + hint = input->outerBoxSize( Q::TextPanel, hint ); + hint = hint.expandedTo( input->strutSizeHint( Q::TextPanel ) ); return hint; } + +#include "moc_QskAbstractTextInputSkinlet.cpp" diff --git a/src/controls/QskTextEditSkinlet.h b/src/controls/QskAbstractTextInputSkinlet.h similarity index 73% rename from src/controls/QskTextEditSkinlet.h rename to src/controls/QskAbstractTextInputSkinlet.h index c27c1169..31ad4987 100644 --- a/src/controls/QskTextEditSkinlet.h +++ b/src/controls/QskAbstractTextInputSkinlet.h @@ -3,13 +3,15 @@ * SPDX-License-Identifier: BSD-3-Clause *****************************************************************************/ -#ifndef QSK_TEXT_EDIT_SKINLET_H -#define QSK_TEXT_EDIT_SKINLET_H +#ifndef QSK_ABSTRACT_TEXT_INPUT_SKINLET_H +#define QSK_ABSTRACT_TEXT_INPUT_SKINLET_H #include "QskSkinlet.h" -class QSK_EXPORT QskTextEditSkinlet : public QskSkinlet +class QSK_EXPORT QskAbstractTextInputSkinlet : public QskSkinlet { + Q_GADGET + using Inherited = QskSkinlet; public: @@ -19,7 +21,8 @@ class QSK_EXPORT QskTextEditSkinlet : public QskSkinlet RoleCount }; - ~QskTextEditSkinlet() override; + Q_INVOKABLE QskAbstractTextInputSkinlet( QskSkin* = nullptr ); + ~QskAbstractTextInputSkinlet() override; QRectF subControlRect( const QskSkinnable*, const QRectF& rect, QskAspect::Subcontrol ) const override; @@ -28,8 +31,6 @@ class QSK_EXPORT QskTextEditSkinlet : public QskSkinlet Qt::SizeHint, const QSizeF& ) const override; protected: - QskTextEditSkinlet( QskSkin* = nullptr ); - QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; }; diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index f4eec4c7..92bc9e5a 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -25,6 +25,9 @@ #include +#include "QskAbstractTextInput.h" +#include "QskAbstractTextInputSkinlet.h" + #include "QskBox.h" #include "QskBoxSkinlet.h" @@ -103,9 +106,6 @@ #include "QskTextArea.h" #include "QskTextAreaSkinlet.h" -#include "QskTextEdit.h" -#include "QskTextEditSkinlet.h" - #include "QskTextField.h" #include "QskTextFieldSkinlet.h" @@ -194,6 +194,7 @@ QskSkin::QskSkin( QObject* parent ) { declareSkinlet< QskControl, QskSkinlet >(); + declareSkinlet< QskAbstractTextInput, QskAbstractTextInputSkinlet >(); declareSkinlet< QskBox, QskBoxSkinlet >(); declareSkinlet< QskCheckBox, QskCheckBoxSkinlet >(); declareSkinlet< QskComboBox, QskComboBoxSkinlet >(); diff --git a/src/controls/QskTextAreaSkinlet.h b/src/controls/QskTextAreaSkinlet.h index aeaa2a6d..ec38f2bd 100644 --- a/src/controls/QskTextAreaSkinlet.h +++ b/src/controls/QskTextAreaSkinlet.h @@ -6,15 +6,15 @@ #ifndef QSK_TEXT_AREA_SKINLET_H #define QSK_TEXT_AREA_SKINLET_H -#include "QskTextEditSkinlet.h" +#include "QskAbstractTextInputSkinlet.h" class QskTextArea; -class QSK_EXPORT QskTextAreaSkinlet : public QskTextEditSkinlet +class QSK_EXPORT QskTextAreaSkinlet : public QskAbstractTextInputSkinlet { Q_GADGET - using Inherited = QskTextEditSkinlet; + using Inherited = QskAbstractTextInputSkinlet; public: enum NodeRole : quint8 diff --git a/src/controls/QskTextEdit.cpp b/src/controls/QskTextEdit.cpp index 6f1b9f59..44604f62 100644 --- a/src/controls/QskTextEdit.cpp +++ b/src/controls/QskTextEdit.cpp @@ -12,6 +12,7 @@ QSK_QT_PRIVATE_BEGIN #include QSK_QT_PRIVATE_END +QSK_SUBCONTROL( QskTextEdit, Text ) QSK_SUBCONTROL( QskTextEdit, TextPanel ) /* @@ -139,24 +140,25 @@ QskTextEdit::QskTextEdit( QQuickItem* parent ) , m_data( new PrivateData() ) { m_data->wrappedEdit = new QuickTextEdit( this ); + auto wrappedEdit = m_data->wrappedEdit; - setAcceptedMouseButtons( m_data->wrappedEdit->acceptedMouseButtons() ); - m_data->wrappedEdit->setAcceptedMouseButtons( Qt::NoButton ); + setAcceptedMouseButtons( wrappedEdit->acceptedMouseButtons() ); + wrappedEdit->setAcceptedMouseButtons( Qt::NoButton ); initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding ); - setup( m_data->wrappedEdit ); + setup( wrappedEdit ); - connect( m_data->wrappedEdit, &QQuickTextEdit::lineCountChanged, + connect( wrappedEdit, &QQuickTextEdit::lineCountChanged, this, [this]() { Q_EMIT lineCountChanged( lineCount() ); } ); - connect( m_data->wrappedEdit, &QQuickTextEdit::linkActivated, + connect( wrappedEdit, &QQuickTextEdit::linkActivated, this, &QskTextEdit::linkActivated ); - connect( m_data->wrappedEdit, &QQuickTextEdit::linkHovered, + connect( wrappedEdit, &QQuickTextEdit::linkHovered, this, &QskTextEdit::linkHovered ); - connect( m_data->wrappedEdit, &QQuickTextEdit::linkActivated, + connect( wrappedEdit, &QQuickTextEdit::linkActivated, this, &QskTextEdit::linkActivated ); } @@ -164,6 +166,18 @@ QskTextEdit::~QskTextEdit() { } +QskAspect::Subcontrol QskTextEdit::substitutedSubcontrol( + QskAspect::Subcontrol subControl ) const +{ + if ( subControl == Inherited::Text ) + return Text; + + if ( subControl == Inherited::TextPanel ) + return TextPanel; + + return Inherited::substitutedSubcontrol( subControl ); +} + QUrl QskTextEdit::baseUrl() const { return m_data->wrappedEdit->baseUrl(); diff --git a/src/controls/QskTextEdit.h b/src/controls/QskTextEdit.h index b1d889f4..ef5fe512 100644 --- a/src/controls/QskTextEdit.h +++ b/src/controls/QskTextEdit.h @@ -27,7 +27,7 @@ class QSK_EXPORT QskTextEdit : public QskAbstractTextInput using Inherited = QskAbstractTextInput; public: - QSK_SUBCONTROLS( TextPanel ) + QSK_SUBCONTROLS( Text, TextPanel ) QskTextEdit( QQuickItem* parent = nullptr ); ~QskTextEdit() override; @@ -54,6 +54,10 @@ class QSK_EXPORT QskTextEdit : public QskAbstractTextInput void linkHovered( const QString& ); void linkActivated( const QString& ); + protected: + QskAspect::Subcontrol substitutedSubcontrol( + QskAspect::Subcontrol ) const override; + private: class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/controls/QskTextEditSkinlet.cpp b/src/controls/QskTextEditSkinlet.cpp deleted file mode 100644 index 3c139f56..00000000 --- a/src/controls/QskTextEditSkinlet.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) The authors - * SPDX-License-Identifier: BSD-3-Clause - *****************************************************************************/ - -#include "QskTextEditSkinlet.h" -#include "QskTextEdit.h" - -#include - -using Q = QskTextEdit; - -QskTextEditSkinlet::QskTextEditSkinlet( QskSkin* skin ) - : Inherited( skin ) -{ - setNodeRoles( { TextPanelRole } ); -} - -QskTextEditSkinlet::~QskTextEditSkinlet() -{ -} - -QRectF QskTextEditSkinlet::subControlRect( const QskSkinnable* skinnable, - const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const -{ - if ( subControl == Q::TextPanel ) - { - return contentsRect; - } - else if ( subControl == Q::Text ) - { - auto rect = skinnable->subControlContentsRect( contentsRect, Q::TextPanel ); - rect = rect.marginsAdded( skinnable->marginHint( Q::Text ) ); - - return rect; - } - - return Inherited::subControlRect( skinnable, contentsRect, subControl ); -} - -QSGNode* QskTextEditSkinlet::updateSubNode( - const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const -{ - switch ( nodeRole ) - { - case TextPanelRole: - { - return updateBoxNode( skinnable, node, Q::TextPanel ); - } - } - - return Inherited::updateSubNode( skinnable, nodeRole, node ); -} - -QSizeF QskTextEditSkinlet::sizeHint( const QskSkinnable* skinnable, - Qt::SizeHint which, const QSizeF& ) const -{ - if ( which != Qt::PreferredSize ) - return QSizeF(); - - const auto textEdit = static_cast< const QskTextEdit* >( skinnable ); - - const QFontMetricsF fm( textEdit->effectiveFont( Q::Text ) ); - - int flags = Qt::TextExpandTabs; - - const auto wm = textEdit->wrapMode(); - - if( wm & QskTextOptions::WordWrap ) - { - flags |= Qt::TextWordWrap; - } - else if( wm & QskTextOptions::WrapAnywhere ) - { - flags |= Qt::TextWrapAnywhere; - } - else if( wm & QskTextOptions::Wrap ) - { - flags |= Qt::TextWordWrap | Qt::TextWrapAnywhere; - } - - auto hint = fm.boundingRect( textEdit->subControlRect( Q::Text ), flags, textEdit->text() ).size(); - - hint = textEdit->outerBoxSize( Q::TextPanel, hint ); - hint = hint.expandedTo( textEdit->strutSizeHint( Q::TextPanel ) ); - - return hint; -} diff --git a/src/controls/QskTextFieldSkinlet.h b/src/controls/QskTextFieldSkinlet.h index 29225a95..ce28d4c3 100644 --- a/src/controls/QskTextFieldSkinlet.h +++ b/src/controls/QskTextFieldSkinlet.h @@ -6,20 +6,20 @@ #ifndef QSK_TEXT_FIELD_SKINLET_H #define QSK_TEXT_FIELD_SKINLET_H -#include "QskTextInputSkinlet.h" +#include "QskAbstractTextInputSkinlet.h" class QskTextField; -class QSK_EXPORT QskTextFieldSkinlet : public QskTextInputSkinlet +class QSK_EXPORT QskTextFieldSkinlet : public QskAbstractTextInputSkinlet { Q_GADGET - using Inherited = QskTextInputSkinlet; + using Inherited = QskAbstractTextInputSkinlet; public: enum NodeRole : quint8 { - PanelRole = QskTextInputSkinlet::RoleCount, + PanelRole = QskAbstractTextInputSkinlet::RoleCount, PlaceholderTextRole, RoleCount diff --git a/src/controls/QskTextInput.cpp b/src/controls/QskTextInput.cpp index 12a48502..64190e8a 100644 --- a/src/controls/QskTextInput.cpp +++ b/src/controls/QskTextInput.cpp @@ -12,6 +12,7 @@ QSK_QT_PRIVATE_BEGIN #include QSK_QT_PRIVATE_END +QSK_SUBCONTROL( QskTextInput, Text ) QSK_SUBCONTROL( QskTextInput, TextPanel ) QSK_SYSTEM_STATE( QskTextInput, Error, QskAspect::FirstSystemState << 4 ) @@ -154,13 +155,6 @@ QskTextInput::QskTextInput( QQuickItem* parent ) : Inherited( parent ) , m_data( new PrivateData() ) { - /* - QQuickTextInput is a beast of almost 5k lines of code, we don't - want to reimplement that - at least not now. - So QskTextInput is more or less a simple wrapper making everything - conforming to qskinny. - */ - m_data->wrappedInput = new QuickTextInput( this ); auto wrappedInput = m_data->wrappedInput; @@ -171,7 +165,6 @@ QskTextInput::QskTextInput( QQuickItem* parent ) setup( wrappedInput ); -#if 1 connect( wrappedInput, &QQuickTextInput::maximumLengthChanged, this, &QskTextInput::maximumLengthChanged ); @@ -183,14 +176,24 @@ QskTextInput::QskTextInput( QQuickItem* parent ) connect( wrappedInput, &QQuickTextInput::acceptableInputChanged, this, [this]() { Q_EMIT acceptableInputChanged( hasAcceptableInput() ); } ); - -#endif } QskTextInput::~QskTextInput() { } +QskAspect::Subcontrol QskTextInput::substitutedSubcontrol( + QskAspect::Subcontrol subControl ) const +{ + if ( subControl == Inherited::Text ) + return Text; + + if ( subControl == Inherited::TextPanel ) + return TextPanel; + + return Inherited::substitutedSubcontrol( subControl ); +} + void QskTextInput::ensureVisible( int position ) { m_data->wrappedInput->ensureVisible( position ); diff --git a/src/controls/QskTextInput.h b/src/controls/QskTextInput.h index e0711632..fdfc11c5 100644 --- a/src/controls/QskTextInput.h +++ b/src/controls/QskTextInput.h @@ -46,8 +46,7 @@ class QSK_EXPORT QskTextInput : public QskAbstractTextInput using Inherited = QskAbstractTextInput; public: - QSK_SUBCONTROLS( TextPanel ) - + QSK_SUBCONTROLS( Text, TextPanel ) QSK_STATES( Error ) enum EchoMode : quint8 @@ -108,6 +107,10 @@ class QSK_EXPORT QskTextInput : public QskAbstractTextInput void displayTextChanged(); + protected: + QskAspect::Subcontrol substitutedSubcontrol( + QskAspect::Subcontrol ) const override; + private: class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/src/controls/QskTextInputSkinlet.h b/src/controls/QskTextInputSkinlet.h deleted file mode 100644 index 0fe94b2d..00000000 --- a/src/controls/QskTextInputSkinlet.h +++ /dev/null @@ -1,37 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) The authors - * SPDX-License-Identifier: BSD-3-Clause - *****************************************************************************/ - -#ifndef QSK_TEXT_INPUT_SKINLET_H -#define QSK_TEXT_INPUT_SKINLET_H - -#include "QskSkinlet.h" - -class QSK_EXPORT QskTextInputSkinlet : public QskSkinlet -{ - using Inherited = QskSkinlet; - - public: - enum NodeRole : quint8 - { - TextPanelRole, - RoleCount - }; - - ~QskTextInputSkinlet() override; - - QRectF subControlRect( const QskSkinnable*, - const QRectF& rect, QskAspect::Subcontrol ) const override; - - QSizeF sizeHint( const QskSkinnable*, - Qt::SizeHint, const QSizeF& ) const override; - - protected: - QskTextInputSkinlet( QskSkin* = nullptr ); - - QSGNode* updateSubNode( const QskSkinnable*, - quint8 nodeRole, QSGNode* ) const override; -}; - -#endif