QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskTextInput.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskTextInput.h"
7#include "QskFontRole.h"
8#include "QskQuick.h"
9
10QSK_QT_PRIVATE_BEGIN
11#include <private/qquicktextinput_p.h>
12#include <private/qquicktextinput_p_p.h>
13QSK_QT_PRIVATE_END
14
15QSK_SUBCONTROL( QskTextInput, Panel )
16QSK_SUBCONTROL( QskTextInput, Text )
17
18#if 1
19// shouldn't this be a Selected state, TODO ...
20QSK_SUBCONTROL( QskTextInput, PanelSelected )
21QSK_SUBCONTROL( QskTextInput, TextSelected )
22#endif
23
24QSK_SYSTEM_STATE( QskTextInput, ReadOnly, QskAspect::FirstSystemState << 1 )
25QSK_SYSTEM_STATE( QskTextInput, Editing, QskAspect::FirstSystemState << 2 )
26
27static inline void qskPropagateReadOnly( QskTextInput* input )
28{
29 Q_EMIT input->readOnlyChanged( input->isReadOnly() );
30
31 QEvent event( QEvent::ReadOnlyChange );
32 QCoreApplication::sendEvent( input, &event );
33}
34
35static inline void qskBindSignals(
36 const QQuickTextInput* wrappedInput, QskTextInput* input )
37{
38 QObject::connect( wrappedInput, &QQuickTextInput::textChanged,
39 input, [ input ] { Q_EMIT input->textChanged( input->text() ); } );
40
41 QObject::connect( wrappedInput, &QQuickTextInput::displayTextChanged,
42 input, [ input ] { Q_EMIT input->displayTextChanged( input->displayText() ); } );
43
44 QObject::connect( wrappedInput, &QQuickTextInput::textEdited,
45 input, [ input ] { Q_EMIT input->textEdited( input->text() ); } );
46
47 QObject::connect( wrappedInput, &QQuickTextInput::validatorChanged,
48 input, &QskTextInput::validatorChanged );
49
50 QObject::connect( wrappedInput, &QQuickTextInput::inputMaskChanged,
51 input, &QskTextInput::inputMaskChanged );
52
53 QObject::connect( wrappedInput, &QQuickTextInput::readOnlyChanged,
54 input, [ input ] { qskPropagateReadOnly( input ); } );
55
56 QObject::connect( wrappedInput, &QQuickTextInput::overwriteModeChanged,
57 input, &QskTextInput::overwriteModeChanged );
58
59 QObject::connect( wrappedInput, &QQuickTextInput::maximumLengthChanged,
60 input, &QskTextInput::maximumLengthChanged );
61
62 QObject::connect( wrappedInput, &QQuickTextInput::wrapModeChanged,
63 input, [ input ] { Q_EMIT input->wrapModeChanged( input->wrapMode() ); } );
64
65 QObject::connect( wrappedInput, &QQuickTextInput::echoModeChanged,
66 input, [ input ] { Q_EMIT input->echoModeChanged( input->echoMode() ); } );
67
68 QObject::connect( wrappedInput, &QQuickTextInput::passwordCharacterChanged,
69 input, &QskTextInput::passwordCharacterChanged );
70
71 QObject::connect( wrappedInput, &QQuickTextInput::passwordMaskDelayChanged,
72 input, &QskTextInput::passwordMaskDelayChanged );
73
74 QObject::connect( wrappedInput, &QQuickItem::implicitWidthChanged,
76
77 QObject::connect( wrappedInput, &QQuickItem::implicitHeightChanged,
79}
80
81namespace
82{
83 class TextInput final : public QQuickTextInput
84 {
85 using Inherited = QQuickTextInput;
86
87 public:
88 TextInput( QskTextInput* );
89
90 void setEditing( bool on );
91
92 inline void setAlignment( Qt::Alignment alignment )
93 {
94 setHAlign( ( HAlignment ) ( int( alignment ) & 0x0f ) );
95 setVAlign( ( VAlignment ) ( int( alignment ) & 0xf0 ) );
96 }
97
98 bool fixup()
99 {
100 return QQuickTextInputPrivate::get( this )->fixup();
101 }
102
103 bool hasAcceptableInput() const
104 {
105 /*
106 we would like to call QQuickTextInputPrivate::hasAcceptableInput
107 but unfortunately it is private, so we need to hack somthing
108 together
109 */
110
111 auto that = const_cast< TextInput* >( this );
112 auto d = QQuickTextInputPrivate::get( that );
113
114 if ( d->m_validator )
115 {
116 QString text = displayText();
117 int pos = d->m_cursor;
118
119 const auto state = d->m_validator->validate( text, pos );
120 if ( state != QValidator::Acceptable )
121 return false;
122 }
123
124 if ( d->m_maskData )
125 {
126 /*
127 We only want to do the check for the maskData here
128 and have to disable d->m_validator temporarily
129 */
130
131 class Validator final : public QValidator
132 {
133 public:
134 State validate( QString&, int& ) const override
135 {
136 return QValidator::Acceptable;
137 }
138 };
139
140 const auto validator = d->m_validator;
141
142 const auto validInput = d->m_validInput;
143 const auto acceptableInput = d->m_acceptableInput;
144
145 d->m_acceptableInput = true;
146
147 static Validator noValidator;
148 that->setValidator( &noValidator ); // implicitly checking maskData
149 that->setValidator( d->m_validator );
150
151 const bool isAcceptable = d->m_acceptableInput;
152
153 // restoring old values
154 d->m_validInput = validInput;
155 d->m_acceptableInput = acceptableInput;
156
157 return isAcceptable;
158 }
159
160 return true;
161 }
162
163 void updateColors();
164 void updateMetrics();
165
166 inline bool handleEvent( QEvent* event )
167 {
168 return this->event( event );
169 }
170
171 protected:
172
173#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
174 void geometryChange(
175 const QRectF& newGeometry, const QRectF& oldGeometry ) override
176 {
177 Inherited::geometryChange( newGeometry, oldGeometry );
178 updateClip();
179 }
180#else
181 void geometryChanged(
182 const QRectF& newGeometry, const QRectF& oldGeometry ) override
183 {
184 Inherited::geometryChanged( newGeometry, oldGeometry );
185 updateClip();
186 }
187#endif
188
189 void updateClip()
190 {
191 setClip( ( contentWidth() > width() ) ||
192 ( contentHeight() > height() ) );
193 }
194
195 QSGNode* updatePaintNode(
196 QSGNode* oldNode, UpdatePaintNodeData* data ) override
197 {
198 updateColors();
199 return Inherited::updatePaintNode( oldNode, data );
200 }
201 };
202
203 TextInput::TextInput( QskTextInput* textInput )
204 : QQuickTextInput( textInput )
205 {
206 classBegin();
207
208 setActiveFocusOnTab( false );
209 setFlag( ItemAcceptsInputMethod, false );
210 setFocusOnPress( false );
211
212 componentComplete();
213
214 connect( this, &TextInput::contentSizeChanged,
215 this, &TextInput::updateClip );
216 }
217
218 void TextInput::setEditing( bool on )
219 {
220 auto d = QQuickTextInputPrivate::get( this );
221
222 if ( d->cursorVisible == on )
223 return;
224
225 setCursorVisible( on );
226 d->setBlinkingCursorEnabled( on );
227
228 if ( !on )
229 {
230 if ( d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive() )
231 d->updatePasswordEchoEditing( false );
232 }
233
234 polish();
235 update();
236 }
237
238 void TextInput::updateMetrics()
239 {
240 auto input = static_cast< const QskTextInput* >( parentItem() );
241
242 setAlignment( input->alignment() );
243 setFont( input->font() );
244 }
245
246 void TextInput::updateColors()
247 {
248 auto input = static_cast< const QskTextInput* >( parentItem() );
249 auto d = QQuickTextInputPrivate::get( this );
250
251 bool isDirty = false;
252
253 QColor color;
254
255 color = input->color( QskTextInput::Text );
256 if ( d->color != color )
257 {
258 d->color = color;
259 isDirty = true;
260 }
261
262 if ( d->hasSelectedText() )
263 {
264 color = input->color( QskTextInput::PanelSelected );
265 if ( d->selectionColor != color )
266 {
267 d->selectionColor = color;
268 isDirty = true;
269 }
270
271 color = input->color( QskTextInput::TextSelected );
272 if ( d->selectedTextColor != color )
273 {
274 d->selectedTextColor = color;
275 isDirty = true;
276 }
277 }
278
279 if ( isDirty )
280 {
281 d->textLayoutDirty = true;
282 d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
283 update();
284 }
285 }
286}
287
288class QskTextInput::PrivateData
289{
290 public:
291 TextInput* textInput;
292 QString description; // f.e. used as prompt in QskInputPanel
293
294 unsigned int activationModes : 3;
295 bool hasPanel : 1;
296};
297
298QskTextInput::QskTextInput( QQuickItem* parent )
299 : Inherited( parent )
300 , m_data( new PrivateData() )
301{
302 m_data->activationModes = ActivationOnMouse | ActivationOnKey;
303 m_data->hasPanel = true;
304
305 setPolishOnResize( true );
306
307 setAcceptHoverEvents( true );
308 setFocusPolicy( Qt::StrongFocus );
309
310 setFlag( QQuickItem::ItemAcceptsInputMethod );
311
312 /*
313 QQuickTextInput is a beast of almost 5k lines of code, we don't
314 want to reimplement that - at least not now.
315 So this is more or less a simple wrapper making everything
316 conforming to qskinny.
317 */
318
319 m_data->textInput = new TextInput( this );
320 qskBindSignals( m_data->textInput, this );
321
322 setAcceptedMouseButtons( m_data->textInput->acceptedMouseButtons() );
323 m_data->textInput->setAcceptedMouseButtons( Qt::NoButton );
324
325 initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Fixed );
326}
327
328QskTextInput::QskTextInput( const QString& text, QQuickItem* parent )
329 : QskTextInput( parent )
330{
331 m_data->textInput->setText( text );
332}
333
334QskTextInput::~QskTextInput()
335{
336}
337
338void QskTextInput::setPanel( bool on )
339{
340 if ( on != m_data->hasPanel )
341 {
342 m_data->hasPanel = on;
343
345 polish();
346 update();
347 }
348}
349
350bool QskTextInput::hasPanel() const
351{
352 return m_data->hasPanel;
353}
354
355bool QskTextInput::event( QEvent* event )
356{
357 if ( event->type() == QEvent::ShortcutOverride )
358 {
359 return m_data->textInput->handleEvent( event );
360 }
361 else if ( event->type() == QEvent::LocaleChange )
362 {
363 qskUpdateInputMethod( this, Qt::ImPreferredLanguage );
364 }
365
366 return Inherited::event( event );
367}
368
369void QskTextInput::keyPressEvent( QKeyEvent* event )
370{
371 if ( isEditing() )
372 {
373 switch ( event->key() )
374 {
375 case Qt::Key_Enter:
376 case Qt::Key_Return:
377 {
378 if ( hasAcceptableInput() || fixup() )
379 {
380 QGuiApplication::inputMethod()->commit();
381
382 if ( !( inputMethodHints() & Qt::ImhMultiLine ) )
383 {
384 setEditing( false );
385
386 // When returning from a virtual keyboard
387 qskForceActiveFocus( this, Qt::PopupFocusReason );
388 }
389 }
390 break;
391 }
392#if 1
393 case Qt::Key_Escape:
394 {
395 setEditing( false );
396 qskForceActiveFocus( this, Qt::PopupFocusReason );
397 break;
398 }
399#endif
400 default:
401 {
402 m_data->textInput->handleEvent( event );
403 }
404 }
405
406 return;
407 }
408
409 if ( ( m_data->activationModes & ActivationOnKey ) && !event->isAutoRepeat() )
410 {
411 if ( event->key() == Qt::Key_Select || event->key() == Qt::Key_Space )
412 {
413 setEditing( true );
414 return;
415 }
416 }
417
418 Inherited::keyPressEvent( event );
419}
420
421void QskTextInput::keyReleaseEvent( QKeyEvent* event )
422{
423 Inherited::keyReleaseEvent( event );
424}
425
426void QskTextInput::mousePressEvent( QMouseEvent* event )
427{
428 m_data->textInput->handleEvent( event );
429
430 if ( !isReadOnly() && !qGuiApp->styleHints()->setFocusOnTouchRelease() )
431 setEditing( true );
432}
433
434void QskTextInput::mouseMoveEvent( QMouseEvent* event )
435{
436 m_data->textInput->handleEvent( event );
437}
438
439void QskTextInput::mouseReleaseEvent( QMouseEvent* event )
440{
441 m_data->textInput->handleEvent( event );
442
443 if ( !isReadOnly() && qGuiApp->styleHints()->setFocusOnTouchRelease() )
444 setEditing( true );
445}
446
447void QskTextInput::mouseDoubleClickEvent( QMouseEvent* event )
448{
449 m_data->textInput->handleEvent( event );
450}
451
452void QskTextInput::inputMethodEvent( QInputMethodEvent* event )
453{
454 m_data->textInput->handleEvent( event );
455}
456
457void QskTextInput::focusInEvent( QFocusEvent* event )
458{
459 if ( m_data->activationModes & ActivationOnFocus )
460 {
461 switch ( event->reason() )
462 {
463 case Qt::ActiveWindowFocusReason:
464 case Qt::PopupFocusReason:
465 break;
466
467 default:
468#if 1
469 // auto selecting the complete text ???
470#endif
471 setEditing( true );
472 }
473 }
474
475 Inherited::focusInEvent( event );
476}
477
478void QskTextInput::focusOutEvent( QFocusEvent* event )
479{
480 switch ( event->reason() )
481 {
482 case Qt::ActiveWindowFocusReason:
483 case Qt::PopupFocusReason:
484 {
485 break;
486 }
487 default:
488 {
489 m_data->textInput->deselect();
490 setEditing( false );
491 }
492 }
493
494 Inherited::focusOutEvent( event );
495}
496
497QSizeF QskTextInput::layoutSizeHint( Qt::SizeHint which, const QSizeF& ) const
498{
499 if ( which != Qt::PreferredSize )
500 return QSizeF();
501
502 auto input = m_data->textInput;
503
504 input->updateMetrics();
505
506 QSizeF hint( input->implicitWidth(), input->implicitHeight() );
507
508 if ( m_data->hasPanel )
509 {
510 hint = outerBoxSize( Panel, hint );
511 hint = hint.expandedTo( strutSizeHint( Panel ) );
512 }
513
514 return hint;
515}
516
517void QskTextInput::updateLayout()
518{
519 auto input = m_data->textInput;
520
521 input->updateMetrics();
522 qskSetItemGeometry( input, subControlRect( Text ) );
523}
524
525void QskTextInput::updateNode( QSGNode* node )
526{
527 m_data->textInput->updateColors();
528 Inherited::updateNode( node );
529}
530
531QString QskTextInput::text() const
532{
533 return m_data->textInput->text();
534}
535
536void QskTextInput::setText( const QString& text )
537{
538 m_data->textInput->setText( text );
539}
540
541void QskTextInput::setDescription( const QString& text )
542{
543 if ( m_data->description != text )
544 {
545 m_data->description = text;
546 Q_EMIT descriptionChanged( text );
547 }
548}
549
550QString QskTextInput::description() const
551{
552 return m_data->description;
553}
554
555QskTextInput::ActivationModes QskTextInput::activationModes() const
556{
557 return static_cast< QskTextInput::ActivationModes >( m_data->activationModes );
558}
559
560void QskTextInput::setActivationModes( ActivationModes modes )
561{
562 if ( static_cast< ActivationModes >( m_data->activationModes ) != modes )
563 {
564 m_data->activationModes = modes;
565 Q_EMIT activationModesChanged();
566 }
567}
568
569static inline void qskUpdateInputMethodFont( const QskTextInput* input )
570{
571 const auto queries = Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle;
572 qskUpdateInputMethod( input, queries );
573}
574
575void QskTextInput::setFontRole( const QskFontRole& role )
576{
577 if ( setFontRoleHint( Text, role ) )
578 {
579 qskUpdateInputMethodFont( this );
580 Q_EMIT fontRoleChanged();
581 }
582}
583
584void QskTextInput::resetFontRole()
585{
586 if ( resetFontRoleHint( Text ) )
587 {
588 qskUpdateInputMethodFont( this );
589 Q_EMIT fontRoleChanged();
590 }
591}
592
593QskFontRole QskTextInput::fontRole() const
594{
595 return fontRoleHint( Text );
596}
597
598void QskTextInput::setAlignment( Qt::Alignment alignment )
599{
600 if ( setAlignmentHint( Text, alignment ) )
601 {
602 m_data->textInput->setAlignment( alignment );
603 Q_EMIT alignmentChanged();
604 }
605}
606
607void QskTextInput::resetAlignment()
608{
609 if ( resetAlignmentHint( Text ) )
610 {
611 m_data->textInput->setAlignment( alignment() );
612 Q_EMIT alignmentChanged();
613 }
614}
615
616Qt::Alignment QskTextInput::alignment() const
617{
618 return alignmentHint( Text, Qt::AlignLeft | Qt::AlignTop );
619}
620
621void QskTextInput::setWrapMode( QskTextOptions::WrapMode wrapMode )
622{
623 m_data->textInput->setWrapMode(
624 static_cast< QQuickTextInput::WrapMode >( wrapMode ) );
625}
626
627QskTextOptions::WrapMode QskTextInput::wrapMode() const
628{
629 return static_cast< QskTextOptions::WrapMode >(
630 m_data->textInput->wrapMode() );
631}
632
633QFont QskTextInput::font() const
634{
635 return effectiveFont( QskTextInput::Text );
636}
637
638bool QskTextInput::isReadOnly() const
639{
640 return m_data->textInput->isReadOnly();
641}
642
643void QskTextInput::setReadOnly( bool on )
644{
645 auto input = m_data->textInput;
646
647 if ( input->isReadOnly() == on )
648 return;
649
650#if 1
651 // do we want to be able to restore the previous policy ?
652 setFocusPolicy( Qt::NoFocus );
653#endif
654
655 input->setReadOnly( on );
656
657 // we are killing user settings here ?
658 input->setFlag( QQuickItem::ItemAcceptsInputMethod, !on );
659 qskUpdateInputMethod( this, Qt::ImEnabled );
660
661 setSkinStateFlag( ReadOnly, on );
662}
663
664void QskTextInput::setEditing( bool on )
665{
666 if ( isReadOnly() || on == isEditing() )
667 return;
668
669 setSkinStateFlag( Editing, on );
670 m_data->textInput->setEditing( on );
671
672 if ( on )
673 {
674#if 0
675 updateInputMethod( Qt::ImCursorRectangle | Qt::ImAnchorRectangle );
676 QGuiApplication::inputMethod()->inputDirection
677#endif
678 qskInputMethodSetVisible( this, true );
679 }
680 else
681 {
682 if ( hasAcceptableInput() || fixup() )
683 Q_EMIT m_data->textInput->editingFinished();
684
685#if 0
686 inputMethod->reset();
687#endif
688 qskInputMethodSetVisible( this, false );
689 }
690
691 Q_EMIT editingChanged( on );
692}
693
694bool QskTextInput::isEditing() const
695{
696 return hasSkinState( Editing );
697}
698
699void QskTextInput::ensureVisible( int position )
700{
701 m_data->textInput->ensureVisible( position );
702}
703
704int QskTextInput::cursorPosition() const
705{
706 return m_data->textInput->cursorPosition();
707}
708
709void QskTextInput::setCursorPosition( int pos )
710{
711 m_data->textInput->setCursorPosition( pos );
712}
713
714int QskTextInput::maxLength() const
715{
716 return m_data->textInput->maxLength();
717}
718
719void QskTextInput::setMaxLength( int length )
720{
721 m_data->textInput->setMaxLength( length );
722}
723
724QValidator* QskTextInput::validator() const
725{
726 return m_data->textInput->validator();
727}
728
729void QskTextInput::setValidator( QValidator* validator )
730{
731 m_data->textInput->setValidator( validator );
732}
733
734QString QskTextInput::inputMask() const
735{
736 return m_data->textInput->inputMask();
737}
738
739void QskTextInput::setInputMask( const QString& mask )
740{
741 m_data->textInput->setInputMask( mask );
742}
743
744QskTextInput::EchoMode QskTextInput::echoMode() const
745{
746 const auto mode = m_data->textInput->echoMode();
747 return static_cast< QskTextInput::EchoMode >( mode );
748}
749
750void QskTextInput::setEchoMode( EchoMode mode )
751{
752 if ( mode != echoMode() )
753 {
754 m_data->textInput->setEchoMode(
755 static_cast< QQuickTextInput::EchoMode >( mode ) );
756
757 qskUpdateInputMethod( this, Qt::ImHints );
758 }
759}
760
761QString QskTextInput::passwordCharacter() const
762{
763 return m_data->textInput->passwordCharacter();
764}
765
766void QskTextInput::setPasswordCharacter( const QString& text )
767{
768 m_data->textInput->setPasswordCharacter( text );
769}
770
771void QskTextInput::resetPasswordCharacter()
772{
773 m_data->textInput->setPasswordCharacter(
774 QGuiApplication::styleHints()->passwordMaskCharacter() );
775}
776
777int QskTextInput::passwordMaskDelay() const
778{
779 return m_data->textInput->passwordMaskDelay();
780}
781
782void QskTextInput::setPasswordMaskDelay( int ms )
783{
784 m_data->textInput->setPasswordMaskDelay( ms );
785}
786
787void QskTextInput::resetPasswordMaskDelay()
788{
789 m_data->textInput->resetPasswordMaskDelay();
790}
791
792QString QskTextInput::displayText() const
793{
794 return m_data->textInput->displayText();
795}
796
797QString QskTextInput::preeditText() const
798{
799 const auto d = QQuickTextInputPrivate::get( m_data->textInput );
800 return d->m_textLayout.preeditAreaText();
801}
802
803bool QskTextInput::overwriteMode() const
804{
805 return m_data->textInput->overwriteMode();
806}
807
808void QskTextInput::setOverwriteMode( bool overwrite )
809{
810 m_data->textInput->setOverwriteMode( overwrite );
811}
812
813bool QskTextInput::hasAcceptableInput() const
814{
815 return m_data->textInput->hasAcceptableInput();
816}
817
818bool QskTextInput::fixup()
819{
820 return m_data->textInput->fixup();
821}
822
823QVariant QskTextInput::inputMethodQuery(
824 Qt::InputMethodQuery property ) const
825{
826 return inputMethodQuery( property, QVariant() );
827}
828
829QVariant QskTextInput::inputMethodQuery(
830 Qt::InputMethodQuery query, const QVariant& argument ) const
831{
832 switch ( query )
833 {
834 case Qt::ImEnabled:
835 {
836 return QVariant( ( bool ) ( flags() & ItemAcceptsInputMethod ) );
837 }
838 case Qt::ImFont:
839 {
840 return font();
841 }
842 case Qt::ImPreferredLanguage:
843 {
844 return locale();
845 }
846 case Qt::ImInputItemClipRectangle:
847 case Qt::ImCursorRectangle:
848 {
849 QVariant v = m_data->textInput->inputMethodQuery( query, argument );
850#if 1
851 if ( v.canConvert< QRectF >() )
852 v.setValue( v.toRectF().translated( m_data->textInput->position() ) );
853#endif
854 return v;
855 }
856 default:
857 {
858 return m_data->textInput->inputMethodQuery( query, argument );
859 }
860 }
861}
862
863bool QskTextInput::canUndo() const
864{
865 return m_data->textInput->canUndo();
866}
867
868bool QskTextInput::canRedo() const
869{
870 return m_data->textInput->canRedo();
871}
872
873Qt::InputMethodHints QskTextInput::inputMethodHints() const
874{
875 return m_data->textInput->inputMethodHints();
876}
877
878void QskTextInput::setInputMethodHints( Qt::InputMethodHints hints )
879{
880 if ( m_data->textInput->inputMethodHints() != hints )
881 {
882 m_data->textInput->setInputMethodHints( hints );
883 qskUpdateInputMethod( this, Qt::ImHints );
884 }
885}
886
887void QskTextInput::setupFrom( const QQuickItem* item )
888{
889 if ( item == nullptr )
890 return;
891
892 // finding attributes from the input hints of item
893
894 int maxCharacters = 32767;
895 QskTextInput::EchoMode echoMode = QskTextInput::Normal;
896
897 Qt::InputMethodQueries queries = Qt::ImQueryAll;
898 queries &= ~Qt::ImEnabled;
899
900 QInputMethodQueryEvent event( queries );
901 QCoreApplication::sendEvent( const_cast< QQuickItem* >( item ), &event );
902
903 if ( event.queries() & Qt::ImHints )
904 {
905 const auto hints = static_cast< Qt::InputMethodHints >(
906 event.value( Qt::ImHints ).toInt() );
907
908 if ( hints & Qt::ImhHiddenText )
909 echoMode = QskTextInput::NoEcho;
910 }
911
912 if ( event.queries() & Qt::ImMaximumTextLength )
913 {
914 // needs to be handled before Qt::ImCursorPosition !
915
916 const auto max = event.value( Qt::ImMaximumTextLength ).toInt();
917 maxCharacters = qBound( 0, max, maxCharacters );
918 }
919
920 setMaxLength( maxCharacters );
921
922 if ( event.queries() & Qt::ImSurroundingText )
923 {
924 const auto text = event.value( Qt::ImSurroundingText ).toString();
925 setText( text );
926 }
927
928 if ( event.queries() & Qt::ImCursorPosition )
929 {
930 const auto pos = event.value( Qt::ImCursorPosition ).toInt();
931 setCursorPosition( pos );
932 }
933
934 if ( event.queries() & Qt::ImCurrentSelection )
935 {
936#if 0
937 const auto text = event.value( Qt::ImCurrentSelection ).toString();
938 if ( !text.isEmpty() )
939 {
940 }
941#endif
942 }
943
944 int passwordMaskDelay = -1;
945 QString passwordCharacter;
946
947 if ( echoMode == QskTextInput::NoEcho )
948 {
949 /*
950 Qt::ImhHiddenText does not provide information
951 to decide between NoEcho/Password, or provides
952 more details about how to deal with hidden inputs.
953 So we try to find out more from trying some properties.
954 */
955
956 QVariant value;
957
958 value = item->property( "passwordMaskDelay" );
959 if ( value.canConvert< int >() )
960 passwordMaskDelay = value.toInt();
961
962 value = item->property( "passwordCharacter" );
963 if ( value.canConvert< QString >() )
964 passwordCharacter = value.toString();
965
966 value = item->property( "echoMode" );
967 if ( value.canConvert< int >() )
968 {
969 const auto mode = value.toInt();
970 if ( mode == QskTextInput::Password )
971 echoMode = QskTextInput::Password;
972 }
973 }
974
975 if ( passwordMaskDelay >= 0 )
976 setPasswordMaskDelay( passwordMaskDelay );
977 else
978 resetPasswordMaskDelay();
979
980 if ( !passwordCharacter.isEmpty() )
981 setPasswordCharacter( passwordCharacter );
982 else
983 resetPasswordCharacter();
984
985 setEchoMode( echoMode );
986}
987
988#include "moc_QskTextInput.cpp"
Lookup key for a QskSkinHintTable.
Definition QskAspect.h:15
@ FirstSystemState
Definition QskAspect.h:115
QRectF subControlRect(QskAspect::Subcontrol) const
QLocale locale
Definition QskControl.h:27
void resetImplicitSize()
Definition QskItem.cpp:721
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