1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2002-2013 Werner Schweer
6 //
7 // This program is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License version 2
9 // as published by the Free Software Foundation and appearing in
10 // the file LICENCE.GPL
11 //=============================================================================
12
13 #include "bracket.h"
14 #include "xml.h"
15 #include "style.h"
16 #include "utils.h"
17 #include "measure.h"
18 #include "staff.h"
19 #include "system.h"
20 #include "score.h"
21 #include "system.h"
22 #include "sym.h"
23 #include "mscore.h"
24 #include "bracketItem.h"
25
26 namespace Ms {
27
28 //---------------------------------------------------------
29 // Bracket
30 //---------------------------------------------------------
31
Bracket(Score * s)32 Bracket::Bracket(Score* s)
33 : Element(s)
34 {
35 ay1 = 0;
36 h2 = 3.5 * spatium();
37 _firstStaff = 0;
38 _lastStaff = 0;
39 _bi = 0;
40 _braceSymbol = SymId::noSym;
41 _magx = 1.;
42 setGenerated(true); // brackets are not saved
43 }
44
~Bracket()45 Bracket::~Bracket()
46 {
47 }
48
49 //---------------------------------------------------------
50 // playTick
51 //---------------------------------------------------------
52
playTick() const53 Fraction Bracket::playTick() const
54 {
55 // Brackets always have a tick value of zero, so play from the start of the first measure in the system that the bracket belongs to.
56 const auto sys = system();
57 if (sys) {
58 const auto firstMeasure = sys->firstMeasure();
59 if (firstMeasure)
60 return firstMeasure->tick();
61 }
62
63 return tick();
64 }
65
66 //---------------------------------------------------------
67 // setHeight
68 //---------------------------------------------------------
69
setHeight(qreal h)70 void Bracket::setHeight(qreal h)
71 {
72 h2 = h * .5;
73 }
74
75 //---------------------------------------------------------
76 // width
77 //---------------------------------------------------------
78
width() const79 qreal Bracket::width() const
80 {
81 qreal w;
82 switch (bracketType()) {
83 case BracketType::BRACE:
84 if (score()->styleSt(Sid::MusicalSymbolFont) == "Emmentaler" || score()->styleSt(Sid::MusicalSymbolFont) == "Gonville")
85 w = score()->styleP(Sid::akkoladeWidth) + score()->styleP(Sid::akkoladeBarDistance);
86 else
87 w = (symWidth(_braceSymbol) * _magx) + score()->styleP(Sid::akkoladeBarDistance);
88 break;
89 case BracketType::NORMAL:
90 w = score()->styleP(Sid::bracketWidth) + score()->styleP(Sid::bracketDistance);
91 break;
92 case BracketType::SQUARE:
93 w = score()->styleP(Sid::staffLineWidth) + spatium() * .5;
94 break;
95 case BracketType::LINE:
96 w = 0.67f * score()->styleP(Sid::bracketWidth) + score()->styleP(Sid::bracketDistance);
97 break;
98 case BracketType::NO_BRACKET:
99 default:
100 w = 0.0;
101 break;
102 }
103 return w;
104 }
105
106 //---------------------------------------------------------
107 // setStaffSpan
108 //---------------------------------------------------------
109
setStaffSpan(int a,int b)110 void Bracket::setStaffSpan(int a, int b)
111 {
112 _firstStaff = a;
113 _lastStaff = b;
114
115 if (bracketType() == BracketType::BRACE &&
116 score()->styleSt(Sid::MusicalSymbolFont) != "Emmentaler" && score()->styleSt(Sid::MusicalSymbolFont) != "Gonville")
117 {
118 int v = _lastStaff - _firstStaff + 1;
119 if (score()->styleSt(Sid::MusicalSymbolFont) == "Leland")
120 v = qMin(4, v);
121 // total default height of a system of n staves / height of a 5 line staff
122 qreal dist = score()->enableVerticalSpread() ? score()->styleS(Sid::maxAkkoladeDistance).val() : score()->styleS(Sid::akkoladeDistance).val();
123 _magx = v + ((v - 1) * dist / 4.0);
124 if (v == 1)
125 _braceSymbol = SymId::braceSmall;
126 else if (v <= 2)
127 _braceSymbol = SymId::brace;
128 else if (v <= 3)
129 _braceSymbol = SymId::braceLarge;
130 else
131 _braceSymbol = SymId::braceLarger;
132 }
133 }
134
135 //---------------------------------------------------------
136 // layout
137 //---------------------------------------------------------
138
layout()139 void Bracket::layout()
140 {
141 path = QPainterPath();
142 if (h2 == 0.0)
143 return;
144
145 _shape.clear();
146 switch (bracketType()) {
147 case BracketType::BRACE: {
148 if (score()->styleSt(Sid::MusicalSymbolFont) == "Emmentaler" || score()->styleSt(Sid::MusicalSymbolFont) == "Gonville") {
149 _braceSymbol = SymId::noSym;
150 qreal w = score()->styleP(Sid::akkoladeWidth);
151
152 #define XM(a) (a+700)*w/700
153 #define YM(a) (a+7100)*h2/7100
154
155 path.moveTo( XM( -8), YM(-2048));
156 path.cubicTo(XM( -8), YM(-3192), XM(-360), YM(-4304), XM( -360), YM(-5400)); // c 0
157 path.cubicTo(XM( -360), YM(-5952), XM(-264), YM(-6488), XM( 32), YM(-6968)); // c 1
158 path.cubicTo(XM( 36), YM(-6974), XM( 38), YM(-6984), XM( 38), YM(-6990)); // c 0
159 path.cubicTo(XM( 38), YM(-7008), XM( 16), YM(-7024), XM( 0), YM(-7024)); // c 0
160 path.cubicTo(XM( -8), YM(-7024), XM( -22), YM(-7022), XM( -32), YM(-7008)); // c 1
161 path.cubicTo(XM( -416), YM(-6392), XM(-544), YM(-5680), XM( -544), YM(-4960)); // c 0
162 path.cubicTo(XM( -544), YM(-3800), XM(-168), YM(-2680), XM( -168), YM(-1568)); // c 0
163 path.cubicTo(XM( -168), YM(-1016), XM(-264), YM( -496), XM( -560), YM( -16)); // c 1
164 path.lineTo( XM( -560), YM( 0)); // l 1
165 path.lineTo( XM( -560), YM( 16)); // l 1
166 path.cubicTo(XM( -264), YM( 496), XM(-168), YM( 1016), XM( -168), YM( 1568)); // c 0
167 path.cubicTo(XM( -168), YM( 2680), XM(-544), YM( 3800), XM( -544), YM( 4960)); // c 0
168 path.cubicTo(XM( -544), YM( 5680), XM(-416), YM( 6392), XM( -32), YM( 7008)); // c 1
169 path.cubicTo(XM( -22), YM( 7022), XM( -8), YM( 7024), XM( 0), YM( 7024)); // c 0
170 path.cubicTo(XM( 16), YM( 7024), XM( 38), YM( 7008), XM( 38), YM( 6990)); // c 0
171 path.cubicTo(XM( 38), YM( 6984), XM( 36), YM( 6974), XM( 32), YM( 6968)); // c 1
172 path.cubicTo(XM( -264), YM( 6488), XM(-360), YM( 5952), XM( -360), YM( 5400)); // c 0
173 path.cubicTo(XM( -360), YM( 4304), XM( -8), YM( 3192), XM( -8), YM( 2048)); // c 0
174 path.cubicTo(XM( - 8), YM( 1320), XM(-136), YM( 624), XM( -512), YM( 0)); // c 1
175 path.cubicTo(XM( -136), YM( -624), XM( -8), YM(-1320), XM( -8), YM(-2048)); // c 0*/
176 setbbox(path.boundingRect());
177 _shape.add(bbox());
178 }
179 else {
180 if (_braceSymbol == SymId::noSym)
181 _braceSymbol = SymId::brace;
182 qreal h = h2 * 2;
183 qreal w = symWidth(_braceSymbol) * _magx;
184 bbox().setRect(0, 0, w, h);
185 _shape.add(bbox());
186 }
187 }
188 break;
189 case BracketType::NORMAL: {
190 qreal _spatium = spatium();
191 qreal w = score()->styleP(Sid::bracketWidth) * .5;
192 qreal x = -w;
193
194 qreal bd = (score()->styleSt(Sid::MusicalSymbolFont) == "Leland") ? _spatium * .5 : _spatium * .25;
195 _shape.add(QRectF(x, -bd, w * 2, 2 * (h2+bd)));
196 _shape.add(symBbox(SymId::bracketTop).translated(QPointF(-w, -bd)));
197 _shape.add(symBbox(SymId::bracketBottom).translated(QPointF(-w, bd + 2*h2)));
198
199 w += symWidth(SymId::bracketTop);
200 qreal y = - symHeight(SymId::bracketTop) - bd;
201 qreal h = (-y + h2) * 2;
202 bbox().setRect(x, y, w, h);
203 }
204 break;
205 case BracketType::SQUARE: {
206 qreal w = score()->styleP(Sid::staffLineWidth) * .5;
207 qreal x = -w;
208 qreal y = -w;
209 qreal h = (h2 + w) * 2 ;
210 w += (.5 * spatium() + 3* w);
211 bbox().setRect(x, y, w, h);
212 _shape.add(bbox());
213 }
214 break;
215 case BracketType::LINE: {
216 qreal _spatium = spatium();
217 qreal w = 0.67 * score()->styleP(Sid::bracketWidth) * .5;
218 qreal x = -w;
219 qreal bd = _spatium * .25;
220 qreal y = -bd;
221 qreal h = (-y + h2) * 2;
222 bbox().setRect(x, y, w, h);
223 _shape.add(bbox());
224 }
225 break;
226 case BracketType::NO_BRACKET:
227 break;
228 }
229 }
230
231 //---------------------------------------------------------
232 // draw
233 //---------------------------------------------------------
234
draw(QPainter * painter) const235 void Bracket::draw(QPainter* painter) const
236 {
237 if (h2 == 0.0)
238 return;
239 switch (bracketType()) {
240 case BracketType::BRACE: {
241 if (_braceSymbol == SymId::noSym) {
242 painter->setPen(Qt::NoPen);
243 painter->setBrush(QBrush(curColor()));
244 painter->drawPath(path);
245 }
246 else {
247 qreal h = 2 * h2;
248 qreal mag = h / (100 * magS());
249 painter->setPen(curColor());
250 painter->save();
251 painter->scale(_magx, mag);
252 drawSymbol(_braceSymbol, painter, QPointF(0, 100 * magS()));
253 painter->restore();
254 }
255 }
256 break;
257 case BracketType::NORMAL: {
258 qreal h = 2 * h2;
259 qreal _spatium = spatium();
260 qreal w = score()->styleP(Sid::bracketWidth);
261 qreal bd = (score()->styleSt(Sid::MusicalSymbolFont) == "Leland") ? _spatium * .5 : _spatium * .25;
262 QPen pen(curColor(), w, Qt::SolidLine, Qt::FlatCap);
263 painter->setPen(pen);
264 painter->drawLine(QLineF(0.0, -bd - w * .5, 0.0, h + bd + w * .5));
265 qreal x = -w * .5;
266 qreal y1 = -bd;
267 qreal y2 = h + bd;
268 drawSymbol(SymId::bracketTop, painter, QPointF(x, y1));
269 drawSymbol(SymId::bracketBottom, painter, QPointF(x, y2));
270 }
271 break;
272 case BracketType::SQUARE: {
273 qreal h = 2 * h2;
274 qreal _spatium = spatium();
275 qreal w = score()->styleP(Sid::staffLineWidth);
276 QPen pen(curColor(), w, Qt::SolidLine, Qt::SquareCap);
277 painter->setPen(pen);
278 painter->drawLine(QLineF(0.0, 0.0, 0.0, h));
279 painter->drawLine(QLineF(0.0, 0.0, w + .5 *_spatium, 0.0));
280 painter->drawLine(QLineF(0.0, h , w + .5 *_spatium, h));
281 }
282 break;
283 case BracketType::LINE: {
284 qreal h = 2 * h2;
285 qreal w = 0.67 * score()->styleP(Sid::bracketWidth);
286 QPen pen(curColor(), w, Qt::SolidLine, Qt::FlatCap);
287 painter->setPen(pen);
288 qreal bd = score()->styleP(Sid::staffLineWidth) * 0.5;
289 painter->drawLine(QLineF(0.0, -bd, 0.0, h + bd));
290 }
291 break;
292 case BracketType::NO_BRACKET:
293 break;
294 }
295 }
296
297 //---------------------------------------------------------
298 // startEdit
299 //---------------------------------------------------------
300
startEdit(EditData & ed)301 void Bracket::startEdit(EditData& ed)
302 {
303 Element::startEdit(ed);
304 ay1 = pagePos().y();
305 }
306
307 //---------------------------------------------------------
308 // gripsPositions
309 //---------------------------------------------------------
310
gripsPositions(const EditData &) const311 std::vector<QPointF> Bracket::gripsPositions(const EditData&) const
312 {
313 return { QPointF(0.0, h2 * 2) + pagePos() };
314 }
315
316 //---------------------------------------------------------
317 // endEdit
318 //---------------------------------------------------------
319
endEdit(EditData & ed)320 void Bracket::endEdit(EditData& ed)
321 {
322 // endEditDrag(ed);
323 triggerLayoutAll();
324 score()->update();
325 ed.element = 0; // score layout invalidates element
326 }
327
328 //---------------------------------------------------------
329 // editDrag
330 //---------------------------------------------------------
331
editDrag(EditData & ed)332 void Bracket::editDrag(EditData& ed)
333 {
334 h2 += ed.delta.y() * .5;
335 layout();
336 }
337
338 //---------------------------------------------------------
339 // endEditDrag
340 // snap to nearest staff
341 //---------------------------------------------------------
342
endEditDrag(EditData &)343 void Bracket::endEditDrag(EditData&)
344 {
345 qreal ay2 = ay1 + h2 * 2;
346
347 int staffIdx1 = staffIdx();
348 int staffIdx2;
349 int n = system()->staves()->size();
350 if (staffIdx1 + 1 >= n)
351 staffIdx2 = staffIdx1;
352 else {
353 qreal ay = parent()->pagePos().y();
354 System* s = system();
355 qreal y = s->staff(staffIdx1)->y() + ay;
356 qreal h1 = staff()->height();
357
358 for (staffIdx2 = staffIdx1 + 1; staffIdx2 < n; ++staffIdx2) {
359 qreal h = s->staff(staffIdx2)->y() + ay - y;
360 if (ay2 < (y + (h + h1) * .5))
361 break;
362 y += h;
363 }
364 staffIdx2 -= 1;
365 }
366
367 qreal sy = system()->staff(staffIdx1)->y();
368 qreal ey = system()->staff(staffIdx2)->y() + score()->staff(staffIdx2)->height();
369 h2 = (ey - sy) * .5;
370 bracketItem()->undoChangeProperty(Pid::BRACKET_SPAN, staffIdx2 - staffIdx1 + 1);
371 // brackets do not survive layout
372 // make sure layout is not called:
373 score()->cmdState()._setUpdateMode(UpdateMode::Update);
374 }
375
376 //---------------------------------------------------------
377 // acceptDrop
378 //---------------------------------------------------------
379
acceptDrop(EditData & data) const380 bool Bracket::acceptDrop(EditData& data) const
381 {
382 return data.dropElement->type() == ElementType::BRACKET;
383 }
384
385 //---------------------------------------------------------
386 // drop
387 //---------------------------------------------------------
388
drop(EditData & data)389 Element* Bracket::drop(EditData& data)
390 {
391 Element* e = data.dropElement;
392 Bracket* b = 0;
393 if (e->isBracket()) {
394 b = toBracket(e);
395 undoChangeProperty(Pid::SYSTEM_BRACKET, int(b->bracketType()));
396 }
397 delete e;
398 return this;
399 }
400
401 //---------------------------------------------------------
402 // edit
403 // return true if event is accepted
404 //---------------------------------------------------------
405
edit(EditData & ed)406 bool Bracket::edit(EditData& ed)
407 {
408 if (!(ed.modifiers & Qt::ShiftModifier))
409 return false;
410
411 if (ed.key == Qt::Key_Left) {
412 bracketItem()->undoChangeProperty(Pid::BRACKET_COLUMN, bracketItem()->column()+1);
413 return true;
414 }
415 if (ed.key == Qt::Key_Right) {
416 if (bracketItem()->column() == 0)
417 return true;
418 bracketItem()->undoChangeProperty(Pid::BRACKET_COLUMN, bracketItem()->column()-1);
419 return true;
420 }
421 return false;
422 }
423
424 //---------------------------------------------------------
425 // getProperty
426 //---------------------------------------------------------
427
getProperty(Pid id) const428 QVariant Bracket::getProperty(Pid id) const
429 {
430 QVariant v = Element::getProperty(id);
431 if (!v.isValid())
432 v = _bi->getProperty(id);
433 return v;
434 }
435
436 //---------------------------------------------------------
437 // setProperty
438 //---------------------------------------------------------
439
setProperty(Pid id,const QVariant & v)440 bool Bracket::setProperty(Pid id, const QVariant& v)
441 {
442 return _bi->setProperty(id, v);
443 }
444
445 //---------------------------------------------------------
446 // propertyDefault
447 //---------------------------------------------------------
448
propertyDefault(Pid id) const449 QVariant Bracket::propertyDefault(Pid id) const
450 {
451 if (id == Pid::BRACKET_COLUMN)
452 return 0;
453 QVariant v = Element::propertyDefault(id);
454 if (!v.isValid())
455 v = _bi->propertyDefault(id);
456 return v;
457 }
458
459 //---------------------------------------------------------
460 // undoChangeProperty
461 //---------------------------------------------------------
462
undoChangeProperty(Pid id,const QVariant & v,PropertyFlags ps)463 void Bracket::undoChangeProperty(Pid id, const QVariant& v, PropertyFlags ps)
464 {
465 // brackets do not survive layout() and therefore cannot be on
466 // the undo stack; delegate to BracketItem:
467 BracketItem* bi = bracketItem();
468 bi->undoChangeProperty(id, v, ps);
469 }
470
471 //---------------------------------------------------------
472 // setSelected
473 //---------------------------------------------------------
474
setSelected(bool f)475 void Bracket::setSelected(bool f)
476 {
477 // _bi->setSelected(f);
478 Element::setSelected(f);
479 }
480
481 //---------------------------------------------------------
482 // Bracket::bracketTypeName
483 //---------------------------------------------------------
484
bracketTypeName(BracketType type)485 const char* Bracket::bracketTypeName(BracketType type)
486 {
487 switch(type) {
488 case BracketType::BRACE:
489 return "Brace";
490 case BracketType::NORMAL:
491 return "Normal";
492 case BracketType::SQUARE:
493 return "Square";
494 case BracketType::LINE:
495 return "Line";
496 case BracketType::NO_BRACKET:
497 return "NoBracket";
498 }
499 Q_UNREACHABLE();
500 }
501
502 //---------------------------------------------------------
503 // Bracket::write
504 // used only for palettes
505 //---------------------------------------------------------
506
write(XmlWriter & xml) const507 void Bracket::write(XmlWriter& xml) const
508 {
509 switch (_bi->bracketType()) {
510 case BracketType::BRACE:
511 case BracketType::SQUARE:
512 case BracketType::LINE:
513 {
514 const char* type = bracketTypeName(_bi->bracketType());
515 xml.stag(this, QString("type=\"%1\"").arg(type));
516 }
517 break;
518 case BracketType::NORMAL:
519 xml.stag(this);
520 break;
521 case BracketType::NO_BRACKET:
522 break;
523 }
524 if (_bi->column())
525 xml.tag("level", _bi->column());
526 Element::writeProperties(xml);
527 xml.etag();
528 }
529
530 //---------------------------------------------------------
531 // Bracket::read
532 // used only for palettes
533 //---------------------------------------------------------
534
read(XmlReader & e)535 void Bracket::read(XmlReader& e)
536 {
537 QString t(e.attribute("type", "Normal"));
538 _bi = new BracketItem(score());
539
540 if (t == "Normal")
541 _bi->setBracketType(BracketType::NORMAL);
542 else if (t == "Akkolade") //compatibility, not used anymore
543 _bi->setBracketType(BracketType::BRACE);
544 else if (t == "Brace")
545 _bi->setBracketType(BracketType::BRACE);
546 else if (t == "Square")
547 _bi->setBracketType(BracketType::SQUARE);
548 else if (t == "Line")
549 _bi->setBracketType(BracketType::LINE);
550 else
551 qDebug("unknown brace type <%s>", qPrintable(t));
552
553 while (e.readNextStartElement()) {
554 if (e.name() == "level")
555 _bi->setColumn(e.readInt());
556 else if (!Element::readProperties(e))
557 e.unknown();
558 }
559 }
560
561
562 }
563
564