qskinny/src/controls/QskTextInput.cpp

927 lines
23 KiB
C++
Raw Normal View History

/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskTextInput.h"
2018-05-01 12:41:20 +02:00
#include "QskQuick.h"
2018-04-09 10:05:59 +02:00
QSK_QT_PRIVATE_BEGIN
#include <private/qquicktextinput_p.h>
2018-04-03 20:15:20 +02:00
#include <private/qquicktextinput_p_p.h>
QSK_QT_PRIVATE_END
2018-04-13 16:32:48 +02:00
QSK_SUBCONTROL( QskTextInput, Panel )
QSK_SUBCONTROL( QskTextInput, Text )
2018-04-18 10:46:11 +02:00
QSK_SUBCONTROL( QskTextInput, PanelSelected )
QSK_SUBCONTROL( QskTextInput, TextSelected )
2018-04-13 16:32:48 +02:00
2019-04-02 17:50:08 +02:00
QSK_SYSTEM_STATE( QskTextInput, ReadOnly, QskAspect::FirstSystemState << 1 )
QSK_SYSTEM_STATE( QskTextInput, Editing, QskAspect::FirstSystemState << 2 )
2018-04-13 16:32:48 +02:00
2018-08-03 08:15:28 +02:00
static inline void qskBindSignals(
const QQuickTextInput* wrappedInput, QskTextInput* input )
2018-04-03 20:15:20 +02:00
{
QObject::connect( wrappedInput, &QQuickTextInput::textChanged,
2018-08-03 11:11:42 +02:00
input, [ input ] { Q_EMIT input->textChanged( input->text() ); } );
2018-04-03 20:15:20 +02:00
2018-08-03 08:15:28 +02:00
#if QT_VERSION >= QT_VERSION_CHECK( 5, 9, 0 )
2018-04-03 20:15:20 +02:00
QObject::connect( wrappedInput, &QQuickTextInput::textEdited,
2018-08-03 11:11:42 +02:00
input, [ input ] { Q_EMIT input->textEdited( input->text() ); } );
2018-04-04 12:05:01 +02:00
#endif
2018-04-03 20:15:20 +02:00
QObject::connect( wrappedInput, &QQuickTextInput::validatorChanged,
input, &QskTextInput::validatorChanged );
QObject::connect( wrappedInput, &QQuickTextInput::inputMaskChanged,
input, &QskTextInput::inputMaskChanged );
QObject::connect( wrappedInput, &QQuickTextInput::readOnlyChanged,
input, &QskTextInput::readOnlyChanged );
2018-08-03 08:15:28 +02:00
#if QT_VERSION >= QT_VERSION_CHECK( 5, 8, 0 )
2018-04-03 20:15:20 +02:00
QObject::connect( wrappedInput, &QQuickTextInput::overwriteModeChanged,
input, &QskTextInput::overwriteModeChanged );
2018-04-04 12:05:01 +02:00
#endif
2018-04-03 20:15:20 +02:00
QObject::connect( wrappedInput, &QQuickTextInput::maximumLengthChanged,
input, &QskTextInput::maximumLengthChanged );
QObject::connect( wrappedInput, &QQuickTextInput::echoModeChanged,
2018-08-03 11:11:42 +02:00
input, [ input ] { Q_EMIT input->echoModeChanged( input->echoMode() ); } );
2018-04-03 20:15:20 +02:00
QObject::connect( wrappedInput, &QQuickTextInput::passwordCharacterChanged,
input, &QskTextInput::passwordCharacterChanged );
QObject::connect( wrappedInput, &QQuickTextInput::passwordMaskDelayChanged,
input, &QskTextInput::passwordMaskDelayChanged );
2018-04-03 20:15:20 +02:00
QObject::connect( wrappedInput, &QQuickItem::implicitWidthChanged,
input, &QskControl::resetImplicitSize );
QObject::connect( wrappedInput, &QQuickItem::implicitHeightChanged,
input, &QskControl::resetImplicitSize );
}
namespace
{
class TextInput final : public QQuickTextInput
{
2018-04-18 10:46:11 +02:00
using Inherited = QQuickTextInput;
2018-08-03 08:15:28 +02:00
public:
2018-04-13 16:32:48 +02:00
TextInput( QskTextInput* );
2018-04-09 10:05:59 +02:00
2018-04-13 16:32:48 +02:00
void setEditing( bool on );
2018-04-09 10:05:59 +02:00
2018-04-13 16:32:48 +02:00
inline void setAlignment( Qt::Alignment alignment )
{
setHAlign( ( HAlignment ) ( int( alignment ) & 0x0f ) );
setVAlign( ( VAlignment ) ( int( alignment ) & 0xf0 ) );
}
2018-04-13 16:32:48 +02:00
bool fixup()
2018-04-09 10:05:59 +02:00
{
return QQuickTextInputPrivate::get( this )->fixup();
}
bool hasAcceptableInput() const
{
/*
we would like to call QQuickTextInputPrivate::hasAcceptableInput
but unfortunately it is private, so we need to hack somthing
together
*/
2018-04-09 10:05:59 +02:00
auto that = const_cast< TextInput* >( this );
auto d = QQuickTextInputPrivate::get( that );
2018-04-09 10:05:59 +02:00
if ( d->m_validator )
{
QString text = d->m_text;
int pos = d->m_cursor;
2018-04-09 10:05:59 +02:00
const auto state = d->m_validator->validate( text, pos );
if ( state != QValidator::Acceptable )
return false;
}
if ( d->m_maskData )
{
/*
We only want to do the check for the maskData here
and have to disable d->m_validator temporarily
*/
class Validator final : public QValidator
{
2019-01-04 13:42:16 +01:00
public:
State validate( QString&, int& ) const override
{
return QValidator::Acceptable;
}
};
const auto validator = d->m_validator;
const auto validInput = d->m_validInput;
const auto acceptableInput = d->m_acceptableInput;
d->m_acceptableInput = true;
static Validator noValidator;
that->setValidator( &noValidator ); // implicitly checking maskData
that->setValidator( d->m_validator );
const bool isAcceptable = d->m_acceptableInput;
// restoring old values
d->m_validInput = validInput;
d->m_acceptableInput = acceptableInput;
return isAcceptable;
}
return true;
2018-04-13 16:32:48 +02:00
}
2018-04-09 10:05:59 +02:00
2018-04-18 10:46:11 +02:00
void updateColors();
void updateMetrics();
inline bool handleEvent( QEvent* event )
{
return this->event( event );
}
2019-01-04 13:42:16 +01:00
protected:
2020-10-26 17:52:08 +01:00
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
void geometryChange(
const QRectF& newGeometry, const QRectF& oldGeometry ) override
{
Inherited::geometryChange( newGeometry, oldGeometry );
updateClip();
}
#else
2018-07-31 17:32:25 +02:00
void geometryChanged(
2018-04-13 16:32:48 +02:00
const QRectF& newGeometry, const QRectF& oldGeometry ) override
{
2018-04-18 10:46:11 +02:00
Inherited::geometryChanged( newGeometry, oldGeometry );
2018-04-13 16:32:48 +02:00
updateClip();
}
2020-10-26 17:52:08 +01:00
#endif
2018-04-09 10:05:59 +02:00
2018-04-13 16:32:48 +02:00
void updateClip()
{
setClip( ( contentWidth() > width() ) ||
( contentHeight() > height() ) );
}
2018-04-18 10:46:11 +02:00
2018-07-31 17:32:25 +02:00
QSGNode* updatePaintNode(
QSGNode* oldNode, UpdatePaintNodeData* data ) override
2018-04-18 10:46:11 +02:00
{
updateColors();
return Inherited::updatePaintNode( oldNode, data );
}
2018-04-13 16:32:48 +02:00
};
2018-04-09 10:05:59 +02:00
2018-08-03 08:15:28 +02:00
TextInput::TextInput( QskTextInput* textInput )
: QQuickTextInput( textInput )
2018-04-13 16:32:48 +02:00
{
classBegin();
2018-04-13 16:32:48 +02:00
setActiveFocusOnTab( false );
setFlag( ItemAcceptsInputMethod, false );
setFocusOnPress( false );
2018-04-03 20:15:20 +02:00
2018-04-13 16:32:48 +02:00
componentComplete();
2018-04-09 10:05:59 +02:00
2018-04-13 16:32:48 +02:00
connect( this, &TextInput::contentSizeChanged,
this, &TextInput::updateClip );
}
2018-04-09 10:05:59 +02:00
2018-04-13 16:32:48 +02:00
void TextInput::setEditing( bool on )
{
auto d = QQuickTextInputPrivate::get( this );
2018-04-13 16:32:48 +02:00
if ( d->cursorVisible == on )
return;
2018-04-09 10:05:59 +02:00
2018-04-13 16:32:48 +02:00
setCursorVisible( on );
2018-08-03 08:15:28 +02:00
#if QT_VERSION >= QT_VERSION_CHECK( 5, 7, 0 )
2018-04-18 10:46:11 +02:00
d->setBlinkingCursorEnabled( on );
2018-04-23 10:42:37 +02:00
#endif
2018-04-03 20:15:20 +02:00
2018-04-13 16:32:48 +02:00
if ( !on )
{
2018-04-09 10:05:59 +02:00
if ( d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive() )
d->updatePasswordEchoEditing( false );
}
2018-04-13 16:32:48 +02:00
polish();
update();
}
2018-04-18 10:46:11 +02:00
void TextInput::updateMetrics()
{
auto input = static_cast< const QskTextInput* >( parentItem() );
setAlignment( input->alignment() );
setFont( input->font() );
}
void TextInput::updateColors()
{
auto input = static_cast< const QskTextInput* >( parentItem() );
auto d = QQuickTextInputPrivate::get( this );
bool isDirty = false;
QColor color;
color = input->color( QskTextInput::Text );
if ( d->color != color )
{
d->color = color;
isDirty = true;
}
if ( d->hasSelectedText() )
{
color = input->color( QskTextInput::PanelSelected );
if ( d->selectionColor != color )
{
d->selectionColor = color;
isDirty = true;
}
color = input->color( QskTextInput::TextSelected );
if ( d->selectedTextColor != color )
{
d->selectedTextColor = color;
isDirty = true;
}
}
if ( isDirty )
{
d->textLayoutDirty = true;
d->updateType = QQuickTextInputPrivate::UpdatePaintNode;
update();
}
}
}
class QskTextInput::PrivateData
{
2018-08-03 08:15:28 +02:00
public:
TextInput* textInput;
QString description; // f.e. used as prompt in QskInputPanel
2018-04-13 16:32:48 +02:00
unsigned int activationModes : 3;
};
2018-08-03 08:15:28 +02:00
QskTextInput::QskTextInput( QQuickItem* parent )
: Inherited( parent )
, m_data( new PrivateData() )
{
2018-04-13 16:32:48 +02:00
m_data->activationModes = ActivationOnMouse | ActivationOnKey;
2018-04-03 20:15:20 +02:00
setPolishOnResize( true );
setFocusPolicy( Qt::StrongFocus );
2018-04-03 20:15:20 +02:00
setFlag( QQuickItem::ItemAcceptsInputMethod );
/*
QQuickTextInput is a beast of almost 5k lines of code, we don't
want to reimplement that - at least not now.
So this is more or less a simple wrapper making everything
conforming to qskinny.
*/
2018-04-03 20:15:20 +02:00
m_data->textInput = new TextInput( this );
qskBindSignals( m_data->textInput, this );
2018-04-03 20:15:20 +02:00
setAcceptedMouseButtons( m_data->textInput->acceptedMouseButtons() );
m_data->textInput->setAcceptedMouseButtons( Qt::NoButton );
2018-04-03 20:15:20 +02:00
initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed );
}
2018-08-03 08:15:28 +02:00
QskTextInput::QskTextInput( const QString& text, QQuickItem* parent )
: QskTextInput( parent )
2018-04-03 20:15:20 +02:00
{
m_data->textInput->setText( text );
}
2018-04-03 20:15:20 +02:00
QskTextInput::~QskTextInput()
{
}
2018-04-03 20:15:20 +02:00
bool QskTextInput::event( QEvent* event )
{
if ( event->type() == QEvent::ShortcutOverride )
{
return m_data->textInput->handleEvent( event );
}
else if ( event->type() == QEvent::LocaleChange )
{
qskUpdateInputMethod( this, Qt::ImPreferredLanguage );
}
2018-04-03 20:15:20 +02:00
return Inherited::event( event );
}
2018-04-03 20:15:20 +02:00
void QskTextInput::keyPressEvent( QKeyEvent* event )
{
if ( isEditing() )
2018-04-13 16:32:48 +02:00
{
2018-08-03 08:15:28 +02:00
switch ( event->key() )
2018-04-13 16:32:48 +02:00
{
2018-04-18 10:46:11 +02:00
case Qt::Key_Enter:
case Qt::Key_Return:
2018-04-13 16:32:48 +02:00
{
if ( hasAcceptableInput() || fixup() )
2018-04-18 10:46:11 +02:00
{
QGuiApplication::inputMethod()->commit();
if ( !( inputMethodHints() & Qt::ImhMultiLine ) )
2018-04-18 10:46:11 +02:00
setEditing( false );
}
2018-04-18 10:46:11 +02:00
break;
}
#if 1
case Qt::Key_Escape:
{
setEditing( false );
break;
}
#endif
default:
{
m_data->textInput->handleEvent( event );
}
2018-04-13 16:32:48 +02:00
}
return;
}
2018-04-13 16:32:48 +02:00
if ( ( m_data->activationModes & ActivationOnKey ) && !event->isAutoRepeat() )
{
if ( event->key() == Qt::Key_Select || event->key() == Qt::Key_Space )
{
setEditing( true );
return;
}
}
Inherited::keyPressEvent( event );
2018-04-03 20:15:20 +02:00
}
2018-04-03 20:15:20 +02:00
void QskTextInput::keyReleaseEvent( QKeyEvent* event )
{
Inherited::keyReleaseEvent( event );
}
void QskTextInput::mousePressEvent( QMouseEvent* event )
{
m_data->textInput->handleEvent( event );
if ( !isReadOnly() && !qGuiApp->styleHints()->setFocusOnTouchRelease() )
2018-04-13 16:32:48 +02:00
setEditing( true );
}
void QskTextInput::mouseMoveEvent( QMouseEvent* event )
{
m_data->textInput->handleEvent( event );
}
void QskTextInput::mouseReleaseEvent( QMouseEvent* event )
{
m_data->textInput->handleEvent( event );
if ( !isReadOnly() && qGuiApp->styleHints()->setFocusOnTouchRelease() )
2018-04-13 16:32:48 +02:00
setEditing( true );
}
void QskTextInput::mouseDoubleClickEvent( QMouseEvent* event )
{
m_data->textInput->handleEvent( event );
}
2018-04-03 20:15:20 +02:00
void QskTextInput::inputMethodEvent( QInputMethodEvent* event )
{
m_data->textInput->handleEvent( event );
}
2018-04-03 20:15:20 +02:00
void QskTextInput::focusInEvent( QFocusEvent* event )
{
2018-04-18 10:46:11 +02:00
if ( m_data->activationModes & ActivationOnFocus )
{
2018-08-03 08:15:28 +02:00
switch ( event->reason() )
2018-04-18 10:46:11 +02:00
{
case Qt::ActiveWindowFocusReason:
case Qt::PopupFocusReason:
break;
default:
setEditing( true );
}
}
2018-04-03 20:15:20 +02:00
Inherited::focusInEvent( event );
}
2018-04-03 20:15:20 +02:00
void QskTextInput::focusOutEvent( QFocusEvent* event )
{
2018-08-03 08:15:28 +02:00
switch ( event->reason() )
2018-04-13 16:32:48 +02:00
{
case Qt::ActiveWindowFocusReason:
case Qt::PopupFocusReason:
{
break;
}
default:
2018-04-13 16:32:48 +02:00
{
m_data->textInput->deselect();
2018-04-13 16:32:48 +02:00
setEditing( false );
}
}
2018-04-03 20:15:20 +02:00
Inherited::focusOutEvent( event );
}
QSizeF QskTextInput::contentsSizeHint( Qt::SizeHint which, const QSizeF& ) const
{
if ( which != Qt::PreferredSize )
return QSizeF();
2018-04-18 10:46:11 +02:00
auto input = m_data->textInput;
input->updateMetrics();
const qreal w = input->implicitWidth();
const qreal h = input->implicitHeight();
const auto hint = outerBoxSize( Panel, QSizeF( w, h ) );
return hint.expandedTo( strutSizeHint( Panel ) );
}
void QskTextInput::updateLayout()
{
2018-04-03 20:15:20 +02:00
auto input = m_data->textInput;
2018-04-18 10:46:11 +02:00
input->updateMetrics();
2018-04-03 20:15:20 +02:00
qskSetItemGeometry( input, subControlRect( Text ) );
}
2018-04-18 10:46:11 +02:00
void QskTextInput::updateNode( QSGNode* node )
{
m_data->textInput->updateColors();
Inherited::updateNode( node );
}
QString QskTextInput::text() const
{
return m_data->textInput->text();
}
void QskTextInput::setText( const QString& text )
{
m_data->textInput->setText( text );
}
void QskTextInput::setDescription( const QString& text )
{
if ( m_data->description != text )
{
m_data->description = text;
Q_EMIT descriptionChanged( text );
}
}
QString QskTextInput::description() const
{
return m_data->description;
}
2018-04-13 16:32:48 +02:00
QskTextInput::ActivationModes QskTextInput::activationModes() const
{
return static_cast< QskTextInput::ActivationModes >( m_data->activationModes );
}
void QskTextInput::setActivationModes( ActivationModes modes )
{
2018-04-23 10:42:37 +02:00
if ( static_cast< ActivationModes >( m_data->activationModes ) != modes )
2018-04-13 16:32:48 +02:00
{
m_data->activationModes = modes;
Q_EMIT activationModesChanged();
}
}
int QskTextInput::fontRole() const
{
return QskSkinnable::fontRole( Text );
}
void QskTextInput::setFontRole( int role )
{
if ( role != fontRole() )
{
QskSkinnable::setFontRole( Text, role );
2018-04-03 20:15:20 +02:00
polish();
resetImplicitSize();
auto queries = Qt::ImCursorRectangle | Qt::ImFont;
2018-08-03 08:15:28 +02:00
#if QT_VERSION >= QT_VERSION_CHECK( 5, 7, 0 )
2018-04-04 12:05:01 +02:00
queries |= Qt::ImAnchorRectangle;
#endif
2018-04-03 20:15:20 +02:00
2018-04-04 12:05:01 +02:00
qskUpdateInputMethod( this, queries );
Q_EMIT fontRoleChanged();
}
}
void QskTextInput::setAlignment( Qt::Alignment alignment )
{
if ( alignment != this->alignment() )
{
setAlignmentHint( Text, alignment );
m_data->textInput->setAlignment( alignment );
2018-04-03 20:15:20 +02:00
polish();
Q_EMIT alignmentChanged();
}
}
Qt::Alignment QskTextInput::alignment() const
{
return alignmentHint( Text, Qt::AlignLeft | Qt::AlignTop );
}
QFont QskTextInput::font() const
{
return effectiveFont( QskTextInput::Text );
}
bool QskTextInput::isReadOnly() const
{
return m_data->textInput->isReadOnly();
}
void QskTextInput::setReadOnly( bool on )
{
2018-04-13 16:32:48 +02:00
if ( m_data->textInput->isReadOnly() == on )
return;
#if 1
// do we want to be able to restore the previous policy ?
setFocusPolicy( Qt::NoFocus );
#endif
m_data->textInput->setReadOnly( on );
2018-04-03 20:15:20 +02:00
2018-04-27 13:48:51 +02:00
// we are killing user settings here ?
2018-04-13 16:32:48 +02:00
m_data->textInput->setFlag( QQuickItem::ItemAcceptsInputMethod, !on );
2018-04-03 20:15:20 +02:00
qskUpdateInputMethod( this, Qt::ImEnabled );
2018-04-13 16:32:48 +02:00
2020-10-20 12:03:05 +02:00
setSkinStateFlag( ReadOnly, on );
}
2018-04-13 16:32:48 +02:00
void QskTextInput::setEditing( bool on )
2018-04-09 10:05:59 +02:00
{
2018-04-13 16:32:48 +02:00
if ( isReadOnly() || on == ( skinState() & Editing ) )
return;
setSkinStateFlag( Editing, on );
m_data->textInput->setEditing( on );
if ( on )
{
#if 0
2020-11-13 15:24:20 +01:00
updateInputMethod( Qt::ImCursorRectangle | Qt::ImAnchorRectangle );
2018-04-13 16:32:48 +02:00
QGuiApplication::inputMethod()->inputDirection
#endif
qskInputMethodSetVisible( this, true );
2018-04-13 16:32:48 +02:00
}
else
{
if ( hasAcceptableInput() || fixup() )
Q_EMIT m_data->textInput->editingFinished();
2018-04-13 16:32:48 +02:00
#if 0
inputMethod->reset();
#endif
qskInputMethodSetVisible( this, false );
2018-04-13 16:32:48 +02:00
#if 1
qskForceActiveFocus( this, Qt::PopupFocusReason );
#endif
}
Q_EMIT editingChanged( on );
2018-04-09 10:05:59 +02:00
}
2018-04-13 16:32:48 +02:00
bool QskTextInput::isEditing() const
{
2018-04-13 16:32:48 +02:00
return skinState() & Editing;
}
2018-04-13 16:32:48 +02:00
void QskTextInput::ensureVisible( int position )
{
2018-04-13 16:32:48 +02:00
m_data->textInput->ensureVisible( position );
}
int QskTextInput::cursorPosition() const
{
return m_data->textInput->cursorPosition();
}
2018-08-03 08:15:28 +02:00
void QskTextInput::setCursorPosition( int pos )
{
m_data->textInput->setCursorPosition( pos );
}
int QskTextInput::maxLength() const
{
return m_data->textInput->maxLength();
}
2018-08-03 08:15:28 +02:00
void QskTextInput::setMaxLength( int length )
{
m_data->textInput->setMaxLength( length );
}
QValidator* QskTextInput::validator() const
{
return m_data->textInput->validator();
}
void QskTextInput::setValidator( QValidator* validator )
{
m_data->textInput->setValidator( validator );
}
QString QskTextInput::inputMask() const
{
return m_data->textInput->inputMask();
}
void QskTextInput::setInputMask( const QString& mask )
{
m_data->textInput->setInputMask( mask );
}
QskTextInput::EchoMode QskTextInput::echoMode() const
{
const auto mode = m_data->textInput->echoMode();
return static_cast< QskTextInput::EchoMode >( mode );
}
void QskTextInput::setEchoMode( EchoMode mode )
{
2018-04-27 13:48:51 +02:00
if ( mode != echoMode() )
{
m_data->textInput->setEchoMode(
static_cast< QQuickTextInput::EchoMode >( mode ) );
2018-04-03 20:15:20 +02:00
2018-04-27 13:48:51 +02:00
qskUpdateInputMethod( this, Qt::ImHints );
}
}
QString QskTextInput::passwordCharacter() const
{
return m_data->textInput->passwordCharacter();
}
void QskTextInput::setPasswordCharacter( const QString& text )
{
m_data->textInput->setPasswordCharacter( text );
}
void QskTextInput::resetPasswordCharacter()
{
m_data->textInput->setPasswordCharacter(
QGuiApplication::styleHints()->passwordMaskCharacter() );
}
int QskTextInput::passwordMaskDelay() const
{
return m_data->textInput->passwordMaskDelay();
}
void QskTextInput::setPasswordMaskDelay( int ms )
{
return m_data->textInput->setPasswordMaskDelay( ms );
}
void QskTextInput::resetPasswordMaskDelay()
{
return m_data->textInput->resetPasswordMaskDelay();
}
QString QskTextInput::displayText() const
{
return m_data->textInput->displayText();
}
QString QskTextInput::preeditText() const
{
auto d = QQuickTextInputPrivate::get( m_data->textInput );
return d->m_textLayout.preeditAreaText();
}
2018-08-03 08:15:28 +02:00
#if QT_VERSION >= QT_VERSION_CHECK( 5, 8, 0 )
bool QskTextInput::overwriteMode() const
{
return m_data->textInput->overwriteMode();
}
void QskTextInput::setOverwriteMode( bool overwrite )
{
m_data->textInput->setOverwriteMode( overwrite );
}
#endif
bool QskTextInput::hasAcceptableInput() const
{
return m_data->textInput->hasAcceptableInput();
}
bool QskTextInput::fixup()
{
return m_data->textInput->fixup();
}
QVariant QskTextInput::inputMethodQuery(
2018-08-03 08:15:28 +02:00
Qt::InputMethodQuery property ) const
{
2018-04-03 20:15:20 +02:00
return inputMethodQuery( property, QVariant() );
}
QVariant QskTextInput::inputMethodQuery(
2018-08-03 08:15:28 +02:00
Qt::InputMethodQuery query, QVariant argument ) const
{
2018-08-03 08:15:28 +02:00
switch ( query )
2018-04-03 20:15:20 +02:00
{
case Qt::ImEnabled:
{
2018-08-03 08:15:28 +02:00
return QVariant( ( bool ) ( flags() & ItemAcceptsInputMethod ) );
2018-04-03 20:15:20 +02:00
}
case Qt::ImFont:
{
return font();
}
case Qt::ImPreferredLanguage:
{
return locale();
}
2018-08-03 08:15:28 +02:00
#if QT_VERSION >= QT_VERSION_CHECK( 5, 7, 0 )
case Qt::ImInputItemClipRectangle:
2018-04-09 10:05:59 +02:00
#endif
2019-01-07 09:13:53 +01:00
case Qt::ImCursorRectangle:
2018-04-03 20:15:20 +02:00
{
QVariant v = m_data->textInput->inputMethodQuery( query, argument );
#if 1
if ( v.canConvert< QRectF >() )
v.setValue( v.toRectF().translated( m_data->textInput->position() ) );
2018-04-03 20:15:20 +02:00
#endif
return v;
}
default:
{
return m_data->textInput->inputMethodQuery( query, argument );
}
}
}
bool QskTextInput::canUndo() const
{
return m_data->textInput->canUndo();
}
bool QskTextInput::canRedo() const
{
return m_data->textInput->canRedo();
}
Qt::InputMethodHints QskTextInput::inputMethodHints() const
{
return m_data->textInput->inputMethodHints();
}
2018-08-03 08:15:28 +02:00
void QskTextInput::setInputMethodHints( Qt::InputMethodHints hints )
{
2018-04-03 20:15:20 +02:00
if ( m_data->textInput->inputMethodHints() != hints )
{
m_data->textInput->setInputMethodHints( hints );
qskUpdateInputMethod( this, Qt::ImHints );
}
}
2018-06-02 17:10:41 +02:00
void QskTextInput::setupFrom( const QQuickItem* item )
{
if ( item == nullptr )
return;
// finding attributes from the input hints of item
int maxCharacters = 32767;
QskTextInput::EchoMode echoMode = QskTextInput::Normal;
Qt::InputMethodQueries queries = Qt::ImQueryAll;
queries &= ~Qt::ImEnabled;
QInputMethodQueryEvent event( queries );
QCoreApplication::sendEvent( const_cast< QQuickItem* >( item ), &event );
if ( event.queries() & Qt::ImHints )
{
const auto hints = static_cast< Qt::InputMethodHints >(
event.value( Qt::ImHints ).toInt() );
if ( hints & Qt::ImhHiddenText )
echoMode = QskTextInput::NoEcho;
}
if ( event.queries() & Qt::ImMaximumTextLength )
{
// needs to be handled before Qt::ImCursorPosition !
const auto max = event.value( Qt::ImMaximumTextLength ).toInt();
maxCharacters = qBound( 0, max, maxCharacters );
}
setMaxLength( maxCharacters );
if ( event.queries() & Qt::ImSurroundingText )
{
const auto text = event.value( Qt::ImSurroundingText ).toString();
setText( text );
}
if ( event.queries() & Qt::ImCursorPosition )
{
const auto pos = event.value( Qt::ImCursorPosition ).toInt();
setCursorPosition( pos );
}
if ( event.queries() & Qt::ImCurrentSelection )
{
#if 0
const auto text = event.value( Qt::ImCurrentSelection ).toString();
if ( !text.isEmpty() )
{
}
#endif
}
int passwordMaskDelay = -1;
QString passwordCharacter;
if ( echoMode == QskTextInput::NoEcho )
{
/*
Qt::ImhHiddenText does not provide information
to decide between NoEcho/Password, or provides
more details about how to deal with hidden inputs.
So we try to find out more from trying some properties.
*/
QVariant value;
value = item->property( "passwordMaskDelay" );
if ( value.canConvert< int >() )
passwordMaskDelay = value.toInt();
value = item->property( "passwordCharacter" );
if ( value.canConvert< QString >() )
passwordCharacter = value.toString();
value = item->property( "echoMode" );
if ( value.canConvert< int >() )
{
const auto mode = value.toInt();
if ( mode == QskTextInput::Password )
echoMode = QskTextInput::Password;
}
}
if ( passwordMaskDelay >= 0 )
setPasswordMaskDelay( passwordMaskDelay );
else
resetPasswordMaskDelay();
if ( !passwordCharacter.isEmpty() )
setPasswordCharacter( passwordCharacter );
else
resetPasswordCharacter();
setEchoMode( echoMode );
}
#include "moc_QskTextInput.cpp"