diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index 2f37f1a6..1a97bf41 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -10,6 +10,7 @@ #include "QskHunspellCompositionModel.h" #include "QskInputPanel.h" +#include "QskLinearBox.h" #include #include #include @@ -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( 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; + } } } diff --git a/playground/inputpanel/main.cpp b/playground/inputpanel/main.cpp index fe660e7f..94b4acb2 100644 --- a/playground/inputpanel/main.cpp +++ b/playground/inputpanel/main.cpp @@ -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(); diff --git a/src/inputpanel/QskInputPanel.cpp b/src/inputpanel/QskInputPanel.cpp index 9b54dea1..6fe7b93a 100644 --- a/src/inputpanel/QskInputPanel.cpp +++ b/src/inputpanel/QskInputPanel.cpp @@ -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(); diff --git a/src/inputpanel/QskInputPanel.h b/src/inputpanel/QskInputPanel.h index f108770d..7945b83e 100644 --- a/src/inputpanel/QskInputPanel.h +++ b/src/inputpanel/QskInputPanel.h @@ -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 >& ); diff --git a/src/inputpanel/QskVirtualKeyboard.cpp b/src/inputpanel/QskVirtualKeyboard.cpp index 55998ec8..e9b5d102 100644 --- a/src/inputpanel/QskVirtualKeyboard.cpp +++ b/src/inputpanel/QskVirtualKeyboard.cpp @@ -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 ) ); diff --git a/src/inputpanel/QskVirtualKeyboard.h b/src/inputpanel/QskVirtualKeyboard.h index fa90e8e1..9b720ff0 100644 --- a/src/inputpanel/QskVirtualKeyboard.h +++ b/src/inputpanel/QskVirtualKeyboard.h @@ -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 );