From 2f2d5cf122f75312edac3bfa7c7c4a3ad246bfe5 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 17:30:29 +0100 Subject: [PATCH 01/21] add TextInput --- playground/inputpanel/TextInput.cpp | 12 ++++++++++++ playground/inputpanel/TextInput.h | 13 +++++++++++++ playground/inputpanel/inputpanel.pro | 6 +++++- playground/inputpanel/main.cpp | 4 ++-- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 playground/inputpanel/TextInput.cpp create mode 100644 playground/inputpanel/TextInput.h diff --git a/playground/inputpanel/TextInput.cpp b/playground/inputpanel/TextInput.cpp new file mode 100644 index 00000000..8d43e2f3 --- /dev/null +++ b/playground/inputpanel/TextInput.cpp @@ -0,0 +1,12 @@ +#include "TextInput.h" + +TextInput::TextInput( QQuickItem* parent ) + : QQuickTextInput( parent ) +{ + +} + +TextInput::~TextInput() +{ + +} diff --git a/playground/inputpanel/TextInput.h b/playground/inputpanel/TextInput.h new file mode 100644 index 00000000..3fe56eeb --- /dev/null +++ b/playground/inputpanel/TextInput.h @@ -0,0 +1,13 @@ +#ifndef TEXTINPUT_H +#define TEXTINPUT_H + +#include + +class TextInput : public QQuickTextInput +{ + public: + TextInput( QQuickItem* parent ); + virtual ~TextInput(); +}; + +#endif // TEXTINPUT_H diff --git a/playground/inputpanel/inputpanel.pro b/playground/inputpanel/inputpanel.pro index 499ddb20..3b9b2535 100644 --- a/playground/inputpanel/inputpanel.pro +++ b/playground/inputpanel/inputpanel.pro @@ -5,4 +5,8 @@ TARGET = inputpanel DEFINES += PLUGIN_PATH=$$clean_path( $$QSK_OUT_ROOT/plugins ) SOURCES += \ - main.cpp + main.cpp \ + TextInput.cpp + +HEADERS += \ + TextInput.h diff --git a/playground/inputpanel/main.cpp b/playground/inputpanel/main.cpp index defd4ce4..0e485801 100644 --- a/playground/inputpanel/main.cpp +++ b/playground/inputpanel/main.cpp @@ -3,6 +3,8 @@ * This file may be used under the terms of the 3-clause BSD License *****************************************************************************/ +#include "TextInput.h" + #include #include @@ -21,8 +23,6 @@ #include #include -#include - #define STRINGIFY(x) #x #define STRING(x) STRINGIFY(x) From 2e3834acf93b6526ffa74bf59db8b6b1d14a5e0b Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 17:30:35 +0100 Subject: [PATCH 02/21] input panel formatting --- src/controls/QskInputPanel.cpp | 315 ++++++++++++++++++++------------- src/controls/QskInputPanel.h | 2 +- 2 files changed, 193 insertions(+), 124 deletions(-) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index e1d0d324..bbc78c4f 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -37,8 +37,10 @@ namespace QskInputPanel::KeyData* qskKeyDataAt( KeyTable& table, qreal x, qreal y ) { - if ( x < 0 || x > 1 || y < 0 || y > 1 ) + if( x < 0 || x > 1 || y < 0 || y > 1 ) + { return nullptr; + } auto rowIndex = size_t( std::floor( y * QskInputPanel::RowCount ) ); auto columnIndex = size_t( std::floor( x * QskInputPanel::KeyCount ) ); @@ -46,40 +48,51 @@ namespace Q_FOREVER { const auto rect = table.data[ rowIndex ][ columnIndex ].rect; - if ( rect.contains( x, y ) ) + + if( rect.contains( x, y ) ) + { return &table.data[ rowIndex ][ columnIndex ]; + } // Look up/down - if ( y < rect.top() ) + if( y < rect.top() ) { - if ( rowIndex == 0 ) + if( rowIndex == 0 ) + { break; + } rowIndex -= 1; continue; } - else if ( y > rect.bottom() ) + else if( y > rect.bottom() ) { - if ( rowIndex == QskInputPanel::RowCount - 1 ) + if( rowIndex == QskInputPanel::RowCount - 1 ) + { break; + } rowIndex += 1; continue; } // Look left/right - if ( x < rect.left() ) + if( x < rect.left() ) { - if ( columnIndex == 0 ) + if( columnIndex == 0 ) + { break; + } columnIndex -= 1; continue; } - else if ( x > rect.right() ) + else if( x > rect.right() ) { - if ( columnIndex == QskInputPanel::KeyCount - 1 ) + if( columnIndex == QskInputPanel::KeyCount - 1 ) + { break; + } columnIndex += 1; continue; @@ -130,7 +143,7 @@ struct QskInputPanelLayouts #define LOWER(x) Qt::Key(x + 32) // Convert an uppercase key to lowercase static constexpr const QskInputPanelLayouts qskInputPanelLayouts = { - #include "QskInputPanelLayouts.cpp" +#include "QskInputPanelLayouts.cpp" }; #undef LOWER @@ -143,7 +156,7 @@ static const Qt::Key KeyStates = static_cast< Qt::Key >( Qt::KeyboardModifierMa static qreal qskKeyStretch( Qt::Key key ) { - switch ( key ) + switch( key ) { case Qt::Key_Backspace: case Qt::Key_Shift: @@ -168,16 +181,20 @@ static qreal qskRowStretch( const QskInputPanel::KeyRow& keyRow ) { qreal stretch = 0; - for ( const auto& key : keyRow ) + for( const auto& key : keyRow ) { - if ( !key ) + if( !key ) + { continue; + } stretch += qskKeyStretch( key ); } - if ( stretch == 0.0 ) + if( stretch == 0.0 ) + { stretch = QskInputPanel::KeyCount; + } return stretch; } @@ -193,34 +210,34 @@ namespace class QskInputPanel::PrivateData { -public: - PrivateData(): - currentLayout( nullptr ), - mode( QskInputPanel::LowercaseMode ), - focusKeyIndex( -1 ), - selectedGroup( -1 ), - candidateOffset( 0 ), - repeatKeyTimerId( -1 ) - { - } + public: + PrivateData(): + currentLayout( nullptr ), + mode( QskInputPanel::LowercaseMode ), + focusKeyIndex( -1 ), + selectedGroup( -1 ), + candidateOffset( 0 ), + repeatKeyTimerId( -1 ) + { + } -public: - const QskInputPanelLayouts::Layout* currentLayout; - QskInputPanel::Mode mode; + public: + const QskInputPanelLayouts::Layout* currentLayout; + QskInputPanel::Mode mode; - qint16 focusKeyIndex; - qint16 selectedGroup; - qint32 candidateOffset; + qint16 focusKeyIndex; + qint16 selectedGroup; + qint32 candidateOffset; - int repeatKeyTimerId; + int repeatKeyTimerId; - QLocale locale; + QLocale locale; - QVector< Qt::Key > groups; - QVector< Qt::Key > candidates; + QVector< Qt::Key > groups; + QVector< Qt::Key > candidates; - std::unordered_map< int, KeyCounter > activeKeys; - KeyTable keyTable[ ModeCount ]; + std::unordered_map< int, KeyCounter > activeKeys; + KeyTable keyTable[ ModeCount ]; }; QskInputPanel::QskInputPanel( QQuickItem* parent ): @@ -235,7 +252,7 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): updateLocale( locale() ); QObject::connect( this, &QskControl::localeChanged, - this, &QskInputPanel::updateLocale ); + this, &QskInputPanel::updateLocale ); } QskInputPanel::~QskInputPanel() @@ -259,7 +276,7 @@ QString QskInputPanel::textForKey( Qt::Key key ) const key &= ~KeyStates; // Special cases - switch ( key ) + switch( key ) { case Qt::Key_Backspace: case Qt::Key_Muhenkan: @@ -306,7 +323,7 @@ QString QskInputPanel::displayLanguageName() const { const auto locale = this->locale(); - switch ( locale.language() ) + switch( locale.language() ) { case QLocale::Bulgarian: return QStringLiteral( "български език" ); @@ -324,19 +341,19 @@ QString QskInputPanel::displayLanguageName() const return QStringLiteral( "Eλληνικά" ); case QLocale::English: - { - switch ( locale.country() ) { - case QLocale::Canada: - case QLocale::UnitedStates: - case QLocale::UnitedStatesMinorOutlyingIslands: - case QLocale::UnitedStatesVirginIslands: - return QStringLiteral( "English (US)" ); + switch( locale.country() ) + { + case QLocale::Canada: + case QLocale::UnitedStates: + case QLocale::UnitedStatesMinorOutlyingIslands: + case QLocale::UnitedStatesVirginIslands: + return QStringLiteral( "English (US)" ); - default: - return QStringLiteral( "English (UK)" ); + default: + return QStringLiteral( "English (UK)" ); + } } - } case QLocale::Spanish: return QStringLiteral( "Español" ); @@ -397,7 +414,7 @@ void QskInputPanel::setPreeditGroups( const QVector< Qt::Key >& groups ) { auto& topRow = m_data->keyTable[ LowercaseMode ].data[ 0 ]; - for ( const auto& group : groups ) + for( const auto& group : groups ) { auto& keyData = topRow[ &group - groups.data() ]; keyData.key = group; @@ -406,14 +423,18 @@ void QskInputPanel::setPreeditGroups( const QVector< Qt::Key >& groups ) m_data->groups = groups; selectGroup( -1 ); - if ( m_data->mode == LowercaseMode ) + if( m_data->mode == LowercaseMode ) + { update(); + } } void QskInputPanel::setPreeditCandidates( const QVector< Qt::Key >& candidates ) { - if ( m_data->candidates == candidates ) + if( m_data->candidates == candidates ) + { return; + } m_data->candidates = candidates; setCandidateOffset( 0 ); @@ -429,19 +450,25 @@ bool QskInputPanel::advanceFocus( bool forward ) Q_FOREVER { focusKeyIndex += offset; - if ( focusKeyIndex < 0 || focusKeyIndex >= RowCount * KeyCount ) + + if( focusKeyIndex < 0 || focusKeyIndex >= RowCount * KeyCount ) { clearFocusKey(); return false; } const auto key = keyDataAt( focusKeyIndex ).key; - if ( key && key != Qt::Key_unknown ) + + if( key && key != Qt::Key_unknown ) + { break; + } } - if ( m_data->focusKeyIndex >= 0 ) + if( m_data->focusKeyIndex >= 0 ) + { keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused; + } m_data->focusKeyIndex = focusKeyIndex; keyDataAt( m_data->focusKeyIndex ).key |= KeyFocused; @@ -451,14 +478,18 @@ bool QskInputPanel::advanceFocus( bool forward ) bool QskInputPanel::activateFocusKey() { - if ( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) + if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) { auto& keyData = keyDataAt( m_data->focusKeyIndex ); - if ( keyData.key & KeyPressed ) + if( keyData.key & KeyPressed ) + { handleKey( m_data->focusKeyIndex ); + } else + { keyData.key |= KeyPressed; + } update(); return true; @@ -469,10 +500,11 @@ bool QskInputPanel::activateFocusKey() bool QskInputPanel::deactivateFocusKey() { - if ( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) + if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) { auto& keyData = keyDataAt( m_data->focusKeyIndex ); - if ( keyData.key & KeyPressed ) + + if( keyData.key & KeyPressed ) { keyData.key &= ~KeyPressed; handleKey( m_data->focusKeyIndex ); @@ -487,7 +519,7 @@ bool QskInputPanel::deactivateFocusKey() void QskInputPanel::clearFocusKey() { - if ( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) + if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) { keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused; update(); @@ -508,34 +540,44 @@ void QskInputPanel::setCandidateOffset( int candidateOffset ) const bool continueLeft = m_data->candidateOffset > 0; const bool continueRight = ( candidateCount - m_data->candidateOffset ) > count; - for ( int i = 0; i < count; ++i ) + for( int i = 0; i < count; ++i ) { auto& keyData = topRow[ i + groupCount ]; - if ( continueLeft && i == 0 ) + if( continueLeft && i == 0 ) + { keyData.key = Qt::Key_ApplicationLeft; - else if ( continueRight && ( i == KeyCount - groupCount - 1 ) ) + } + else if( continueRight && ( i == KeyCount - groupCount - 1 ) ) + { keyData.key = Qt::Key_ApplicationRight; + } else + { keyData.key = m_data->candidates.at( i + m_data->candidateOffset ); + } } - for ( int i = count; i < KeyCount - groupCount; ++i ) + for( int i = count; i < KeyCount - groupCount; ++i ) { auto& keyData = topRow[ i + groupCount ]; keyData.key = Qt::Key_unknown; } - if ( m_data->mode == LowercaseMode ) + if( m_data->mode == LowercaseMode ) + { update(); + } } QRectF QskInputPanel::keyboardRect() const { auto keyboardRect = rect(); // ### margins? would eliminate this thing below - if ( QskDialog::instance()->policy() != QskDialog::TopLevelWindow ) + if( QskDialog::instance()->policy() != QskDialog::TopLevelWindow ) + { keyboardRect.adjust( 0, keyboardRect.height() * 0.5, 0, 0 ); + } return keyboardRect; } @@ -549,7 +591,7 @@ void QskInputPanel::geometryChanged( void QskInputPanel::mousePressEvent( QMouseEvent* e ) { - if ( !keyboardRect().contains( e->pos() ) ) + if( !keyboardRect().contains( e->pos() ) ) { e->ignore(); return; @@ -560,7 +602,7 @@ void QskInputPanel::mousePressEvent( QMouseEvent* e ) touchPoint.setState( Qt::TouchPointPressed ); QTouchEvent touchEvent( QTouchEvent::TouchBegin, nullptr, - e->modifiers(), Qt::TouchPointPressed, { touchPoint } ); + e->modifiers(), Qt::TouchPointPressed, { touchPoint } ); QCoreApplication::sendEvent( this, &touchEvent ); e->setAccepted( touchEvent.isAccepted() ); @@ -573,7 +615,7 @@ void QskInputPanel::mouseMoveEvent( QMouseEvent* e ) touchPoint.setState( Qt::TouchPointMoved ); QTouchEvent touchEvent( QTouchEvent::TouchUpdate, nullptr, - e->modifiers(), Qt::TouchPointMoved, { touchPoint } ); + e->modifiers(), Qt::TouchPointMoved, { touchPoint } ); QCoreApplication::sendEvent( this, &touchEvent ); e->setAccepted( touchEvent.isAccepted() ); @@ -586,7 +628,7 @@ void QskInputPanel::mouseReleaseEvent( QMouseEvent* e ) touchPoint.setState( Qt::TouchPointReleased ); QTouchEvent touchEvent( QTouchEvent::TouchEnd, nullptr, - e->modifiers(), Qt::TouchPointReleased, { touchPoint } ); + e->modifiers(), Qt::TouchPointReleased, { touchPoint } ); QCoreApplication::sendEvent( this, &touchEvent ); e->setAccepted( touchEvent.isAccepted() ); @@ -595,17 +637,20 @@ void QskInputPanel::mouseReleaseEvent( QMouseEvent* e ) // Try to handle touch-specific details here; once touch is resolved, send to handleKey() void QskInputPanel::touchEvent( QTouchEvent* e ) { - if ( e->type() == QEvent::TouchCancel ) + if( e->type() == QEvent::TouchCancel ) { - for ( auto& it : m_data->activeKeys ) + for( auto& it : m_data->activeKeys ) + { keyDataAt( it.second.keyIndex ).key &= ~KeyPressed; + } m_data->activeKeys.clear(); return; } const auto rect = keyboardRect(); - for ( const auto& tp : e->touchPoints() ) + + for( const auto& tp : e->touchPoints() ) { const auto pos = tp.pos(); @@ -613,11 +658,15 @@ void QskInputPanel::touchEvent( QTouchEvent* e ) const auto y = ( pos.y() - rect.y() ) / rect.height(); auto keyData = qskKeyDataAt( m_data->keyTable[ m_data->mode ], x, y ); - if ( !keyData || ( !keyData->key || keyData->key == Qt::Key_unknown ) ) + + if( !keyData || ( !keyData->key || keyData->key == Qt::Key_unknown ) ) { auto it = m_data->activeKeys.find( tp.id() ); - if ( it == m_data->activeKeys.cend() ) + + if( it == m_data->activeKeys.cend() ) + { continue; + } keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; m_data->activeKeys.erase( it ); @@ -627,7 +676,7 @@ void QskInputPanel::touchEvent( QTouchEvent* e ) const auto keyIndex = m_data->keyTable[ m_data->mode ].indexOf( keyData ); auto it = m_data->activeKeys.find( tp.id() ); - if ( tp.state() == Qt::TouchPointReleased ) + if( tp.state() == Qt::TouchPointReleased ) { const int repeatCount = it->second.count; @@ -635,20 +684,22 @@ void QskInputPanel::touchEvent( QTouchEvent* e ) keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; m_data->activeKeys.erase( it ); - if ( repeatCount < 0 ) - continue; // Don't compose an accepted held key + if( repeatCount < 0 ) + { + continue; // Don't compose an accepted held key + } handleKey( keyIndex ); continue; } - if ( it == m_data->activeKeys.end() ) + if( it == m_data->activeKeys.end() ) { m_data->activeKeys.emplace( tp.id(), KeyCounter { keyIndex, 0 } ); } else { - if ( it->second.keyIndex != keyIndex ) + if( it->second.keyIndex != keyIndex ) { keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; it->second.count = 0; @@ -661,15 +712,15 @@ void QskInputPanel::touchEvent( QTouchEvent* e ) } // Now start an update timer based on active keys - if ( m_data->activeKeys.empty() && m_data->repeatKeyTimerId >= 0 ) + if( m_data->activeKeys.empty() && m_data->repeatKeyTimerId >= 0 ) { killTimer( m_data->repeatKeyTimerId ); m_data->repeatKeyTimerId = -1; } - else if ( m_data->repeatKeyTimerId < 0 ) + else if( m_data->repeatKeyTimerId < 0 ) { m_data->repeatKeyTimerId = startTimer( 1000 - / QGuiApplication::styleHints()->keyboardAutoRepeatRate() ); + / QGuiApplication::styleHints()->keyboardAutoRepeatRate() ); } /* else timer is already running as it should be */ update(); @@ -677,31 +728,32 @@ void QskInputPanel::touchEvent( QTouchEvent* e ) void QskInputPanel::timerEvent( QTimerEvent* e ) { - if ( e->timerId() == m_data->repeatKeyTimerId ) + if( e->timerId() == m_data->repeatKeyTimerId ) { - for ( auto it = m_data->activeKeys.begin(); it != m_data->activeKeys.end(); ) + for( auto it = m_data->activeKeys.begin(); it != m_data->activeKeys.end(); ) { - if ( it->second.count >= 0 && it->second.count++ > 20 ) // ### use platform long-press hint + if( it->second.count >= 0 && it->second.count++ > 20 ) // ### use platform long-press hint { const auto key = keyDataAt( it->second.keyIndex ).key & ~KeyStates; - if ( !key || key == Qt::Key_unknown ) + if( !key || key == Qt::Key_unknown ) { it = m_data->activeKeys.erase( it ); continue; } - if ( key == Qt::Key_ApplicationLeft || key == Qt::Key_ApplicationRight ) + if( key == Qt::Key_ApplicationLeft || key == Qt::Key_ApplicationRight ) { setCandidateOffset( m_data->candidateOffset - + ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) ); + + ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) ); } - else if ( !( key & KeyLocked ) ) // do not repeat locked keys + else if( !( key & KeyLocked ) ) // do not repeat locked keys { // long press events could be emitted from here compose( key & ~KeyStates ); } } + ++it; } } @@ -722,29 +774,36 @@ void QskInputPanel::handleKey( int keyIndex ) const auto row = keyIndex / KeyCount; const auto column = keyIndex % KeyCount; - if ( m_data->mode == LowercaseMode && !m_data->groups.isEmpty() && row == 0 ) + if( m_data->mode == LowercaseMode && !m_data->groups.isEmpty() && row == 0 ) { - if ( key == Qt::Key_ApplicationLeft - || key == Qt::Key_ApplicationRight ) + if( key == Qt::Key_ApplicationLeft + || key == Qt::Key_ApplicationRight ) { setCandidateOffset( m_data->candidateOffset - + ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) ); + + ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) ); return; } const auto groupCount = m_data->groups.length(); - if ( column < groupCount ) + + if( column < groupCount ) + { selectGroup( column ); - else if ( column < KeyCount ) + } + else if( column < KeyCount ) + { selectCandidate( column - groupCount + m_data->candidateOffset ); + } else - Q_UNREACHABLE(); // Handle the final key... + { + Q_UNREACHABLE(); // Handle the final key... + } return; } // Mode-switching keys - switch ( key ) + switch( key ) { case Qt::Key_CapsLock: case Qt::Key_Kana_Lock: @@ -758,8 +817,8 @@ void QskInputPanel::handleKey( int keyIndex ) case Qt::Key_Mode_switch: // Cycle through modes, but skip caps setMode( static_cast< QskInputPanel::Mode >( - m_data->mode ? ( ( m_data->mode + 1 ) % QskInputPanel::ModeCount ) - : SpecialCharacterMode ) ); + m_data->mode ? ( ( m_data->mode + 1 ) % QskInputPanel::ModeCount ) + : SpecialCharacterMode ) ); return; default: @@ -779,18 +838,25 @@ void QskInputPanel::compose( Qt::Key key ) void QskInputPanel::selectGroup( int index ) { auto& topRow = m_data->keyTable[ m_data->mode ].data[ 0 ]; - if ( m_data->selectedGroup >= 0 ) - topRow[ m_data->selectedGroup ].key &= ~KeyLocked; - if ( m_data->selectedGroup == index ) - index = -1; // clear selection + if( m_data->selectedGroup >= 0 ) + { + topRow[ m_data->selectedGroup ].key &= ~KeyLocked; + } + + if( m_data->selectedGroup == index ) + { + index = -1; // clear selection + } m_data->selectedGroup = index; QGuiApplication::inputMethod()->invokeAction( static_cast< QInputMethod::Action >( SelectGroup ), m_data->selectedGroup + 1 ); - if ( m_data->selectedGroup < 0 ) + if( m_data->selectedGroup < 0 ) + { return; + } topRow[ m_data->selectedGroup ].key |= KeyLocked; } @@ -803,7 +869,7 @@ void QskInputPanel::selectCandidate( int index ) void QskInputPanel::updateLocale( const QLocale& locale ) { - switch ( locale.language() ) + switch( locale.language() ) { case QLocale::Bulgarian: m_data->currentLayout = &qskInputPanelLayouts.bg; @@ -826,21 +892,24 @@ void QskInputPanel::updateLocale( const QLocale& locale ) break; case QLocale::English: - { - switch ( locale.country() ) { - case QLocale::Canada: - case QLocale::UnitedStates: - case QLocale::UnitedStatesMinorOutlyingIslands: - case QLocale::UnitedStatesVirginIslands: - m_data->currentLayout = &qskInputPanelLayouts.en_US; - break; - default: - m_data->currentLayout = &qskInputPanelLayouts.en_GB; - break; + switch( locale.country() ) + { + case QLocale::Canada: + case QLocale::UnitedStates: + case QLocale::UnitedStatesMinorOutlyingIslands: + case QLocale::UnitedStatesVirginIslands: + m_data->currentLayout = &qskInputPanelLayouts.en_US; + break; + + default: + m_data->currentLayout = &qskInputPanelLayouts.en_GB; + break; + } + + break; } - break; - } + case QLocale::Spanish: m_data->currentLayout = &qskInputPanelLayouts.es; break; @@ -925,12 +994,12 @@ void QskInputPanel::updateKeyData() // Key data is in normalized coordinates const auto keyHeight = 1.0f / RowCount; - for ( const auto& keyLayout : *m_data->currentLayout ) + for( const auto& keyLayout : *m_data->currentLayout ) { auto& keyDataLayout = m_data->keyTable[ &keyLayout - *m_data->currentLayout ]; qreal yPos = 0; - for ( int i = 0; i < RowCount; i++ ) + for( int i = 0; i < RowCount; i++ ) { auto& row = keyLayout.data[i]; auto& keyDataRow = keyDataLayout.data[ i ]; @@ -940,7 +1009,7 @@ void QskInputPanel::updateKeyData() qreal xPos = 0; qreal keyWidth = baseKeyWidth; - for ( const auto& key : row ) + for( const auto& key : row ) { auto& keyData = keyDataRow[ &key - row ]; keyData.key = key; diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index 963e08a2..b5a4da29 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -17,7 +17,7 @@ class QSK_EXPORT QskInputPanel : public QskControl Q_PROPERTY( QRectF keyboardRect READ keyboardRect NOTIFY keyboardRectChanged ) Q_PROPERTY( QString displayLanguageName READ displayLanguageName - NOTIFY displayLanguageNameChanged ) + NOTIFY displayLanguageNameChanged ) using Inherited = QskControl; From e365592457907df7c9d660c402a75a5cbb5994d1 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 17:30:37 +0100 Subject: [PATCH 03/21] new input panel code --- skins/material/QskMaterialSkin.cpp | 2 + skins/squiek/QskSquiekSkin.cpp | 2 + src/controls/QskInputPanel.cpp | 409 ++++++++++++-------------- src/controls/QskInputPanel.h | 53 +++- src/controls/QskInputPanelSkinlet.cpp | 222 -------------- src/controls/QskInputPanelSkinlet.h | 43 --- src/controls/QskSkin.cpp | 4 - src/src.pro | 2 - 8 files changed, 229 insertions(+), 508 deletions(-) delete mode 100644 src/controls/QskInputPanelSkinlet.cpp delete mode 100644 src/controls/QskInputPanelSkinlet.h diff --git a/skins/material/QskMaterialSkin.cpp b/skins/material/QskMaterialSkin.cpp index 37a4b8b0..f4987bf6 100644 --- a/skins/material/QskMaterialSkin.cpp +++ b/skins/material/QskMaterialSkin.cpp @@ -525,6 +525,7 @@ void QskMaterialSkin::initInputPanelHints() const ColorPalette& pal = m_data->palette; +/* // key panel setMargins( Q::KeyPanel | Margin, 2 ); @@ -552,6 +553,7 @@ void QskMaterialSkin::initInputPanelHints() setBoxBorderMetrics( Q::Panel, 0 ); setGradient( Q::Panel, pal.darker150 ); setBoxBorderColors( Q::Panel, pal.baseColor ); +*/ } void QskMaterialSkin::initScrollViewHints() diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 4d199662..5b1d3ba9 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -558,6 +558,7 @@ void QskSquiekSkin::initInputPanelHints() const ColorPalette& pal = m_data->palette; +/* // key panel setMargins( Q::KeyPanel | Margin, 2 ); // should be Panel | Spacing @@ -584,6 +585,7 @@ void QskSquiekSkin::initInputPanelHints() setMargins( Q::Panel | Padding, 5 ); setMargins( Q::Panel | Spacing, 5 ); setPanel( Q::Panel, Raised ); +*/ } void QskSquiekSkin::initScrollViewHints() diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index bbc78c4f..967e1e34 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -7,21 +7,19 @@ #include "QskAspect.h" +#include +#include #include #include #include #include +#include + +#include #include #include -QSK_SUBCONTROL( QskInputPanel, Panel ) -QSK_SUBCONTROL( QskInputPanel, KeyPanel ) -QSK_SUBCONTROL( QskInputPanel, KeyGlyph ) - -QSK_STATE( QskInputPanel, Checked, QskAspect::LastSystemState >> 3 ) -QSK_STATE( QskInputPanel, Pressed, QskAspect::LastSystemState >> 2 ) - namespace { struct KeyTable @@ -34,73 +32,6 @@ namespace return int( intptr_t( value - data[0] ) ); } }; - - QskInputPanel::KeyData* qskKeyDataAt( KeyTable& table, qreal x, qreal y ) - { - if( x < 0 || x > 1 || y < 0 || y > 1 ) - { - return nullptr; - } - - auto rowIndex = size_t( std::floor( y * QskInputPanel::RowCount ) ); - auto columnIndex = size_t( std::floor( x * QskInputPanel::KeyCount ) ); - - Q_FOREVER - { - const auto rect = table.data[ rowIndex ][ columnIndex ].rect; - - if( rect.contains( x, y ) ) - { - return &table.data[ rowIndex ][ columnIndex ]; - } - - // Look up/down - if( y < rect.top() ) - { - if( rowIndex == 0 ) - { - break; - } - - rowIndex -= 1; - continue; - } - else if( y > rect.bottom() ) - { - if( rowIndex == QskInputPanel::RowCount - 1 ) - { - break; - } - - rowIndex += 1; - continue; - } - - // Look left/right - if( x < rect.left() ) - { - if( columnIndex == 0 ) - { - break; - } - - columnIndex -= 1; - continue; - } - else if( x > rect.right() ) - { - if( columnIndex == QskInputPanel::KeyCount - 1 ) - { - break; - } - - columnIndex += 1; - continue; - } - } - - return nullptr; - } } struct QskInputPanelLayouts @@ -208,6 +139,64 @@ namespace }; } +QSK_SUBCONTROL( QskKeyButton, Panel ) +QSK_SUBCONTROL( QskKeyButton, Text ) +QSK_SUBCONTROL( QskKeyButton, TextCancelButton ) + +QskKeyButton::QskKeyButton( int keyIndex, QskInputPanel* inputPanel, QQuickItem* parent ) : + Inherited( parent ), + m_keyIndex( keyIndex ), + m_inputPanel( inputPanel ) +{ + setFlag( QQuickItem::ItemAcceptsInputMethod ); + + updateText(); + + connect( this, &QskKeyButton::pressed, this, [ this ]() + { + m_inputPanel->handleKey( m_keyIndex ); + } ); + + connect( m_inputPanel, &QskInputPanel::modeChanged, this, &QskKeyButton::updateText ); +} + +QskAspect::Subcontrol QskKeyButton::effectiveSubcontrol( QskAspect::Subcontrol subControl ) const +{ + if( subControl == QskPushButton::Panel ) + { + return QskKeyButton::Panel; + } + + if( subControl == QskPushButton::Text ) + { + // ### we could also introduce a state to not always query the button + return isCancelButton() ? QskKeyButton::TextCancelButton : QskKeyButton::Text; + } + + return subControl; +} + +void QskKeyButton::updateText() +{ + QString text = m_inputPanel->currentTextForKeyIndex( m_keyIndex ); + + if( text.count() == 1 && text.at( 0 ) == Qt::Key_unknown ) + { + setText( QStringLiteral( "" ) ); + } + else + { + setText( text ); + } +} + +bool QskKeyButton::isCancelButton() const +{ + auto keyData = m_inputPanel->keyDataAt( m_keyIndex ); + bool isCancel = ( keyData.key == 0x2716 ); + return isCancel; +} + class QskInputPanel::PrivateData { public: @@ -217,7 +206,8 @@ class QskInputPanel::PrivateData focusKeyIndex( -1 ), selectedGroup( -1 ), candidateOffset( 0 ), - repeatKeyTimerId( -1 ) + repeatKeyTimerId( -1 ), + isUIInitialized( false ) { } @@ -238,12 +228,17 @@ class QskInputPanel::PrivateData std::unordered_map< int, KeyCounter > activeKeys; KeyTable keyTable[ ModeCount ]; + + QList< QskKeyButton* > keyButtons; + bool isUIInitialized; }; QskInputPanel::QskInputPanel( QQuickItem* parent ): QskControl( parent ), m_data( new PrivateData ) { + qRegisterMetaType< Qt::Key >(); + setFlag( ItemHasContents ); setAcceptedMouseButtons( Qt::LeftButton ); @@ -353,6 +348,8 @@ QString QskInputPanel::displayLanguageName() const default: return QStringLiteral( "English (UK)" ); } + + break; } case QLocale::Spanish: @@ -554,6 +551,7 @@ void QskInputPanel::setCandidateOffset( int candidateOffset ) } else { + keyData.isSuggestionKey = true; // ### reset when switching layouts etc.! keyData.key = m_data->candidates.at( i + m_data->candidateOffset ); } } @@ -566,166 +564,38 @@ void QskInputPanel::setCandidateOffset( int candidateOffset ) if( m_data->mode == LowercaseMode ) { - update(); + updateUI(); } } QRectF QskInputPanel::keyboardRect() const { auto keyboardRect = rect(); // ### margins? would eliminate this thing below - - if( QskDialog::instance()->policy() != QskDialog::TopLevelWindow ) - { - keyboardRect.adjust( 0, keyboardRect.height() * 0.5, 0, 0 ); - } - + // if ( QskDialog::instance()->policy() != QskDialog::TopLevelWindow ) + // keyboardRect.adjust( 0, keyboardRect.height() * 0.5, 0, 0 ); return keyboardRect; } +void QskInputPanel::registerCompositionModelForLocale( const QLocale& locale, + QskInputCompositionModel* model ) +{ + Q_EMIT inputMethodRegistered( locale, model ); +} + void QskInputPanel::geometryChanged( const QRectF& newGeometry, const QRectF& oldGeometry ) { Inherited::geometryChanged( newGeometry, oldGeometry ); + + if( newGeometry != oldGeometry && !newGeometry.size().isNull() && !m_data->isUIInitialized ) + { + createUI(); + m_data->isUIInitialized = true; + } + Q_EMIT keyboardRectChanged(); } -void QskInputPanel::mousePressEvent( QMouseEvent* e ) -{ - if( !keyboardRect().contains( e->pos() ) ) - { - e->ignore(); - return; - } - - QTouchEvent::TouchPoint touchPoint( 0 ); - touchPoint.setPos( e->pos() ); - touchPoint.setState( Qt::TouchPointPressed ); - - QTouchEvent touchEvent( QTouchEvent::TouchBegin, nullptr, - e->modifiers(), Qt::TouchPointPressed, { touchPoint } ); - QCoreApplication::sendEvent( this, &touchEvent ); - - e->setAccepted( touchEvent.isAccepted() ); -} - -void QskInputPanel::mouseMoveEvent( QMouseEvent* e ) -{ - QTouchEvent::TouchPoint touchPoint( 0 ); - touchPoint.setPos( e->pos() ); - touchPoint.setState( Qt::TouchPointMoved ); - - QTouchEvent touchEvent( QTouchEvent::TouchUpdate, nullptr, - e->modifiers(), Qt::TouchPointMoved, { touchPoint } ); - QCoreApplication::sendEvent( this, &touchEvent ); - - e->setAccepted( touchEvent.isAccepted() ); -} - -void QskInputPanel::mouseReleaseEvent( QMouseEvent* e ) -{ - QTouchEvent::TouchPoint touchPoint( 0 ); - touchPoint.setPos( e->pos() ); - touchPoint.setState( Qt::TouchPointReleased ); - - QTouchEvent touchEvent( QTouchEvent::TouchEnd, nullptr, - e->modifiers(), Qt::TouchPointReleased, { touchPoint } ); - QCoreApplication::sendEvent( this, &touchEvent ); - - e->setAccepted( touchEvent.isAccepted() ); -} - -// Try to handle touch-specific details here; once touch is resolved, send to handleKey() -void QskInputPanel::touchEvent( QTouchEvent* e ) -{ - if( e->type() == QEvent::TouchCancel ) - { - for( auto& it : m_data->activeKeys ) - { - keyDataAt( it.second.keyIndex ).key &= ~KeyPressed; - } - - m_data->activeKeys.clear(); - return; - } - - const auto rect = keyboardRect(); - - for( const auto& tp : e->touchPoints() ) - { - const auto pos = tp.pos(); - - const auto x = ( pos.x() - rect.x() ) / rect.width(); - const auto y = ( pos.y() - rect.y() ) / rect.height(); - - auto keyData = qskKeyDataAt( m_data->keyTable[ m_data->mode ], x, y ); - - if( !keyData || ( !keyData->key || keyData->key == Qt::Key_unknown ) ) - { - auto it = m_data->activeKeys.find( tp.id() ); - - if( it == m_data->activeKeys.cend() ) - { - continue; - } - - keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; - m_data->activeKeys.erase( it ); - continue; - } - - const auto keyIndex = m_data->keyTable[ m_data->mode ].indexOf( keyData ); - auto it = m_data->activeKeys.find( tp.id() ); - - if( tp.state() == Qt::TouchPointReleased ) - { - const int repeatCount = it->second.count; - - auto it = m_data->activeKeys.find( tp.id() ); - keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; - m_data->activeKeys.erase( it ); - - if( repeatCount < 0 ) - { - continue; // Don't compose an accepted held key - } - - handleKey( keyIndex ); - continue; - } - - if( it == m_data->activeKeys.end() ) - { - m_data->activeKeys.emplace( tp.id(), KeyCounter { keyIndex, 0 } ); - } - else - { - if( it->second.keyIndex != keyIndex ) - { - keyDataAt( it->second.keyIndex ).key &= ~KeyPressed; - it->second.count = 0; - } - - it->second.keyIndex = keyIndex; - } - - keyDataAt( keyIndex ).key |= KeyPressed; - } - - // Now start an update timer based on active keys - if( m_data->activeKeys.empty() && m_data->repeatKeyTimerId >= 0 ) - { - killTimer( m_data->repeatKeyTimerId ); - m_data->repeatKeyTimerId = -1; - } - else if( m_data->repeatKeyTimerId < 0 ) - { - m_data->repeatKeyTimerId = startTimer( 1000 - / QGuiApplication::styleHints()->keyboardAutoRepeatRate() ); - } /* else timer is already running as it should be */ - - update(); -} - void QskInputPanel::timerEvent( QTimerEvent* e ) { if( e->timerId() == m_data->repeatKeyTimerId ) @@ -759,6 +629,76 @@ void QskInputPanel::timerEvent( QTimerEvent* e ) } } +bool QskInputPanel::eventFilter( QObject* object, QEvent* event ) +{ + if( event->type() == QEvent::InputMethod ) + { + QInputMethodEvent* inputMethodEvent = static_cast< QInputMethodEvent* >( event ); + Q_EMIT inputMethodEventReceived( inputMethodEvent ); + return true; + } + else if( event->type() == QEvent::KeyPress ) + { + // Return, Backspace and others are covered here (maybe because they don't carry a 'commit string'): + QKeyEvent* keyEvent = static_cast< QKeyEvent* >( event ); + Q_EMIT keyEventReceived( keyEvent ); + return true; + } + else + { + return Inherited::eventFilter( object, event ); + } +} + +void QskInputPanel::createUI() +{ + // deferring the UI creation until we are visible so that the contentsRect() returns the proper value + + setAutoLayoutChildren( true ); + + auto& panelKeyData = keyData(); + + const auto contentsRect = keyboardRect(); + const qreal sx = contentsRect.size().width(); + const qreal sy = contentsRect.size().height(); + + QskLinearBox* outterBox = new QskLinearBox( Qt::Vertical, this ); + outterBox->setAutoAddChildren( true ); + + for( const auto& keyRow : panelKeyData ) + { + QskLinearBox* rowBox = new QskLinearBox( Qt::Horizontal, outterBox ); + rowBox->setAutoAddChildren( true ); + + for( const auto& keyData : keyRow ) + { + if( !keyData.key ) + { + continue; + } + + const QSizeF buttonSize( keyData.rect.width() * sx, keyData.rect.height() * sy ); + + int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData ); + QskKeyButton* button = new QskKeyButton( keyIndex, this, rowBox ); + + button->installEventFilter( this ); + + button->setMaximumWidth( buttonSize.width() ); // ### set min width as well? + button->setFixedHeight( buttonSize.height() ); + m_data->keyButtons.append( button ); + } + } +} + +void QskInputPanel::updateUI() +{ + for( QskKeyButton* button : m_data->keyButtons ) + { + button->updateText(); + } +} + QskInputPanel::KeyData& QskInputPanel::keyDataAt( int keyIndex ) const { const auto row = keyIndex / KeyCount; @@ -768,7 +708,8 @@ QskInputPanel::KeyData& QskInputPanel::keyDataAt( int keyIndex ) const void QskInputPanel::handleKey( int keyIndex ) { - const auto key = keyDataAt( keyIndex ).key & ~KeyStates; + KeyData keyData = keyDataAt( keyIndex ); + const auto key = keyData.key & ~KeyStates; // Preedit keys const auto row = keyIndex / KeyCount; @@ -821,12 +762,30 @@ void QskInputPanel::handleKey( int keyIndex ) : SpecialCharacterMode ) ); return; + // This is (one of) the cancel symbol, not Qt::Key_Cancel: + case Qt::Key( 10006 ): + Q_EMIT cancelPressed(); + return; + default: break; } - // Normal keys - compose( key ); + if( keyData.isSuggestionKey ) + { + selectCandidate( keyIndex ); + } + else + { + compose( key ); + } +} + +QString QskInputPanel::currentTextForKeyIndex( int keyIndex ) const +{ + auto keyData = keyDataAt( keyIndex ); + QString text = textForKey( keyData.key ); + return text; } void QskInputPanel::compose( Qt::Key key ) @@ -974,10 +933,6 @@ void QskInputPanel::updateLocale( const QLocale& locale ) m_data->currentLayout = &qskInputPanelLayouts.zh; break; - case QLocale::C: - m_data->currentLayout = &qskInputPanelLayouts.en_US; - break; - default: qWarning() << "QskInputPanel: unsupported locale:" << locale; m_data->currentLayout = &qskInputPanelLayouts.en_US; @@ -1027,7 +982,7 @@ void QskInputPanel::updateKeyData() void QskInputPanel::setMode( QskInputPanel::Mode mode ) { m_data->mode = mode; - update(); + Q_EMIT modeChanged( m_data->mode ); } #include "QskInputPanel.moc" diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index b5a4da29..fa316770 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -7,9 +7,35 @@ #define QSK_INPUT_PANEL_H #include "QskControl.h" +#include "QskPushButton.h" #include +class QskInputCompositionModel; +class QskInputPanel; + +class QskKeyButton : public QskPushButton +{ + Q_OBJECT + + using Inherited = QskPushButton; + + public: + QSK_SUBCONTROLS( Panel, Text, TextCancelButton ) + QskKeyButton( int keyIndex, QskInputPanel* inputPanel, QQuickItem* parent = nullptr ); + + virtual QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol subControl ) const override; + + public Q_SLOTS: + void updateText(); + + private: + bool isCancelButton() const; + + const int m_keyIndex; + QskInputPanel* m_inputPanel; +}; + class QSK_EXPORT QskInputPanel : public QskControl { Q_OBJECT @@ -22,12 +48,10 @@ class QSK_EXPORT QskInputPanel : public QskControl using Inherited = QskControl; public: - QSK_SUBCONTROLS( Panel, KeyPanel, KeyGlyph ) - QSK_STATES( Checked, Pressed ) - struct KeyData { Qt::Key key = Qt::Key( 0 ); + bool isSuggestionKey = false; QRectF rect; }; @@ -74,6 +98,10 @@ public: QRectF keyboardRect() const; + // takes ownership: + void registerCompositionModelForLocale( const QLocale& locale, + QskInputCompositionModel* model ); + public Q_SLOTS: void setPreeditGroups( const QVector< Qt::Key >& ); void setPreeditCandidates( const QVector< Qt::Key >& ); @@ -82,19 +110,19 @@ public Q_SLOTS: bool deactivateFocusKey(); void clearFocusKey(); + void handleKey( int keyIndex ); + KeyData& keyDataAt( int ) const; + QString currentTextForKeyIndex( int keyIndex ) const; + protected: virtual void geometryChanged( const QRectF&, const QRectF& ) override; - - virtual void mousePressEvent( QMouseEvent* ) override; - virtual void mouseMoveEvent( QMouseEvent* ) override; - virtual void mouseReleaseEvent( QMouseEvent* ) override; - virtual void touchEvent( QTouchEvent* ) override; virtual void timerEvent( QTimerEvent* ) override; + virtual bool eventFilter( QObject* object, QEvent* event ) override; private: - KeyData& keyDataAt( int ) const; + void createUI(); + void updateUI(); // e.g. called when updating Pinyin suggestions - void handleKey( int ); void compose( Qt::Key ); void selectGroup( int ); void selectCandidate( int ); @@ -105,6 +133,11 @@ private: Q_SIGNALS: void keyboardRectChanged(); void displayLanguageNameChanged(); + void inputMethodRegistered( const QLocale& locale, QskInputCompositionModel* model ); + void inputMethodEventReceived( QInputMethodEvent* inputMethodEvent ); + void keyEventReceived( QKeyEvent* keyEvent ); + void modeChanged( QskInputPanel::Mode mode ); + void cancelPressed(); public: class PrivateData; diff --git a/src/controls/QskInputPanelSkinlet.cpp b/src/controls/QskInputPanelSkinlet.cpp deleted file mode 100644 index 56acd7a4..00000000 --- a/src/controls/QskInputPanelSkinlet.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#include "QskInputPanelSkinlet.h" -#include "QskInputPanel.h" - -#include "QskAspect.h" -#include "QskSkin.h" -#include "QskTextOptions.h" -#include "QskTextNode.h" -#include "QskBoxNode.h" - -static constexpr const QSGNode::Flag IsSubtreeBlocked = - static_cast< QSGNode::Flag >( 0x100000 ); -static constexpr const QSGNode::Flag KeyFrameNode = - static_cast< QSGNode::Flag >( 0x200000 ); -static constexpr const QSGNode::Flag KeyGlyphNode = - static_cast< QSGNode::Flag >( 0x400000 ); - -namespace -{ - class KeySkinnable: public QskSkinnable - { - public: - KeySkinnable( QskInputPanel* panel ): - m_panel( panel ) - { - } - - void setKey( Qt::Key key ) - { - setSkinStateFlag( QskInputPanel::Pressed, key & Qt::ShiftModifier ); - setSkinStateFlag( QskInputPanel::Checked, key & Qt::ControlModifier ); - setSkinStateFlag( QskInputPanel::Focused, key & Qt::MetaModifier ); - } - - const QMetaObject* metaObject() const override final - { - // Use the parent skinlet - return &QskInputPanelSkinlet::staticMetaObject; - } - - protected: - virtual const QskSkinlet* effectiveSkinlet() const override final - { - return m_panel->effectiveSkinlet(); - } - - private: - virtual QskControl* owningControl() const override final - { - return const_cast< QskInputPanel* >( m_panel ); - } - - private: - QskInputPanel* m_panel; - }; - - class FrameNode final : public QskBoxNode, public KeySkinnable - { - public: - FrameNode( QskInputPanel* panel ): - KeySkinnable( panel ) - { - setFlag( KeyFrameNode ); - } - }; - - class TextNode final : public QskTextNode, public KeySkinnable - { - public: - TextNode( QskInputPanel* panel ): - KeySkinnable( panel ) - { - setFlag( KeyGlyphNode ); - } - }; - - class InputPanelNode final : public QskBoxNode - { - public: - InputPanelNode() - { - } - - virtual bool isSubtreeBlocked() const override final - { - return flags() & IsSubtreeBlocked; - } - - using Row = QSGNode*[ QskInputPanel::KeyCount ]; - Row frames[ QskInputPanel::RowCount ] = {}; - Row glyphs[ QskInputPanel::RowCount ] = {}; - }; -} - -static_assert( QskInputPanel::RowCount * QskInputPanel::KeyCount < 255, - "The number of keys must fit into an unsigned byte." ); - -QskInputPanelSkinlet::QskInputPanelSkinlet( QskSkin* skin ): - Inherited( skin ) -{ - setNodeRoles( { Panel0, Panel1, Panel2 } ); -} - -QskInputPanelSkinlet::~QskInputPanelSkinlet() -{ -} - -QSGNode* QskInputPanelSkinlet::updateSubNode( - const QskSkinnable* control, quint8 nodeRole, QSGNode* node ) const -{ - auto inputPanel = static_cast< const QskInputPanel* >( control ); - const bool blockSubtree = inputPanel->mode() != nodeRole; - - auto panelNode = static_cast< InputPanelNode* >( node ); - if ( panelNode && panelNode->isSubtreeBlocked() != blockSubtree ) - { - panelNode->setFlag( IsSubtreeBlocked, blockSubtree ); - panelNode->markDirty( QSGNode::DirtySubtreeBlocked ); - } - - if ( !blockSubtree ) - node = updatePanelNode( inputPanel, panelNode ); - - return node; -} - -QSGNode* QskInputPanelSkinlet::updatePanelNode( - const QskInputPanel* panel, QSGNode* node ) const -{ - auto panelNode = static_cast< InputPanelNode* >( node ); - if ( panelNode == nullptr ) - panelNode = new InputPanelNode; - - const auto contentsRect = panel->keyboardRect(); - - auto& panelKeyData = panel->keyData(); - for ( const auto& keyRow : panelKeyData ) - { - const auto rowIndex = &keyRow - panelKeyData; - auto& frames = panelNode->frames[ rowIndex ]; - auto& glyphs = panelNode->glyphs[ rowIndex ]; - - for ( const auto& keyData : keyRow ) - { - const auto colIndex = &keyData - keyRow; - auto& frame = frames[ colIndex ]; - auto& glyph = glyphs[ colIndex ]; - - if ( !keyData.key || keyData.key == Qt::Key_unknown ) - { - delete frame; - frame = nullptr; - - delete glyph; - glyph = nullptr; - - continue; - } - - const qreal sx = contentsRect.size().width(); - const qreal sy = contentsRect.size().height(); - - const QRectF keyRect( - contentsRect.x() + keyData.rect.x() * sx, - contentsRect.y() + keyData.rect.y() * sy, - keyData.rect.width() * sx, - keyData.rect.height() * sy ); - - frame = updateKeyFrameNode( panel, frame, keyRect, keyData.key ); - if ( frame->parent() != panelNode ) - panelNode->appendChildNode( frame ); - - glyph = updateKeyGlyphNode( panel, glyph, keyRect, keyData.key ); - if ( glyph->parent() != panelNode ) - panelNode->appendChildNode( glyph ); - } - } - - updateBoxNode( panel, panelNode, contentsRect, QskInputPanel::Panel ); - - return panelNode; -} - -QSGNode* QskInputPanelSkinlet::updateKeyFrameNode( - const QskInputPanel* panel, QSGNode* node, - const QRectF& rect, Qt::Key key ) const -{ - auto frameNode = static_cast< FrameNode* >( node ); - if ( frameNode == nullptr ) - frameNode = new FrameNode( const_cast< QskInputPanel* >( panel ) ); - - frameNode->setKey( key ); - updateBoxNode( frameNode, frameNode, rect, QskInputPanel::KeyPanel ); - - return frameNode; -} - -QSGNode* QskInputPanelSkinlet::updateKeyGlyphNode( - const QskInputPanel* panel, QSGNode* node, - const QRectF& rect, Qt::Key key ) const -{ - auto textNode = static_cast< TextNode* >( node ); - if ( textNode == nullptr ) - textNode = new TextNode( const_cast< QskInputPanel* >( panel ) ); - - textNode->setKey( key ); - - QskTextOptions options; - options.setFontSizeMode( QskTextOptions::VerticalFit ); - - const auto alignment = textNode->flagHint< Qt::Alignment >( - QskInputPanel::KeyGlyph | QskAspect::Alignment, Qt::AlignCenter ); - - return updateTextNode( panel, textNode, rect, alignment, - panel->textForKey( key ), options, QskInputPanel::KeyGlyph ); -} - -#include "moc_QskInputPanelSkinlet.cpp" diff --git a/src/controls/QskInputPanelSkinlet.h b/src/controls/QskInputPanelSkinlet.h deleted file mode 100644 index 02202069..00000000 --- a/src/controls/QskInputPanelSkinlet.h +++ /dev/null @@ -1,43 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#ifndef QSK_INPUT_PANEL_SKINLET_H -#define QSK_INPUT_PANEL_SKINLET_H - -#include "QskSkinlet.h" - -class QskInputPanel; - -class QSK_EXPORT QskInputPanelSkinlet : public QskSkinlet -{ - Q_GADGET - - using Inherited = QskSkinlet; - - enum NodeRole - { - Panel0, - Panel1, - Panel2 - }; - -public: - Q_INVOKABLE QskInputPanelSkinlet( QskSkin* = nullptr ); - virtual ~QskInputPanelSkinlet(); - -protected: - virtual QSGNode* updateSubNode( const QskSkinnable*, - quint8, QSGNode* ) const override; - - virtual QSGNode* updatePanelNode( const QskInputPanel*, QSGNode* ) const; - - virtual QSGNode* updateKeyFrameNode( const QskInputPanel*, - QSGNode*, const QRectF&, Qt::Key ) const; - - virtual QSGNode* updateKeyGlyphNode( const QskInputPanel*, - QSGNode*, const QRectF&, Qt::Key ) const; -}; - -#endif diff --git a/src/controls/QskSkin.cpp b/src/controls/QskSkin.cpp index 8b262531..427878ea 100644 --- a/src/controls/QskSkin.cpp +++ b/src/controls/QskSkin.cpp @@ -39,9 +39,6 @@ QSK_QT_PRIVATE_END #include "QskGraphicLabel.h" #include "QskGraphicLabelSkinlet.h" -#include "QskInputPanel.h" -#include "QskInputPanelSkinlet.h" - #include "QskListView.h" #include "QskListViewSkinlet.h" @@ -130,7 +127,6 @@ QskSkin::QskSkin( QObject* parent ): declareSkinlet< QskBox, QskBoxSkinlet >(); declareSkinlet< QskFocusIndicator, QskFocusIndicatorSkinlet >(); declareSkinlet< QskGraphicLabel, QskGraphicLabelSkinlet >(); - declareSkinlet< QskInputPanel, QskInputPanelSkinlet >(); declareSkinlet< QskListView, QskListViewSkinlet >(); declareSkinlet< QskPageIndicator, QskPageIndicatorSkinlet >(); declareSkinlet< QskPopup, QskPopupSkinlet >(); diff --git a/src/src.pro b/src/src.pro index 828b7a41..c92375ce 100644 --- a/src/src.pro +++ b/src/src.pro @@ -136,7 +136,6 @@ HEADERS += \ controls/QskGraphicLabelSkinlet.h \ controls/QskHintAnimator.h \ controls/QskInputPanel.h \ - controls/QskInputPanelSkinlet.h \ controls/QskListView.h \ controls/QskListViewSkinlet.h \ controls/QskObjectTree.h \ @@ -201,7 +200,6 @@ SOURCES += \ controls/QskGraphicLabelSkinlet.cpp \ controls/QskHintAnimator.cpp \ controls/QskInputPanel.cpp \ - controls/QskInputPanelSkinlet.cpp \ controls/QskListView.cpp \ controls/QskListViewSkinlet.cpp \ controls/QskObjectTree.cpp \ From 5a250eff8bb010930306d6add6f44a3c9498c690 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 17:30:39 +0100 Subject: [PATCH 04/21] Fix input panel event propagation --- inputcontext/QskInputCompositionModel.cpp | 29 ++++++++++----- inputcontext/QskInputCompositionModel.h | 4 +++ inputcontext/QskInputContext.cpp | 43 +++++++++++++++++------ inputcontext/QskInputContext.h | 2 ++ playground/inputpanel/TextInput.cpp | 5 +++ playground/inputpanel/TextInput.h | 5 ++- src/controls/QskInputPanel.cpp | 5 +-- 7 files changed, 71 insertions(+), 22 deletions(-) diff --git a/inputcontext/QskInputCompositionModel.cpp b/inputcontext/QskInputCompositionModel.cpp index 601b7aef..567f0dcb 100644 --- a/inputcontext/QskInputCompositionModel.cpp +++ b/inputcontext/QskInputCompositionModel.cpp @@ -37,20 +37,20 @@ static QString qskKeyString( int code ) class QskInputCompositionModel::PrivateData { public: + PrivateData() : + inputItem( nullptr ), + groupIndex( 0 ) + { + } // QInputMethod QString preedit; QTextCharFormat preeditFormat; QList< QInputMethodEvent::Attribute > preeditAttributes; + QObject* inputItem; int groupIndex; }; -static inline void sendCompositionEvent( QInputMethodEvent* e ) -{ - if ( auto focusObject = QGuiApplication::focusObject() ) - QCoreApplication::sendEvent( focusObject, e ); -} - QskInputCompositionModel::QskInputCompositionModel(): m_data( new PrivateData ) { @@ -77,7 +77,7 @@ void QskInputCompositionModel::composeKey( Qt::Key key ) QInputMethodQueryEvent queryEvent( Qt::ImSurroundingText | Qt::ImMaximumTextLength | Qt::ImHints ); - QCoreApplication::sendEvent( focusObject, &queryEvent ); + QCoreApplication::sendEvent( m_data->inputItem, &queryEvent ); const auto hints = static_cast< Qt::InputMethodHints >( queryEvent.value( Qt::ImHints ).toInt() ); const int maxLength = queryEvent.value( Qt::ImMaximumTextLength ).toInt(); @@ -237,8 +237,8 @@ void QskInputCompositionModel::backspace() // Backspace one character only if preedit was inactive QKeyEvent keyPress( QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier ); QKeyEvent keyRelease( QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier ); - QCoreApplication::sendEvent( focusWindow, &keyPress ); - QCoreApplication::sendEvent( focusWindow, &keyRelease ); + QCoreApplication::sendEvent( m_data->inputItem, &keyPress ); + QCoreApplication::sendEvent( m_data->inputItem, &keyRelease ); return; } @@ -267,6 +267,12 @@ void QskInputCompositionModel::moveCursor( Qt::Key key ) QCoreApplication::sendEvent( focusWindow, &moveCursorRelease ); } +void QskInputCompositionModel::sendCompositionEvent( QInputMethodEvent* e ) +{ + if ( m_data->inputItem ) + QCoreApplication::sendEvent( m_data->inputItem, e ); +} + bool QskInputCompositionModel::hasIntermediate() const { return false; @@ -300,6 +306,11 @@ QVector< Qt::Key > QskInputCompositionModel::groups() const return QVector< Qt::Key >(); } +void QskInputCompositionModel::setInputItem( QObject *inputItem ) +{ + m_data->inputItem = inputItem; +} + bool QskInputCompositionModel::nextGroupIndex(int& index, bool forward) const { Q_UNUSED(index); diff --git a/inputcontext/QskInputCompositionModel.h b/inputcontext/QskInputCompositionModel.h index e96eecd2..94e5be53 100644 --- a/inputcontext/QskInputCompositionModel.h +++ b/inputcontext/QskInputCompositionModel.h @@ -10,6 +10,7 @@ #include +class QInputMethodEvent; class QStringList; class QskInputCompositionModel : public QObject @@ -37,6 +38,8 @@ public: virtual QVector< Qt::Key > groups() const; + void setInputItem( QObject* inputItem ); + protected: // Used for text composition virtual bool hasIntermediate() const; @@ -50,6 +53,7 @@ Q_SIGNALS: private: void backspace(); void moveCursor( Qt::Key key ); + void sendCompositionEvent( QInputMethodEvent* e ); class PrivateData; std::unique_ptr< PrivateData > m_data; diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index 20a24c20..9f97057e 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -26,6 +26,8 @@ QskInputContext::QskInputContext(): connect( qskSetup, &QskSetup::inputPanelChanged, this, &QskInputContext::setInputPanel ); setInputPanel( qskSetup->inputPanel() ); + + m_inputCompositionModel.reset( new QskInputCompositionModel ); } QskInputContext::~QskInputContext() @@ -41,11 +43,11 @@ bool QskInputContext::isValid() const void QskInputContext::update( Qt::InputMethodQueries queries ) { - if ( !m_focusObject ) + if ( !m_inputItem ) return; QInputMethodQueryEvent queryEvent( queries ); - if ( !QCoreApplication::sendEvent( m_focusObject, &queryEvent ) ) + if ( !QCoreApplication::sendEvent( m_inputItem, &queryEvent ) ) return; // Qt::ImCursorRectangle @@ -209,18 +211,39 @@ void QskInputContext::setFocusObject( QObject* focusObject ) m_focusObject = focusObject; if ( !m_focusObject ) - return; - - QInputMethodQueryEvent queryEvent( Qt::ImEnabled ); - if ( !QCoreApplication::sendEvent( m_focusObject, &queryEvent ) ) - return; - - if ( !queryEvent.value( Qt::ImEnabled ).toBool() ) { - hideInputPanel(); + m_inputItem = nullptr; + m_inputCompositionModel->setInputItem( nullptr ); return; } + bool inputItemChanged = false; + + auto focusQuickItem = qobject_cast< QQuickItem* >( focusObject ); + if( focusQuickItem ) + { + // Do not change the input item when panel buttons get the focus: + if( qskNearestFocusScope( focusQuickItem ) != m_inputPanel ) + { + m_inputItem = focusQuickItem; + m_inputCompositionModel->setInputItem( m_inputItem ); // ### use a signal/slot connection + inputItemChanged = true; + } + } + + if( inputItemChanged ) + { + QInputMethodQueryEvent queryEvent( Qt::ImEnabled ); + if ( !QCoreApplication::sendEvent( m_inputItem, &queryEvent ) ) + return; + + if ( !queryEvent.value( Qt::ImEnabled ).toBool() ) + { + hideInputPanel(); + return; + } + } + m_focusObject->installEventFilter( this ); update( Qt::InputMethodQuery( Qt::ImQueryAll & ~Qt::ImEnabled ) ); } diff --git a/inputcontext/QskInputContext.h b/inputcontext/QskInputContext.h index 1a167f86..31a7c30d 100644 --- a/inputcontext/QskInputContext.h +++ b/inputcontext/QskInputContext.h @@ -8,6 +8,7 @@ #include #include +#include #include @@ -45,6 +46,7 @@ private Q_SLOTS: private: QPointer< QObject > m_focusObject; + QPointer< QQuickItem > m_inputItem; QPointer< QskInputPanel > m_inputPanel; std::unique_ptr< QskInputCompositionModel > m_inputCompositionModel; }; diff --git a/playground/inputpanel/TextInput.cpp b/playground/inputpanel/TextInput.cpp index 8d43e2f3..6069ffdc 100644 --- a/playground/inputpanel/TextInput.cpp +++ b/playground/inputpanel/TextInput.cpp @@ -10,3 +10,8 @@ TextInput::~TextInput() { } + +void TextInput::inputMethodEvent(QInputMethodEvent *event) +{ + QQuickTextInput::inputMethodEvent(event); +} diff --git a/playground/inputpanel/TextInput.h b/playground/inputpanel/TextInput.h index 3fe56eeb..86ff4f3f 100644 --- a/playground/inputpanel/TextInput.h +++ b/playground/inputpanel/TextInput.h @@ -7,7 +7,10 @@ class TextInput : public QQuickTextInput { public: TextInput( QQuickItem* parent ); - virtual ~TextInput(); + virtual ~TextInput() override; + +protected: + void inputMethodEvent(QInputMethodEvent *) Q_DECL_OVERRIDE; }; #endif // TEXTINPUT_H diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 967e1e34..e49e94db 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -148,8 +148,6 @@ QskKeyButton::QskKeyButton( int keyIndex, QskInputPanel* inputPanel, QQuickItem* m_keyIndex( keyIndex ), m_inputPanel( inputPanel ) { - setFlag( QQuickItem::ItemAcceptsInputMethod ); - updateText(); connect( this, &QskKeyButton::pressed, this, [ this ]() @@ -248,6 +246,9 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): QObject::connect( this, &QskControl::localeChanged, this, &QskInputPanel::updateLocale ); + + setFlag( ItemIsFocusScope, true ); + setTabFence( true ); } QskInputPanel::~QskInputPanel() From debd286b4d81270f11fd37569182f8ca3b36ea92 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 17:30:41 +0100 Subject: [PATCH 05/21] input panel: Apply style to new input panel --- inputcontext/QskInputCompositionModel.cpp | 2 +- skins/material/QskMaterialSkin.cpp | 28 ++++++++++----------- skins/squiek/QskSquiekSkin.cpp | 30 +++++++++++------------ src/controls/QskInputPanel.h | 4 +-- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/inputcontext/QskInputCompositionModel.cpp b/inputcontext/QskInputCompositionModel.cpp index 567f0dcb..da956d5b 100644 --- a/inputcontext/QskInputCompositionModel.cpp +++ b/inputcontext/QskInputCompositionModel.cpp @@ -56,7 +56,7 @@ QskInputCompositionModel::QskInputCompositionModel(): { m_data->groupIndex = 0; - m_data->preeditFormat.setFontUnderline(true); + m_data->preeditFormat.setFontUnderline( true ); m_data->preeditAttributes.append( QInputMethodEvent::Attribute( QInputMethodEvent::TextFormat, 0, 0, m_data->preeditFormat ) ); } diff --git a/skins/material/QskMaterialSkin.cpp b/skins/material/QskMaterialSkin.cpp index f4987bf6..fe2df2ea 100644 --- a/skins/material/QskMaterialSkin.cpp +++ b/skins/material/QskMaterialSkin.cpp @@ -521,39 +521,37 @@ void QskMaterialSkin::initTabViewHints() void QskMaterialSkin::initInputPanelHints() { using namespace QskAspect; - using Q = QskInputPanel; + using Q = QskKeyButton; const ColorPalette& pal = m_data->palette; -/* // key panel - setMargins( Q::KeyPanel | Margin, 2 ); +// setMargins( Q::KeyPanel | Margin, 2 ); - setBoxShape( Q::KeyPanel, 20.0, Qt::RelativeSize ); - setBoxBorderMetrics( Q::KeyPanel, 2 ); + setBoxShape( Q::Panel, 20.0, Qt::RelativeSize ); + setBoxBorderMetrics( Q::Panel, 2 ); - setGradient( Q::KeyPanel, pal.darker125 ); - setBoxBorderColors( Q::KeyPanel, pal.baseColor ); + setGradient( Q::Panel, pal.darker125 ); + setBoxBorderColors( Q::Panel, pal.baseColor ); for ( auto state : { NoState, Q::Focused } ) - setBoxBorderColors( Q::KeyPanel | Q::Pressed | state, pal.accentColor ); + setBoxBorderColors( Q::Panel | Q::Pressed | state, pal.accentColor ); - setAnimation( Q::KeyPanel | Color, qskDuration ); - setAnimation( Q::KeyPanel | Metric, qskDuration ); + setAnimation( Q::Panel | Color, qskDuration ); + setAnimation( Q::Panel | Metric, qskDuration ); // glyph - setSkinHint( Q::KeyGlyph | Alignment, Qt::AlignCenter ); - setFontRole( Q::KeyGlyph, QskSkin::TinyFont ); +// setSkinHint( Q::KeyGlyph | Alignment, Qt::AlignCenter ); +// setFontRole( Q::KeyGlyph, QskSkin::TinyFont ); - setColor( Q::KeyGlyph, pal.textColor ); - setColor( Q::KeyGlyph | Q::Disabled, pal.darker200 ); +// setColor( Q::KeyGlyph, pal.textColor ); +// setColor( Q::KeyGlyph | Q::Disabled, pal.darker200 ); // panel setBoxShape( Q::Panel, 0 ); setBoxBorderMetrics( Q::Panel, 0 ); setGradient( Q::Panel, pal.darker150 ); setBoxBorderColors( Q::Panel, pal.baseColor ); -*/ } void QskMaterialSkin::initScrollViewHints() diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 5b1d3ba9..e2b353ba 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -554,38 +554,36 @@ void QskSquiekSkin::initTabViewHints() void QskSquiekSkin::initInputPanelHints() { using namespace QskAspect; - using Q = QskInputPanel; + using Q = QskKeyButton; const ColorPalette& pal = m_data->palette; -/* // key panel - setMargins( Q::KeyPanel | Margin, 2 ); // should be Panel | Spacing +// setMargins( Q::Panel | Margin, 2 ); // should be Panel | Spacing - setButton( Q::KeyPanel, Raised ); - setButton( Q::KeyPanel | Q::Pressed, Sunken ); + setButton( Q::Panel, Raised ); + setButton( Q::Panel | Q::Pressed, Sunken ); - setAnimation( Q::KeyPanel | Color, qskDuration ); + setAnimation( Q::Panel | Color, qskDuration ); #if 0 // crashes because animations are started from updateNode // TODO ... - setAnimation( Q::KeyPanel | Metric, qskDuration ); + setAnimation( Q::Panel | Metric, qskDuration ); #endif // glyph - setSkinHint( Q::KeyGlyph | Alignment, Qt::AlignCenter ); - setFontRole( Q::KeyGlyph, QskSkin::TinyFont ); +// setSkinHint( Q::Text | Alignment, Qt::AlignCenter ); +// setFontRole( Q::Text, QskSkin::TinyFont ); - setColor( Q::KeyGlyph, pal.themeForeground ); - setColor( Q::KeyGlyph | Q::Disabled, pal.darker200 ); + setColor( Q::Text, pal.themeForeground ); + setColor( Q::Text | Q::Disabled, pal.darker200 ); - // panel +// // panel - setMargins( Q::Panel | Padding, 5 ); - setMargins( Q::Panel | Spacing, 5 ); - setPanel( Q::Panel, Raised ); -*/ +// setMargins( Q::Panel | Padding, 5 ); +// setMargins( Q::Panel | Spacing, 5 ); +// setPanel( Q::Panel, Raised ); } void QskSquiekSkin::initScrollViewHints() diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index fa316770..1f18b638 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -14,7 +14,7 @@ class QskInputCompositionModel; class QskInputPanel; -class QskKeyButton : public QskPushButton +class QskKeyButton : public QskPushButton // ### rename to QskInputButton or so? { Q_OBJECT @@ -84,7 +84,7 @@ public: using KeyDataSet = KeyDataRow[RowCount]; QskInputPanel( QQuickItem* parent = nullptr ); - virtual ~QskInputPanel(); + virtual ~QskInputPanel() override; void updateLocale( const QLocale& locale ); From a0995f6d72634f279059664fe5cb61879f96184b Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 18:00:55 +0100 Subject: [PATCH 06/21] keyboard: fix cursor navigation and clean up the code a bit --- inputcontext/QskInputCompositionModel.cpp | 13 +++++-------- inputcontext/QskInputContext.cpp | 6 ++++-- inputcontext/QskInputContext.h | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/inputcontext/QskInputCompositionModel.cpp b/inputcontext/QskInputCompositionModel.cpp index da956d5b..eed9c1bb 100644 --- a/inputcontext/QskInputCompositionModel.cpp +++ b/inputcontext/QskInputCompositionModel.cpp @@ -71,8 +71,7 @@ void QskInputCompositionModel::composeKey( Qt::Key key ) if ( !inputMethod ) return; - auto focusObject = QGuiApplication::focusObject(); - if ( !focusObject ) + if ( !m_data->inputItem ) return; QInputMethodQueryEvent queryEvent( @@ -224,8 +223,7 @@ void QskInputCompositionModel::commitCandidate( int index ) void QskInputCompositionModel::backspace() { - auto focusWindow = QGuiApplication::focusWindow(); - if ( !focusWindow ) + if ( !m_data->inputItem ) return; if ( !m_data->preedit.isEmpty() ) @@ -253,8 +251,7 @@ void QskInputCompositionModel::moveCursor( Qt::Key key ) if ( key != Qt::Key_Left && key != Qt::Key_Right ) return; - auto focusWindow = QGuiApplication::focusWindow(); - if ( !focusWindow ) + if ( !m_data->inputItem ) return; // Moving cursor is disabled when preedit is active. @@ -263,8 +260,8 @@ void QskInputCompositionModel::moveCursor( Qt::Key key ) QKeyEvent moveCursorPress( QEvent::KeyPress, key, Qt::NoModifier ); QKeyEvent moveCursorRelease( QEvent::KeyRelease, key, Qt::NoModifier ); - QCoreApplication::sendEvent( focusWindow, &moveCursorPress ); - QCoreApplication::sendEvent( focusWindow, &moveCursorRelease ); + QCoreApplication::sendEvent( m_data->inputItem, &moveCursorPress ); + QCoreApplication::sendEvent( m_data->inputItem, &moveCursorRelease ); } void QskInputCompositionModel::sendCompositionEvent( QInputMethodEvent* e ) diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index 9f97057e..a95259eb 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -21,13 +21,15 @@ #include QskInputContext::QskInputContext(): - Inherited() + Inherited(), + m_inputCompositionModel( new QskInputCompositionModel ) { connect( qskSetup, &QskSetup::inputPanelChanged, this, &QskInputContext::setInputPanel ); setInputPanel( qskSetup->inputPanel() ); - m_inputCompositionModel.reset( new QskInputCompositionModel ); + // We could connect candidatesChanged() here, but we don't emit + // the signal in the normal composition model anyhow } QskInputContext::~QskInputContext() diff --git a/inputcontext/QskInputContext.h b/inputcontext/QskInputContext.h index 31a7c30d..85a852eb 100644 --- a/inputcontext/QskInputContext.h +++ b/inputcontext/QskInputContext.h @@ -23,7 +23,7 @@ class QskInputContext : public QPlatformInputContext public: QskInputContext(); - ~QskInputContext(); + ~QskInputContext() override; bool isValid() const override; void update( Qt::InputMethodQueries ) override; From 80249f0c306793c0742913c82eb7e6ecafdd764b Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Thu, 15 Mar 2018 10:31:50 +0100 Subject: [PATCH 07/21] QskInputPanel: Support margins --- skins/squiek/QskSquiekSkin.cpp | 2 +- src/controls/QskInputPanel.cpp | 5 +++++ src/controls/QskInputPanel.h | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index e2b353ba..0093feba 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -559,7 +559,7 @@ void QskSquiekSkin::initInputPanelHints() const ColorPalette& pal = m_data->palette; // key panel -// setMargins( Q::Panel | Margin, 2 ); // should be Panel | Spacing + setMargins( QskInputPanel::Panel | Margin, 2 ); setButton( Q::Panel, Raised ); setButton( Q::Panel | Q::Pressed, Sunken ); diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index e49e94db..28c35f89 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -139,6 +139,8 @@ namespace }; } +QSK_SUBCONTROL( QskInputPanel, Panel ) + QSK_SUBCONTROL( QskKeyButton, Panel ) QSK_SUBCONTROL( QskKeyButton, Text ) QSK_SUBCONTROL( QskKeyButton, TextCancelButton ) @@ -242,6 +244,9 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding ); + auto margins = marginsHint( Panel | QskAspect::Margin ); + setMargins( margins ); + updateLocale( locale() ); QObject::connect( this, &QskControl::localeChanged, diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index 1f18b638..4c893bbe 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -48,6 +48,9 @@ class QSK_EXPORT QskInputPanel : public QskControl using Inherited = QskControl; public: + + QSK_SUBCONTROLS( Panel ) + struct KeyData { Qt::Key key = Qt::Key( 0 ); From a28909327bb4e837626c210273e76cb7f8c8ec31 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Thu, 22 Mar 2018 15:48:29 +0100 Subject: [PATCH 08/21] Add subcontrol for input panel --- skins/squiek/QskSquiekSkin.cpp | 1 + src/controls/QskInputPanel.cpp | 14 ++++++++++++++ src/controls/QskInputPanel.h | 2 ++ 3 files changed, 17 insertions(+) diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 0093feba..81fd27cc 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -560,6 +560,7 @@ void QskSquiekSkin::initInputPanelHints() // key panel setMargins( QskInputPanel::Panel | Margin, 2 ); + setButton( QskInputPanel::Panel, Raised ); setButton( Q::Panel, Raised ); setButton( Q::Panel | Q::Pressed, Sunken ); diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 28c35f89..5be42f36 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -244,6 +244,8 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding ); + setAutoFillBackground( true ); + auto margins = marginsHint( Panel | QskAspect::Margin ); setMargins( margins ); @@ -260,6 +262,18 @@ QskInputPanel::~QskInputPanel() { } + +QskAspect::Subcontrol QskInputPanel::effectiveSubcontrol( QskAspect::Subcontrol subControl ) const +{ + if( subControl == QskAspect::Control ) + { + return QskInputPanel::Panel; + } + + return subControl; +} + + QskInputPanel::Mode QskInputPanel::mode() const { return m_data->mode; diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index 4c893bbe..d5fb7d35 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -89,6 +89,8 @@ public: QskInputPanel( QQuickItem* parent = nullptr ); virtual ~QskInputPanel() override; + virtual QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol subControl ) const override; + void updateLocale( const QLocale& locale ); void setMode( QskInputPanel::Mode index ); From fcba8982172d0fd33645178d8081ce3b96549700 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 21 Mar 2018 13:00:24 +0100 Subject: [PATCH 09/21] fix layout --- src/controls/QskInputPanel.cpp | 50 ++++++++++++++++++++++++++-------- src/controls/QskInputPanel.h | 5 +++- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 5be42f36..cea57709 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -176,6 +176,11 @@ QskAspect::Subcontrol QskKeyButton::effectiveSubcontrol( QskAspect::Subcontrol s return subControl; } +int QskKeyButton::keyIndex() const +{ + return m_keyIndex; +} + void QskKeyButton::updateText() { QString text = m_inputPanel->currentTextForKeyIndex( m_keyIndex ); @@ -207,6 +212,7 @@ class QskInputPanel::PrivateData selectedGroup( -1 ), candidateOffset( 0 ), repeatKeyTimerId( -1 ), + buttonsBox( nullptr ), isUIInitialized( false ) { } @@ -229,6 +235,7 @@ class QskInputPanel::PrivateData std::unordered_map< int, KeyCounter > activeKeys; KeyTable keyTable[ ModeCount ]; + QskLinearBox* buttonsBox; QList< QskKeyButton* > keyButtons; bool isUIInitialized; }; @@ -670,24 +677,47 @@ bool QskInputPanel::eventFilter( QObject* object, QEvent* event ) } } +void QskInputPanel::updateLayout() +{ + if( m_data->buttonsBox == nullptr ) + return; // UI not initialized + + QMarginsF margins = marginsHint( Panel | QskAspect::Margin ); + QRectF rect = keyboardRect().marginsRemoved( margins ); + qreal verticalSpacing = m_data->buttonsBox->spacing(); + + for( QQuickItem* rowItem : m_data->buttonsBox->childItems() ) + { + QskLinearBox* rowBox = qobject_cast< QskLinearBox* >( rowItem ); + qreal horizontalSpacing = rowBox->spacing(); + + for( QQuickItem* keyItem : rowBox->childItems() ) + { + QskKeyButton* button = qobject_cast< QskKeyButton* >( keyItem ); + QRectF keyRect = keyDataAt( button->keyIndex() ).rect; + qreal width = keyRect.width() * rect.width() - horizontalSpacing; + qreal height = keyRect.height() * rect.height() - verticalSpacing; + + button->setFixedSize( width, height ); + } + } +} + void QskInputPanel::createUI() { + // ### no need to defer: // deferring the UI creation until we are visible so that the contentsRect() returns the proper value setAutoLayoutChildren( true ); auto& panelKeyData = keyData(); - const auto contentsRect = keyboardRect(); - const qreal sx = contentsRect.size().width(); - const qreal sy = contentsRect.size().height(); - - QskLinearBox* outterBox = new QskLinearBox( Qt::Vertical, this ); - outterBox->setAutoAddChildren( true ); + m_data->buttonsBox = new QskLinearBox( Qt::Vertical, this ); + m_data->buttonsBox->setAutoAddChildren( true ); for( const auto& keyRow : panelKeyData ) { - QskLinearBox* rowBox = new QskLinearBox( Qt::Horizontal, outterBox ); + QskLinearBox* rowBox = new QskLinearBox( Qt::Horizontal, m_data->buttonsBox ); rowBox->setAutoAddChildren( true ); for( const auto& keyData : keyRow ) @@ -697,15 +727,11 @@ void QskInputPanel::createUI() continue; } - const QSizeF buttonSize( keyData.rect.width() * sx, keyData.rect.height() * sy ); - int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData ); QskKeyButton* button = new QskKeyButton( keyIndex, this, rowBox ); button->installEventFilter( this ); - button->setMaximumWidth( buttonSize.width() ); // ### set min width as well? - button->setFixedHeight( buttonSize.height() ); m_data->keyButtons.append( button ); } } @@ -713,7 +739,7 @@ void QskInputPanel::createUI() void QskInputPanel::updateUI() { - for( QskKeyButton* button : m_data->keyButtons ) + for( QskKeyButton* button : qskAsConst( m_data->keyButtons ) ) { button->updateText(); } diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index d5fb7d35..a514bb1f 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -26,6 +26,8 @@ class QskKeyButton : public QskPushButton // ### rename to QskInputButton or so? virtual QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol subControl ) const override; + int keyIndex() const; + public Q_SLOTS: void updateText(); @@ -43,7 +45,7 @@ class QSK_EXPORT QskInputPanel : public QskControl Q_PROPERTY( QRectF keyboardRect READ keyboardRect NOTIFY keyboardRectChanged ) Q_PROPERTY( QString displayLanguageName READ displayLanguageName - NOTIFY displayLanguageNameChanged ) + NOTIFY displayLanguageNameChanged ) using Inherited = QskControl; @@ -123,6 +125,7 @@ protected: virtual void geometryChanged( const QRectF&, const QRectF& ) override; virtual void timerEvent( QTimerEvent* ) override; virtual bool eventFilter( QObject* object, QEvent* event ) override; + virtual void updateLayout() override; private: void createUI(); From fbdfb5aa198f83111806a126a2d8f5595db323a3 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Thu, 22 Mar 2018 18:30:15 +0100 Subject: [PATCH 10/21] create UI in constructor, no need to defer anymore --- src/controls/QskInputPanel.cpp | 72 ++++++++++++++-------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index cea57709..47e5f710 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -263,6 +263,34 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): setFlag( ItemIsFocusScope, true ); setTabFence( true ); + + setAutoLayoutChildren( true ); + + auto& panelKeyData = keyData(); + + m_data->buttonsBox = new QskLinearBox( Qt::Vertical, this ); + m_data->buttonsBox->setAutoAddChildren( true ); + + for( const auto& keyRow : panelKeyData ) + { + QskLinearBox* rowBox = new QskLinearBox( Qt::Horizontal, m_data->buttonsBox ); + rowBox->setAutoAddChildren( true ); + + for( const auto& keyData : keyRow ) + { + if( !keyData.key ) + { + continue; + } + + int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData ); + QskKeyButton* button = new QskKeyButton( keyIndex, this, rowBox ); + + button->installEventFilter( this ); + + m_data->keyButtons.append( button ); + } + } } QskInputPanel::~QskInputPanel() @@ -614,12 +642,6 @@ void QskInputPanel::geometryChanged( { Inherited::geometryChanged( newGeometry, oldGeometry ); - if( newGeometry != oldGeometry && !newGeometry.size().isNull() && !m_data->isUIInitialized ) - { - createUI(); - m_data->isUIInitialized = true; - } - Q_EMIT keyboardRectChanged(); } @@ -679,8 +701,8 @@ bool QskInputPanel::eventFilter( QObject* object, QEvent* event ) void QskInputPanel::updateLayout() { - if( m_data->buttonsBox == nullptr ) - return; // UI not initialized + if( geometry().isNull() ) + return; // no need to calculate anything, will be called again QMarginsF margins = marginsHint( Panel | QskAspect::Margin ); QRectF rect = keyboardRect().marginsRemoved( margins ); @@ -703,40 +725,6 @@ void QskInputPanel::updateLayout() } } -void QskInputPanel::createUI() -{ - // ### no need to defer: - // deferring the UI creation until we are visible so that the contentsRect() returns the proper value - - setAutoLayoutChildren( true ); - - auto& panelKeyData = keyData(); - - m_data->buttonsBox = new QskLinearBox( Qt::Vertical, this ); - m_data->buttonsBox->setAutoAddChildren( true ); - - for( const auto& keyRow : panelKeyData ) - { - QskLinearBox* rowBox = new QskLinearBox( Qt::Horizontal, m_data->buttonsBox ); - rowBox->setAutoAddChildren( true ); - - for( const auto& keyData : keyRow ) - { - if( !keyData.key ) - { - continue; - } - - int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData ); - QskKeyButton* button = new QskKeyButton( keyIndex, this, rowBox ); - - button->installEventFilter( this ); - - m_data->keyButtons.append( button ); - } - } -} - void QskInputPanel::updateUI() { for( QskKeyButton* button : qskAsConst( m_data->keyButtons ) ) From 02da3993f214a688c3171050c716bdabc0a86857 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 23 Mar 2018 07:59:26 +0100 Subject: [PATCH 11/21] keyboard: make font size grow --- src/controls/QskInputPanel.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 47e5f710..092ad7e2 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -150,6 +151,10 @@ QskKeyButton::QskKeyButton( int keyIndex, QskInputPanel* inputPanel, QQuickItem* m_keyIndex( keyIndex ), m_inputPanel( inputPanel ) { + QskTextOptions options; + options.setFontSizeMode( QskTextOptions::VerticalFit ); + setTextOptions( options ); + updateText(); connect( this, &QskKeyButton::pressed, this, [ this ]() From 412267cf9aebd9c8d5f9cc21a386e710bff59976 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 26 Mar 2018 10:05:44 +0200 Subject: [PATCH 12/21] keyboard: Make auto repeat work --- src/controls/QskInputPanel.cpp | 54 ++++++++++++---------------------- src/controls/QskInputPanel.h | 1 - 2 files changed, 18 insertions(+), 37 deletions(-) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 092ad7e2..241b1373 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -131,6 +131,14 @@ static qreal qskRowStretch( const QskInputPanel::KeyRow& keyRow ) return stretch; } +static bool qskIsAutorepeat( Qt::Key key ) +{ + return ( key != Qt::Key_Return && key != Qt::Key_Enter + && key != Qt::Key_Shift && key!= Qt::Key_CapsLock + && key != Qt::Key_Mode_switch ); + +} + namespace { struct KeyCounter @@ -155,6 +163,16 @@ QskKeyButton::QskKeyButton( int keyIndex, QskInputPanel* inputPanel, QQuickItem* options.setFontSizeMode( QskTextOptions::VerticalFit ); setTextOptions( options ); + auto keyData = m_inputPanel->keyDataAt( m_keyIndex ); + const auto key = keyData.key & ~KeyStates; + + if ( qskIsAutorepeat( key ) ) + { + setAutoRepeat( true ); + setAutoRepeatDelay( 500 ); + setAutoRepeatInterval( 1000 / QGuiApplication::styleHints()->keyboardAutoRepeatRate() ); + } + updateText(); connect( this, &QskKeyButton::pressed, this, [ this ]() @@ -216,7 +234,6 @@ class QskInputPanel::PrivateData focusKeyIndex( -1 ), selectedGroup( -1 ), candidateOffset( 0 ), - repeatKeyTimerId( -1 ), buttonsBox( nullptr ), isUIInitialized( false ) { @@ -230,8 +247,6 @@ class QskInputPanel::PrivateData qint16 selectedGroup; qint32 candidateOffset; - int repeatKeyTimerId; - QLocale locale; QVector< Qt::Key > groups; @@ -650,39 +665,6 @@ void QskInputPanel::geometryChanged( Q_EMIT keyboardRectChanged(); } -void QskInputPanel::timerEvent( QTimerEvent* e ) -{ - if( e->timerId() == m_data->repeatKeyTimerId ) - { - for( auto it = m_data->activeKeys.begin(); it != m_data->activeKeys.end(); ) - { - if( it->second.count >= 0 && it->second.count++ > 20 ) // ### use platform long-press hint - { - const auto key = keyDataAt( it->second.keyIndex ).key & ~KeyStates; - - if( !key || key == Qt::Key_unknown ) - { - it = m_data->activeKeys.erase( it ); - continue; - } - - if( key == Qt::Key_ApplicationLeft || key == Qt::Key_ApplicationRight ) - { - setCandidateOffset( m_data->candidateOffset - + ( key == Qt::Key_ApplicationLeft ? -1 : 1 ) ); - } - else if( !( key & KeyLocked ) ) // do not repeat locked keys - { - // long press events could be emitted from here - compose( key & ~KeyStates ); - } - } - - ++it; - } - } -} - bool QskInputPanel::eventFilter( QObject* object, QEvent* event ) { if( event->type() == QEvent::InputMethod ) diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index a514bb1f..4fc648cc 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -123,7 +123,6 @@ public Q_SLOTS: protected: virtual void geometryChanged( const QRectF&, const QRectF& ) override; - virtual void timerEvent( QTimerEvent* ) override; virtual bool eventFilter( QObject* object, QEvent* event ) override; virtual void updateLayout() override; From ddea04445ccc0175484c5ee434b1edad83305e7a Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Mon, 26 Mar 2018 15:48:03 +0200 Subject: [PATCH 13/21] keyboard: Fix focusing / tab key --- inputcontext/QskInputContext.cpp | 59 ++------------- inputcontext/QskInputContext.h | 3 - src/controls/QskInputPanel.cpp | 120 +------------------------------ src/controls/QskInputPanel.h | 5 -- 4 files changed, 10 insertions(+), 177 deletions(-) diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index a95259eb..9d8ba5a5 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -208,9 +208,6 @@ QLocale QskInputContext::locale() const void QskInputContext::setFocusObject( QObject* focusObject ) { - if ( m_focusObject ) - m_focusObject->removeEventFilter( this ); - m_focusObject = focusObject; if ( !m_focusObject ) { @@ -229,8 +226,15 @@ void QskInputContext::setFocusObject( QObject* focusObject ) { m_inputItem = focusQuickItem; m_inputCompositionModel->setInputItem( m_inputItem ); // ### use a signal/slot connection + if( m_inputPanel ) + m_inputPanel->setTabFence( false ); inputItemChanged = true; } + else + { + if( m_inputPanel ) + m_inputPanel->setTabFence( true ); + } } if( inputItemChanged ) @@ -246,58 +250,9 @@ void QskInputContext::setFocusObject( QObject* focusObject ) } } - m_focusObject->installEventFilter( this ); update( Qt::InputMethodQuery( Qt::ImQueryAll & ~Qt::ImEnabled ) ); } -bool QskInputContext::eventFilter( QObject* object, QEvent* event ) -{ - if ( m_inputPanel && event->type() == QEvent::KeyPress ) - { - auto keyEvent = static_cast< QKeyEvent* >( event ); - const auto key = keyEvent->key(); - switch ( key ) - { - case Qt::Key_Tab: - case Qt::Key_Backtab: - if ( m_inputPanel->advanceFocus( key == Qt::Key_Tab ) ) - { - keyEvent->accept(); - return true; - } - break; - case Qt::Key_Select: - case Qt::Key_Space: - // if there is a focused key, treat the key like a push button - if ( m_inputPanel->activateFocusKey() ) - { - keyEvent->accept(); - return true; - } - break; - } - } - - if ( m_inputPanel && event->type() == QEvent::KeyRelease ) - { - auto keyEvent = static_cast< QKeyEvent* >( event ); - const auto key = keyEvent->key(); - switch ( key ) - { - case Qt::Key_Select: - case Qt::Key_Space: - if ( m_inputPanel->deactivateFocusKey() ) - { - keyEvent->accept(); - return true; - } - break; - } - } - - return Inherited::eventFilter( object, event ); -} - void QskInputContext::invokeAction( QInputMethod::Action action, int cursorPosition ) { Q_UNUSED(cursorPosition); diff --git a/inputcontext/QskInputContext.h b/inputcontext/QskInputContext.h index 85a852eb..b7694bfb 100644 --- a/inputcontext/QskInputContext.h +++ b/inputcontext/QskInputContext.h @@ -36,9 +36,6 @@ public: QLocale locale() const override; void setFocusObject( QObject* ) override; -protected: - bool eventFilter( QObject*, QEvent* ) override; - private Q_SLOTS: void emitAnimatingChanged(); void handleCandidatesChanged(); diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 241b1373..633f687f 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -81,9 +80,7 @@ static constexpr const QskInputPanelLayouts qskInputPanelLayouts = QSK_DECLARE_OPERATORS_FOR_FLAGS( Qt::Key ) // Must appear after the LOWER macro -static const Qt::Key KeyPressed = static_cast< Qt::Key >( Qt::ShiftModifier ); static const Qt::Key KeyLocked = static_cast< Qt::Key >( Qt::ControlModifier ); -static const Qt::Key KeyFocused = static_cast< Qt::Key >( Qt::MetaModifier ); static const Qt::Key KeyStates = static_cast< Qt::Key >( Qt::KeyboardModifierMask ); static qreal qskKeyStretch( Qt::Key key ) @@ -231,7 +228,6 @@ class QskInputPanel::PrivateData PrivateData(): currentLayout( nullptr ), mode( QskInputPanel::LowercaseMode ), - focusKeyIndex( -1 ), selectedGroup( -1 ), candidateOffset( 0 ), buttonsBox( nullptr ), @@ -243,7 +239,6 @@ class QskInputPanel::PrivateData const QskInputPanelLayouts::Layout* currentLayout; QskInputPanel::Mode mode; - qint16 focusKeyIndex; qint16 selectedGroup; qint32 candidateOffset; @@ -282,7 +277,9 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): this, &QskInputPanel::updateLocale ); setFlag( ItemIsFocusScope, true ); - setTabFence( true ); + + // ### for some reason we never get focus when this is a tab fence: +// setTabFence( true ); setAutoLayoutChildren( true ); @@ -306,8 +303,6 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData ); QskKeyButton* button = new QskKeyButton( keyIndex, this, rowBox ); - button->installEventFilter( this ); - m_data->keyButtons.append( button ); } } @@ -512,94 +507,6 @@ void QskInputPanel::setPreeditCandidates( const QVector< Qt::Key >& candidates ) setCandidateOffset( 0 ); } -bool QskInputPanel::advanceFocus( bool forward ) -{ - deactivateFocusKey(); - auto offset = forward ? 1 : -1; - - auto focusKeyIndex = m_data->focusKeyIndex; - - Q_FOREVER - { - focusKeyIndex += offset; - - if( focusKeyIndex < 0 || focusKeyIndex >= RowCount * KeyCount ) - { - clearFocusKey(); - return false; - } - - const auto key = keyDataAt( focusKeyIndex ).key; - - if( key && key != Qt::Key_unknown ) - { - break; - } - } - - if( m_data->focusKeyIndex >= 0 ) - { - keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused; - } - - m_data->focusKeyIndex = focusKeyIndex; - keyDataAt( m_data->focusKeyIndex ).key |= KeyFocused; - update(); - return true; -} - -bool QskInputPanel::activateFocusKey() -{ - if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) - { - auto& keyData = keyDataAt( m_data->focusKeyIndex ); - - if( keyData.key & KeyPressed ) - { - handleKey( m_data->focusKeyIndex ); - } - else - { - keyData.key |= KeyPressed; - } - - update(); - return true; - } - - return false; -} - -bool QskInputPanel::deactivateFocusKey() -{ - if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) - { - auto& keyData = keyDataAt( m_data->focusKeyIndex ); - - if( keyData.key & KeyPressed ) - { - keyData.key &= ~KeyPressed; - handleKey( m_data->focusKeyIndex ); - } - - update(); - return true; - } - - return true; -} - -void QskInputPanel::clearFocusKey() -{ - if( m_data->focusKeyIndex > 0 && m_data->focusKeyIndex < RowCount * KeyCount ) - { - keyDataAt( m_data->focusKeyIndex ).key &= ~KeyFocused; - update(); - } - - m_data->focusKeyIndex = -1; -} - void QskInputPanel::setCandidateOffset( int candidateOffset ) { m_data->candidateOffset = candidateOffset; @@ -665,27 +572,6 @@ void QskInputPanel::geometryChanged( Q_EMIT keyboardRectChanged(); } -bool QskInputPanel::eventFilter( QObject* object, QEvent* event ) -{ - if( event->type() == QEvent::InputMethod ) - { - QInputMethodEvent* inputMethodEvent = static_cast< QInputMethodEvent* >( event ); - Q_EMIT inputMethodEventReceived( inputMethodEvent ); - return true; - } - else if( event->type() == QEvent::KeyPress ) - { - // Return, Backspace and others are covered here (maybe because they don't carry a 'commit string'): - QKeyEvent* keyEvent = static_cast< QKeyEvent* >( event ); - Q_EMIT keyEventReceived( keyEvent ); - return true; - } - else - { - return Inherited::eventFilter( object, event ); - } -} - void QskInputPanel::updateLayout() { if( geometry().isNull() ) diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index 4fc648cc..35435e52 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -112,10 +112,6 @@ public: public Q_SLOTS: void setPreeditGroups( const QVector< Qt::Key >& ); void setPreeditCandidates( const QVector< Qt::Key >& ); - bool advanceFocus( bool = true ); - bool activateFocusKey(); - bool deactivateFocusKey(); - void clearFocusKey(); void handleKey( int keyIndex ); KeyData& keyDataAt( int ) const; @@ -123,7 +119,6 @@ public Q_SLOTS: protected: virtual void geometryChanged( const QRectF&, const QRectF& ) override; - virtual bool eventFilter( QObject* object, QEvent* event ) override; virtual void updateLayout() override; private: From 60c16c82c82744767e78d54192c83d57ff3bccdd Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Tue, 27 Mar 2018 19:00:43 +0200 Subject: [PATCH 14/21] keyboard: Make key buttons work Not sure whether this is the right way... --- inputcontext/QskInputCompositionModel.cpp | 3 +++ src/controls/QskInputPanel.cpp | 2 ++ 2 files changed, 5 insertions(+) diff --git a/inputcontext/QskInputCompositionModel.cpp b/inputcontext/QskInputCompositionModel.cpp index eed9c1bb..4eb112e8 100644 --- a/inputcontext/QskInputCompositionModel.cpp +++ b/inputcontext/QskInputCompositionModel.cpp @@ -258,8 +258,11 @@ void QskInputCompositionModel::moveCursor( Qt::Key key ) if ( !m_data->preedit.isEmpty() ) return; + // ### this should be in the panel: QKeyEvent moveCursorPress( QEvent::KeyPress, key, Qt::NoModifier ); QKeyEvent moveCursorRelease( QEvent::KeyRelease, key, Qt::NoModifier ); + QFocusEvent focusIn( QEvent::FocusIn ); // hack to display the cursor + QCoreApplication::sendEvent( m_data->inputItem, &focusIn ); QCoreApplication::sendEvent( m_data->inputItem, &moveCursorPress ); QCoreApplication::sendEvent( m_data->inputItem, &moveCursorRelease ); } diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 633f687f..49aff391 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -160,6 +160,8 @@ QskKeyButton::QskKeyButton( int keyIndex, QskInputPanel* inputPanel, QQuickItem* options.setFontSizeMode( QskTextOptions::VerticalFit ); setTextOptions( options ); + setFocusPolicy( Qt::TabFocus ); + auto keyData = m_inputPanel->keyDataAt( m_keyIndex ); const auto key = keyData.key & ~KeyStates; From ee5cffdc79b4c42cd3e1269864a68f46bd3a221a Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 28 Mar 2018 10:26:33 +0200 Subject: [PATCH 15/21] keyboard: Fix special characters mode --- src/controls/QskInputPanel.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 49aff391..d123a88b 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -207,12 +207,13 @@ void QskKeyButton::updateText() { QString text = m_inputPanel->currentTextForKeyIndex( m_keyIndex ); - if( text.count() == 1 && text.at( 0 ) == Qt::Key_unknown ) + if( text.count() == 1 && text.at( 0 ) == QChar( 0 ) ) { - setText( QStringLiteral( "" ) ); + setVisible( false ); } else { + setVisible( true ); setText( text ); } } @@ -304,10 +305,15 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): int keyIndex = m_data->keyTable[ m_data->mode ].indexOf( &keyData ); QskKeyButton* button = new QskKeyButton( keyIndex, this, rowBox ); + rowBox->setRetainSizeWhenHidden( button, true ); m_data->keyButtons.append( button ); } } + + connect( this, &QskInputPanel::modeChanged, this, [ this ]() { + updateLayout(); + }); } QskInputPanel::~QskInputPanel() From 745adf463eb5a0eec7d98900eed93aeec7941280 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 28 Mar 2018 11:46:31 +0200 Subject: [PATCH 16/21] keyboard: Store ints rather than Qt::Keys --- src/controls/QskInputPanel.cpp | 13 +++++++------ src/controls/QskInputPanel.h | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index d123a88b..7e286d8c 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -80,8 +80,8 @@ static constexpr const QskInputPanelLayouts qskInputPanelLayouts = QSK_DECLARE_OPERATORS_FOR_FLAGS( Qt::Key ) // Must appear after the LOWER macro -static const Qt::Key KeyLocked = static_cast< Qt::Key >( Qt::ControlModifier ); -static const Qt::Key KeyStates = static_cast< Qt::Key >( Qt::KeyboardModifierMask ); +static const int KeyLocked = static_cast< int >( Qt::ControlModifier ); +static const int KeyStates = static_cast< int >( Qt::KeyboardModifierMask ); static qreal qskKeyStretch( Qt::Key key ) { @@ -128,7 +128,7 @@ static qreal qskRowStretch( const QskInputPanel::KeyRow& keyRow ) return stretch; } -static bool qskIsAutorepeat( Qt::Key key ) +static bool qskIsAutorepeat( int key ) { return ( key != Qt::Key_Return && key != Qt::Key_Enter && key != Qt::Key_Shift && key!= Qt::Key_CapsLock @@ -344,7 +344,7 @@ const QskInputPanel::KeyDataSet& QskInputPanel::keyData( Mode mode ) const return m_data->keyTable[ mode ].data; } -QString QskInputPanel::textForKey( Qt::Key key ) const +QString QskInputPanel::textForKey( int key ) const { key &= ~KeyStates; @@ -703,7 +703,7 @@ QString QskInputPanel::currentTextForKeyIndex( int keyIndex ) const return text; } -void QskInputPanel::compose( Qt::Key key ) +void QskInputPanel::compose( int key ) { QGuiApplication::inputMethod()->invokeAction( static_cast< QInputMethod::Action >( Compose ), key ); @@ -715,7 +715,8 @@ void QskInputPanel::selectGroup( int index ) if( m_data->selectedGroup >= 0 ) { - topRow[ m_data->selectedGroup ].key &= ~KeyLocked; + auto group = static_cast< int >( m_data->selectedGroup ); + topRow[ group ].key &= ~KeyLocked; } if( m_data->selectedGroup == index ) diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index 35435e52..820071e8 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -55,7 +55,7 @@ public: struct KeyData { - Qt::Key key = Qt::Key( 0 ); + int key = 0; bool isSuggestionKey = false; QRectF rect; }; @@ -100,7 +100,7 @@ public: const KeyDataSet& keyData( QskInputPanel::Mode = CurrentMode ) const; - QString textForKey( Qt::Key ) const; + QString textForKey( int ) const; QString displayLanguageName() const; QRectF keyboardRect() const; @@ -125,7 +125,7 @@ private: void createUI(); void updateUI(); // e.g. called when updating Pinyin suggestions - void compose( Qt::Key ); + void compose( int ); void selectGroup( int ); void selectCandidate( int ); void setCandidateOffset( int ); From 2951523aaf09bdbf810f72f70b998698d9b9d68e Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 28 Mar 2018 14:01:26 +0200 Subject: [PATCH 17/21] Don't use a tab fence --- inputcontext/QskInputContext.cpp | 7 ------- src/controls/QskInputPanel.cpp | 5 +++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/inputcontext/QskInputContext.cpp b/inputcontext/QskInputContext.cpp index 9d8ba5a5..c516740b 100644 --- a/inputcontext/QskInputContext.cpp +++ b/inputcontext/QskInputContext.cpp @@ -226,15 +226,8 @@ void QskInputContext::setFocusObject( QObject* focusObject ) { m_inputItem = focusQuickItem; m_inputCompositionModel->setInputItem( m_inputItem ); // ### use a signal/slot connection - if( m_inputPanel ) - m_inputPanel->setTabFence( false ); inputItemChanged = true; } - else - { - if( m_inputPanel ) - m_inputPanel->setTabFence( true ); - } } if( inputItemChanged ) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 7e286d8c..13891342 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -281,8 +281,9 @@ QskInputPanel::QskInputPanel( QQuickItem* parent ): setFlag( ItemIsFocusScope, true ); - // ### for some reason we never get focus when this is a tab fence: -// setTabFence( true ); +#if 0 + setTabFence( true ); +#endif setAutoLayoutChildren( true ); From 3d584beee2e087dbe23e39d1ecc79bd17782af92 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 28 Mar 2018 14:42:05 +0200 Subject: [PATCH 18/21] keyboard: Highlight hacks --- inputcontext/QskInputCompositionModel.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inputcontext/QskInputCompositionModel.cpp b/inputcontext/QskInputCompositionModel.cpp index 4eb112e8..3a9b8961 100644 --- a/inputcontext/QskInputCompositionModel.cpp +++ b/inputcontext/QskInputCompositionModel.cpp @@ -261,7 +261,9 @@ void QskInputCompositionModel::moveCursor( Qt::Key key ) // ### this should be in the panel: QKeyEvent moveCursorPress( QEvent::KeyPress, key, Qt::NoModifier ); QKeyEvent moveCursorRelease( QEvent::KeyRelease, key, Qt::NoModifier ); +#if 1 QFocusEvent focusIn( QEvent::FocusIn ); // hack to display the cursor +#endif QCoreApplication::sendEvent( m_data->inputItem, &focusIn ); QCoreApplication::sendEvent( m_data->inputItem, &moveCursorPress ); QCoreApplication::sendEvent( m_data->inputItem, &moveCursorRelease ); From c1945a00ecec012235b31b4535430466a8044f1f Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 28 Mar 2018 15:06:00 +0200 Subject: [PATCH 19/21] keyboard skins: remove commented lines --- skins/material/QskMaterialSkin.cpp | 9 +-------- skins/squiek/QskSquiekSkin.cpp | 16 ---------------- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/skins/material/QskMaterialSkin.cpp b/skins/material/QskMaterialSkin.cpp index fe2df2ea..aac89c7e 100644 --- a/skins/material/QskMaterialSkin.cpp +++ b/skins/material/QskMaterialSkin.cpp @@ -526,7 +526,7 @@ void QskMaterialSkin::initInputPanelHints() const ColorPalette& pal = m_data->palette; // key panel -// setMargins( Q::KeyPanel | Margin, 2 ); + setMargins( QskInputPanel::Panel | Margin, 2 ); setBoxShape( Q::Panel, 20.0, Qt::RelativeSize ); setBoxBorderMetrics( Q::Panel, 2 ); @@ -540,13 +540,6 @@ void QskMaterialSkin::initInputPanelHints() setAnimation( Q::Panel | Color, qskDuration ); setAnimation( Q::Panel | Metric, qskDuration ); - // glyph -// setSkinHint( Q::KeyGlyph | Alignment, Qt::AlignCenter ); -// setFontRole( Q::KeyGlyph, QskSkin::TinyFont ); - -// setColor( Q::KeyGlyph, pal.textColor ); -// setColor( Q::KeyGlyph | Q::Disabled, pal.darker200 ); - // panel setBoxShape( Q::Panel, 0 ); setBoxBorderMetrics( Q::Panel, 0 ); diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 81fd27cc..2effd19d 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -566,25 +566,9 @@ void QskSquiekSkin::initInputPanelHints() setButton( Q::Panel | Q::Pressed, Sunken ); setAnimation( Q::Panel | Color, qskDuration ); -#if 0 - // crashes because animations are started from updateNode - // TODO ... - - setAnimation( Q::Panel | Metric, qskDuration ); -#endif - - // glyph -// setSkinHint( Q::Text | Alignment, Qt::AlignCenter ); -// setFontRole( Q::Text, QskSkin::TinyFont ); setColor( Q::Text, pal.themeForeground ); setColor( Q::Text | Q::Disabled, pal.darker200 ); - -// // panel - -// setMargins( Q::Panel | Padding, 5 ); -// setMargins( Q::Panel | Spacing, 5 ); -// setPanel( Q::Panel, Raised ); } void QskSquiekSkin::initScrollViewHints() From 7af9cc6cdff263fbba844b1dff6f3a3a5681ae63 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 28 Mar 2018 15:31:44 +0200 Subject: [PATCH 20/21] input panel: derive from QskBox --- src/controls/QskInputPanel.cpp | 4 ++-- src/controls/QskInputPanel.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 13891342..75afeae9 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -259,7 +259,7 @@ class QskInputPanel::PrivateData }; QskInputPanel::QskInputPanel( QQuickItem* parent ): - QskControl( parent ), + Inherited( parent ), m_data( new PrivateData ) { qRegisterMetaType< Qt::Key >(); @@ -324,7 +324,7 @@ QskInputPanel::~QskInputPanel() QskAspect::Subcontrol QskInputPanel::effectiveSubcontrol( QskAspect::Subcontrol subControl ) const { - if( subControl == QskAspect::Control ) + if( subControl == QskBox::Panel ) { return QskInputPanel::Panel; } diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index 820071e8..8b17bb8d 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -6,7 +6,7 @@ #ifndef QSK_INPUT_PANEL_H #define QSK_INPUT_PANEL_H -#include "QskControl.h" +#include "QskBox.h" #include "QskPushButton.h" #include @@ -38,7 +38,7 @@ class QskKeyButton : public QskPushButton // ### rename to QskInputButton or so? QskInputPanel* m_inputPanel; }; -class QSK_EXPORT QskInputPanel : public QskControl +class QSK_EXPORT QskInputPanel : public QskBox { Q_OBJECT @@ -47,7 +47,7 @@ class QSK_EXPORT QskInputPanel : public QskControl Q_PROPERTY( QString displayLanguageName READ displayLanguageName NOTIFY displayLanguageNameChanged ) - using Inherited = QskControl; + using Inherited = QskBox; public: From b68fc92cc9739bb920206faa6cf1053ac5138ff3 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 28 Mar 2018 15:49:45 +0200 Subject: [PATCH 21/21] keyboard: fix layout calculation --- skins/squiek/QskSquiekSkin.cpp | 4 ++-- src/controls/QskInputPanel.cpp | 23 ++++++++--------------- src/controls/QskInputPanel.h | 2 -- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/skins/squiek/QskSquiekSkin.cpp b/skins/squiek/QskSquiekSkin.cpp index 2effd19d..ed700ba2 100644 --- a/skins/squiek/QskSquiekSkin.cpp +++ b/skins/squiek/QskSquiekSkin.cpp @@ -559,8 +559,8 @@ void QskSquiekSkin::initInputPanelHints() const ColorPalette& pal = m_data->palette; // key panel - setMargins( QskInputPanel::Panel | Margin, 2 ); - setButton( QskInputPanel::Panel, Raised ); + setMargins( QskInputPanel::Panel | Padding, 5 ); + setPanel( QskInputPanel::Panel, Raised ); setButton( Q::Panel, Raised ); setButton( Q::Panel | Q::Pressed, Sunken ); diff --git a/src/controls/QskInputPanel.cpp b/src/controls/QskInputPanel.cpp index 75afeae9..99c55199 100644 --- a/src/controls/QskInputPanel.cpp +++ b/src/controls/QskInputPanel.cpp @@ -559,14 +559,6 @@ void QskInputPanel::setCandidateOffset( int candidateOffset ) } } -QRectF QskInputPanel::keyboardRect() const -{ - auto keyboardRect = rect(); // ### margins? would eliminate this thing below - // if ( QskDialog::instance()->policy() != QskDialog::TopLevelWindow ) - // keyboardRect.adjust( 0, keyboardRect.height() * 0.5, 0, 0 ); - return keyboardRect; -} - void QskInputPanel::registerCompositionModelForLocale( const QLocale& locale, QskInputCompositionModel* model ) { @@ -586,18 +578,19 @@ void QskInputPanel::updateLayout() if( geometry().isNull() ) return; // no need to calculate anything, will be called again - QMarginsF margins = marginsHint( Panel | QskAspect::Margin ); - QRectF rect = keyboardRect().marginsRemoved( margins ); + QRectF rect = layoutRect(); qreal verticalSpacing = m_data->buttonsBox->spacing(); - for( QQuickItem* rowItem : m_data->buttonsBox->childItems() ) + const auto& children = m_data->buttonsBox->childItems(); + for( auto rowItem : children ) { - QskLinearBox* rowBox = qobject_cast< QskLinearBox* >( rowItem ); - qreal horizontalSpacing = rowBox->spacing(); + auto rowBox = qobject_cast< QskLinearBox* >( rowItem ); + const qreal horizontalSpacing = rowBox->spacing(); - for( QQuickItem* keyItem : rowBox->childItems() ) + const auto& rowChildren = rowBox->childItems(); + for( auto keyItem : rowChildren ) { - QskKeyButton* button = qobject_cast< QskKeyButton* >( keyItem ); + auto button = qobject_cast< QskKeyButton* >( keyItem ); QRectF keyRect = keyDataAt( button->keyIndex() ).rect; qreal width = keyRect.width() * rect.width() - horizontalSpacing; qreal height = keyRect.height() * rect.height() - verticalSpacing; diff --git a/src/controls/QskInputPanel.h b/src/controls/QskInputPanel.h index 8b17bb8d..16a5fa75 100644 --- a/src/controls/QskInputPanel.h +++ b/src/controls/QskInputPanel.h @@ -42,8 +42,6 @@ class QSK_EXPORT QskInputPanel : public QskBox { Q_OBJECT - Q_PROPERTY( QRectF keyboardRect READ keyboardRect NOTIFY keyboardRectChanged ) - Q_PROPERTY( QString displayLanguageName READ displayLanguageName NOTIFY displayLanguageNameChanged )