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