improving QskInputContext
This commit is contained in:
parent
0ee83c1e32
commit
d1ecec2ad8
|
@ -10,6 +10,7 @@
|
||||||
#include "QskHunspellCompositionModel.h"
|
#include "QskHunspellCompositionModel.h"
|
||||||
|
|
||||||
#include "QskInputPanel.h"
|
#include "QskInputPanel.h"
|
||||||
|
#include "QskLinearBox.h"
|
||||||
#include <QskDialog.h>
|
#include <QskDialog.h>
|
||||||
#include <QskPopup.h>
|
#include <QskPopup.h>
|
||||||
#include <QskWindow.h>
|
#include <QskWindow.h>
|
||||||
|
@ -91,8 +92,8 @@ public:
|
||||||
QPointer< QQuickItem > inputPanel;
|
QPointer< QQuickItem > inputPanel;
|
||||||
|
|
||||||
// popup or window embedding the inputPanel
|
// popup or window embedding the inputPanel
|
||||||
QPointer< QskPopup > inputPopup;
|
QskPopup* inputPopup = nullptr;
|
||||||
QPointer< QskWindow > inputWindow;
|
QskWindow* inputWindow = nullptr;
|
||||||
|
|
||||||
QskInputCompositionModel* compositionModel;
|
QskInputCompositionModel* compositionModel;
|
||||||
QHash< QLocale, QskInputCompositionModel* > compositionModels;
|
QHash< QLocale, QskInputCompositionModel* > compositionModels;
|
||||||
|
@ -320,9 +321,14 @@ void QskInputContext::showInputPanel()
|
||||||
{
|
{
|
||||||
auto popup = new QskPopup( m_data->inputItem->window()->contentItem() );
|
auto popup = new QskPopup( m_data->inputItem->window()->contentItem() );
|
||||||
popup->setAutoLayoutChildren( true );
|
popup->setAutoLayoutChildren( true );
|
||||||
|
popup->setTransparentForPositioner( false );
|
||||||
|
popup->setOverlay( false );
|
||||||
popup->setModal( true );
|
popup->setModal( true );
|
||||||
|
|
||||||
inputPanel->setParentItem( popup );
|
auto box = new QskLinearBox( popup );
|
||||||
|
box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge );
|
||||||
|
box->addItem( inputPanel );
|
||||||
|
|
||||||
inputPopup = popup;
|
inputPopup = popup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -343,7 +349,6 @@ void QskInputContext::showInputPanel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inputPopup->setGeometry( qskItemGeometry( inputPopup->parentItem() ) );
|
|
||||||
inputPopup->setVisible( true );
|
inputPopup->setVisible( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,19 +368,13 @@ void QskInputContext::hideInputPanel()
|
||||||
|
|
||||||
if ( m_data->inputPopup == m_data->inputPanel )
|
if ( m_data->inputPopup == m_data->inputPanel )
|
||||||
{
|
{
|
||||||
|
|
||||||
m_data->inputPopup->removeEventFilter( this );
|
m_data->inputPopup->removeEventFilter( this );
|
||||||
m_data->inputPopup = nullptr;
|
m_data->inputPopup = nullptr;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if ( m_data->inputPopup )
|
if ( m_data->inputPopup )
|
||||||
{
|
m_data->inputPopup->deleteLater();
|
||||||
auto popup = m_data->inputPopup.data();
|
|
||||||
m_data->inputPopup = nullptr;
|
|
||||||
|
|
||||||
popup->deleteLater();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QskWindow* window = m_data->inputWindow;
|
QskWindow* window = m_data->inputWindow;
|
||||||
|
@ -599,40 +598,78 @@ void QskInputContext::commit()
|
||||||
|
|
||||||
bool QskInputContext::eventFilter( QObject* object, QEvent* event )
|
bool QskInputContext::eventFilter( QObject* object, QEvent* event )
|
||||||
{
|
{
|
||||||
switch( static_cast< int >( event->type() ) )
|
if ( object == m_data->inputWindow )
|
||||||
{
|
{
|
||||||
case QEvent::Move:
|
switch( event->type() )
|
||||||
case QEvent::Resize:
|
|
||||||
{
|
{
|
||||||
if ( m_data->inputPanel && object == m_data->inputPanel->window() )
|
case QEvent::Move:
|
||||||
emitKeyboardRectChanged();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QskEvent::GeometryChange:
|
|
||||||
{
|
|
||||||
if ( object == m_data->inputPopup )
|
|
||||||
emitKeyboardRectChanged();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case QEvent::InputMethodQuery:
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Qt/Quick expects that the item associated with the input context
|
|
||||||
holds the focus. But this does not work, when a virtual
|
|
||||||
keyboard is used, where you can navigate and select inside.
|
|
||||||
So we have to fix the receiver.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if ( ( object != m_data->inputItem )
|
|
||||||
&& qskIsAncestorOf( m_data->inputPanel, m_data->inputItem ) )
|
|
||||||
{
|
{
|
||||||
sendEventToInputItem( event );
|
if ( m_data->inputPanel )
|
||||||
return true;
|
emitKeyboardRectChanged();
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::Resize:
|
||||||
|
{
|
||||||
|
QQuickItem* panel = m_data->inputPanel;
|
||||||
|
|
||||||
|
if ( m_data->inputPanel )
|
||||||
|
m_data->inputPanel->setSize( m_data->inputWindow->size() );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::DeferredDelete:
|
||||||
|
{
|
||||||
|
object->removeEventFilter( this );
|
||||||
|
qGuiApp->removeEventFilter( this );
|
||||||
|
m_data->inputWindow = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch( static_cast<int>( event->type() ) )
|
||||||
|
{
|
||||||
|
case QskEvent::GeometryChange:
|
||||||
|
{
|
||||||
|
if ( object == m_data->inputPanel )
|
||||||
|
{
|
||||||
|
if ( event->type() == QskEvent::GeometryChange )
|
||||||
|
emitKeyboardRectChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::InputMethodQuery:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Qt/Quick expects that the item associated with the input context
|
||||||
|
holds the focus. But this does not work, when a virtual
|
||||||
|
keyboard is used, where you can navigate and select inside.
|
||||||
|
So we have to fix the receiver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ( object != m_data->inputItem )
|
||||||
|
&& qskIsAncestorOf( m_data->inputPanel, m_data->inputItem ) )
|
||||||
|
{
|
||||||
|
sendEventToInputItem( event );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::DeferredDelete:
|
||||||
|
{
|
||||||
|
if ( object == m_data->inputPopup )
|
||||||
|
{
|
||||||
|
object->removeEventFilter( this );
|
||||||
|
qGuiApp->removeEventFilter( this );
|
||||||
|
m_data->inputPopup = nullptr;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -160,7 +160,7 @@ int main( int argc, char* argv[] )
|
||||||
SkinnyFont::init( &app );
|
SkinnyFont::init( &app );
|
||||||
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
// We don't want to have a top level window.
|
// We don't want to have a top level window.
|
||||||
qskDialog->setPolicy( QskDialog::EmbeddedBox );
|
qskDialog->setPolicy( QskDialog::EmbeddedBox );
|
||||||
#endif
|
#endif
|
||||||
|
@ -195,7 +195,7 @@ int main( int argc, char* argv[] )
|
||||||
window.addItem( box );
|
window.addItem( box );
|
||||||
window.addItem( new QskFocusIndicator() );
|
window.addItem( new QskFocusIndicator() );
|
||||||
|
|
||||||
window.resize( 800, 300 );
|
window.resize( 600, 600 );
|
||||||
window.show();
|
window.show();
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
|
|
@ -102,6 +102,7 @@ QString qskNativeLocaleString( const QLocale& locale )
|
||||||
class QskInputPanel::PrivateData
|
class QskInputPanel::PrivateData
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
QskLinearBox* layout;
|
||||||
QskInputSuggestionBar* suggestionBar;
|
QskInputSuggestionBar* suggestionBar;
|
||||||
QskVirtualKeyboard* keyboard;
|
QskVirtualKeyboard* keyboard;
|
||||||
};
|
};
|
||||||
|
@ -111,16 +112,17 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ):
|
||||||
m_data( new PrivateData() )
|
m_data( new PrivateData() )
|
||||||
{
|
{
|
||||||
setAutoLayoutChildren( true );
|
setAutoLayoutChildren( true );
|
||||||
|
initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Constrained );
|
||||||
|
|
||||||
auto layout = new QskLinearBox( Qt::Vertical, this );
|
m_data->layout = new QskLinearBox( Qt::Vertical, this );
|
||||||
|
|
||||||
m_data->suggestionBar = new QskInputSuggestionBar( layout );
|
m_data->suggestionBar = new QskInputSuggestionBar( m_data->layout );
|
||||||
m_data->suggestionBar->setVisible( false );
|
m_data->suggestionBar->setVisible( false );
|
||||||
|
|
||||||
connect( m_data->suggestionBar, &QskInputSuggestionBar::suggested,
|
connect( m_data->suggestionBar, &QskInputSuggestionBar::suggested,
|
||||||
this, &QskInputPanel::commitCandidate );
|
this, &QskInputPanel::commitCandidate );
|
||||||
|
|
||||||
m_data->keyboard = new QskVirtualKeyboard( layout );
|
m_data->keyboard = new QskVirtualKeyboard( m_data->layout );
|
||||||
|
|
||||||
connect( m_data->keyboard, &QskVirtualKeyboard::keySelected,
|
connect( m_data->keyboard, &QskVirtualKeyboard::keySelected,
|
||||||
this, &QskInputPanel::commitKey );
|
this, &QskInputPanel::commitKey );
|
||||||
|
@ -130,6 +132,48 @@ QskInputPanel::~QskInputPanel()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal QskInputPanel::heightForWidth( qreal width ) const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
This code looks like as it could be generalized
|
||||||
|
and moved to QskLinearBox. TODO ...
|
||||||
|
*/
|
||||||
|
|
||||||
|
const auto margins = this->margins();
|
||||||
|
|
||||||
|
width -= margins.left() + margins.right();
|
||||||
|
|
||||||
|
qreal height = m_data->keyboard->heightForWidth( width );
|
||||||
|
|
||||||
|
if ( m_data->suggestionBar->isVisible() )
|
||||||
|
{
|
||||||
|
height += m_data->layout->spacing();
|
||||||
|
height += m_data->suggestionBar->sizeHint().height();
|
||||||
|
}
|
||||||
|
|
||||||
|
height += margins.top() + margins.bottom();
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal QskInputPanel::widthForHeight( qreal height ) const
|
||||||
|
{
|
||||||
|
const auto margins = this->margins();
|
||||||
|
|
||||||
|
height -= margins.top() + margins.bottom();
|
||||||
|
|
||||||
|
if ( m_data->suggestionBar->isVisible() )
|
||||||
|
{
|
||||||
|
height -= m_data->layout->spacing();
|
||||||
|
height -= m_data->suggestionBar->sizeHint().height();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal width = m_data->keyboard->widthForHeight( height );
|
||||||
|
width += margins.left() + margins.right();
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
bool QskInputPanel::isCandidatesEnabled() const
|
bool QskInputPanel::isCandidatesEnabled() const
|
||||||
{
|
{
|
||||||
return m_data->suggestionBar->isVisible();
|
return m_data->suggestionBar->isVisible();
|
||||||
|
|
|
@ -34,6 +34,9 @@ public:
|
||||||
bool isCandidatesEnabled() const;
|
bool isCandidatesEnabled() const;
|
||||||
QVector< QString > candidates() const;
|
QVector< QString > candidates() const;
|
||||||
|
|
||||||
|
virtual qreal heightForWidth( qreal width ) const override;
|
||||||
|
virtual qreal widthForHeight( qreal height ) const override;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void setCandidatesEnabled( bool );
|
void setCandidatesEnabled( bool );
|
||||||
void setCandidates( const QVector< QString >& );
|
void setCandidates( const QVector< QString >& );
|
||||||
|
|
|
@ -15,10 +15,10 @@ namespace
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
RowCount = 5,
|
RowCount = 5,
|
||||||
KeyCount = 12
|
ColumnCount = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
using KeyRow = Qt::Key[KeyCount];
|
using KeyRow = Qt::Key[ ColumnCount ];
|
||||||
|
|
||||||
class Button final : public QskPushButton
|
class Button final : public QskPushButton
|
||||||
{
|
{
|
||||||
|
@ -60,7 +60,7 @@ struct QskVirtualKeyboardLayouts
|
||||||
{
|
{
|
||||||
struct KeyCodes
|
struct KeyCodes
|
||||||
{
|
{
|
||||||
using Row = Qt::Key[ KeyCount ];
|
using Row = Qt::Key[ ColumnCount ];
|
||||||
Row data[ RowCount ];
|
Row data[ RowCount ];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -137,7 +137,7 @@ static qreal qskRowStretch( const KeyRow& keyRow )
|
||||||
|
|
||||||
if( stretch == 0.0 )
|
if( stretch == 0.0 )
|
||||||
{
|
{
|
||||||
stretch = KeyCount;
|
stretch = ColumnCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stretch;
|
return stretch;
|
||||||
|
@ -216,16 +216,16 @@ QskVirtualKeyboard::QskVirtualKeyboard( QQuickItem* parent ):
|
||||||
m_data( new PrivateData )
|
m_data( new PrivateData )
|
||||||
{
|
{
|
||||||
setPolishOnResize( true );
|
setPolishOnResize( true );
|
||||||
initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding );
|
initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Constrained );
|
||||||
|
|
||||||
m_data->keyButtons.reserve( RowCount * KeyCount );
|
m_data->keyButtons.reserve( RowCount * ColumnCount );
|
||||||
|
|
||||||
const auto autoRepeatInterval =
|
const auto autoRepeatInterval =
|
||||||
1000 / QGuiApplication::styleHints()->keyboardAutoRepeatRate();
|
1000 / QGuiApplication::styleHints()->keyboardAutoRepeatRate();
|
||||||
|
|
||||||
for ( int row = 0; row < RowCount; row++ )
|
for ( int row = 0; row < RowCount; row++ )
|
||||||
{
|
{
|
||||||
for ( int col = 0; col < KeyCount; col++ )
|
for ( int col = 0; col < ColumnCount; col++ )
|
||||||
{
|
{
|
||||||
auto button = new Button( row, col, this );
|
auto button = new Button( row, col, this );
|
||||||
button->installEventFilter( this );
|
button->installEventFilter( this );
|
||||||
|
@ -266,6 +266,32 @@ QskVirtualKeyboard::Mode QskVirtualKeyboard::mode() const
|
||||||
return m_data->mode;
|
return m_data->mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal QskVirtualKeyboard::heightForWidth( qreal width ) const
|
||||||
|
{
|
||||||
|
constexpr qreal ratio = qreal( RowCount ) / ColumnCount;
|
||||||
|
const auto margins = this->margins();
|
||||||
|
|
||||||
|
width -= margins.left() + margins.right();
|
||||||
|
|
||||||
|
qreal height = width * ratio;
|
||||||
|
height += margins.top() + margins.bottom();
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal QskVirtualKeyboard::widthForHeight( qreal height ) const
|
||||||
|
{
|
||||||
|
constexpr qreal ratio = qreal( RowCount ) / ColumnCount;
|
||||||
|
const auto margins = this->margins();
|
||||||
|
|
||||||
|
height -= margins.top() + margins.bottom();
|
||||||
|
|
||||||
|
qreal width = height / ratio;
|
||||||
|
width += margins.left() + margins.right();
|
||||||
|
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
void QskVirtualKeyboard::updateLayout()
|
void QskVirtualKeyboard::updateLayout()
|
||||||
{
|
{
|
||||||
const auto r = layoutRect();
|
const auto r = layoutRect();
|
||||||
|
@ -290,7 +316,7 @@ void QskVirtualKeyboard::updateLayout()
|
||||||
auto totalHSpacing = -spacing;
|
auto totalHSpacing = -spacing;
|
||||||
if ( spacing )
|
if ( spacing )
|
||||||
{
|
{
|
||||||
for ( int col = 0; col < KeyCount; col++ )
|
for ( int col = 0; col < ColumnCount; col++ )
|
||||||
{
|
{
|
||||||
if ( keys[ col ] != Qt::Key( 0 ) )
|
if ( keys[ col ] != Qt::Key( 0 ) )
|
||||||
totalHSpacing += spacing;
|
totalHSpacing += spacing;
|
||||||
|
@ -300,10 +326,10 @@ void QskVirtualKeyboard::updateLayout()
|
||||||
const auto baseKeyWidth = ( r.width() - totalHSpacing ) / qskRowStretch( keys );
|
const auto baseKeyWidth = ( r.width() - totalHSpacing ) / qskRowStretch( keys );
|
||||||
qreal xPos = r.left();
|
qreal xPos = r.left();
|
||||||
|
|
||||||
for ( int col = 0; col < KeyCount; col++ )
|
for ( int col = 0; col < ColumnCount; col++ )
|
||||||
{
|
{
|
||||||
const Qt::Key key = keys[ col ];
|
const Qt::Key key = keys[ col ];
|
||||||
auto button = m_data->keyButtons[ row * KeyCount + col ];
|
auto button = m_data->keyButtons[ row * ColumnCount + col ];
|
||||||
|
|
||||||
button->setVisible( key != Qt::Key( 0 ) );
|
button->setVisible( key != Qt::Key( 0 ) );
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,9 @@ public:
|
||||||
void setMode( Mode );
|
void setMode( Mode );
|
||||||
Mode mode() const;
|
Mode mode() const;
|
||||||
|
|
||||||
|
virtual qreal heightForWidth( qreal width ) const override;
|
||||||
|
virtual qreal widthForHeight( qreal height ) const override;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void modeChanged( Mode );
|
void modeChanged( Mode );
|
||||||
void keySelected( Qt::Key );
|
void keySelected( Qt::Key );
|
||||||
|
|
Loading…
Reference in New Issue