964 lines
24 KiB
C++
964 lines
24 KiB
C++
/******************************************************************************
|
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
|
*****************************************************************************/
|
|
|
|
#include "QskTextInput.h"
|
|
#include "QskQuick.h"
|
|
|
|
QSK_QT_PRIVATE_BEGIN
|
|
#include <private/qquicktextinput_p.h>
|
|
#include <private/qquicktextinput_p_p.h>
|
|
QSK_QT_PRIVATE_END
|
|
|
|
QSK_SUBCONTROL( QskTextInput, Panel )
|
|
QSK_SUBCONTROL( QskTextInput, Text )
|
|
QSK_SUBCONTROL( QskTextInput, PanelSelected )
|
|
QSK_SUBCONTROL( QskTextInput, TextSelected )
|
|
|
|
QSK_SYSTEM_STATE( QskTextInput, ReadOnly, QskAspect::FirstSystemState << 1 )
|
|
QSK_SYSTEM_STATE( QskTextInput, Editing, QskAspect::FirstSystemState << 2 )
|
|
|
|
static inline void qskPropagateReadOnly( QskTextInput* input )
|
|
{
|
|
Q_EMIT input->readOnlyChanged( input->isReadOnly() );
|
|
|
|
QEvent event( QEvent::ReadOnlyChange );
|
|
QCoreApplication::sendEvent( input, &event );
|
|
}
|
|
|
|
static inline void qskBindSignals(
|
|
const QQuickTextInput* wrappedInput, QskTextInput* input )
|
|
{
|
|
QObject::connect( wrappedInput, &QQuickTextInput::textChanged,
|
|
input, [ input ] { Q_EMIT input->textChanged( input->text() ); } );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::displayTextChanged,
|
|
input, [ input ] { Q_EMIT input->displayTextChanged( input->displayText() ); } );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::textEdited,
|
|
input, [ input ] { Q_EMIT input->textEdited( input->text() ); } );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::validatorChanged,
|
|
input, &QskTextInput::validatorChanged );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::inputMaskChanged,
|
|
input, &QskTextInput::inputMaskChanged );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::readOnlyChanged,
|
|
input, [ input ] { qskPropagateReadOnly( input ); } );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::overwriteModeChanged,
|
|
input, &QskTextInput::overwriteModeChanged );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::maximumLengthChanged,
|
|
input, &QskTextInput::maximumLengthChanged );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::echoModeChanged,
|
|
input, [ input ] { Q_EMIT input->echoModeChanged( input->echoMode() ); } );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::passwordCharacterChanged,
|
|
input, &QskTextInput::passwordCharacterChanged );
|
|
|
|
QObject::connect( wrappedInput, &QQuickTextInput::passwordMaskDelayChanged,
|
|
input, &QskTextInput::passwordMaskDelayChanged );
|
|
|
|
QObject::connect( wrappedInput, &QQuickItem::implicitWidthChanged,
|
|
input, &QskControl::resetImplicitSize );
|
|
|
|
QObject::connect( wrappedInput, &QQuickItem::implicitHeightChanged,
|
|
input, &QskControl::resetImplicitSize );
|
|
}
|
|
|
|
namespace
|
|
{
|
|
class TextInput final : public QQuickTextInput
|
|
{
|
|
using Inherited = QQuickTextInput;
|
|
|
|
public:
|
|
TextInput( QskTextInput* );
|
|
|
|
void setEditing( bool on );
|
|
|
|
inline void setAlignment( Qt::Alignment alignment )
|
|
{
|
|
setHAlign( ( HAlignment ) ( int( alignment ) & 0x0f ) );
|
|
setVAlign( ( VAlignment ) ( int( alignment ) & 0xf0 ) );
|
|
}
|
|
|
|
bool fixup()
|
|
{
|
|
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
|
|
*/
|
|
|
|
auto that = const_cast< TextInput* >( this );
|
|
auto d = QQuickTextInputPrivate::get( that );
|
|
|
|
if ( d->m_validator )
|
|
{
|
|
QString text = displayText();
|
|
int pos = d->m_cursor;
|
|
|
|
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
|
|
{
|
|
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;
|
|
}
|
|
|
|
void updateColors();
|
|
void updateMetrics();
|
|
|
|
inline bool handleEvent( QEvent* event )
|
|
{
|
|
return this->event( event );
|
|
}
|
|
|
|
protected:
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
|
|
void geometryChange(
|
|
const QRectF& newGeometry, const QRectF& oldGeometry ) override
|
|
{
|
|
Inherited::geometryChange( newGeometry, oldGeometry );
|
|
updateClip();
|
|
}
|
|
#else
|
|
void geometryChanged(
|
|
const QRectF& newGeometry, const QRectF& oldGeometry ) override
|
|
{
|
|
Inherited::geometryChanged( newGeometry, oldGeometry );
|
|
updateClip();
|
|
}
|
|
#endif
|
|
|
|
void updateClip()
|
|
{
|
|
setClip( ( contentWidth() > width() ) ||
|
|
( contentHeight() > height() ) );
|
|
}
|
|
|
|
QSGNode* updatePaintNode(
|
|
QSGNode* oldNode, UpdatePaintNodeData* data ) override
|
|
{
|
|
updateColors();
|
|
return Inherited::updatePaintNode( oldNode, data );
|
|
}
|
|
};
|
|
|
|
TextInput::TextInput( QskTextInput* textInput )
|
|
: QQuickTextInput( textInput )
|
|
{
|
|
classBegin();
|
|
|
|
setActiveFocusOnTab( false );
|
|
setFlag( ItemAcceptsInputMethod, false );
|
|
setFocusOnPress( false );
|
|
|
|
componentComplete();
|
|
|
|
connect( this, &TextInput::contentSizeChanged,
|
|
this, &TextInput::updateClip );
|
|
}
|
|
|
|
void TextInput::setEditing( bool on )
|
|
{
|
|
auto d = QQuickTextInputPrivate::get( this );
|
|
|
|
if ( d->cursorVisible == on )
|
|
return;
|
|
|
|
setCursorVisible( on );
|
|
d->setBlinkingCursorEnabled( on );
|
|
|
|
if ( !on )
|
|
{
|
|
if ( d->m_passwordEchoEditing || d->m_passwordEchoTimer.isActive() )
|
|
d->updatePasswordEchoEditing( false );
|
|
}
|
|
|
|
polish();
|
|
update();
|
|
}
|
|
|
|
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
|
|
{
|
|
public:
|
|
TextInput* textInput;
|
|
QString description; // f.e. used as prompt in QskInputPanel
|
|
|
|
unsigned int activationModes : 3;
|
|
bool hasPanel : 1;
|
|
};
|
|
|
|
QskTextInput::QskTextInput( QQuickItem* parent )
|
|
: Inherited( parent )
|
|
, m_data( new PrivateData() )
|
|
{
|
|
m_data->activationModes = ActivationOnMouse | ActivationOnKey;
|
|
m_data->hasPanel = true;
|
|
|
|
setPolishOnResize( true );
|
|
setFocusPolicy( Qt::StrongFocus );
|
|
|
|
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.
|
|
*/
|
|
|
|
m_data->textInput = new TextInput( this );
|
|
qskBindSignals( m_data->textInput, this );
|
|
|
|
setAcceptedMouseButtons( m_data->textInput->acceptedMouseButtons() );
|
|
m_data->textInput->setAcceptedMouseButtons( Qt::NoButton );
|
|
|
|
initSizePolicy( QskSizePolicy::Minimum, QskSizePolicy::Fixed );
|
|
}
|
|
|
|
QskTextInput::QskTextInput( const QString& text, QQuickItem* parent )
|
|
: QskTextInput( parent )
|
|
{
|
|
m_data->textInput->setText( text );
|
|
}
|
|
|
|
QskTextInput::~QskTextInput()
|
|
{
|
|
}
|
|
|
|
void QskTextInput::setPanel( bool on )
|
|
{
|
|
if ( on != m_data->hasPanel )
|
|
{
|
|
m_data->hasPanel = on;
|
|
|
|
resetImplicitSize();
|
|
polish();
|
|
update();
|
|
}
|
|
}
|
|
|
|
bool QskTextInput::hasPanel() const
|
|
{
|
|
return m_data->hasPanel;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
return Inherited::event( event );
|
|
}
|
|
|
|
void QskTextInput::keyPressEvent( QKeyEvent* event )
|
|
{
|
|
if ( isEditing() )
|
|
{
|
|
switch ( event->key() )
|
|
{
|
|
case Qt::Key_Enter:
|
|
case Qt::Key_Return:
|
|
{
|
|
if ( hasAcceptableInput() || fixup() )
|
|
{
|
|
QGuiApplication::inputMethod()->commit();
|
|
|
|
if ( !( inputMethodHints() & Qt::ImhMultiLine ) )
|
|
{
|
|
setEditing( false );
|
|
|
|
// When returning from a virtual keyboard
|
|
qskForceActiveFocus( this, Qt::PopupFocusReason );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#if 1
|
|
case Qt::Key_Escape:
|
|
{
|
|
setEditing( false );
|
|
qskForceActiveFocus( this, Qt::PopupFocusReason );
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
{
|
|
m_data->textInput->handleEvent( event );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if ( ( m_data->activationModes & ActivationOnKey ) && !event->isAutoRepeat() )
|
|
{
|
|
if ( event->key() == Qt::Key_Select || event->key() == Qt::Key_Space )
|
|
{
|
|
setEditing( true );
|
|
return;
|
|
}
|
|
}
|
|
|
|
Inherited::keyPressEvent( event );
|
|
}
|
|
|
|
void QskTextInput::keyReleaseEvent( QKeyEvent* event )
|
|
{
|
|
Inherited::keyReleaseEvent( event );
|
|
}
|
|
|
|
void QskTextInput::mousePressEvent( QMouseEvent* event )
|
|
{
|
|
m_data->textInput->handleEvent( event );
|
|
|
|
if ( !isReadOnly() && !qGuiApp->styleHints()->setFocusOnTouchRelease() )
|
|
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() )
|
|
setEditing( true );
|
|
}
|
|
|
|
void QskTextInput::mouseDoubleClickEvent( QMouseEvent* event )
|
|
{
|
|
m_data->textInput->handleEvent( event );
|
|
}
|
|
|
|
void QskTextInput::inputMethodEvent( QInputMethodEvent* event )
|
|
{
|
|
m_data->textInput->handleEvent( event );
|
|
}
|
|
|
|
void QskTextInput::focusInEvent( QFocusEvent* event )
|
|
{
|
|
if ( m_data->activationModes & ActivationOnFocus )
|
|
{
|
|
switch ( event->reason() )
|
|
{
|
|
case Qt::ActiveWindowFocusReason:
|
|
case Qt::PopupFocusReason:
|
|
break;
|
|
|
|
default:
|
|
setEditing( true );
|
|
}
|
|
}
|
|
|
|
Inherited::focusInEvent( event );
|
|
}
|
|
|
|
void QskTextInput::focusOutEvent( QFocusEvent* event )
|
|
{
|
|
switch ( event->reason() )
|
|
{
|
|
case Qt::ActiveWindowFocusReason:
|
|
case Qt::PopupFocusReason:
|
|
{
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
m_data->textInput->deselect();
|
|
setEditing( false );
|
|
}
|
|
}
|
|
|
|
Inherited::focusOutEvent( event );
|
|
}
|
|
|
|
QSizeF QskTextInput::layoutSizeHint( Qt::SizeHint which, const QSizeF& ) const
|
|
{
|
|
if ( which != Qt::PreferredSize )
|
|
return QSizeF();
|
|
|
|
auto input = m_data->textInput;
|
|
|
|
input->updateMetrics();
|
|
|
|
QSizeF hint( input->implicitWidth(), input->implicitHeight() );
|
|
|
|
if ( m_data->hasPanel )
|
|
{
|
|
hint = outerBoxSize( Panel, hint );
|
|
hint = hint.expandedTo( strutSizeHint( Panel ) );
|
|
}
|
|
|
|
return hint;
|
|
}
|
|
|
|
void QskTextInput::updateLayout()
|
|
{
|
|
auto input = m_data->textInput;
|
|
|
|
input->updateMetrics();
|
|
qskSetItemGeometry( input, subControlRect( Text ) );
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
QskTextInput::ActivationModes QskTextInput::activationModes() const
|
|
{
|
|
return static_cast< QskTextInput::ActivationModes >( m_data->activationModes );
|
|
}
|
|
|
|
void QskTextInput::setActivationModes( ActivationModes modes )
|
|
{
|
|
if ( static_cast< ActivationModes >( m_data->activationModes ) != modes )
|
|
{
|
|
m_data->activationModes = modes;
|
|
Q_EMIT activationModesChanged();
|
|
}
|
|
}
|
|
|
|
static inline void qskUpdateInputMethodFont( const QskTextInput* input )
|
|
{
|
|
const auto queries = Qt::ImCursorRectangle | Qt::ImFont | Qt::ImAnchorRectangle;
|
|
qskUpdateInputMethod( input, queries );
|
|
}
|
|
|
|
void QskTextInput::setFontRole( int role )
|
|
{
|
|
if ( setFontRoleHint( Text, role ) )
|
|
{
|
|
qskUpdateInputMethodFont( this );
|
|
Q_EMIT fontRoleChanged();
|
|
}
|
|
}
|
|
|
|
void QskTextInput::resetFontRole()
|
|
{
|
|
if ( resetFontRoleHint( Text ) )
|
|
{
|
|
qskUpdateInputMethodFont( this );
|
|
Q_EMIT fontRoleChanged();
|
|
}
|
|
}
|
|
|
|
int QskTextInput::fontRole() const
|
|
{
|
|
return fontRoleHint( Text );
|
|
}
|
|
|
|
void QskTextInput::setAlignment( Qt::Alignment alignment )
|
|
{
|
|
if ( setAlignmentHint( Text, alignment ) )
|
|
{
|
|
m_data->textInput->setAlignment( alignment );
|
|
Q_EMIT alignmentChanged();
|
|
}
|
|
}
|
|
|
|
void QskTextInput::resetAlignment()
|
|
{
|
|
if ( resetAlignmentHint( Text ) )
|
|
{
|
|
m_data->textInput->setAlignment( alignment() );
|
|
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 )
|
|
{
|
|
auto input = m_data->textInput;
|
|
|
|
if ( input->isReadOnly() == on )
|
|
return;
|
|
|
|
#if 1
|
|
// do we want to be able to restore the previous policy ?
|
|
setFocusPolicy( Qt::NoFocus );
|
|
#endif
|
|
|
|
input->setReadOnly( on );
|
|
|
|
// we are killing user settings here ?
|
|
input->setFlag( QQuickItem::ItemAcceptsInputMethod, !on );
|
|
qskUpdateInputMethod( this, Qt::ImEnabled );
|
|
|
|
setSkinStateFlag( ReadOnly, on );
|
|
}
|
|
|
|
void QskTextInput::setEditing( bool on )
|
|
{
|
|
if ( isReadOnly() || on == isEditing() )
|
|
return;
|
|
|
|
setSkinStateFlag( Editing, on );
|
|
m_data->textInput->setEditing( on );
|
|
|
|
if ( on )
|
|
{
|
|
#if 0
|
|
updateInputMethod( Qt::ImCursorRectangle | Qt::ImAnchorRectangle );
|
|
QGuiApplication::inputMethod()->inputDirection
|
|
#endif
|
|
qskInputMethodSetVisible( this, true );
|
|
}
|
|
else
|
|
{
|
|
if ( hasAcceptableInput() || fixup() )
|
|
Q_EMIT m_data->textInput->editingFinished();
|
|
|
|
#if 0
|
|
inputMethod->reset();
|
|
#endif
|
|
qskInputMethodSetVisible( this, false );
|
|
}
|
|
|
|
Q_EMIT editingChanged( on );
|
|
}
|
|
|
|
bool QskTextInput::isEditing() const
|
|
{
|
|
return hasSkinState( Editing );
|
|
}
|
|
|
|
void QskTextInput::ensureVisible( int position )
|
|
{
|
|
m_data->textInput->ensureVisible( position );
|
|
}
|
|
|
|
int QskTextInput::cursorPosition() const
|
|
{
|
|
return m_data->textInput->cursorPosition();
|
|
}
|
|
|
|
void QskTextInput::setCursorPosition( int pos )
|
|
{
|
|
m_data->textInput->setCursorPosition( pos );
|
|
}
|
|
|
|
int QskTextInput::maxLength() const
|
|
{
|
|
return m_data->textInput->maxLength();
|
|
}
|
|
|
|
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 )
|
|
{
|
|
if ( mode != echoMode() )
|
|
{
|
|
m_data->textInput->setEchoMode(
|
|
static_cast< QQuickTextInput::EchoMode >( mode ) );
|
|
|
|
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();
|
|
}
|
|
|
|
bool QskTextInput::overwriteMode() const
|
|
{
|
|
return m_data->textInput->overwriteMode();
|
|
}
|
|
|
|
void QskTextInput::setOverwriteMode( bool overwrite )
|
|
{
|
|
m_data->textInput->setOverwriteMode( overwrite );
|
|
}
|
|
|
|
bool QskTextInput::hasAcceptableInput() const
|
|
{
|
|
return m_data->textInput->hasAcceptableInput();
|
|
}
|
|
|
|
bool QskTextInput::fixup()
|
|
{
|
|
return m_data->textInput->fixup();
|
|
}
|
|
|
|
QVariant QskTextInput::inputMethodQuery(
|
|
Qt::InputMethodQuery property ) const
|
|
{
|
|
return inputMethodQuery( property, QVariant() );
|
|
}
|
|
|
|
QVariant QskTextInput::inputMethodQuery(
|
|
Qt::InputMethodQuery query, QVariant argument ) const
|
|
{
|
|
switch ( query )
|
|
{
|
|
case Qt::ImEnabled:
|
|
{
|
|
return QVariant( ( bool ) ( flags() & ItemAcceptsInputMethod ) );
|
|
}
|
|
case Qt::ImFont:
|
|
{
|
|
return font();
|
|
}
|
|
case Qt::ImPreferredLanguage:
|
|
{
|
|
return locale();
|
|
}
|
|
case Qt::ImInputItemClipRectangle:
|
|
case Qt::ImCursorRectangle:
|
|
{
|
|
QVariant v = m_data->textInput->inputMethodQuery( query, argument );
|
|
#if 1
|
|
if ( v.canConvert< QRectF >() )
|
|
v.setValue( v.toRectF().translated( m_data->textInput->position() ) );
|
|
#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();
|
|
}
|
|
|
|
void QskTextInput::setInputMethodHints( Qt::InputMethodHints hints )
|
|
{
|
|
if ( m_data->textInput->inputMethodHints() != hints )
|
|
{
|
|
m_data->textInput->setInputMethodHints( hints );
|
|
qskUpdateInputMethod( this, Qt::ImHints );
|
|
}
|
|
}
|
|
|
|
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"
|