1 //=============================================================================
2 // MuseScore
3 // Music Composition & Notation
4 //
5 // Copyright (C) 2010-2011 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 "shadownote.h"
14 #include "score.h"
15 #include "drumset.h"
16 #include "sym.h"
17 #include "rest.h"
18 #include "mscore.h"
19 #include "accidental.h"
20
21 namespace Ms {
22
23 //---------------------------------------------------------
24 // ShadowNote
25 //---------------------------------------------------------
26
ShadowNote(Score * s)27 ShadowNote::ShadowNote(Score* s)
28 : Element(s), _notehead(SymId::noSym)
29 {
30 _line = 1000;
31 _duration = TDuration(TDuration::DurationType::V_INVALID);
32 _voice = 0;
33 _rest = false;
34 }
35
isValid() const36 bool ShadowNote::isValid() const
37 {
38 return _notehead != SymId::noSym;
39 }
40
setState(SymId noteSymbol,int voice,TDuration duration,bool rest)41 void ShadowNote::setState(SymId noteSymbol, int voice, TDuration duration, bool rest)
42 {
43 // clear symbols
44 _notehead = SymId::noSym;
45
46 _notehead = noteSymbol;
47 _duration = duration;
48 _voice = voice;
49 _rest = rest;
50 }
51
getNoteFlag() const52 SymId ShadowNote::getNoteFlag() const
53 {
54 SymId flag = SymId::noSym;
55 if (_rest)
56 return flag;
57 TDuration::DurationType type = _duration.type();
58 switch (type) {
59 case TDuration::DurationType::V_LONG:
60 flag = SymId::lastSym;
61 break;
62 case TDuration::DurationType::V_BREVE:
63 flag = SymId::noSym;
64 break;
65 case TDuration::DurationType::V_WHOLE:
66 flag = SymId::noSym;
67 break;
68 case TDuration::DurationType::V_HALF:
69 flag = SymId::lastSym;
70 break;
71 case TDuration::DurationType::V_QUARTER:
72 flag = SymId::lastSym;
73 break;
74 case TDuration::DurationType::V_EIGHTH:
75 flag = computeUp() ? SymId::flag8thUp : SymId::flag8thDown;
76 break;
77 case TDuration::DurationType::V_16TH:
78 flag = computeUp() ? SymId::flag16thUp : SymId::flag16thDown;
79 break;
80 case TDuration::DurationType::V_32ND:
81 flag = computeUp() ? SymId::flag32ndUp : SymId::flag32ndDown;
82 break;
83 case TDuration::DurationType::V_64TH:
84 flag = computeUp() ? SymId::flag64thUp : SymId::flag64thDown;
85 break;
86 case TDuration::DurationType::V_128TH:
87 flag = computeUp() ? SymId::flag128thUp : SymId::flag128thDown;
88 break;
89 case TDuration::DurationType::V_256TH:
90 flag = computeUp() ? SymId::flag256thUp : SymId::flag256thDown;
91 break;
92 case TDuration::DurationType::V_512TH:
93 flag = computeUp() ? SymId::flag512thUp : SymId::flag512thDown;
94 break;
95 case TDuration::DurationType::V_1024TH:
96 flag = computeUp() ? SymId::flag1024thUp : SymId::flag1024thDown;
97 break;
98 default:
99 flag = SymId::noSym;
100 }
101 return flag;
102 }
103
computeUp() const104 bool ShadowNote::computeUp() const
105 {
106 if (_voice % VOICES == 0)
107 return _line > 4;
108 else
109 return _voice % VOICES == 2;
110 }
111
112 //---------------------------------------------------------
113 // draw
114 //---------------------------------------------------------
115
draw(QPainter * painter) const116 void ShadowNote::draw(QPainter* painter) const
117 {
118 if (!visible() || !isValid())
119 return;
120
121 QPointF ap(pagePos());
122 painter->translate(ap);
123 qreal lw = score()->styleP(Sid::stemWidth);
124 QPen pen(MScore::selectColor[_voice].lighter(SHADOW_NOTE_LIGHT), lw, Qt::SolidLine, Qt::FlatCap);
125 painter->setPen(pen);
126
127 // draw the accidental
128 SymId acc = Accidental::subtype2symbol(score()->inputState().accidentalType());
129 if (acc != SymId::noSym) {
130 QPointF posAcc;
131 posAcc.rx() -= symWidth(acc) + score()->styleP(Sid::accidentalNoteDistance) * mag();
132 drawSymbol(acc, painter, posAcc);
133 }
134
135 // draw the notehead
136 drawSymbol(_notehead, painter);
137
138 // draw the dots
139 qreal noteheadWidth = symWidth(_notehead);
140 qreal spmag = spatium() * mag();
141 qreal spmag5 = 0.5 * spmag;
142 qreal sp5 = 0.5 * spatium();
143 QPointF posDot;
144 if (_duration.dots() > 0) {
145 qreal d = score()->styleP(Sid::dotNoteDistance) * mag();
146 qreal dd = score()->styleP(Sid::dotDotDistance) * mag();
147 posDot.rx() += (noteheadWidth + d);
148 if (!_rest)
149 posDot.ry() -= (_line % 2 == 0 ? sp5 : 0);
150 else
151 posDot.ry() += Rest::getDotline(_duration.type()) * spmag5;
152 for (int i = 0; i < _duration.dots(); i++) {
153 posDot.rx() += dd * i;
154 drawSymbol(SymId::augmentationDot, painter, posDot, 1);
155 posDot.rx() -= dd * i;
156 }
157 }
158
159 // stem and flag
160 SymId flag = getNoteFlag();
161 if (flag != SymId::noSym) {
162 bool up = computeUp();
163 qreal x = up ? (noteheadWidth - (lw / 2)) : lw / 2;
164 qreal y1 = (up ? symStemUpSE(_notehead) : symStemDownNW(_notehead)).y() * mag();
165 qreal y2 = (up ? -3.5 : 3.5) * spmag;
166
167 if (flag != SymId::lastSym) { // If there is a flag
168 if (up && _duration.dots() > 0 && !(_line & 1)) {
169 y2 -= spmag5; // Lengthen stem to avoid collision of dots with hook
170 }
171 QPointF flagPoint(x - (lw / 2), y2);
172 drawSymbol(flag, painter, flagPoint, 1);
173 y2 += ( up ? symStemUpNW(flag) : symStemDownSW(flag) ).y();
174 }
175 painter->drawLine(QLineF(x, y1, x, y2));
176 }
177
178 // Ledger lines
179 qreal extraLen = score()->styleP(Sid::ledgerLineLength) * mag();
180 qreal x1 = -extraLen;
181 qreal x2 = noteheadWidth + extraLen;
182
183 lw = score()->styleP(Sid::ledgerLineWidth);
184 painter->setPen(QPen(MScore::selectColor[_voice].lighter(SHADOW_NOTE_LIGHT), lw, Qt::SolidLine, Qt::FlatCap));
185
186 if (_line < 100 && _line > -100 && !_rest) {
187 for (int i = -2; i >= _line; i -= 2) {
188 qreal y = spmag5 * (i - _line);
189 painter->drawLine(QLineF(x1, y, x2, y));
190 }
191 for (int i = 10; i <= _line; i += 2) {
192 qreal y = spmag5 * (i - _line);
193 painter->drawLine(QLineF(x1, y, x2, y));
194 }
195 }
196 painter->translate(-ap);
197 }
198
199 //---------------------------------------------------------
200 // layout
201 //---------------------------------------------------------
202
layout()203 void ShadowNote::layout()
204 {
205 if (!isValid()) {
206 setbbox(QRectF());
207 return;
208 }
209 qreal _spatium = spatium();
210 QRectF b;
211 QRectF noteheadBbox = symBbox(_notehead);
212 SymId flag = getNoteFlag();
213 qreal height = noteheadBbox.height();
214 qreal dotWidth = 0;
215 if (_duration.dots() > 0) {
216 qreal noteheadWidth = symWidth(_notehead);
217 qreal d = score()->styleP(Sid::dotNoteDistance) * mag();
218 qreal dd = score()->styleP(Sid::dotDotDistance) * mag();
219 dotWidth += (noteheadWidth + d);
220 for (int i = 0; i < _duration.dots(); i++)
221 dotWidth += dd * i;
222 height += (_line % 2 == 0 && !_rest ? 0.5 * spatium() : 0); // move flag up
223 }
224 if(flag == SymId::noSym) {
225 b.setRect(noteheadBbox.x(), noteheadBbox.y(), noteheadBbox.width() + dotWidth, noteheadBbox.height());
226 }
227 else {
228 qreal x = noteheadBbox.x();
229 qreal width = noteheadBbox.width();
230 qreal flagWidth = 0;
231 int up = computeUp() ? 1 : 0;
232 qreal y = up ? 0 : -height;
233 if (flag != SymId::lastSym) {
234 QRectF flagBbox = symBbox(flag);
235 qreal lw = score()->styleP(Sid::stemWidth) * mag();
236 qreal h = flagBbox.height() + lw / 2 + spatium() * mag();
237 y -= h * up;
238 height += h;
239 flagWidth = flagBbox.width();
240 }
241 else {
242 qreal sh = 4 * spatium() * mag();
243 y -= up * sh;
244 height += sh;
245 }
246 width += qMax(flagWidth, dotWidth);
247
248 b.setRect(x, y, width, height);
249 }
250
251 qreal lw = score()->styleP(Sid::ledgerLineWidth);
252
253 qreal x1 = (noteheadBbox.width()) * .5 - (_spatium * mag()) - lw * .5;
254
255 qreal x2 = x1 + 2 * _spatium * mag() + lw * .5;
256
257 InputState ps = score()->inputState();
258 QRectF r(x1, -lw * .5, x2 - x1, lw);
259 if (_line < 100 && _line > -100 && !ps.rest()) {
260 for (int i = -2; i >= _line; i -= 2)
261 b |= r.translated(QPointF(0, _spatium * .5 * (i - _line)));
262 for (int i = 10; i <= _line; i += 2)
263 b |= r.translated(QPointF(0, _spatium * .5 * (i - _line)));
264 }
265 setbbox(b);
266 }
267 }
268
269