Merge branch 'peter-ha-qsktextinput'
This commit is contained in:
commit
63795d21b0
|
@ -37,26 +37,26 @@ 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 )
|
||||
{
|
||||
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 ) );
|
||||
}
|
||||
|
@ -71,13 +71,12 @@ void QskInputCompositionModel::composeKey( Qt::Key key )
|
|||
if ( !inputMethod )
|
||||
return;
|
||||
|
||||
auto focusObject = QGuiApplication::focusObject();
|
||||
if ( !focusObject )
|
||||
if ( !m_data->inputItem )
|
||||
return;
|
||||
|
||||
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();
|
||||
|
@ -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() )
|
||||
|
@ -237,8 +235,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;
|
||||
}
|
||||
|
||||
|
@ -253,18 +251,28 @@ 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.
|
||||
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 );
|
||||
QCoreApplication::sendEvent( focusWindow, &moveCursorPress );
|
||||
QCoreApplication::sendEvent( focusWindow, &moveCursorRelease );
|
||||
#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 );
|
||||
}
|
||||
|
||||
void QskInputCompositionModel::sendCompositionEvent( QInputMethodEvent* e )
|
||||
{
|
||||
if ( m_data->inputItem )
|
||||
QCoreApplication::sendEvent( m_data->inputItem, e );
|
||||
}
|
||||
|
||||
bool QskInputCompositionModel::hasIntermediate() const
|
||||
|
@ -300,6 +308,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);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <memory>
|
||||
|
||||
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;
|
||||
|
|
|
@ -21,11 +21,15 @@
|
|||
#include <QRectF>
|
||||
|
||||
QskInputContext::QskInputContext():
|
||||
Inherited()
|
||||
Inherited(),
|
||||
m_inputCompositionModel( new QskInputCompositionModel )
|
||||
{
|
||||
connect( qskSetup, &QskSetup::inputPanelChanged,
|
||||
this, &QskInputContext::setInputPanel );
|
||||
setInputPanel( qskSetup->inputPanel() );
|
||||
|
||||
// We could connect candidatesChanged() here, but we don't emit
|
||||
// the signal in the normal composition model anyhow
|
||||
}
|
||||
|
||||
QskInputContext::~QskInputContext()
|
||||
|
@ -41,11 +45,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
|
||||
|
@ -204,75 +208,44 @@ QLocale QskInputContext::locale() const
|
|||
|
||||
void QskInputContext::setFocusObject( QObject* focusObject )
|
||||
{
|
||||
if ( m_focusObject )
|
||||
m_focusObject->removeEventFilter( this );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
m_focusObject->installEventFilter( this );
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <qpa/qplatforminputcontext.h>
|
||||
#include <QPointer>
|
||||
#include <QQuickItem>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -22,7 +23,7 @@ class QskInputContext : public QPlatformInputContext
|
|||
|
||||
public:
|
||||
QskInputContext();
|
||||
~QskInputContext();
|
||||
~QskInputContext() override;
|
||||
|
||||
bool isValid() const override;
|
||||
void update( Qt::InputMethodQueries ) override;
|
||||
|
@ -35,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();
|
||||
|
@ -45,6 +43,7 @@ private Q_SLOTS:
|
|||
|
||||
private:
|
||||
QPointer< QObject > m_focusObject;
|
||||
QPointer< QQuickItem > m_inputItem;
|
||||
QPointer< QskInputPanel > m_inputPanel;
|
||||
std::unique_ptr< QskInputCompositionModel > m_inputCompositionModel;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
#include "TextInput.h"
|
||||
|
||||
TextInput::TextInput( QQuickItem* parent )
|
||||
: QQuickTextInput( parent )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
TextInput::~TextInput()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TextInput::inputMethodEvent(QInputMethodEvent *event)
|
||||
{
|
||||
QQuickTextInput::inputMethodEvent(event);
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef TEXTINPUT_H
|
||||
#define TEXTINPUT_H
|
||||
|
||||
#include <private/qquicktextinput_p.h>
|
||||
|
||||
class TextInput : public QQuickTextInput
|
||||
{
|
||||
public:
|
||||
TextInput( QQuickItem* parent );
|
||||
virtual ~TextInput() override;
|
||||
|
||||
protected:
|
||||
void inputMethodEvent(QInputMethodEvent *) Q_DECL_OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // TEXTINPUT_H
|
|
@ -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
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* This file may be used under the terms of the 3-clause BSD License
|
||||
*****************************************************************************/
|
||||
|
||||
#include "TextInput.h"
|
||||
|
||||
#include <SkinnyFont.h>
|
||||
#include <SkinnyShortcut.h>
|
||||
|
||||
|
@ -21,8 +23,6 @@
|
|||
#include <QGuiApplication>
|
||||
#include <QFontMetricsF>
|
||||
|
||||
#include <private/qquicktextinput_p.h>
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define STRING(x) STRINGIFY(x)
|
||||
|
||||
|
|
|
@ -521,31 +521,24 @@ 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( QskInputPanel::Panel | 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 );
|
||||
|
||||
// glyph
|
||||
setSkinHint( Q::KeyGlyph | Alignment, Qt::AlignCenter );
|
||||
setFontRole( Q::KeyGlyph, QskSkin::TinyFont );
|
||||
|
||||
setColor( Q::KeyGlyph, pal.textColor );
|
||||
setColor( Q::KeyGlyph | Q::Disabled, pal.darker200 );
|
||||
setAnimation( Q::Panel | Color, qskDuration );
|
||||
setAnimation( Q::Panel | Metric, qskDuration );
|
||||
|
||||
// panel
|
||||
setBoxShape( Q::Panel, 0 );
|
||||
|
|
|
@ -554,36 +554,21 @@ 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( QskInputPanel::Panel | Padding, 5 );
|
||||
setPanel( QskInputPanel::Panel, Raised );
|
||||
|
||||
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 );
|
||||
#if 0
|
||||
// crashes because animations are started from updateNode
|
||||
// TODO ...
|
||||
setAnimation( Q::Panel | Color, qskDuration );
|
||||
|
||||
setAnimation( Q::KeyPanel | Metric, qskDuration );
|
||||
#endif
|
||||
|
||||
// glyph
|
||||
setSkinHint( Q::KeyGlyph | Alignment, Qt::AlignCenter );
|
||||
setFontRole( Q::KeyGlyph, QskSkin::TinyFont );
|
||||
|
||||
setColor( Q::KeyGlyph, pal.themeForeground );
|
||||
setColor( Q::KeyGlyph | Q::Disabled, pal.darker200 );
|
||||
|
||||
// panel
|
||||
|
||||
setMargins( Q::Panel | Padding, 5 );
|
||||
setMargins( Q::Panel | Spacing, 5 );
|
||||
setPanel( Q::Panel, Raised );
|
||||
setColor( Q::Text, pal.themeForeground );
|
||||
setColor( Q::Text | Q::Disabled, pal.darker200 );
|
||||
}
|
||||
|
||||
void QskSquiekSkin::initScrollViewHints()
|
||||
|
|
|
@ -7,21 +7,19 @@
|
|||
|
||||
#include "QskAspect.h"
|
||||
|
||||
#include <QskPushButton.h>
|
||||
#include <QskTextLabel.h>
|
||||
#include <QskDialog.h>
|
||||
#include <QFocusEvent>
|
||||
#include <QGuiApplication>
|
||||
#include <QStyleHints>
|
||||
#include <QskLinearBox.h>
|
||||
#include <QskTextOptions.h>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#include <cmath>
|
||||
#include <unordered_map>
|
||||
|
||||
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,60 +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
|
||||
|
@ -130,20 +74,18 @@ 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
|
||||
|
||||
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 const int KeyLocked = static_cast< int >( Qt::ControlModifier );
|
||||
static const int KeyStates = static_cast< int >( Qt::KeyboardModifierMask );
|
||||
|
||||
static qreal qskKeyStretch( Qt::Key key )
|
||||
{
|
||||
switch ( key )
|
||||
switch( key )
|
||||
{
|
||||
case Qt::Key_Backspace:
|
||||
case Qt::Key_Shift:
|
||||
|
@ -168,20 +110,32 @@ 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;
|
||||
}
|
||||
|
||||
static bool qskIsAutorepeat( int 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
|
||||
|
@ -191,57 +145,194 @@ namespace
|
|||
};
|
||||
}
|
||||
|
||||
class QskInputPanel::PrivateData
|
||||
QSK_SUBCONTROL( QskInputPanel, Panel )
|
||||
|
||||
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 )
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
currentLayout( nullptr ),
|
||||
mode( QskInputPanel::LowercaseMode ),
|
||||
focusKeyIndex( -1 ),
|
||||
selectedGroup( -1 ),
|
||||
candidateOffset( 0 ),
|
||||
repeatKeyTimerId( -1 )
|
||||
QskTextOptions options;
|
||||
options.setFontSizeMode( QskTextOptions::VerticalFit );
|
||||
setTextOptions( options );
|
||||
|
||||
setFocusPolicy( Qt::TabFocus );
|
||||
|
||||
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() );
|
||||
}
|
||||
|
||||
public:
|
||||
const QskInputPanelLayouts::Layout* currentLayout;
|
||||
QskInputPanel::Mode mode;
|
||||
updateText();
|
||||
|
||||
qint16 focusKeyIndex;
|
||||
qint16 selectedGroup;
|
||||
qint32 candidateOffset;
|
||||
connect( this, &QskKeyButton::pressed, this, [ this ]()
|
||||
{
|
||||
m_inputPanel->handleKey( m_keyIndex );
|
||||
} );
|
||||
|
||||
int repeatKeyTimerId;
|
||||
connect( m_inputPanel, &QskInputPanel::modeChanged, this, &QskKeyButton::updateText );
|
||||
}
|
||||
|
||||
QLocale locale;
|
||||
QskAspect::Subcontrol QskKeyButton::effectiveSubcontrol( QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
if( subControl == QskPushButton::Panel )
|
||||
{
|
||||
return QskKeyButton::Panel;
|
||||
}
|
||||
|
||||
QVector< Qt::Key > groups;
|
||||
QVector< Qt::Key > candidates;
|
||||
if( subControl == QskPushButton::Text )
|
||||
{
|
||||
// ### we could also introduce a state to not always query the button
|
||||
return isCancelButton() ? QskKeyButton::TextCancelButton : QskKeyButton::Text;
|
||||
}
|
||||
|
||||
std::unordered_map< int, KeyCounter > activeKeys;
|
||||
KeyTable keyTable[ ModeCount ];
|
||||
return subControl;
|
||||
}
|
||||
|
||||
int QskKeyButton::keyIndex() const
|
||||
{
|
||||
return m_keyIndex;
|
||||
}
|
||||
|
||||
void QskKeyButton::updateText()
|
||||
{
|
||||
QString text = m_inputPanel->currentTextForKeyIndex( m_keyIndex );
|
||||
|
||||
if( text.count() == 1 && text.at( 0 ) == QChar( 0 ) )
|
||||
{
|
||||
setVisible( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
setVisible( true );
|
||||
setText( text );
|
||||
}
|
||||
}
|
||||
|
||||
bool QskKeyButton::isCancelButton() const
|
||||
{
|
||||
auto keyData = m_inputPanel->keyDataAt( m_keyIndex );
|
||||
bool isCancel = ( keyData.key == 0x2716 );
|
||||
return isCancel;
|
||||
}
|
||||
|
||||
class QskInputPanel::PrivateData
|
||||
{
|
||||
public:
|
||||
PrivateData():
|
||||
currentLayout( nullptr ),
|
||||
mode( QskInputPanel::LowercaseMode ),
|
||||
selectedGroup( -1 ),
|
||||
candidateOffset( 0 ),
|
||||
buttonsBox( nullptr ),
|
||||
isUIInitialized( false )
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
const QskInputPanelLayouts::Layout* currentLayout;
|
||||
QskInputPanel::Mode mode;
|
||||
|
||||
qint16 selectedGroup;
|
||||
qint32 candidateOffset;
|
||||
|
||||
QLocale locale;
|
||||
|
||||
QVector< Qt::Key > groups;
|
||||
QVector< Qt::Key > candidates;
|
||||
|
||||
std::unordered_map< int, KeyCounter > activeKeys;
|
||||
KeyTable keyTable[ ModeCount ];
|
||||
|
||||
QskLinearBox* buttonsBox;
|
||||
QList< QskKeyButton* > keyButtons;
|
||||
bool isUIInitialized;
|
||||
};
|
||||
|
||||
QskInputPanel::QskInputPanel( QQuickItem* parent ):
|
||||
QskControl( parent ),
|
||||
Inherited( parent ),
|
||||
m_data( new PrivateData )
|
||||
{
|
||||
qRegisterMetaType< Qt::Key >();
|
||||
|
||||
setFlag( ItemHasContents );
|
||||
setAcceptedMouseButtons( Qt::LeftButton );
|
||||
|
||||
initSizePolicy( QskSizePolicy::Expanding, QskSizePolicy::Expanding );
|
||||
|
||||
setAutoFillBackground( true );
|
||||
|
||||
auto margins = marginsHint( Panel | QskAspect::Margin );
|
||||
setMargins( margins );
|
||||
|
||||
updateLocale( locale() );
|
||||
|
||||
QObject::connect( this, &QskControl::localeChanged,
|
||||
this, &QskInputPanel::updateLocale );
|
||||
this, &QskInputPanel::updateLocale );
|
||||
|
||||
setFlag( ItemIsFocusScope, true );
|
||||
|
||||
#if 0
|
||||
setTabFence( true );
|
||||
#endif
|
||||
|
||||
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 );
|
||||
rowBox->setRetainSizeWhenHidden( button, true );
|
||||
|
||||
m_data->keyButtons.append( button );
|
||||
}
|
||||
}
|
||||
|
||||
connect( this, &QskInputPanel::modeChanged, this, [ this ]() {
|
||||
updateLayout();
|
||||
});
|
||||
}
|
||||
|
||||
QskInputPanel::~QskInputPanel()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QskAspect::Subcontrol QskInputPanel::effectiveSubcontrol( QskAspect::Subcontrol subControl ) const
|
||||
{
|
||||
if( subControl == QskBox::Panel )
|
||||
{
|
||||
return QskInputPanel::Panel;
|
||||
}
|
||||
|
||||
return subControl;
|
||||
}
|
||||
|
||||
|
||||
QskInputPanel::Mode QskInputPanel::mode() const
|
||||
{
|
||||
return m_data->mode;
|
||||
|
@ -254,12 +345,12 @@ 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;
|
||||
|
||||
// Special cases
|
||||
switch ( key )
|
||||
switch( key )
|
||||
{
|
||||
case Qt::Key_Backspace:
|
||||
case Qt::Key_Muhenkan:
|
||||
|
@ -306,7 +397,7 @@ QString QskInputPanel::displayLanguageName() const
|
|||
{
|
||||
const auto locale = this->locale();
|
||||
|
||||
switch ( locale.language() )
|
||||
switch( locale.language() )
|
||||
{
|
||||
case QLocale::Bulgarian:
|
||||
return QStringLiteral( "български език" );
|
||||
|
@ -324,19 +415,21 @@ 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)" );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
case QLocale::Spanish:
|
||||
return QStringLiteral( "Español" );
|
||||
|
@ -397,7 +490,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,96 +499,23 @@ 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 );
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -508,202 +528,83 @@ 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.isSuggestionKey = true; // ### reset when switching layouts etc.!
|
||||
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 )
|
||||
update();
|
||||
if( m_data->mode == LowercaseMode )
|
||||
{
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
QRectF QskInputPanel::keyboardRect() const
|
||||
void QskInputPanel::registerCompositionModelForLocale( const QLocale& locale,
|
||||
QskInputCompositionModel* model )
|
||||
{
|
||||
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;
|
||||
Q_EMIT inputMethodRegistered( locale, model );
|
||||
}
|
||||
|
||||
void QskInputPanel::geometryChanged(
|
||||
const QRectF& newGeometry, const QRectF& oldGeometry )
|
||||
{
|
||||
Inherited::geometryChanged( newGeometry, oldGeometry );
|
||||
|
||||
Q_EMIT keyboardRectChanged();
|
||||
}
|
||||
|
||||
void QskInputPanel::mousePressEvent( QMouseEvent* e )
|
||||
void QskInputPanel::updateLayout()
|
||||
{
|
||||
if ( !keyboardRect().contains( e->pos() ) )
|
||||
if( geometry().isNull() )
|
||||
return; // no need to calculate anything, will be called again
|
||||
|
||||
QRectF rect = layoutRect();
|
||||
qreal verticalSpacing = m_data->buttonsBox->spacing();
|
||||
|
||||
const auto& children = m_data->buttonsBox->childItems();
|
||||
for( auto rowItem : children )
|
||||
{
|
||||
e->ignore();
|
||||
return;
|
||||
auto rowBox = qobject_cast< QskLinearBox* >( rowItem );
|
||||
const qreal horizontalSpacing = rowBox->spacing();
|
||||
|
||||
const auto& rowChildren = rowBox->childItems();
|
||||
for( auto keyItem : rowChildren )
|
||||
{
|
||||
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;
|
||||
|
||||
button->setFixedSize( width, height );
|
||||
}
|
||||
}
|
||||
|
||||
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 )
|
||||
void QskInputPanel::updateUI()
|
||||
{
|
||||
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( QskKeyButton* button : qskAsConst( m_data->keyButtons ) )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
button->updateText();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,35 +617,43 @@ 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;
|
||||
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,19 +667,37 @@ 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;
|
||||
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
void QskInputPanel::compose( Qt::Key key )
|
||||
QString QskInputPanel::currentTextForKeyIndex( int keyIndex ) const
|
||||
{
|
||||
auto keyData = keyDataAt( keyIndex );
|
||||
QString text = textForKey( keyData.key );
|
||||
return text;
|
||||
}
|
||||
|
||||
void QskInputPanel::compose( int key )
|
||||
{
|
||||
QGuiApplication::inputMethod()->invokeAction(
|
||||
static_cast< QInputMethod::Action >( Compose ), key );
|
||||
|
@ -779,18 +706,26 @@ 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 )
|
||||
{
|
||||
auto group = static_cast< int >( m_data->selectedGroup );
|
||||
topRow[ group ].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 +738,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 +761,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;
|
||||
|
@ -905,10 +843,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;
|
||||
|
@ -925,12 +859,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 +874,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;
|
||||
|
@ -958,7 +892,7 @@ void QskInputPanel::updateKeyData()
|
|||
void QskInputPanel::setMode( QskInputPanel::Mode mode )
|
||||
{
|
||||
m_data->mode = mode;
|
||||
update();
|
||||
Q_EMIT modeChanged( m_data->mode );
|
||||
}
|
||||
|
||||
#include "QskInputPanel.moc"
|
||||
|
|
|
@ -6,28 +6,55 @@
|
|||
#ifndef QSK_INPUT_PANEL_H
|
||||
#define QSK_INPUT_PANEL_H
|
||||
|
||||
#include "QskControl.h"
|
||||
#include "QskBox.h"
|
||||
#include "QskPushButton.h"
|
||||
|
||||
#include <QRectF>
|
||||
|
||||
class QSK_EXPORT QskInputPanel : public QskControl
|
||||
class QskInputCompositionModel;
|
||||
class QskInputPanel;
|
||||
|
||||
class QskKeyButton : public QskPushButton // ### rename to QskInputButton or so?
|
||||
{
|
||||
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;
|
||||
|
||||
int keyIndex() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void updateText();
|
||||
|
||||
private:
|
||||
bool isCancelButton() const;
|
||||
|
||||
const int m_keyIndex;
|
||||
QskInputPanel* m_inputPanel;
|
||||
};
|
||||
|
||||
class QSK_EXPORT QskInputPanel : public QskBox
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY( QRectF keyboardRect READ keyboardRect NOTIFY keyboardRectChanged )
|
||||
|
||||
Q_PROPERTY( QString displayLanguageName READ displayLanguageName
|
||||
NOTIFY displayLanguageNameChanged )
|
||||
NOTIFY displayLanguageNameChanged )
|
||||
|
||||
using Inherited = QskControl;
|
||||
using Inherited = QskBox;
|
||||
|
||||
public:
|
||||
QSK_SUBCONTROLS( Panel, KeyPanel, KeyGlyph )
|
||||
QSK_STATES( Checked, Pressed )
|
||||
|
||||
QSK_SUBCONTROLS( Panel )
|
||||
|
||||
struct KeyData
|
||||
{
|
||||
Qt::Key key = Qt::Key( 0 );
|
||||
int key = 0;
|
||||
bool isSuggestionKey = false;
|
||||
QRectF rect;
|
||||
};
|
||||
|
||||
|
@ -60,7 +87,9 @@ public:
|
|||
using KeyDataSet = KeyDataRow[RowCount];
|
||||
|
||||
QskInputPanel( QQuickItem* parent = nullptr );
|
||||
virtual ~QskInputPanel();
|
||||
virtual ~QskInputPanel() override;
|
||||
|
||||
virtual QskAspect::Subcontrol effectiveSubcontrol( QskAspect::Subcontrol subControl ) const override;
|
||||
|
||||
void updateLocale( const QLocale& locale );
|
||||
|
||||
|
@ -69,33 +98,32 @@ public:
|
|||
|
||||
const KeyDataSet& keyData( QskInputPanel::Mode = CurrentMode ) const;
|
||||
|
||||
QString textForKey( Qt::Key ) const;
|
||||
QString textForKey( int ) const;
|
||||
QString displayLanguageName() const;
|
||||
|
||||
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 >& );
|
||||
bool advanceFocus( bool = true );
|
||||
bool activateFocusKey();
|
||||
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 void updateLayout() 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 compose( int );
|
||||
void selectGroup( int );
|
||||
void selectCandidate( int );
|
||||
void setCandidateOffset( 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;
|
||||
|
|
|
@ -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"
|
|
@ -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
|
|
@ -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 >();
|
||||
|
|
|
@ -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 \
|
||||
|
|
Loading…
Reference in New Issue