From 6460485d3fa5844fac93317871ef17c626794f66 Mon Sep 17 00:00:00 2001 From: Andrei Tuicu Date: Thu, 10 Jul 2014 15:13:37 +0300 Subject: [PATCH] Score accessibility system. Provides screen-reader feedback for the selected element. --- libmscore/accidental.cpp | 10 ++ libmscore/accidental.h | 3 + libmscore/ambitus.cpp | 21 ++++ libmscore/ambitus.h | 2 + libmscore/articulation.cpp | 10 ++ libmscore/articulation.h | 3 +- libmscore/barline.cpp | 98 ++++++++++++++++ libmscore/barline.h | 12 +- libmscore/breath.cpp | 15 +++ libmscore/breath.h | 1 + libmscore/chord.cpp | 27 +++++ libmscore/chord.h | 2 + libmscore/chordline.cpp | 21 ++++ libmscore/chordline.h | 3 + libmscore/chordrest.cpp | 94 ++++++++++++++++ libmscore/chordrest.h | 3 +- libmscore/clef.cpp | 11 ++ libmscore/clef.h | 3 +- libmscore/durationtype.cpp | 39 ++++--- libmscore/durationtype.h | 2 +- libmscore/dynamic.cpp | 9 ++ libmscore/dynamic.h | 5 +- libmscore/element.cpp | 9 ++ libmscore/element.h | 13 ++- libmscore/fingering.cpp | 13 +++ libmscore/fingering.h | 2 + libmscore/hairpin.cpp | 15 +++ libmscore/hairpin.h | 1 + libmscore/harmony.cpp | 41 +++++++ libmscore/harmony.h | 3 + libmscore/jump.cpp | 43 ++++--- libmscore/jump.h | 18 +++ libmscore/keysig.cpp | 20 ++++ libmscore/keysig.h | 2 +- libmscore/marker.cpp | 32 ++++++ libmscore/marker.h | 10 ++ libmscore/measure.cpp | 9 ++ libmscore/measure.h | 1 + libmscore/note.cpp | 94 +++++++++++++++- libmscore/note.h | 6 +- libmscore/ottava.cpp | 9 ++ libmscore/ottava.h | 2 + libmscore/pitchspelling.cpp | 16 +-- libmscore/pitchspelling.h | 4 +- libmscore/repeat.cpp | 9 ++ libmscore/repeat.h | 2 + libmscore/rest.cpp | 11 ++ libmscore/rest.h | 4 +- libmscore/score.cpp | 7 +- libmscore/score.h | 3 + libmscore/segment.cpp | 55 +++++++++ libmscore/segment.h | 2 +- libmscore/spanner.cpp | 9 ++ libmscore/spanner.h | 5 + libmscore/tempotext.cpp | 26 +++++ libmscore/tempotext.h | 1 + libmscore/text.cpp | 33 ++++++ libmscore/text.h | 1 + libmscore/timesig.cpp | 18 +++ libmscore/timesig.h | 2 +- libmscore/tremolo.cpp | 13 +++ libmscore/tremolo.h | 2 + libmscore/trill.cpp | 31 +++++ libmscore/trill.h | 11 ++ libmscore/volta.cpp | 7 ++ libmscore/volta.h | 1 + mscore/CMakeLists.txt | 5 +- mscore/fotomode.cpp | 4 +- mscore/menus.cpp | 113 ++++--------------- mscore/musescore.cpp | 20 +++- mscore/scoreaccessibility.cpp | 206 ++++++++++++++++++++++++++++++++++ mscore/scoreaccessibility.h | 45 ++++++++ mscore/scoreview.cpp | 3 +- 73 files changed, 1242 insertions(+), 164 deletions(-) create mode 100644 mscore/scoreaccessibility.cpp create mode 100644 mscore/scoreaccessibility.h diff --git a/libmscore/accidental.cpp b/libmscore/accidental.cpp index c0e02ac68e..6255d60f56 100644 --- a/libmscore/accidental.cpp +++ b/libmscore/accidental.cpp @@ -474,5 +474,15 @@ bool Accidental::setProperty(P_ID propertyId, const QVariant& v) score()->setLayoutAll(true); // spacing changes return true; } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Accidental::accessibleInfo() + { + return Element::accessibleInfo() + " " + QString(Accidental::subtype2name(accidentalType())); + } + } diff --git a/libmscore/accidental.h b/libmscore/accidental.h index 3d9106db91..6e19d36df9 100644 --- a/libmscore/accidental.h +++ b/libmscore/accidental.h @@ -144,7 +144,10 @@ class Accidental : public Element { static const char* subtype2name(Type); static Type value2subtype(AccidentalVal); static Type name2subtype(const QString&); + + QString accessibleInfo() override; }; + } // namespace Ms Q_DECLARE_METATYPE(Ms::Accidental::Role); diff --git a/libmscore/ambitus.cpp b/libmscore/ambitus.cpp index f70ab2691a..0183f00d72 100644 --- a/libmscore/ambitus.cpp +++ b/libmscore/ambitus.cpp @@ -718,5 +718,26 @@ Element* Ambitus::prevElement() { return segment()->lastInPrevSegments(staffIdx()); } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- +QString Ambitus::accessibleInfo() + { + return Element::accessibleInfo() + " " + + tr("Top pitch: %1%2").arg(tpc2name(topTpc(), NoteSpellingType::STANDARD, false, false)).arg(QString::number(topOctave())) + " " + + tr("Bottom pitch: %1%2").arg(tpc2name(bottomTpc(), NoteSpellingType::STANDARD, false, false)).arg(QString::number(bottomOctave())); + } + +//--------------------------------------------------------- +// screenReaderInfo +//--------------------------------------------------------- + +QString Ambitus::screenReaderInfo() + { + return Element::screenReaderInfo() + " " + + tr("Top pitch: %1%2").arg(tpc2name(topTpc(), NoteSpellingType::STANDARD, false, true)).arg(QString::number(topOctave())) + " " + + tr("Bottom pitch: %1%2").arg(tpc2name(bottomTpc(), NoteSpellingType::STANDARD, false, true)).arg(QString::number(bottomOctave())); + } } diff --git a/libmscore/ambitus.h b/libmscore/ambitus.h index a02cea95f6..b9dd0a8eba 100644 --- a/libmscore/ambitus.h +++ b/libmscore/ambitus.h @@ -88,6 +88,8 @@ class Ambitus : public Element { virtual void setTrack(int val); virtual Space space() const; virtual void write(Xml&) const; + virtual QString accessibleInfo() override; + virtual QString screenReaderInfo() override; // properties QVariant getProperty(P_ID ) const; diff --git a/libmscore/articulation.cpp b/libmscore/articulation.cpp index fac7a07d85..d3f63e99c2 100644 --- a/libmscore/articulation.cpp +++ b/libmscore/articulation.cpp @@ -626,6 +626,16 @@ qreal Articulation::mag() const { return parent() ? parent()->mag() * score()->styleD(StyleIdx::articulationMag): 1.0; } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Articulation::accessibleInfo() + { + return Element::accessibleInfo() + " " + subtypeUserName(); + } + } diff --git a/libmscore/articulation.h b/libmscore/articulation.h index abd469c2ee..55efaa66c7 100644 --- a/libmscore/articulation.h +++ b/libmscore/articulation.h @@ -134,8 +134,9 @@ class Articulation : public Element { _articulationType == ArticulationType::Shortfermata || _articulationType == ArticulationType::Longfermata || _articulationType == ArticulationType::Verylongfermata; } - }; + QString accessibleInfo() override; + }; } // namespace Ms #endif diff --git a/libmscore/barline.cpp b/libmscore/barline.cpp index 6a45e88c17..c8549f3ce7 100644 --- a/libmscore/barline.cpp +++ b/libmscore/barline.cpp @@ -20,6 +20,7 @@ #include "articulation.h" #include "stafftype.h" #include "xml.h" +#include "marker.h" namespace Ms { @@ -50,6 +51,22 @@ static const char* barLineNames[] = { QT_TRANSLATE_NOOP("barline", "dotted") }; +const barLineTableItem barLineTable[] = { + { BarLineType::NORMAL, QT_TRANSLATE_NOOP("Palette", "Normal") }, + { BarLineType::BROKEN, QT_TRANSLATE_NOOP("Palette", "Dashed style") }, + { BarLineType::DOTTED, QT_TRANSLATE_NOOP("Palette", "Dotted style") }, + { BarLineType::END, QT_TRANSLATE_NOOP("Palette", "End Bar style") }, + { BarLineType::DOUBLE, QT_TRANSLATE_NOOP("Palette", "Double Bar style") }, + { BarLineType::START_REPEAT, QT_TRANSLATE_NOOP("Palette", "Start Repeat") }, + { BarLineType::END_REPEAT, QT_TRANSLATE_NOOP("Palette", "End Repeat") }, + { BarLineType::END_START_REPEAT, QT_TRANSLATE_NOOP("Palette", "End-Start Repeat") }, + }; + +unsigned int barLineTableSize() + { + return sizeof(barLineTable)/sizeof(*barLineTable); + } + //--------------------------------------------------------- // userTypeName //--------------------------------------------------------- @@ -59,6 +76,16 @@ QString BarLine::userTypeName(BarLineType t) return qApp->translate("barline", barLineNames[int(t)]); } +QString BarLine::userTypeName2(BarLineType t) + { + for (unsigned i = 0; i < sizeof(barLineTable)/sizeof(*barLineTable); ++i) { + if(barLineTable[i].type == t) + return barLineTable[i].name; + } + return QString(); + } + + //--------------------------------------------------------- // BarLine //--------------------------------------------------------- @@ -1155,5 +1182,76 @@ Element* BarLine::prevElement() return parent()->prevElement(); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString BarLine::accessibleInfo() + { + return Element::accessibleInfo() + " " + BarLine::userTypeName2(this->barLineType()); + } + +//--------------------------------------------------------- +// accessibleExtraInfo +//--------------------------------------------------------- + +QString BarLine::accessibleExtraInfo() + { + if (parent()->type() == Element::Type::SEGMENT) { + Segment* seg = static_cast(parent()); + QString rez = ""; + + foreach(Element* e, *el()) + rez += " " + e->screenReaderInfo(); + + foreach (Element* e, seg->annotations()) { + if (e->track() == track()) + rez += " " + e->screenReaderInfo(); + } + Measure* m = seg->measure(); + + if (m) { + //jumps + foreach (Element* e, *m->el()) { + if(e->type() == Element::Type::JUMP) + rez+= " " + e->screenReaderInfo(); + if(e->type() == Element::Type::MARKER) { + Marker* m = static_cast(e); + if (m->markerType() == Marker::Type::FINE) + rez += " " + e->screenReaderInfo(); + } + + } + //markers + Measure* nextM = m->nextMeasureMM(); + if (nextM) { + foreach (Element* e, *nextM->el()) { + if(e->type() == Element::Type::MARKER) + if(static_cast(e)->markerType() == Marker::Type::FINE) + continue; //added above^ + rez += " " + e->screenReaderInfo(); + } + } + } + + int tick = seg->tick(); + SpannerMap smap = score()->spannerMap(); + std::vector< ::Interval > spanners = smap.findOverlapping(tick, tick); + for (std::vector< ::Interval >::iterator i = spanners.begin(); i < spanners.end(); i++) { + ::Interval interval = *i; + Spanner* s = interval.value; + if (s->type() == Element::Type::VOLTA) { + if(s->tick() == tick) + rez += " " + tr("Start of %1").arg(s->screenReaderInfo()); + if(s->tick2() == tick) + rez += " " + tr("End of %1").arg(s->screenReaderInfo()); + } + } + return rez; + } + + return Element::accessibleExtraInfo(); + } + } diff --git a/libmscore/barline.h b/libmscore/barline.h index b4fc748a03..4c1d533062 100644 --- a/libmscore/barline.h +++ b/libmscore/barline.h @@ -113,9 +113,11 @@ class BarLine : public Element { const ElementList* el() const { return &_el; } static QString userTypeName(BarLineType); + static QString userTypeName2(BarLineType); + QString barLineTypeName() const; void setBarLineType(const QString& s); - void setBarLineType(BarLineType i) { _barLineType = i; } + void setBarLineType(BarLineType i) { _barLineType = i; } BarLineType barLineType() const { return _barLineType; } virtual QVariant getProperty(P_ID propertyId) const override; @@ -130,8 +132,16 @@ class BarLine : public Element { virtual Element* nextElement() override; virtual Element* prevElement() override; + QString accessibleInfo() override; + QString accessibleExtraInfo() override; }; +typedef struct { + BarLineType type; + const char* name; + } barLineTableItem; +extern const barLineTableItem barLineTable[]; +unsigned int barLineTableSize(); } // namespace Ms #endif diff --git a/libmscore/breath.cpp b/libmscore/breath.cpp index a3b98b8fbd..b0502e2064 100644 --- a/libmscore/breath.cpp +++ b/libmscore/breath.cpp @@ -126,5 +126,20 @@ Element* Breath::prevElement() { return segment()->lastInPrevSegments(staffIdx()); } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Breath::accessibleInfo() + { + switch (breathType()) { + case 2: + case 3: + return tr("Caesura"); + default: + return tr("Breath"); + } + } } diff --git a/libmscore/breath.h b/libmscore/breath.h index 0034d6ce5d..51291d344a 100644 --- a/libmscore/breath.h +++ b/libmscore/breath.h @@ -52,6 +52,7 @@ class Breath : public Element { virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual QString accessibleInfo() override; }; diff --git a/libmscore/chord.cpp b/libmscore/chord.cpp index 9768195baf..73ece1b256 100644 --- a/libmscore/chord.cpp +++ b/libmscore/chord.cpp @@ -2816,6 +2816,7 @@ TremoloChordType Chord::tremoloChordType() const return TremoloChordType::TremoloSingle; } + //--------------------------------------------------------- // nextElement //--------------------------------------------------------- @@ -2854,5 +2855,31 @@ Element* Chord::prevElement() return ChordRest::prevElement(); } +QString Chord::accessibleExtraInfo() + { + QString rez = ""; + + if (!isGrace()) { + foreach (Chord* c, graceNotes()) { + foreach (Note* n, c->notes()) { + rez = " " + n->screenReaderInfo(); + } + } + } + + if (arpeggio()) + rez = rez + " " + arpeggio()->screenReaderInfo(); + + if (tremolo()) + rez = rez + " " + tremolo()->screenReaderInfo(); + + if (glissando()) + rez = rez + " " + glissando()->screenReaderInfo(); + + foreach (Element* e, el()) + rez = rez + " " + e->screenReaderInfo(); + + return rez + " " + ChordRest::accessibleExtraInfo(); + } } diff --git a/libmscore/chord.h b/libmscore/chord.h index 7b2f3c86a9..db51ea9871 100644 --- a/libmscore/chord.h +++ b/libmscore/chord.h @@ -213,8 +213,10 @@ class Chord : public ChordRest { void sortNotes(); + virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual QString accessibleExtraInfo() override; }; diff --git a/libmscore/chordline.cpp b/libmscore/chordline.cpp index c3fb28ffad..2b5505b8fa 100644 --- a/libmscore/chordline.cpp +++ b/libmscore/chordline.cpp @@ -19,6 +19,14 @@ namespace Ms { +const char* scorelineNames[] = { + QT_TR_NOOP("fall"), + QT_TR_NOOP("doit"), + QT_TR_NOOP("plop"), + QT_TR_NOOP("scoop"), + }; + + //--------------------------------------------------------- // ChordLine //--------------------------------------------------------- @@ -390,5 +398,18 @@ void ChordLine::updateGrips(int* grips, int* defaultGrip, QRectF* grip) const } } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString ChordLine::accessibleInfo() + { + QString rez = Element::accessibleInfo(); + if(chordLineType() != ChordLineType::NOTYPE) + rez = rez + " " + scorelineNames[static_cast(chordLineType()) - 1]; + return rez; + } + } diff --git a/libmscore/chordline.h b/libmscore/chordline.h index 43892be705..6c8c1329c4 100644 --- a/libmscore/chordline.h +++ b/libmscore/chordline.h @@ -64,8 +64,11 @@ class ChordLine : public Element { virtual void editDrag(const EditData&); virtual void updateGrips(int*, int*, QRectF*) const override; + + virtual QString accessibleInfo() override; }; +extern const char* scorelineNames[]; } // namespace Ms #endif diff --git a/libmscore/chordrest.cpp b/libmscore/chordrest.cpp index c0e0675e97..c3253b43cc 100644 --- a/libmscore/chordrest.cpp +++ b/libmscore/chordrest.cpp @@ -925,6 +925,56 @@ void ChordRest::setDurationType(const TDuration& v) _crossMeasure = CrossMeasure::UNKNOWN; } +QString ChordRest::durationUserName() + { + QString duration = tr("Duration:"); + QString tupletType = ""; + if(tuplet()) { + switch (tuplet()->ratio().numerator()) { + case 2: + tupletType += " " + tr("Duplet"); + break; + case 3: + tupletType += " " + tr("Triplet"); + break; + case 4: + tupletType += " " + tr("Quadruplet"); + break; + case 5: + tupletType += " " + tr("Quinplet"); + break; + case 6: + tupletType += " " + tr("Sextuplet"); + break; + case 7: + tupletType += " " + tr("Septuplet"); + break; + case 8: + tupletType += " " + tr("Octuplet"); + break; + case 9: + tupletType += " " + tr("Nontuplet"); + break; + default: + tupletType += " " + tr("Custom Tuplet"); + } + } + QString dotString = ""; + + switch (dots()) { + case 1: + dotString += " " + tr("Dotted"); + break; + case 2: + dotString += " " + tr("Double dotted"); + break; + case 3: + dotString += " " + tr("Triple dotted"); + break; + } + return duration + tupletType + dotString + " " + durationType().durationTypeUserName() + " " + tr("note"); + } + //--------------------------------------------------------- // setTrack //--------------------------------------------------------- @@ -1192,5 +1242,49 @@ Element* ChordRest::prevElement() return segment()->lastInPrevSegments(staffIdx()); } +QString ChordRest::accessibleExtraInfo() + { + QString rez = ""; + foreach (Articulation* a, articulations()) + rez = rez + " " + a->screenReaderInfo(); + + foreach (Element* l, lyricsList()) + rez = rez + " " + l->screenReaderInfo(); + + if(segment()) { + foreach (Element* e, segment()->annotations()) { + if (e->staffIdx() == staffIdx() ) + rez = rez + " " + e->screenReaderInfo(); + } + + SpannerMap smap = score()->spannerMap(); + std::vector< ::Interval > spanners = smap.findOverlapping(tick(), tick()); + for (std::vector< ::Interval >::iterator i = spanners.begin(); i < spanners.end(); i++) { + ::Interval interval = *i; + Spanner* s = interval.value; + if (s->type() == Element::Type::VOLTA || //voltas are added for barlines + s->type() == Element::Type::TIE ) //ties are added in notes + continue; + + Segment* seg = 0; + if (s->type() == Element::Type::SLUR) { + if(s->tick() == tick() && s->track() == track()) + rez += " " + tr("Start of %1").arg(s->screenReaderInfo()); + if(s->tick2() == tick() && s->track2() == track()) + rez += " " + tr("End of %1").arg(s->screenReaderInfo()); + } + else { + if(s->tick() == tick() && s->staffIdx() == staffIdx()) + rez += " " + tr("Start of %1").arg(s->screenReaderInfo()); + seg = segment()->next1MM(Segment::Type::ChordRest); + if (!seg) + continue; + if(s->tick2() == seg->tick() && s->staffIdx() == staffIdx()) + rez += " " + tr("End of %1").arg(s->screenReaderInfo()); + } + } + } + return rez; + } } diff --git a/libmscore/chordrest.h b/libmscore/chordrest.h index 259e7a23bc..2b1997fcbe 100644 --- a/libmscore/chordrest.h +++ b/libmscore/chordrest.h @@ -137,6 +137,7 @@ class ChordRest : public DurationElement { int actualDots() const { return _durationType.dots(); } int durationTypeTicks() { return _crossMeasure == CrossMeasure::FIRST ? _crossMeasureTDur.ticks() : _durationType.ticks(); } + QString durationUserName(); virtual void setTrack(int val); virtual int tick() const; @@ -161,11 +162,11 @@ class ChordRest : public DurationElement { bool isGraceBefore() const; bool isGraceAfter() const; void writeBeam(Xml& xml); - Segment* nextSegmentAfterCR(Segment::Type types) const; virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual QString accessibleExtraInfo() override; }; diff --git a/libmscore/clef.cpp b/libmscore/clef.cpp index bc8c4b1608..2a7642ffd6 100644 --- a/libmscore/clef.cpp +++ b/libmscore/clef.cpp @@ -55,6 +55,7 @@ const ClefInfo ClefInfo::clefTable[] = { { "TAB2", "TAB", 5, 0, 0, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, QT_TRANSLATE_NOOP("clefTable", "Tablature2"), StaffGroup::TAB }, }; + //--------------------------------------------------------- // tag2type //--------------------------------------------------------- @@ -650,5 +651,15 @@ Element* Clef::prevElement() { return segment()->lastInPrevSegments(staffIdx()); } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Clef::accessibleInfo() + { + return ClefInfo::name(clefType()); + } + } diff --git a/libmscore/clef.h b/libmscore/clef.h index c44633b1b9..2dc7542849 100644 --- a/libmscore/clef.h +++ b/libmscore/clef.h @@ -31,6 +31,7 @@ class Segment; static const int NO_CLEF = -1000; + //--------------------------------------------------------- // ClefType //--------------------------------------------------------- @@ -186,9 +187,9 @@ class Clef : public Element { virtual Element* nextElement() override; virtual Element* prevElement() override; + QString accessibleInfo() override; }; - } // namespace Ms #endif diff --git a/libmscore/durationtype.cpp b/libmscore/durationtype.cpp index 17fc7ee26f..59609bf81e 100644 --- a/libmscore/durationtype.cpp +++ b/libmscore/durationtype.cpp @@ -516,29 +516,28 @@ QList toDurationList(Fraction l, bool useDots, int maxDots, bool prin // print //--------------------------------------------------------- -void TDuration::print() const +QString TDuration::durationTypeUserName() const { - qDebug("TDuration("); - const char* s = "?"; + QString s = QObject::tr("Custom"); switch(_val) { - case DurationType::V_LONG: s = "Long"; break; - case DurationType::V_BREVE: s = "Breve"; break; - case DurationType::V_WHOLE: s = "Whole"; break; - case DurationType::V_HALF: s = "Half"; break; - case DurationType::V_QUARTER: s = "Quarter"; break; - case DurationType::V_EIGHTH: s = "Eighth"; break; - case DurationType::V_16TH: s = "16th"; break; - case DurationType::V_32ND: s = "32nd"; break; - case DurationType::V_64TH: s = "64th"; break; - case DurationType::V_128TH: s = "128th"; break; - case DurationType::V_256TH: s = "256th"; break; - case DurationType::V_512TH: s = "512th"; break; - case DurationType::V_1024TH: s = "1024th"; break; - case DurationType::V_ZERO: s = "Zero"; break; - case DurationType::V_MEASURE: s = "Measure"; break; - case DurationType::V_INVALID: s = "Invalid"; break; + case DurationType::V_LONG: s = QObject::tr("Long" ); break; + case DurationType::V_BREVE: s = QObject::tr("Breve" ); break; + case DurationType::V_WHOLE: s = QObject::tr("Whole" ); break; + case DurationType::V_HALF: s = QObject::tr("Half" ); break; + case DurationType::V_QUARTER: s = QObject::tr("Quarter"); break; + case DurationType::V_EIGHTH: s = QObject::tr("Eighth" ); break; + case DurationType::V_16TH: s = QObject::tr("16th" ); break; + case DurationType::V_32ND: s = QObject::tr("32nd" ); break; + case DurationType::V_64TH: s = QObject::tr("64th" ); break; + case DurationType::V_128TH: s = QObject::tr("128th" ); break; + case DurationType::V_256TH: s = QObject::tr("256th" ); break; + case DurationType::V_512TH: s = QObject::tr("512th" ); break; + case DurationType::V_1024TH: s = QObject::tr("1024th" ); break; + case DurationType::V_ZERO: s = QObject::tr("Zero" ); break; + case DurationType::V_MEASURE: s = QObject::tr("Measure"); break; + case DurationType::V_INVALID: s = QObject::tr("Invalid"); break; }; - qDebug(" %s,dots=%d)", s, _dots); + return s; } //--------------------------------------------------------- diff --git a/libmscore/durationtype.h b/libmscore/durationtype.h index 50f6e803c7..3a6156a841 100644 --- a/libmscore/durationtype.h +++ b/libmscore/durationtype.h @@ -66,7 +66,7 @@ class TDuration { int dots() const { return _dots; } void setDots(int v); Fraction fraction() const; - void print() const; + QString durationTypeUserName() const; }; extern QList toDurationList( diff --git a/libmscore/dynamic.cpp b/libmscore/dynamic.cpp index 9bcad11bc4..e5c99158ae 100644 --- a/libmscore/dynamic.cpp +++ b/libmscore/dynamic.cpp @@ -440,5 +440,14 @@ QVariant Dynamic::propertyDefault(P_ID id) const } } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Dynamic::accessibleInfo() + { + return Element::accessibleInfo() + " " + this->dynamicTypeName(); + } + } diff --git a/libmscore/dynamic.h b/libmscore/dynamic.h index 6461239fd3..08391558af 100644 --- a/libmscore/dynamic.h +++ b/libmscore/dynamic.h @@ -86,7 +86,7 @@ class Dynamic : public Text { Segment* segment() const { return (Segment*)parent(); } Measure* measure() const { return (Measure*)parent()->parent(); } - void setDynamicType(Type val) { _dynamicType = val; } + void setDynamicType(Type val) { _dynamicType = val; } void setDynamicType(const QString&); QString dynamicTypeName() const; Type dynamicType() const { return _dynamicType; } @@ -113,8 +113,9 @@ class Dynamic : public Text { virtual QVariant getProperty(P_ID propertyId) const override; virtual bool setProperty(P_ID propertyId, const QVariant&) override; virtual QVariant propertyDefault(P_ID id) const override; - }; + virtual QString accessibleInfo() override; + }; } // namespace Ms diff --git a/libmscore/element.cpp b/libmscore/element.cpp index 9909113cca..355961455b 100644 --- a/libmscore/element.cpp +++ b/libmscore/element.cpp @@ -1943,4 +1943,13 @@ Element* Element::prevElement() } return score()->firstElement(); } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Element::accessibleInfo() + { + return userName(); + } } diff --git a/libmscore/element.h b/libmscore/element.h index f41e790058..c64b4c1402 100644 --- a/libmscore/element.h +++ b/libmscore/element.h @@ -39,10 +39,12 @@ class TextStyle; class Element; enum class SymId; + //--------------------------------------------------------- // ElementFlag //--------------------------------------------------------- + enum class ElementFlag : char { DROP_TARGET = 0x2, SELECTABLE = 0x4, @@ -301,11 +303,9 @@ class Element : public QObject { mutable QRectF _bbox; ///< Bounding box relative to _pos + _userOff ///< valid after call to layout() uint _tag; ///< tag bitmask - protected: Score* _score; QPointF _startDragPosition; ///< used during drag - public: Element(Score* s = 0); Element(const Element&); @@ -497,6 +497,8 @@ class Element : public QObject { qreal magS() const; bool isText() const; + virtual bool isSpanner() const { return false; } + virtual bool isSpannerSegment() const { return false; } qreal point(const Spatium sp) const { return sp.val() * spatium(); } @@ -573,6 +575,11 @@ class Element : public QObject { virtual Element* prevElement(); //< next-element and prev-element command bool concertPitch() const; + virtual QString accessibleInfo(); //< used to populate the status bar + virtual QString screenReaderInfo() { return accessibleInfo(); } //< by default returns accessibleInfo, but can be overriden + // if the screen-reader needs a special string (see note for example) + virtual QString accessibleExtraInfo() { return QString(); } //< used to return info that will be appended to accessibleInfo + // and passed only to the screen-reader }; //--------------------------------------------------------- @@ -705,6 +712,8 @@ extern void collectElements(void* data, Element* e); } // namespace Ms + + Q_DECLARE_METATYPE(Ms::Element::Type); Q_DECLARE_METATYPE(Ms::Element::Placement); diff --git a/libmscore/fingering.cpp b/libmscore/fingering.cpp index 5bfbbf7fda..b089f1f70f 100644 --- a/libmscore/fingering.cpp +++ b/libmscore/fingering.cpp @@ -66,5 +66,18 @@ void Fingering::reset() score()->undoChangeProperty(this, P_ID::USER_OFF, no); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Fingering::accessibleInfo() + { + QString rez = Element::accessibleInfo(); + if (textStyleType() == TextStyleType::STRING_NUMBER) { + rez += " " + tr("String number"); + } + return rez + " " + text(); + } + } diff --git a/libmscore/fingering.h b/libmscore/fingering.h index fec7e1a737..a9b2652746 100644 --- a/libmscore/fingering.h +++ b/libmscore/fingering.h @@ -36,6 +36,8 @@ class Fingering : public Text { virtual void write(Xml&) const override; virtual void read(XmlReader&) override; virtual void reset() override; + + virtual QString accessibleInfo() override; }; diff --git a/libmscore/hairpin.cpp b/libmscore/hairpin.cpp index 12269dfef4..fdf155905b 100644 --- a/libmscore/hairpin.cpp +++ b/libmscore/hairpin.cpp @@ -572,5 +572,20 @@ void Hairpin::reset() SLine::reset(); } +QString Hairpin::accessibleInfo() + { + QString rez = SLine::accessibleInfo(); + switch (hairpinType()) { + case Type::CRESCENDO: + rez += " " + tr("Crescendo"); + break; + case Type::DECRESCENDO: + rez += " " + tr("Descrescendo"); + break; + default: + rez += " " + tr("Custom"); + } + return rez; + } } diff --git a/libmscore/hairpin.h b/libmscore/hairpin.h index 6812fcde13..8197d01894 100644 --- a/libmscore/hairpin.h +++ b/libmscore/hairpin.h @@ -130,6 +130,7 @@ class Hairpin : public SLine { virtual void setYoff(qreal) override; virtual void styleChanged() override; virtual void reset() override; + virtual QString accessibleInfo() override; }; } // namespace Ms diff --git a/libmscore/harmony.cpp b/libmscore/harmony.cpp index 74ecbc3ef6..30c036f7b8 100644 --- a/libmscore/harmony.cpp +++ b/libmscore/harmony.cpp @@ -1452,4 +1452,45 @@ const ParsedChord* Harmony::parsedForm() return _parsedForm; } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Harmony::accessibleInfo() + { + return Element::accessibleInfo() + " " + harmonyName(); + } + +//--------------------------------------------------------- +// screenReaderInfo +//--------------------------------------------------------- + +QString Harmony::screenReaderInfo() + { + QString rez = Element::accessibleInfo(); + if (_rootTpc != Tpc::TPC_INVALID) + rez += " " + tpc2name(_rootTpc, NoteSpellingType::STANDARD, false, true); + + if (parsedForm() && !hTextName().isEmpty()) { + QString aux = parsedForm()->handle(); + aux = aux.replace("#", tr("sharp")).replace("<", ""); + QString extension = ""; + + foreach (QString s, aux.split(">", QString::SkipEmptyParts)) { + if(!s.contains("blues")) + s.replace("b", tr("flat")); + extension += s + " "; + } + rez += " " + extension; + } + else { + rez += " " + hTextName(); + } + + if (_baseTpc != Tpc::TPC_INVALID) + rez += + " / " + tpc2name(_baseTpc, NoteSpellingType::STANDARD, false, true); + + return rez; + } + } diff --git a/libmscore/harmony.h b/libmscore/harmony.h index cee0e05732..534e3d1efb 100644 --- a/libmscore/harmony.h +++ b/libmscore/harmony.h @@ -178,6 +178,9 @@ class Harmony : public Text { void setHarmony(const QString& s); virtual QPainterPath shape() const; void calculateBoundingRect(); + + virtual QString accessibleInfo() override; + virtual QString screenReaderInfo() override; }; diff --git a/libmscore/jump.cpp b/libmscore/jump.cpp index ce28ccc8ac..80e7bb7a6b 100644 --- a/libmscore/jump.cpp +++ b/libmscore/jump.cpp @@ -21,23 +21,19 @@ namespace Ms { // JumpTypeTable //--------------------------------------------------------- -struct JumpTypeTable { - Jump::Type type; - TextStyleType textStyleType; - const char* text; - const char* jumpTo; - const char* playUntil; - const char* continueAt; +const JumpTypeTable jumpTypeTable[] = { + { Jump::Type::DC, TextStyleType::REPEAT_RIGHT, "D.C.", "start", "end", "", QObject::tr("Da Capo") }, + { Jump::Type::DC_AL_FINE, TextStyleType::REPEAT_RIGHT, "D.C. al Fine", "start", "fine", "" , QObject::tr("Da Capo al Fine")}, + { Jump::Type::DC_AL_CODA, TextStyleType::REPEAT_RIGHT, "D.C. al Coda", "start", "coda", "codab", QObject::tr("Da Capo al Coda")}, + { Jump::Type::DS_AL_CODA, TextStyleType::REPEAT_RIGHT, "D.S. al Coda", "segno", "coda", "codab", QObject::tr("D.S. al Coda") }, + { Jump::Type::DS_AL_FINE, TextStyleType::REPEAT_RIGHT, "D.S. al Fine", "segno", "fine", "", QObject::tr("D.S. al Fine") }, + { Jump::Type::DS, TextStyleType::REPEAT_RIGHT, "D.S.", "segno", "end", "", QObject::tr("D.S.") } }; -static const JumpTypeTable jumpTypeTable[] = { - { Jump::Type::DC, TextStyleType::REPEAT_RIGHT, "D.C.", "start", "end", "" }, - { Jump::Type::DC_AL_FINE, TextStyleType::REPEAT_RIGHT, "D.C. al Fine", "start", "fine", "" }, - { Jump::Type::DC_AL_CODA, TextStyleType::REPEAT_RIGHT, "D.C. al Coda", "start", "coda", "codab" }, - { Jump::Type::DS_AL_CODA, TextStyleType::REPEAT_RIGHT, "D.S. al Coda", "segno", "coda", "codab" }, - { Jump::Type::DS_AL_FINE, TextStyleType::REPEAT_RIGHT, "D.S. al Fine", "segno", "fine", "" }, - { Jump::Type::DS, TextStyleType::REPEAT_RIGHT, "D.S.", "segno", "end", "" } - }; +int jumpTypeTableSize() + { + return sizeof(jumpTypeTable)/sizeof(JumpTypeTable); + } //--------------------------------------------------------- // Jump @@ -82,6 +78,14 @@ Jump::Type Jump::jumpType() const return Type::USER; } +QString Jump::jumpTypeUserName() const + { + int idx = static_cast(this->jumpType()); + if(idx < jumpTypeTableSize()) + return jumpTypeTable[idx].userText; + return QString("Custom"); + } + //--------------------------------------------------------- // read //--------------------------------------------------------- @@ -224,5 +228,14 @@ Element* Jump::prevElement() return nextElement(); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Jump::accessibleInfo() + { + return Element::accessibleInfo() + " " + this->jumpTypeUserName(); + } + } diff --git a/libmscore/jump.h b/libmscore/jump.h index 72002725ff..bef0128df0 100644 --- a/libmscore/jump.h +++ b/libmscore/jump.h @@ -27,6 +27,7 @@ namespace Ms { // @P jumpType Ms::Jump::Type (DC, DC_AL_FINE, DC_AL_CODA, DS_AL_CODA, DS_AL_FINE, DS, USER) (read only) //--------------------------------------------------------- + class Jump : public Text { Q_OBJECT @@ -55,6 +56,7 @@ class Jump : public Text { void setJumpType(Type t); Type jumpType() const; + QString jumpTypeUserName() const; virtual Jump* clone() const { return new Jump(*this); } virtual Element::Type type() const { return Element::Type::JUMP; } @@ -79,10 +81,26 @@ class Jump : public Text { virtual QVariant getProperty(P_ID propertyId) const; virtual bool setProperty(P_ID propertyId, const QVariant&); virtual QVariant propertyDefault(P_ID) const; + Element* nextElement() override; Element* prevElement() override; + virtual QString accessibleInfo() override; }; + +struct JumpTypeTable { + Jump::Type type; + TextStyleType textStyleType; + const char* text; + const char* jumpTo; + const char* playUntil; + const char* continueAt; + QString userText; + }; + +extern const JumpTypeTable jumpTypeTable[]; +int jumpTypeTableSize(); + } // namespace Ms Q_DECLARE_METATYPE(Ms::Jump::Type); diff --git a/libmscore/keysig.cpp b/libmscore/keysig.cpp index e0686bbc1f..5aa480fdfc 100644 --- a/libmscore/keysig.cpp +++ b/libmscore/keysig.cpp @@ -524,6 +524,26 @@ Element* KeySig::prevElement() return segment()->lastInPrevSegments(staffIdx()); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString KeySig::accessibleInfo() + { + QString keySigType; + if (isCustom()) + keySigType = tr("Custom"); + + if (key() == Key::C) + return keyNames[14]; + int keyInt = static_cast(key()); + if (keyInt < 0) + keySigType = keyNames[(7 + keyInt) * 2 + 1]; + else + keySigType = keyNames[(keyInt - 1) * 2]; + return Element::accessibleInfo() + " " + keySigType; + } + } diff --git a/libmscore/keysig.h b/libmscore/keysig.h index d687acfedf..e0b1c9b20d 100644 --- a/libmscore/keysig.h +++ b/libmscore/keysig.h @@ -93,11 +93,11 @@ class KeySig : public Element { virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual QString accessibleInfo() override; }; extern const char* keyNames[]; - } // namespace Ms #endif diff --git a/libmscore/marker.cpp b/libmscore/marker.cpp index f05c35d01c..db03a25b31 100644 --- a/libmscore/marker.cpp +++ b/libmscore/marker.cpp @@ -18,6 +18,23 @@ namespace Ms { +//must be in sync with Marker::Type enum +const MarkerTypeItem markerTypeTable[] = { + { Marker::Type::SEGNO , QObject::tr("Segno") }, + { Marker::Type::VARSEGNO, QObject::tr("Segno Variation")}, + { Marker::Type::CODA , QObject::tr("Coda") }, + { Marker::Type::VARCODA , QObject::tr("Varied coda") }, + { Marker::Type::CODETTA , QObject::tr("Codetta") }, + { Marker::Type::FINE , QObject::tr("Fine") }, + { Marker::Type::TOCODA , QObject::tr("To Coda") }, + { Marker::Type::USER , QObject::tr("Custom") } + }; + +int markerTypeTableSize() + { + return sizeof(markerTypeTable)/sizeof(MarkerTypeItem) - 1; //-1 for the user defined + } + //--------------------------------------------------------- // Marker //--------------------------------------------------------- @@ -88,6 +105,11 @@ void Marker::setMarkerType(Type t) setText(txt); } +QString Marker::markerTypeUserName() + { + return markerTypeTable[static_cast(_markerType)].name; + } + //--------------------------------------------------------- // styleChanged //--------------------------------------------------------- @@ -274,6 +296,7 @@ QVariant Marker::propertyDefault(P_ID propertyId) const return Text::propertyDefault(propertyId); } + //--------------------------------------------------------- // nextElement //--------------------------------------------------------- @@ -303,5 +326,14 @@ Element* Marker::prevElement() return nextElement(); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Marker::accessibleInfo() + { + return Element::accessibleInfo() + " " + markerTypeUserName(); + } + } diff --git a/libmscore/marker.h b/libmscore/marker.h index 2a1485c745..bfd2b3fc5c 100644 --- a/libmscore/marker.h +++ b/libmscore/marker.h @@ -44,6 +44,7 @@ class Marker : public Text { USER }; + private: Type _markerType; QString _label; ///< referenced from Jump() element @@ -55,6 +56,7 @@ class Marker : public Text { void setMarkerType(Type t); Type markerType() const { return _markerType; } + QString markerTypeUserName(); virtual Marker* clone() const override { return new Marker(*this); } virtual Element::Type type() const override { return Element::Type::MARKER; } @@ -80,8 +82,16 @@ class Marker : public Text { virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual QString accessibleInfo() override; }; +typedef struct { + Marker::Type type; + QString name; + } MarkerTypeItem; + +extern const MarkerTypeItem markerTypeTable[]; +int markerTypeTableSize(); } // namespace Ms Q_DECLARE_METATYPE(Ms::Marker::Type); diff --git a/libmscore/measure.cpp b/libmscore/measure.cpp index 8dce1636ad..c228327fe2 100644 --- a/libmscore/measure.cpp +++ b/libmscore/measure.cpp @@ -4038,5 +4038,14 @@ Element* Measure::prevElement(int staff) return score()->lastElement(); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Measure::accessibleInfo() + { + return Element::accessibleInfo() + " " + QString::number(no() + 1); + } + } diff --git a/libmscore/measure.h b/libmscore/measure.h index 1b77b146c7..ec09ed56df 100644 --- a/libmscore/measure.h +++ b/libmscore/measure.h @@ -323,6 +323,7 @@ class Measure : public MeasureBase { Element* nextElement(int staff); Element* prevElement(int staff); + virtual QString accessibleInfo() override; }; } // namespace Ms diff --git a/libmscore/note.cpp b/libmscore/note.cpp index 0299a49aee..6fdc0a03bc 100644 --- a/libmscore/note.cpp +++ b/libmscore/note.cpp @@ -9,7 +9,8 @@ // as published by the Free Software Foundation and appearing in // the file LICENCE.GPL //============================================================================= - +#include +#include /** \file Implementation of classes Note and ShadowNote. @@ -416,6 +417,13 @@ int Note::tpc() const return _tpc[concertPitchIdx()]; } +QString Note::tpcUserName(bool explicitAccidental) + { + QString pitch = tr("Pitch: %1").arg(tpc2name(tpc(), NoteSpellingType::STANDARD, false, explicitAccidental)); + QString octave = QString::number((this->pitch() / 12) - 2); + return pitch + (explicitAccidental ? " " : "") + octave; + } + //--------------------------------------------------------- // transposeTpc // return transposed tpc @@ -1735,6 +1743,32 @@ NoteType Note::noteType() const return chord()->noteType(); } +//--------------------------------------------------------- +// noteTypeUserName +//--------------------------------------------------------- + +QString Note::noteTypeUserName() + { + switch (noteType()) { + case NoteType::ACCIACCATURA: + return tr("Accaciatura"); + case NoteType::APPOGGIATURA: + return tr("Appoggiatura"); + case NoteType::GRACE8_AFTER: + case NoteType::GRACE16_AFTER: + case NoteType::GRACE32_AFTER: + return tr("Grace note after"); + case NoteType::GRACE4: + case NoteType::GRACE16: + case NoteType::GRACE32: + return tr("Grace note before"); + case NoteType::INVALID: + return tr("Invalid note"); + default: + return tr("Note"); + } + } + //--------------------------------------------------------- // pagePos //--------------------------------------------------------- @@ -2370,6 +2404,64 @@ void Note::setScore(Score* s) _tieFor->setScore(s); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Note::accessibleInfo() + { + QString duration = chord()->durationUserName(); + QString voice = tr("Voice: %1").arg(QString::number(track() % VOICES + 1)); + return noteTypeUserName() + " " + tpcUserName(false) +" " + duration + " " + (chord()->isGrace() ? "" : voice); + } + +//--------------------------------------------------------- +// screenReaderInfo +//--------------------------------------------------------- + +QString Note::screenReaderInfo() + { + QString duration = chord()->durationUserName(); + QString voice = tr("Voice: %1").arg(QString::number(track() % VOICES + 1)); + return noteTypeUserName() + " " + tpcUserName(true) +" " + duration + " " + (chord()->isGrace() ? "" : voice); + } + +//--------------------------------------------------------- +// accessibleExtraInfo +//--------------------------------------------------------- + +QString Note::accessibleExtraInfo() + { + QString rez = ""; + if (accidental()) { + rez += " " + accidental()->screenReaderInfo(); + } + if (!el().isEmpty()) { + foreach (Element* e, el()) { + rez = rez + " " + e->screenReaderInfo(); + } + } + if (tieFor()) + rez += " " + tr("Start of %1").arg(tieFor()->screenReaderInfo()); + + if (tieBack()) + rez += " " + tr("End of %1").arg(tieBack()->screenReaderInfo()); + + if (!spannerFor().isEmpty()) { + foreach (Spanner* s, spannerFor()) { + rez += " " + tr("Start of %1").arg(s->screenReaderInfo()); + } + } + if (!spannerBack().isEmpty()) { + foreach (Spanner* s, spannerBack()) { + rez += " " + tr("End of %2").arg(s->screenReaderInfo()); + } + } + + rez = rez + " " + chord()->accessibleExtraInfo(); + return rez; + } + //--------------------------------------------------------- // noteVal //--------------------------------------------------------- diff --git a/libmscore/note.h b/libmscore/note.h index 4069dfd2ad..e4d72e744d 100644 --- a/libmscore/note.h +++ b/libmscore/note.h @@ -285,6 +285,7 @@ class Note : public Element { int tpc() const; int tpc1() const { return _tpc[0]; } // non transposed tpc int tpc2() const { return _tpc[1]; } // transposed tpc + QString tpcUserName(bool explicitAccidental = false); void setTpc(int v); void setTpc1(int v) { _tpc[0] = v; } @@ -330,7 +331,6 @@ class Note : public Element { Chord* chord() const { return (Chord*)parent(); } void setChord(Chord* a) { setParent((Element*)a); } - void draw(QPainter*) const; void read(XmlReader&); @@ -345,6 +345,7 @@ class Note : public Element { void setDotsHidden(bool val) { _dotsHidden = val; } NoteType noteType() const; + QString noteTypeUserName(); ElementList el() { return _el; } const ElementList el() const { return _el; } @@ -423,6 +424,9 @@ class Note : public Element { virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual QString accessibleInfo() override; + virtual QString screenReaderInfo() override; + virtual QString accessibleExtraInfo() override; }; // extern const SymId noteHeads[2][int(NoteHead::Group::HEAD_GROUPS)][int(NoteHead::Type::HEAD_TYPES)]; diff --git a/libmscore/ottava.cpp b/libmscore/ottava.cpp index 5024fd9bbd..63cb116e32 100644 --- a/libmscore/ottava.cpp +++ b/libmscore/ottava.cpp @@ -540,5 +540,14 @@ void Ottava::reset() TextLine::reset(); } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Ottava::accessibleInfo() + { + return Element::accessibleInfo() + " " + ottavaDefault[static_cast(ottavaType())].name; + } } diff --git a/libmscore/ottava.h b/libmscore/ottava.h index d127039e31..ceec2e9ac4 100644 --- a/libmscore/ottava.h +++ b/libmscore/ottava.h @@ -115,6 +115,8 @@ class Ottava : public TextLine { virtual void setYoff(qreal) override; virtual void styleChanged() override; virtual void reset() override; + + virtual QString accessibleInfo() override; }; } // namespace Ms diff --git a/libmscore/pitchspelling.cpp b/libmscore/pitchspelling.cpp index faac44abc6..0e84f0a295 100644 --- a/libmscore/pitchspelling.cpp +++ b/libmscore/pitchspelling.cpp @@ -225,34 +225,34 @@ int tpc2alterByKey(int tpc, Key key) { // return note name //--------------------------------------------------------- -QString tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase) +QString tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase, bool explicitAccidental) { QString s; QString acc; - tpc2name(tpc, spelling, lowerCase, s, acc); - return s + acc; + tpc2name(tpc, spelling, lowerCase, s, acc, explicitAccidental); + return s + (explicitAccidental ? " " : "") + acc; } //--------------------------------------------------------- // tpc2name //--------------------------------------------------------- -void tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase, QString& s, QString& acc) +void tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase, QString& s, QString& acc, bool explicitAccidental) { int n; tpc2name(tpc, spelling, lowerCase, s, n); switch (n) { - case -2: acc = "bb" ; break; + case -2: acc = explicitAccidental ? QObject::tr("double flat") : "bb" ; break; case -1: if (spelling != NoteSpellingType::GERMAN) - acc = "b"; + acc = explicitAccidental ? QObject::tr("flat") : "b"; else // render flats as "es" except for A and E, which get "s" acc = (tpc == 10 || tpc == 11) ? "s" : "es"; break; case 0: acc = ""; break; - case 1: acc = (spelling != NoteSpellingType::GERMAN) ? "#" : "is"; break; - case 2: acc = "##"; break; + case 1: acc = (spelling != NoteSpellingType::GERMAN) ? (explicitAccidental ? QObject::tr("sharp") : "#") : "is"; break; + case 2: acc = explicitAccidental ? QObject::tr("double sharp") : "##"; break; default: qDebug("tpc2name(%d): acc %d", tpc, n); acc = ""; diff --git a/libmscore/pitchspelling.h b/libmscore/pitchspelling.h index 1d56b5c3bd..e3140af3fc 100644 --- a/libmscore/pitchspelling.h +++ b/libmscore/pitchspelling.h @@ -60,8 +60,8 @@ extern void spell(QList& notes, int); extern void spell(QList& notes); extern int computeWindow(const QList& notes, int start, int end); extern int tpc(int idx, int pitch, int opt); -extern QString tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase); -extern void tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase, QString& s, QString& acc); +extern QString tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase, bool explicitAccidental = false); +extern void tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase, QString& s, QString& acc, bool explicitAccidental = false); extern void tpc2name(int tpc, NoteSpellingType spelling, bool lowerCase, QString& s, int& acc); extern int step2tpc(const QString& stepName, AccidentalVal alter); extern int step2tpc(int step); diff --git a/libmscore/repeat.cpp b/libmscore/repeat.cpp index 204b57fc57..b1f0dc5051 100644 --- a/libmscore/repeat.cpp +++ b/libmscore/repeat.cpp @@ -78,5 +78,14 @@ Fraction RepeatMeasure::duration() const return Fraction(0, 1); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString RepeatMeasure::accessibleInfo() + { + return Element::accessibleInfo(); + } + } diff --git a/libmscore/repeat.h b/libmscore/repeat.h index 19d7d82a50..85eb2ac80c 100644 --- a/libmscore/repeat.h +++ b/libmscore/repeat.h @@ -38,6 +38,8 @@ class RepeatMeasure : public Rest { virtual void draw(QPainter*) const; virtual void layout(); virtual Fraction duration() const; + + virtual QString accessibleInfo(); }; diff --git a/libmscore/rest.cpp b/libmscore/rest.cpp index 0618ffeb67..0f9c01fb5f 100644 --- a/libmscore/rest.cpp +++ b/libmscore/rest.cpp @@ -624,5 +624,16 @@ qreal Rest::stemPosX() const else return bbox().left(); } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Rest::accessibleInfo() + { + QString voice = tr("Voice: %1").arg(QString::number(track() % VOICES + 1)); + return Element::accessibleInfo() + " " + durationUserName() + " " + voice ; + } + } diff --git a/libmscore/rest.h b/libmscore/rest.h index 2f90e50d0e..65db3f2f34 100644 --- a/libmscore/rest.h +++ b/libmscore/rest.h @@ -49,7 +49,6 @@ class Rest : public ChordRest { virtual Rest* clone() const override { return new Rest(*this, false); } virtual Rest* linkedClone() const { return new Rest(*this, true); } - virtual Measure* measure() const override { return parent() ? (Measure*)(parent()->parent()) : 0; } virtual qreal mag() const override; virtual void draw(QPainter*) const override; @@ -75,8 +74,9 @@ class Rest : public ChordRest { virtual QPointF stemPos() const; virtual qreal stemPosX() const; virtual QPointF stemPosBeam() const; - }; + virtual QString accessibleInfo() override; + }; } // namespace Ms #endif diff --git a/libmscore/score.cpp b/libmscore/score.cpp index 55af52e98e..e61f0ff9c9 100644 --- a/libmscore/score.cpp +++ b/libmscore/score.cpp @@ -337,6 +337,7 @@ Score::Score() _tempomap = new TempoMap; _sigmap = new TimeSigMap(); _style = *(MScore::defaultStyle()); + accInfo = tr("No selection"); } Score::Score(const MStyle* s) @@ -347,6 +348,7 @@ Score::Score(const MStyle* s) _tempomap = new TempoMap; _sigmap = new TimeSigMap(); _style = *s; + accInfo = tr("No selection"); } // @@ -383,6 +385,7 @@ Score::Score(Score* parent) } _synthesizerState = parent->_synthesizerState; + accInfo = tr("No selection"); } Score::Score(Score* parent, const MStyle* s) @@ -391,6 +394,7 @@ Score::Score(Score* parent, const MStyle* s) _parentScore = parent; init(); _style = *s; + accInfo = tr("No selection"); } //--------------------------------------------------------- @@ -2710,8 +2714,9 @@ void Score::selectSingle(Element* e, int staffIdx) _selection.add(e); _is.setTrack(e->track()); selState = SelState::LIST; - if (e->type() == Element::Type::NOTE) + if (e->type() == Element::Type::NOTE) { e = e->parent(); + } if (e->type() == Element::Type::REST || e->type() == Element::Type::CHORD) { _is.setLastSegment(_is.segment()); _is.setSegment(static_cast(e)->segment()); diff --git a/libmscore/score.h b/libmscore/score.h index 4b31ad278a..60a0f206bc 100644 --- a/libmscore/score.h +++ b/libmscore/score.h @@ -374,6 +374,7 @@ class Score : public QObject { PlayMode _playMode; qreal _noteHeadWidth; + QString accInfo; ///< information used by the screen-reader //------------------ @@ -989,6 +990,8 @@ class Score : public QObject { Element* lastElement(); void cmdInsertClef(Clef* clef, ChordRest* cr); + void setAccessibleInfo(QString s) { accInfo = s.remove(":"); } + QString accessibleInfo() { return accInfo; } friend class ChangeSynthesizerState; friend class Chord; diff --git a/libmscore/segment.cpp b/libmscore/segment.cpp index 4b79e9ae16..6bfe6f1a6e 100644 --- a/libmscore/segment.cpp +++ b/libmscore/segment.cpp @@ -1166,4 +1166,59 @@ Element* Segment::lastElement(int staff) return 0; } +QString Segment::accessibleExtraInfo() + { + QString rez = ""; + if (!this->annotations().empty()) { + rez = rez + tr("Annotations: "); + foreach (Element* a, this->annotations()) { + switch(a->type()) { + case Element::Type::DYNAMIC: + //they are added in the chordrest, because they are for only one staff + break; + default: + rez = rez + " " + a->accessibleInfo(); + } + } + } + + QString startSpanners = ""; + QString endSpanners = ""; + SpannerMap smap = score()->spannerMap(); + std::vector< ::Interval > spanners = smap.findOverlapping(this->tick(), this->tick()); + for (std::vector< ::Interval >::iterator i = spanners.begin(); i < spanners.end(); i++) { + ::Interval interval = *i; + Spanner* s = interval.value; + if (this->segmentType() == Segment::Type::EndBarLine || + this->segmentType() == Segment::Type::BarLine || + this->segmentType() == Segment::Type::StartRepeatBarLine) { + if (s->type() != Element::Type::VOLTA) + continue; + } + else { + if (s->type() == Element::Type::VOLTA || + s->type() == Element::Type::TIE ) //ties are added in Note + continue; + } + + if (s->tick() == this->tick()) + startSpanners += tr("Start of ") + s->accessibleInfo(); + + Segment* seg = 0; + switch (s->type()) { + case Element::Type::VOLTA: + case Element::Type::SLUR: + seg = this; + break; + default: + seg = this->next1MM(Segment::Type::ChordRest); + break; + } + + if (seg && s->tick2() == seg->tick()) + endSpanners += tr("End of ") + s->accessibleInfo(); + } + return rez + " " + startSpanners + " " + endSpanners; + } + } // namespace Ms diff --git a/libmscore/segment.h b/libmscore/segment.h index 82708ec0a2..9ca11c3597 100644 --- a/libmscore/segment.h +++ b/libmscore/segment.h @@ -201,7 +201,7 @@ public: bool operator<(const Segment&) const; bool operator>(const Segment&) const; - + virtual QString accessibleExtraInfo() override; Element* firstInNextSegments(int activeStaff); //< Element* lastInPrevSegments(int activeStaff); //< Element* firstElement(int staff); //< These methods are used for navigation diff --git a/libmscore/spanner.cpp b/libmscore/spanner.cpp index 69ab2ad92d..16f8017913 100644 --- a/libmscore/spanner.cpp +++ b/libmscore/spanner.cpp @@ -190,6 +190,15 @@ Element* SpannerSegment::prevElement() return spanner()->prevElement(); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString SpannerSegment::accessibleInfo() + { + return spanner()->accessibleInfo(); + } + //--------------------------------------------------------- // Spanner //--------------------------------------------------------- diff --git a/libmscore/spanner.h b/libmscore/spanner.h index e9bf14413d..12bb11400e 100644 --- a/libmscore/spanner.h +++ b/libmscore/spanner.h @@ -77,8 +77,11 @@ class SpannerSegment : public Element { virtual void reset() override; virtual void setSelected(bool f) override; virtual void setVisible(bool f) override; + virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual bool isSpannerSegment() const override { return true; } + virtual QString accessibleInfo() override; }; //---------------------------------------------------------------------------------- @@ -178,6 +181,8 @@ class Spanner : public Element { virtual Element* nextElement() override; virtual Element* prevElement() override; + virtual bool isSpanner() const override { return true; } + friend class SpannerSegment; }; diff --git a/libmscore/tempotext.cpp b/libmscore/tempotext.cpp index fdd7f76a59..3ecadf15fa 100644 --- a/libmscore/tempotext.cpp +++ b/libmscore/tempotext.cpp @@ -252,5 +252,31 @@ void TempoText::layout() } } +QString TempoText::accessibleInfo() + { + TDuration t; + int len; + int x = findTempoDuration(text(), len, t); + QString dots; + + switch (t.dots()) { + case 1: dots = tr("Dotted"); + break; + case 2: dots = tr("Double dotted"); + break; + case 3: dots = tr("Triple dotted"); + break; + default: + dots = ""; + break; + } + + QString bpm = text().split(" = ").back(); + if(x != -1) + return Element::accessibleInfo() + dots + " " + t.durationTypeUserName() + " " + tr("note = %1").arg(bpm); + else + return Text::accessibleInfo(); + } + } diff --git a/libmscore/tempotext.h b/libmscore/tempotext.h index 27b572740f..f71b714b43 100644 --- a/libmscore/tempotext.h +++ b/libmscore/tempotext.h @@ -60,6 +60,7 @@ class TempoText : public Text { QVariant getProperty(P_ID propertyId) const override; bool setProperty(P_ID propertyId, const QVariant&) override; QVariant propertyDefault(P_ID id) const override; + virtual QString accessibleInfo() override; }; diff --git a/libmscore/text.cpp b/libmscore/text.cpp index f7f16c3613..489031b741 100644 --- a/libmscore/text.cpp +++ b/libmscore/text.cpp @@ -2504,5 +2504,38 @@ QString Text::convertToHtml(const QString& s, const TextStyle& st) QString family = st.family(); return QString("%3").arg(family).arg(size).arg(s); } + +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Text::accessibleInfo() + { + QString rez; + switch (textStyleType()) { + case TextStyleType::TITLE: + rez = tr ("Title"); + break; + case TextStyleType::SUBTITLE: + rez = tr ("Subtitle"); + break; + case TextStyleType::COMPOSER: + rez = tr("Composer"); + break; + case TextStyleType::POET: + rez = tr ("Poet"); + break; + case TextStyleType::TRANSLATOR: + rez = tr ("Translator"); + break; + case TextStyleType::MEASURE_NUMBER: + rez = tr ("Measure number"); + break; + default: + rez = Element::accessibleInfo(); + break; + } + return rez + " " + text(); + } } diff --git a/libmscore/text.h b/libmscore/text.h index a975e74a74..3f40646086 100644 --- a/libmscore/text.h +++ b/libmscore/text.h @@ -303,6 +303,7 @@ class Text : public Element { static QString convertToHtml(const QString&, const TextStyle&); void undoSetText(const QString& s) { undoChangeProperty(P_ID::TEXT, s); } + virtual QString accessibleInfo() override; }; diff --git a/libmscore/timesig.cpp b/libmscore/timesig.cpp index 6cbb19c611..f1f433c552 100644 --- a/libmscore/timesig.cpp +++ b/libmscore/timesig.cpp @@ -565,5 +565,23 @@ Element* TimeSig::prevElement() return segment()->lastInPrevSegments(staffIdx()); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString TimeSig::accessibleInfo() + { + QString timeSigString; + switch (timeSigType()) { + case TimeSigType::FOUR_FOUR: + timeSigString = tr("Common time"); + case TimeSigType::ALLA_BREVE: + timeSigString = tr("Cut time"); + default: + timeSigString = tr("%1/%2 time").arg(QString::number(numerator())).arg(QString::number(denominator())); + } + return Element::accessibleInfo() + " " + timeSigString; + } + } diff --git a/libmscore/timesig.h b/libmscore/timesig.h index 4a574d06eb..4df50595a3 100644 --- a/libmscore/timesig.h +++ b/libmscore/timesig.h @@ -137,9 +137,9 @@ class TimeSig : public Element { virtual Element* nextElement(); virtual Element* prevElement(); + virtual QString accessibleInfo() override; }; - } // namespace Ms #endif diff --git a/libmscore/tremolo.cpp b/libmscore/tremolo.cpp index cf28fa2263..8412458878 100644 --- a/libmscore/tremolo.cpp +++ b/libmscore/tremolo.cpp @@ -338,10 +338,23 @@ Fraction Tremolo::tremoloLen() const return f; } +//--------------------------------------------------------- +// subtypeName +//--------------------------------------------------------- + QString Tremolo::subtypeName() const { return tremoloName[subtype() - int(TremoloType::R8)]; } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Tremolo::accessibleInfo() + { + return Element::accessibleInfo() + " " + subtypeName(); + } + } diff --git a/libmscore/tremolo.h b/libmscore/tremolo.h index 6cec87d256..f38f2581fd 100644 --- a/libmscore/tremolo.h +++ b/libmscore/tremolo.h @@ -78,6 +78,8 @@ class Tremolo : public Element { Fraction tremoloLen() const; bool twoNotes() const { return tremoloType() > TremoloType::R64; } // is it a two note tremolo? int lines() const { return _lines; } + + virtual QString accessibleInfo() override; }; diff --git a/libmscore/trill.cpp b/libmscore/trill.cpp index 83ee6b8826..41f55d6dcd 100644 --- a/libmscore/trill.cpp +++ b/libmscore/trill.cpp @@ -23,6 +23,20 @@ namespace Ms { + +// must be in sync with Trill::Type +const TrillTableItem trillTable[] = { + { Trill::Type::TRILL_LINE, "trill", QObject::tr("Trill line") }, + { Trill::Type::UPPRALL_LINE, "upprall", QObject::tr("Upprall line") }, + { Trill::Type::DOWNPRALL_LINE, "downprall", QObject::tr("Downprall line") }, + { Trill::Type::PRALLPRALL_LINE, "prallprall", QObject::tr("Prallprall line") }, + { Trill::Type::PURE_LINE , "pure", QObject::tr("Wavy line") } +}; + +int trillTableSize() { + return sizeof(trillTable)/sizeof(TrillTableItem); + } + //--------------------------------------------------------- // draw //--------------------------------------------------------- @@ -414,6 +428,15 @@ QString Trill::trillTypeName() const } } +//--------------------------------------------------------- +// trillTypeName +//--------------------------------------------------------- + +QString Trill::trillTypeUserName() + { + return trillTable[static_cast(trillType())].userName; + } + //--------------------------------------------------------- // scanElements //--------------------------------------------------------- @@ -493,5 +516,13 @@ void Trill::setYoff(qreal val) rUserYoffset() += (val - score()->styleS(StyleIdx::trillY).val()) * spatium(); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Trill::accessibleInfo() + { + return Element::accessibleInfo() + " " + trillTypeUserName(); + } } diff --git a/libmscore/trill.h b/libmscore/trill.h index 79708863a3..4997097329 100644 --- a/libmscore/trill.h +++ b/libmscore/trill.h @@ -92,6 +92,7 @@ class Trill : public SLine { void setTrillType(Type tt) { _trillType = tt; } Type trillType() const { return _trillType; } QString trillTypeName() const; + QString trillTypeUserName(); Accidental* accidental() const { return _accidental; } void setAccidental(Accidental* a) { _accidental = a; } @@ -102,8 +103,18 @@ class Trill : public SLine { virtual bool setProperty(P_ID propertyId, const QVariant&) override; virtual QVariant propertyDefault(P_ID) const override; virtual void setYoff(qreal) override; + + virtual QString accessibleInfo() override; }; +struct TrillTableItem { + Trill::Type type; + const char* name; + QString userName; + }; + +extern const TrillTableItem trillTable[]; +extern int trillTableSize(); } // namespace Ms diff --git a/libmscore/volta.cpp b/libmscore/volta.cpp index b48968dad9..829003f490 100644 --- a/libmscore/volta.cpp +++ b/libmscore/volta.cpp @@ -412,5 +412,12 @@ void Volta::reset() TextLine::reset(); } +//--------------------------------------------------------- +// accessibleInfo +//--------------------------------------------------------- + +QString Volta::accessibleInfo(){ + return Element::accessibleInfo() + " " + text(); + } } diff --git a/libmscore/volta.h b/libmscore/volta.h index d92653dee4..2cb216cc25 100644 --- a/libmscore/volta.h +++ b/libmscore/volta.h @@ -97,6 +97,7 @@ private: virtual void setYoff(qreal); virtual void reset() override; virtual bool systemFlag() const override { return true; } + virtual QString accessibleInfo() override; }; } // namespace Ms diff --git a/mscore/CMakeLists.txt b/mscore/CMakeLists.txt index b6c356bc11..16fec05b70 100644 --- a/mscore/CMakeLists.txt +++ b/mscore/CMakeLists.txt @@ -152,8 +152,7 @@ QT4_WRAP_CPP (mocs paletteBoxButton.h pathlistdialog.h exampleview.h noteGroups.h inspector/inspectorTextLine.h importmidi_panel.h importmidi_delegate.h importmidi_view.h debugger/debugger.h - resourceManager.h downloadUtils.h accessibletoolbutton.h - + resourceManager.h downloadUtils.h accessibletoolbutton.h scoreaccessibility.h ${OMR_MOCS} ${SCRIPT_MOCS} ) @@ -278,7 +277,7 @@ add_executable ( ${ExecutableName} importmidi_simplify.cpp importmidi_voice.cpp importmidi_view.cpp resourceManager.cpp downloadUtils.cpp textcursor.cpp - continuouspanel.cpp accessibletoolbutton.cpp + continuouspanel.cpp accessibletoolbutton.cpp scoreaccessibility.cpp ${OMR_FILES} ${AUDIO} diff --git a/mscore/fotomode.cpp b/mscore/fotomode.cpp index c65a85583c..9de8b753e0 100644 --- a/mscore/fotomode.cpp +++ b/mscore/fotomode.cpp @@ -402,10 +402,10 @@ void ScoreView::doDragFoto(QMouseEvent* ev) QRectF rr(_foto->rect()); r = _matrix.mapRect(rr); QSize sz(r.size().toSize()); - mscore->statusBar()->showMessage(QString("%1 x %2").arg(sz.width()).arg(sz.height()), 3000); + //mscore->statusBar()->showMessage(QString("%1 x %2").arg(sz.width()).arg(sz.height()), 3000); update(); - mscore->showMessage("drag", 2000); + //mscore->showMessage("drag", 2000); } //--------------------------------------------------------- diff --git a/mscore/menus.cpp b/mscore/menus.cpp index 3ec0f4a9c8..6d00d8f326 100644 --- a/mscore/menus.cpp +++ b/mscore/menus.cpp @@ -292,23 +292,10 @@ Palette* MuseScore::newBarLinePalette() sp->setGrid(42, 38); // bar line styles - struct { - BarLineType type; - const char* name; - } t[] = { - { BarLineType::NORMAL, QT_TRANSLATE_NOOP("Palette", "Normal") }, - { BarLineType::BROKEN, QT_TRANSLATE_NOOP("Palette", "Dashed style") }, - { BarLineType::DOTTED, QT_TRANSLATE_NOOP("Palette", "Dotted style") }, - { BarLineType::END, QT_TRANSLATE_NOOP("Palette", "End Bar style") }, - { BarLineType::DOUBLE, QT_TRANSLATE_NOOP("Palette", "Double Bar style") }, - { BarLineType::START_REPEAT, QT_TRANSLATE_NOOP("Palette", "Start Repeat") }, - { BarLineType::END_REPEAT, QT_TRANSLATE_NOOP("Palette", "End Repeat") }, - { BarLineType::END_START_REPEAT, QT_TRANSLATE_NOOP("Palette", "End-Start Repeat") }, - }; - for (unsigned i = 0; i < sizeof(t)/sizeof(*t); ++i) { + for (unsigned i = 0; i < barLineTableSize(); ++i) { BarLine* b = new BarLine(gscore); - b->setBarLineType(t[i].type); - sp->append(b, t[i].name); + b->setBarLineType(barLineTable[i].type); + sp->append(b, barLineTable[i].name); } // bar line spans @@ -346,57 +333,21 @@ Palette* MuseScore::newRepeatsPalette() RepeatMeasure* rm = new RepeatMeasure(gscore); sp->append(rm, tr("Repeat measure sign")); - Marker* mk = new Marker(gscore); - mk->setMarkerType(Marker::Type::SEGNO); - sp->append(mk, tr("Segno")); + for (int i = 0; i < markerTypeTableSize(); i++) { + if(markerTypeTable[i].type == Marker::Type::CODETTA) //not in smufl + continue; - mk = new Marker(gscore); - mk->setMarkerType(Marker::Type::VARSEGNO); - sp->append(mk, tr("Segno Variation")); + Marker* mk = new Marker(gscore); + mk->setMarkerType(markerTypeTable[i].type); + sp->append(mk, markerTypeTable[i].name); + } - mk = new Marker(gscore); - mk->setMarkerType(Marker::Type::CODA); - sp->append(mk, tr("Coda")); + for (int i = 0; i < jumpTypeTableSize(); i++) { + Jump* jp = new Jump(gscore); + jp->setJumpType(jumpTypeTable[i].type); + sp->append(jp, jumpTypeTable[i].userText); + } - mk = new Marker(gscore); - mk->setMarkerType(Marker::Type::VARCODA); - sp->append(mk, tr("Varied coda")); - -/* mk = new Marker(gscore); // not in smufl - mk->setMarkerType(Marker::Type::CODETTA); - sp->append(mk, tr("Codetta")); - */ - mk = new Marker(gscore); - mk->setMarkerType(Marker::Type::FINE); - sp->append(mk, tr("Fine")); - - Jump* jp = new Jump(gscore); - jp->setJumpType(Jump::Type::DC); - sp->append(jp, tr("Da Capo")); - - jp = new Jump(gscore); - jp->setJumpType(Jump::Type::DC_AL_FINE); - sp->append(jp, tr("Da Capo al Fine")); - - jp = new Jump(gscore); - jp->setJumpType(Jump::Type::DC_AL_CODA); - sp->append(jp, tr("Da Capo al Coda")); - - jp = new Jump(gscore); - jp->setJumpType(Jump::Type::DS_AL_CODA); - sp->append(jp, tr("D.S. al Coda")); - - jp = new Jump(gscore); - jp->setJumpType(Jump::Type::DS_AL_FINE); - sp->append(jp, tr("D.S. al Fine")); - - jp = new Jump(gscore); - jp->setJumpType(Jump::Type::DS); - sp->append(jp, tr("D.S.")); - - mk = new Marker(gscore); - mk->setMarkerType(Marker::Type::TOCODA); - sp->append(mk, tr("To Coda")); return sp; } @@ -629,12 +580,6 @@ Palette* MuseScore::newArpeggioPalette() } //fall and doits - const char* scorelineNames[] = { - QT_TR_NOOP("fall"), - QT_TR_NOOP("doit"), - QT_TR_NOOP("plop"), - QT_TR_NOOP("scoop"), - }; ChordLine* cl = new ChordLine(gscore); cl->setChordLineType(ChordLineType::FALL); @@ -879,29 +824,13 @@ Palette* MuseScore::newLinesPalette() pedal->setEndHook(true); sp->append(pedal, QT_TRANSLATE_NOOP("Palette", "Pedal")); - Trill* trill = new Trill(gscore); - trill->setLen(w); - sp->append(trill, QT_TRANSLATE_NOOP("Palette", "Trill line")); - trill = new Trill(gscore); - trill->setTrillType("upprall"); - trill->setLen(w); - sp->append(trill, QT_TRANSLATE_NOOP("Palette", "Upprall line")); - - trill = new Trill(gscore); - trill->setTrillType("downprall"); - trill->setLen(w); - sp->append(trill, QT_TRANSLATE_NOOP("Palette", "Downprall line")); - - trill = new Trill(gscore); - trill->setTrillType("prallprall"); - trill->setLen(w); - sp->append(trill, QT_TRANSLATE_NOOP("Palette", "Prallprall line")); - - trill = new Trill(gscore); - trill->setTrillType("pure"); - trill->setLen(w); - sp->append(trill, QT_TRANSLATE_NOOP("Palette", "Wavy line")); + for (int i = 0; i < trillTableSize(); i++) { + Trill* trill = new Trill(gscore); + trill->setTrillType(trillTable[i].type); + trill->setLen(w); + sp->append(trill, trillTable[i].userName); + } TextLine* textLine = new TextLine(gscore); textLine->setLen(w); diff --git a/mscore/musescore.cpp b/mscore/musescore.cpp index 1182c28fc7..86fa68c94b 100644 --- a/mscore/musescore.cpp +++ b/mscore/musescore.cpp @@ -79,6 +79,7 @@ #include "texttools.h" #include "textpalette.h" #include "resourceManager.h" +#include "scoreaccessibility.h" #include "libmscore/mscore.h" #include "libmscore/system.h" @@ -462,7 +463,9 @@ MuseScore::MuseScore() _modeText = new QLabel; _modeText->setAutoFillBackground(false); _modeText->setObjectName("modeLabel"); + _statusBar = new QStatusBar; + hRasterAction = getAction("hraster"); hRasterAction->setCheckable(true); vRasterAction = getAction("vraster"); @@ -508,6 +511,7 @@ MuseScore::MuseScore() _statusBar->addPermanentWidget(_positionLabel, 0); setStatusBar(_statusBar); + ScoreAccessibility::createInstance(this); _progressBar = 0; @@ -1613,9 +1617,10 @@ void MuseScore::setCurrentScoreView(ScoreView* view) a->setChecked(cs->styleB(StyleIdx::concertPitch)); setPos(cs->inputPos()); - showMessage(cs->filePath(), 2000); + //showMessage(cs->filePath(), 2000); if (_navigator && _navigator->widget()) navigator()->setScoreView(view); + ScoreAccessibility::instance()->updateAccessibilityInfo(); } //--------------------------------------------------------- @@ -2413,7 +2418,7 @@ bool MuseScoreApplication::event(QEvent *event) paths.append(static_cast(event)->file()); return true; default: - return QApplication::event(event); + return QtSingleApplication::event(event); } } @@ -2431,7 +2436,7 @@ bool MuseScore::eventFilter(QObject *obj, QEvent *event) handleMessage(static_cast(event)->file()); return true; default: - return QObject::eventFilter(obj, event); + return QMainWindow::eventFilter(obj, event); } } @@ -2779,7 +2784,9 @@ void MuseScore::readSettings() mainWindow->setOpaqueResize(false); move(settings.value("pos", QPoint(10, 10)).toPoint()); - if (settings.value("maximized", false).toBool()) + //for some reason when MuseScore starts maximized the screen-reader + //doesn't respond to QAccessibleEvents + if (settings.value("maximized", false).toBool() && !QAccessible::isActive()) showMaximized(); mscore->showPalette(settings.value("showPanel", "1").toBool()); mscore->showInspector(settings.value("showInspector", "0").toBool()); @@ -4003,6 +4010,7 @@ void MuseScore::endCmd() if (e == 0 && cs->noteEntryMode()) e = cs->inputState().cr(); cs->end(); + ScoreAccessibility::instance()->updateAccessibilityInfo(); } else { if (inspector) @@ -4553,6 +4561,8 @@ namespace Ms { using namespace Ms; + + //--------------------------------------------------------- // main //--------------------------------------------------------- @@ -4577,6 +4587,7 @@ int main(int argc, char* av[]) QCoreApplication::setOrganizationName("MuseScore"); QCoreApplication::setOrganizationDomain("musescore.org"); QCoreApplication::setApplicationName("MuseScoreDevelopment"); + QAccessible::installFactory(AccessibleScoreView::ScoreViewFactory); Q_INIT_RESOURCE(zita); Q_INIT_RESOURCE(noeffect); // Q_INIT_RESOURCE(freeverb); @@ -5021,6 +5032,7 @@ int main(int argc, char* av[]) break; } } + return qApp->exec(); } diff --git a/mscore/scoreaccessibility.cpp b/mscore/scoreaccessibility.cpp new file mode 100644 index 0000000000..b5f9ab2103 --- /dev/null +++ b/mscore/scoreaccessibility.cpp @@ -0,0 +1,206 @@ +#include +#include +#include "scoreaccessibility.h" +#include "musescore.h" +#include "libmscore/segment.h" +#include "libmscore/timesig.h" +#include "libmscore/score.h" +#include "libmscore/measure.h" +#include "inspector/inspector.h" + +namespace Ms{ +AccessibleScoreView::AccessibleScoreView(ScoreView* scView) : QAccessibleWidget(scView){ + s = scView; + } + +int AccessibleScoreView::childCount() const{ + return 0; + } + +QAccessibleInterface* AccessibleScoreView::child(int /*index*/) const{ + return 0; + } +QAccessibleInterface* AccessibleScoreView::parent() const{ + return QAccessibleWidget::parent(); + } +QRect AccessibleScoreView::rect() const{ + return s->rect(); + } +QAccessible::Role AccessibleScoreView::role() const{ + return QAccessible::NoRole; + } + +QString AccessibleScoreView::text(QAccessible::Text t) const { + switch (t) { + case QAccessible::Name: + return tr("Score %1").arg(s->score()->name()); + case QAccessible::Value: + return s->score()->accessibleInfo(); + default: + return QString(); + } + return QString(); + } + +QWindow* AccessibleScoreView::window() const { + return qApp->focusWindow(); + } + +QAccessibleInterface* AccessibleScoreView::ScoreViewFactory(const QString &classname, QObject *object) + { + QAccessibleInterface *iface = 0; + if (classname == QLatin1String("Ms::ScoreView") && object && object->isWidgetType()){ + qDebug("Creating interface for ScoreView object"); + iface = static_cast(new AccessibleScoreView(static_cast(object))); + } + + return iface; + } + + +ScoreAccessibility* ScoreAccessibility::inst = 0; + +ScoreAccessibility::ScoreAccessibility(QMainWindow* mainWindow) : QObject(mainWindow) + { + this->mainWindow = mainWindow; + statusBarLabel = 0; + } + +void ScoreAccessibility::createInstance(QMainWindow* mainWindow) + { + if (!inst) { + inst = new ScoreAccessibility(mainWindow); + } + } + +ScoreAccessibility::~ScoreAccessibility() + { + } + +void ScoreAccessibility::clearAccessibilityInfo() + { + if(statusBarLabel != 0) { + mainWindow->statusBar()->removeWidget(statusBarLabel); + delete statusBarLabel; + statusBarLabel = 0; + static_cast(mainWindow)->currentScoreView()->score()->setAccessibleInfo(tr("No selection")); + } + } + +void ScoreAccessibility::currentInfoChanged() + { + clearAccessibilityInfo(); + statusBarLabel = new QLabel(mainWindow->statusBar()); + ScoreView* scoreView = static_cast(mainWindow)->currentScoreView(); + Score* score = scoreView->score(); + if (score->selection().isSingle()) { + Element* e = score->selection().element(); + if (!e) { + return; + } + Element* el = e->isSpannerSegment() ? static_cast(e)->spanner() : e; + QString barsAndBeats = ""; + std::pair bar_beat; + if (el->isSpanner()){ + Spanner* s = static_cast(el); + bar_beat = barbeat(s->startSegment()); + barsAndBeats += tr("Start Bar: %1").arg(QString::number(bar_beat.first)) + " " + tr("Start Beat: %1").arg(QString::number(bar_beat.second)); + Segment* seg = s->endSegment(); + if(!seg) + seg = score->lastSegment()->prev1MM(Segment::Type::ChordRest); + + if (seg->tick() != score->lastSegment()->prev1MM(Segment::Type::ChordRest)->tick() && + s->type() != Element::Type::SLUR && + s->type() != Element::Type::TIE ) + seg = seg->prev1MM(Segment::Type::ChordRest); + + bar_beat = barbeat(seg); + barsAndBeats += " " + tr("End Bar: %1").arg(QString::number(bar_beat.first)) + " " + tr("End Beat: %1").arg(QString::number(bar_beat.second)); + } + else { + std::pairbar_beat = barbeat(el); + if (bar_beat.first) { + barsAndBeats += " " + tr("Bar: %1").arg(QString::number(bar_beat.first)); + if (bar_beat.second) + barsAndBeats += " " + tr("Beat: %1").arg(QString::number(bar_beat.second)); + } + } + + statusBarLabel->setText(e->accessibleInfo() + barsAndBeats); + score->setAccessibleInfo(e->screenReaderInfo() + barsAndBeats + " " + e->accessibleExtraInfo()); + } + else if (score->selection().isRange()) { + QString barsAndBeats = ""; + std::pair bar_beat; + + bar_beat = barbeat(score->selection().startSegment()); + barsAndBeats += " " + tr("Start Bar: %1").arg(QString::number(bar_beat.first)) + " " + tr("Start Beat: %1").arg(QString::number(bar_beat.second)); + Segment* endSegment = score->selection().endSegment(); + + if (!endSegment) + endSegment = score->lastSegment(); + else + endSegment = endSegment->prev1MM(); + + bar_beat = barbeat(endSegment); + barsAndBeats += " " + tr("End Bar: %1").arg(QString::number(bar_beat.first)) + " " + tr("End Beat: %1").arg(QString::number(bar_beat.second)); + statusBarLabel->setText(tr("Range Selection") + barsAndBeats); + score->setAccessibleInfo(tr("Range Selection") + barsAndBeats); + } + else if (score->selection().isList()) { + statusBarLabel->setText(tr("List Selection")); + score->setAccessibleInfo(tr("List Selection")); + } + mainWindow->statusBar()->addWidget(statusBarLabel); + } + +ScoreAccessibility* ScoreAccessibility::instance() + { + return inst; + } + +void ScoreAccessibility::updateAccessibilityInfo() + { + currentInfoChanged(); + ScoreView* w = static_cast(mainWindow)->currentScoreView(); + + //getInspector->isAncestorOf is used so that inspector doesn't lose focus + //when this method is called + if ( (qApp->focusWidget() != w) && !mscore->getInspector()->isAncestorOf(qApp->focusWidget())) { + w->setFocus(); + } + QObject* obj = static_cast(w); + QAccessibleValueChangeEvent ev(obj, w->score()->accessibleInfo()); + QAccessible::updateAccessibility(&ev); + } + +std::pair ScoreAccessibility::barbeat(Element *e) + { + if (!e) { + return std::pair(0, 0); + } + + int bar; + int beat; + int ticks; + TimeSigMap* tsm = e->score()->sigmap(); + Element* p = e; + while(p && p->type() != Element::Type::SEGMENT && p->type() != Element::Type::MEASURE) + p = p->parent(); + + if (!p) { + return std::pair(0, 0); + } + else if (p->type() == Element::Type::SEGMENT) { + Segment* seg = static_cast(p); + tsm->tickValues(seg->tick(), &bar, &beat, &ticks); + } + else if (p->type() == Element::Type::MEASURE) { + Measure* m = static_cast(p); + bar = m->no(); + beat = -1; + ticks = 0; + } + return pair(bar + 1, beat + 1 + ticks / static_cast(MScore::division)); + } +} diff --git a/mscore/scoreaccessibility.h b/mscore/scoreaccessibility.h new file mode 100644 index 0000000000..de2313de8e --- /dev/null +++ b/mscore/scoreaccessibility.h @@ -0,0 +1,45 @@ +#ifndef __SCORE_ACCESSIBILITY__ +#define __SCORE_ACCESSIBILITY__ + +#include +#include +#include +#include "scoreview.h" + +namespace Ms { +class AccessibleScoreView : public QAccessibleWidget { +public: + AccessibleScoreView(ScoreView* c); + int childCount() const Q_DECL_OVERRIDE; + QAccessibleInterface* child(int /*index*/) const Q_DECL_OVERRIDE; + QAccessibleInterface* parent() const Q_DECL_OVERRIDE; + QRect rect() const Q_DECL_OVERRIDE; + QAccessible::Role role() const Q_DECL_OVERRIDE; + QString text(QAccessible::Text t) const Q_DECL_OVERRIDE; + QWindow* window() const Q_DECL_OVERRIDE; + static QAccessibleInterface* ScoreViewFactory(const QString &classname, QObject *object); +private: + ScoreView* s; + }; + +class ScoreAccessibility : public QObject { + Q_OBJECT +private: + static ScoreAccessibility* inst; + QMainWindow* mainWindow; + QLabel* statusBarLabel; + ScoreAccessibility(QMainWindow* statusBar); + std::pairbarbeat(Element* e); + +public: + ~ScoreAccessibility(); + void updateAccessibilityInfo(); + void clearAccessibilityInfo(); + static void createInstance(QMainWindow* statusBar); + static ScoreAccessibility* instance(); + void currentInfoChanged(); + }; + +} + +#endif diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index 80cd3d1f59..11c55f8758 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -2482,8 +2482,9 @@ void ScoreView::cmd(const QAction* a) if (MScore::debugMode) qDebug("ScoreView::cmd <%s>", qPrintable(cmd)); - if (cmd == "escape") + if (cmd == "escape") { sm->postEvent(new CommandEvent(cmd)); + } else if (cmd == "note-input" || cmd == "copy" || cmd == "paste" || cmd == "cut" || cmd == "fotomode") { sm->postEvent(new CommandEvent(cmd));