Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 : #include "accessibleroot.h"
23 :
24 : #include "../dom/score.h"
25 : #include "../dom/staff.h"
26 : #include "../dom/part.h"
27 : #include "../dom/segment.h"
28 :
29 : #include "log.h"
30 : #include "translation.h"
31 :
32 : using namespace mu::engraving;
33 : using namespace muse::accessibility;
34 :
35 4668 : AccessibleRoot::AccessibleRoot(RootItem* e, Role role)
36 4668 : : AccessibleItem(e, role)
37 : {
38 4668 : }
39 :
40 4190 : AccessibleRoot::~AccessibleRoot()
41 : {
42 4190 : if (m_registred && accessibilityController()) {
43 0 : accessibilityController()->unreg(this);
44 0 : m_registred = false;
45 : }
46 :
47 4190 : m_element = nullptr;
48 4190 : }
49 :
50 0 : void AccessibleRoot::setFocusedElement(AccessibleItemPtr e, bool voiceStaffInfoChange)
51 : {
52 0 : if (!m_enabled) {
53 0 : return; // User is outside the score panel (e.g. in the Braille panel).
54 : }
55 :
56 0 : AccessibleItemWeakPtr old = m_focusedElement;
57 0 : updateStaffInfo(e, old, voiceStaffInfoChange);
58 :
59 0 : if (auto oldItem = old.lock()) {
60 0 : oldItem->notifyAboutFocus(false);
61 0 : }
62 :
63 0 : m_focusedElement = e;
64 0 : if (auto newItem = m_focusedElement.lock()) {
65 0 : newItem->notifyAboutFocus(true);
66 0 : }
67 0 : }
68 :
69 0 : AccessibleItemWeakPtr AccessibleRoot::focusedElement() const
70 : {
71 0 : return m_focusedElement;
72 : }
73 :
74 0 : void AccessibleRoot::notifyAboutFocusedElementNameChanged()
75 : {
76 0 : m_staffInfo = "";
77 :
78 0 : if (auto focusedElement = m_focusedElement.lock()) {
79 0 : focusedElement->accessiblePropertyChanged().send(IAccessible::Property::Name, muse::Val());
80 0 : }
81 0 : }
82 :
83 0 : RectF AccessibleRoot::toScreenRect(const RectF& rect, bool* ok) const
84 : {
85 0 : RectF result;
86 0 : if (m_accessibleMapToScreenFunc) {
87 0 : result = m_accessibleMapToScreenFunc(rect);
88 : }
89 :
90 0 : if (ok) {
91 0 : *ok = m_accessibleMapToScreenFunc != nullptr;
92 : }
93 :
94 0 : return result;
95 : }
96 :
97 0 : const IAccessible* AccessibleRoot::accessibleParent() const
98 : {
99 0 : return accessibilityController()->accessibleRoot();
100 : }
101 :
102 0 : IAccessible::Role AccessibleRoot::accessibleRole() const
103 : {
104 0 : return IAccessible::Panel;
105 : }
106 :
107 0 : QString AccessibleRoot::accessibleName() const
108 : {
109 0 : return muse::qtrc("engraving", "Score") + " " + element()->score()->name();
110 : }
111 :
112 0 : bool AccessibleRoot::enabled() const
113 : {
114 0 : return m_enabled;
115 : }
116 :
117 0 : void AccessibleRoot::setEnabled(bool enabled)
118 : {
119 0 : m_enabled = enabled;
120 0 : }
121 :
122 0 : QString AccessibleRoot::staffInfo() const
123 : {
124 0 : return m_staffInfo;
125 : }
126 :
127 0 : void AccessibleRoot::updateStaffInfo(const AccessibleItemWeakPtr newAccessibleItem, const AccessibleItemWeakPtr oldAccessibleItem,
128 : bool voiceStaffInfoChange)
129 : {
130 0 : m_staffInfo = "";
131 :
132 0 : if (!voiceStaffInfoChange) {
133 0 : return;
134 : }
135 :
136 0 : AccessibleItemPtr newItem = newAccessibleItem.lock();
137 0 : AccessibleItemPtr oldItem = oldAccessibleItem.lock();
138 :
139 0 : if (newItem && newItem->element()->hasStaff()) {
140 0 : staff_idx_t newStaffIdx = newItem->element()->staffIdx();
141 0 : staff_idx_t oldStaffIdx = oldItem ? oldItem->element()->staffIdx() : muse::nidx;
142 :
143 0 : if (newStaffIdx != oldStaffIdx) {
144 0 : auto element = newItem->element();
145 0 : QString staff = muse::qtrc("engraving", "Staff %1").arg(QString::number(element->staffIdx() + 1));
146 :
147 0 : const Part* origin = element->originPart();
148 0 : QString staffName = origin ? origin->longName(element->tick()).toQString() : QString();
149 0 : if (staffName.isEmpty() && origin) {
150 0 : staffName = origin->partName().toQString();
151 : }
152 :
153 0 : if (staffName.isEmpty()) {
154 0 : m_staffInfo = staff;
155 : } else {
156 0 : m_staffInfo = QString("%2 (%3)").arg(staff, staffName);
157 : }
158 0 : }
159 : }
160 0 : }
161 :
162 0 : void AccessibleRoot::setMapToScreenFunc(const AccessibleMapToScreenFunc& func)
163 : {
164 0 : m_accessibleMapToScreenFunc = func;
165 0 : }
166 :
167 0 : bool AccessibleRoot::isRangeSelection() const
168 : {
169 0 : return element()->score()->selection().isRange();
170 : }
171 :
172 0 : QString AccessibleRoot::rangeSelectionInfo()
173 : {
174 0 : Score* score = element()->score();
175 0 : Selection selection = score->selection();
176 0 : Segment* startSegment = selection.startSegment();
177 0 : Segment* endSegment = selection.endSegment();
178 :
179 0 : if (endSegment) {
180 : // Make end beat match status bar text
181 0 : endSegment = endSegment->prev1(SegmentType::ChordRest);
182 : }
183 :
184 0 : IF_ASSERT_FAILED(selection.isRange() && startSegment && endSegment) {
185 0 : return QString();
186 : }
187 :
188 0 : String startBarBeat = startSegment->formatBarsAndBeats();
189 0 : String endBarBeat = endSegment->formatBarsAndBeats();
190 :
191 0 : startBarBeat.remove(u';'); // Too many pauses in speech
192 0 : endBarBeat.remove(u';');
193 :
194 0 : QString staffInstrument1, staffInstrument2;
195 0 : staff_idx_t startStaff = selection.staffStart();
196 0 : staff_idx_t endStaff = selection.staffEnd() - 1;
197 :
198 0 : if (startStaff != endStaff) {
199 0 : const Staff* staff1 = score->staff(startStaff);
200 0 : const Staff* staff2 = score->staff(endStaff);
201 0 : const Part* part1 = staff1 ? staff1->originPart(startSegment->tick()) : nullptr;
202 0 : const Part* part2 = staff2 ? staff2->originPart(endSegment->tick()) : nullptr;
203 0 : if (staff1 && staff2 && part1 && part2) {
204 0 : staffInstrument1 = muse::qtrc("engraving", "Staff %1 (%2)")
205 0 : .arg(QString::number(startStaff + 1))
206 0 : .arg(staff1 ? part1->partName().toQString() : "");
207 0 : staffInstrument2 = muse::qtrc("engraving", "Staff %1 (%2)")
208 0 : .arg(QString::number(endStaff + 1))
209 0 : .arg(staff2 ? part2->partName().toQString() : "");
210 : }
211 : }
212 :
213 0 : return muse::qtrc("engraving", "Range selection starts %1%2 ends %3%4")
214 0 : .arg(startBarBeat)
215 0 : .arg(!staffInstrument1.isEmpty() ? (" " + staffInstrument1) : "")
216 0 : .arg(endBarBeat)
217 0 : .arg(!staffInstrument2.isEmpty() ? (" " + staffInstrument2) : "");
218 0 : }
|