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 :
23 : #include "bracket.h"
24 :
25 : #include "types/typesconv.h"
26 :
27 : #include "bracketitem.h"
28 : #include "instrumentname.h"
29 : #include "measure.h"
30 : #include "score.h"
31 : #include "staff.h"
32 : #include "system.h"
33 : #include "text.h"
34 :
35 : #include "log.h"
36 :
37 : using namespace mu;
38 : using namespace mu::engraving;
39 : using namespace muse::draw;
40 :
41 : //---------------------------------------------------------
42 : // Bracket
43 : //---------------------------------------------------------
44 :
45 2069 : Bracket::Bracket(DummyParentOr<EngravingItem> parent)
46 2069 : : EngravingItem(ElementType::BRACKET, parent)
47 : {
48 2069 : m_ay1 = 0;
49 2069 : m_firstStaff = 0;
50 2069 : m_lastStaff = 0;
51 2069 : m_labelType = InstrumentNameType::LONG;
52 2069 : m_bi = 0;
53 2069 : m_braceSymbol = SymId::noSym;
54 2069 : m_magx = 1.;
55 2069 : setGenerated(true); // brackets are not saved
56 2069 : }
57 :
58 3972 : Bracket::~Bracket()
59 : {
60 1986 : if (m_text) {
61 0 : delete m_text;
62 : }
63 3972 : }
64 :
65 122 : void Bracket::scanElements(std::function<void(EngravingItem*)> func)
66 : {
67 122 : if (m_text) {
68 0 : m_text->scanElements(func);
69 : }
70 :
71 122 : EngravingItem::scanElements(func);
72 122 : }
73 :
74 : //---------------------------------------------------------
75 : // setStaffSpan
76 : //---------------------------------------------------------
77 :
78 3550 : void Bracket::setStaffSpan(size_t a, size_t b)
79 : {
80 3550 : m_firstStaff = a;
81 3550 : m_lastStaff = b;
82 :
83 7100 : if (bracketType() == BracketType::BRACE
84 3550 : && style().styleSt(Sid::musicalSymbolFont) != "Emmentaler" && style().styleSt(Sid::musicalSymbolFont) != "Gonville") {
85 1721 : int v = static_cast<int>(m_lastStaff - m_firstStaff + 1);
86 :
87 : // if staves inner staves are hidden, decrease span
88 5151 : for (size_t staffIndex = m_firstStaff; staffIndex <= m_lastStaff; ++staffIndex) {
89 3430 : if (system() && !system()->staff(staffIndex)->show()) {
90 0 : --v;
91 : }
92 : }
93 :
94 1721 : if (style().styleSt(Sid::musicalSymbolFont) == "Leland") {
95 1721 : v = std::min(4, v);
96 : }
97 :
98 : // 1.625 is a "magic" number based on akkoladeDistance/4.0 (default value 6.5).
99 1721 : m_magx = v + ((v - 1) * 1.625);
100 :
101 1721 : if (v == 1) {
102 12 : m_braceSymbol = SymId::braceSmall;
103 1709 : } else if (v <= 2) {
104 1709 : m_braceSymbol = SymId::brace;
105 0 : } else if (v <= 3) {
106 0 : m_braceSymbol = SymId::braceLarge;
107 : } else {
108 0 : m_braceSymbol = SymId::braceLarger;
109 : }
110 : }
111 3550 : }
112 :
113 0 : bool Bracket::isEditable() const
114 : {
115 0 : return true;
116 : }
117 :
118 0 : bool Bracket::needStartEditingAfterSelecting() const
119 : {
120 0 : return true;
121 : }
122 :
123 : //---------------------------------------------------------
124 : // startEdit
125 : //---------------------------------------------------------
126 :
127 0 : void Bracket::startEdit(EditData& ed)
128 : {
129 0 : EngravingItem::startEdit(ed);
130 0 : m_ay1 = pagePos().y();
131 0 : }
132 :
133 : //---------------------------------------------------------
134 : // gripsPositions
135 : //---------------------------------------------------------
136 :
137 0 : std::vector<PointF> Bracket::gripsPositions(const EditData&) const
138 : {
139 0 : return { PointF(0.0, ldata()->bracketHeight()) + pagePos() };
140 : }
141 :
142 : //---------------------------------------------------------
143 : // endEdit
144 : //---------------------------------------------------------
145 :
146 0 : void Bracket::endEdit(EditData& ed)
147 : {
148 0 : triggerLayoutAll();
149 0 : ed.clear(); // score layout invalidates element
150 0 : }
151 :
152 0 : void Bracket::dragGrip(EditData& ed)
153 : {
154 0 : double bracketHeight = ldata()->bracketHeight();
155 0 : bracketHeight += ed.delta.y();
156 0 : mutldata()->bracketHeight.set_value(bracketHeight);
157 0 : }
158 :
159 : //---------------------------------------------------------
160 : // endDragGrip
161 : // snap to nearest staff
162 : //---------------------------------------------------------
163 :
164 0 : void Bracket::endDragGrip(EditData&)
165 : {
166 0 : double ay2 = m_ay1 + ldata()->bracketHeight();
167 :
168 0 : staff_idx_t staffIdx1 = staffIdx();
169 : staff_idx_t staffIdx2;
170 0 : size_t n = system()->staves().size();
171 0 : if (staffIdx1 + 1 >= n) {
172 0 : staffIdx2 = staffIdx1;
173 : } else {
174 0 : double ay = layoutParent()->pagePos().y();
175 0 : System* s = system();
176 0 : double y = s->staff(staffIdx1)->y() + ay;
177 0 : double h1 = staff()->staffHeight();
178 :
179 0 : for (staffIdx2 = staffIdx1 + 1; staffIdx2 < n; ++staffIdx2) {
180 0 : double h = s->staff(staffIdx2)->y() + ay - y;
181 0 : if (ay2 < (y + (h + h1) * .5)) {
182 0 : break;
183 : }
184 0 : y += h;
185 : }
186 0 : staffIdx2 -= 1;
187 : }
188 :
189 0 : double sy = system()->staff(staffIdx1)->y();
190 0 : double ey = system()->staff(staffIdx2)->y() + score()->staff(staffIdx2)->staffHeight();
191 0 : mutldata()->bracketHeight.set_value(ey - sy);
192 0 : bracketItem()->undoChangeProperty(Pid::BRACKET_SPAN, staffIdx2 - staffIdx1 + 1);
193 0 : }
194 :
195 : //---------------------------------------------------------
196 : // acceptDrop
197 : //---------------------------------------------------------
198 :
199 0 : bool Bracket::acceptDrop(EditData& data) const
200 : {
201 0 : return data.dropElement->type() == ElementType::BRACKET;
202 : }
203 :
204 : //---------------------------------------------------------
205 : // drop
206 : //---------------------------------------------------------
207 :
208 0 : EngravingItem* Bracket::drop(Transaction&, EditData& data)
209 : {
210 0 : EngravingItem* e = data.dropElement;
211 0 : Bracket* b = 0;
212 0 : if (e->isBracket()) {
213 0 : b = toBracket(e);
214 0 : undoChangeProperty(Pid::SYSTEM_BRACKET, int(b->bracketType()));
215 : }
216 0 : delete e;
217 0 : return this;
218 : }
219 :
220 0 : bool Bracket::isEditAllowed(EditData& ed) const
221 : {
222 0 : if (ed.key == Key_Up && span() > 1) {
223 0 : return true;
224 : }
225 0 : if (ed.key == Key_Down && m_lastStaff < system()->staves().size() - 1) {
226 0 : return true;
227 : }
228 :
229 0 : if (!(ed.modifiers & ShiftModifier)) {
230 0 : return false;
231 : }
232 :
233 0 : if (ed.key == Key_Left) {
234 0 : return true;
235 : }
236 0 : if (ed.key == Key_Right) {
237 0 : if (bracketItem()->column() == 0) {
238 0 : return true;
239 : }
240 0 : return true;
241 : }
242 :
243 0 : return false;
244 : }
245 :
246 : //---------------------------------------------------------
247 : // edit
248 : // return true if event is accepted
249 : //---------------------------------------------------------
250 :
251 0 : bool Bracket::edit(EditData& ed)
252 : {
253 0 : if (!isEditAllowed(ed)) {
254 0 : return false;
255 : }
256 :
257 0 : if (ed.key == Key_Up && span() > 1) {
258 0 : bracketItem()->undoChangeProperty(Pid::BRACKET_SPAN, static_cast<int>(span()) - 1);
259 0 : return true;
260 : }
261 0 : if (ed.key == Key_Down && m_lastStaff < system()->staves().size() - 1) {
262 0 : bracketItem()->undoChangeProperty(Pid::BRACKET_SPAN, static_cast<int>(span()) + 1);
263 0 : return true;
264 : }
265 :
266 0 : if (ed.key == Key_Left) {
267 0 : bracketItem()->undoChangeProperty(Pid::BRACKET_COLUMN, bracketItem()->column() + 1);
268 0 : return true;
269 : }
270 0 : if (ed.key == Key_Right) {
271 0 : if (bracketItem()->column() == 0) {
272 0 : return true;
273 : }
274 0 : bracketItem()->undoChangeProperty(Pid::BRACKET_COLUMN, bracketItem()->column() - 1);
275 0 : return true;
276 : }
277 0 : return false;
278 : }
279 :
280 : //---------------------------------------------------------
281 : // getProperty
282 : //---------------------------------------------------------
283 :
284 0 : PropertyValue Bracket::getProperty(Pid id) const
285 : {
286 0 : PropertyValue v = EngravingItem::getProperty(id);
287 0 : if (!v.isValid()) {
288 0 : v = m_bi->getProperty(id);
289 : }
290 0 : return v;
291 0 : }
292 :
293 : //---------------------------------------------------------
294 : // setProperty
295 : //---------------------------------------------------------
296 :
297 0 : bool Bracket::setProperty(Pid id, const PropertyValue& v)
298 : {
299 0 : return m_bi->setProperty(id, v);
300 : }
301 :
302 : //---------------------------------------------------------
303 : // propertyDefault
304 : //---------------------------------------------------------
305 :
306 0 : PropertyValue Bracket::propertyDefault(Pid id) const
307 : {
308 0 : if (id == Pid::BRACKET_COLUMN) {
309 0 : return size_t(0);
310 : }
311 0 : PropertyValue v = EngravingItem::propertyDefault(id);
312 0 : if (!v.isValid()) {
313 0 : v = m_bi->propertyDefault(id);
314 : }
315 0 : return v;
316 0 : }
317 :
318 : //---------------------------------------------------------
319 : // subtypeUserName
320 : //---------------------------------------------------------
321 :
322 0 : muse::TranslatableString Bracket::subtypeUserName() const
323 : {
324 0 : return TConv::userName(bracketType());
325 : }
326 :
327 : //---------------------------------------------------------
328 : // undoChangeProperty
329 : //---------------------------------------------------------
330 :
331 0 : void Bracket::undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps)
332 : {
333 0 : if (id == Pid::COLOR) {
334 0 : setColor(v.value<Color>());
335 : }
336 :
337 : // brackets do not survive layout() and therefore cannot be on
338 : // the undo stack; delegate to BracketItem:
339 0 : BracketItem* bi = bracketItem();
340 0 : bi->undoChangeProperty(id, v, ps);
341 0 : }
342 :
343 76 : Fraction Bracket::tick() const
344 : {
345 76 : if (measure()) {
346 76 : return measure()->tick();
347 : }
348 0 : return EngravingItem::tick();
349 : }
350 :
351 : //---------------------------------------------------------
352 : // setSelected
353 : //---------------------------------------------------------
354 :
355 0 : void Bracket::setSelected(bool f)
356 : {
357 0 : m_bi->setSelected(f);
358 0 : if (m_text) {
359 0 : m_text->setSelected(f);
360 : }
361 :
362 0 : EngravingItem::setSelected(f);
363 0 : }
364 :
365 407 : bool Bracket::intersects(const Bracket* other) const
366 : {
367 407 : return m_firstStaff <= other->m_lastStaff && m_lastStaff >= other->m_firstStaff;
368 : }
369 :
370 0 : bool Bracket::contains(staff_idx_t staffIdx) const
371 : {
372 0 : return staffIdx >= m_firstStaff && staffIdx <= m_lastStaff;
373 : }
|