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