1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2017 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 "letring.h"
14 #include "sym.h"
15 #include "xml.h"
16 #include "system.h"
17 #include "measure.h"
18 #include "chordrest.h"
19 
20 #include "score.h"
21 
22 namespace Ms {
23 
24 static const ElementStyle letRingStyle {
25       { Sid::letRingFontFace,                      Pid::BEGIN_FONT_FACE        },
26       { Sid::letRingFontFace,                      Pid::CONTINUE_FONT_FACE     },
27       { Sid::letRingFontFace,                      Pid::END_FONT_FACE          },
28       { Sid::letRingFontSize,                      Pid::BEGIN_FONT_SIZE        },
29       { Sid::letRingFontSize,                      Pid::CONTINUE_FONT_SIZE     },
30       { Sid::letRingFontSize,                      Pid::END_FONT_SIZE          },
31       { Sid::letRingFontStyle,                     Pid::BEGIN_FONT_STYLE       },
32       { Sid::letRingFontStyle,                     Pid::CONTINUE_FONT_STYLE    },
33       { Sid::letRingFontStyle,                     Pid::END_FONT_STYLE         },
34       { Sid::letRingTextAlign,                     Pid::BEGIN_TEXT_ALIGN       },
35       { Sid::letRingTextAlign,                     Pid::CONTINUE_TEXT_ALIGN    },
36       { Sid::letRingTextAlign,                     Pid::END_TEXT_ALIGN         },
37       { Sid::letRingHookHeight,                    Pid::BEGIN_HOOK_HEIGHT      },
38       { Sid::letRingHookHeight,                    Pid::END_HOOK_HEIGHT        },
39       { Sid::letRingLineStyle,                     Pid::LINE_STYLE             },
40       { Sid::letRingBeginTextOffset,               Pid::BEGIN_TEXT_OFFSET      },
41       { Sid::letRingEndHookType,                   Pid::END_HOOK_TYPE          },
42       { Sid::letRingLineWidth,                     Pid::LINE_WIDTH             },
43       { Sid::letRingPlacement,                     Pid::PLACEMENT              },
44       //{ Sid::letRingPosBelow,                      Pid::OFFSET                 },
45       };
46 
47 //---------------------------------------------------------
48 //   layout
49 //---------------------------------------------------------
50 
layout()51 void LetRingSegment::layout()
52       {
53       TextLineBaseSegment::layout();
54       autoplaceSpannerSegment();
55       }
56 
57 //---------------------------------------------------------
58 //   LetRing
59 //---------------------------------------------------------
60 
LetRing(Score * s)61 LetRing::LetRing(Score* s)
62    : TextLineBase(s)
63       {
64       initElementStyle(&letRingStyle);
65       resetProperty(Pid::LINE_VISIBLE);
66 
67       resetProperty(Pid::BEGIN_TEXT_PLACE);
68       resetProperty(Pid::BEGIN_TEXT);
69       resetProperty(Pid::CONTINUE_TEXT_PLACE);
70       resetProperty(Pid::CONTINUE_TEXT);
71       resetProperty(Pid::END_TEXT_PLACE);
72       resetProperty(Pid::END_TEXT);
73       }
74 
75 //---------------------------------------------------------
76 //   read
77 //---------------------------------------------------------
78 
read(XmlReader & e)79 void LetRing::read(XmlReader& e)
80       {
81       if (score()->mscVersion() < 301)
82             e.addSpanner(e.intAttribute("id", -1), this);
83       while (e.readNextStartElement()) {
84             if (readProperty(e.name(), e, Pid::LINE_WIDTH))
85                   setPropertyFlags(Pid::LINE_WIDTH, PropertyFlags::UNSTYLED);
86             else if (!TextLineBase::readProperties(e))
87                   e.unknown();
88             }
89       }
90 
91 //---------------------------------------------------------
92 //   write
93 //
94 //   The removal of this function is potentially a temporary
95 //   change. For now, the intended behavior does no more than
96 //   the base write function and so we will just use that.
97 //
98 //   also see palmmute.cpp
99 //---------------------------------------------------------
100 
101 /*
102 void LetRing::write(XmlWriter& xml) const
103       {
104       if (!xml.canWrite(this))
105             return;
106       xml.stag(this);
107 
108       for (const StyledProperty& spp : *styledProperties()) {
109             if (!isStyled(spp.pid))
110                   writeProperty(xml, spp.pid);
111             }
112 
113       TextLineBase::writeProperties(xml);
114       xml.etag();
115       }
116 */
117 
118 static const ElementStyle letRingSegmentStyle {
119       //{ Sid::letRingPosBelow,       Pid::OFFSET       },
120       { Sid::letRingMinDistance,    Pid::MIN_DISTANCE },
121       };
122 
123 //---------------------------------------------------------
124 //   createLineSegment
125 //---------------------------------------------------------
126 
createLineSegment()127 LineSegment* LetRing::createLineSegment()
128       {
129       LetRingSegment* lr = new LetRingSegment(this, score());
130       lr->setTrack(track());
131       lr->initElementStyle(&letRingSegmentStyle);
132       return lr;
133       }
134 
135 //---------------------------------------------------------
136 //   propertyDefault
137 //---------------------------------------------------------
138 
propertyDefault(Pid propertyId) const139 QVariant LetRing::propertyDefault(Pid propertyId) const
140       {
141       switch (propertyId) {
142             case Pid::LINE_WIDTH:
143                   return score()->styleV(Sid::letRingLineWidth);
144 
145             case Pid::ALIGN:
146                   return QVariant::fromValue(Align::LEFT | Align::BASELINE);
147 
148             case Pid::LINE_STYLE:
149                   return score()->styleV(Sid::letRingLineStyle);
150 
151             case Pid::LINE_VISIBLE:
152                   return true;
153 
154             case Pid::CONTINUE_TEXT_OFFSET:
155             case Pid::END_TEXT_OFFSET:
156                   return QPointF(0, 0);
157 
158             case Pid::BEGIN_FONT_STYLE:
159                   return score()->styleV(Sid::letRingFontStyle);
160 
161             case Pid::BEGIN_TEXT:
162                   return score()->styleV(Sid::letRingText);
163             case Pid::CONTINUE_TEXT:
164             case Pid::END_TEXT:
165                   return "";
166 
167             case Pid::BEGIN_HOOK_TYPE:
168                   return int(HookType::NONE);
169 
170             case Pid::BEGIN_TEXT_PLACE:
171             case Pid::CONTINUE_TEXT_PLACE:
172             case Pid::END_TEXT_PLACE:
173                   return int(PlaceText::AUTO);
174 
175             default:
176                   return TextLineBase::propertyDefault(propertyId);
177             }
178       }
179 
180 //---------------------------------------------------------
181 //   getPropertyStyle
182 //---------------------------------------------------------
183 
getPropertyStyle(Pid id) const184 Sid LetRing::getPropertyStyle(Pid id) const
185       {
186       switch (id) {
187             case Pid::PLACEMENT:
188                   return Sid::letRingPlacement;
189             case Pid::BEGIN_FONT_FACE:
190                   return Sid::letRingFontFace;
191             case Pid::BEGIN_FONT_SIZE:
192             case Pid::CONTINUE_FONT_SIZE:
193             case Pid::END_FONT_SIZE:
194                   return Sid::letRingFontSize;
195             case Pid::BEGIN_FONT_STYLE:
196             case Pid::CONTINUE_FONT_STYLE:
197             case Pid::END_FONT_STYLE:
198                   return Sid::letRingFontStyle;
199             case Pid::BEGIN_TEXT_ALIGN:
200             case Pid::CONTINUE_TEXT_ALIGN:
201             case Pid::END_TEXT_ALIGN:
202                   return Sid::letRingTextAlign;
203             case Pid::BEGIN_HOOK_HEIGHT:
204             case Pid::END_HOOK_HEIGHT:
205                   return Sid::letRingHookHeight;
206             case Pid::BEGIN_TEXT:
207                   return Sid::letRingText;
208             default:
209                   break;
210             }
211       return TextLineBase::getPropertyStyle(id);
212       }
213 
214 
215 //---------------------------------------------------------
216 //   linePos
217 //    return System() coordinates
218 //---------------------------------------------------------
219 
linePos(Grip grip,System ** sys) const220 QPointF LetRing::linePos(Grip grip, System** sys) const
221       {
222       qreal x = 0.0;
223       qreal nhw = score()->noteHeadWidth();
224       System* s = nullptr;
225       if (grip == Grip::START) {
226             ChordRest* c = toChordRest(startElement());
227             if (!c)
228                   return QPointF();
229             s = c->segment()->system();
230             x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x();
231             if (c->isRest() && c->durationType() == TDuration::DurationType::V_MEASURE)
232                   x -= c->x();
233             }
234       else {
235             Element* e = endElement();
236             ChordRest* c = toChordRest(endElement());
237             if (!e || e == startElement() || (endHookType() == HookType::HOOK_90)) {
238                   // pedal marking on single note or ends with non-angled hook:
239                   // extend to next note or end of measure
240                   Segment* seg = nullptr;
241                   if (!e)
242                         seg = startSegment();
243                   else
244                         seg = c->segment();
245                   if (seg) {
246                         seg = seg->next();
247                         for ( ; seg; seg = seg->next()) {
248                               if (seg->segmentType() == SegmentType::ChordRest) {
249                                     // look for a chord/rest in any voice on this staff
250                                     bool crFound = false;
251                                     int track = staffIdx() * VOICES;
252                                     for (int i = 0; i < VOICES; ++i) {
253                                           if (seg->element(track + i)) {
254                                                 crFound = true;
255                                                 break;
256                                                 }
257                                           }
258                                     if (crFound)
259                                           break;
260                                     }
261                               else if (seg->segmentType() == SegmentType::EndBarLine) {
262                                     break;
263                                     }
264                               }
265                         }
266                   if (seg) {
267                         s = seg->system();
268                         x = seg->pos().x() + seg->measure()->pos().x() - nhw * 2;
269                         }
270                   }
271             else if (c) {
272                   s = c->segment()->system();
273                   x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x();
274                   if (c->isRest() && c->durationType() == TDuration::DurationType::V_MEASURE)
275                         x -= c->x();
276                   }
277             if (!s) {
278                   Fraction t = tick2();
279                   Measure* m = score()->tick2measure(t);
280                   s = m->system();
281                   x = m->tick2pos(t);
282                   }
283             x += nhw;
284             }
285 
286       *sys = s;
287       return QPointF(x, 0);
288       }
289 
290 }
291 
292