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