6#include "QskTextInput.h"
7#include "QskFontRole.h"
11#include <private/qquicktextinput_p.h>
12#include <private/qquicktextinput_p_p.h>
27static inline
void qskPropagateReadOnly(
QskTextInput* input )
29 Q_EMIT input->readOnlyChanged( input->isReadOnly() );
31 QEvent event( QEvent::ReadOnlyChange );
32 QCoreApplication::sendEvent( input, &event );
35static inline void qskBindSignals(
36 const QQuickTextInput* wrappedInput,
QskTextInput* input )
38 QObject::connect( wrappedInput, &QQuickTextInput::textChanged,
39 input, [ input ] { Q_EMIT input->textChanged( input->text() ); } );
41 QObject::connect( wrappedInput, &QQuickTextInput::displayTextChanged,
42 input, [ input ] { Q_EMIT input->displayTextChanged( input->displayText() ); } );
44 QObject::connect( wrappedInput, &QQuickTextInput::textEdited,
45 input, [ input ] { Q_EMIT input->textEdited( input->text() ); } );
47 QObject::connect( wrappedInput, &QQuickTextInput::validatorChanged,
48 input, &QskTextInput::validatorChanged );
50 QObject::connect( wrappedInput, &QQuickTextInput::inputMaskChanged,
51 input, &QskTextInput::inputMaskChanged );
53 QObject::connect( wrappedInput, &QQuickTextInput::readOnlyChanged,
54 input, [ input ] { qskPropagateReadOnly( input ); } );
56 QObject::connect( wrappedInput, &QQuickTextInput::overwriteModeChanged,
57 input, &QskTextInput::overwriteModeChanged );
59 QObject::connect( wrappedInput, &QQuickTextInput::maximumLengthChanged,
60 input, &QskTextInput::maximumLengthChanged );
62 QObject::connect( wrappedInput, &QQuickTextInput::wrapModeChanged,
63 input, [ input ] { Q_EMIT input->wrapModeChanged( input->wrapMode() ); } );
65 QObject::connect( wrappedInput, &QQuickTextInput::echoModeChanged,
66 input, [ input ] { Q_EMIT input->echoModeChanged( input->echoMode() ); } );
68 QObject::connect( wrappedInput, &QQuickTextInput::passwordCharacterChanged,
69 input, &QskTextInput::passwordCharacterChanged );
71 QObject::connect( wrappedInput, &QQuickTextInput::passwordMaskDelayChanged,
72 input, &QskTextInput::passwordMaskDelayChanged );
74 QObject::connect( wrappedInput, &QQuickItem::implicitWidthChanged,
77 QObject::connect( wrappedInput, &QQuickItem::implicitHeightChanged,
83 class TextInput final :
public QQuickTextInput
85 using Inherited = QQuickTextInput;
90 void setEditing(
bool on );
92 inline void setAlignment( Qt::Alignment alignment )
94 setHAlign( ( HAlignment ) (
int( alignment ) & 0x0f ) );
95 setVAlign( ( VAlignment ) (
int( alignment ) & 0xf0 ) );
100 return QQuickTextInputPrivate::get(
this )->fixup();
103 bool hasAcceptableInput()
const
111 auto that =
const_cast< TextInput*
>( this );
112 auto d = QQuickTextInputPrivate::get( that );
114 if ( d->m_validator )
116 QString text = displayText();
117 int pos = d->m_cursor;
119 const auto state = d->m_validator->validate( text, pos );
120 if ( state != QValidator::Acceptable )
131 class Validator final :
public QValidator
134 State validate( QString&,
int& )
const override
136 return QValidator::Acceptable;
140 const auto validator = d->m_validator;
142 const auto validInput = d->m_validInput;
143 const auto acceptableInput = d->m_acceptableInput;
145 d->m_acceptableInput =
true;
147 static Validator noValidator;
148 that->setValidator( &noValidator );
149 that->setValidator( d->m_validator );
151 const bool isAcceptable = d->m_acceptableInput;
154 d->m_validInput = validInput;
155 d->m_acceptableInput = acceptableInput;
164 void updateMetrics();
166 inline bool handleEvent( QEvent* event )
168 return this->event( event );
173#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
175 const QRectF& newGeometry,
const QRectF& oldGeometry )
override
177 Inherited::geometryChange( newGeometry, oldGeometry );
181 void geometryChanged(
182 const QRectF& newGeometry,
const QRectF& oldGeometry )
override
184 Inherited::geometryChanged( newGeometry, oldGeometry );
191 setClip( ( contentWidth() > width() ) ||
192 ( contentHeight() > height() ) );
195 QSGNode* updatePaintNode(
196 QSGNode* oldNode, UpdatePaintNodeData* data )
override
199 return Inherited::updatePaintNode( oldNode, data );
204 : QQuickTextInput( textInput )
208 setActiveFocusOnTab(
false );
209 setFlag( ItemAcceptsInputMethod,
false );
210 setFocusOnPress(
false );
214 connect(
this, &TextInput::contentSizeChanged,
215 this, &TextInput::updateClip );
218 void TextInput::setEditing(
bool on )
220 auto d = QQuickTextInputPrivate::get(
this );
222 if ( d->cursorVisible == on )
225 setCursorVisible( on );
226 d->setBlinkingCursorEnabled( on );
230 if ( d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive() )
231 d->updatePasswordEchoEditing(
false );
238 void TextInput::updateMetrics()
240 auto input =
static_cast< const QskTextInput*
>( parentItem() );
242 setAlignment( input->alignment() );
243 setFont( input->font() );
246 void TextInput::updateColors()
248 auto input =
static_cast< const QskTextInput*
>( parentItem() );
249 auto d = QQuickTextInputPrivate::get(
this );
251 bool isDirty =
false;
255 color = input->
color( QskTextInput::Text );
256 if ( d->color != color )
262 if ( d->hasSelectedText() )
264 color = input->
color( QskTextInput::PanelSelected );
265 if ( d->selectionColor != color )
267 d->selectionColor = color;
271 color = input->
color( QskTextInput::TextSelected );
272 if ( d->selectedTextColor != color )
274 d->selectedTextColor = color;
281 d->textLayoutDirty =
true;
282 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
288class QskTextInput::PrivateData
291 TextInput* textInput;
294 unsigned int activationModes : 3;
298QskTextInput::QskTextInput( QQuickItem* parent )
299 : Inherited( parent )
300 , m_data( new PrivateData() )
302 m_data->activationModes = ActivationOnMouse | ActivationOnKey;
303 m_data->hasPanel =
true;
305 setPolishOnResize(
true );
307 setAcceptHoverEvents(
true );
308 setFocusPolicy( Qt::StrongFocus );
310 setFlag( QQuickItem::ItemAcceptsInputMethod );
319 m_data->textInput =
new TextInput(
this );
320 qskBindSignals( m_data->textInput,
this );
322 setAcceptedMouseButtons( m_data->textInput->acceptedMouseButtons() );
323 m_data->textInput->setAcceptedMouseButtons( Qt::NoButton );
325 initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Fixed );
328QskTextInput::QskTextInput(
const QString& text, QQuickItem* parent )
331 m_data->textInput->setText( text );
334QskTextInput::~QskTextInput()
338void QskTextInput::setPanel(
bool on )
340 if ( on != m_data->hasPanel )
342 m_data->hasPanel = on;
350bool QskTextInput::hasPanel()
const
352 return m_data->hasPanel;
355bool QskTextInput::event( QEvent* event )
357 if ( event->type() == QEvent::ShortcutOverride )
359 return m_data->textInput->handleEvent( event );
361 else if ( event->type() == QEvent::LocaleChange )
363 qskUpdateInputMethod(
this, Qt::ImPreferredLanguage );
366 return Inherited::event( event );
369void QskTextInput::keyPressEvent( QKeyEvent* event )
373 switch ( event->key() )
378 if ( hasAcceptableInput() || fixup() )
380 QGuiApplication::inputMethod()->commit();
382 if ( !( inputMethodHints() & Qt::ImhMultiLine ) )
387 qskForceActiveFocus(
this, Qt::PopupFocusReason );
396 qskForceActiveFocus(
this, Qt::PopupFocusReason );
402 m_data->textInput->handleEvent( event );
409 if ( ( m_data->activationModes & ActivationOnKey ) && !event->isAutoRepeat() )
411 if ( event->key() == Qt::Key_Select || event->key() == Qt::Key_Space )
418 Inherited::keyPressEvent( event );
421void QskTextInput::keyReleaseEvent( QKeyEvent* event )
423 Inherited::keyReleaseEvent( event );
426void QskTextInput::mousePressEvent( QMouseEvent* event )
428 m_data->textInput->handleEvent( event );
430 if ( !isReadOnly() && !qGuiApp->styleHints()->setFocusOnTouchRelease() )
434void QskTextInput::mouseMoveEvent( QMouseEvent* event )
436 m_data->textInput->handleEvent( event );
439void QskTextInput::mouseReleaseEvent( QMouseEvent* event )
441 m_data->textInput->handleEvent( event );
443 if ( !isReadOnly() && qGuiApp->styleHints()->setFocusOnTouchRelease() )
447void QskTextInput::mouseDoubleClickEvent( QMouseEvent* event )
449 m_data->textInput->handleEvent( event );
452void QskTextInput::inputMethodEvent( QInputMethodEvent* event )
454 m_data->textInput->handleEvent( event );
457void QskTextInput::focusInEvent( QFocusEvent* event )
459 if ( m_data->activationModes & ActivationOnFocus )
461 switch ( event->reason() )
463 case Qt::ActiveWindowFocusReason:
464 case Qt::PopupFocusReason:
475 Inherited::focusInEvent( event );
478void QskTextInput::focusOutEvent( QFocusEvent* event )
480 switch ( event->reason() )
482 case Qt::ActiveWindowFocusReason:
483 case Qt::PopupFocusReason:
489 m_data->textInput->deselect();
494 Inherited::focusOutEvent( event );
497QSizeF QskTextInput::layoutSizeHint( Qt::SizeHint which,
const QSizeF& )
const
499 if ( which != Qt::PreferredSize )
502 auto input = m_data->textInput;
504 input->updateMetrics();
506 QSizeF hint( input->implicitWidth(), input->implicitHeight() );
508 if ( m_data->hasPanel )
517void QskTextInput::updateLayout()
519 auto input = m_data->textInput;
521 input->updateMetrics();
527 m_data->textInput->updateColors();
531QString QskTextInput::text()
const
533 return m_data->textInput->text();
536void QskTextInput::setText(
const QString& text )
538 m_data->textInput->setText( text );
541void QskTextInput::setDescription(
const QString& text )
543 if ( m_data->description != text )
545 m_data->description = text;
546 Q_EMIT descriptionChanged( text );
550QString QskTextInput::description()
const
552 return m_data->description;
555QskTextInput::ActivationModes QskTextInput::activationModes()
const
557 return static_cast< QskTextInput::ActivationModes
>( m_data->activationModes );
560void QskTextInput::setActivationModes( ActivationModes modes )
562 if (
static_cast< ActivationModes
>( m_data->activationModes ) != modes )
564 m_data->activationModes = modes;
565 Q_EMIT activationModesChanged();
569static inline void qskUpdateInputMethodFont(
const QskTextInput* input )
571 const auto queries = Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle;
572 qskUpdateInputMethod( input, queries );
575void QskTextInput::setFontRole(
const QskFontRole& role )
579 qskUpdateInputMethodFont(
this );
580 Q_EMIT fontRoleChanged();
584void QskTextInput::resetFontRole()
588 qskUpdateInputMethodFont(
this );
589 Q_EMIT fontRoleChanged();
598void QskTextInput::setAlignment( Qt::Alignment alignment )
602 m_data->textInput->setAlignment( alignment );
603 Q_EMIT alignmentChanged();
607void QskTextInput::resetAlignment()
611 m_data->textInput->setAlignment( alignment() );
612 Q_EMIT alignmentChanged();
616Qt::Alignment QskTextInput::alignment()
const
621void QskTextInput::setWrapMode( QskTextOptions::WrapMode wrapMode )
623 m_data->textInput->setWrapMode(
624 static_cast< QQuickTextInput::WrapMode
>( wrapMode ) );
627QskTextOptions::WrapMode QskTextInput::wrapMode()
const
629 return static_cast< QskTextOptions::WrapMode
>(
630 m_data->textInput->wrapMode() );
633QFont QskTextInput::font()
const
638bool QskTextInput::isReadOnly()
const
640 return m_data->textInput->isReadOnly();
643void QskTextInput::setReadOnly(
bool on )
645 auto input = m_data->textInput;
647 if ( input->isReadOnly() == on )
652 setFocusPolicy( Qt::NoFocus );
655 input->setReadOnly( on );
658 input->setFlag( QQuickItem::ItemAcceptsInputMethod, !on );
659 qskUpdateInputMethod(
this, Qt::ImEnabled );
664void QskTextInput::setEditing(
bool on )
666 if ( isReadOnly() || on == isEditing() )
670 m_data->textInput->setEditing( on );
675 updateInputMethod( Qt::ImCursorRectangle | Qt::ImAnchorRectangle );
676 QGuiApplication::inputMethod()->inputDirection
678 qskInputMethodSetVisible(
this,
true );
682 if ( hasAcceptableInput() || fixup() )
683 Q_EMIT m_data->textInput->editingFinished();
686 inputMethod->reset();
688 qskInputMethodSetVisible(
this,
false );
691 Q_EMIT editingChanged( on );
694bool QskTextInput::isEditing()
const
696 return hasSkinState( Editing );
699void QskTextInput::ensureVisible(
int position )
701 m_data->textInput->ensureVisible( position );
704int QskTextInput::cursorPosition()
const
706 return m_data->textInput->cursorPosition();
709void QskTextInput::setCursorPosition(
int pos )
711 m_data->textInput->setCursorPosition( pos );
714int QskTextInput::maxLength()
const
716 return m_data->textInput->maxLength();
719void QskTextInput::setMaxLength(
int length )
721 m_data->textInput->setMaxLength( length );
724QValidator* QskTextInput::validator()
const
726 return m_data->textInput->validator();
729void QskTextInput::setValidator( QValidator* validator )
731 m_data->textInput->setValidator( validator );
734QString QskTextInput::inputMask()
const
736 return m_data->textInput->inputMask();
739void QskTextInput::setInputMask(
const QString& mask )
741 m_data->textInput->setInputMask( mask );
744QskTextInput::EchoMode QskTextInput::echoMode()
const
746 const auto mode = m_data->textInput->echoMode();
747 return static_cast< QskTextInput::EchoMode
>( mode );
750void QskTextInput::setEchoMode( EchoMode mode )
752 if ( mode != echoMode() )
754 m_data->textInput->setEchoMode(
755 static_cast< QQuickTextInput::EchoMode
>( mode ) );
757 qskUpdateInputMethod(
this, Qt::ImHints );
761QString QskTextInput::passwordCharacter()
const
763 return m_data->textInput->passwordCharacter();
766void QskTextInput::setPasswordCharacter(
const QString& text )
768 m_data->textInput->setPasswordCharacter( text );
771void QskTextInput::resetPasswordCharacter()
773 m_data->textInput->setPasswordCharacter(
774 QGuiApplication::styleHints()->passwordMaskCharacter() );
777int QskTextInput::passwordMaskDelay()
const
779 return m_data->textInput->passwordMaskDelay();
782void QskTextInput::setPasswordMaskDelay(
int ms )
784 m_data->textInput->setPasswordMaskDelay( ms );
787void QskTextInput::resetPasswordMaskDelay()
789 m_data->textInput->resetPasswordMaskDelay();
792QString QskTextInput::displayText()
const
794 return m_data->textInput->displayText();
797QString QskTextInput::preeditText()
const
799 const auto d = QQuickTextInputPrivate::get( m_data->textInput );
800 return d->m_textLayout.preeditAreaText();
803bool QskTextInput::overwriteMode()
const
805 return m_data->textInput->overwriteMode();
808void QskTextInput::setOverwriteMode(
bool overwrite )
810 m_data->textInput->setOverwriteMode( overwrite );
813bool QskTextInput::hasAcceptableInput()
const
815 return m_data->textInput->hasAcceptableInput();
818bool QskTextInput::fixup()
820 return m_data->textInput->fixup();
823QVariant QskTextInput::inputMethodQuery(
824 Qt::InputMethodQuery property )
const
826 return inputMethodQuery( property, QVariant() );
829QVariant QskTextInput::inputMethodQuery(
830 Qt::InputMethodQuery query,
const QVariant& argument )
const
836 return QVariant( (
bool ) ( flags() & ItemAcceptsInputMethod ) );
842 case Qt::ImPreferredLanguage:
846 case Qt::ImInputItemClipRectangle:
847 case Qt::ImCursorRectangle:
849 QVariant v = m_data->textInput->inputMethodQuery( query, argument );
851 if ( v.canConvert< QRectF >() )
852 v.setValue( v.toRectF().translated( m_data->textInput->position() ) );
858 return m_data->textInput->inputMethodQuery( query, argument );
863bool QskTextInput::canUndo()
const
865 return m_data->textInput->canUndo();
868bool QskTextInput::canRedo()
const
870 return m_data->textInput->canRedo();
873Qt::InputMethodHints QskTextInput::inputMethodHints()
const
875 return m_data->textInput->inputMethodHints();
878void QskTextInput::setInputMethodHints( Qt::InputMethodHints hints )
880 if ( m_data->textInput->inputMethodHints() != hints )
882 m_data->textInput->setInputMethodHints( hints );
883 qskUpdateInputMethod(
this, Qt::ImHints );
887void QskTextInput::setupFrom(
const QQuickItem* item )
889 if ( item ==
nullptr )
894 int maxCharacters = 32767;
895 QskTextInput::EchoMode echoMode = QskTextInput::Normal;
897 Qt::InputMethodQueries queries = Qt::ImQueryAll;
898 queries &= ~Qt::ImEnabled;
900 QInputMethodQueryEvent event( queries );
901 QCoreApplication::sendEvent(
const_cast< QQuickItem*
>( item ), &event );
903 if ( event.queries() & Qt::ImHints )
905 const auto hints =
static_cast< Qt::InputMethodHints
>(
906 event.value( Qt::ImHints ).toInt() );
908 if ( hints & Qt::ImhHiddenText )
909 echoMode = QskTextInput::NoEcho;
912 if ( event.queries() & Qt::ImMaximumTextLength )
916 const auto max =
event.value( Qt::ImMaximumTextLength ).toInt();
917 maxCharacters = qBound( 0, max, maxCharacters );
920 setMaxLength( maxCharacters );
922 if ( event.queries() & Qt::ImSurroundingText )
924 const auto text =
event.value( Qt::ImSurroundingText ).toString();
928 if ( event.queries() & Qt::ImCursorPosition )
930 const auto pos =
event.value( Qt::ImCursorPosition ).toInt();
931 setCursorPosition( pos );
934 if ( event.queries() & Qt::ImCurrentSelection )
937 const auto text =
event.value( Qt::ImCurrentSelection ).toString();
938 if ( !text.isEmpty() )
944 int passwordMaskDelay = -1;
945 QString passwordCharacter;
947 if ( echoMode == QskTextInput::NoEcho )
958 value = item->property(
"passwordMaskDelay" );
959 if ( value.canConvert<
int >() )
960 passwordMaskDelay = value.toInt();
962 value = item->property(
"passwordCharacter" );
963 if ( value.canConvert< QString >() )
964 passwordCharacter = value.toString();
966 value = item->property(
"echoMode" );
967 if ( value.canConvert<
int >() )
969 const auto mode = value.toInt();
970 if ( mode == QskTextInput::Password )
971 echoMode = QskTextInput::Password;
975 if ( passwordMaskDelay >= 0 )
976 setPasswordMaskDelay( passwordMaskDelay );
978 resetPasswordMaskDelay();
980 if ( !passwordCharacter.isEmpty() )
981 setPasswordCharacter( passwordCharacter );
983 resetPasswordCharacter();
985 setEchoMode( echoMode );
988#include "moc_QskTextInput.cpp"
Lookup key for a QskSkinHintTable.
QRectF subControlRect(QskAspect::Subcontrol) const
bool setAlignmentHint(QskAspect, Qt::Alignment)
Sets an alignment hint.
bool resetFontRoleHint(QskAspect)
Removes a font role hint from the local table.
QFont effectiveFont(QskAspect) const
QSizeF strutSizeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a strut size hint.
QSizeF outerBoxSize(QskAspect, const QSizeF &innerBoxSize) const
Calculate the size, when being expanded by paddings, indentations.
bool setFontRoleHint(QskAspect, const QskFontRole &)
Sets a font role hint.
QskFontRole fontRoleHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a font role hint.
void setSkinStateFlag(QskAspect::State, bool on=true)
bool resetAlignmentHint(QskAspect)
Removes an alignment hint from the local table.
QColor color(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint.
virtual void updateNode(QSGNode *)
Qt::Alignment alignmentHint(QskAspect, Qt::Alignment=Qt::Alignment()) const
Retrieves an alignment hint.
void updateNode(QSGNode *) override