add QAD::VirtualKeyboard library, vkbd for widgets with JSON-based description
This commit is contained in:
@@ -3,8 +3,8 @@ cmake_policy(SET CMP0017 NEW) # need include() with .cmake
|
|||||||
cmake_policy(SET CMP0072 NEW) # FindOpenGL prefers GLVND by default
|
cmake_policy(SET CMP0072 NEW) # FindOpenGL prefers GLVND by default
|
||||||
project(QAD)
|
project(QAD)
|
||||||
set(QAD_MAJOR 2)
|
set(QAD_MAJOR 2)
|
||||||
set(QAD_MINOR 28)
|
set(QAD_MINOR 29)
|
||||||
set(QAD_REVISION 1)
|
set(QAD_REVISION 0)
|
||||||
set(QAD_SUFFIX )
|
set(QAD_SUFFIX )
|
||||||
set(QAD_COMPANY SHS)
|
set(QAD_COMPANY SHS)
|
||||||
set(QAD_DOMAIN org.SHS)
|
set(QAD_DOMAIN org.SHS)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ Create imported targets:
|
|||||||
* QAD::SQLTable
|
* QAD::SQLTable
|
||||||
* QAD::TouchWidgets
|
* QAD::TouchWidgets
|
||||||
* QAD::Doc
|
* QAD::Doc
|
||||||
|
* QAD::VirtualKeyboard
|
||||||
* QAD::PIQt
|
* QAD::PIQt
|
||||||
* QAD::PIQtUtils
|
* 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!")
|
message(FATAL_ERROR "QAD version ${QAD_VERSION} is available, but ${QAD_FIND_VERSION} requested!")
|
||||||
endif()
|
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)
|
if (PIP_FOUND OR BUILDING_PIP)
|
||||||
list(APPEND __libs "piqt;piqt_utils")
|
list(APPEND __libs "piqt;piqt_utils")
|
||||||
endif()
|
endif()
|
||||||
@@ -65,6 +66,7 @@ set(__module_doc Doc )
|
|||||||
set(__module_map Map )
|
set(__module_map Map )
|
||||||
set(__module_piqt PIQt )
|
set(__module_piqt PIQt )
|
||||||
set(__module_piqt_utils PIQtUtils )
|
set(__module_piqt_utils PIQtUtils )
|
||||||
|
set(__module_virtual_keyboard VirtualKeyboard)
|
||||||
|
|
||||||
foreach (_l ${__libs})
|
foreach (_l ${__libs})
|
||||||
set( __inc_${_l} "")
|
set( __inc_${_l} "")
|
||||||
@@ -82,6 +84,7 @@ set(__deps_sql_table "QAD::Widgets")
|
|||||||
set(__deps_map "QAD::Utils;QAD::PIQt")
|
set(__deps_map "QAD::Utils;QAD::PIQt")
|
||||||
set(__deps_piqt "QAD::Widgets;PIP")
|
set(__deps_piqt "QAD::Widgets;PIP")
|
||||||
set(__deps_piqt_utils "QAD::Blockview;QAD::PIQt")
|
set(__deps_piqt_utils "QAD::Blockview;QAD::PIQt")
|
||||||
|
set(__deps_virtual_keyboard "QAD::PIQt")
|
||||||
|
|
||||||
#message("find QAD ${BUILDING_QAD}")
|
#message("find QAD ${BUILDING_QAD}")
|
||||||
|
|
||||||
|
|||||||
BIN
icons/virtual_keyboard.png
Normal file
BIN
icons/virtual_keyboard.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 634 B |
4
libs/virtual_keyboard/CMakeLists.txt
Normal file
4
libs/virtual_keyboard/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
find_package(PIP)
|
||||||
|
if (PIP_FOUND)
|
||||||
|
qad_library(virtual_keyboard "Gui;Widgets" "qad_piqt")
|
||||||
|
endif()
|
||||||
99
libs/virtual_keyboard/default.json
Normal file
99
libs/virtual_keyboard/default.json
Normal 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"}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
1
libs/virtual_keyboard/plugin/CMakeLists.txt
Normal file
1
libs/virtual_keyboard/plugin/CMakeLists.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
qad_plugin(virtual_keyboard "Gui;Widgets" "")
|
||||||
17
libs/virtual_keyboard/plugin/qad_virtual_keyboard.cpp
Normal file
17
libs/virtual_keyboard/plugin/qad_virtual_keyboard.cpp
Normal 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
|
||||||
24
libs/virtual_keyboard/plugin/qad_virtual_keyboard.h
Normal file
24
libs/virtual_keyboard/plugin/qad_virtual_keyboard.h
Normal 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
|
||||||
62
libs/virtual_keyboard/plugin/virtual_keyboard_plugin.cpp
Normal file
62
libs/virtual_keyboard/plugin/virtual_keyboard_plugin.cpp
Normal 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");
|
||||||
|
}
|
||||||
36
libs/virtual_keyboard/plugin/virtual_keyboard_plugin.h
Normal file
36
libs/virtual_keyboard/plugin/virtual_keyboard_plugin.h
Normal 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
|
||||||
166
libs/virtual_keyboard/virtual_keyboard.cpp
Normal file
166
libs/virtual_keyboard/virtual_keyboard.cpp
Normal 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);
|
||||||
|
}
|
||||||
54
libs/virtual_keyboard/virtual_keyboard.h
Normal file
54
libs/virtual_keyboard/virtual_keyboard.h
Normal 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
|
||||||
8
libs/virtual_keyboard/virtual_keyboard.qrc
Normal file
8
libs/virtual_keyboard/virtual_keyboard.qrc
Normal 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>
|
||||||
74
libs/virtual_keyboard/virtual_keyboard.ui
Normal file
74
libs/virtual_keyboard/virtual_keyboard.ui
Normal 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>
|
||||||
72
libs/virtual_keyboard/virtual_keyboard_layout.cpp
Normal file
72
libs/virtual_keyboard/virtual_keyboard_layout.cpp
Normal 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);
|
||||||
|
}
|
||||||
39
libs/virtual_keyboard/virtual_keyboard_layout.h
Normal file
39
libs/virtual_keyboard/virtual_keyboard_layout.h
Normal 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
|
||||||
154
libs/virtual_keyboard/virtual_keyboard_layout_page.cpp
Normal file
154
libs/virtual_keyboard/virtual_keyboard_layout_page.cpp
Normal 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());
|
||||||
|
}
|
||||||
55
libs/virtual_keyboard/virtual_keyboard_layout_page.h
Normal file
55
libs/virtual_keyboard/virtual_keyboard_layout_page.h
Normal 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
|
||||||
Reference in New Issue
Block a user