diff options
author | Sharad Sahu <sharad.sahu@crossware.io> | 2022-06-08 17:20:41 +0530 |
---|---|---|
committer | Morten Johan Sørvig <morten.sorvig@qt.io> | 2022-12-27 14:30:25 +0000 |
commit | 13c3fd959ed400396ee770d3e300778cf20a50a9 (patch) | |
tree | cccd065f103214450015a97148125b9801c3176d | |
parent | 42d4619967688e4f313f5508de7594f0c0c976ff (diff) |
wasm: Work on wasm accessibility elements and events
Implement a11y support by adding html elements (Toolbar, Menu,
DialogBox) and events of the appropriate type and/or with the
appropriate ARIA attribute behind the canvas.
Pick-to: 6.5
Change-Id: If9c9fbff9a451b44e57de5d8834f4a78f33f41bc
Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
-rw-r--r-- | src/plugins/platforms/wasm/qwasmaccessibility.cpp | 128 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmaccessibility.h | 8 | ||||
-rw-r--r-- | tests/manual/wasm/a11y/basic_widgets/CMakeLists.txt | 4 | ||||
-rw-r--r-- | tests/manual/wasm/a11y/basic_widgets/basica11ywidget.cpp | 114 | ||||
-rw-r--r-- | tests/manual/wasm/a11y/basic_widgets/basica11ywidget.h | 41 | ||||
-rw-r--r-- | tests/manual/wasm/a11y/basic_widgets/main.cpp | 24 | ||||
-rw-r--r-- | tests/manual/wasm/a11y/basic_widgets/tabswidget.cpp | 63 | ||||
-rw-r--r-- | tests/manual/wasm/a11y/basic_widgets/tabswidget.h | 34 |
8 files changed, 392 insertions, 24 deletions
diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.cpp b/src/plugins/platforms/wasm/qwasmaccessibility.cpp index cb1e3f135c..552f7846ea 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.cpp +++ b/src/plugins/platforms/wasm/qwasmaccessibility.cpp @@ -140,7 +140,7 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac // Translate the Qt a11y elemen role into html element type + ARIA role. // Here we can either create <div> elements with a spesific ARIA role, // or create e.g. <button> elements which should have built-in accessibility. - emscripten::val element = [iface, document] { + emscripten::val element = [this, iface, document] { emscripten::val element = emscripten::val::undefined(); @@ -149,16 +149,44 @@ emscripten::val QWasmAccessibility::createHtmlElement(QAccessibleInterface *ifac case QAccessible::Button: { element = document.call<emscripten::val>("createElement", std::string("button")); } break; - case QAccessible::CheckBox: { element = document.call<emscripten::val>("createElement", std::string("input")); element.call<void>("setAttribute", std::string("type"), std::string("checkbox")); } break; - + case QAccessible::Dialog: { + element = document.call<emscripten::val>("createElement", std::string("dialog")); + }break; + case QAccessible::ToolBar: + case QAccessible::ButtonMenu: { + element = document.call<emscripten::val>("createElement", std::string("div")); + QString text = iface->text(QAccessible::Name); + + element.call<void>("setAttribute", std::string("role"), std::string("widget")); + element.call<void>("setAttribute", std::string("title"), text.toStdString()); + element.call<void>("addEventListener", emscripten::val("click"), + emscripten::val::module_property("qtEventReceived"), true); + }break; + case QAccessible::MenuBar: + case QAccessible::PopupMenu: { + element = document.call<emscripten::val>("createElement",std::string("div")); + QString text = iface->text(QAccessible::Name); + element.call<void>("setAttribute", std::string("role"), std::string("widget")); + element.call<void>("setAttribute", std::string("title"), text.toStdString()); + for (int i = 0; i < iface->childCount(); ++i) { + ensureHtmlElement(iface->child(i)); + setHtmlElementTextName(iface->child(i)); + setHtmlElementGeometry(iface->child(i)); + } + }break; + case QAccessible::EditableText: { + element = document.call<emscripten::val>("createElement", std::string("input")); + element.call<void>("setAttribute", std::string("type"),std::string("text")); + element.call<void>("addEventListener", emscripten::val("input"), + emscripten::val::module_property("qtEventReceived"), true); + } break; default: qCDebug(lcQpaAccessibility) << "TODO: createHtmlElement() handle" << iface->role(); element = document.call<emscripten::val>("createElement", std::string("div")); - //element.set("AriaRole", "foo"); } return element; @@ -245,6 +273,34 @@ void QWasmAccessibility::handleStaticTextUpdate(QAccessibleEvent *event) } } +void QWasmAccessibility::setHtmlElementTextNameLE(QAccessibleInterface *iface) { + emscripten::val element = ensureHtmlElement(iface); + QString text = iface->text(QAccessible::Name); + element.call<void>("setAttribute", std::string("name"), text.toStdString()); + QString value = iface->text(QAccessible::Value); + element.set("innerHTML", value.toStdString()); +} + +void QWasmAccessibility::handleLineEditUpdate(QAccessibleEvent *event) { + + switch (event->type()) { + case QAccessible::NameChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + case QAccessible::Focus: + case QAccessible::TextRemoved: + case QAccessible::TextInserted: + case QAccessible::TextCaretMoved: { + setHtmlElementTextNameLE(event->accessibleInterface()); + } break; + + default: + qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type(); + break; + } +} + + void QWasmAccessibility::handleButtonUpdate(QAccessibleEvent *event) { qCDebug(lcQpaAccessibility) << "TODO: implement handleButtonUpdate for event" << event->type(); @@ -261,6 +317,55 @@ void QWasmAccessibility::handleCheckBoxUpdate(QAccessibleEvent *event) break; } } +void QWasmAccessibility::handleToolUpdate(QAccessibleEvent *event) +{ + QAccessibleInterface *iface = event->accessibleInterface(); + QString text = iface->text(QAccessible::Name); + QString desc = iface->text(QAccessible::Description); + switch (event->type()) { + case QAccessible::NameChanged: + case QAccessible::StateChanged:{ + emscripten::val element = ensureHtmlElement(iface); + element.call<void>("setAttribute", std::string("title"), text.toStdString()); + } break; + default: + qCDebug(lcQpaAccessibility) << "TODO: implement handleToolUpdate for event" << event->type(); + break; + } +} +void QWasmAccessibility::handleMenuUpdate(QAccessibleEvent *event) +{ + QAccessibleInterface *iface = event->accessibleInterface(); + QString text = iface->text(QAccessible::Name); + QString desc = iface->text(QAccessible::Description); + switch (event->type()) { + case QAccessible::NameChanged: + case QAccessible::MenuStart ://"TODO: To implement later + case QAccessible::PopupMenuStart://"TODO: To implement later + case QAccessible::StateChanged:{ + emscripten::val element = ensureHtmlElement(iface); + element.call<void>("setAttribute", std::string("title"), text.toStdString()); + } break; + default: + qCDebug(lcQpaAccessibility) << "TODO: implement handleMenuUpdate for event" << event->type(); + break; + } +} +void QWasmAccessibility::handleDialogUpdate(QAccessibleEvent *event) { + + switch (event->type()) { + case QAccessible::NameChanged: + case QAccessible::Focus: + case QAccessible::DialogStart: + case QAccessible::StateChanged: { + setHtmlElementTextName(event->accessibleInterface()); + } break; + + default: + qCDebug(lcQpaAccessibility) << "TODO: implement handleLineEditUpdate for event" << event->type(); + break; + } +} void QWasmAccessibility::populateAccessibilityTree(QAccessibleInterface *iface) { @@ -323,6 +428,21 @@ void QWasmAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event) case QAccessible::CheckBox: handleCheckBoxUpdate(event); break; + case QAccessible::EditableText: + handleLineEditUpdate(event); + break; + case QAccessible::Dialog: + handleDialogUpdate(event); + break; + case QAccessible::MenuItem: + case QAccessible::MenuBar: + case QAccessible::PopupMenu: + handleMenuUpdate(event); + break; + case QAccessible::ToolBar: + case QAccessible::ButtonMenu: + handleToolUpdate(event); + break; default: qCDebug(lcQpaAccessibility) << "TODO: implement notifyAccessibilityUpdate for role" << iface->role(); }; diff --git a/src/plugins/platforms/wasm/qwasmaccessibility.h b/src/plugins/platforms/wasm/qwasmaccessibility.h index 2c76f41c00..35f97259e8 100644 --- a/src/plugins/platforms/wasm/qwasmaccessibility.h +++ b/src/plugins/platforms/wasm/qwasmaccessibility.h @@ -12,6 +12,7 @@ #include <QLoggingCategory> #include <map> +#include <emscripten/bind.h> Q_DECLARE_LOGGING_CATEGORY(lcQpaAccessibility) @@ -47,6 +48,12 @@ private: void handleStaticTextUpdate(QAccessibleEvent *event); void handleButtonUpdate(QAccessibleEvent *event); void handleCheckBoxUpdate(QAccessibleEvent *event); + void handleDialogUpdate(QAccessibleEvent *event); + void handleMenuUpdate(QAccessibleEvent *event); + void handleToolUpdate(QAccessibleEvent *event); + void handleLineEditUpdate(QAccessibleEvent *event); + void setHtmlElementTextNameLE(QAccessibleInterface *iface); + void populateAccessibilityTree(QAccessibleInterface *iface); void notifyAccessibilityUpdate(QAccessibleEvent *event) override; @@ -54,6 +61,7 @@ private: void initialize() override; void cleanup() override; + private: static QWasmAccessibility *s_instance; QObject *m_rootObject = nullptr; diff --git a/tests/manual/wasm/a11y/basic_widgets/CMakeLists.txt b/tests/manual/wasm/a11y/basic_widgets/CMakeLists.txt index 2aafd831ac..11534bdf68 100644 --- a/tests/manual/wasm/a11y/basic_widgets/CMakeLists.txt +++ b/tests/manual/wasm/a11y/basic_widgets/CMakeLists.txt @@ -1,6 +1,10 @@ qt_internal_add_manual_test(a11y_basic_widgets GUI SOURCES + tabswidget.cpp + tabswidget.h + basica11ywidget.h + basica11ywidget.cpp main.cpp LIBRARIES Qt::Core diff --git a/tests/manual/wasm/a11y/basic_widgets/basica11ywidget.cpp b/tests/manual/wasm/a11y/basic_widgets/basica11ywidget.cpp new file mode 100644 index 0000000000..eaf736160a --- /dev/null +++ b/tests/manual/wasm/a11y/basic_widgets/basica11ywidget.cpp @@ -0,0 +1,114 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "basica11ywidget.h" + +BasicA11yWidget::BasicA11yWidget() : + m_toolBar (new QToolBar()), + m_layout(new QVBoxLayout), + m_tabWidget(new QTabWidget) +{ + createActions(); + createMenus(); + createToolBar(); + m_lblDateTime =new QLabel("Select Chrono Menu for todays date and time."); + m_layout->addWidget(m_lblDateTime); + m_tabWidget->addTab(new GeneralTab(), ("General Widget")); + m_editView =new EditViewTab(); + m_tabWidget->addTab(m_editView, ("Edit Widget")); + m_layout->addWidget(m_tabWidget); + + m_layout->addStretch(); + + connect(m_editView, &EditViewTab::connectToToolBar, this,&BasicA11yWidget::connectToolBar); + setLayout(m_layout); + +} +void BasicA11yWidget::handleButton() { + + QDialog *asmSmplDlg = new QDialog(this); + QVBoxLayout *vlayout = new QVBoxLayout(asmSmplDlg); + asmSmplDlg->setWindowTitle("WebAssembly Dialog box "); + QLabel *label = new QLabel("Accessibility Demo sample application developed in Qt."); + QAbstractButton *bExit = new QPushButton("Exit"); + vlayout->addWidget(label); + vlayout->addWidget(bExit); + asmSmplDlg->setLayout(vlayout); + auto p = asmSmplDlg->palette(); + p.setColor( asmSmplDlg->backgroundRole(), Qt::gray); + asmSmplDlg->setPalette(p); + asmSmplDlg->show(); + asmSmplDlg->connect(bExit, SIGNAL(clicked()), asmSmplDlg, SLOT(close())); +} + +void BasicA11yWidget::createToolBar() +{ + m_copyAct = new QAction(tr("&Copy"), this); + m_copyAct->setShortcuts(QKeySequence::Copy); + + m_pasteAct = new QAction(tr("&Paste"), this); + m_pasteAct->setStatusTip(tr("To paste selected text")); + m_pasteAct->setShortcuts(QKeySequence::Paste); + + m_cutAct = new QAction(tr("C&ut"), this); + m_cutAct->setShortcuts(QKeySequence::Cut); + + m_toolBar->addAction(m_copyAct); + m_toolBar->addAction(m_cutAct); + m_toolBar->addAction(m_pasteAct); + m_layout->addWidget(m_toolBar); + +} +void BasicA11yWidget::connectToolBar() +{ + connect(m_copyAct, &QAction::triggered, m_editView->getTextEdit(), &QPlainTextEdit::copy); + connect(m_pasteAct, &QAction::triggered, m_editView->getTextEdit(), &QPlainTextEdit::paste); + connect(m_cutAct, &QAction::triggered, m_editView->getTextEdit(), &QPlainTextEdit::cut); +} +void BasicA11yWidget::createActions() +{ + m_DateAct = new QAction( tr("&Date"), this); + m_DateAct->setStatusTip(tr("To tell you todays date.")); + connect(m_DateAct, &QAction::triggered, this, &BasicA11yWidget::todaysDate); + + m_TimeAct = new QAction(tr("&Time"), this); + m_TimeAct->setStatusTip(tr("To tell you current time.")); + connect(m_TimeAct, &QAction::triggered, this, &BasicA11yWidget::currentTime); + +} +void BasicA11yWidget::createMenus() +{ + m_menuBar = new QMenuBar(); + + m_TodayMenu = m_menuBar->addMenu(tr("&Chrono")); + m_TodayMenu->addAction(m_DateAct); + m_TodayMenu->addAction(m_TimeAct); + + m_aboutAct = new QAction(tr("&About"), this); + m_aboutAct->setStatusTip(tr("Show the application's About box")); + connect(m_aboutAct, &QAction::triggered, this, &BasicA11yWidget::about); + + m_helpMenu = m_menuBar->addMenu(tr("&Help")); + m_helpMenu->addAction(m_aboutAct); + + m_layout->setMenuBar(m_menuBar); +} + +void BasicA11yWidget::todaysDate() +{ + QDateTime dt=QDateTime::currentDateTime(); + QString str = "Today's Date:"+ dt.date().toString(); + m_lblDateTime->setText(str); +} + +void BasicA11yWidget::currentTime() +{ + QDateTime dt=QDateTime::currentDateTime(); + QString str = "Current Time:"+ dt.time().toString(); + m_lblDateTime->setText(str); +} + +void BasicA11yWidget::about() +{ + handleButton(); +} diff --git a/tests/manual/wasm/a11y/basic_widgets/basica11ywidget.h b/tests/manual/wasm/a11y/basic_widgets/basica11ywidget.h new file mode 100644 index 0000000000..c8d9a4157b --- /dev/null +++ b/tests/manual/wasm/a11y/basic_widgets/basica11ywidget.h @@ -0,0 +1,41 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include <QtWidgets> +#include "tabswidget.h" + +class BasicA11yWidget: public QWidget +{ + Q_OBJECT +private: + QMenu* m_helpMenu = nullptr; + QMenu* m_TodayMenu = nullptr; + QMenuBar* m_menuBar = nullptr; + QToolBar* m_toolBar = nullptr; + QLabel* m_lblDateTime = nullptr; + QVBoxLayout* m_layout = nullptr ; + QTabWidget* m_tabWidget = nullptr; + EditViewTab *m_editView = nullptr; + + QAction* m_DateAct = nullptr; + QAction* m_TimeAct = nullptr; + QAction* m_aboutAct = nullptr; + QAction* m_copyAct = nullptr; + QAction* m_pasteAct = nullptr; + QAction* m_cutAct = nullptr; + +public slots: + void connectToolBar(); +public: + BasicA11yWidget() ; + void createActions(); + void createMenus(); + void createToolBar(); + + void todaysDate(); + void currentTime(); + void about(); + QToolBar* getToolbar(){return m_toolBar;} + void handleButton(); + +}; diff --git a/tests/manual/wasm/a11y/basic_widgets/main.cpp b/tests/manual/wasm/a11y/basic_widgets/main.cpp index 78f142bc1e..5417195ecf 100644 --- a/tests/manual/wasm/a11y/basic_widgets/main.cpp +++ b/tests/manual/wasm/a11y/basic_widgets/main.cpp @@ -1,26 +1,9 @@ -// Copyright (C) 2019 The Qt Company Ltd. +// Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause +#include <QApplication> #include <QtWidgets> - -class BasicA11yWidget: public QWidget -{ -public: - BasicA11yWidget() { - - QVBoxLayout *layout = new QVBoxLayout(); - - layout->addWidget(new QLabel("This is a text label")); - layout->addWidget(new QPushButton("This is a push button")); - layout->addWidget(new QCheckBox("This is a check box")); - - // TODO: Add more widgets - - layout->addStretch(); - - setLayout(layout); - } -}; +#include "basica11ywidget.h" int main(int argc, char **argv) { @@ -31,3 +14,4 @@ int main(int argc, char **argv) return app.exec(); } + diff --git a/tests/manual/wasm/a11y/basic_widgets/tabswidget.cpp b/tests/manual/wasm/a11y/basic_widgets/tabswidget.cpp new file mode 100644 index 0000000000..19bd0cf71b --- /dev/null +++ b/tests/manual/wasm/a11y/basic_widgets/tabswidget.cpp @@ -0,0 +1,63 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "tabswidget.h" + +GeneralTab::GeneralTab(QWidget *parent) + : QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(); + layout->setSizeConstraint(QLayout::SetMaximumSize); + + layout->addWidget(new QLabel("This is a text label")); + + QPushButton *btn = new QPushButton("This is a push button"); + layout->addWidget(btn); + connect(btn, &QPushButton::released, this, [=] () { + btn->setText("You clicked me"); + }); + + layout->addWidget(new QCheckBox("This is a check box")); + + layout->addWidget(new QRadioButton("Radio 1")); + layout->addWidget(new QRadioButton("Radio 2")); + + QSlider *slider = new QSlider(Qt::Horizontal); + slider->setTickInterval(10); + slider->setTickPosition(QSlider::TicksAbove); + layout->addWidget(slider); + + QSpinBox *spin = new QSpinBox(); + spin->setValue(10); + spin->setSingleStep(1); + layout->addWidget(spin); + layout->addStretch(); + + QScrollBar *scrollBar = new QScrollBar(Qt::Horizontal); + scrollBar->setFocusPolicy(Qt::StrongFocus); + layout->addWidget(scrollBar); + + setLayout(layout); +} + + +EditViewTab::EditViewTab(QWidget *parent) : + QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(); + layout->setSizeConstraint(QLayout::SetMaximumSize); + textEdit = new QPlainTextEdit(); + textEdit->setPlaceholderText("Enter Text here"); + layout->addWidget(textEdit); + setLayout(layout); + +} + +void EditViewTab::showEvent( QShowEvent* event ) { + if (!b_connected) + { + emit connectToToolBar(); + b_connected=true; + } + QWidget::showEvent( event ); +} diff --git a/tests/manual/wasm/a11y/basic_widgets/tabswidget.h b/tests/manual/wasm/a11y/basic_widgets/tabswidget.h new file mode 100644 index 0000000000..0d7983cb42 --- /dev/null +++ b/tests/manual/wasm/a11y/basic_widgets/tabswidget.h @@ -0,0 +1,34 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef TABDIALOG_H +#define TABDIALOG_H +#include <QTabWidget> +#include <QtWidgets> + +class GeneralTab : public QWidget +{ + Q_OBJECT + +public: + + explicit GeneralTab(QWidget *parent = nullptr); +}; + +class EditViewTab : public QWidget +{ + + Q_OBJECT +private: + bool b_connected = false; + QPlainTextEdit* textEdit =nullptr; + QToolBar* m_toolbar= nullptr; +public: + void showEvent( QShowEvent* event ) ; + QPlainTextEdit* getTextEdit(){return textEdit;} + explicit EditViewTab( QWidget *parent = nullptr); +signals: + void connectToToolBar(); +}; + +#endif |