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 void update( Qt::InputMethodQueries ) override;
|
||||
Q_INVOKABLE void update( const QQuickItem*, Qt::InputMethodQueries );
|
||||
|
||||
virtual void invokeAction( QInputMethod::Action, int ) override;
|
||||
|
||||
virtual QRectF keyboardRect() const override;
|
||||
@ -64,6 +66,8 @@ public:
|
||||
|
||||
virtual void showInputPanel() override;
|
||||
virtual void hideInputPanel() override;
|
||||
Q_INVOKABLE void setInputPanelVisible( const QQuickItem*, bool );
|
||||
|
||||
virtual bool isInputPanelVisible() const override;
|
||||
|
||||
virtual void reset() override;
|
||||
@ -76,8 +80,6 @@ public:
|
||||
|
||||
virtual bool filterEvent( const QEvent* ) override;
|
||||
|
||||
Q_INVOKABLE void update( const QQuickItem*, Qt::InputMethodQueries );
|
||||
|
||||
protected:
|
||||
virtual bool event( QEvent* ) override;
|
||||
|
||||
@ -164,10 +166,7 @@ void QskPlatformInputContext::invokeAction(
|
||||
QInputMethod::Action action, int cursorPosition )
|
||||
{
|
||||
if ( m_context )
|
||||
{
|
||||
if ( action == QInputMethod::Click )
|
||||
m_context->processClickAt( cursorPosition );
|
||||
}
|
||||
m_context->invokeAction( action, cursorPosition );
|
||||
}
|
||||
|
||||
QRectF QskPlatformInputContext::keyboardRect() const
|
||||
@ -188,20 +187,25 @@ bool QskPlatformInputContext::isAnimating() const
|
||||
|
||||
void QskPlatformInputContext::showInputPanel()
|
||||
{
|
||||
if ( m_context )
|
||||
m_context->setActive( true );
|
||||
setInputPanelVisible( nullptr, true );
|
||||
}
|
||||
|
||||
void QskPlatformInputContext::hideInputPanel()
|
||||
{
|
||||
setInputPanelVisible( nullptr, false );
|
||||
}
|
||||
|
||||
void QskPlatformInputContext::setInputPanelVisible(
|
||||
const QQuickItem* item, bool on )
|
||||
{
|
||||
if ( m_context )
|
||||
m_context->setActive( false );
|
||||
m_context->setInputPanelVisible( item, on );
|
||||
}
|
||||
|
||||
bool QskPlatformInputContext::isInputPanelVisible() const
|
||||
{
|
||||
if ( m_context )
|
||||
return m_context->isActive();
|
||||
return m_context->isInputPanelVisible();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -303,17 +303,13 @@ int main( int argc, char* argv[] )
|
||||
qskDialog->setPolicy( QskDialog::EmbeddedBox );
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
QskInputContext::setInputEngine( ... );
|
||||
#endif
|
||||
|
||||
Window window1;
|
||||
window1.setObjectName( "Window 1" );
|
||||
window1.setColor( "PapayaWhip" );
|
||||
window1.resize( 600, 600 );
|
||||
window1.show();
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
Window window2;
|
||||
window2.setObjectName( "Window 2" );
|
||||
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 )
|
||||
{
|
||||
if ( item )
|
||||
|
@ -31,6 +31,7 @@ QSK_EXPORT void qskForceActiveFocus( QQuickItem*, Qt::FocusReason );
|
||||
QSK_EXPORT QList< QQuickItem* > qskPaintOrderChildItems( const QQuickItem* );
|
||||
|
||||
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* qskPaintNode( const QQuickItem* );
|
||||
|
@ -302,9 +302,7 @@ void QskTextInput::keyPressEvent( QKeyEvent* event )
|
||||
#if 1
|
||||
case Qt::Key_Escape:
|
||||
{
|
||||
QGuiApplication::inputMethod()->hide();
|
||||
setEditing( false );
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -563,7 +561,7 @@ void QskTextInput::setEditing( bool on )
|
||||
updateInputMethod(Qt::ImCursorRectangle | Qt::ImAnchorRectangle);
|
||||
QGuiApplication::inputMethod()->inputDirection
|
||||
#endif
|
||||
inputMethod->show();
|
||||
qskInputMethodSetVisible( this, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -579,7 +577,7 @@ void QskTextInput::setEditing( bool on )
|
||||
#if 0
|
||||
inputMethod->reset();
|
||||
#endif
|
||||
inputMethod->hide();
|
||||
qskInputMethodSetVisible( this, false );
|
||||
#if 1
|
||||
qskForceActiveFocus( this, Qt::PopupFocusReason );
|
||||
#endif
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include <QPointer>
|
||||
#include <QGuiApplication>
|
||||
#include <QMap>
|
||||
|
||||
QSK_QT_PRIVATE_BEGIN
|
||||
#include <private/qguiapplication_p.h>
|
||||
@ -71,6 +72,85 @@ namespace
|
||||
private:
|
||||
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;
|
||||
@ -116,14 +196,80 @@ QskInputContext* QskInputContext::instance()
|
||||
class QskInputContext::PrivateData
|
||||
{
|
||||
public:
|
||||
// item receiving the input
|
||||
QPointer< QQuickItem > inputItem;
|
||||
QPointer< QskInputPanel > panel;
|
||||
|
||||
// popup or window embedding the panel
|
||||
QskPopup* inputPopup = nullptr;
|
||||
QskWindow* inputWindow = nullptr;
|
||||
inline QskInputPanel* createPanel( QskInputContext* context ) const
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
||||
@ -166,313 +312,161 @@ QskTextPredictor* QskInputContext::textPredictor( const QLocale& locale )
|
||||
|
||||
void QskInputContext::update( const QQuickItem* item, Qt::InputMethodQueries queries )
|
||||
{
|
||||
if ( m_data->inputItem == nullptr )
|
||||
return;
|
||||
|
||||
if ( item == nullptr )
|
||||
{
|
||||
item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
|
||||
#if 1
|
||||
// those are coming from QQuickWindow based on focus changes
|
||||
return;
|
||||
#endif
|
||||
item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
|
||||
}
|
||||
|
||||
auto channel = m_data->channels.channel( item );
|
||||
if ( channel == nullptr )
|
||||
return;
|
||||
|
||||
if ( queries & Qt::ImEnabled )
|
||||
{
|
||||
QInputMethodQueryEvent event( Qt::ImEnabled );
|
||||
QCoreApplication::sendEvent( m_data->inputItem, &event );
|
||||
QCoreApplication::sendEvent( channel->item, &event );
|
||||
|
||||
if ( !event.value( Qt::ImEnabled ).toBool() )
|
||||
{
|
||||
hidePanel();
|
||||
hidePanel( item );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_data->panel )
|
||||
m_data->panel->updateInputPanel( queries );
|
||||
channel->panel->updateInputPanel( queries );
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel )
|
||||
void QskInputContext::showPanel( const QQuickItem* item )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 )
|
||||
if ( item == nullptr )
|
||||
return;
|
||||
|
||||
QskInputPanel* panel = nullptr;
|
||||
|
||||
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 ) )
|
||||
if ( m_data->channels.ancestorChannel( item ) )
|
||||
{
|
||||
// ignore: usually the input proxy of the panel
|
||||
// We are inside of an existing panel
|
||||
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 )
|
||||
{
|
||||
// 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 )
|
||||
QSize size = window->effectivePreferredSize();
|
||||
if ( size.isEmpty() )
|
||||
{
|
||||
auto window = createEmbeddingWindow( m_data->panel );
|
||||
|
||||
if ( window )
|
||||
{
|
||||
QSize size = window->effectivePreferredSize();
|
||||
if ( size.isEmpty() )
|
||||
{
|
||||
// no idea, may be something based on the screen size
|
||||
size = QSize( 800, 240 );
|
||||
}
|
||||
|
||||
window->resize( size );
|
||||
window->show();
|
||||
|
||||
window->setDeleteOnClose( true );
|
||||
window->installEventFilter( this );
|
||||
}
|
||||
|
||||
m_data->inputWindow = window;
|
||||
// no idea, may be something based on the screen size
|
||||
size = QSize( 800, 240 );
|
||||
}
|
||||
|
||||
window->resize( size );
|
||||
window->show();
|
||||
|
||||
window->setDeleteOnClose( true );
|
||||
|
||||
channel->window = window;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The input panel is embedded in a popup
|
||||
|
||||
delete m_data->inputWindow;
|
||||
auto popup = m_data->createPopup( panel );
|
||||
|
||||
if ( m_data->inputPopup == nullptr )
|
||||
{
|
||||
auto popup = createEmbeddingPopup( m_data->panel );
|
||||
|
||||
if ( popup )
|
||||
{
|
||||
popup->setParentItem( m_data->inputItem->window()->contentItem() );
|
||||
if ( popup->parent() == nullptr )
|
||||
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 )
|
||||
{
|
||||
popup->setParentItem( item->window()->contentItem() );
|
||||
popup->setParent( this );
|
||||
#if 1
|
||||
if ( auto focusItem = m_data->inputPopup->scopedFocusItem() )
|
||||
{
|
||||
/*
|
||||
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 );
|
||||
}
|
||||
popup->setVisible( true );
|
||||
#endif
|
||||
|
||||
channel->popup = popup;
|
||||
}
|
||||
|
||||
if ( m_data->panel )
|
||||
{
|
||||
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;
|
||||
panel->attachInputItem( const_cast< QQuickItem* >( item ) );
|
||||
}
|
||||
|
||||
void QskInputContext::setActive( bool on )
|
||||
void QskInputContext::hidePanel( const QQuickItem* item )
|
||||
{
|
||||
if ( on )
|
||||
showPanel();
|
||||
else
|
||||
hidePanel();
|
||||
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() );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskInputContext::isActive() const
|
||||
void QskInputContext::setInputPanelVisible( const QQuickItem* item, bool on )
|
||||
{
|
||||
const QQuickWindow* window = m_data->inputWindow;
|
||||
if ( window == nullptr && m_data->inputPopup )
|
||||
window = m_data->inputPopup->window();
|
||||
// called from inside the controls
|
||||
|
||||
return window && window->isVisible();
|
||||
if ( item == nullptr )
|
||||
item = qobject_cast< QQuickItem* >( QGuiApplication::focusObject() );
|
||||
|
||||
if ( item )
|
||||
{
|
||||
if ( on )
|
||||
showPanel( item );
|
||||
else
|
||||
hidePanel( item );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskInputContext::isInputPanelVisible() const
|
||||
{
|
||||
return m_data->channels.currentChannel() != nullptr;
|
||||
}
|
||||
|
||||
QLocale QskInputContext::locale() const
|
||||
{
|
||||
if ( m_data->panel )
|
||||
return m_data->panel->locale();
|
||||
if ( auto channel = m_data->channels.currentChannel() )
|
||||
{
|
||||
if ( channel->panel )
|
||||
return channel->panel->locale();
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@ -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 ):
|
||||
QObject( parent )
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "QskGlobal.h"
|
||||
#include <QObject>
|
||||
#include <Qt>
|
||||
#include <QInputMethod>
|
||||
#include <memory>
|
||||
|
||||
class QskTextPredictor;
|
||||
@ -45,8 +46,8 @@ public:
|
||||
|
||||
QRectF panelRect() const;
|
||||
|
||||
void setActive( bool );
|
||||
bool isActive() const;
|
||||
void setInputPanelVisible( const QQuickItem*, bool );
|
||||
bool isInputPanelVisible() const;
|
||||
|
||||
QLocale locale() const;
|
||||
|
||||
@ -62,24 +63,18 @@ Q_SIGNALS:
|
||||
void panelRectChanged();
|
||||
|
||||
protected:
|
||||
virtual bool eventFilter( QObject*, QEvent* ) override;
|
||||
|
||||
virtual QskPopup* createEmbeddingPopup( QskInputPanel* );
|
||||
virtual QskWindow* createEmbeddingWindow( QskInputPanel* );
|
||||
|
||||
virtual void showPanel();
|
||||
virtual void hidePanel();
|
||||
virtual void showPanel( const QQuickItem* );
|
||||
virtual void hidePanel( const QQuickItem* );
|
||||
|
||||
private:
|
||||
friend class QskPlatformInputContext;
|
||||
|
||||
// called from QskPlatformInputContext
|
||||
void setFocusObject( QObject* );
|
||||
void update( const QQuickItem*, Qt::InputMethodQueries );
|
||||
void processClickAt( int cursorPosition );
|
||||
void commitPrediction( bool );
|
||||
virtual void setFocusObject( QObject* );
|
||||
virtual void update( const QQuickItem*, Qt::InputMethodQueries );
|
||||
virtual void invokeAction( QInputMethod::Action, int cursorPosition );
|
||||
|
||||
void ensurePanel();
|
||||
void commitPrediction( bool );
|
||||
|
||||
class PrivateData;
|
||||
std::unique_ptr< PrivateData > m_data;
|
||||
|
Loading…
x
Reference in New Issue
Block a user