moving code from QskInputPanel
This commit is contained in:
parent
11dd05ff49
commit
23eec85708
@ -265,11 +265,7 @@ int main( int argc, char* argv[] )
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
/*
|
||||
If no input panel has been assigned QskInputContext creates
|
||||
default panel if none has been assigned
|
||||
*/
|
||||
QskInputContext::setInputPanel( new QskInputPanel() );
|
||||
QskInputContext::setInputManager( ... );
|
||||
#endif
|
||||
|
||||
auto box = new QskLinearBox( Qt::Horizontal );
|
||||
|
@ -790,4 +790,105 @@ void QskTextInput::setInputMethodHints(Qt::InputMethodHints hints )
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
@ -31,6 +31,9 @@ class QSK_EXPORT QskTextInput : public QskControl
|
||||
Q_PROPERTY( bool editing READ isEditing
|
||||
WRITE setEditing NOTIFY editingChanged )
|
||||
|
||||
Q_PROPERTY( EchoMode echoMode READ echoMode
|
||||
WRITE setEchoMode NOTIFY echoModeChanged )
|
||||
|
||||
Q_PROPERTY( QString passwordCharacter READ passwordCharacter
|
||||
WRITE setPasswordCharacter RESET resetPasswordCharacter
|
||||
NOTIFY passwordCharacterChanged )
|
||||
@ -75,6 +78,8 @@ public:
|
||||
|
||||
virtual ~QskTextInput();
|
||||
|
||||
void setupFrom( const QQuickItem* );
|
||||
|
||||
QString text() const;
|
||||
|
||||
void setDescription( const QString& );
|
||||
|
@ -11,6 +11,12 @@
|
||||
#include <QPointer>
|
||||
#include <QTextCharFormat>
|
||||
|
||||
static inline QQuickItem* qskReceiverItem( const QskInputManager* manager )
|
||||
{
|
||||
auto item = manager->inputProxy();
|
||||
return item ? item : manager->inputItem();
|
||||
}
|
||||
|
||||
static inline void qskSendReplaceText( QQuickItem* receiver, const QString& text )
|
||||
{
|
||||
if ( receiver == nullptr )
|
||||
@ -74,6 +80,7 @@ public:
|
||||
QPointer< QskControl > panel;
|
||||
|
||||
QLocale predictorLocale;
|
||||
Qt::InputMethodHints inputHints = 0;
|
||||
};
|
||||
|
||||
QskInputManager::QskInputManager( QObject* parent ):
|
||||
@ -98,14 +105,18 @@ void QskInputManager::attachInputItem( QQuickItem* item )
|
||||
const auto locale = context->locale();
|
||||
|
||||
updateEngine( locale );
|
||||
m_data->engine->reset();
|
||||
|
||||
panel->setEngine( m_data->engine );
|
||||
panel->setLocale( locale );
|
||||
panel->attachInputItem( item );
|
||||
|
||||
Qt::InputMethodQueries queries = Qt::ImQueryAll;
|
||||
queries &= ~Qt::ImEnabled;
|
||||
|
||||
processInputMethodQueries( queries );
|
||||
}
|
||||
else
|
||||
{
|
||||
panel->setEngine( nullptr );
|
||||
panel->attachInputItem( nullptr );
|
||||
}
|
||||
}
|
||||
@ -113,8 +124,21 @@ void QskInputManager::attachInputItem( QQuickItem* item )
|
||||
void QskInputManager::processInputMethodQueries(
|
||||
Qt::InputMethodQueries queries )
|
||||
{
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
|
||||
panel->processInputMethodQueries( queries );
|
||||
if ( queries & Qt::ImHints )
|
||||
{
|
||||
m_data->inputHints = 0;
|
||||
|
||||
if ( auto item = inputItem() )
|
||||
{
|
||||
QInputMethodQueryEvent event( Qt::ImHints );
|
||||
QCoreApplication::sendEvent( item, &event );
|
||||
|
||||
m_data->inputHints = static_cast< Qt::InputMethodHints >(
|
||||
event.value( Qt::ImHints ).toInt() );
|
||||
}
|
||||
|
||||
updatePanel();
|
||||
}
|
||||
}
|
||||
|
||||
QskControl* QskInputManager::panel( bool doCreate )
|
||||
@ -134,7 +158,7 @@ Qt::Alignment QskInputManager::panelAlignment() const
|
||||
{
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
|
||||
{
|
||||
if ( panel->hasInputProxy() )
|
||||
if ( panel->panelHints() & QskInputPanel::InputProxy )
|
||||
{
|
||||
/*
|
||||
When the panel has an input proxy we don't need to see
|
||||
@ -152,14 +176,11 @@ QskControl* QskInputManager::createPanel()
|
||||
{
|
||||
auto panel = new QskInputPanel();
|
||||
|
||||
connect( panel, &QskInputPanel::done,
|
||||
this, &QskInputManager::applyInput, Qt::UniqueConnection );
|
||||
connect( panel, &QskInputPanel::keySelected,
|
||||
this, &QskInputManager::commitKey, Qt::UniqueConnection );
|
||||
|
||||
connect( panel, &QskInputPanel::textEntered,
|
||||
this, &QskInputManager::applyText, Qt::UniqueConnection );
|
||||
|
||||
connect( panel, &QskInputPanel::keyEntered,
|
||||
this, &QskInputManager::applyKey, Qt::UniqueConnection );
|
||||
connect( panel, &QskInputPanel::predictiveTextSelected,
|
||||
this, &QskInputManager::commitPredictiveText, Qt::UniqueConnection );
|
||||
|
||||
return panel;
|
||||
}
|
||||
@ -171,7 +192,7 @@ QskInputEngine* QskInputManager::createEngine()
|
||||
|
||||
void QskInputManager::updateEngine( const QLocale& locale )
|
||||
{
|
||||
auto context = QskInputContext::instance();
|
||||
bool updatePredictor;
|
||||
|
||||
if ( m_data->engine == nullptr)
|
||||
{
|
||||
@ -179,18 +200,24 @@ void QskInputManager::updateEngine( const QLocale& locale )
|
||||
if ( engine->parent() == nullptr )
|
||||
engine->setParent( this );
|
||||
|
||||
m_data->predictorLocale = locale;
|
||||
engine->setPredictor( context->textPredictor( locale ) );
|
||||
connect( engine, &QskInputEngine::predictionChanged,
|
||||
this, &QskInputManager::updatePrediction );
|
||||
|
||||
m_data->engine = engine;
|
||||
updatePredictor = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_data->predictorLocale != locale )
|
||||
{
|
||||
m_data->predictorLocale = locale;
|
||||
m_data->engine->setPredictor( context->textPredictor( locale ) );
|
||||
}
|
||||
updatePredictor = ( locale != m_data->predictorLocale );
|
||||
}
|
||||
|
||||
if ( updatePredictor )
|
||||
{
|
||||
auto context = QskInputContext::instance();
|
||||
|
||||
m_data->predictorLocale = locale;
|
||||
m_data->engine->setPredictor( context->textPredictor( locale ) );
|
||||
updatePanel();
|
||||
}
|
||||
}
|
||||
|
||||
@ -206,6 +233,18 @@ void QskInputManager::updatePredictor()
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputManager::updatePanel()
|
||||
{
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
|
||||
{
|
||||
const auto mask = Qt::ImhNoPredictiveText
|
||||
| Qt::ImhExclusiveInputMask | Qt::ImhHiddenText;
|
||||
|
||||
panel->setPanelHint( QskInputPanel::Prediction,
|
||||
m_data->engine->predictor() && !( m_data->inputHints & mask ) );
|
||||
}
|
||||
}
|
||||
|
||||
QQuickItem* QskInputManager::inputItem() const
|
||||
{
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
|
||||
@ -218,7 +257,7 @@ QQuickItem* QskInputManager::inputProxy() const
|
||||
{
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
|
||||
{
|
||||
if ( panel->hasInputProxy() )
|
||||
if ( panel->panelHints() & QskInputPanel::InputProxy )
|
||||
return panel->inputProxy();
|
||||
}
|
||||
|
||||
@ -246,22 +285,85 @@ void QskInputManager::applyInput( bool success )
|
||||
|
||||
void QskInputManager::applyText( const QString& text, bool isFinal )
|
||||
{
|
||||
auto item = inputProxy();
|
||||
if ( item == nullptr )
|
||||
item = inputItem();
|
||||
|
||||
qskSendText( item, text, isFinal );
|
||||
qskSendText( qskReceiverItem( this ), text, isFinal );
|
||||
}
|
||||
|
||||
void QskInputManager::applyKey( int key )
|
||||
{
|
||||
// control keys like left/right
|
||||
qskSendKey( qskReceiverItem( this ), key );
|
||||
}
|
||||
|
||||
auto item = inputProxy();
|
||||
if ( item == nullptr )
|
||||
item = inputItem();
|
||||
void QskInputManager::commitPredictiveText( int index )
|
||||
{
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
|
||||
{
|
||||
panel->setPrediction( QStringList() );
|
||||
|
||||
qskSendKey( item, key );
|
||||
const QString text = m_data->engine->predictiveText( index );
|
||||
|
||||
m_data->engine->reset();
|
||||
applyText( text, true );
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputManager::updatePrediction()
|
||||
{
|
||||
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
|
||||
panel->setPrediction( m_data->engine->prediction() );
|
||||
}
|
||||
|
||||
void QskInputManager::commitKey( int key )
|
||||
{
|
||||
auto panel = qobject_cast< QskInputPanel* >( m_data->panel );
|
||||
if ( panel == nullptr )
|
||||
return;
|
||||
|
||||
int spaceLeft = -1;
|
||||
|
||||
if ( !( m_data->inputHints & Qt::ImhMultiLine ) )
|
||||
{
|
||||
QInputMethodQueryEvent event1( Qt::ImMaximumTextLength );
|
||||
QCoreApplication::sendEvent( panel->attachedInputItem(), &event1 );
|
||||
|
||||
const int maxChars = event1.value( Qt::ImMaximumTextLength ).toInt();
|
||||
if ( maxChars >= 0 )
|
||||
{
|
||||
QInputMethodQueryEvent event2( Qt::ImSurroundingText );
|
||||
QCoreApplication::sendEvent( qskReceiverItem( this ), &event2 );
|
||||
|
||||
const auto text = event2.value( Qt::ImSurroundingText ).toString();
|
||||
spaceLeft = maxChars - text.length();
|
||||
}
|
||||
}
|
||||
|
||||
const auto result = m_data->engine->processKey(
|
||||
key, m_data->inputHints, spaceLeft );
|
||||
|
||||
if ( result.key )
|
||||
{
|
||||
switch( result.key )
|
||||
{
|
||||
case Qt::Key_Return:
|
||||
{
|
||||
applyInput( true );
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Escape:
|
||||
{
|
||||
applyInput( false );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
applyKey( result.key );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( !result.text.isEmpty() )
|
||||
{
|
||||
applyText( result.text, result.isFinal );
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_QskInputManager.cpp"
|
||||
|
@ -46,6 +46,12 @@ private:
|
||||
void applyText( const QString&, bool isFinal );
|
||||
void applyKey( int keyCode );
|
||||
|
||||
void commitKey( int keyCode );
|
||||
void commitPredictiveText( int index );
|
||||
|
||||
void updatePrediction();
|
||||
void updatePanel();
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
@ -4,7 +4,6 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "QskInputPanel.h"
|
||||
#include "QskInputEngine.h"
|
||||
#include "QskVirtualKeyboard.h"
|
||||
#include "QskInputPredictionBar.h"
|
||||
#include "QskTextInput.h"
|
||||
@ -28,39 +27,6 @@ namespace
|
||||
setFocusPolicy( Qt::NoFocus );
|
||||
}
|
||||
|
||||
void setup( QQuickItem* inputItem )
|
||||
{
|
||||
int passwordMaskDelay = -1;
|
||||
QString passwordCharacter;
|
||||
|
||||
if ( auto textInput = qobject_cast< QskTextInput* >( inputItem ) )
|
||||
{
|
||||
passwordMaskDelay = textInput->passwordMaskDelay();
|
||||
passwordCharacter = textInput->passwordCharacter();
|
||||
|
||||
if ( echoMode() == QskTextInput::NoEcho )
|
||||
{
|
||||
/*
|
||||
Qt::ImhHiddenText does not provide information
|
||||
to decide between NoEcho/Password
|
||||
*/
|
||||
auto mode = textInput->echoMode();
|
||||
if ( mode == QskTextInput::Password )
|
||||
setEchoMode( mode );
|
||||
}
|
||||
}
|
||||
|
||||
if ( passwordMaskDelay >= 0 )
|
||||
setPasswordMaskDelay( passwordMaskDelay );
|
||||
else
|
||||
resetPasswordMaskDelay();
|
||||
|
||||
if ( !passwordCharacter.isEmpty() )
|
||||
setPasswordCharacter( passwordCharacter );
|
||||
else
|
||||
resetPasswordCharacter();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void focusInEvent( QFocusEvent* ) override final
|
||||
{
|
||||
@ -77,20 +43,6 @@ QSK_SUBCONTROL( QskInputPanel, Panel )
|
||||
class QskInputPanel::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
inputHints( 0 ),
|
||||
maxChars( -1 ),
|
||||
hasPrediction( true ),
|
||||
hasInputProxy( true )
|
||||
{
|
||||
}
|
||||
|
||||
QQuickItem* receiverItem()
|
||||
{
|
||||
return hasInputProxy ? inputProxy : inputItem;
|
||||
}
|
||||
|
||||
QPointer< QskInputEngine > engine;
|
||||
QPointer< QQuickItem > inputItem;
|
||||
|
||||
QskLinearBox* layout;
|
||||
@ -99,11 +51,9 @@ public:
|
||||
QskInputPredictionBar* predictionBar;
|
||||
QskVirtualKeyboard* keyboard;
|
||||
|
||||
Qt::InputMethodHints inputHints;
|
||||
int maxChars;
|
||||
int maxChars = -1;
|
||||
|
||||
bool hasPrediction : 1;
|
||||
bool hasInputProxy : 1;
|
||||
QskInputPanel::PanelHints panelHints = QskInputPanel::InputProxy;
|
||||
};
|
||||
|
||||
QskInputPanel::QskInputPanel( QQuickItem* parent ):
|
||||
@ -117,10 +67,12 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ):
|
||||
m_data->prompt->setVisible( false );
|
||||
|
||||
m_data->inputProxy = new TextInputProxy();
|
||||
m_data->inputProxy->setVisible( m_data->hasInputProxy );
|
||||
m_data->inputProxy->setVisible(
|
||||
m_data->panelHints & QskInputPanel::InputProxy );
|
||||
|
||||
m_data->predictionBar = new QskInputPredictionBar();
|
||||
m_data->predictionBar->setVisible( false );
|
||||
m_data->predictionBar->setVisible(
|
||||
m_data->panelHints & QskInputPanel::Prediction );
|
||||
|
||||
m_data->keyboard = new QskVirtualKeyboard();
|
||||
|
||||
@ -135,34 +87,45 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ):
|
||||
m_data->layout = layout;
|
||||
|
||||
connect( m_data->predictionBar, &QskInputPredictionBar::predictiveTextSelected,
|
||||
this, &QskInputPanel::commitPredictiveText );
|
||||
this, &QskInputPanel::predictiveTextSelected );
|
||||
|
||||
connect( m_data->keyboard, &QskVirtualKeyboard::keySelected,
|
||||
this, &QskInputPanel::commitKey );
|
||||
this, &QskInputPanel::keySelected );
|
||||
}
|
||||
|
||||
QskInputPanel::~QskInputPanel()
|
||||
{
|
||||
}
|
||||
|
||||
void QskInputPanel::setEngine( QskInputEngine* engine )
|
||||
void QskInputPanel::setPanelHint( PanelHint hint, bool on )
|
||||
{
|
||||
if ( engine == m_data->engine )
|
||||
if ( on )
|
||||
setPanelHints( m_data->panelHints | hint );
|
||||
else
|
||||
setPanelHints( m_data->panelHints & ~hint );
|
||||
}
|
||||
|
||||
void QskInputPanel::setPanelHints( PanelHints hints )
|
||||
{
|
||||
if ( hints == m_data->panelHints )
|
||||
return;
|
||||
|
||||
if ( m_data->engine )
|
||||
m_data->engine->disconnect( this );
|
||||
m_data->panelHints = hints;
|
||||
|
||||
m_data->engine = engine;
|
||||
m_data->inputProxy->setVisible( hints & QskInputPanel::InputProxy );
|
||||
m_data->predictionBar->setVisible( hints & QskInputPanel::Prediction );
|
||||
|
||||
if ( engine )
|
||||
{
|
||||
connect( engine, &QskInputEngine::predictionChanged,
|
||||
this, &QskInputPanel::updatePrediction );
|
||||
}
|
||||
const bool showPrompt = ( hints & QskInputPanel::InputProxy )
|
||||
&& !m_data->prompt->text().isEmpty();
|
||||
|
||||
m_data->predictionBar->setVisible(
|
||||
m_data->hasPrediction && engine && engine->predictor() );
|
||||
m_data->prompt->setVisible( showPrompt );
|
||||
|
||||
Q_EMIT panelHintsChanged();
|
||||
}
|
||||
|
||||
QskInputPanel::PanelHints QskInputPanel::panelHints() const
|
||||
{
|
||||
return m_data->panelHints;
|
||||
}
|
||||
|
||||
void QskInputPanel::attachInputItem( QQuickItem* item )
|
||||
@ -172,29 +135,19 @@ void QskInputPanel::attachInputItem( QQuickItem* item )
|
||||
|
||||
m_data->inputItem = item;
|
||||
|
||||
if ( m_data->engine )
|
||||
m_data->engine->reset();
|
||||
|
||||
if ( item )
|
||||
{
|
||||
Qt::InputMethodQueries queries = Qt::ImQueryAll;
|
||||
queries &= ~Qt::ImEnabled;
|
||||
|
||||
processInputMethodQueries( queries );
|
||||
|
||||
if ( m_data->hasInputProxy )
|
||||
if ( m_data->panelHints & QskInputPanel::InputProxy )
|
||||
{
|
||||
m_data->inputProxy->setupFrom( item );
|
||||
m_data->inputProxy->setEditing( true );
|
||||
|
||||
// hiding the cursor in the real input item
|
||||
// hiding the cursor in item
|
||||
const QInputMethodEvent::Attribute attribute(
|
||||
QInputMethodEvent::Cursor, 0, 0, QVariant() );
|
||||
|
||||
QInputMethodEvent event( QString(), { attribute } );
|
||||
QCoreApplication::sendEvent( item, &event );
|
||||
|
||||
// not all information is available from the input method query
|
||||
m_data->inputProxy->setup( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,17 +162,6 @@ QQuickItem* QskInputPanel::inputProxy() const
|
||||
return m_data->inputProxy;
|
||||
}
|
||||
|
||||
void QskInputPanel::updatePrediction()
|
||||
{
|
||||
m_data->predictionBar->setPrediction(
|
||||
m_data->engine->prediction() );
|
||||
}
|
||||
|
||||
QskInputEngine* QskInputPanel::engine()
|
||||
{
|
||||
return m_data->engine;
|
||||
}
|
||||
|
||||
QskAspect::Subcontrol QskInputPanel::effectiveSubcontrol(
|
||||
QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
@ -242,226 +184,16 @@ void QskInputPanel::setInputPrompt( const QString& text )
|
||||
{
|
||||
prompt->setText( text );
|
||||
|
||||
if ( m_data->hasInputProxy )
|
||||
if ( m_data->panelHints & QskInputPanel::InputProxy )
|
||||
prompt->setVisible( !text.isEmpty() );
|
||||
|
||||
Q_EMIT inputPromptChanged( text );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskInputPanel::hasInputProxy() const
|
||||
void QskInputPanel::setPrediction( const QStringList& prediction )
|
||||
{
|
||||
return m_data->hasInputProxy;
|
||||
}
|
||||
|
||||
void QskInputPanel::setInputProxy( bool on )
|
||||
{
|
||||
if ( m_data->hasInputProxy == on )
|
||||
return;
|
||||
|
||||
m_data->hasInputProxy = on;
|
||||
m_data->inputProxy->setVisible( on );
|
||||
|
||||
auto prompt = m_data->prompt;
|
||||
|
||||
if ( on )
|
||||
prompt->setVisible( !prompt->text().isEmpty() );
|
||||
else
|
||||
prompt->setVisible( false );
|
||||
}
|
||||
|
||||
void QskInputPanel::commitPredictiveText( int index )
|
||||
{
|
||||
m_data->predictionBar->setPrediction( QStringList() );
|
||||
|
||||
if ( m_data->engine )
|
||||
{
|
||||
const QString text = m_data->engine->predictiveText( index );
|
||||
|
||||
m_data->engine->reset();
|
||||
Q_EMIT textEntered( text, true );
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputPanel::commitKey( int key )
|
||||
{
|
||||
if ( m_data->engine == nullptr || m_data->inputItem == nullptr )
|
||||
return;
|
||||
|
||||
int spaceLeft = -1;
|
||||
|
||||
if ( !( m_data->inputHints & Qt::ImhMultiLine ) )
|
||||
{
|
||||
auto receiver = m_data->receiverItem();
|
||||
|
||||
if ( m_data->maxChars >= 0 )
|
||||
{
|
||||
QInputMethodQueryEvent event( Qt::ImSurroundingText );
|
||||
QCoreApplication::sendEvent( receiver, &event );
|
||||
|
||||
const auto text = event.value( Qt::ImSurroundingText ).toString();
|
||||
spaceLeft = m_data->maxChars - text.length();
|
||||
}
|
||||
}
|
||||
|
||||
processKey( key, m_data->inputHints, spaceLeft );
|
||||
}
|
||||
|
||||
void QskInputPanel::processKey( int key,
|
||||
Qt::InputMethodHints inputHints, int spaceLeft )
|
||||
{
|
||||
const auto result = m_data->engine->processKey( key, inputHints, spaceLeft );
|
||||
|
||||
auto inputItem = m_data->inputItem;
|
||||
|
||||
if ( result.key )
|
||||
{
|
||||
switch( result.key )
|
||||
{
|
||||
case Qt::Key_Return:
|
||||
{
|
||||
Q_EMIT done( true );
|
||||
break;
|
||||
}
|
||||
case Qt::Key_Escape:
|
||||
{
|
||||
Q_EMIT done( false );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Q_EMIT keyEntered( result.key );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( !result.text.isEmpty() )
|
||||
{
|
||||
Q_EMIT textEntered( result.text, result.isFinal );
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputPanel::processInputMethodQueries( Qt::InputMethodQueries queries )
|
||||
{
|
||||
if ( m_data->inputItem == nullptr )
|
||||
return;
|
||||
|
||||
QInputMethodQueryEvent event( queries );
|
||||
QCoreApplication::sendEvent( m_data->inputItem, &event );
|
||||
|
||||
if ( event.queries() & Qt::ImHints )
|
||||
{
|
||||
bool hasPrediction = true;
|
||||
QskTextInput::EchoMode echoMode = QskTextInput::Normal;
|
||||
|
||||
const auto hints = static_cast< Qt::InputMethodHints >(
|
||||
event.value( Qt::ImHints ).toInt() );
|
||||
|
||||
if ( hints & Qt::ImhHiddenText )
|
||||
{
|
||||
echoMode = QskTextInput::NoEcho;
|
||||
}
|
||||
|
||||
/*
|
||||
- Qt::ImhSensitiveData
|
||||
- Qt::ImhNoAutoUppercase
|
||||
- Qt::ImhMultiLine
|
||||
|
||||
// we should start in a specific mode
|
||||
|
||||
- Qt::ImhPreferNumbers
|
||||
- Qt::ImhPreferUppercase
|
||||
- Qt::ImhPreferLowercase
|
||||
- Qt::ImhPreferLatin
|
||||
|
||||
// we should lock all other modes
|
||||
|
||||
- Qt::ImhFormattedNumbersOnly
|
||||
- Qt::ImhUppercaseOnly
|
||||
- Qt::ImhDialableCharactersOnly
|
||||
- Qt::ImhEmailCharactersOnly
|
||||
- Qt::ImhUrlCharactersOnly
|
||||
- Qt::ImhLatinOnly
|
||||
|
||||
// we should have specific input panels
|
||||
|
||||
- Qt::ImhDate
|
||||
- Qt::ImhTime
|
||||
- Qt::ImhDigitsOnly
|
||||
- Qt::ImhFormattedNumbersOnly
|
||||
*/
|
||||
|
||||
m_data->hasPrediction =
|
||||
!( hints & ( Qt::ImhNoPredictiveText | Qt::ImhExclusiveInputMask ) );
|
||||
|
||||
m_data->predictionBar->setVisible(
|
||||
hasPrediction && m_data->engine && m_data->engine->predictor() );
|
||||
|
||||
m_data->inputProxy->setEchoMode( echoMode );
|
||||
|
||||
m_data->inputHints = hints;
|
||||
}
|
||||
|
||||
if ( event.queries() & Qt::ImPreferredLanguage )
|
||||
{
|
||||
// already handled by the input context
|
||||
}
|
||||
|
||||
if ( event.queries() & Qt::ImMaximumTextLength )
|
||||
{
|
||||
// needs to be handled before Qt::ImCursorPosition !
|
||||
|
||||
m_data->maxChars = event.value( Qt::ImMaximumTextLength ).toInt();
|
||||
#if 1
|
||||
if ( m_data->maxChars >= 32767 )
|
||||
m_data->maxChars = -1;
|
||||
#endif
|
||||
|
||||
if ( m_data->hasInputProxy )
|
||||
m_data->inputProxy->setMaxLength( m_data->maxChars );
|
||||
}
|
||||
|
||||
|
||||
if ( event.queries() & Qt::ImSurroundingText )
|
||||
{
|
||||
if ( m_data->hasInputProxy )
|
||||
{
|
||||
const auto text = event.value( Qt::ImSurroundingText ).toString();
|
||||
m_data->inputProxy->setText( text );
|
||||
}
|
||||
}
|
||||
|
||||
if ( event.queries() & Qt::ImCursorPosition )
|
||||
{
|
||||
if ( m_data->hasInputProxy )
|
||||
{
|
||||
const auto pos = event.value( Qt::ImCursorPosition ).toInt();
|
||||
m_data->inputProxy->setCursorPosition( pos );
|
||||
}
|
||||
}
|
||||
|
||||
if ( event.queries() & Qt::ImCurrentSelection )
|
||||
{
|
||||
#if 0
|
||||
const auto text = event.value( Qt::ImCurrentSelection ).toString();
|
||||
if ( !text.isEmpty() )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
Qt::ImMicroFocus
|
||||
Qt::ImCursorRectangle
|
||||
Qt::ImFont
|
||||
Qt::ImAnchorPosition
|
||||
|
||||
Qt::ImAbsolutePosition
|
||||
Qt::ImTextBeforeCursor
|
||||
Qt::ImTextAfterCursor
|
||||
Qt::ImPlatformData // hard to say...
|
||||
Qt::ImEnterKeyType
|
||||
Qt::ImAnchorRectangle
|
||||
Qt::ImInputItemClipRectangle
|
||||
*/
|
||||
m_data->predictionBar->setPrediction( prediction );
|
||||
}
|
||||
|
||||
void QskInputPanel::keyPressEvent( QKeyEvent* event )
|
||||
@ -473,7 +205,7 @@ void QskInputPanel::keyPressEvent( QKeyEvent* event )
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Escape:
|
||||
{
|
||||
commitKey( event->key() );
|
||||
Q_EMIT keySelected( event->key() );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -492,17 +224,13 @@ void QskInputPanel::keyPressEvent( QKeyEvent* event )
|
||||
default:
|
||||
{
|
||||
const auto text = event->text();
|
||||
|
||||
if ( !text.isEmpty() )
|
||||
commitKey( text[0].unicode() );
|
||||
Q_EMIT keySelected( text[0].unicode() );
|
||||
else
|
||||
commitKey( event->key() );
|
||||
Q_EMIT keySelected( event->key() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputPanel::keyReleaseEvent( QKeyEvent* event )
|
||||
{
|
||||
return Inherited::keyReleaseEvent( event );
|
||||
}
|
||||
|
||||
#include "moc_QskInputPanel.cpp"
|
||||
|
@ -20,8 +20,8 @@ class QSK_EXPORT QskInputPanel : public QskBox
|
||||
|
||||
using Inherited = QskBox;
|
||||
|
||||
Q_PROPERTY( bool inputProxy READ hasInputProxy
|
||||
WRITE setInputProxy NOTIFY inputProxyChanged )
|
||||
Q_PROPERTY( PanelHints panelHints READ panelHints
|
||||
WRITE setPanelHints NOTIFY panelHintsChanged )
|
||||
|
||||
Q_PROPERTY( QString inputPrompt READ inputPrompt
|
||||
WRITE setInputPrompt NOTIFY inputPromptChanged )
|
||||
@ -29,16 +29,26 @@ class QSK_EXPORT QskInputPanel : public QskBox
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel )
|
||||
|
||||
enum PanelHint
|
||||
{
|
||||
InputProxy = 1 << 0,
|
||||
Prediction = 1 << 1
|
||||
};
|
||||
|
||||
Q_ENUM( PanelHint )
|
||||
Q_DECLARE_FLAGS( PanelHints, PanelHint )
|
||||
|
||||
QskInputPanel( QQuickItem* parent = nullptr );
|
||||
virtual ~QskInputPanel() override;
|
||||
|
||||
void attachInputItem( QQuickItem* );
|
||||
QQuickItem* attachedInputItem() const;
|
||||
|
||||
void setEngine( QskInputEngine* );
|
||||
QskInputEngine* engine();
|
||||
void setPanelHint( PanelHint, bool on );
|
||||
|
||||
void setPanelHints( PanelHints );
|
||||
PanelHints panelHints() const;
|
||||
|
||||
bool hasInputProxy() const;
|
||||
QQuickItem* inputProxy() const;
|
||||
|
||||
QString inputPrompt() const;
|
||||
@ -46,35 +56,26 @@ public:
|
||||
virtual QskAspect::Subcontrol effectiveSubcontrol(
|
||||
QskAspect::Subcontrol ) const override;
|
||||
|
||||
virtual void processInputMethodQueries( Qt::InputMethodQueries );
|
||||
|
||||
Q_SIGNALS:
|
||||
void inputProxyChanged( bool );
|
||||
void panelHintsChanged();
|
||||
void inputPromptChanged( const QString& );
|
||||
|
||||
void textEntered( const QString&, bool isFinal );
|
||||
void keyEntered( int keyCode );
|
||||
void done( bool success );
|
||||
void keySelected( int keyCode );
|
||||
void predictiveTextSelected( int );
|
||||
|
||||
public Q_SLOTS:
|
||||
void setInputPrompt( const QString& );
|
||||
void setInputProxy( bool );
|
||||
void setPrediction( const QStringList& );
|
||||
|
||||
protected:
|
||||
virtual void keyPressEvent( QKeyEvent* ) override;
|
||||
virtual void keyReleaseEvent( QKeyEvent* ) override;
|
||||
|
||||
virtual void processKey( int key,
|
||||
Qt::InputMethodHints, int spaceLeft );
|
||||
|
||||
virtual void updatePrediction();
|
||||
|
||||
private:
|
||||
void commitKey( int key );
|
||||
void commitPredictiveText( int );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( QskInputPanel::PanelHints )
|
||||
Q_DECLARE_METATYPE( QskInputPanel::PanelHints )
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user