add QAD::VirtualKeyboard library, vkbd for widgets with JSON-based description

This commit is contained in:
2024-05-29 21:42:16 +03:00
parent 85adc666ef
commit ac0f5bc325
18 changed files with 871 additions and 3 deletions

View File

@@ -3,8 +3,8 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake
cmake_policy(SET CMP0072 NEW) # FindOpenGL prefers GLVND by default
project(QAD)
set(QAD_MAJOR 2)
set(QAD_MINOR 28)
set(QAD_REVISION 1)
set(QAD_MINOR 29)
set(QAD_REVISION 0)
set(QAD_SUFFIX )
set(QAD_COMPANY SHS)
set(QAD_DOMAIN org.SHS)

View File

@@ -11,6 +11,7 @@ Create imported targets:
* QAD::SQLTable
* QAD::TouchWidgets
* QAD::Doc
* QAD::VirtualKeyboard
* QAD::PIQt
* QAD::PIQtUtils
@@ -46,7 +47,7 @@ if(QAD_FIND_VERSION VERSION_GREATER QAD_VERSION)
message(FATAL_ERROR "QAD version ${QAD_VERSION} is available, but ${QAD_FIND_VERSION} requested!")
endif()
set(__libs "utils;widgets;application;blockview;graphic;graphic_analysis;graphic3d;sql;sql_table;touch_widgets;doc;map")
set(__libs "utils;widgets;application;blockview;graphic;graphic_analysis;graphic3d;sql;sql_table;touch_widgets;doc;map;virtual_keyboard")
if (PIP_FOUND OR BUILDING_PIP)
list(APPEND __libs "piqt;piqt_utils")
endif()
@@ -65,6 +66,7 @@ set(__module_doc Doc )
set(__module_map Map )
set(__module_piqt PIQt )
set(__module_piqt_utils PIQtUtils )
set(__module_virtual_keyboard VirtualKeyboard)
foreach (_l ${__libs})
set( __inc_${_l} "")
@@ -82,6 +84,7 @@ set(__deps_sql_table "QAD::Widgets")
set(__deps_map "QAD::Utils;QAD::PIQt")
set(__deps_piqt "QAD::Widgets;PIP")
set(__deps_piqt_utils "QAD::Blockview;QAD::PIQt")
set(__deps_virtual_keyboard "QAD::PIQt")
#message("find QAD ${BUILDING_QAD}")

BIN
icons/virtual_keyboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

View File

@@ -0,0 +1,4 @@
find_package(PIP)
if (PIP_FOUND)
qad_library(virtual_keyboard "Gui;Widgets" "qad_piqt")
endif()

View File

@@ -0,0 +1,99 @@
{
"default_page": "latin",
"pages": [
{
"name": "numeric",
"rows": [
[
{"role": "l", "text": "1"},
{"role": "l", "text": "2"},
{"role": "l", "text": "3"},
{"role": "l", "text": "4"},
{"role": "l", "text": "5"},
{"role": "l", "text": "6"},
{"role": "l", "text": "7"},
{"role": "l", "text": "8"},
{"role": "l", "text": "9"},
{"role": "l", "text": "0"},
{"role": "backspace"}
],
[
{"role": "l", "text": "@"},
{"role": "l", "text": "#"},
{"role": "l", "text": "%"},
{"role": "l", "text": "&&"},
{"role": "l", "text": "*"},
{"role": "l", "text": "-"},
{"role": "l", "text": "+"},
{"role": "l", "text": "("},
{"role": "l", "text": ")"},
{"role": "return", "stretch": 2}
],
[
{"role": "l", "text": "!"},
{"role": "l", "text": "\""},
{"role": "l", "text": "<"},
{"role": "l", "text": ">"},
{"role": "l", "text": "'"},
{"role": "l", "text": ":"},
{"role": "l", "text": ";"},
{"role": "l", "text": "/"},
{"role": "l", "text": "?"},
{"role": "l", "text": "_"}
],
[
{"role": "gotopage", "text": "en", "page": "latin"},
{"role": "space", "stretch": 6},
{"role": "hide"}
]
]
},
{
"name": "latin",
"rows": [
[
{"role": "l", "text": "q"},
{"role": "l", "text": "w"},
{"role": "l", "text": "e"},
{"role": "l", "text": "r"},
{"role": "l", "text": "t"},
{"role": "l", "text": "y"},
{"role": "l", "text": "u"},
{"role": "l", "text": "i"},
{"role": "l", "text": "o"},
{"role": "l", "text": "p"},
{"role": "backspace"}
],
[
{"role": "l", "text": "a"},
{"role": "l", "text": "s"},
{"role": "l", "text": "d"},
{"role": "l", "text": "f"},
{"role": "l", "text": "g"},
{"role": "l", "text": "h"},
{"role": "l", "text": "j"},
{"role": "l", "text": "k"},
{"role": "l", "text": "l"},
{"role": "return", "stretch": 2}
],
[
{"role": "l", "text": "z"},
{"role": "l", "text": "x"},
{"role": "l", "text": "c"},
{"role": "l", "text": "v"},
{"role": "l", "text": "b"},
{"role": "l", "text": "n"},
{"role": "l", "text": "m"},
{"role": "shift", "stretch": 2}
],
[
{"role": "gotopage", "text": "123", "page": "numeric"},
{"role": "l", "text": ","},
{"role": "space", "stretch": 6},
{"role": "l", "text": "."},
{"role": "hide"}
]
]
}
]
}

View File

@@ -0,0 +1 @@
qad_plugin(virtual_keyboard "Gui;Widgets" "")

View File

@@ -0,0 +1,17 @@
#include "qad_virtual_keyboard.h"
#include "virtual_keyboard_plugin.h"
QADVirtualKeyboard::QADVirtualKeyboard(QObject * parent): QObject(parent) {
m_widgets << new VirtualKeyboardPlugin(this);
}
QList<QDesignerCustomWidgetInterface *> QADVirtualKeyboard::customWidgets() const {
return m_widgets;
}
#if QT_VERSION < 0x050000
Q_EXPORT_PLUGIN2(qad_virtual_keyboard_plugin, QADVirtualKeyboard)
#endif

View File

@@ -0,0 +1,24 @@
#ifndef qad_virtual_keyboard_h
#define qad_virtual_keyboard_h
#include <QtCore/qplugin.h>
#include <QtDesigner/QtDesigner>
class QADVirtualKeyboard
: public QObject
, public QDesignerCustomWidgetCollectionInterface {
Q_OBJECT
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "qad.virtual_keyboard")
#endif
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
public:
explicit QADVirtualKeyboard(QObject * parent = 0);
virtual QList<QDesignerCustomWidgetInterface *> customWidgets() const;
private:
QList<QDesignerCustomWidgetInterface *> m_widgets;
};
#endif

View File

@@ -0,0 +1,62 @@
#include "virtual_keyboard_plugin.h"
#include "virtual_keyboard.h"
#include <QDesignerFormEditorInterface>
#include <QDesignerPropertyEditorInterface>
#include <QtCore/QtPlugin>
VirtualKeyboardPlugin::VirtualKeyboardPlugin(QObject * parent): QObject(parent) {
m_initialized = false;
}
void VirtualKeyboardPlugin::initialize(QDesignerFormEditorInterface * /* core */) {
if (m_initialized) return;
// Add extension registrations, etc. here
m_initialized = true;
}
bool VirtualKeyboardPlugin::isInitialized() const {
return m_initialized;
}
QWidget * VirtualKeyboardPlugin::createWidget(QWidget * parent) {
auto ret = new VirtualKeyboard(parent);
ret->setAlwaysVisible(true);
return ret;
}
QString VirtualKeyboardPlugin::name() const {
return QLatin1String("VirtualKeyboard");
}
QString VirtualKeyboardPlugin::group() const {
return QLatin1String("Touch Widgets");
}
QIcon VirtualKeyboardPlugin::icon() const {
return QIcon(":/icons/virtual_keyboard.png");
}
QString VirtualKeyboardPlugin::toolTip() const {
return QLatin1String("");
}
QString VirtualKeyboardPlugin::whatsThis() const {
return QLatin1String("");
}
bool VirtualKeyboardPlugin::isContainer() const {
return false;
}
QString VirtualKeyboardPlugin::domXml() const {
return QLatin1String("<widget class=\"VirtualKeyboard\" name=\"virtualKeyboard\">\n</widget>\n");
}
QString VirtualKeyboardPlugin::includeFile() const {
return QLatin1String("virtual_keyboard.h");
}

View File

@@ -0,0 +1,36 @@
#ifndef virtual_keyboard_plugin_h
#define virtual_keyboard_plugin_h
#include <QObject>
#if QT_VERSION >= 0x050000
# include <QtUiPlugin/QDesignerCustomWidgetInterface>
#else
# include <QDesignerCustomWidgetInterface>
#endif
class VirtualKeyboardPlugin
: public QObject
, public QDesignerCustomWidgetInterface {
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
VirtualKeyboardPlugin(QObject * parent = 0);
bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget * createWidget(QWidget * parent);
void initialize(QDesignerFormEditorInterface * core);
private:
bool m_initialized;
};
#endif

View File

@@ -0,0 +1,166 @@
#include "virtual_keyboard.h"
#include "ui_virtual_keyboard.h"
#include "virtual_keyboard_layout.h"
#include "virtual_keyboard_layout_page.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStyle>
#include <QStyleFactory>
#include <pibase.h>
#include <picout.h>
#include <piliterals_time.h>
VirtualKeyboard::VirtualKeyboard(QWidget * parent): QWidget(parent) {
ui = new Ui::VirtualKeyboard();
ui->setupUi(this);
ui->stackedPages->setStyle(QStyleFactory::create("Fusion"));
connect(qApp, &QApplication::focusChanged, this, [this](QWidget * old, QWidget * now) {
if (watched) {
watched->removeEventFilter(this);
watched = nullptr;
}
if (!now || !layout) {
setKeyboardVisible(false);
return;
}
if (!now->inputMethodQuery(Qt::ImCursorPosition).isValid()) {
setKeyboardVisible(false);
return;
}
watched = now;
auto imh = Qt::InputMethodHints(watched->inputMethodQuery(Qt::ImHints).toInt());
layout->setDefaultPage();
setKeyboardVisible(true);
layout->applyHints(imh);
watched->installEventFilter(this);
});
}
VirtualKeyboard::~VirtualKeyboard() {
if (watched) {
watched->removeEventFilter(this);
watched = nullptr;
}
destroy();
delete ui;
}
void VirtualKeyboard::init(QString layout_path) {
destroy();
QFile f(layout_path);
if (!f.open(QIODevice::ReadOnly)) return;
QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
layout = new VirtualKeyboardLayout(doc.object());
auto pages = layout->getPages();
for (auto p: pages)
ui->stackedPages->addWidget(p);
connect(layout, &VirtualKeyboardLayout::gotoPageRequest, this, [this](QString pagename) {
auto page = layout->getPageByName(pagename);
if (!page) return;
ui->stackedPages->setCurrentWidget(page);
layout->setCurrentPage(page);
});
connect(layout, &VirtualKeyboardLayout::hideRequest, this, [this]() { setKeyboardVisible(false); });
layout->setDefaultPage();
// piCout << pages.size();
adjust();
}
bool VirtualKeyboard::eventFilter(QObject * o, QEvent * e) {
if (e->type() == QEvent::MouseButtonPress) setKeyboardVisible(true);
return QWidget::eventFilter(o, e);
}
void VirtualKeyboard::changeEvent(QEvent * e) {
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange: ui->retranslateUi(this); break;
case QEvent::Show: ui->retranslateUi(this); break;
default: break;
}
}
void VirtualKeyboard::resizeEvent(QResizeEvent * e) {
if (prev_width == width()) return;
prev_width = width();
adjust();
}
void VirtualKeyboard::showEvent(QShowEvent * e) {
if (first_show) {
first_show = false;
if (layout_path_.isEmpty()) init(":/virtual_keyboard/default.json");
}
QWidget::showEvent(e);
}
void VirtualKeyboard::destroy() {
piDeleteSafety(layout);
while (ui->stackedPages->count() > 0)
delete ui->stackedPages->widget(0);
}
void VirtualKeyboard::adjust() {
if (!layout) return;
auto pages = layout->getPages();
int cols = 0;
for (auto p: pages)
cols = piMaxi(cols, p->buttonColumns());
if (cols < 1) return;
int spacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, nullptr, this);
int pixel_width = width() - spacing * (cols - 1) - ui->verticalLayout->margin() * 2;
int bw = piMaxi(2, pixel_width / cols);
ui->stackedPages->setStyleSheet(QString("font:%1px").arg(bw / 2));
for (auto p: pages)
p->setButtonsSize(bw);
// piCout << cols << spacing << bw;
}
void VirtualKeyboard::setKeyboardVisible(bool yes) {
if (always_visible || !isEnabled()) return;
if (yes) {
stopIndexedTimer(0);
setVisible(true);
} else startIndexedTimer(0, 10_Hz, [this]{
if (QApplication::mouseButtons() != 0) return;
stopIndexedTimer(0);
setVisible(false);
});
}
void VirtualKeyboard::setLayoutPath(const QString & path) {
layout_path_ = path;
init(layout_path_);
}
void VirtualKeyboard::setAlwaysVisible(bool yes) {
always_visible = yes;
if (yes) show();
}
void VirtualKeyboard::setEnabled(bool yes) {
if (!yes) hide();
QWidget::setEnabled(yes);
}
void VirtualKeyboard::setDisabled(bool yes) {
if (yes) hide();
QWidget::setDisabled(yes);
}

View File

@@ -0,0 +1,54 @@
#ifndef virtual_keyboard_h
#define virtual_keyboard_h
#include "qad_virtual_keyboard_export.h"
#include <QWidget>
#include <qad_timers.h>
namespace Ui {
class VirtualKeyboard;
};
class VirtualKeyboardLayout;
class QAD_VIRTUAL_KEYBOARD_EXPORT VirtualKeyboard: public QWidget, private IndexedTimer<> {
Q_OBJECT
Q_PROPERTY(QString layoutPath READ layoutPath WRITE setLayoutPath)
public:
VirtualKeyboard(QWidget * parent = nullptr);
~VirtualKeyboard();
const QString & layoutPath() const { return layout_path_; }
void setLayoutPath(const QString & path);
bool isAlwaysVisible() const { return always_visible; }
void setAlwaysVisible(bool yes);
void setEnabled(bool yes);
void setDisabled(bool yes);
protected:
bool eventFilter(QObject * o, QEvent * e) override;
void changeEvent(QEvent * e) override;
void resizeEvent(QResizeEvent * e) override;
void showEvent(QShowEvent * e) override;
void init(QString layout_path);
void destroy();
void adjust();
void setKeyboardVisible(bool yes);
private:
Ui::VirtualKeyboard * ui = nullptr;
VirtualKeyboardLayout * layout = nullptr;
QWidget * watched = nullptr;
QString layout_path_;
bool first_show = true, always_visible = false;
int prev_width = -1;
private slots:
};
#endif

View File

@@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/">
<file>../../icons/virtual_keyboard.png</file>
</qresource>
<qresource prefix="/virtual_keyboard">
<file>default.json</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>VirtualKeyboard</class>
<widget class="QWidget" name="VirtualKeyboard">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>565</width>
<height>389</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">QWidget{
background-color: black;
}
QToolButton{
background-color: rgb(64,64,64);
color: white;
}
QToolButton:pressed{
background-color: rgb(48,48,48);
}
QToolButton:disabled{
background-color: rgb(32,32,32);
color: rgb(128,128,128);
}
QToolButton:checked{
background-color: rgb(52,52,52);
color: rgb(92,192,92);
}
</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="stackedPages">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">font:14pt</string>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,72 @@
#include "virtual_keyboard_layout.h"
#include <QJsonArray>
#include <QJsonObject>
VirtualKeyboardLayout::VirtualKeyboardLayout(QJsonObject root) {
default_page = root["default_page"].toString();
auto pa = root["pages"].toArray();
for (auto p: pa) {
auto page = new VirtualKeyboardLayoutPage(p.toObject());
if (page->isValid()) {
connect(page, &VirtualKeyboardLayoutPage::gotoPageRequest, this, &VirtualKeyboardLayout::gotoPageRequest);
connect(page, &VirtualKeyboardLayoutPage::hideRequest, this, &VirtualKeyboardLayout::hideRequest);
pages << page;
} else
delete page;
}
}
VirtualKeyboardLayout::~VirtualKeyboardLayout() {
// piDeleteAllAndClear(pages);
}
VirtualKeyboardLayoutPage * VirtualKeyboardLayout::getPageByName(QString name) const {
for (auto p: pages)
if (p->name() == name) return p;
return nullptr;
}
void VirtualKeyboardLayout::setDefaultPage() {
emit gotoPageRequest(default_page);
}
void VirtualKeyboardLayout::setCurrentPage(VirtualKeyboardLayoutPage * p) {
current_page = p;
}
void VirtualKeyboardLayout::applyHints(Qt::InputMethodHints hints) {
// qDebug() << hints << current_page;
if (hints.testFlag(Qt::ImhPreferNumbers) || hints.testFlag(Qt::ImhDigitsOnly)) gotoPageRequest("numeric");
if (hints.testFlag(Qt::ImhPreferLatin) || hints.testFlag(Qt::ImhLatinOnly)) gotoPageRequest("latin");
if (hints.testFlag(Qt::ImhPreferLowercase) || hints.testFlag(Qt::ImhLowercaseOnly) || hints.testFlag(Qt::ImhNoAutoUppercase))
setCapital(false);
else
setCapital(true);
setGotoEnabled(!hints.testFlag(Qt::ImhDigitsOnly) && !hints.testFlag(Qt::ImhLatinOnly));
setCapitalEnabled(!hints.testFlag(Qt::ImhUppercaseOnly) && !hints.testFlag(Qt::ImhLowercaseOnly));
}
void VirtualKeyboardLayout::setGotoEnabled(bool yes) {
for (auto p: pages)
p->setGotoEnabled(yes);
}
void VirtualKeyboardLayout::setCapitalEnabled(bool yes) {
for (auto p: pages)
p->setCapitalEnabled(yes);
}
void VirtualKeyboardLayout::setCapital(bool yes) {
for (auto p: pages)
p->setCapital(yes);
}

View File

@@ -0,0 +1,39 @@
#ifndef virtual_keyboard_layout_h
#define virtual_keyboard_layout_h
#include <QWidget>
#include "virtual_keyboard_layout_page.h"
class VirtualKeyboardLayout: public QObject {
Q_OBJECT
public:
VirtualKeyboardLayout(QJsonObject root);
~VirtualKeyboardLayout();
QVector<VirtualKeyboardLayoutPage * > getPages() const {return pages;}
VirtualKeyboardLayoutPage * getPageByName(QString name) const;
void setDefaultPage();
void setCurrentPage(VirtualKeyboardLayoutPage * p);
void applyHints(Qt::InputMethodHints hints);
protected:
void setGotoEnabled(bool yes);
void setCapitalEnabled(bool yes);
void setCapital(bool yes);
QVector<VirtualKeyboardLayoutPage * > pages;
VirtualKeyboardLayoutPage * current_page = nullptr;
QString default_page;
private slots:
signals:
void gotoPageRequest(QString);
void hideRequest();
};
#endif

View File

@@ -0,0 +1,154 @@
#include "virtual_keyboard_layout_page.h"
#include <QApplication>
#include <QBoxLayout>
#include <QJsonArray>
#include <QJsonObject>
#include <QKeyEvent>
#include <QTimer>
static const char property_role[] = "role";
static const char property_page[] = "page";
static const char property_stretch[] = "stretch";
VirtualKeyboardLayoutPage::VirtualKeyboardLayoutPage(QJsonObject root) {
auto main_lay = new QBoxLayout(QBoxLayout::TopToBottom);
name_ = root["name"].toString();
auto rows = root["rows"].toArray();
for (auto row: rows) {
auto rowa = row.toArray();
QBoxLayout * row_lay = nullptr;
int cur_cols = 0;
for (auto rb: rowa) {
auto * b = createButton(rb.toObject());
if (!b) continue;
if (!row_lay) row_lay = new QBoxLayout(QBoxLayout::LeftToRight);
buttons << b;
row_lay->addWidget(b, b->property(property_stretch).toInt());
++cur_cols;
}
if (row_lay) main_lay->addLayout(row_lay);
columns = piMaxi(columns, cur_cols);
}
// qDebug() << "VirtualKeyboardLayoutPage" << name;
setLayout(main_lay);
}
VirtualKeyboardLayoutPage::~VirtualKeyboardLayoutPage() {}
void VirtualKeyboardLayoutPage::setCapital(bool yes) {
capital = yes;
for (auto b: buttons) {
auto role = buttonRole(b);
if (role == rLetter) {
b->setText(yes ? b->text().toUpper() : b->text().toLower());
}
if (role == rShift) {
// b->setText(yes ? QString::fromUtf8("⇫") : QString::fromUtf8("⇧"));
b->setChecked(yes);
}
}
}
void VirtualKeyboardLayoutPage::setGotoEnabled(bool yes) {
for (auto b: buttons) {
auto role = buttonRole(b);
if (role == rGotoPage) b->setEnabled(yes);
}
}
void VirtualKeyboardLayoutPage::setCapitalEnabled(bool yes) {
capital_enabled = yes;
for (auto b: buttons) {
auto role = buttonRole(b);
if (role == rShift) b->setEnabled(yes);
}
}
void VirtualKeyboardLayoutPage::setButtonsSize(int h) {
for (auto b: buttons) {
b->setFixedHeight(h);
}
if (!isVisible()) {
adjustSize();
layout()->invalidate();
}
}
QToolButton * VirtualKeyboardLayoutPage::createButton(QJsonObject jb) {
QString role_str = jb["role"].toString();
if (role_str.isEmpty()) return nullptr;
auto ret = new QToolButton();
int role = roleFromText(role_str);
int stretch = jb["stretch"].toInt();
if (stretch == 0) stretch = 1;
auto text = jb["text"].toString();
ret->setProperty(property_role, role);
ret->setProperty(property_stretch, stretch);
ret->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
ret->setFocusPolicy(Qt::NoFocus);
ret->setMinimumSize(QSize(2, 2));
ret->setAutoRepeat(true);
switch (role) {
case rBackspace: text = QString::fromUtf8(""); break;
case rReturn: text = QString::fromUtf8(""); break;
case rSpace: text = QString::fromUtf8("────"); break;
case rShift:
text = QString::fromUtf8("");
ret->setCheckable(true);
break; // ⇪⇧⇫⇯⇩⬆⌨
case rHide: text = QString::fromUtf8(""); break;
case rGotoPage: ret->setProperty(property_page, jb["page"].toString()); break;
}
ret->setText(text);
connect(ret, &QToolButton::clicked, this, [this, role, ret](bool press) {
int key = 0;
QString text;
switch (role) {
case rLetter:
text = ret->text();
if (text.startsWith('&')) text.remove(0, 1);
break;
case rBackspace: key = Qt::Key_Backspace; break;
case rReturn: key = Qt::Key_Return; break;
case rSpace:
key = Qt::Key_Space;
text = " ";
break;
case rHide: emit hideRequest(); break;
case rShift: setCapital(!isCapital()); break;
case rGotoPage: emit gotoPageRequest(ret->property(property_page).toString()); break;
}
if (key == 0 && text.isEmpty()) return;
QApplication::postEvent(QApplication::focusWidget(), new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier, text));
QApplication::postEvent(QApplication::focusWidget(), new QKeyEvent(QEvent::KeyRelease, key, Qt::NoModifier, text));
if (role == rLetter && isCapital() && capital_enabled) setCapital(false);
});
return ret;
}
VirtualKeyboardLayoutPage::Role VirtualKeyboardLayoutPage::roleFromText(QString str) {
str = str.toLower();
if (str == "l") return rLetter;
if (str == "backspace") return rBackspace;
if (str == "return") return rReturn;
if (str == "space") return rSpace;
if (str == "hide") return rHide;
if (str == "shift") return rShift;
if (str == "gotopage") return rGotoPage;
return rInvalid;
}
VirtualKeyboardLayoutPage::Role VirtualKeyboardLayoutPage::buttonRole(QToolButton * b) const {
if (!b) return rInvalid;
return static_cast<Role>(b->property(property_role).toInt());
}

View File

@@ -0,0 +1,55 @@
#ifndef virtual_keyboard_layout_page_h
#define virtual_keyboard_layout_page_h
#include <QToolButton>
#include <pibase.h>
class VirtualKeyboardLayoutPage: public QWidget {
Q_OBJECT
public:
VirtualKeyboardLayoutPage(QJsonObject root);
~VirtualKeyboardLayoutPage();
bool isValid() const {return !buttons.isEmpty();}
QString name() const {return name_;}
bool isCapital() const {return capital;}
void setCapital(bool yes);
void setGotoEnabled(bool yes);
void setCapitalEnabled(bool yes);
int buttonColumns() const {return columns;}
void setButtonsSize(int h);
enum Role {
rInvalid,
rLetter,
rBackspace,
rReturn,
rSpace,
rHide,
rShift,
rGotoPage,
};
protected:
QToolButton * createButton(QJsonObject jb);
Role roleFromText(QString str);
Role buttonRole(QToolButton * b) const;
QVector<QToolButton * > buttons;
QString name_;
int columns = 0;
bool capital = false, capital_enabled = true;
private slots:
signals:
void gotoPageRequest(QString);
void hideRequest();
};
#endif