QskInputManager introduced

This commit is contained in:
Uwe Rathmann 2018-06-01 12:00:31 +02:00
parent 221b573287
commit 186b18587b
4 changed files with 241 additions and 83 deletions

View File

@ -4,8 +4,7 @@
*****************************************************************************/
#include "QskInputContext.h"
#include "QskInputPanel.h"
#include "QskInputEngine.h"
#include "QskInputManager.h"
#include "QskLinearBox.h"
#include "QskDialog.h"
@ -69,22 +68,19 @@ class QskInputContext::PrivateData
public:
// item receiving the input
QPointer< QQuickItem > inputItem;
QPointer< QskInputPanel > inputPanel;
// popup or window embedding the panel
QskPopup* inputPopup = nullptr;
QskWindow* inputWindow = nullptr;
QskInputEngine* engine = nullptr;
bool isPredictorDirty = true;
QskInputManager* inputManager = nullptr;
};
QskInputContext::QskInputContext():
m_data( new PrivateData() )
{
setObjectName( "InputContext" );
m_data->engine = new QskInputEngine( this );
m_data->inputManager = new QskInputManager( this );
}
QskInputContext::~QskInputContext()
@ -96,25 +92,22 @@ QQuickItem* QskInputContext::inputItem() const
return m_data->inputItem;
}
QskInputPanel* QskInputContext::inputPanel() const
QskControl* QskInputContext::inputPanel() const
{
if ( m_data->inputPanel == nullptr )
{
auto that = const_cast< QskInputContext* >( this );
auto panel = m_data->inputManager->panel( true );
auto panel = new QskInputPanel();
panel->setParent( that );
if ( panel->parent() != this )
{
panel->setParent( const_cast< QskInputContext* >( this ) );
connect( panel, &QQuickItem::visibleChanged,
this, &QskInputContext::activeChanged );
connect( panel, &QskControl::localeChanged,
this, &QskInputContext::updateLocale );
this, &QskInputContext::activeChanged, Qt::UniqueConnection );
m_data->inputPanel = panel;
connect( panel, &QskControl::localeChanged,
this, [] { qskSendToPlatformContext( QEvent::LocaleChange ); } );
}
return m_data->inputPanel;
return panel;
}
void QskInputContext::update( Qt::InputMethodQueries queries )
@ -131,8 +124,7 @@ void QskInputContext::update( Qt::InputMethodQueries queries )
}
}
if ( auto panel = inputPanel() )
panel->processInputMethodQueries( queries );
m_data->inputManager->processInputMethodQueries( queries );
}
QRectF QskInputContext::panelRect() const
@ -143,7 +135,7 @@ QRectF QskInputContext::panelRect() const
return QRectF();
}
QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel )
QskPopup* QskInputContext::createEmbeddingPopup( QskControl* panel )
{
auto popup = new QskPopup();
@ -154,24 +146,35 @@ QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel )
auto box = new QskLinearBox( popup );
box->addItem( panel );
/*
When the panel has an input proxy ( usually a local text input )
we don't need to see the input item and display the overlay
and align in the center of the window.
*/
const bool hasInputProxy = panel->hasInputProxy();
const auto alignment =
m_data->inputManager->panelAlignment() & Qt::AlignVertical_Mask;
popup->setOverlay( hasInputProxy );
popup->setOverlay( alignment == Qt::AlignVCenter );
if ( hasInputProxy )
box->setMargins( QMarginsF( 5, 5, 5, 5 ) );
else
box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge );
switch( alignment )
{
case Qt::AlignTop:
{
box->setExtraSpacingAt( Qt::BottomEdge | Qt::LeftEdge | Qt::RightEdge );
break;
}
case Qt::AlignVCenter:
{
box->setMargins( QMarginsF( 5, 5, 5, 5 ) );
break;
}
case Qt::AlignBottom:
default:
{
box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge );
}
}
return popup;
}
QskWindow* QskInputContext::createEmbeddingWindow( QskInputPanel* panel )
QskWindow* QskInputContext::createEmbeddingWindow( QskControl* panel )
{
auto window = new QskWindow();
@ -254,16 +257,12 @@ void QskInputContext::showPanel()
popup->setVisible( true );
popup->installEventFilter( this );
}
m_data->inputPopup = popup;
}
}
updatePredictor();
panel->setLocale( locale() );
panel->attachInputItem( m_data->inputItem );
panel->setEngine( m_data->engine );
m_data->inputManager->attachInputItem( m_data->inputItem );
}
void QskInputContext::hidePanel()
@ -285,17 +284,13 @@ void QskInputContext::hidePanel()
#endif
}
if ( auto panel = inputPanel() )
{
if ( auto panel = m_data->inputManager->panel( false ) )
panel->setParentItem( nullptr );
panel->attachInputItem( nullptr );
panel->setEngine( nullptr );
}
m_data->inputManager->attachInputItem( nullptr );
if ( m_data->inputPopup )
{
m_data->inputPopup->deleteLater();
}
if ( m_data->inputWindow )
{
@ -341,28 +336,6 @@ QLocale QskInputContext::locale() const
return QLocale();
}
void QskInputContext::updateLocale()
{
m_data->isPredictorDirty = true;
if ( isActive() )
updatePredictor();
qskSendToPlatformContext( QEvent::LocaleChange );
}
void QskInputContext::updatePredictor()
{
if ( m_data->isPredictorDirty )
{
if ( m_data->engine )
{
m_data->engine->setPredictor( textPredictor( locale() ) );
m_data->isPredictorDirty = false;
}
}
}
void QskInputContext::setFocusObject( QObject* focusObject )
{
if ( m_data->inputItem == nullptr || m_data->inputItem == focusObject )

View File

@ -12,7 +12,8 @@
#include <memory>
class QskTextPredictor;
class QskInputPanel;
class QskControl;
class QskInputManager;
class QskPopup;
class QskWindow;
class QQuickItem;
@ -27,19 +28,23 @@ public:
QskInputContext();
virtual ~QskInputContext();
virtual QRectF panelRect() const;
void setManager( QskInputManager* );
QskInputManager manager();
virtual void setActive( bool );
virtual bool isActive() const;
QRectF panelRect() const;
virtual QLocale locale() const;
void setActive( bool );
bool isActive() const;
virtual QQuickItem* inputItem() const;
virtual QskInputPanel* inputPanel() const;
QLocale locale() const;
QQuickItem* inputItem() const;
static QskInputContext* instance();
static void setInstance( QskInputContext* );
virtual QskTextPredictor* textPredictor( const QLocale& ) const;
Q_SIGNALS:
void activeChanged();
void panelRectChanged();
@ -47,13 +52,13 @@ Q_SIGNALS:
protected:
virtual bool eventFilter( QObject*, QEvent* ) override;
virtual QskPopup* createEmbeddingPopup( QskInputPanel* );
virtual QskWindow* createEmbeddingWindow( QskInputPanel* );
virtual QskPopup* createEmbeddingPopup( QskControl* );
virtual QskWindow* createEmbeddingWindow( QskControl* );
virtual void showPanel();
virtual void hidePanel();
virtual QskTextPredictor* textPredictor( const QLocale& ) const;
QskControl* inputPanel() const;
private:
friend class QskPlatformInputContext;
@ -64,12 +69,8 @@ private:
virtual void processClickAt( int cursorPosition );
virtual void commitPrediction( bool );
void updateLocale();
void updatePredictor();
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif

View File

@ -0,0 +1,138 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#include "QskInputManager.h"
#include "QskInputPanel.h"
#include "QskInputEngine.h"
#include "QskInputContext.h"
#include <QPointer>
class QskInputManager::PrivateData
{
public:
QPointer< QskInputEngine > engine;
QPointer< QskControl > panel;
QLocale predictorLocale;
};
QskInputManager::QskInputManager( QObject* parent ):
Inherited( parent ),
m_data( new PrivateData() )
{
}
QskInputManager::~QskInputManager()
{
}
void QskInputManager::attachInputItem( QQuickItem* item )
{
auto panel = qobject_cast< QskInputPanel* >( m_data->panel );
if ( panel == nullptr )
return;
if ( item )
{
auto context = QskInputContext::instance();
const auto locale = context->locale();
updateEngine( locale );
panel->setEngine( m_data->engine );
panel->setLocale( locale );
panel->attachInputItem( item );
}
else
{
panel->setEngine( nullptr );
panel->attachInputItem( nullptr );
}
}
void QskInputManager::processInputMethodQueries(
Qt::InputMethodQueries queries )
{
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
panel->processInputMethodQueries( queries );
}
QskControl* QskInputManager::panel( bool doCreate )
{
if ( m_data->panel == nullptr && doCreate )
{
m_data->panel = createPanel();
connect( m_data->panel, &QskControl::localeChanged,
this, &QskInputManager::updatePredictor, Qt::UniqueConnection );
}
return m_data->panel;
}
Qt::Alignment QskInputManager::panelAlignment() const
{
if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) )
{
if ( panel->hasInputProxy() )
{
/*
When the panel has an input proxy we don't need to see
the input item and can put the panel in the center
*/
return Qt::AlignVCenter;
}
}
return Qt::AlignBottom;
}
QskControl* QskInputManager::createPanel()
{
return new QskInputPanel();
}
QskInputEngine* QskInputManager::createEngine()
{
return new QskInputEngine();
}
void QskInputManager::updateEngine( const QLocale& locale )
{
auto context = QskInputContext::instance();
if ( m_data->engine == nullptr)
{
auto engine = createEngine();
if ( engine->parent() == nullptr )
engine->setParent( this );
m_data->predictorLocale = locale;
engine->setPredictor( context->textPredictor( locale ) );
m_data->engine = engine;
}
else
{
if ( m_data->predictorLocale != locale )
{
m_data->predictorLocale = locale;
m_data->engine->setPredictor( context->textPredictor( locale ) );
}
}
}
void QskInputManager::updatePredictor()
{
if ( m_data->panel && m_data->engine )
{
auto context = QskInputContext::instance();
const auto locale = context->locale();
if ( m_data->predictorLocale != locale )
m_data->engine->setPredictor( context->textPredictor( locale ) );
}
}

View File

@ -0,0 +1,46 @@
/******************************************************************************
* QSkinny - Copyright (C) 2016 Uwe Rathmann
* This file may be used under the terms of the QSkinny License, Version 1.0
*****************************************************************************/
#ifndef QSK_INPUT_MANAGER_H
#define QSK_INPUT_MANAGER_H
#include "QskGlobal.h"
#include <QObject>
#include <memory>
class QskInputEngine;
class QskControl;
class QQuickItem;
class QLocale;
class QSK_EXPORT QskInputManager : public QObject
{
Q_OBJECT
using Inherited = QObject;
public:
QskInputManager( QObject* parent = nullptr );
virtual ~QskInputManager() override;
virtual void attachInputItem( QQuickItem* );
virtual void processInputMethodQueries( Qt::InputMethodQueries );
QskControl* panel( bool doCreate );
virtual Qt::Alignment panelAlignment() const;
protected:
virtual QskControl* createPanel();
virtual QskInputEngine* createEngine();
void updatePredictor();
void updateEngine( const QLocale& );
private:
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};
#endif