1 /* This file is part of the KDE project
2  * Copyright (C) 2007 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 #include "Renderer.h"
20 #include "MusicStyle.h"
21 
22 #include "core/Sheet.h"
23 #include "core/Part.h"
24 #include "core/Voice.h"
25 #include "core/Staff.h"
26 #include "core/VoiceBar.h"
27 #include "core/Chord.h"
28 #include "core/Note.h"
29 #include "core/Clef.h"
30 #include "core/Bar.h"
31 #include "core/KeySignature.h"
32 #include "core/TimeSignature.h"
33 #include "core/StaffSystem.h"
34 
35 #include <QMultiMap>
36 #include <QPainterPath>
37 
38 #include <climits>
39 #include <algorithm>
40 
41 using namespace MusicCore;
42 
MusicRenderer(MusicStyle * style)43 MusicRenderer::MusicRenderer(MusicStyle* style) : m_style(style), m_debug(false)
44 {
45 }
46 
renderSheet(QPainter & painter,Sheet * sheet,int firstSystem,int lastSystem)47 void MusicRenderer::renderSheet(QPainter& painter, Sheet* sheet, int firstSystem, int lastSystem)
48 {
49     int firstBar = sheet->staffSystem(firstSystem)->firstBar();
50     int lastBar = INT_MAX;
51     if (lastSystem < sheet->staffSystemCount()-1) {
52         lastBar = sheet->staffSystem(lastSystem+1)->firstBar()-1;
53     }
54 
55     for (int i = 0; i < sheet->partCount(); i++) {
56         renderPart(painter, sheet->part(i), firstBar, lastBar);
57     }
58     for (int i = firstSystem; i <= lastSystem && i < sheet->staffSystemCount(); i++) {
59         StaffSystem* ss = sheet->staffSystem(i);
60         if (ss->indent() == 0) continue;
61         int b = ss->firstBar();
62         Bar* bar = sheet->bar(b);
63         qreal by = bar->position().y();
64         qreal ind = ss->indent();
65 
66         for (int p = 0; p < sheet->partCount(); p++) {
67             Part* part = sheet->part(p);
68             for (int s = 0; s < part->staffCount(); s++) {
69                 Staff* staff = part->staff(s);
70                 qreal y = staff->top();
71                 qreal dy = staff->lineSpacing();
72 
73                 painter.setPen(m_style->staffLinePen());
74                 for (int l = 0; l < staff->lineCount(); l++) {
75                     painter.drawLine(QPointF(0, by + y + l * dy), QPointF(ind, by + y + l * dy));
76                 }
77 
78                 Clef* clef = ss->clef(staff);
79                 RenderState foo;
80                 qreal x = 15;
81                 if (clef) {
82                     renderClef(painter, clef, QPointF(x, by), foo, Qt::black, true);
83                     x += clef->width() + 15;
84                 }
85                 KeySignature* ks = staff->lastKeySignatureChange(b);
86                 if (ks) {
87                     renderKeySignature(painter, ks, QPointF(x, by), foo, Qt::black, true);
88                 }
89             }
90         }
91     }
92 }
93 
renderPart(QPainter & painter,Part * part,int firstBar,int lastBar,const QColor & color)94 void MusicRenderer::renderPart(QPainter& painter, Part* part, int firstBar, int lastBar, const QColor& color)
95 {
96     if (lastBar < firstBar) return;
97 
98     for (int i = 0; i < part->staffCount(); i++) {
99         renderStaff(painter, part->staff(i), firstBar, lastBar, color);
100     }
101     qreal firstStaff = part->staff(0)->top();
102     int c = part->staffCount()-1;
103     qreal lastStaff = part->staff(c)->bottom();
104     for (int b = firstBar; b <= lastBar && b < part->sheet()->barCount(); b++) {
105         Bar* bar = part->sheet()->bar(b);
106         QPointF p = bar->position();
107         painter.drawLine(QPointF(p.x() + bar->size(), p.y() + firstStaff), QPointF(p.x() + bar->size(), p.y() + lastStaff));
108         if (m_debug) {
109             painter.setPen(QPen(Qt::green, 0));
110             painter.drawLine(QPointF(p.x(), p.y() + firstStaff - 3), QPointF(p.x(), p.y() + lastStaff + 3));
111             painter.drawLine(QPointF(p.x() - bar->prefix(), p.y() + firstStaff - 3), QPointF(p.x() - bar->prefix(), p.y() + lastStaff + 3));
112         }
113 
114         // check if the bar contains any elements, if not render a rest
115         bool hasContents = false;
116         for (int v = 0; v < part->voiceCount(); v++) {
117             if (part->voice(v)->bar(bar)->elementCount() > 0) {
118                 hasContents = true;
119                 break;
120             }
121         }
122 
123         if (!hasContents) {
124             QPointF pos = bar->position();
125             qreal w = bar->size();
126             for (int sid = 0; sid < part->staffCount(); sid++) {
127                 Staff* s = part->staff(sid);
128                 renderRest(painter, WholeNote, pos + QPointF(w/2, s->top() + s->lineSpacing()), color);
129             }
130         }
131     }
132     for (int i = 0; i < part->voiceCount(); i++) {
133         renderVoice(painter, part->voice(i), firstBar, lastBar, color);
134     }
135 }
136 
renderStaff(QPainter & painter,Staff * staff,int firstBar,int lastBar,const QColor & color)137 void MusicRenderer::renderStaff(QPainter& painter, Staff *staff, int firstBar, int lastBar, const QColor& color)
138 {
139     qreal dy = staff->lineSpacing();
140     qreal y = staff->top();
141     for (int b = firstBar; b <= lastBar && b < staff->part()->sheet()->barCount(); b++) {
142         Bar* bar = staff->part()->sheet()->bar(b);
143         QPointF p = bar->position();
144         QPointF prep = bar->prefixPosition() + QPointF(bar->prefix(), 0);
145         painter.setPen(m_style->staffLinePen(color));
146         for (int i = 0; i < staff->lineCount(); i++) {
147             painter.drawLine(QPointF(p.x(), p.y() + y + i * dy), QPointF(p.x() + bar->size(), p.y() + y + i * dy));
148         }
149         if (bar->prefix() > 0) {
150             QPointF q = bar->prefixPosition();
151             for (int i = 0; i < staff->lineCount(); i++) {
152                 painter.drawLine(QPointF(q.x(), q.y() + y + i * dy), QPointF(q.x() + bar->prefix(), q.y() + y + i * dy));
153             }
154         }
155         RenderState state;
156         for (int e = 0; e < bar->staffElementCount(staff); e++) {
157             StaffElement* se = bar->staffElement(staff, e);
158             if (se->startTime() == 0) {
159                 renderStaffElement(painter, bar->staffElement(staff, e), prep, state, color);
160             } else {
161                 renderStaffElement(painter, bar->staffElement(staff, e), p, state, color);
162             }
163         }
164     }
165 }
166 
renderVoice(QPainter & painter,Voice * voice,int firstBar,int lastBar,const QColor & color)167 void MusicRenderer::renderVoice(QPainter& painter, Voice *voice, int firstBar, int lastBar, const QColor& color)
168 {
169     RenderState state;
170     state.clef = 0;
171     for (int b = firstBar; b <= lastBar && b < voice->part()->sheet()->barCount(); b++) {
172         Bar* bar = voice->part()->sheet()->bar(b);
173         QPointF p = bar->position();
174         VoiceBar* vb = voice->bar(bar);
175         for (int e = 0; e < vb->elementCount(); e++) {
176             if (vb->element(e)->staff()) {
177                 state.clef = vb->element(e)->staff()->lastClefChange(b, 0);
178             }
179             renderElement(painter, vb->element(e), voice, p, state, color);
180         }
181     }
182 }
183 
renderElement(QPainter & painter,VoiceElement * me,Voice * voice,const QPointF & pos,RenderState & state,const QColor & color)184 void MusicRenderer::renderElement(QPainter& painter, VoiceElement* me, Voice* voice, const QPointF& pos, RenderState& state, const QColor& color)
185 {
186     Q_UNUSED( state ); // unused for now, but will probably be used again in the future
187 
188     qreal top = 0;
189     if (me->staff()) top += me->staff()->top();
190     if (m_debug) {
191         painter.setPen(QPen(Qt::blue, 0));
192         painter.drawLine(pos + QPointF(me->x(), top + me->y() - 4), pos + QPointF(me->x(), top + me->y() + me->height() + 4));
193         painter.drawLine(pos + QPointF(me->x() + me->width(), top + me->y() - 4), pos + QPointF(me->x() + me->width(), top + me->y() + me->height() + 4));
194 
195         painter.drawLine(pos + QPointF(me->x() - 4, top + me->y()), pos + QPointF(me->x() + me->width() + 4, top + me->y()));
196         painter.drawLine(pos + QPointF(me->x() - 4, top + me->y() + me->height()), pos + QPointF(me->x() + me->width() + 4, top + me->y() + me->height()));
197 
198         painter.setPen(QPen(Qt::red, 0));
199         painter.drawLine(pos + QPointF(me->x() + me->beatline(), top + me->y() - 10), pos + QPointF(me->x() + me->beatline(), top + me->y() + me->height() + 10));
200     }
201 
202     // TODO: make this less hacky
203     Chord *c = dynamic_cast<Chord*>(me);
204     if (c) renderChord(painter, c, voice, pos, color);
205 }
206 
renderStaffElement(QPainter & painter,MusicCore::StaffElement * se,const QPointF & pos,RenderState & state,const QColor & color)207 void MusicRenderer::renderStaffElement(QPainter& painter, MusicCore::StaffElement* se, const QPointF& pos, RenderState& state, const QColor& color)
208 {
209     qreal top = 0;
210     top += se->staff()->top();
211     if (m_debug) {
212         painter.setPen(QPen(Qt::blue, 0));
213         painter.drawLine(pos + QPointF(se->x(), top + se->y() - 20), pos + QPointF(se->x(), top + se->y() + 20));
214         painter.drawLine(pos + QPointF(se->x() + se->width(), top + se->y() - 20), pos + QPointF(se->x() + se->width(), top + se->y() + 20));
215 
216         painter.drawLine(pos + QPointF(se->x() - 10, top + se->y()), pos + QPointF(se->x() + se->width() + 10, top + se->y()));
217         painter.drawLine(pos + QPointF(se->x() - 10, top + se->y() + se->height()), pos + QPointF(se->x() + se->width() + 10, top + se->y() + se->height()));
218     }
219 
220     Clef *cl = dynamic_cast<Clef*>(se);
221     if (cl) renderClef(painter, cl, pos, state, color);
222     KeySignature *ks = dynamic_cast<KeySignature*>(se);
223     if (ks) renderKeySignature(painter, ks, pos, state, color);
224     TimeSignature* ts = dynamic_cast<TimeSignature*>(se);
225     if (ts) renderTimeSignature(painter, ts, pos, color);
226 }
227 
228 
renderClef(QPainter & painter,Clef * c,const QPointF & pos,RenderState & state,const QColor & color,bool ignoreOwnPos)229 void MusicRenderer::renderClef(QPainter& painter, Clef *c, const QPointF& pos, RenderState& state, const QColor& color, bool ignoreOwnPos)
230 {
231     Q_UNUSED(color);
232     state.clef = c;
233     Staff* s = c->staff();
234     m_style->renderClef(painter, pos.x() + (ignoreOwnPos ? 0 : c->x()), pos.y() + s->top() + (s->lineCount() - c->line()) * s->lineSpacing(), c->shape());
235 }
236 
renderKeySignature(QPainter & painter,KeySignature * ks,const QPointF & pos,RenderState & state,const QColor & color,bool ignoreOwnPos)237 void MusicRenderer::renderKeySignature(QPainter& painter, KeySignature* ks, const QPointF& pos, RenderState& state, const QColor& color, bool ignoreOwnPos)
238 {
239     Q_UNUSED(color);
240     Staff * s = ks->staff();
241     qreal curx = pos.x() + (ignoreOwnPos ? 0 : ks->x());
242     // draw naturals for sharps
243     int idx = 3;
244     for (int i = 0; i < 7; i++) {
245         if (ks->cancel(idx) > 0) {
246             int line = 10;
247             if (state.clef) line = state.clef->pitchToLine(idx);
248 
249             while (line < 0) line += 7;
250             while (line >= 6) line -= 7;
251             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 0 );
252 
253             curx += 6;
254         }
255         idx = (idx + 4) % 7;
256     }
257 
258     // draw naturals for flats
259     idx = 6;
260     for (int i = 0; i < 7; i++) {
261         if (ks->cancel(idx) < 0) {
262             int line = 10;
263             if (state.clef) line = state.clef->pitchToLine(idx);
264 
265             while (line < 0) line += 7;
266             while (line >= 6) line -= 7;
267 
268             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 0 );
269 
270             curx += 6;
271         }
272         idx = (idx + 3) % 7;
273     }
274 
275     // draw sharps
276     idx = 3;
277     for (int i = 0; i < 7; i++) {
278         if (ks->accidentals(idx) > 0) {
279             int line = 10;
280             if (state.clef) line = state.clef->pitchToLine(idx);
281 
282             while (line < 0) line += 7;
283             while (line >= 6) line -= 7;
284             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 1 );
285 
286             curx += 6;
287         }
288         idx = (idx + 4) % 7;
289     }
290 
291     // draw flats
292     idx = 6;
293     for (int i = 0; i < 7; i++) {
294         if (ks->accidentals(idx) < 0) {
295             int line = 10;
296             if (state.clef) line = state.clef->pitchToLine(idx);
297 
298             while (line < 0) line += 7;
299             while (line >= 6) line -= 7;
300 
301             m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, -1 );
302 
303             curx += 6;
304         }
305         idx = (idx + 3) % 7;
306     }
307 }
308 
renderTimeSignature(QPainter & painter,TimeSignature * ts,const QPointF & pos,const QColor & color)309 void MusicRenderer::renderTimeSignature(QPainter& painter, TimeSignature* ts, const QPointF& pos, const QColor& color)
310 {
311     Q_UNUSED(color);
312     Staff* s = ts->staff();
313     qreal hh = 0.5 * (s->lineCount() - 1) * s->lineSpacing();
314     m_style->renderTimeSignatureNumber( painter, pos.x() + ts->x(), pos.y() + s->top() + hh, ts->width(), ts->beats());
315     m_style->renderTimeSignatureNumber( painter, pos.x() + ts->x(), pos.y() + s->top() + 2*hh, ts->width(), ts->beat());
316 }
317 
renderRest(QPainter & painter,Duration duration,const QPointF & pos,const QColor & color)318 void MusicRenderer::renderRest(QPainter& painter, Duration duration, const QPointF& pos, const QColor& color)
319 {
320     m_style->renderRest(painter, pos.x(), pos.y(), duration, color);
321 }
322 
renderChord(QPainter & painter,Chord * chord,Voice * voice,const QPointF & ref,const QColor & color)323 void MusicRenderer::renderChord(QPainter& painter, Chord* chord, Voice* voice, const QPointF& ref, const QColor& color)
324 {
325     qreal x = chord->x();
326     if (chord->noteCount() == 0) { // a rest
327         Staff *s = chord->staff();
328         renderRest(painter, chord->duration(), ref + QPointF(x, s->top() + (2 - (chord->duration() == WholeNote)) * s->lineSpacing()), color);
329         return;
330     }
331     int topLine = 0, bottomLine = 0;
332     VoiceBar* vb = chord->voiceBar();
333     Bar* bar = vb->bar();
334     Sheet* sheet = voice->part()->sheet();
335     int barIdx = bar->sheet()->indexOfBar(bar);
336     qreal topy = 1e9, bottomy = -1e9;
337     Staff* topStaff = 0, *bottomStaff = 0;
338 
339     qreal mainNoteX = (chord->stemDirection() == StemUp ? chord->stemX() - 6 : chord->stemX());
340     qreal alternateNoteX = mainNoteX + (chord->stemDirection() == StemUp ? 6 : -6);
341     bool prevAlternate = false;
342     qreal maxNoteX = 0;
343 
344     QMultiMap<Staff*, int> dots;
345 
346     Chord* nextChord = 0;
347 
348     for (int i = 0; i < chord->noteCount(); i++) {
349         Note *n = chord->note(i);
350         Staff * s = n->staff();
351         Clef* clef = s->lastClefChange(barIdx);
352         int line = 10;
353         if (clef) line = clef->pitchToLine(n->pitch());
354 
355         qreal noteX = mainNoteX;
356         if (i > 0) {
357             int prevPitch = chord->note(i-1)->pitch();
358             if (abs(prevPitch - n->pitch()) <= 1 && !prevAlternate) {
359                 noteX = alternateNoteX;
360             }
361         }
362         if (i < chord->noteCount()-1 && chord->stemDirection() == StemDown) {
363             int pitch = n->pitch();
364             int nPitch = chord->note(i+1)->pitch();
365             if (abs(pitch - nPitch) <= 1 && !prevAlternate) {
366                 noteX = alternateNoteX;
367             }
368         }
369         prevAlternate = noteX != mainNoteX;
370         if (noteX > maxNoteX) maxNoteX = noteX;
371 
372         if (line > 9) { // lines under the bar
373             painter.setPen(m_style->staffLinePen(color));
374             for (int i = 10; i <= line; i+= 2) {
375                 qreal y = s->top() + i * s->lineSpacing() / 2;
376                 painter.drawLine(ref + QPointF(noteX - 4, y), ref + QPointF(noteX + 10, y));
377             }
378         } else if (line < -1) { // lines above the bar
379             painter.setPen(m_style->staffLinePen(color));
380             for (int i = -2; i >= line; i-= 2) {
381                 qreal y = s->top() + i * s->lineSpacing() / 2;
382                 painter.drawLine(ref + QPointF(noteX - 4, y), ref + QPointF(noteX + 10, y));
383             }
384         }
385 
386         qreal ypos = s->top() + line * s->lineSpacing() / 2;
387         if (ypos < topy) {
388             topy = ypos;
389             topLine = line;
390             topStaff = s;
391         }
392         if (ypos > bottomy) {
393             bottomy = ypos;
394             bottomLine = line;
395             bottomStaff = s;
396         }
397 
398         m_style->renderNoteHead( painter, ref.x() + noteX, ref.y() + s->top() + line * s->lineSpacing() / 2, chord->duration(), color );
399 
400         // render accidentals
401         if (n->drawAccidentals()) {
402             m_style->renderAccidental( painter, ref.x() + x, ref.y() + /*chord->y() +*/ s->top() + line * s->lineSpacing() / 2, n->accidentals(), color );
403         }
404 
405         dots.insert(s, line);
406 
407         if (n->isStartTie()) {
408             // render tie for this note...
409             if (!nextChord) {
410                 // figure out what the next chord in this voice is
411                 bool afterCurrent = false;
412                 for (int e = 0; e < vb->elementCount(); e++) {
413                     if (afterCurrent) {
414                         nextChord = dynamic_cast<Chord*>(vb->element(e));
415                         if (nextChord) break;
416                     } else {
417                         if (vb->element(e) == chord) {
418                             afterCurrent = true;
419                         }
420                     }
421                 }
422                 if (!nextChord) {
423                     // check the next bar
424                     int nextBar = sheet->indexOfBar(bar)+1;
425                     if (nextBar < sheet->barCount()) {
426                         VoiceBar* nextVB = voice->bar(nextBar);
427                         for (int e = 0; e < nextVB->elementCount(); e++) {
428                             nextChord = dynamic_cast<Chord*>(nextVB->element(e));
429                             if (nextChord) break;
430                         }
431                     }
432                 }
433             }
434 
435             // okay, now nextChord is the chord to which the tie should go
436             if (nextChord) {
437                 QPointF startPos = bar->position() + QPointF(1 + chord->x() + chord->width(), ypos);
438                 QPointF endPos = nextChord->voiceBar()->bar()->position() + QPointF(nextChord->x() - 1, ypos);
439                 if (bar->position().y() < nextChord->voiceBar()->bar()->position().y() - 1e-6) {
440                     endPos = bar->position() + QPointF(bar->size(), 0);
441                 }
442 
443                 endPos.setY(startPos.y());
444                 QPointF c1a = startPos + QPointF(2, 4);
445                 QPointF c2a = endPos + QPointF(-2, 4);
446                 QPointF c1b = startPos + QPointF(2, 5);
447                 QPointF c2b = endPos + QPointF(-2, 5);
448 
449                 QPainterPath p;
450                 p.moveTo(startPos);
451                 p.cubicTo(c1a, c2a, endPos);
452                 p.cubicTo(c2b, c1b, startPos);
453                 painter.setPen(Qt::NoPen);//m_style->slurPen(color));
454                 painter.setBrush(QBrush(color));
455                 painter.drawPath(p);
456             }
457         }
458     }
459 
460     // calculate correct positioning of dots
461     // render dots of notes
462     painter.setPen(m_style->noteDotPen(color));
463     foreach (Staff* s, dots.keys()) {
464         QList<int> lines = dots.values(s);
465         std::sort(lines.begin(), lines.end());
466 
467         int lastLine = INT_MIN;
468         bool moveGroupDown = true;
469         for (int i = 0; i < lines.size(); i++) {
470             int line = lines[i];
471             if (line % 2 == 0) {
472                 line--;
473             }
474             if (line == lastLine) {
475                 if (moveGroupDown) {
476                     lines[i-1] += 2;
477                     for (int j = i-2; j >= 0; j--) {
478                         if (lines[j] == lines[j+1]) {
479                             lines[j] += 2;
480                         } else {
481                             break;
482                         }
483                     }
484                 } else {
485                     line -= 2;
486                 }
487                 moveGroupDown = !moveGroupDown;
488             }
489             lines[i] = line;
490             lastLine = line;
491         }
492 
493         foreach (int line, lines) {
494             qreal dotX = maxNoteX + 11;
495             for (int i = 0; i < chord->dots(); i++) {
496                 painter.drawPoint(ref + QPointF(dotX, s->top() + line * s->lineSpacing() / 2));
497                 dotX += 3;
498             }
499         }
500     }
501 
502     qreal stemLen = chord->stemLength() * 2;
503     if (stemLen != 0.0 && stemLen != -0.0) {
504         qreal stemX = chord->stemX();
505         bool stemsUp = chord->stemDirection() == StemUp;
506 
507         painter.setPen(m_style->stemPen(color));
508         if (stemsUp) {
509             painter.drawLine(ref + QPointF(stemX, chord->stemEndY()),
510                              ref + QPointF(stemX, bottomStaff->top() + bottomLine * bottomStaff->lineSpacing() / 2));
511             if (chord->beamType(0) == BeamFlag) {
512                 m_style->renderNoteFlags( painter, ref.x() + stemX, ref.y() + chord->stemEndY(), chord->duration(), stemsUp, color );
513             }
514         } else {
515             painter.drawLine(ref + QPointF(stemX, topStaff->top() + topLine * topStaff->lineSpacing() / 2),
516                              ref + QPointF(stemX, chord->stemEndY()));
517             if (chord->beamType(0) == BeamFlag) {
518                 m_style->renderNoteFlags( painter, ref.x() + stemX, ref.y() + chord->stemEndY(), chord->duration(), stemsUp, color );
519             }
520         }
521 
522         painter.setPen(QPen(Qt::NoPen));
523         painter.setBrush(QBrush(color));
524         for (int i = 0; i < chord->beamCount(); i++) {
525             if (chord->beamType(i) == BeamStart) {
526                 const Chord* endChord = chord->beamEnd(i);
527 
528                 QPointF beamStart(chord->stemX(), chord->stemEndY());
529                 QPointF beamEnd(endChord->stemX(), endChord->stemEndY());
530                 if (stemsUp) {
531                     beamStart += QPointF(0, topStaff->lineSpacing() * i);
532                     beamEnd += QPointF(0, topStaff->lineSpacing() * i);
533                 } else {
534                     beamStart -= QPointF(0, bottomStaff->lineSpacing() * i);
535                     beamEnd -= QPointF(0, bottomStaff->lineSpacing() * i);
536                 }
537 
538 
539                 QPointF dir(0, (stemsUp ? 1 : -1) * m_style->beamLineWidth());
540                 QPointF p[4];
541                 p[0] = ref + beamStart;
542                 p[1] = ref + beamEnd;
543                 p[2] = p[1] + dir;
544                 p[3] = p[0] + dir;
545                 painter.drawConvexPolygon(p, 4);
546             } else if (chord->beamType(i) == BeamForwardHook || chord->beamType(i) == BeamBackwardHook) {
547                 QPointF beamStart(chord->stemX(), chord->stemEndY());
548                 qreal dir = 6;
549                 if (chord->beamType(i) == BeamBackwardHook) dir = -dir;
550                 if (stemsUp) {
551                     beamStart += QPointF(0, topStaff->lineSpacing() * i);
552                 } else {
553                     beamStart -= QPointF(0, bottomStaff->lineSpacing() * i);
554                 }
555 
556                 QPointF beamEnd = beamStart + QPointF(dir, dir * chord->beamDirection());
557 
558                 QPointF bdir(0, (stemsUp ? 1 : -1) * m_style->beamLineWidth());
559                 QPointF p[4];
560                 p[0] = ref + beamStart;
561                 p[1] = ref + beamEnd;
562                 p[2] = p[1] + bdir;
563                 p[3] = p[0] + bdir;
564                 painter.drawConvexPolygon(p, 4);
565             }
566         }
567 
568     }
569 }
570 
renderNote(QPainter & painter,Duration duration,const QPointF & pos,qreal stemLength,const QColor & color)571 void MusicRenderer::renderNote(QPainter& painter, Duration duration, const QPointF& pos, qreal stemLength, const QColor& color)
572 {
573     m_style->renderNoteHead(painter, pos.x(), pos.y(), duration, color);
574 
575     if (duration <= HalfNote) {
576         painter.setPen(m_style->stemPen(color));
577         painter.drawLine(pos + QPointF(6, -stemLength), pos + QPointF(6, 0));
578     }
579     if (duration <= EighthNote) {
580         m_style->renderNoteFlags(painter, pos.x()+6, pos.y() - stemLength, duration, true, color);
581     }
582 }
583 
renderAccidental(QPainter & painter,int accidentals,const QPointF & pos,const QColor & color)584 void MusicRenderer::renderAccidental(QPainter& painter, int accidentals, const QPointF& pos, const QColor& color)
585 {
586     m_style->renderAccidental( painter, pos.x(), pos.y(), accidentals, color );
587 }
588