From 2e3834acf93b6526ffa74bf59db8b6b1d14a5e0b Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Wed, 14 Mar 2018 17:30:35 +0100 Subject: [PATCH] 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;