Score accessibility system.

Provides screen-reader feedback for the selected element.
This commit is contained in:
Andrei Tuicu 2014-07-10 15:13:37 +03:00
parent 6377816fa7
commit 6460485d3f
73 changed files with 1242 additions and 164 deletions

View file

@ -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()));
}
}

View file

@ -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);

View file

@ -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()));
}
}

View file

@ -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;

View file

@ -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();
}
}

View file

@ -134,8 +134,9 @@ class Articulation : public Element {
_articulationType == ArticulationType::Shortfermata ||
_articulationType == ArticulationType::Longfermata ||
_articulationType == ArticulationType::Verylongfermata; }
};
QString accessibleInfo() override;
};
} // namespace Ms
#endif

View file

@ -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<Segment*>(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<Marker*>(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<Marker*>(e)->markerType() == Marker::Type::FINE)
continue; //added above^
rez += " " + e->screenReaderInfo();
}
}
}
int tick = seg->tick();
SpannerMap smap = score()->spannerMap();
std::vector< ::Interval<Spanner*> > spanners = smap.findOverlapping(tick, tick);
for (std::vector< ::Interval<Spanner*> >::iterator i = spanners.begin(); i < spanners.end(); i++) {
::Interval<Spanner*> 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();
}
}

View file

@ -113,6 +113,8 @@ 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; }
@ -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

View file

@ -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");
}
}
}

View file

@ -52,6 +52,7 @@ class Breath : public Element {
virtual Element* nextElement() override;
virtual Element* prevElement() override;
virtual QString accessibleInfo() override;
};

View file

@ -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();
}
}

View file

@ -213,8 +213,10 @@ class Chord : public ChordRest {
void sortNotes();
virtual Element* nextElement() override;
virtual Element* prevElement() override;
virtual QString accessibleExtraInfo() override;
};

View file

@ -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<int>(chordLineType()) - 1];
return rez;
}
}

View file

@ -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

View file

@ -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<Spanner*> > spanners = smap.findOverlapping(tick(), tick());
for (std::vector< ::Interval<Spanner*> >::iterator i = spanners.begin(); i < spanners.end(); i++) {
::Interval<Spanner*> 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;
}
}

View file

@ -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;
};

View file

@ -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());
}
}

View file

@ -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

View file

@ -516,29 +516,28 @@ QList<TDuration> 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;
}
//---------------------------------------------------------

View file

@ -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<TDuration> toDurationList(

View file

@ -440,5 +440,14 @@ QVariant Dynamic::propertyDefault(P_ID id) const
}
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
QString Dynamic::accessibleInfo()
{
return Element::accessibleInfo() + " " + this->dynamicTypeName();
}
}

View file

@ -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

View file

@ -1943,4 +1943,13 @@ Element* Element::prevElement()
}
return score()->firstElement();
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
QString Element::accessibleInfo()
{
return userName();
}
}

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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;
};

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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;
};

View file

@ -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<int>(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();
}
}

View file

@ -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);

View file

@ -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<int>(key());
if (keyInt < 0)
keySigType = keyNames[(7 + keyInt) * 2 + 1];
else
keySigType = keyNames[(keyInt - 1) * 2];
return Element::accessibleInfo() + " " + keySigType;
}
}

View file

@ -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

View file

@ -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<int>(_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();
}
}

View file

@ -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);

View file

@ -4038,5 +4038,14 @@ Element* Measure::prevElement(int staff)
return score()->lastElement();
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
QString Measure::accessibleInfo()
{
return Element::accessibleInfo() + " " + QString::number(no() + 1);
}
}

View file

@ -323,6 +323,7 @@ class Measure : public MeasureBase {
Element* nextElement(int staff);
Element* prevElement(int staff);
virtual QString accessibleInfo() override;
};
} // namespace Ms

View file

@ -9,7 +9,8 @@
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include <QLabel>
#include <QList>
/**
\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
//---------------------------------------------------------

View file

@ -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)];

View file

@ -540,5 +540,14 @@ void Ottava::reset()
TextLine::reset();
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
QString Ottava::accessibleInfo()
{
return Element::accessibleInfo() + " " + ottavaDefault[static_cast<int>(ottavaType())].name;
}
}

View file

@ -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

View file

@ -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 = "";

View file

@ -60,8 +60,8 @@ extern void spell(QList<Event>& notes, int);
extern void spell(QList<Note*>& notes);
extern int computeWindow(const QList<Note*>& 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);

View file

@ -78,5 +78,14 @@ Fraction RepeatMeasure::duration() const
return Fraction(0, 1);
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
QString RepeatMeasure::accessibleInfo()
{
return Element::accessibleInfo();
}
}

View file

@ -38,6 +38,8 @@ class RepeatMeasure : public Rest {
virtual void draw(QPainter*) const;
virtual void layout();
virtual Fraction duration() const;
virtual QString accessibleInfo();
};

View file

@ -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 ;
}
}

View file

@ -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

View file

@ -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<ChordRest*>(e)->segment());

View file

@ -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;

View file

@ -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<Spanner*> > spanners = smap.findOverlapping(this->tick(), this->tick());
for (std::vector< ::Interval<Spanner*> >::iterator i = spanners.begin(); i < spanners.end(); i++) {
::Interval<Spanner*> 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

View file

@ -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

View file

@ -190,6 +190,15 @@ Element* SpannerSegment::prevElement()
return spanner()->prevElement();
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
QString SpannerSegment::accessibleInfo()
{
return spanner()->accessibleInfo();
}
//---------------------------------------------------------
// Spanner
//---------------------------------------------------------

View file

@ -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;
};

View file

@ -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();
}
}

View file

@ -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;
};

View file

@ -2504,5 +2504,38 @@ QString Text::convertToHtml(const QString& s, const TextStyle& st)
QString family = st.family();
return QString("<html><body style=\"font-family:'%1'; font-size:%2pt;\">%3</body></html>").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();
}
}

View file

@ -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;
};

View file

@ -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;
}
}

View file

@ -137,9 +137,9 @@ class TimeSig : public Element {
virtual Element* nextElement();
virtual Element* prevElement();
virtual QString accessibleInfo() override;
};
} // namespace Ms
#endif

View file

@ -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();
}
}

View file

@ -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;
};

View file

@ -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<int>(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();
}
}

View file

@ -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

View file

@ -412,5 +412,12 @@ void Volta::reset()
TextLine::reset();
}
//---------------------------------------------------------
// accessibleInfo
//---------------------------------------------------------
QString Volta::accessibleInfo(){
return Element::accessibleInfo() + " " + text();
}
}

View file

@ -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

View file

@ -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}

View file

@ -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);
}
//---------------------------------------------------------

View file

@ -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"));
for (int i = 0; i < markerTypeTableSize(); i++) {
if(markerTypeTable[i].type == Marker::Type::CODETTA) //not in smufl
continue;
Marker* mk = new Marker(gscore);
mk->setMarkerType(Marker::Type::SEGNO);
sp->append(mk, tr("Segno"));
mk = new Marker(gscore);
mk->setMarkerType(Marker::Type::VARSEGNO);
sp->append(mk, tr("Segno Variation"));
mk = new Marker(gscore);
mk->setMarkerType(Marker::Type::CODA);
sp->append(mk, tr("Coda"));
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"));
mk->setMarkerType(markerTypeTable[i].type);
sp->append(mk, markerTypeTable[i].name);
}
for (int i = 0; i < jumpTypeTableSize(); i++) {
Jump* jp = new Jump(gscore);
jp->setJumpType(Jump::Type::DC);
sp->append(jp, tr("Da Capo"));
jp->setJumpType(jumpTypeTable[i].type);
sp->append(jp, jumpTypeTable[i].userText);
}
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"));
for (int i = 0; i < trillTableSize(); i++) {
Trill* trill = new Trill(gscore);
trill->setTrillType(trillTable[i].type);
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"));
sp->append(trill, trillTable[i].userName);
}
TextLine* textLine = new TextLine(gscore);
textLine->setLen(w);

View file

@ -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<QFileOpenEvent *>(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<QFileOpenEvent *>(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();
}

View file

@ -0,0 +1,206 @@
#include <QMainWindow>
#include <QWidget>
#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<QAccessibleInterface*>(new AccessibleScoreView(static_cast<ScoreView*>(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<MuseScore*>(mainWindow)->currentScoreView()->score()->setAccessibleInfo(tr("No selection"));
}
}
void ScoreAccessibility::currentInfoChanged()
{
clearAccessibilityInfo();
statusBarLabel = new QLabel(mainWindow->statusBar());
ScoreView* scoreView = static_cast<MuseScore*>(mainWindow)->currentScoreView();
Score* score = scoreView->score();
if (score->selection().isSingle()) {
Element* e = score->selection().element();
if (!e) {
return;
}
Element* el = e->isSpannerSegment() ? static_cast<SpannerSegment*>(e)->spanner() : e;
QString barsAndBeats = "";
std::pair<int, float> bar_beat;
if (el->isSpanner()){
Spanner* s = static_cast<Spanner*>(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::pair<int, float>bar_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<int, float> 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<MuseScore*>(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<QObject*>(w);
QAccessibleValueChangeEvent ev(obj, w->score()->accessibleInfo());
QAccessible::updateAccessibility(&ev);
}
std::pair<int, float> ScoreAccessibility::barbeat(Element *e)
{
if (!e) {
return std::pair<int, float>(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<int, float>(0, 0);
}
else if (p->type() == Element::Type::SEGMENT) {
Segment* seg = static_cast<Segment*>(p);
tsm->tickValues(seg->tick(), &bar, &beat, &ticks);
}
else if (p->type() == Element::Type::MEASURE) {
Measure* m = static_cast<Measure*>(p);
bar = m->no();
beat = -1;
ticks = 0;
}
return pair<int,float>(bar + 1, beat + 1 + ticks / static_cast<float>(MScore::division));
}
}

View file

@ -0,0 +1,45 @@
#ifndef __SCORE_ACCESSIBILITY__
#define __SCORE_ACCESSIBILITY__
#include<QStatusBar>
#include<QAccessible>
#include<QAccessibleWidget>
#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::pair<int, float>barbeat(Element* e);
public:
~ScoreAccessibility();
void updateAccessibilityInfo();
void clearAccessibilityInfo();
static void createInstance(QMainWindow* statusBar);
static ScoreAccessibility* instance();
void currentInfoChanged();
};
}
#endif

View file

@ -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));