File indexing completed on 2024-05-12 16:34:16
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2007 Marijn Kruisselbrink <mkruisselbrink@kde.org> 0003 * 0004 * This library is free software; you can redistribute it and/or 0005 * modify it under the terms of the GNU Library General Public 0006 * License as published by the Free Software Foundation; either 0007 * version 2 of the License, or (at your option) any later version. 0008 * 0009 * This library is distributed in the hope that it will be useful, 0010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 * Library General Public License for more details. 0013 * 0014 * You should have received a copy of the GNU Library General Public License 0015 * along with this library; see the file COPYING.LIB. If not, write to 0016 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 * Boston, MA 02110-1301, USA. 0018 */ 0019 #include "Renderer.h" 0020 #include "MusicStyle.h" 0021 0022 #include "core/Sheet.h" 0023 #include "core/Part.h" 0024 #include "core/Voice.h" 0025 #include "core/Staff.h" 0026 #include "core/VoiceBar.h" 0027 #include "core/Chord.h" 0028 #include "core/Note.h" 0029 #include "core/Clef.h" 0030 #include "core/Bar.h" 0031 #include "core/KeySignature.h" 0032 #include "core/TimeSignature.h" 0033 #include "core/StaffSystem.h" 0034 0035 #include <QMultiMap> 0036 #include <QPainterPath> 0037 0038 #include <climits> 0039 #include <algorithm> 0040 0041 using namespace MusicCore; 0042 0043 MusicRenderer::MusicRenderer(MusicStyle* style) : m_style(style), m_debug(false) 0044 { 0045 } 0046 0047 void MusicRenderer::renderSheet(QPainter& painter, Sheet* sheet, int firstSystem, int lastSystem) 0048 { 0049 int firstBar = sheet->staffSystem(firstSystem)->firstBar(); 0050 int lastBar = INT_MAX; 0051 if (lastSystem < sheet->staffSystemCount()-1) { 0052 lastBar = sheet->staffSystem(lastSystem+1)->firstBar()-1; 0053 } 0054 0055 for (int i = 0; i < sheet->partCount(); i++) { 0056 renderPart(painter, sheet->part(i), firstBar, lastBar); 0057 } 0058 for (int i = firstSystem; i <= lastSystem && i < sheet->staffSystemCount(); i++) { 0059 StaffSystem* ss = sheet->staffSystem(i); 0060 if (ss->indent() == 0) continue; 0061 int b = ss->firstBar(); 0062 Bar* bar = sheet->bar(b); 0063 qreal by = bar->position().y(); 0064 qreal ind = ss->indent(); 0065 0066 for (int p = 0; p < sheet->partCount(); p++) { 0067 Part* part = sheet->part(p); 0068 for (int s = 0; s < part->staffCount(); s++) { 0069 Staff* staff = part->staff(s); 0070 qreal y = staff->top(); 0071 qreal dy = staff->lineSpacing(); 0072 0073 painter.setPen(m_style->staffLinePen()); 0074 for (int l = 0; l < staff->lineCount(); l++) { 0075 painter.drawLine(QPointF(0, by + y + l * dy), QPointF(ind, by + y + l * dy)); 0076 } 0077 0078 Clef* clef = ss->clef(staff); 0079 RenderState foo; 0080 qreal x = 15; 0081 if (clef) { 0082 renderClef(painter, clef, QPointF(x, by), foo, Qt::black, true); 0083 x += clef->width() + 15; 0084 } 0085 KeySignature* ks = staff->lastKeySignatureChange(b); 0086 if (ks) { 0087 renderKeySignature(painter, ks, QPointF(x, by), foo, Qt::black, true); 0088 } 0089 } 0090 } 0091 } 0092 } 0093 0094 void MusicRenderer::renderPart(QPainter& painter, Part* part, int firstBar, int lastBar, const QColor& color) 0095 { 0096 if (lastBar < firstBar) return; 0097 0098 for (int i = 0; i < part->staffCount(); i++) { 0099 renderStaff(painter, part->staff(i), firstBar, lastBar, color); 0100 } 0101 qreal firstStaff = part->staff(0)->top(); 0102 int c = part->staffCount()-1; 0103 qreal lastStaff = part->staff(c)->bottom(); 0104 for (int b = firstBar; b <= lastBar && b < part->sheet()->barCount(); b++) { 0105 Bar* bar = part->sheet()->bar(b); 0106 QPointF p = bar->position(); 0107 painter.drawLine(QPointF(p.x() + bar->size(), p.y() + firstStaff), QPointF(p.x() + bar->size(), p.y() + lastStaff)); 0108 if (m_debug) { 0109 painter.setPen(QPen(Qt::green, 0)); 0110 painter.drawLine(QPointF(p.x(), p.y() + firstStaff - 3), QPointF(p.x(), p.y() + lastStaff + 3)); 0111 painter.drawLine(QPointF(p.x() - bar->prefix(), p.y() + firstStaff - 3), QPointF(p.x() - bar->prefix(), p.y() + lastStaff + 3)); 0112 } 0113 0114 // check if the bar contains any elements, if not render a rest 0115 bool hasContents = false; 0116 for (int v = 0; v < part->voiceCount(); v++) { 0117 if (part->voice(v)->bar(bar)->elementCount() > 0) { 0118 hasContents = true; 0119 break; 0120 } 0121 } 0122 0123 if (!hasContents) { 0124 QPointF pos = bar->position(); 0125 qreal w = bar->size(); 0126 for (int sid = 0; sid < part->staffCount(); sid++) { 0127 Staff* s = part->staff(sid); 0128 renderRest(painter, WholeNote, pos + QPointF(w/2, s->top() + s->lineSpacing()), color); 0129 } 0130 } 0131 } 0132 for (int i = 0; i < part->voiceCount(); i++) { 0133 renderVoice(painter, part->voice(i), firstBar, lastBar, color); 0134 } 0135 } 0136 0137 void MusicRenderer::renderStaff(QPainter& painter, Staff *staff, int firstBar, int lastBar, const QColor& color) 0138 { 0139 qreal dy = staff->lineSpacing(); 0140 qreal y = staff->top(); 0141 for (int b = firstBar; b <= lastBar && b < staff->part()->sheet()->barCount(); b++) { 0142 Bar* bar = staff->part()->sheet()->bar(b); 0143 QPointF p = bar->position(); 0144 QPointF prep = bar->prefixPosition() + QPointF(bar->prefix(), 0); 0145 painter.setPen(m_style->staffLinePen(color)); 0146 for (int i = 0; i < staff->lineCount(); i++) { 0147 painter.drawLine(QPointF(p.x(), p.y() + y + i * dy), QPointF(p.x() + bar->size(), p.y() + y + i * dy)); 0148 } 0149 if (bar->prefix() > 0) { 0150 QPointF q = bar->prefixPosition(); 0151 for (int i = 0; i < staff->lineCount(); i++) { 0152 painter.drawLine(QPointF(q.x(), q.y() + y + i * dy), QPointF(q.x() + bar->prefix(), q.y() + y + i * dy)); 0153 } 0154 } 0155 RenderState state; 0156 for (int e = 0; e < bar->staffElementCount(staff); e++) { 0157 StaffElement* se = bar->staffElement(staff, e); 0158 if (se->startTime() == 0) { 0159 renderStaffElement(painter, bar->staffElement(staff, e), prep, state, color); 0160 } else { 0161 renderStaffElement(painter, bar->staffElement(staff, e), p, state, color); 0162 } 0163 } 0164 } 0165 } 0166 0167 void MusicRenderer::renderVoice(QPainter& painter, Voice *voice, int firstBar, int lastBar, const QColor& color) 0168 { 0169 RenderState state; 0170 state.clef = 0; 0171 for (int b = firstBar; b <= lastBar && b < voice->part()->sheet()->barCount(); b++) { 0172 Bar* bar = voice->part()->sheet()->bar(b); 0173 QPointF p = bar->position(); 0174 VoiceBar* vb = voice->bar(bar); 0175 for (int e = 0; e < vb->elementCount(); e++) { 0176 if (vb->element(e)->staff()) { 0177 state.clef = vb->element(e)->staff()->lastClefChange(b, 0); 0178 } 0179 renderElement(painter, vb->element(e), voice, p, state, color); 0180 } 0181 } 0182 } 0183 0184 void MusicRenderer::renderElement(QPainter& painter, VoiceElement* me, Voice* voice, const QPointF& pos, RenderState& state, const QColor& color) 0185 { 0186 Q_UNUSED( state ); // unused for now, but will probably be used again in the future 0187 0188 qreal top = 0; 0189 if (me->staff()) top += me->staff()->top(); 0190 if (m_debug) { 0191 painter.setPen(QPen(Qt::blue, 0)); 0192 painter.drawLine(pos + QPointF(me->x(), top + me->y() - 4), pos + QPointF(me->x(), top + me->y() + me->height() + 4)); 0193 painter.drawLine(pos + QPointF(me->x() + me->width(), top + me->y() - 4), pos + QPointF(me->x() + me->width(), top + me->y() + me->height() + 4)); 0194 0195 painter.drawLine(pos + QPointF(me->x() - 4, top + me->y()), pos + QPointF(me->x() + me->width() + 4, top + me->y())); 0196 painter.drawLine(pos + QPointF(me->x() - 4, top + me->y() + me->height()), pos + QPointF(me->x() + me->width() + 4, top + me->y() + me->height())); 0197 0198 painter.setPen(QPen(Qt::red, 0)); 0199 painter.drawLine(pos + QPointF(me->x() + me->beatline(), top + me->y() - 10), pos + QPointF(me->x() + me->beatline(), top + me->y() + me->height() + 10)); 0200 } 0201 0202 // TODO: make this less hacky 0203 Chord *c = dynamic_cast<Chord*>(me); 0204 if (c) renderChord(painter, c, voice, pos, color); 0205 } 0206 0207 void MusicRenderer::renderStaffElement(QPainter& painter, MusicCore::StaffElement* se, const QPointF& pos, RenderState& state, const QColor& color) 0208 { 0209 qreal top = 0; 0210 top += se->staff()->top(); 0211 if (m_debug) { 0212 painter.setPen(QPen(Qt::blue, 0)); 0213 painter.drawLine(pos + QPointF(se->x(), top + se->y() - 20), pos + QPointF(se->x(), top + se->y() + 20)); 0214 painter.drawLine(pos + QPointF(se->x() + se->width(), top + se->y() - 20), pos + QPointF(se->x() + se->width(), top + se->y() + 20)); 0215 0216 painter.drawLine(pos + QPointF(se->x() - 10, top + se->y()), pos + QPointF(se->x() + se->width() + 10, top + se->y())); 0217 painter.drawLine(pos + QPointF(se->x() - 10, top + se->y() + se->height()), pos + QPointF(se->x() + se->width() + 10, top + se->y() + se->height())); 0218 } 0219 0220 Clef *cl = dynamic_cast<Clef*>(se); 0221 if (cl) renderClef(painter, cl, pos, state, color); 0222 KeySignature *ks = dynamic_cast<KeySignature*>(se); 0223 if (ks) renderKeySignature(painter, ks, pos, state, color); 0224 TimeSignature* ts = dynamic_cast<TimeSignature*>(se); 0225 if (ts) renderTimeSignature(painter, ts, pos, color); 0226 } 0227 0228 0229 void MusicRenderer::renderClef(QPainter& painter, Clef *c, const QPointF& pos, RenderState& state, const QColor& color, bool ignoreOwnPos) 0230 { 0231 Q_UNUSED(color); 0232 state.clef = c; 0233 Staff* s = c->staff(); 0234 m_style->renderClef(painter, pos.x() + (ignoreOwnPos ? 0 : c->x()), pos.y() + s->top() + (s->lineCount() - c->line()) * s->lineSpacing(), c->shape()); 0235 } 0236 0237 void MusicRenderer::renderKeySignature(QPainter& painter, KeySignature* ks, const QPointF& pos, RenderState& state, const QColor& color, bool ignoreOwnPos) 0238 { 0239 Q_UNUSED(color); 0240 Staff * s = ks->staff(); 0241 qreal curx = pos.x() + (ignoreOwnPos ? 0 : ks->x()); 0242 // draw naturals for sharps 0243 int idx = 3; 0244 for (int i = 0; i < 7; i++) { 0245 if (ks->cancel(idx) > 0) { 0246 int line = 10; 0247 if (state.clef) line = state.clef->pitchToLine(idx); 0248 0249 while (line < 0) line += 7; 0250 while (line >= 6) line -= 7; 0251 m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 0 ); 0252 0253 curx += 6; 0254 } 0255 idx = (idx + 4) % 7; 0256 } 0257 0258 // draw naturals for flats 0259 idx = 6; 0260 for (int i = 0; i < 7; i++) { 0261 if (ks->cancel(idx) < 0) { 0262 int line = 10; 0263 if (state.clef) line = state.clef->pitchToLine(idx); 0264 0265 while (line < 0) line += 7; 0266 while (line >= 6) line -= 7; 0267 0268 m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 0 ); 0269 0270 curx += 6; 0271 } 0272 idx = (idx + 3) % 7; 0273 } 0274 0275 // draw sharps 0276 idx = 3; 0277 for (int i = 0; i < 7; i++) { 0278 if (ks->accidentals(idx) > 0) { 0279 int line = 10; 0280 if (state.clef) line = state.clef->pitchToLine(idx); 0281 0282 while (line < 0) line += 7; 0283 while (line >= 6) line -= 7; 0284 m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, 1 ); 0285 0286 curx += 6; 0287 } 0288 idx = (idx + 4) % 7; 0289 } 0290 0291 // draw flats 0292 idx = 6; 0293 for (int i = 0; i < 7; i++) { 0294 if (ks->accidentals(idx) < 0) { 0295 int line = 10; 0296 if (state.clef) line = state.clef->pitchToLine(idx); 0297 0298 while (line < 0) line += 7; 0299 while (line >= 6) line -= 7; 0300 0301 m_style->renderAccidental( painter, curx, pos.y() + s->top() + line * s->lineSpacing() / 2, -1 ); 0302 0303 curx += 6; 0304 } 0305 idx = (idx + 3) % 7; 0306 } 0307 } 0308 0309 void MusicRenderer::renderTimeSignature(QPainter& painter, TimeSignature* ts, const QPointF& pos, const QColor& color) 0310 { 0311 Q_UNUSED(color); 0312 Staff* s = ts->staff(); 0313 qreal hh = 0.5 * (s->lineCount() - 1) * s->lineSpacing(); 0314 m_style->renderTimeSignatureNumber( painter, pos.x() + ts->x(), pos.y() + s->top() + hh, ts->width(), ts->beats()); 0315 m_style->renderTimeSignatureNumber( painter, pos.x() + ts->x(), pos.y() + s->top() + 2*hh, ts->width(), ts->beat()); 0316 } 0317 0318 void MusicRenderer::renderRest(QPainter& painter, Duration duration, const QPointF& pos, const QColor& color) 0319 { 0320 m_style->renderRest(painter, pos.x(), pos.y(), duration, color); 0321 } 0322 0323 void MusicRenderer::renderChord(QPainter& painter, Chord* chord, Voice* voice, const QPointF& ref, const QColor& color) 0324 { 0325 qreal x = chord->x(); 0326 if (chord->noteCount() == 0) { // a rest 0327 Staff *s = chord->staff(); 0328 renderRest(painter, chord->duration(), ref + QPointF(x, s->top() + (2 - (chord->duration() == WholeNote)) * s->lineSpacing()), color); 0329 return; 0330 } 0331 int topLine = 0, bottomLine = 0; 0332 VoiceBar* vb = chord->voiceBar(); 0333 Bar* bar = vb->bar(); 0334 Sheet* sheet = voice->part()->sheet(); 0335 int barIdx = bar->sheet()->indexOfBar(bar); 0336 qreal topy = 1e9, bottomy = -1e9; 0337 Staff* topStaff = 0, *bottomStaff = 0; 0338 0339 qreal mainNoteX = (chord->stemDirection() == StemUp ? chord->stemX() - 6 : chord->stemX()); 0340 qreal alternateNoteX = mainNoteX + (chord->stemDirection() == StemUp ? 6 : -6); 0341 bool prevAlternate = false; 0342 qreal maxNoteX = 0; 0343 0344 QMultiMap<Staff*, int> dots; 0345 0346 Chord* nextChord = 0; 0347 0348 for (int i = 0; i < chord->noteCount(); i++) { 0349 Note *n = chord->note(i); 0350 Staff * s = n->staff(); 0351 Clef* clef = s->lastClefChange(barIdx); 0352 int line = 10; 0353 if (clef) line = clef->pitchToLine(n->pitch()); 0354 0355 qreal noteX = mainNoteX; 0356 if (i > 0) { 0357 int prevPitch = chord->note(i-1)->pitch(); 0358 if (abs(prevPitch - n->pitch()) <= 1 && !prevAlternate) { 0359 noteX = alternateNoteX; 0360 } 0361 } 0362 if (i < chord->noteCount()-1 && chord->stemDirection() == StemDown) { 0363 int pitch = n->pitch(); 0364 int nPitch = chord->note(i+1)->pitch(); 0365 if (abs(pitch - nPitch) <= 1 && !prevAlternate) { 0366 noteX = alternateNoteX; 0367 } 0368 } 0369 prevAlternate = noteX != mainNoteX; 0370 if (noteX > maxNoteX) maxNoteX = noteX; 0371 0372 if (line > 9) { // lines under the bar 0373 painter.setPen(m_style->staffLinePen(color)); 0374 for (int i = 10; i <= line; i+= 2) { 0375 qreal y = s->top() + i * s->lineSpacing() / 2; 0376 painter.drawLine(ref + QPointF(noteX - 4, y), ref + QPointF(noteX + 10, y)); 0377 } 0378 } else if (line < -1) { // lines above the bar 0379 painter.setPen(m_style->staffLinePen(color)); 0380 for (int i = -2; i >= line; i-= 2) { 0381 qreal y = s->top() + i * s->lineSpacing() / 2; 0382 painter.drawLine(ref + QPointF(noteX - 4, y), ref + QPointF(noteX + 10, y)); 0383 } 0384 } 0385 0386 qreal ypos = s->top() + line * s->lineSpacing() / 2; 0387 if (ypos < topy) { 0388 topy = ypos; 0389 topLine = line; 0390 topStaff = s; 0391 } 0392 if (ypos > bottomy) { 0393 bottomy = ypos; 0394 bottomLine = line; 0395 bottomStaff = s; 0396 } 0397 0398 m_style->renderNoteHead( painter, ref.x() + noteX, ref.y() + s->top() + line * s->lineSpacing() / 2, chord->duration(), color ); 0399 0400 // render accidentals 0401 if (n->drawAccidentals()) { 0402 m_style->renderAccidental( painter, ref.x() + x, ref.y() + /*chord->y() +*/ s->top() + line * s->lineSpacing() / 2, n->accidentals(), color ); 0403 } 0404 0405 dots.insert(s, line); 0406 0407 if (n->isStartTie()) { 0408 // render tie for this note... 0409 if (!nextChord) { 0410 // figure out what the next chord in this voice is 0411 bool afterCurrent = false; 0412 for (int e = 0; e < vb->elementCount(); e++) { 0413 if (afterCurrent) { 0414 nextChord = dynamic_cast<Chord*>(vb->element(e)); 0415 if (nextChord) break; 0416 } else { 0417 if (vb->element(e) == chord) { 0418 afterCurrent = true; 0419 } 0420 } 0421 } 0422 if (!nextChord) { 0423 // check the next bar 0424 int nextBar = sheet->indexOfBar(bar)+1; 0425 if (nextBar < sheet->barCount()) { 0426 VoiceBar* nextVB = voice->bar(nextBar); 0427 for (int e = 0; e < nextVB->elementCount(); e++) { 0428 nextChord = dynamic_cast<Chord*>(nextVB->element(e)); 0429 if (nextChord) break; 0430 } 0431 } 0432 } 0433 } 0434 0435 // okay, now nextChord is the chord to which the tie should go 0436 if (nextChord) { 0437 QPointF startPos = bar->position() + QPointF(1 + chord->x() + chord->width(), ypos); 0438 QPointF endPos = nextChord->voiceBar()->bar()->position() + QPointF(nextChord->x() - 1, ypos); 0439 if (bar->position().y() < nextChord->voiceBar()->bar()->position().y() - 1e-6) { 0440 endPos = bar->position() + QPointF(bar->size(), 0); 0441 } 0442 0443 endPos.setY(startPos.y()); 0444 QPointF c1a = startPos + QPointF(2, 4); 0445 QPointF c2a = endPos + QPointF(-2, 4); 0446 QPointF c1b = startPos + QPointF(2, 5); 0447 QPointF c2b = endPos + QPointF(-2, 5); 0448 0449 QPainterPath p; 0450 p.moveTo(startPos); 0451 p.cubicTo(c1a, c2a, endPos); 0452 p.cubicTo(c2b, c1b, startPos); 0453 painter.setPen(Qt::NoPen);//m_style->slurPen(color)); 0454 painter.setBrush(QBrush(color)); 0455 painter.drawPath(p); 0456 } 0457 } 0458 } 0459 0460 // calculate correct positioning of dots 0461 // render dots of notes 0462 painter.setPen(m_style->noteDotPen(color)); 0463 foreach (Staff* s, dots.keys()) { 0464 QList<int> lines = dots.values(s); 0465 std::sort(lines.begin(), lines.end()); 0466 0467 int lastLine = INT_MIN; 0468 bool moveGroupDown = true; 0469 for (int i = 0; i < lines.size(); i++) { 0470 int line = lines[i]; 0471 if (line % 2 == 0) { 0472 line--; 0473 } 0474 if (line == lastLine) { 0475 if (moveGroupDown) { 0476 lines[i-1] += 2; 0477 for (int j = i-2; j >= 0; j--) { 0478 if (lines[j] == lines[j+1]) { 0479 lines[j] += 2; 0480 } else { 0481 break; 0482 } 0483 } 0484 } else { 0485 line -= 2; 0486 } 0487 moveGroupDown = !moveGroupDown; 0488 } 0489 lines[i] = line; 0490 lastLine = line; 0491 } 0492 0493 foreach (int line, lines) { 0494 qreal dotX = maxNoteX + 11; 0495 for (int i = 0; i < chord->dots(); i++) { 0496 painter.drawPoint(ref + QPointF(dotX, s->top() + line * s->lineSpacing() / 2)); 0497 dotX += 3; 0498 } 0499 } 0500 } 0501 0502 qreal stemLen = chord->stemLength() * 2; 0503 if (stemLen != 0.0 && stemLen != -0.0) { 0504 qreal stemX = chord->stemX(); 0505 bool stemsUp = chord->stemDirection() == StemUp; 0506 0507 painter.setPen(m_style->stemPen(color)); 0508 if (stemsUp) { 0509 painter.drawLine(ref + QPointF(stemX, chord->stemEndY()), 0510 ref + QPointF(stemX, bottomStaff->top() + bottomLine * bottomStaff->lineSpacing() / 2)); 0511 if (chord->beamType(0) == BeamFlag) { 0512 m_style->renderNoteFlags( painter, ref.x() + stemX, ref.y() + chord->stemEndY(), chord->duration(), stemsUp, color ); 0513 } 0514 } else { 0515 painter.drawLine(ref + QPointF(stemX, topStaff->top() + topLine * topStaff->lineSpacing() / 2), 0516 ref + QPointF(stemX, chord->stemEndY())); 0517 if (chord->beamType(0) == BeamFlag) { 0518 m_style->renderNoteFlags( painter, ref.x() + stemX, ref.y() + chord->stemEndY(), chord->duration(), stemsUp, color ); 0519 } 0520 } 0521 0522 painter.setPen(QPen(Qt::NoPen)); 0523 painter.setBrush(QBrush(color)); 0524 for (int i = 0; i < chord->beamCount(); i++) { 0525 if (chord->beamType(i) == BeamStart) { 0526 const Chord* endChord = chord->beamEnd(i); 0527 0528 QPointF beamStart(chord->stemX(), chord->stemEndY()); 0529 QPointF beamEnd(endChord->stemX(), endChord->stemEndY()); 0530 if (stemsUp) { 0531 beamStart += QPointF(0, topStaff->lineSpacing() * i); 0532 beamEnd += QPointF(0, topStaff->lineSpacing() * i); 0533 } else { 0534 beamStart -= QPointF(0, bottomStaff->lineSpacing() * i); 0535 beamEnd -= QPointF(0, bottomStaff->lineSpacing() * i); 0536 } 0537 0538 0539 QPointF dir(0, (stemsUp ? 1 : -1) * m_style->beamLineWidth()); 0540 QPointF p[4]; 0541 p[0] = ref + beamStart; 0542 p[1] = ref + beamEnd; 0543 p[2] = p[1] + dir; 0544 p[3] = p[0] + dir; 0545 painter.drawConvexPolygon(p, 4); 0546 } else if (chord->beamType(i) == BeamForwardHook || chord->beamType(i) == BeamBackwardHook) { 0547 QPointF beamStart(chord->stemX(), chord->stemEndY()); 0548 qreal dir = 6; 0549 if (chord->beamType(i) == BeamBackwardHook) dir = -dir; 0550 if (stemsUp) { 0551 beamStart += QPointF(0, topStaff->lineSpacing() * i); 0552 } else { 0553 beamStart -= QPointF(0, bottomStaff->lineSpacing() * i); 0554 } 0555 0556 QPointF beamEnd = beamStart + QPointF(dir, dir * chord->beamDirection()); 0557 0558 QPointF bdir(0, (stemsUp ? 1 : -1) * m_style->beamLineWidth()); 0559 QPointF p[4]; 0560 p[0] = ref + beamStart; 0561 p[1] = ref + beamEnd; 0562 p[2] = p[1] + bdir; 0563 p[3] = p[0] + bdir; 0564 painter.drawConvexPolygon(p, 4); 0565 } 0566 } 0567 0568 } 0569 } 0570 0571 void MusicRenderer::renderNote(QPainter& painter, Duration duration, const QPointF& pos, qreal stemLength, const QColor& color) 0572 { 0573 m_style->renderNoteHead(painter, pos.x(), pos.y(), duration, color); 0574 0575 if (duration <= HalfNote) { 0576 painter.setPen(m_style->stemPen(color)); 0577 painter.drawLine(pos + QPointF(6, -stemLength), pos + QPointF(6, 0)); 0578 } 0579 if (duration <= EighthNote) { 0580 m_style->renderNoteFlags(painter, pos.x()+6, pos.y() - stemLength, duration, true, color); 0581 } 0582 } 0583 0584 void MusicRenderer::renderAccidental(QPainter& painter, int accidentals, const QPointF& pos, const QColor& color) 0585 { 0586 m_style->renderAccidental( painter, pos.x(), pos.y(), accidentals, color ); 0587 }