support for input panels per window added
This commit is contained in:
parent
1fc4d3af18
commit
54f4655698
|
@ -57,6 +57,8 @@ public:
|
||||||
virtual bool hasCapability( Capability ) const override;
|
virtual bool hasCapability( Capability ) const override;
|
||||||
|
|
||||||
virtual void update( Qt::InputMethodQueries ) override;
|
virtual void update( Qt::InputMethodQueries ) override;
|
||||||
|
Q_INVOKABLE void update( const QQuickItem*, Qt::InputMethodQueries );
|
||||||
|
|
||||||
virtual void invokeAction( QInputMethod::Action, int ) override;
|
virtual void invokeAction( QInputMethod::Action, int ) override;
|
||||||
|
|
||||||
virtual QRectF keyboardRect() const override;
|
virtual QRectF keyboardRect() const override;
|
||||||
|
@ -64,6 +66,8 @@ public:
|
||||||
|
|
||||||
virtual void showInputPanel() override;
|
virtual void showInputPanel() override;
|
||||||
virtual void hideInputPanel() override;
|
virtual void hideInputPanel() override;
|
||||||
|
Q_INVOKABLE void setInputPanelVisible( const QQuickItem*, bool );
|
||||||
|
|
||||||
virtual bool isInputPanelVisible() const override;
|
virtual bool isInputPanelVisible() const override;
|
||||||
|
|
||||||
virtual void reset() override;
|
virtual void reset() override;
|
||||||
|
@ -76,8 +80,6 @@ public:
|
||||||
|
|
||||||
virtual bool filterEvent( const QEvent* ) override;
|
virtual bool filterEvent( const QEvent* ) override;
|
||||||
|
|
||||||
Q_INVOKABLE void update( const QQuickItem*, Qt::InputMethodQueries );
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool event( QEvent* ) override;
|
virtual bool event( QEvent* ) override;
|
||||||
|
|
||||||
|
@ -164,10 +166,7 @@ void QskPlatformInputContext::invokeAction(
|
||||||
QInputMethod::Action action, int cursorPosition )
|
QInputMethod::Action action, int cursorPosition )
|
||||||
{
|
{
|
||||||
if ( m_context )
|
if ( m_context )
|
||||||
{
|
m_context->invokeAction( action, cursorPosition );
|
||||||
if ( action == QInputMethod::Click )
|
|
||||||
m_context->processClickAt( cursorPosition );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF QskPlatformInputContext::keyboardRect() const
|
QRectF QskPlatformInputContext::keyboardRect() const
|
||||||
|
@ -188,20 +187,25 @@ bool QskPlatformInputContext::isAnimating() const
|
||||||
|
|
||||||
void QskPlatformInputContext::showInputPanel()
|
void QskPlatformInputContext::showInputPanel()
|
||||||
{
|
{
|
||||||
if ( m_context )
|
setInputPanelVisible( nullptr, true );
|
||||||
m_context->setActive( true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskPlatformInputContext::hideInputPanel()
|
void QskPlatformInputContext::hideInputPanel()
|
||||||
|
{
|
||||||
|
setInputPanelVisible( nullptr, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskPlatformInputContext::setInputPanelVisible(
|
||||||
|
const QQuickItem* item, bool on )
|
||||||
{
|
{
|
||||||
if ( m_context )
|
if ( m_context )
|
||||||
m_context->setActive( false );
|
m_context->setInputPanelVisible( item, on );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QskPlatformInputContext::isInputPanelVisible() const
|
bool QskPlatformInputContext::isInputPanelVisible() const
|
||||||
{
|
{
|
||||||
if ( m_context )
|
if ( m_context )
|
||||||
return m_context->isActive();
|
return m_context->isInputPanelVisible();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -303,17 +303,13 @@ int main( int argc, char* argv[] )
|
||||||
qskDialog->setPolicy( QskDialog::EmbeddedBox );
|
qskDialog->setPolicy( QskDialog::EmbeddedBox );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
QskInputContext::setInputEngine( ... );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Window window1;
|
Window window1;
|
||||||
window1.setObjectName( "Window 1" );
|
window1.setObjectName( "Window 1" );
|
||||||
window1.setColor( "PapayaWhip" );
|
window1.setColor( "PapayaWhip" );
|
||||||
window1.resize( 600, 600 );
|
window1.resize( 600, 600 );
|
||||||
window1.show();
|
window1.show();
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
Window window2;
|
Window window2;
|
||||||
window2.setObjectName( "Window 2" );
|
window2.setObjectName( "Window 2" );
|
||||||
window2.setColor( "Pink" );
|
window2.setColor( "Pink" );
|
||||||
|
|
|
@ -188,6 +188,43 @@ void qskUpdateInputMethod( const QQuickItem* item, Qt::InputMethodQueries querie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qskInputMethodSetVisible( const QQuickItem* item, bool on )
|
||||||
|
{
|
||||||
|
static QPlatformInputContext* context = nullptr;
|
||||||
|
static int methodId = -1;
|
||||||
|
|
||||||
|
auto inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
|
||||||
|
if ( inputContext == nullptr )
|
||||||
|
{
|
||||||
|
context = nullptr;
|
||||||
|
methodId = -1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( inputContext != context )
|
||||||
|
{
|
||||||
|
context = inputContext;
|
||||||
|
methodId = inputContext->metaObject()->indexOfMethod(
|
||||||
|
"setInputPanelVisible(const QQuickItem*,bool)" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( methodId >= 0 )
|
||||||
|
{
|
||||||
|
inputContext->metaObject()->method( methodId ).invoke(
|
||||||
|
inputContext, Qt::DirectConnection,
|
||||||
|
Q_ARG( const QQuickItem*, item ),
|
||||||
|
Q_ARG( bool, on ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( on )
|
||||||
|
QGuiApplication::inputMethod()->show();
|
||||||
|
else
|
||||||
|
QGuiApplication::inputMethod()->hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* item )
|
QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* item )
|
||||||
{
|
{
|
||||||
if ( item )
|
if ( item )
|
||||||
|
|
|
@ -31,6 +31,7 @@ QSK_EXPORT void qskForceActiveFocus( QQuickItem*, Qt::FocusReason );
|
||||||
QSK_EXPORT QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* );
|
QSK_EXPORT QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* );
|
||||||
|
|
||||||
QSK_EXPORT void qskUpdateInputMethod( const QQuickItem*, Qt::InputMethodQueries );
|
QSK_EXPORT void qskUpdateInputMethod( const QQuickItem*, Qt::InputMethodQueries );
|
||||||
|
QSK_EXPORT void qskInputMethodSetVisible( const QQuickItem*, bool );
|
||||||
|
|
||||||
QSK_EXPORT const QSGNode* qskItemNode( const QQuickItem* );
|
QSK_EXPORT const QSGNode* qskItemNode( const QQuickItem* );
|
||||||
QSK_EXPORT const QSGNode* qskPaintNode( const QQuickItem* );
|
QSK_EXPORT const QSGNode* qskPaintNode( const QQuickItem* );
|
||||||
|
|
|
@ -302,9 +302,7 @@ void QskTextInput::keyPressEvent( QKeyEvent* event )
|
||||||
#if 1
|
#if 1
|
||||||
case Qt::Key_Escape:
|
case Qt::Key_Escape:
|
||||||
{
|
{
|
||||||
QGuiApplication::inputMethod()->hide();
|
|
||||||
setEditing( false );
|
setEditing( false );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -563,7 +561,7 @@ void QskTextInput::setEditing( bool on )
|
||||||
updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
|
updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
|
||||||
QGuiApplication::inputMethod()->inputDirection
|
QGuiApplication::inputMethod()->inputDirection
|
||||||
#endif
|
#endif
|
||||||
inputMethod->show();
|
qskInputMethodSetVisible( this, true );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -579,7 +577,7 @@ void QskTextInput::setEditing( bool on )
|
||||||
#if 0
|
#if 0
|
||||||
inputMethod->reset();
|
inputMethod->reset();
|
||||||
#endif
|
#endif
|
||||||
inputMethod->hide();
|
qskInputMethodSetVisible( this, false );
|
||||||
#if 1
|
#if 1
|
||||||
qskForceActiveFocus( this, Qt::PopupFocusReason );
|
qskForceActiveFocus( this, Qt::PopupFocusReason );
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
QSK_QT_PRIVATE_BEGIN
|
QSK_QT_PRIVATE_BEGIN
|
||||||
#include <private/qguiapplication_p.h>
|
#include <private/qguiapplication_p.h>
|
||||||
|
@ -71,6 +72,85 @@ namespace
|
||||||
private:
|
private:
|
||||||
QskInputPanelBox* m_box;
|
QskInputPanelBox* m_box;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Channel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// item receiving the input
|
||||||
|
QPointer< QQuickItem > item;
|
||||||
|
|
||||||
|
// panel for inserting the input
|
||||||
|
QPointer< QskInputPanel > panel;
|
||||||
|
|
||||||
|
// popup or window embedding the panel
|
||||||
|
QPointer< QskPopup > popup;
|
||||||
|
QPointer< QskWindow > window;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChannelTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline Channel* currentChannel() const
|
||||||
|
{
|
||||||
|
const auto object = QGuiApplication::focusObject();
|
||||||
|
return channel( qobject_cast< const QQuickItem* >( object ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Channel* channel( const QQuickWindow* window ) const
|
||||||
|
{
|
||||||
|
if ( window )
|
||||||
|
{
|
||||||
|
auto it = m_map.constFind( window );
|
||||||
|
if ( it != m_map.constEnd() )
|
||||||
|
return const_cast< Channel* >( &it.value() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Channel* channel( const QQuickItem* item ) const
|
||||||
|
{
|
||||||
|
if ( item )
|
||||||
|
{
|
||||||
|
auto channel = this->channel( item->window() );
|
||||||
|
if ( channel && channel->item == item )
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Channel* ancestorChannel( const QQuickItem* item ) const
|
||||||
|
{
|
||||||
|
for ( auto it = m_map.constBegin();
|
||||||
|
it != m_map.constEnd(); ++it )
|
||||||
|
{
|
||||||
|
if ( const auto panel = it.value().panel )
|
||||||
|
{
|
||||||
|
if ( ( item == panel )
|
||||||
|
|| qskIsAncestorOf( panel, item ) )
|
||||||
|
{
|
||||||
|
return const_cast< Channel*>( &it.value() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Channel* insert( const QQuickWindow* window )
|
||||||
|
{
|
||||||
|
return &m_map[ window ];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void remove( const QQuickWindow* window )
|
||||||
|
{
|
||||||
|
m_map.remove( window );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMap< const QQuickWindow*, Channel > m_map;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static QPointer< QskInputContext > qskInputContext = nullptr;
|
static QPointer< QskInputContext > qskInputContext = nullptr;
|
||||||
|
@ -116,14 +196,80 @@ QskInputContext* QskInputContext::instance()
|
||||||
class QskInputContext::PrivateData
|
class QskInputContext::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// item receiving the input
|
|
||||||
QPointer< QQuickItem > inputItem;
|
|
||||||
QPointer< QskInputPanel > panel;
|
|
||||||
|
|
||||||
// popup or window embedding the panel
|
inline QskInputPanel* createPanel( QskInputContext* context ) const
|
||||||
QskPopup* inputPopup = nullptr;
|
{
|
||||||
QskWindow* inputWindow = nullptr;
|
QskInputPanel* panel = nullptr;
|
||||||
|
|
||||||
|
if ( this->factory )
|
||||||
|
panel = this->factory->createPanel();
|
||||||
|
|
||||||
|
if ( panel == nullptr )
|
||||||
|
panel = new Panel();
|
||||||
|
|
||||||
|
connect( panel, &QskInputPanel::visibleChanged,
|
||||||
|
context, &QskInputContext::activeChanged );
|
||||||
|
|
||||||
|
connect( panel, &QskInputPanel::localeChanged,
|
||||||
|
context, [] { qskSendToPlatformContext( QEvent::LocaleChange ); } );
|
||||||
|
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QskPopup* createPopup( QskInputPanel* panel ) const
|
||||||
|
{
|
||||||
|
auto popup = new QskPopup();
|
||||||
|
|
||||||
|
popup->setAutoLayoutChildren( true );
|
||||||
|
popup->setTransparentForPositioner( false );
|
||||||
|
popup->setModal( true );
|
||||||
|
|
||||||
|
auto box = new QskLinearBox( popup );
|
||||||
|
box->addItem( panel );
|
||||||
|
|
||||||
|
const auto alignment = panel->alignment() & Qt::AlignVertical_Mask;
|
||||||
|
popup->setOverlay( alignment == Qt::AlignVCenter );
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline QskWindow* createWindow( QskInputPanel* panel ) const
|
||||||
|
{
|
||||||
|
auto window = new QskWindow();
|
||||||
|
|
||||||
|
window->setFlags( window->flags() & Qt::Dialog );
|
||||||
|
//window->setModality( Qt::ApplicationModal );
|
||||||
|
window->setAutoLayoutChildren( true );
|
||||||
|
#if 0
|
||||||
|
window->setFlags( Qt::Tool | Qt::WindowDoesNotAcceptFocus );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
panel->setParentItem( window->contentItem() );
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelTable channels;
|
||||||
QPointer< QskInputContextFactory > factory;
|
QPointer< QskInputContextFactory > factory;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,150 +312,72 @@ QskTextPredictor* QskInputContext::textPredictor( const QLocale& locale )
|
||||||
|
|
||||||
void QskInputContext::update( const QQuickItem* item, Qt::InputMethodQueries queries )
|
void QskInputContext::update( const QQuickItem* item, Qt::InputMethodQueries queries )
|
||||||
{
|
{
|
||||||
if ( m_data->inputItem == nullptr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( item == nullptr )
|
if ( item == nullptr )
|
||||||
{
|
{
|
||||||
item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
|
|
||||||
#if 1
|
|
||||||
// those are coming from QQuickWindow based on focus changes
|
// those are coming from QQuickWindow based on focus changes
|
||||||
return;
|
item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto channel = m_data->channels.channel( item );
|
||||||
|
if ( channel == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
if ( queries & Qt::ImEnabled )
|
if ( queries & Qt::ImEnabled )
|
||||||
{
|
{
|
||||||
QInputMethodQueryEvent event( Qt::ImEnabled );
|
QInputMethodQueryEvent event( Qt::ImEnabled );
|
||||||
QCoreApplication::sendEvent( m_data->inputItem, &event );
|
QCoreApplication::sendEvent( channel->item, &event );
|
||||||
|
|
||||||
if ( !event.value( Qt::ImEnabled ).toBool() )
|
if ( !event.value( Qt::ImEnabled ).toBool() )
|
||||||
{
|
{
|
||||||
hidePanel();
|
hidePanel( item );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_data->panel )
|
channel->panel->updateInputPanel( queries );
|
||||||
m_data->panel->updateInputPanel( queries );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF QskInputContext::panelRect() const
|
QRectF QskInputContext::panelRect() const
|
||||||
{
|
{
|
||||||
if ( m_data->inputPopup )
|
/*
|
||||||
return m_data->inputPopup->geometry();
|
As we can have more than panel at the same time we
|
||||||
|
better don't return any geometry
|
||||||
|
*/
|
||||||
|
|
||||||
return QRectF();
|
return QRectF();
|
||||||
}
|
}
|
||||||
|
|
||||||
QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel )
|
void QskInputContext::showPanel( const QQuickItem* item )
|
||||||
{
|
{
|
||||||
auto popup = new QskPopup();
|
if ( item == nullptr )
|
||||||
|
|
||||||
popup->setAutoLayoutChildren( true );
|
|
||||||
popup->setTransparentForPositioner( false );
|
|
||||||
popup->setModal( true );
|
|
||||||
|
|
||||||
auto box = new QskLinearBox( popup );
|
|
||||||
box->addItem( panel );
|
|
||||||
|
|
||||||
const auto alignment = panel->alignment() & Qt::AlignVertical_Mask;
|
|
||||||
popup->setOverlay( alignment == Qt::AlignVCenter );
|
|
||||||
|
|
||||||
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 )
|
|
||||||
{
|
|
||||||
auto window = new QskWindow();
|
|
||||||
|
|
||||||
window->setFlags( window->flags() & Qt::Dialog );
|
|
||||||
//window->setModality( Qt::ApplicationModal );
|
|
||||||
window->setAutoLayoutChildren( true );
|
|
||||||
#if 0
|
|
||||||
window->setFlags( Qt::Tool | Qt::WindowDoesNotAcceptFocus );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
panel->setParentItem( window->contentItem() );
|
|
||||||
|
|
||||||
return window;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskInputContext::ensurePanel()
|
|
||||||
{
|
|
||||||
if ( m_data->panel )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QskInputPanel* panel = nullptr;
|
if ( m_data->channels.ancestorChannel( item ) )
|
||||||
|
|
||||||
if ( m_data->factory )
|
|
||||||
panel = m_data->factory->createPanel();
|
|
||||||
|
|
||||||
if ( panel == nullptr )
|
|
||||||
panel = new Panel();
|
|
||||||
|
|
||||||
panel->setParent( const_cast< QskInputContext* >( this ) );
|
|
||||||
|
|
||||||
connect( panel, &QskInputPanel::visibleChanged,
|
|
||||||
this, &QskInputContext::activeChanged,
|
|
||||||
Qt::UniqueConnection );
|
|
||||||
|
|
||||||
connect( panel, &QskInputPanel::localeChanged,
|
|
||||||
this, [] { qskSendToPlatformContext( QEvent::LocaleChange ); },
|
|
||||||
Qt::UniqueConnection );
|
|
||||||
|
|
||||||
m_data->panel = panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskInputContext::showPanel()
|
|
||||||
{
|
|
||||||
auto focusItem = qobject_cast< QQuickItem* >( qGuiApp->focusObject() );
|
|
||||||
if ( focusItem == nullptr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
ensurePanel();
|
|
||||||
|
|
||||||
if ( ( focusItem == m_data->panel )
|
|
||||||
|| qskIsAncestorOf( m_data->panel, focusItem ) )
|
|
||||||
{
|
{
|
||||||
// ignore: usually the input proxy of the panel
|
// We are inside of an existing panel
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_data->inputItem = focusItem;
|
if ( auto channel = m_data->channels.channel( item->window() ) )
|
||||||
|
{
|
||||||
|
if ( channel->item == item )
|
||||||
|
return;
|
||||||
|
|
||||||
|
hidePanel( channel->item );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto panel = m_data->createPanel( this );
|
||||||
|
|
||||||
|
auto channel = m_data->channels.insert( item->window() );
|
||||||
|
channel->item = const_cast< QQuickItem*>( item );
|
||||||
|
channel->panel = panel;
|
||||||
|
|
||||||
if ( QskDialog::instance()->policy() == QskDialog::TopLevelWindow )
|
if ( QskDialog::instance()->policy() == QskDialog::TopLevelWindow )
|
||||||
{
|
{
|
||||||
// The input panel is embedded in a top level window
|
// The input panel is embedded in a top level window
|
||||||
|
|
||||||
delete m_data->inputPopup;
|
auto window = m_data->createWindow( panel );
|
||||||
|
|
||||||
if ( m_data->inputWindow == nullptr )
|
|
||||||
{
|
|
||||||
auto window = createEmbeddingWindow( m_data->panel );
|
|
||||||
|
|
||||||
if ( window )
|
|
||||||
{
|
|
||||||
QSize size = window->effectivePreferredSize();
|
QSize size = window->effectivePreferredSize();
|
||||||
if ( size.isEmpty() )
|
if ( size.isEmpty() )
|
||||||
{
|
{
|
||||||
|
@ -321,158 +389,84 @@ void QskInputContext::showPanel()
|
||||||
window->show();
|
window->show();
|
||||||
|
|
||||||
window->setDeleteOnClose( true );
|
window->setDeleteOnClose( true );
|
||||||
window->installEventFilter( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_data->inputWindow = window;
|
channel->window = window;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// The input panel is embedded in a popup
|
// The input panel is embedded in a popup
|
||||||
|
|
||||||
delete m_data->inputWindow;
|
auto popup = m_data->createPopup( panel );
|
||||||
|
|
||||||
if ( m_data->inputPopup == nullptr )
|
popup->setParentItem( item->window()->contentItem() );
|
||||||
{
|
|
||||||
auto popup = createEmbeddingPopup( m_data->panel );
|
|
||||||
|
|
||||||
if ( popup )
|
|
||||||
{
|
|
||||||
popup->setParentItem( m_data->inputItem->window()->contentItem() );
|
|
||||||
if ( popup->parent() == nullptr )
|
|
||||||
popup->setParent( this );
|
popup->setParent( this );
|
||||||
|
|
||||||
popup->setVisible( true );
|
|
||||||
popup->installEventFilter( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_data->inputPopup = popup;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_data->panel->attachInputItem( m_data->inputItem );
|
|
||||||
}
|
|
||||||
|
|
||||||
void QskInputContext::hidePanel()
|
|
||||||
{
|
|
||||||
if ( m_data->inputPopup )
|
|
||||||
{
|
|
||||||
#if 1
|
#if 1
|
||||||
if ( auto focusItem = m_data->inputPopup->scopedFocusItem() )
|
popup->setVisible( true );
|
||||||
{
|
|
||||||
/*
|
|
||||||
Qt bug: QQuickItem::hasFocus() is not cleared
|
|
||||||
when the corresponding focusScope gets deleted.
|
|
||||||
Usually no problem, but here the focusItem is no
|
|
||||||
child and will be reused with a different parent
|
|
||||||
later.
|
|
||||||
*/
|
|
||||||
focusItem->setFocus( false );
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
channel->popup = popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( m_data->panel )
|
panel->attachInputItem( const_cast< QQuickItem* >( item ) );
|
||||||
{
|
|
||||||
m_data->panel->setParentItem( nullptr );
|
|
||||||
m_data->panel->disconnect( this );
|
|
||||||
|
|
||||||
m_data->panel->attachInputItem( nullptr );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( m_data->inputPopup )
|
|
||||||
m_data->inputPopup->deleteLater();
|
|
||||||
|
|
||||||
if ( m_data->inputWindow )
|
|
||||||
{
|
|
||||||
QskWindow* window = m_data->inputWindow;
|
|
||||||
m_data->inputWindow = nullptr;
|
|
||||||
|
|
||||||
window->removeEventFilter( this );
|
|
||||||
window->close(); // deleteOnClose is set
|
|
||||||
}
|
|
||||||
|
|
||||||
m_data->inputItem = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskInputContext::setActive( bool on )
|
void QskInputContext::hidePanel( const QQuickItem* item )
|
||||||
{
|
{
|
||||||
|
if ( item == nullptr )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( auto channel = m_data->channels.channel( item ) )
|
||||||
|
{
|
||||||
|
if ( channel->popup )
|
||||||
|
channel->popup->deleteLater();
|
||||||
|
|
||||||
|
if ( channel->window )
|
||||||
|
channel->window->close(); // deleteOnClose is set
|
||||||
|
|
||||||
|
m_data->channels.remove( item->window() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskInputContext::setInputPanelVisible( const QQuickItem* item, bool on )
|
||||||
|
{
|
||||||
|
// called from inside the controls
|
||||||
|
|
||||||
|
if ( item == nullptr )
|
||||||
|
item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
|
||||||
|
|
||||||
|
if ( item )
|
||||||
|
{
|
||||||
if ( on )
|
if ( on )
|
||||||
showPanel();
|
showPanel( item );
|
||||||
else
|
else
|
||||||
hidePanel();
|
hidePanel( item );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QskInputContext::isActive() const
|
bool QskInputContext::isInputPanelVisible() const
|
||||||
{
|
{
|
||||||
const QQuickWindow* window = m_data->inputWindow;
|
return m_data->channels.currentChannel() != nullptr;
|
||||||
if ( window == nullptr && m_data->inputPopup )
|
|
||||||
window = m_data->inputPopup->window();
|
|
||||||
|
|
||||||
return window && window->isVisible();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QLocale QskInputContext::locale() const
|
QLocale QskInputContext::locale() const
|
||||||
{
|
{
|
||||||
if ( m_data->panel )
|
if ( auto channel = m_data->channels.currentChannel() )
|
||||||
return m_data->panel->locale();
|
{
|
||||||
|
if ( channel->panel )
|
||||||
|
return channel->panel->locale();
|
||||||
|
}
|
||||||
|
|
||||||
return QLocale();
|
return QLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskInputContext::setFocusObject( QObject* focusObject )
|
void QskInputContext::setFocusObject( QObject* )
|
||||||
{
|
{
|
||||||
if ( m_data->inputItem == nullptr || m_data->inputItem == focusObject )
|
|
||||||
{
|
|
||||||
// we don't care
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto w = m_data->inputItem->window();
|
|
||||||
if ( w == nullptr )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ( m_data->inputWindow )
|
|
||||||
{
|
|
||||||
if ( focusObject == nullptr )
|
|
||||||
{
|
|
||||||
if ( m_data->inputItem->hasFocus() )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
As long as the focus is nowhere and
|
|
||||||
the local focus stay on the input item
|
|
||||||
we don't care
|
|
||||||
*/
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const auto focusItem = qobject_cast< QQuickItem* >( focusObject );
|
|
||||||
if ( focusItem && focusItem->window() == m_data->inputWindow )
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( m_data->inputPopup )
|
|
||||||
{
|
|
||||||
if ( w->contentItem()->scopedFocusItem() == m_data->inputPopup )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
As long as the focus stays inside the inputPopup
|
|
||||||
we don't care
|
|
||||||
*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hidePanel();
|
|
||||||
m_data->inputItem = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QskInputContext::processClickAt( int cursorPosition )
|
void QskInputContext::invokeAction(
|
||||||
|
QInputMethod::Action, int cursorPosition )
|
||||||
{
|
{
|
||||||
|
// called from qquicktextinput/qquicktextedit
|
||||||
Q_UNUSED( cursorPosition );
|
Q_UNUSED( cursorPosition );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -485,53 +479,6 @@ void QskInputContext::commitPrediction( bool )
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QskInputContext::eventFilter( QObject* object, QEvent* event )
|
|
||||||
{
|
|
||||||
if ( object == m_data->inputWindow )
|
|
||||||
{
|
|
||||||
switch( event->type() )
|
|
||||||
{
|
|
||||||
case QEvent::Move:
|
|
||||||
{
|
|
||||||
Q_EMIT panelRectChanged();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QEvent::Resize:
|
|
||||||
{
|
|
||||||
if ( m_data->panel )
|
|
||||||
m_data->panel->setSize( m_data->inputWindow->size() );
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QEvent::DeferredDelete:
|
|
||||||
{
|
|
||||||
m_data->inputWindow = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( object == m_data->inputPopup )
|
|
||||||
{
|
|
||||||
switch( static_cast< int >( event->type() ) )
|
|
||||||
{
|
|
||||||
case QskEvent::GeometryChange:
|
|
||||||
{
|
|
||||||
Q_EMIT panelRectChanged();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QEvent::DeferredDelete:
|
|
||||||
{
|
|
||||||
m_data->inputPopup = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Inherited::eventFilter( object, event );
|
|
||||||
}
|
|
||||||
|
|
||||||
QskInputContextFactory::QskInputContextFactory( QObject* parent ):
|
QskInputContextFactory::QskInputContextFactory( QObject* parent ):
|
||||||
QObject( parent )
|
QObject( parent )
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "QskGlobal.h"
|
#include "QskGlobal.h"
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <Qt>
|
#include <Qt>
|
||||||
|
#include <QInputMethod>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class QskTextPredictor;
|
class QskTextPredictor;
|
||||||
|
@ -45,8 +46,8 @@ public:
|
||||||
|
|
||||||
QRectF panelRect() const;
|
QRectF panelRect() const;
|
||||||
|
|
||||||
void setActive( bool );
|
void setInputPanelVisible( const QQuickItem*, bool );
|
||||||
bool isActive() const;
|
bool isInputPanelVisible() const;
|
||||||
|
|
||||||
QLocale locale() const;
|
QLocale locale() const;
|
||||||
|
|
||||||
|
@ -62,24 +63,18 @@ Q_SIGNALS:
|
||||||
void panelRectChanged();
|
void panelRectChanged();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool eventFilter( QObject*, QEvent* ) override;
|
virtual void showPanel( const QQuickItem* );
|
||||||
|
virtual void hidePanel( const QQuickItem* );
|
||||||
virtual QskPopup* createEmbeddingPopup( QskInputPanel* );
|
|
||||||
virtual QskWindow* createEmbeddingWindow( QskInputPanel* );
|
|
||||||
|
|
||||||
virtual void showPanel();
|
|
||||||
virtual void hidePanel();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class QskPlatformInputContext;
|
friend class QskPlatformInputContext;
|
||||||
|
|
||||||
// called from QskPlatformInputContext
|
// called from QskPlatformInputContext
|
||||||
void setFocusObject( QObject* );
|
virtual void setFocusObject( QObject* );
|
||||||
void update( const QQuickItem*, Qt::InputMethodQueries );
|
virtual void update( const QQuickItem*, Qt::InputMethodQueries );
|
||||||
void processClickAt( int cursorPosition );
|
virtual void invokeAction( QInputMethod::Action, int cursorPosition );
|
||||||
void commitPrediction( bool );
|
|
||||||
|
|
||||||
void ensurePanel();
|
void commitPrediction( bool );
|
||||||
|
|
||||||
class PrivateData;
|
class PrivateData;
|
||||||
std::unique_ptr< PrivateData > m_data;
|
std::unique_ptr< PrivateData > m_data;
|
||||||
|
|
Loading…
Reference in New Issue