From 524d8367cf311d1b9392b9cb754fb840619b2548 Mon Sep 17 00:00:00 2001 From: Eism Date: Wed, 25 Aug 2021 15:55:11 +0200 Subject: [PATCH] Implemented accessibility for menu --- src/appshell/qml/AppMenuBar.qml | 11 +++++++ src/appshell/qml/AppTitleBar.qml | 29 +++++++++++++++++++ src/appshell/view/notationstatusbarmodel.cpp | 10 +++++++ .../qml/MuseScore/UiComponents/FlatButton.qml | 2 +- .../MuseScore/UiComponents/ListItemBlank.qml | 2 ++ .../qml/MuseScore/UiComponents/MenuButton.qml | 2 ++ .../MuseScore/UiComponents/StyledMenuItem.qml | 25 ++++++++++++++-- .../UiComponents/StyledMenuLoader.qml | 4 +++ .../MuseScore/NotationScene/NotationView.qml | 2 ++ .../MuseScore/NotationScene/NoteInputBar.qml | 3 ++ .../NotationScene/ViewModeControl.qml | 2 ++ .../MuseScore/NotationScene/ZoomControl.qml | 2 ++ .../MuseScore/Palette/internal/Palette.qml | 2 ++ .../MuseScore/Playback/PlaybackToolBar.qml | 3 ++ 14 files changed, 96 insertions(+), 3 deletions(-) diff --git a/src/appshell/qml/AppMenuBar.qml b/src/appshell/qml/AppMenuBar.qml index fdaf2cfcc7..92912b3bd9 100644 --- a/src/appshell/qml/AppMenuBar.qml +++ b/src/appshell/qml/AppMenuBar.qml @@ -26,6 +26,7 @@ import MuseScore.UiComponents 1.0 import MuseScore.AppShell 1.0 ListView { + id: root property alias navigation: navPanel @@ -33,6 +34,8 @@ ListView { width: contentWidth orientation: Qt.Horizontal + interactive: false + model: appMenuModel.items AppMenuModel { @@ -52,6 +55,8 @@ ListView { NavigationPanel { id: navPanel name: "AppMenuBar" + enabled: root.enabled && root.visible + accessible.name: qsTrc("appshell", "App menu bar") + " " + navPanel.directionInfo } delegate: FlatButton { @@ -65,8 +70,12 @@ ListView { hoveredStateColor: ui.theme.accentColor text: Boolean(item) ? item.title : "" + navigation.name: text navigation.panel: navPanel navigation.order: index + navigation.accessible.name: { + return text.replace('&', '') + } mouseArea.onContainsMouseChanged: { if (!mouseArea.containsMouse || !prv.showedMenu || @@ -98,6 +107,8 @@ ListView { StyledMenuLoader { id: menuLoader + navigation: radioButtonDelegate.navigation + onHandleMenuItem: { Qt.callLater(appMenuModel.handleMenuItem, item.id) } diff --git a/src/appshell/qml/AppTitleBar.qml b/src/appshell/qml/AppTitleBar.qml index a85b913e58..3d8721cf07 100644 --- a/src/appshell/qml/AppTitleBar.qml +++ b/src/appshell/qml/AppTitleBar.qml @@ -41,6 +41,12 @@ Rectangle { id: navSec name: "AppTitleBar" order: 0 + + onActiveChanged: { + if (active) { + root.forceActiveFocus() + } + } } Item { @@ -82,10 +88,23 @@ Rectangle { anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter + NavigationPanel { + id: navAppControlPanel + name: "AppControl" + section: navSec + order: 1 + accessible.name: qsTrc("appshell", "App control") + " " + navAppControlPanel.directionInfo + } + FlatButton { icon: IconCode.MINUS normalStateColor: "transparent" + navigation.name: "AppControl" + navigation.panel: navAppControlPanel + navigation.order: 1 + accessible.name: qsTrc("appshell", "Minimize") + onClicked: { root.showWindowMinimizedRequested() } @@ -95,6 +114,11 @@ Rectangle { icon: IconCode.SPLIT_OUT_ARROWS normalStateColor: "transparent" + navigation.name: "AppControl" + navigation.panel: navAppControlPanel + navigation.order: 2 + accessible.name: qsTrc("appshell", "Maximize") // todo + onClicked: { root.toggleWindowMaximizedRequested() } @@ -106,6 +130,11 @@ Rectangle { pressedStateColor: "red" hoveredStateColor: "red" + navigation.name: "AppControl" + navigation.panel: navAppControlPanel + navigation.order: 3 + accessible.name: qsTrc("appshell", "Quit") + onClicked: { root.closeWindowRequested() } diff --git a/src/appshell/view/notationstatusbarmodel.cpp b/src/appshell/view/notationstatusbarmodel.cpp index 81647ea2a7..6324d707c3 100644 --- a/src/appshell/view/notationstatusbarmodel.cpp +++ b/src/appshell/view/notationstatusbarmodel.cpp @@ -102,6 +102,10 @@ QVariant NotationStatusBarModel::currentViewMode() const QVariantList NotationStatusBarModel::availableViewModeList() const { + if (!notation()) { + return {}; + } + static const QMap allModeMap { { ViewMode::PAGE, "view-mode-page" }, { ViewMode::LINE, "view-mode-continuous" }, @@ -122,6 +126,8 @@ QVariantList NotationStatusBarModel::availableViewModeList() const QVariantList result; + ViewMode currentViewMode = notation()->viewMode(); + for (const ViewMode& viewMode: allModeMap.keys()) { ActionCode code = allModeMap[viewMode]; UiAction action = actionsRegister()->action(code); @@ -131,6 +137,8 @@ QVariantList NotationStatusBarModel::availableViewModeList() const viewModeObj[ID_KEY] = QString::fromStdString(code); viewModeObj[TITLE_KEY] = correctedTitle(viewMode, action.title); viewModeObj[ICON_KEY] = static_cast(action.iconCode); + viewModeObj[SELECTABLE_KEY] = true; + viewModeObj[SELECTED_KEY] = currentViewMode == viewMode; result << viewModeObj; } @@ -170,10 +178,12 @@ void NotationStatusBarModel::load() } emit currentViewModeChanged(); + emit availableViewModeListChanged(); emit zoomEnabledChanged(); notation()->notationChanged().onNotify(this, [this]() { emit currentViewModeChanged(); + emit availableViewModeListChanged(); }); listenChangesInAccessibility(); diff --git a/src/framework/uicomponents/qml/MuseScore/UiComponents/FlatButton.qml b/src/framework/uicomponents/qml/MuseScore/UiComponents/FlatButton.qml index dff57274c7..9118d5cb5a 100644 --- a/src/framework/uicomponents/qml/MuseScore/UiComponents/FlatButton.qml +++ b/src/framework/uicomponents/qml/MuseScore/UiComponents/FlatButton.qml @@ -84,7 +84,7 @@ FocusScope { enabled: root.enabled && root.visible accessible.role: MUAccessible.Button - accessible.name: root.text + accessible.name: Boolean(root.text) ? root.text : root.toolTipTitle accessible.visualItem: root onTriggered: { diff --git a/src/framework/uicomponents/qml/MuseScore/UiComponents/ListItemBlank.qml b/src/framework/uicomponents/qml/MuseScore/UiComponents/ListItemBlank.qml index aa5727b491..b0aaea4a5a 100644 --- a/src/framework/uicomponents/qml/MuseScore/UiComponents/ListItemBlank.qml +++ b/src/framework/uicomponents/qml/MuseScore/UiComponents/ListItemBlank.qml @@ -45,6 +45,8 @@ FocusableControl { Accessible.selectable: true Accessible.selected: isSelected + navigation.accessible.role: MUAccessible.ListItem + background.color: normalStateColor background.opacity: root.enabled ? 1 : ui.theme.itemOpacityDisabled diff --git a/src/framework/uicomponents/qml/MuseScore/UiComponents/MenuButton.qml b/src/framework/uicomponents/qml/MuseScore/UiComponents/MenuButton.qml index 6b4ba00be7..841c39a6a8 100644 --- a/src/framework/uicomponents/qml/MuseScore/UiComponents/MenuButton.qml +++ b/src/framework/uicomponents/qml/MuseScore/UiComponents/MenuButton.qml @@ -48,6 +48,8 @@ FlatButton { StyledMenuLoader { id: menuLoader + navigation: root.navigation + onHandleMenuItem: { root.handleMenuItem(item) } diff --git a/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuItem.qml b/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuItem.qml index edbd16b227..d1a9de11dd 100644 --- a/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuItem.qml +++ b/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuItem.qml @@ -57,6 +57,26 @@ ListItemBlank { isSelected: Boolean(itemPrv.showedSubMenu) || (itemPrv.isSelectable && itemPrv.isSelected) || navigation.active + navigation.name: titleLabel.text + navigation.accessible.name: { + var text = titleLabel.text + if (itemPrv.isCheckable) { + text += " " + (itemPrv.isChecked ? qsTrc("appshell", "checked") : qsTrc("appshell", "not checked")) + } else if (itemPrv.isSelectable) { + text += " " + (itemPrv.isSelected ? qsTrc("appshell", "selected") : qsTrc("appshell", "not selected")) + } + + if (itemPrv.hasShortcut) { + text += " " + itemPrv.shortcut + } + + if (itemPrv.hasSubMenu) { + text += " " + qsTrc("appshell", "menu") + } + + return text.replace('&', '') + } + navigation.onNavigationEvent: { switch (event.type) { case NavigationEvent.Right: @@ -100,6 +120,7 @@ ListItemBlank { id: itemPrv property bool hasShortcut: Boolean(modelData) && Boolean(modelData.shortcut) + property string shortcut: hasShortcut ? modelData.shortcut : "" property bool hasSubMenu: Boolean(modelData) && Boolean(modelData.subitems) && modelData.subitems.length > 0 property var showedSubMenu: null @@ -237,9 +258,9 @@ ListItemBlank { StyledTextLabel { id: shortcutLabel Layout.alignment: Qt.AlignRight - text: itemPrv.hasShortcut ? modelData.shortcut : "" + text: itemPrv.shortcut horizontalAlignment: Text.AlignRight - visible: !isEmpty || (root.reserveSpaceForShortcutOrSubmenuIndicator) + visible: !itemPrv.hasShortcut || (root.reserveSpaceForShortcutOrSubmenuIndicator) } StyledIconLabel { diff --git a/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuLoader.qml b/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuLoader.qml index de8b5ec59b..8d204125c4 100644 --- a/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuLoader.qml +++ b/src/framework/uicomponents/qml/MuseScore/UiComponents/StyledMenuLoader.qml @@ -31,6 +31,8 @@ Loader { property bool isMenuOpened: Boolean(loader.menu) && loader.menu.isOpened + property var navigation: null + QtObject { id: prv @@ -56,6 +58,8 @@ Loader { } menu.anchorItem = menuAnchorItem + menu.navigationParentControl = loader.navigation + update(model, x, y) menu.open() } diff --git a/src/notation/qml/MuseScore/NotationScene/NotationView.qml b/src/notation/qml/MuseScore/NotationScene/NotationView.qml index 57aad24279..e1c10c3d6a 100644 --- a/src/notation/qml/MuseScore/NotationScene/NotationView.qml +++ b/src/notation/qml/MuseScore/NotationScene/NotationView.qml @@ -195,6 +195,8 @@ FocusScope { StyledMenuLoader { id: contextMenuLoader + navigation: navPanel + onHandleMenuItem: function (item) { contextMenuModel.handleMenuItem(item.id) } diff --git a/src/notation/qml/MuseScore/NotationScene/NoteInputBar.qml b/src/notation/qml/MuseScore/NotationScene/NoteInputBar.qml index b5e4a995b0..d2aea1e4a5 100644 --- a/src/notation/qml/MuseScore/NotationScene/NoteInputBar.qml +++ b/src/notation/qml/MuseScore/NotationScene/NoteInputBar.qml @@ -170,6 +170,9 @@ Rectangle { StyledMenuLoader { id: menuLoader + + navigation: btn.navigation + onHandleMenuItem: function(item) { noteInputModel.handleMenuItem(item.id) } diff --git a/src/notation/qml/MuseScore/NotationScene/ViewModeControl.qml b/src/notation/qml/MuseScore/NotationScene/ViewModeControl.qml index 7ec82af1f6..0d159f9cd0 100644 --- a/src/notation/qml/MuseScore/NotationScene/ViewModeControl.qml +++ b/src/notation/qml/MuseScore/NotationScene/ViewModeControl.qml @@ -71,6 +71,8 @@ FlatButton { menuAnchorItem: ui.rootItem + navigation: root.navigation + onHandleMenuItem: { Qt.callLater(root.changeCurrentViewModeRequested, item.id) } diff --git a/src/notation/qml/MuseScore/NotationScene/ZoomControl.qml b/src/notation/qml/MuseScore/NotationScene/ZoomControl.qml index 2c447da5ce..1a49fd5751 100644 --- a/src/notation/qml/MuseScore/NotationScene/ZoomControl.qml +++ b/src/notation/qml/MuseScore/NotationScene/ZoomControl.qml @@ -122,6 +122,8 @@ RowLayout { menuAnchorItem: ui.rootItem + navigation: menuButton.navigation + onHandleMenuItem: { root.changeZoomRequested(item.id) } diff --git a/src/palette/qml/MuseScore/Palette/internal/Palette.qml b/src/palette/qml/MuseScore/Palette/internal/Palette.qml index cecfa96669..0278aea7fe 100644 --- a/src/palette/qml/MuseScore/Palette/internal/Palette.qml +++ b/src/palette/qml/MuseScore/Palette/internal/Palette.qml @@ -623,6 +623,8 @@ GridView { property var modelIndex: null property bool canEdit: true + navigation: paletteCell.navigation + property var items: [ { id: "delete", title: qsTrc("palette", "Delete"), icon: IconCode.DELETE_TANK, enabled: contextMenu.canEdit }, { id: "properties", title: qsTrc("palette", "Properties…"), enabled: contextMenu.canEdit } diff --git a/src/playback/qml/MuseScore/Playback/PlaybackToolBar.qml b/src/playback/qml/MuseScore/Playback/PlaybackToolBar.qml index 6f38ec6580..8ca87d2c21 100644 --- a/src/playback/qml/MuseScore/Playback/PlaybackToolBar.qml +++ b/src/playback/qml/MuseScore/Playback/PlaybackToolBar.qml @@ -127,6 +127,9 @@ Rectangle { StyledMenuLoader { id: menuLoader + + navigation: btn.navigation + onHandleMenuItem: playbackModel.handleMenuItem(item.id) } }