improving QskInputContext
This commit is contained in:
parent
0ee83c1e32
commit
d1ecec2ad8
@ -10,6 +10,7 @@
|
||||
#include "QskHunspellCompositionModel.h"
|
||||
|
||||
#include "QskInputPanel.h"
|
||||
#include "QskLinearBox.h"
|
||||
#include <QskDialog.h>
|
||||
#include <QskPopup.h>
|
||||
#include <QskWindow.h>
|
||||
@ -91,8 +92,8 @@ public:
|
||||
QPointer< QQuickItem > inputPanel;
|
||||
|
||||
// popup or window embedding the inputPanel
|
||||
QPointer< QskPopup > inputPopup;
|
||||
QPointer< QskWindow > inputWindow;
|
||||
QskPopup* inputPopup = nullptr;
|
||||
QskWindow* inputWindow = nullptr;
|
||||
|
||||
QskInputCompositionModel* compositionModel;
|
||||
QHash< QLocale, QskInputCompositionModel* > compositionModels;
|
||||
@ -320,9 +321,14 @@ void QskInputContext::showInputPanel()
|
||||
{
|
||||
auto popup = new QskPopup( m_data->inputItem->window()->contentItem() );
|
||||
popup->setAutoLayoutChildren( true );
|
||||
popup->setTransparentForPositioner( false );
|
||||
popup->setOverlay( false );
|
||||
popup->setModal( true );
|
||||
|
||||
inputPanel->setParentItem( popup );
|
||||
auto box = new QskLinearBox( popup );
|
||||
box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge );
|
||||
box->addItem( inputPanel );
|
||||
|
||||
inputPopup = popup;
|
||||
}
|
||||
|
||||
@ -343,7 +349,6 @@ void QskInputContext::showInputPanel()
|
||||
}
|
||||
}
|
||||
|
||||
inputPopup->setGeometry( qskItemGeometry( inputPopup->parentItem() ) );
|
||||
inputPopup->setVisible( true );
|
||||
}
|
||||
|
||||
@ -363,19 +368,13 @@ void QskInputContext::hideInputPanel()
|
||||
|
||||
if ( m_data->inputPopup == m_data->inputPanel )
|
||||
{
|
||||
|
||||
m_data->inputPopup->removeEventFilter( this );
|
||||
m_data->inputPopup = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_data->inputPopup )
|
||||
{
|
||||
auto popup = m_data->inputPopup.data();
|
||||
m_data->inputPopup = nullptr;
|
||||
|
||||
popup->deleteLater();
|
||||
}
|
||||
m_data->inputPopup->deleteLater();
|
||||
}
|
||||
|
||||
QskWindow* window = m_data->inputWindow;
|
||||
@ -599,40 +598,78 @@ void QskInputContext::commit()
|
||||
|
||||
bool QskInputContext::eventFilter( QObject* object, QEvent* event )
|
||||
{
|
||||
switch( static_cast< int >( event->type() ) )
|
||||
if ( object == m_data->inputWindow )
|
||||
{
|
||||
case QEvent::Move:
|
||||
case QEvent::Resize:
|
||||
switch( event->type() )
|
||||
{
|
||||
if ( m_data->inputPanel && object == m_data->inputPanel->window() )
|
||||
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 ) )
|
||||
case QEvent::Move:
|
||||
{
|
||||
sendEventToInputItem( event );
|
||||
return true;
|
||||
}
|
||||
if ( m_data->inputPanel )
|
||||
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 );
|
||||
SkinnyShortcut::enable( SkinnyShortcut::AllShortcuts );
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
// We don't want to have a top level window.
|
||||
qskDialog->setPolicy( QskDialog::EmbeddedBox );
|
||||
#endif
|
||||
@ -195,7 +195,7 @@ int main( int argc, char* argv[] )
|
||||
window.addItem( box );
|
||||
window.addItem( new QskFocusIndicator() );
|
||||
|
||||
window.resize( 800, 300 );
|
||||
window.resize( 600, 600 );
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
|
@ -102,6 +102,7 @@ QString qskNativeLocaleString( const QLocale& locale )
|
||||
class QskInputPanel::PrivateData
|
||||
{
|
||||
public:
|
||||
QskLinearBox* layout;
|
||||
QskInputSuggestionBar* suggestionBar;
|
||||
QskVirtualKeyboard* keyboard;
|
||||
};
|
||||
@ -111,16 +112,17 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ):
|
||||
m_data( new PrivateData() )
|
||||
{
|
||||
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 );
|
||||
|
||||
connect( m_data->suggestionBar, &QskInputSuggestionBar::suggested,
|
||||
this, &QskInputPanel::commitCandidate );
|
||||
|
||||
m_data->keyboard = new QskVirtualKeyboard( layout );
|
||||
m_data->keyboard = new QskVirtualKeyboard( m_data->layout );
|
||||
|
||||
connect( m_data->keyboard, &QskVirtualKeyboard::keySelected,
|
||||
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
|
||||
{
|
||||
return m_data->suggestionBar->isVisible();
|
||||
|
@ -34,6 +34,9 @@ public:
|
||||
bool isCandidatesEnabled() const;
|
||||
QVector< QString > candidates() const;
|
||||
|
||||
virtual qreal heightForWidth( qreal width ) const override;
|
||||
virtual qreal widthForHeight( qreal height ) const override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void setCandidatesEnabled( bool );
|
||||
void setCandidates( const QVector< QString >& );
|
||||
|
@ -15,10 +15,10 @@ namespace
|
||||
enum
|
||||
{
|
||||
RowCount = 5,
|
||||
KeyCount = 12
|
||||
ColumnCount = 12
|
||||
};
|
||||
|
||||
using KeyRow = Qt::Key[KeyCount];
|
||||
using KeyRow = Qt::Key[ ColumnCount ];
|
||||
|
||||
class Button final : public QskPushButton
|
||||
{
|
||||
@ -60,7 +60,7 @@ struct QskVirtualKeyboardLayouts
|
||||
{
|
||||
struct KeyCodes
|
||||
{
|
||||
using Row = Qt::Key[ KeyCount ];
|
||||
using Row = Qt::Key[ ColumnCount ];
|
||||
Row data[ RowCount ];
|
||||
};
|
||||
|
||||
@ -137,7 +137,7 @@ static qreal qskRowStretch( const KeyRow& keyRow )
|
||||
|
||||
if( stretch == 0.0 )
|
||||
{
|
||||
stretch = KeyCount;
|
||||
stretch = ColumnCount;
|
||||
}
|
||||
|
||||
return stretch;
|
||||
@ -216,16 +216,16 @@ QskVirtualKeyboard::QskVirtualKeyboard( QQuickItem* parent ):
|
||||
m_data( new PrivateData )
|
||||
{
|
||||
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 =
|
||||
1000 / QGuiApplication::styleHints()->keyboardAutoRepeatRate();
|
||||
|
||||
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 );
|
||||
button->installEventFilter( this );
|
||||
@ -266,6 +266,32 @@ QskVirtualKeyboard::Mode QskVirtualKeyboard::mode() const
|
||||
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()
|
||||
{
|
||||
const auto r = layoutRect();
|
||||
@ -290,7 +316,7 @@ void QskVirtualKeyboard::updateLayout()
|
||||
auto totalHSpacing = -spacing;
|
||||
if ( spacing )
|
||||
{
|
||||
for ( int col = 0; col < KeyCount; col++ )
|
||||
for ( int col = 0; col < ColumnCount; col++ )
|
||||
{
|
||||
if ( keys[ col ] != Qt::Key( 0 ) )
|
||||
totalHSpacing += spacing;
|
||||
@ -300,10 +326,10 @@ void QskVirtualKeyboard::updateLayout()
|
||||
const auto baseKeyWidth = ( r.width() - totalHSpacing ) / qskRowStretch( keys );
|
||||
qreal xPos = r.left();
|
||||
|
||||
for ( int col = 0; col < KeyCount; col++ )
|
||||
for ( int col = 0; col < ColumnCount; 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 ) );
|
||||
|
||||
|
@ -38,6 +38,9 @@ public:
|
||||
void setMode( Mode );
|
||||
Mode mode() const;
|
||||
|
||||
virtual qreal heightForWidth( qreal width ) const override;
|
||||
virtual qreal widthForHeight( qreal height ) const override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void modeChanged( Mode );
|
||||
void keySelected( Qt::Key );
|
||||
|
Loading…
x
Reference in New Issue
Block a user