Skip to content

Commit

Permalink
fix #301789: Accessibility: no speech for keysig chooser +collect_art…
Browse files Browse the repository at this point in the history
…ifacts

Re-implement the New Score Wizard's key signature chooser as a QListView
using the same model as is used by the QML palettes. QListViews are
accessible by default.
  • Loading branch information
shoogle committed Feb 29, 2020
1 parent 2fdc875 commit 6f61450
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 23 deletions.
1 change: 1 addition & 0 deletions mscore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ add_library(mscoreapp STATIC
palette/createpalettedialog.cpp
palette/palettedialog.cpp palette/palettecelldialog.cpp
palette/palettemodel.cpp palette/palettetree.cpp palette/paletteworkspace.cpp palette/palettewidget.cpp
palette/palettelistview.cpp
scorecmp/scorecmp.cpp scorecmp/scorediffmodel.cpp scorecmp/scorelistmodel.cpp
resourceManager.cpp downloadUtils.cpp
textcursor.cpp continuouspanel.cpp accessibletoolbutton.cpp scoreaccessibility.cpp
Expand Down
27 changes: 7 additions & 20 deletions mscore/newwizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include "newwizard.h"
#include "musescore.h"
#include "preferences.h"
#include "palette.h"
#include "palette/palettelistview.h"
#include "instrdialog.h"
#include "templateBrowser.h"
#include "extension.h"
Expand Down Expand Up @@ -383,25 +383,14 @@ NewWizardKeysigPage::NewWizardKeysigPage(QWidget* parent)
b1->setTitle(tr("Key Signature"));
b1->setAccessibleName(b1->title());
b1->setAccessibleDescription(tr("Choose a key signature"));
sp = MuseScore::newKeySigPalette();
sp->setMoreElements(false);
sp->setShowContextMenu(false);
sp->setSelectable(true);
sp->setDisableElementsApply(true);
int keysigCMajorIdx = 14;
sp->setSelected(keysigCMajorIdx);
PaletteScrollArea* sa = new PaletteScrollArea(sp);
// set widget name to include name of selected element
// we could set the description, but some screen readers ignore it
QString name = tr("Key Signature: %1").arg(qApp->translate("Palette", sp->cellAt(keysigCMajorIdx)->name.toUtf8()));
ScoreAccessibility::makeReadable(name);
sa->setAccessibleName(name);
QAccessibleEvent event(sa, QAccessible::NameChanged);
QAccessible::updateAccessibility(&event);

QVBoxLayout* l1 = new QVBoxLayout;
l1->addWidget(sa);
b1->setLayout(l1);

_plv = new PaletteListView(mscore->newKeySigPalettePanel());
l1->addWidget(_plv);
_plv->setCurrentRow(14); // C Major

tempoGroup = new QGroupBox;
tempoGroup->setCheckable(true);
tempoGroup->setChecked(false);
Expand Down Expand Up @@ -435,9 +424,7 @@ NewWizardKeysigPage::NewWizardKeysigPage(QWidget* parent)

KeySigEvent NewWizardKeysigPage::keysig() const
{
int idx = sp->getSelectedIdx();
Element* e = sp->element(idx);
return static_cast<KeySig*>(e)->keySigEvent();
return static_cast<KeySig*>(_plv->currentElement())->keySigEvent();
}

//---------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions mscore/newwizard.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
namespace Ms {

class Score;
class Palette;
class PaletteListView;
class StaffListItem;
class InstrumentsWidget;
class TemplateBrowser;
Expand Down Expand Up @@ -158,7 +158,7 @@ class NewWizardTemplatePage : public QWizardPage {
class NewWizardKeysigPage : public QWizardPage {
Q_OBJECT

Palette* sp;
PaletteListView* _plv;
QDoubleSpinBox* _tempo;
QGroupBox* tempoGroup;

Expand Down
108 changes: 108 additions & 0 deletions mscore/palette/palettelistview.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//=============================================================================
// PaletteListView
//
// Copyright (C) 2020 Peter Jonas
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================

#include "palettelistview.h"

#include "palettemodel.h"

namespace Ms {

//---------------------------------------------------------
// PaletteListView::PaletteListView
//---------------------------------------------------------

PaletteListView::PaletteListView(PalettePanel* panel, QWidget* parent)
: QListView(parent)
{
setViewMode(QListView::IconMode);
setMovement(QListView::Static);
setResizeMode(QListView::Adjust);
setIconSize(panel->gridSize());
setSpacing(-5); // zero spacing still has a large gap between icons

PaletteTree* tree = new PaletteTree();
tree->append(panel);

PaletteTreeModel* model = new PaletteTreeModel(tree);
QModelIndex parentCategory = model->index(0, 0, QModelIndex());

setModel(model);
setRootIndex(parentCategory);
}

//---------------------------------------------------------
// PaletteListView::currentCell
//---------------------------------------------------------

const PaletteCell* PaletteListView::currentCell() const
{
return model()->data(currentIndex(), PaletteTreeModel::PaletteCellRole).value<const PaletteCell*>();
}

//---------------------------------------------------------
// PaletteListView::currentElement
//---------------------------------------------------------

Element* PaletteListView::currentElement() const
{
return currentCell()->element.get();
}

//---------------------------------------------------------
// PaletteListView::focusNextMatchingCell
//---------------------------------------------------------

void PaletteListView::focusNextMatchingCell(const QString& str)
{
const int nextRow = (currentRow() == count() - 1) ? 0 : currentRow() + 1;
const QModelIndex nextIndex = model()->index(nextRow, 0, rootIndex());
const auto matchedIndexList = model()->match(nextIndex, Qt::ToolTipRole, str);
if (!matchedIndexList.isEmpty())
setCurrentIndex(matchedIndexList.first());
}

//---------------------------------------------------------
// onlyContainsVisibleCharacters
/// Return true if string is non-empty and contains no whitespace
/// or control characters, otherwise false.
//---------------------------------------------------------

static bool onlyContainsVisibleCharacters(const QString& str)
{
constexpr auto options = QRegularExpression::UseUnicodePropertiesOption;
const QRegularExpression pattern("^[[:graph:]]+$", options);
return pattern.match(str).hasMatch();
}

//---------------------------------------------------------
// PaletteListView::keyPressEvent
//---------------------------------------------------------

void PaletteListView::keyPressEvent(QKeyEvent* event)
{
const int key = event->key();
switch (key) {
case Qt::Key_Down:
case Qt::Key_Right:
incrementCurrentRow();
break;
case Qt::Key_Up:
case Qt::Key_Left:
decrementCurrentRow();
break;
default:
if (onlyContainsVisibleCharacters(event->text()))
focusNextMatchingCell(event->text());
else
QListView::keyPressEvent(event);
}
}
}
60 changes: 60 additions & 0 deletions mscore/palette/palettelistview.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//=============================================================================
// PaletteListView
//
// Copyright (C) 2020 Peter Jonas
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================

#ifndef __PALETTELISTVIEW_H__
#define __PALETTELISTVIEW_H__

namespace Ms {

class Element;
class PalettePanel;

struct PaletteCell;

//---------------------------------------------------------
// PaletteListView
/// Display a simple icon list of elements from a single
/// palette category (e.g. key signatures).
//---------------------------------------------------------

class PaletteListView : public QListView // see also QListWidget
{
Q_OBJECT

public:
PaletteListView(PalettePanel* panel, QWidget* parent = nullptr);
const PaletteCell* currentCell() const;
Element* currentElement() const;
void focusNextMatchingCell(const QString& str);

int count() { return model()->rowCount(rootIndex()); }
int currentRow() { return currentIndex().row(); }
void setCurrentRow(int row) { setCurrentIndex(model()->index(row, 0, rootIndex())); }

void incrementCurrentRow()
{
if (currentRow() < (count() - 1))
setCurrentRow(currentRow() + 1);
}

void decrementCurrentRow()
{
if (currentRow() > 0)
setCurrentRow(currentRow() - 1);
}

protected:
virtual void keyPressEvent(QKeyEvent* event) override;

};
}

#endif // __PALETTELISTVIEW_H__
5 changes: 4 additions & 1 deletion mscore/palette/palettemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,10 @@ QVariant PaletteTreeModel::data(const QModelIndex& index, int role) const

if (PaletteCellConstPtr cell = findCell(index)) {
switch (role) {
case Qt::DisplayRole: // TODO don't display cell names in palettes
case Qt::DisplayRole:
return QVariant(); // Don't show element names in
// item views (i.e. just show icons). If you need
// to know the name, use the ToolTip instead.
case Qt::ToolTipRole:
return cell->translatedName();
case Qt::AccessibleTextRole: {
Expand Down

0 comments on commit 6f61450

Please sign in to comment.