Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2023 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "singledraw.h"
24 :
25 : #include "draw/painter.h"
26 : #include "draw/svgrenderer.h"
27 : #include "draw/types/drawtypes.h"
28 :
29 : #include "iengravingconfiguration.h" // IWYU pragma: keep
30 :
31 : #include "style/style.h"
32 : #include "style/defaultstyle.h"
33 :
34 : #include "dom/accidental.h"
35 : #include "dom/actionicon.h"
36 : #include "dom/ambitus.h"
37 : #include "dom/arpeggio.h"
38 : #include "dom/articulation.h"
39 :
40 : #include "dom/bagpembell.h"
41 : #include "dom/barline.h"
42 : #include "dom/beam.h"
43 : #include "dom/bend.h"
44 : #include "dom/bracket.h"
45 : #include "dom/breath.h"
46 :
47 : #include "dom/chordbracket.h"
48 : #include "dom/chordline.h"
49 : #include "dom/clef.h"
50 : #include "dom/capo.h"
51 :
52 : #include "dom/deadslapped.h"
53 : #include "dom/dynamic.h"
54 :
55 : #include "dom/expression.h"
56 :
57 : #include "dom/fermata.h"
58 : #include "dom/figuredbass.h"
59 : #include "dom/fingering.h"
60 : #include "dom/fret.h"
61 :
62 : #include "dom/glissando.h"
63 : #include "dom/gradualtempochange.h"
64 : #include "dom/guitarbend.h"
65 :
66 : #include "dom/hairpin.h"
67 : #include "dom/hammeronpulloff.h"
68 : #include "dom/harppedaldiagram.h"
69 : #include "dom/harmonicmark.h"
70 : #include "dom/harmony.h"
71 : #include "dom/hook.h"
72 :
73 : #include "dom/image.h"
74 : #include "dom/instrchange.h"
75 : #include "dom/instrumentname.h"
76 :
77 : #include "dom/jump.h"
78 :
79 : #include "dom/keysig.h"
80 :
81 : #include "dom/layoutbreak.h"
82 : #include "dom/ledgerline.h"
83 : #include "dom/letring.h"
84 : #include "dom/lyrics.h"
85 :
86 : #include "dom/marker.h"
87 : #include "dom/measure.h"
88 : #include "dom/measurenumber.h"
89 : #include "dom/measurerepeat.h"
90 :
91 : #include "dom/note.h"
92 : #include "dom/noteline.h"
93 :
94 : #include "dom/ornament.h"
95 : #include "dom/ottava.h"
96 :
97 : #include "dom/palmmute.h"
98 : #include "dom/part.h"
99 : #include "dom/pedal.h"
100 : #include "dom/pickscrape.h"
101 : #include "dom/playcounttext.h"
102 : #include "dom/playtechannotation.h"
103 :
104 : #include "dom/rasgueado.h"
105 : #include "dom/rehearsalmark.h"
106 : #include "dom/rest.h"
107 :
108 : #include "dom/score.h"
109 : #include "dom/shadownote.h"
110 : #include "dom/slur.h"
111 : #include "dom/soundflag.h"
112 : #include "dom/spacer.h"
113 : #include "dom/staff.h"
114 : #include "dom/stafflines.h"
115 : #include "dom/staffstate.h"
116 : #include "dom/stafftext.h"
117 : #include "dom/stafftype.h"
118 : #include "dom/stafftypechange.h"
119 : #include "dom/stavesharinglabel.h"
120 : #include "dom/stem.h"
121 : #include "dom/stemslash.h"
122 : #include "dom/sticking.h"
123 : #include "dom/stringtunings.h"
124 : #include "dom/symbol.h"
125 : #include "dom/systemdivider.h"
126 : #include "dom/systemtext.h"
127 :
128 : #include "dom/tapping.h"
129 : #include "dom/tempotext.h"
130 : #include "dom/text.h"
131 : #include "dom/textbase.h"
132 : #include "dom/textline.h"
133 : #include "dom/textlinebase.h"
134 : #include "dom/tie.h"
135 : #include "dom/timesig.h"
136 : #include "dom/tremolosinglechord.h"
137 : #include "dom/tremolotwochord.h"
138 : #include "dom/tremolobar.h"
139 : #include "dom/trill.h"
140 : #include "dom/tripletfeel.h"
141 : #include "dom/tuplet.h"
142 :
143 : #include "dom/vibrato.h"
144 : #include "dom/volta.h"
145 :
146 : #include "dom/whammybar.h"
147 :
148 : #include "editing/mscoreview.h"
149 :
150 : #include "rendering/score/stemlayout.h"
151 :
152 : #include "infrastructure/rtti.h"
153 :
154 : using namespace mu::engraving::rendering::single;
155 : using namespace mu::engraving;
156 : using namespace mu::engraving::rtti;
157 : using namespace muse;
158 : using namespace muse::draw;
159 :
160 0 : void SingleDraw::drawItem(const EngravingItem* item, Painter* painter, const PaintOptions& opt)
161 : {
162 0 : switch (item->type()) {
163 0 : case ElementType::ACCIDENTAL: draw(item_cast<const Accidental*>(item), painter, opt);
164 0 : break;
165 0 : case ElementType::ACTION_ICON: draw(item_cast<const ActionIcon*>(item), painter, opt);
166 0 : break;
167 0 : case ElementType::AMBITUS: draw(item_cast<const Ambitus*>(item), painter, opt);
168 0 : break;
169 0 : case ElementType::ARPEGGIO: draw(item_cast<const Arpeggio*>(item), painter, opt);
170 0 : break;
171 0 : case ElementType::CHORD_BRACKET: draw(item_cast<const ChordBracket*>(item), painter, opt);
172 0 : break;
173 0 : case ElementType::ARTICULATION: draw(item_cast<const Articulation*>(item), painter, opt);
174 0 : break;
175 :
176 0 : case ElementType::BAGPIPE_EMBELLISHMENT: draw(item_cast<const BagpipeEmbellishment*>(item), painter, opt);
177 0 : break;
178 0 : case ElementType::BAR_LINE: draw(item_cast<const BarLine*>(item), painter, opt);
179 0 : break;
180 0 : case ElementType::BEAM: draw(item_cast<const Beam*>(item), painter, opt);
181 0 : break;
182 0 : case ElementType::BEND: draw(item_cast<const Bend*>(item), painter, opt);
183 0 : break;
184 0 : case ElementType::BRACKET: draw(item_cast<const Bracket*>(item), painter, opt);
185 0 : break;
186 0 : case ElementType::BREATH: draw(item_cast<const Breath*>(item), painter, opt);
187 0 : break;
188 :
189 0 : case ElementType::CHORDLINE: draw(item_cast<const ChordLine*>(item), painter, opt);
190 0 : break;
191 0 : case ElementType::CLEF: draw(item_cast<const Clef*>(item), painter, opt);
192 0 : break;
193 0 : case ElementType::CAPO: draw(item_cast<const Capo*>(item), painter, opt);
194 0 : break;
195 :
196 0 : case ElementType::DEAD_SLAPPED: draw(item_cast<const DeadSlapped*>(item), painter, opt);
197 0 : break;
198 0 : case ElementType::DYNAMIC: draw(item_cast<const Dynamic*>(item), painter, opt);
199 0 : break;
200 :
201 0 : case ElementType::EXPRESSION: draw(item_cast<const Expression*>(item), painter, opt);
202 0 : break;
203 :
204 0 : case ElementType::FERMATA: draw(item_cast<const Fermata*>(item), painter, opt);
205 0 : break;
206 0 : case ElementType::FIGURED_BASS: draw(item_cast<const FiguredBass*>(item), painter, opt);
207 0 : break;
208 0 : case ElementType::FINGERING: draw(item_cast<const Fingering*>(item), painter, opt);
209 0 : break;
210 0 : case ElementType::FRET_DIAGRAM: draw(item_cast<const FretDiagram*>(item), painter, opt);
211 0 : break;
212 0 : case ElementType::FSYMBOL: draw(item_cast<const FSymbol*>(item), painter, opt);
213 0 : break;
214 :
215 0 : case ElementType::GLISSANDO_SEGMENT: draw(item_cast<const GlissandoSegment*>(item), painter, opt);
216 0 : break;
217 0 : case ElementType::GRADUAL_TEMPO_CHANGE_SEGMENT: draw(item_cast<const GradualTempoChangeSegment*>(item), painter, opt);
218 0 : break;
219 0 : case ElementType::GUITAR_BEND_SEGMENT: draw(item_cast<const GuitarBendSegment*>(item), painter, opt);
220 0 : break;
221 0 : case ElementType::GUITAR_BEND_TEXT: drawTextBase(toTextBase(item), painter, opt);
222 0 : break;
223 :
224 0 : case ElementType::HAIRPIN_SEGMENT: draw(item_cast<const HairpinSegment*>(item), painter, opt);
225 0 : break;
226 0 : case ElementType::HAMMER_ON_PULL_OFF_SEGMENT: draw(item_cast<const HammerOnPullOffSegment*>(item), painter, opt);
227 0 : break;
228 0 : case ElementType::HAMMER_ON_PULL_OFF_TEXT: draw(item_cast<const HammerOnPullOffText*>(item), painter, opt);
229 0 : break;
230 0 : case ElementType::HARP_DIAGRAM: draw(item_cast<const HarpPedalDiagram*>(item), painter, opt);
231 0 : break;
232 0 : case ElementType::HARMONIC_MARK_SEGMENT: draw(item_cast<const HarmonicMarkSegment*>(item), painter, opt);
233 0 : break;
234 0 : case ElementType::HARMONY: draw(item_cast<const Harmony*>(item), painter, opt);
235 0 : break;
236 0 : case ElementType::HOOK: draw(item_cast<const Hook*>(item), painter, opt);
237 0 : break;
238 :
239 0 : case ElementType::IMAGE: draw(item_cast<const Image*>(item), painter, opt);
240 0 : break;
241 0 : case ElementType::INSTRUMENT_CHANGE: draw(item_cast<const InstrumentChange*>(item), painter, opt);
242 0 : break;
243 0 : case ElementType::INSTRUMENT_NAME: draw(item_cast<const InstrumentName*>(item), painter, opt);
244 0 : break;
245 :
246 0 : case ElementType::JUMP: draw(item_cast<const Jump*>(item), painter, opt);
247 0 : break;
248 :
249 0 : case ElementType::KEYSIG: draw(item_cast<const KeySig*>(item), painter, opt);
250 0 : break;
251 :
252 0 : case ElementType::LAYOUT_BREAK: draw(item_cast<const LayoutBreak*>(item), painter, opt);
253 0 : break;
254 0 : case ElementType::LEDGER_LINE: draw(item_cast<const LedgerLine*>(item), painter, opt);
255 0 : break;
256 0 : case ElementType::LET_RING_SEGMENT: draw(item_cast<const LetRingSegment*>(item), painter, opt);
257 0 : break;
258 0 : case ElementType::LYRICS: draw(item_cast<const Lyrics*>(item), painter, opt);
259 0 : break;
260 :
261 0 : case ElementType::MARKER: draw(item_cast<const Marker*>(item), painter, opt);
262 0 : break;
263 0 : case ElementType::MEASURE_NUMBER: draw(item_cast<const MeasureNumber*>(item), painter, opt);
264 0 : break;
265 0 : case ElementType::MEASURE_REPEAT: draw(item_cast<const MeasureRepeat*>(item), painter, opt);
266 0 : break;
267 :
268 0 : case ElementType::NOTE: draw(item_cast<const Note*>(item), painter, opt);
269 0 : break;
270 0 : case ElementType::NOTEHEAD: draw(item_cast<const NoteHead*>(item), painter, opt);
271 0 : break;
272 0 : case ElementType::NOTELINE_SEGMENT: draw(item_cast<const NoteLineSegment*>(item), painter, opt);
273 0 : break;
274 :
275 0 : case ElementType::ORNAMENT: draw(item_cast<const Ornament*>(item), painter, opt);
276 0 : break;
277 0 : case ElementType::OTTAVA_SEGMENT: draw(item_cast<const OttavaSegment*>(item), painter, opt);
278 0 : break;
279 :
280 0 : case ElementType::PALM_MUTE_SEGMENT: draw(item_cast<const PalmMuteSegment*>(item), painter, opt);
281 0 : break;
282 0 : case ElementType::PEDAL_SEGMENT: draw(item_cast<const PedalSegment*>(item), painter, opt);
283 0 : break;
284 0 : case ElementType::PICK_SCRAPE_SEGMENT: draw(item_cast<const PickScrapeSegment*>(item), painter, opt);
285 0 : break;
286 0 : case ElementType::PLAY_COUNT_TEXT: draw(item_cast<const PlayCountText*>(item), painter, opt);
287 0 : break;
288 0 : case ElementType::PLAYTECH_ANNOTATION: draw(item_cast<const PlayTechAnnotation*>(item), painter, opt);
289 0 : break;
290 :
291 0 : case ElementType::RASGUEADO_SEGMENT: draw(item_cast<const RasgueadoSegment*>(item), painter, opt);
292 0 : break;
293 0 : case ElementType::REHEARSAL_MARK: draw(item_cast<const RehearsalMark*>(item), painter, opt);
294 0 : break;
295 0 : case ElementType::REST: draw(item_cast<const Rest*>(item), painter, opt);
296 0 : break;
297 :
298 0 : case ElementType::SHADOW_NOTE: draw(item_cast<const ShadowNote*>(item), painter, opt);
299 0 : break;
300 0 : case ElementType::SLUR_SEGMENT: draw(item_cast<const SlurSegment*>(item), painter, opt);
301 0 : break;
302 0 : case ElementType::SPACER: draw(item_cast<const Spacer*>(item), painter, opt);
303 0 : break;
304 0 : case ElementType::STAFF_LINES: draw(item_cast<const StaffLines*>(item), painter, opt);
305 0 : break;
306 0 : case ElementType::STAFF_STATE: draw(item_cast<const StaffState*>(item), painter, opt);
307 0 : break;
308 0 : case ElementType::STAFF_TEXT: draw(item_cast<const StaffText*>(item), painter, opt);
309 0 : break;
310 0 : case ElementType::STAVE_SHARING_LABEL: draw(item_cast<const StaveSharingLabel*>(item), painter, opt);
311 0 : break;
312 0 : case ElementType::STAFFTYPE_CHANGE: draw(item_cast<const StaffTypeChange*>(item), painter, opt);
313 0 : break;
314 0 : case ElementType::STEM: draw(item_cast<const Stem*>(item), painter, opt);
315 0 : break;
316 0 : case ElementType::STEM_SLASH: draw(item_cast<const StemSlash*>(item), painter, opt);
317 0 : break;
318 0 : case ElementType::STICKING: draw(item_cast<const Sticking*>(item), painter, opt);
319 0 : break;
320 0 : case ElementType::STRING_TUNINGS: draw(item_cast<const StringTunings*>(item), painter, opt);
321 0 : break;
322 0 : case ElementType::SYMBOL: draw(item_cast<const Symbol*>(item), painter, opt);
323 0 : break;
324 0 : case ElementType::SYSTEM_DIVIDER: draw(item_cast<const SystemDivider*>(item), painter, opt);
325 0 : break;
326 0 : case ElementType::SYSTEM_TEXT: draw(item_cast<const SystemText*>(item), painter, opt);
327 0 : break;
328 0 : case ElementType::SOUND_FLAG: draw(item_cast<const SoundFlag*>(item), painter, opt);
329 0 : break;
330 :
331 0 : case ElementType::TAPPING: draw(item_cast<const Tapping*>(item), painter, opt);
332 0 : break;
333 0 : case ElementType::TEMPO_TEXT: draw(item_cast<const TempoText*>(item), painter, opt);
334 0 : break;
335 0 : case ElementType::TEXT: draw(item_cast<const Text*>(item), painter, opt);
336 0 : break;
337 0 : case ElementType::TEXTLINE_SEGMENT: draw(item_cast<const TextLineSegment*>(item), painter, opt);
338 0 : break;
339 0 : case ElementType::TIE_SEGMENT: draw(item_cast<const TieSegment*>(item), painter, opt);
340 0 : break;
341 0 : case ElementType::TIMESIG: draw(item_cast<const TimeSig*>(item), painter, opt);
342 0 : break;
343 0 : case ElementType::TREMOLO_SINGLECHORD: draw(item_cast<const TremoloSingleChord*>(item), painter, opt);
344 0 : break;
345 0 : case ElementType::TREMOLO_TWOCHORD: draw(item_cast<const TremoloTwoChord*>(item), painter, opt);
346 0 : break;
347 0 : case ElementType::TREMOLOBAR: draw(item_cast<const TremoloBar*>(item), painter, opt);
348 0 : break;
349 0 : case ElementType::TRILL_SEGMENT: draw(item_cast<const TrillSegment*>(item), painter, opt);
350 0 : break;
351 0 : case ElementType::TRIPLET_FEEL: draw(item_cast<const TripletFeel*>(item), painter, opt);
352 0 : break;
353 0 : case ElementType::TUPLET: draw(item_cast<const Tuplet*>(item), painter, opt);
354 0 : break;
355 :
356 0 : case ElementType::VIBRATO_SEGMENT: draw(item_cast<const VibratoSegment*>(item), painter, opt);
357 0 : break;
358 0 : case ElementType::VOLTA_SEGMENT: draw(item_cast<const VoltaSegment*>(item), painter, opt);
359 0 : break;
360 :
361 0 : case ElementType::WHAMMY_BAR_SEGMENT: draw(item_cast<const WhammyBarSegment*>(item), painter, opt);
362 0 : break;
363 0 : default:
364 0 : NOT_IMPLEMENTED << item->typeName();
365 0 : UNREACHABLE;
366 : }
367 0 : }
368 :
369 0 : void SingleDraw::draw(const Accidental* item, Painter* painter, const PaintOptions& opt)
370 : {
371 0 : IF_ASSERT_FAILED(item->ldata()) {
372 0 : return;
373 : }
374 :
375 0 : painter->setPen(item->curColor(opt));
376 0 : for (const Accidental::LayoutData::Sym& e : item->ldata()->syms) {
377 0 : item->drawSymbol(e.sym, painter, PointF(e.x, e.y));
378 : }
379 : }
380 :
381 0 : void SingleDraw::draw(const ActionIcon* item, Painter* painter, const PaintOptions&)
382 : {
383 : TRACE_DRAW_ITEM;
384 0 : painter->setFont(item->iconFont());
385 0 : painter->drawText(PointF(), Char(item->icon()));
386 0 : }
387 :
388 0 : void SingleDraw::draw(const Ambitus* item, Painter* painter, const PaintOptions& opt)
389 : {
390 : TRACE_DRAW_ITEM;
391 :
392 0 : const Ambitus::LayoutData* layoutData = item->ldata();
393 0 : IF_ASSERT_FAILED(layoutData) {
394 0 : return;
395 : }
396 :
397 0 : double spatium = item->spatium();
398 0 : double lw = item->lineWidth().val() * spatium;
399 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
400 :
401 0 : item->drawSymbol(item->noteHead(), painter, layoutData->topPos);
402 0 : item->drawSymbol(item->noteHead(), painter, layoutData->bottomPos);
403 0 : if (item->hasLine()) {
404 0 : painter->drawLine(layoutData->line);
405 : }
406 : }
407 :
408 0 : void SingleDraw::draw(const Arpeggio* item, Painter* painter, const PaintOptions& opt)
409 : {
410 : TRACE_DRAW_ITEM;
411 :
412 0 : const Arpeggio::LayoutData* ldata = item->ldata();
413 0 : IF_ASSERT_FAILED(ldata) {
414 0 : return;
415 : }
416 :
417 0 : const double y1 = ldata->bbox().top();
418 0 : const double y2 = ldata->bbox().bottom();
419 0 : const double lineWidth = item->style().styleAbsolute(Sid::arpeggioLineWidth);
420 :
421 0 : painter->setPen(Pen(item->curColor(opt), lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
422 0 : painter->save();
423 :
424 0 : switch (item->arpeggioType()) {
425 0 : case ArpeggioType::NORMAL:
426 : case ArpeggioType::UP:
427 : {
428 0 : const RectF& r = ldata->symsBBox;
429 0 : painter->rotate(-90.0);
430 0 : item->drawSymbols(ldata->symbols, painter, PointF(-r.right() - y1, -r.bottom() + r.height()));
431 0 : } break;
432 :
433 0 : case ArpeggioType::DOWN:
434 : {
435 0 : const RectF& r = ldata->symsBBox;
436 0 : painter->rotate(90.0);
437 0 : item->drawSymbols(ldata->symbols, painter, PointF(-r.left() + y1, -r.top() - r.height()));
438 0 : } break;
439 :
440 0 : case ArpeggioType::UP_STRAIGHT:
441 : {
442 0 : const RectF& r = ldata->symsBBox;
443 0 : double x1 = item->spatium() * 0.5;
444 0 : item->drawSymbol(SymId::arrowheadBlackUp, painter, PointF(x1 - r.width() * 0.5, y1 - r.top()));
445 0 : double ny1 = y1 - r.top() * 0.5;
446 0 : painter->drawLine(LineF(x1, ny1, x1, y2));
447 0 : } break;
448 :
449 0 : case ArpeggioType::DOWN_STRAIGHT:
450 : {
451 0 : const RectF& r = ldata->symsBBox;
452 0 : double x1 = item->spatium() * 0.5;
453 0 : item->drawSymbol(SymId::arrowheadBlackDown, painter, PointF(x1 - r.width() * 0.5, y2 - r.bottom()));
454 0 : double ny2 = y2 + r.top() * 0.5;
455 0 : painter->drawLine(LineF(x1, y1, x1, ny2));
456 0 : } break;
457 :
458 0 : case ArpeggioType::BRACKET:
459 : {
460 0 : double w = item->style().styleS(Sid::arpeggioHookLen).val() * item->spatium();
461 0 : painter->drawLine(LineF(0.0, y1, w, y1));
462 0 : painter->drawLine(LineF(0.0, y2, w, y2));
463 0 : painter->drawLine(LineF(0.0, y1 - lineWidth / 2, 0.0, y2 + lineWidth / 2));
464 0 : } break;
465 : }
466 0 : painter->restore();
467 : }
468 :
469 0 : void SingleDraw::draw(const ChordBracket* item, muse::draw::Painter* painter, const PaintOptions& opt)
470 : {
471 0 : const Arpeggio::LayoutData* ldata = item->ldata();
472 :
473 0 : const double lineWidth = item->style().styleAbsolute(Sid::chordBracketLineWidth);
474 0 : painter->setPen(Pen(item->curColor(opt), lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
475 :
476 0 : const double halfLineWidth = 0.5 * lineWidth;
477 0 : const double y1 = ldata->bbox().top() + halfLineWidth;
478 0 : const double y2 = ldata->bbox().bottom() - halfLineWidth;
479 :
480 0 : double w = item->absoluteFromSpatium(item->hookLength());
481 0 : if (item->hookPos() != DirectionV::DOWN) {
482 0 : painter->drawLine(LineF(0.0, y1, w, y1));
483 : }
484 0 : if (item->hookPos() != DirectionV::UP) {
485 0 : painter->drawLine(LineF(0.0, y2, w, y2));
486 : }
487 :
488 0 : const double x = halfLineWidth;
489 0 : painter->drawLine(LineF(x, y1, x, y2));
490 0 : }
491 :
492 0 : void SingleDraw::draw(const Articulation* item, Painter* painter, const PaintOptions& opt)
493 : {
494 : TRACE_DRAW_ITEM;
495 :
496 0 : painter->setPen(item->curColor(opt));
497 :
498 0 : if (item->textType() == ArticulationTextType::NO_TEXT) {
499 0 : item->drawSymbol(item->symId(), painter, PointF(-0.5 * item->width(), 0.0));
500 : } else {
501 0 : item->text()->setColor(item->curColor(opt));
502 0 : drawTextBase(item->text(), painter, opt);
503 : }
504 0 : }
505 :
506 0 : void SingleDraw::draw(const Note* item, Painter* painter, const PaintOptions& opt)
507 : {
508 : TRACE_DRAW_ITEM;
509 0 : if (item->hidden()) {
510 0 : return;
511 : }
512 :
513 0 : const Note::LayoutData* ldata = item->ldata();
514 0 : auto config = item->configuration();
515 :
516 0 : bool negativeFret = item->negativeFretUsed() && item->staff()->isTabStaff(item->tick());
517 :
518 0 : Color c(negativeFret && !opt.isPrinting ? config->criticalColor() : item->curColor(opt));
519 0 : painter->setPen(c);
520 0 : bool tablature = item->staff() && item->staff()->isTabStaff(item->chord()->tick());
521 :
522 : // tablature
523 0 : if (tablature) {
524 0 : if (item->displayFret() == Note::DisplayFretOption::Hide) {
525 0 : return;
526 : }
527 0 : const Staff* st = item->staff();
528 0 : const StaffType* tab = st->staffTypeForElement(item);
529 0 : if (item->tieBackNonPartial() && !tab->showBackTied()) {
530 0 : if (item->chord()->measure()->system() == item->tieBack()->startNote()->chord()->measure()->system() && item->el().empty()) {
531 : // fret should be hidden, so return without drawing it
532 0 : return;
533 : }
534 : }
535 : // draw background, if required (to hide a segment of string line or to show a fretting conflict)
536 0 : if (!tab->linesThrough() || item->fretConflict()) {
537 0 : double d = item->spatium() * .1;
538 0 : RectF bb = RectF(ldata->bbox().x() - d,
539 0 : tab->fretMaskY() * item->magS(),
540 0 : ldata->bbox().width() + 2 * d,
541 0 : tab->fretMaskH() * item->magS());
542 : // we do not know which viewer did this draw() call
543 : // so update all:
544 0 : if (!item->score()->getViewer().empty()) {
545 0 : for (MuseScoreView* view : item->score()->getViewer()) {
546 0 : view->drawBackground(painter, bb);
547 : }
548 : } else {
549 0 : painter->fillRect(bb, config->noteBackgroundColor());
550 : }
551 :
552 0 : if (item->fretConflict() && !opt.isPrinting && item->score()->showUnprintable()) { //on fret conflict, draw on red background
553 0 : painter->save();
554 0 : painter->setPen(config->criticalColor());
555 0 : painter->setBrush(config->criticalColor());
556 0 : painter->drawRect(bb);
557 0 : painter->restore();
558 : }
559 : }
560 0 : Font f(tab->fretFont());
561 0 : f.setPointSizeF(f.pointSizeF() * item->magS());
562 0 : painter->setFont(f);
563 0 : painter->setPen(c);
564 0 : double startPosX = ldata->bbox().x();
565 :
566 0 : painter->drawText(PointF(startPosX, tab->fretFontYOffset() * item->magS()), item->fretString());
567 0 : }
568 : // NOT tablature
569 : else {
570 : // skip drawing, if second note of a cross-measure value
571 0 : if (item->chord() && item->chord()->crossMeasure() == CrossMeasure::SECOND) {
572 0 : return;
573 : }
574 : // warn if pitch extends usable range of instrument
575 : // by coloring the notehead
576 0 : if (item->chord() && item->chord()->segment() && item->staff() && !opt.isPrinting
577 0 : && MScore::warnPitchRange && !item->staff()->isDrumStaff(item->chord()->tick())) {
578 0 : const Instrument* in = item->originPart()->instrument(item->chord()->tick());
579 0 : int i = item->ppitch();
580 0 : if (i < in->minPitchP() || i > in->maxPitchP()) {
581 0 : painter->setPen(
582 0 : item->selected() ? config->criticalSelectedColor() : config->criticalColor());
583 0 : } else if (i < in->minPitchA() || i > in->maxPitchA()) {
584 0 : painter->setPen(item->selected() ? config->warningSelectedColor() : config->warningColor());
585 : }
586 : }
587 : // Warn if notes are unplayable based on previous harp diagram setting
588 0 : if (item->chord() && item->chord()->segment() && item->staff() && !opt.isPrinting
589 0 : && !item->staff()->isDrumStaff(item->chord()->tick())) {
590 0 : HarpPedalDiagram* prevDiagram = item->originPart()->currentHarpDiagram(item->chord()->segment()->tick());
591 0 : if (prevDiagram && !prevDiagram->isTpcPlayable(item->tpc())) {
592 0 : painter->setPen(item->selected() ? config->criticalSelectedColor() : config->criticalColor());
593 : }
594 : }
595 : // draw blank notehead to avoid staff and ledger lines
596 0 : if (ldata->cachedSymNull() != SymId::noSym) {
597 0 : painter->save();
598 0 : painter->setPen(config->noteBackgroundColor());
599 0 : item->drawSymbol(ldata->cachedSymNull(), painter);
600 0 : painter->restore();
601 : }
602 0 : item->drawSymbol(ldata->cachedNoteheadSym.value(), painter);
603 : }
604 0 : }
605 :
606 0 : void SingleDraw::draw(const NoteHead* item, Painter* painter, const PaintOptions& opt)
607 : {
608 0 : draw(static_cast<const Symbol*>(item), painter, opt);
609 0 : }
610 :
611 0 : void SingleDraw::draw(const NoteLineSegment*, Painter*, const PaintOptions&)
612 : {
613 : // TRACE_DRAW_ITEM;
614 : // To be implemented
615 0 : }
616 :
617 0 : void SingleDraw::draw(const Ornament* item, Painter* painter, const PaintOptions& opt)
618 : {
619 0 : draw(static_cast<const Articulation*>(item), painter, opt);
620 0 : }
621 :
622 0 : void SingleDraw::draw(const BagpipeEmbellishment* item, Painter* painter, const PaintOptions& opt)
623 : {
624 : TRACE_DRAW_ITEM;
625 :
626 0 : const BagpipeEmbellishment::LayoutData* data = item->ldata();
627 0 : IF_ASSERT_FAILED(data) {
628 0 : return;
629 : }
630 0 : const BagpipeEmbellishment::LayoutData::BeamData& dataBeam = data->beamData;
631 :
632 0 : Pen pen(item->curColor(opt), data->stemLineW, PenStyle::SolidLine, PenCapStyle::FlatCap);
633 0 : painter->setPen(pen);
634 :
635 : // draw the notes including stem, (optional) flag and (optional) ledger line
636 0 : for (const auto& p : data->notesData) {
637 0 : const BagpipeEmbellishment::LayoutData::NoteData& noteData = p.second;
638 :
639 : // Draw Grace Note
640 : {
641 : // draw head
642 0 : item->drawSymbol(data->headsym, painter, noteData.headXY);
643 :
644 : // draw stem
645 0 : painter->drawLine(noteData.stemLine);
646 :
647 0 : if (data->isDrawFlag) {
648 : // draw flag
649 0 : item->drawSymbol(data->flagsym, painter, noteData.flagXY);
650 : }
651 : }
652 :
653 : // draw the ledger line for high A
654 0 : if (!noteData.ledgerLine.isNull()) {
655 0 : painter->drawLine(noteData.ledgerLine);
656 : }
657 : }
658 :
659 0 : if (data->isDrawBeam) {
660 0 : Pen beamPen(item->curColor(opt), dataBeam.width, PenStyle::SolidLine, PenCapStyle::FlatCap);
661 0 : painter->setPen(beamPen);
662 : // draw the beams
663 0 : auto drawBeams = [](Painter* painter, const double spatium,
664 : const double x1, const double x2, double y)
665 : {
666 : // draw the beams
667 0 : painter->drawLine(LineF(x1, y, x2, y));
668 0 : y += spatium / 1.5;
669 0 : painter->drawLine(LineF(x1, y, x2, y));
670 0 : y += spatium / 1.5;
671 0 : painter->drawLine(LineF(x1, y, x2, y));
672 0 : };
673 :
674 0 : drawBeams(painter, data->spatium, dataBeam.x1, dataBeam.x2, dataBeam.y);
675 0 : }
676 0 : }
677 :
678 0 : static void drawDots(const BarLine* item, Painter* painter, double x)
679 : {
680 0 : double spatium = item->spatium();
681 :
682 0 : double y1l = 1.5 * spatium;
683 0 : double y2l = 2.5 * spatium;
684 :
685 0 : item->drawSymbol(SymId::repeatDot, painter, PointF(x, y1l));
686 0 : item->drawSymbol(SymId::repeatDot, painter, PointF(x, y2l));
687 0 : }
688 :
689 0 : static void drawTips(const BarLine* item, Painter* painter, bool reversed, double x)
690 : {
691 0 : const BarLine::LayoutData* ldata = item->ldata();
692 0 : if (reversed) {
693 0 : if (item->isTop()) {
694 0 : item->drawSymbol(SymId::reversedBracketTop, painter, PointF(x - item->symWidth(SymId::reversedBracketTop), ldata->y1));
695 : }
696 0 : if (item->isBottom()) {
697 0 : item->drawSymbol(SymId::reversedBracketBottom, painter, PointF(x - item->symWidth(SymId::reversedBracketBottom), ldata->y2));
698 : }
699 : } else {
700 0 : if (item->isTop()) {
701 0 : item->drawSymbol(SymId::bracketTop, painter, PointF(x, ldata->y1));
702 : }
703 0 : if (item->isBottom()) {
704 0 : item->drawSymbol(SymId::bracketBottom, painter, PointF(x, ldata->y2));
705 : }
706 : }
707 0 : }
708 :
709 0 : void SingleDraw::draw(const BarLine* item, Painter* painter, const PaintOptions& opt)
710 : {
711 : TRACE_DRAW_ITEM;
712 0 : const BarLine::LayoutData* ldata = item->ldata();
713 0 : switch (item->barLineType()) {
714 0 : case BarLineType::NORMAL: {
715 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
716 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
717 0 : painter->drawLine(LineF(lw * .5, ldata->y1, lw * .5, ldata->y2));
718 : }
719 0 : break;
720 :
721 0 : case BarLineType::BROKEN: {
722 0 : double lw = item->style().styleAbsolute(Sid::dashBarWidth) * item->mag();
723 0 : double dl = RealIsNull(lw) ? 0.0 : item->style().styleAbsolute(Sid::dashBarDash) * item->mag() / lw;
724 0 : double gl = RealIsNull(lw) ? 0.0 : item->style().styleAbsolute(Sid::dashBarGap) * item->mag() / lw;
725 0 : Pen pen(item->curColor(opt), lw, PenStyle::DashLine, PenCapStyle::FlatCap);
726 0 : pen.setDashPattern({ dl, gl });
727 0 : painter->setPen(pen);
728 0 : painter->drawLine(LineF(lw * .5, ldata->y1, lw * .5, ldata->y2));
729 0 : }
730 0 : break;
731 :
732 0 : case BarLineType::DOTTED: {
733 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
734 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::DotLine, PenCapStyle::FlatCap));
735 0 : painter->drawLine(LineF(lw * .5, ldata->y1, lw * .5, ldata->y2));
736 : }
737 0 : break;
738 :
739 0 : case BarLineType::END: {
740 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
741 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
742 0 : double x = lw * .5;
743 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
744 :
745 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
746 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
747 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
748 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
749 : }
750 0 : break;
751 :
752 0 : case BarLineType::DOUBLE: {
753 0 : double lw = item->style().styleAbsolute(Sid::doubleBarWidth) * item->mag();
754 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
755 0 : double x = lw * .5;
756 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
757 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::doubleBarDistance) + (lw * .5)) * item->mag();
758 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
759 : }
760 0 : break;
761 :
762 0 : case BarLineType::REVERSE_END: {
763 0 : double lw = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
764 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
765 0 : double x = lw * .5;
766 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
767 :
768 0 : double lw2 = item->style().styleAbsolute(Sid::barWidth) * item->mag();
769 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
770 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
771 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
772 : }
773 0 : break;
774 :
775 0 : case BarLineType::HEAVY: {
776 0 : double lw = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
777 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
778 0 : painter->drawLine(LineF(lw * .5, ldata->y1, lw * .5, ldata->y2));
779 : }
780 0 : break;
781 :
782 0 : case BarLineType::DOUBLE_HEAVY: {
783 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
784 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
785 0 : double x = lw2 * .5;
786 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
787 0 : x += ((lw2 * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
788 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
789 : }
790 0 : break;
791 :
792 0 : case BarLineType::START_REPEAT: {
793 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
794 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
795 0 : double x = lw2 * .5;
796 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
797 :
798 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
799 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
800 0 : x += ((lw2 * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw * .5)) * item->mag();
801 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
802 :
803 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::repeatBarlineDotSeparation)) * item->mag();
804 0 : drawDots(item, painter, x);
805 :
806 0 : if (item->style().styleB(Sid::repeatBarTips)) {
807 0 : drawTips(item, painter, false, 0.0);
808 : }
809 : }
810 0 : break;
811 :
812 0 : case BarLineType::END_REPEAT: {
813 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
814 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
815 :
816 0 : double x = 0.0;
817 0 : drawDots(item, painter, x);
818 :
819 0 : x += item->symBbox(SymId::repeatDot).width();
820 0 : x += (item->style().styleAbsolute(Sid::repeatBarlineDotSeparation) + (lw * .5)) * item->mag();
821 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
822 :
823 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
824 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
825 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
826 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
827 :
828 0 : if (item->style().styleB(Sid::repeatBarTips)) {
829 0 : drawTips(item, painter, true, x + lw2 * .5);
830 : }
831 : }
832 0 : break;
833 0 : case BarLineType::END_START_REPEAT: {
834 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
835 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
836 :
837 0 : double x = 0.0;
838 0 : drawDots(item, painter, x);
839 :
840 0 : x += item->symBbox(SymId::repeatDot).width();
841 0 : x += (item->style().styleAbsolute(Sid::repeatBarlineDotSeparation) + (lw * .5)) * item->mag();
842 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
843 :
844 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
845 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
846 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
847 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
848 :
849 0 : if (item->style().styleB(Sid::repeatBarTips)) {
850 0 : drawTips(item, painter, true, x + lw2 * .5);
851 : }
852 :
853 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
854 0 : x += ((lw2 * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw * .5)) * item->mag();
855 0 : painter->drawLine(LineF(x, ldata->y1, x, ldata->y2));
856 :
857 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::repeatBarlineDotSeparation)) * item->mag();
858 0 : drawDots(item, painter, x);
859 :
860 0 : if (item->style().styleB(Sid::repeatBarTips)) {
861 0 : drawTips(item, painter, false, 0.0);
862 : }
863 : }
864 0 : break;
865 : }
866 0 : }
867 :
868 0 : void SingleDraw::draw(const Beam* item, Painter* painter, const PaintOptions& opt)
869 : {
870 : TRACE_DRAW_ITEM;
871 0 : if (item->beamSegments().empty()) {
872 0 : return;
873 : }
874 0 : painter->setBrush(Brush(item->curColor(opt)));
875 0 : painter->setNoPen();
876 :
877 : // make beam thickness independent of slant
878 : // (expression can be simplified?)
879 :
880 0 : const LineF bs = item->beamSegments().front()->line;
881 0 : double d = (std::abs(bs.y2() - bs.y1())) / (bs.x2() - bs.x1());
882 0 : if (item->beamSegments().size() > 1 && d > M_PI / 6.0) {
883 0 : d = M_PI / 6.0;
884 : }
885 0 : double ww = (item->beamWidth() / 2.0) / sin(M_PI_2 - atan(d));
886 :
887 0 : for (const BeamSegment* bs1 : item->beamSegments()) {
888 0 : painter->drawPolygon(
889 0 : PolygonF({
890 0 : PointF(bs1->line.x1(), bs1->line.y1() - ww),
891 0 : PointF(bs1->line.x2(), bs1->line.y2() - ww),
892 0 : PointF(bs1->line.x2(), bs1->line.y2() + ww),
893 0 : PointF(bs1->line.x1(), bs1->line.y1() + ww),
894 0 : }),
895 : FillRule::OddEvenFill);
896 : }
897 : }
898 :
899 0 : void SingleDraw::draw(const Bend* item, Painter* painter, const PaintOptions& opt)
900 : {
901 : TRACE_DRAW_ITEM;
902 :
903 0 : const Bend::LayoutData* ldata = item->ldata();
904 0 : double _spatium = item->spatium();
905 0 : double _lw = item->absoluteFromSpatium(item->lineWidth());
906 :
907 0 : Pen pen(item->curColor(opt), _lw, PenStyle::SolidLine, PenCapStyle::RoundCap, PenJoinStyle::RoundJoin);
908 0 : painter->setPen(pen);
909 0 : painter->setBrush(Brush(item->curColor(opt)));
910 :
911 0 : Font f = item->font(_spatium);
912 0 : painter->setFont(f);
913 :
914 0 : double x = ldata->noteWidth + _spatium * .2;
915 0 : double y = -_spatium * .8;
916 : double x2, y2;
917 :
918 0 : double aw = item->style().styleAbsolute(Sid::bendArrowWidth);
919 0 : PolygonF arrowUp;
920 0 : arrowUp << PointF(0, 0) << PointF(aw * .5, aw) << PointF(-aw * .5, aw);
921 0 : PolygonF arrowDown;
922 0 : arrowDown << PointF(0, 0) << PointF(aw * .5, -aw) << PointF(-aw * .5, -aw);
923 :
924 0 : size_t n = item->points().size();
925 0 : for (size_t pt = 0; pt < n - 1; ++pt) {
926 0 : int pitch = item->points()[pt].pitch;
927 0 : if (pt == 0 && pitch) {
928 0 : y2 = -ldata->notePos.y() - _spatium * 2;
929 0 : x2 = x;
930 0 : painter->drawLine(LineF(x, y, x2, y2));
931 :
932 0 : painter->setBrush(item->curColor(opt));
933 0 : painter->drawPolygon(arrowUp.translated(x2, y2));
934 :
935 0 : int idx = (pitch + 12) / 25;
936 0 : const char* l = item->label[idx];
937 0 : painter->drawText(RectF(x2, y2, .0, .0),
938 : muse::draw::AlignHCenter | muse::draw::AlignBottom,
939 : muse::draw::TextDontClip,
940 0 : String::fromAscii(l));
941 :
942 0 : y = y2;
943 : }
944 0 : if (pitch == item->points()[pt + 1].pitch) {
945 0 : if (pt == (n - 2)) {
946 0 : break;
947 : }
948 0 : x2 = x + _spatium;
949 0 : y2 = y;
950 0 : painter->drawLine(LineF(x, y, x2, y2));
951 0 : } else if (pitch < item->points()[pt + 1].pitch) {
952 : // up
953 0 : x2 = x + _spatium * .5;
954 0 : y2 = -ldata->notePos.y() - _spatium * 2;
955 0 : double dx = x2 - x;
956 0 : double dy = y2 - y;
957 :
958 0 : PainterPath path;
959 0 : path.moveTo(x, y);
960 0 : path.cubicTo(x + dx / 2, y, x2, y + dy / 4, x2, y2);
961 0 : painter->setBrush(BrushStyle::NoBrush);
962 0 : painter->drawPath(path);
963 :
964 0 : painter->setBrush(item->curColor(opt));
965 0 : painter->drawPolygon(arrowUp.translated(x2, y2));
966 :
967 0 : int idx = (item->points()[pt + 1].pitch + 12) / 25;
968 0 : const char* l = item->label[idx];
969 0 : double ty = y2; // - _spatium;
970 0 : painter->drawText(RectF(x2, ty, .0, .0),
971 : muse::draw::AlignHCenter | muse::draw::AlignBottom,
972 : muse::draw::TextDontClip,
973 0 : String::fromAscii(l));
974 0 : } else {
975 : // down
976 0 : x2 = x + _spatium * .5;
977 0 : y2 = y + _spatium * 3;
978 0 : double dx = x2 - x;
979 0 : double dy = y2 - y;
980 :
981 0 : PainterPath path;
982 0 : path.moveTo(x, y);
983 0 : path.cubicTo(x + dx / 2, y, x2, y + dy / 4, x2, y2);
984 0 : painter->setBrush(BrushStyle::NoBrush);
985 0 : painter->drawPath(path);
986 :
987 0 : painter->setBrush(item->curColor(opt));
988 0 : painter->drawPolygon(arrowDown.translated(x2, y2));
989 0 : }
990 0 : x = x2;
991 0 : y = y2;
992 : }
993 0 : }
994 :
995 0 : void SingleDraw::draw(const Bracket* item, Painter* painter, const PaintOptions& opt)
996 : {
997 : TRACE_DRAW_ITEM;
998 :
999 0 : const Bracket::LayoutData* ldata = item->ldata();
1000 :
1001 0 : painter->save();
1002 0 : setMask(item, painter);
1003 :
1004 0 : switch (item->bracketType()) {
1005 0 : case BracketType::BRACE: {
1006 0 : double h = ldata->bracketHeight;
1007 0 : double glyphHeight = item->symHeight(ldata->braceSymbol);
1008 0 : double mag = h / glyphHeight;
1009 0 : painter->setPen(item->curColor(opt));
1010 0 : painter->save();
1011 0 : painter->scale(item->magx(), mag);
1012 0 : item->drawSymbol(ldata->braceSymbol, painter, PointF(0, glyphHeight));
1013 0 : painter->restore();
1014 : }
1015 0 : break;
1016 0 : case BracketType::NORMAL: {
1017 0 : double h = ldata->bracketHeight;
1018 0 : double _spatium = item->spatium();
1019 0 : double w = item->style().styleAbsolute(Sid::bracketWidth);
1020 0 : double bd = (item->style().styleSt(Sid::musicalSymbolFont) == "Leland") ? _spatium * .5 : _spatium * .25;
1021 0 : Pen pen(item->curColor(opt), w, PenStyle::SolidLine, PenCapStyle::FlatCap);
1022 0 : painter->setPen(pen);
1023 0 : painter->drawLine(LineF(0.0, -bd - w * .5, 0.0, h + bd + w * .5));
1024 0 : double x = -w * .5;
1025 0 : double y1 = -bd;
1026 0 : double y2 = h + bd;
1027 0 : item->drawSymbol(SymId::bracketTop, painter, PointF(x, y1));
1028 0 : item->drawSymbol(SymId::bracketBottom, painter, PointF(x, y2));
1029 0 : }
1030 0 : break;
1031 0 : case BracketType::SQUARE:
1032 : {
1033 0 : double h = ldata->bracketHeight;
1034 0 : double lineW = item->style().styleAbsolute(Sid::staffLineWidth);
1035 0 : double bracketWidth = ldata->bracketWidth - lineW / 2;
1036 0 : Pen pen(item->curColor(opt), lineW, PenStyle::SolidLine, PenCapStyle::FlatCap);
1037 0 : painter->setPen(pen);
1038 0 : painter->drawLine(LineF(0.0, 0.0, 0.0, h));
1039 0 : painter->drawLine(LineF(-lineW / 2, 0.0, lineW / 2 + bracketWidth, 0.0));
1040 0 : painter->drawLine(LineF(-lineW / 2, h, lineW / 2 + bracketWidth, h));
1041 0 : }
1042 0 : break;
1043 0 : case BracketType::LINE: {
1044 0 : double h = ldata->bracketHeight;
1045 0 : double w = 0.67 * item->style().styleAbsolute(Sid::bracketWidth);
1046 0 : Pen pen(item->curColor(opt), w, PenStyle::SolidLine, PenCapStyle::FlatCap);
1047 0 : painter->setPen(pen);
1048 0 : double bd = item->style().styleAbsolute(Sid::staffLineWidth) * 0.5;
1049 0 : painter->drawLine(LineF(0.0, -bd, 0.0, h + bd));
1050 0 : }
1051 0 : break;
1052 0 : case BracketType::GROUP:
1053 : {
1054 0 : double h = ldata->bracketHeight;
1055 0 : double lineW = item->style().styleAbsolute(Sid::staffLineWidth);
1056 0 : double bracketWidth = ldata->bracketWidth;
1057 0 : Pen pen(item->curColor(opt), lineW, PenStyle::SolidLine, PenCapStyle::FlatCap);
1058 0 : painter->setPen(pen);
1059 0 : painter->drawLine(LineF(0.5 * lineW, 0.0, 0.5 * lineW, h));
1060 0 : painter->drawLine(LineF(0.0, 0.0, bracketWidth, 0.0));
1061 0 : painter->drawLine(LineF(0.0, h, bracketWidth, h));
1062 0 : }
1063 0 : break;
1064 0 : case BracketType::NO_BRACKET:
1065 0 : break;
1066 : }
1067 :
1068 0 : painter->restore();
1069 0 : }
1070 :
1071 0 : void SingleDraw::draw(const Breath* item, Painter* painter, const PaintOptions& opt)
1072 : {
1073 : TRACE_DRAW_ITEM;
1074 0 : painter->setPen(item->curColor(opt));
1075 0 : item->drawSymbol(item->symId(), painter);
1076 0 : }
1077 :
1078 0 : void SingleDraw::draw(const ChordLine* item, Painter* painter, const PaintOptions& opt)
1079 : {
1080 : TRACE_DRAW_ITEM;
1081 0 : const ChordLine::LayoutData* ldata = item->ldata();
1082 0 : IF_ASSERT_FAILED(ldata) {
1083 0 : return;
1084 : }
1085 :
1086 0 : if (!item->isWavy()) {
1087 0 : painter->setPen(Pen(item->curColor(opt), item->style().styleAbsolute(Sid::chordlineThickness) * item->mag(), PenStyle::SolidLine));
1088 0 : painter->setBrush(BrushStyle::NoBrush);
1089 0 : painter->drawPath(ldata->path);
1090 : } else {
1091 0 : painter->save();
1092 0 : painter->rotate((item->chordLineType() == ChordLineType::FALL ? 1 : -1));
1093 0 : item->drawSymbol(item->waveSym(), painter);
1094 0 : painter->restore();
1095 : }
1096 : }
1097 :
1098 0 : void SingleDraw::draw(const Clef* item, Painter* painter, const PaintOptions& opt)
1099 : {
1100 : TRACE_DRAW_ITEM;
1101 0 : const Clef::LayoutData* ldata = item->ldata();
1102 0 : IF_ASSERT_FAILED(ldata) {
1103 0 : return;
1104 : }
1105 :
1106 0 : if (ldata->symId == SymId::noSym) {
1107 0 : return;
1108 : }
1109 0 : painter->setPen(item->curColor(opt));
1110 0 : item->drawSymbol(ldata->symId, painter);
1111 : }
1112 :
1113 0 : void SingleDraw::draw(const Capo* item, Painter* painter, const PaintOptions& opt)
1114 : {
1115 0 : drawTextBase(item, painter, opt);
1116 0 : }
1117 :
1118 0 : void SingleDraw::draw(const DeadSlapped* item, Painter* painter, const PaintOptions& opt)
1119 : {
1120 : TRACE_DRAW_ITEM;
1121 0 : const DeadSlapped::LayoutData* ldata = item->ldata();
1122 0 : IF_ASSERT_FAILED(ldata) {
1123 0 : return;
1124 : }
1125 :
1126 0 : painter->setPen(PenStyle::NoPen);
1127 0 : painter->setBrush(item->curColor(opt));
1128 0 : painter->drawPath(ldata->path1);
1129 0 : painter->drawPath(ldata->path2);
1130 : }
1131 :
1132 0 : void SingleDraw::draw(const Dynamic* item, Painter* painter, const PaintOptions& opt)
1133 : {
1134 0 : drawTextBase(item, painter, opt);
1135 0 : }
1136 :
1137 0 : void SingleDraw::draw(const Expression* item, Painter* painter, const PaintOptions& opt)
1138 : {
1139 0 : drawTextBase(item, painter, opt);
1140 0 : }
1141 :
1142 0 : void SingleDraw::draw(const Fermata* item, Painter* painter, const PaintOptions& opt)
1143 : {
1144 : TRACE_DRAW_ITEM;
1145 0 : painter->setPen(item->curColor(opt));
1146 0 : item->drawSymbol(item->symId(), painter, PointF(-0.5 * item->width(), 0.0));
1147 0 : }
1148 :
1149 0 : void SingleDraw::draw(const FiguredBass* item, Painter* painter, const PaintOptions& opt)
1150 : {
1151 : TRACE_DRAW_ITEM;
1152 0 : if (item->items().size() < 1) { // if not parseable into f.b. items
1153 0 : drawTextBase(item, painter, opt); // draw as standard text
1154 : } else {
1155 0 : for (FiguredBassItem* fi : item->items()) { // if parseable into f.b. items
1156 0 : painter->translate(fi->pos()); // draw each item in its proper position
1157 0 : draw(fi, painter, opt);
1158 0 : painter->translate(-fi->pos());
1159 : }
1160 : }
1161 0 : }
1162 :
1163 0 : void SingleDraw::draw(const FiguredBassItem* item, Painter* painter, const PaintOptions& opt)
1164 : {
1165 : TRACE_DRAW_ITEM;
1166 :
1167 0 : const FiguredBassItem::LayoutData* ldata = item->ldata();
1168 0 : int font = 0;
1169 0 : double _spatium = item->spatium();
1170 : // set font from general style
1171 0 : Font f(FiguredBass::FBFonts().at(font).family, Font::Type::Tablature);
1172 :
1173 : // (use the same font selection as used in layout() above)
1174 0 : double m = item->style().styleD(Sid::figuredBassFontSize) * item->spatium() / item->defaultSpatium();
1175 0 : f.setPointSizeF(m);
1176 :
1177 0 : painter->setFont(f);
1178 0 : painter->setBrush(BrushStyle::NoBrush);
1179 0 : Pen pen(item->figuredBass()->curColor(opt), FiguredBass::FB_CONTLINE_THICKNESS.toAbsolute(_spatium), PenStyle::SolidLine,
1180 0 : PenCapStyle::RoundCap);
1181 0 : painter->setPen(pen);
1182 0 : painter->drawText(ldata->bbox(),
1183 : muse::draw::AlignLeft | muse::draw::AlignTop,
1184 : muse::draw::TextDontClip,
1185 0 : ldata->displayText);
1186 :
1187 : // continuation line
1188 0 : double lineEndX = 0.0;
1189 0 : if (item->contLine() != FiguredBassItem::ContLine::NONE) {
1190 0 : double lineStartX = ldata->textWidth; // by default, line starts right after text
1191 0 : if (lineStartX > 0.0) {
1192 0 : lineStartX += FiguredBass::FB_CONTLINE_LEFT_PADDING.toAbsolute(_spatium); // if some text, give some room after it
1193 : }
1194 0 : lineEndX = item->figuredBass()->ldata()->printedLineLength; // by default, line ends with item duration
1195 0 : if (lineEndX - lineStartX < 1.0) { // if line length < 1 sp, ignore it
1196 0 : lineEndX = 0.0;
1197 : }
1198 :
1199 : // if extended cont.line and no closing parenthesis: look at next FB element
1200 0 : if (item->contLine() > FiguredBassItem::ContLine::SIMPLE && item->parenth5() == FiguredBassItem::Parenthesis::NONE) {
1201 : FiguredBass* nextFB;
1202 : // if there is a contiguous FB element
1203 0 : if ((nextFB = item->figuredBass()->nextFiguredBass()) != 0) {
1204 : // retrieve the X position (in page coords) of a possible cont. line of nextFB
1205 : // on the same line of 'this'
1206 0 : PointF pgPos = item->pagePos();
1207 0 : double nextContPageX = nextFB->additionalContLineX(pgPos.y());
1208 : // if an additional cont. line has been found, extend up to its initial X coord
1209 0 : if (nextContPageX > 0) {
1210 0 : lineEndX = nextContPageX - pgPos.x() + FiguredBass::FB_CONTLINE_OVERLAP.toAbsolute(_spatium);
1211 : }
1212 : // with a little bit of overlap
1213 : else {
1214 0 : lineEndX = item->figuredBass()->ldata()->lineLength(0); // if none found, draw to the duration end
1215 : }
1216 : }
1217 : }
1218 : // if some line, draw it
1219 0 : if (lineEndX > 0.0) {
1220 0 : double h = ldata->bbox().height() * FiguredBass::FB_CONTLINE_HEIGHT;
1221 0 : painter->drawLine(lineStartX, h, lineEndX - ldata->pos().x(), h);
1222 : }
1223 : }
1224 :
1225 : // closing cont.line parenthesis
1226 0 : if (item->parenth5() != FiguredBassItem::Parenthesis::NONE) {
1227 0 : int x = lineEndX > 0.0 ? lineEndX : ldata->textWidth;
1228 0 : painter->drawText(RectF(x, 0, ldata->bbox().width(), ldata->bbox().height()),
1229 : muse::draw::AlignLeft | muse::draw::AlignTop,
1230 : muse::draw::TextDontClip,
1231 0 : Char(FiguredBass::FBFonts().at(font).displayParenthesis[int(item->parenth5())].unicode()));
1232 : }
1233 0 : }
1234 :
1235 0 : void SingleDraw::draw(const Fingering* item, Painter* painter, const PaintOptions& opt)
1236 : {
1237 : TRACE_DRAW_ITEM;
1238 0 : drawTextBase(item, painter, opt);
1239 0 : }
1240 :
1241 0 : void SingleDraw::draw(const FretDiagram* item, Painter* painter, const PaintOptions& opt)
1242 : {
1243 : TRACE_DRAW_ITEM;
1244 0 : const FretDiagram::LayoutData* ldata = item->ldata();
1245 0 : PointF translation = -PointF(ldata->stringDist * (item->strings() - 1), 0);
1246 0 : if (item->orientation() == Orientation::HORIZONTAL) {
1247 0 : painter->save();
1248 0 : painter->rotate(-90);
1249 0 : painter->translate(translation);
1250 : }
1251 :
1252 : // Init pen and other values
1253 0 : Pen pen(item->curColor(opt));
1254 0 : pen.setCapStyle(PenCapStyle::FlatCap);
1255 0 : painter->setBrush(Brush(Color(painter->pen().color())));
1256 :
1257 : // x2 is the x val of the rightmost string
1258 0 : double x2 = (item->strings() - 1) * ldata->stringDist;
1259 :
1260 : // Draw the nut
1261 0 : pen.setWidthF(ldata->nutLineWidth);
1262 0 : painter->setPen(pen);
1263 0 : painter->drawLine(LineF(-ldata->stringLineWidth * .5, 0.0, x2 + ldata->stringLineWidth * .5, 0.0));
1264 :
1265 : // Draw strings and frets
1266 0 : pen.setWidthF(ldata->stringLineWidth);
1267 0 : painter->setPen(pen);
1268 :
1269 : // y2 is the y val of the bottom fretline
1270 0 : double y2 = ldata->fretDist * item->frets();
1271 0 : for (int i = 0; i < item->strings(); ++i) {
1272 0 : double x = ldata->stringDist * i;
1273 0 : painter->drawLine(LineF(x, 0.0, x, y2));
1274 : }
1275 0 : for (int i = 1; i <= item->frets(); ++i) {
1276 0 : double y = ldata->fretDist * i;
1277 0 : painter->drawLine(LineF(0.0, y, x2, y));
1278 : }
1279 :
1280 : // dotd is the diameter of a dot
1281 0 : double dotd = item->style().styleAbsolute(Sid::fretDotSpatiumSize);
1282 :
1283 : // Draw dots, sym pen is used to draw them (and markers)
1284 0 : Pen symPen(pen);
1285 0 : symPen.setCapStyle(PenCapStyle::RoundCap);
1286 0 : double symPenWidth = ldata->stringLineWidth * 1.2;
1287 0 : symPen.setWidthF(symPenWidth);
1288 :
1289 0 : for (auto const& i : item->dots()) {
1290 0 : for (auto const& d : i.second) {
1291 0 : if (!d.exists()) {
1292 0 : continue;
1293 : }
1294 :
1295 0 : int string = i.first;
1296 0 : int fret = d.fret - 1;
1297 :
1298 : // Calculate coords of the top left corner of the dot
1299 0 : double x = ldata->stringDist * string - dotd * .5;
1300 0 : double y = ldata->fretDist * fret + ldata->fretDist * .5 - dotd * .5;
1301 :
1302 : // Draw different symbols
1303 0 : painter->setPen(symPen);
1304 0 : switch (d.dtype) {
1305 0 : case FretDotType::CROSS:
1306 : // Give the cross a slightly larger width
1307 0 : symPen.setWidthF(symPenWidth * 1.5);
1308 0 : painter->setPen(symPen);
1309 0 : painter->drawLine(LineF(x, y, x + dotd, y + dotd));
1310 0 : painter->drawLine(LineF(x + dotd, y, x, y + dotd));
1311 0 : symPen.setWidthF(symPenWidth);
1312 0 : break;
1313 0 : case FretDotType::SQUARE:
1314 0 : painter->setBrush(BrushStyle::NoBrush);
1315 0 : painter->drawRect(RectF(x, y, dotd, dotd));
1316 0 : break;
1317 0 : case FretDotType::TRIANGLE:
1318 0 : painter->drawLine(LineF(x, y + dotd, x + .5 * dotd, y));
1319 0 : painter->drawLine(LineF(x + .5 * dotd, y, x + dotd, y + dotd));
1320 0 : painter->drawLine(LineF(x + dotd, y + dotd, x, y + dotd));
1321 0 : break;
1322 0 : case FretDotType::NORMAL:
1323 : default:
1324 0 : painter->setBrush(symPen.color());
1325 0 : painter->setNoPen();
1326 0 : painter->drawEllipse(RectF(x, y, dotd, dotd));
1327 0 : break;
1328 : }
1329 : }
1330 : }
1331 :
1332 : // Draw markers
1333 0 : symPen.setWidthF(symPenWidth * 1.2);
1334 0 : painter->setBrush(BrushStyle::NoBrush);
1335 0 : painter->setPen(symPen);
1336 0 : for (auto const& i : item->markers()) {
1337 0 : int string = i.first;
1338 0 : FretItem::Marker marker = i.second;
1339 0 : if (!marker.exists()) {
1340 0 : continue;
1341 : }
1342 :
1343 0 : double x = ldata->stringDist * string - ldata->markerSize * .5;
1344 0 : double y = -ldata->fretDist - ldata->markerSize * .5;
1345 0 : if (marker.mtype == FretMarkerType::CIRCLE) {
1346 0 : painter->drawEllipse(RectF(x, y, ldata->markerSize, ldata->markerSize));
1347 0 : } else if (marker.mtype == FretMarkerType::CROSS) {
1348 0 : painter->drawLine(PointF(x, y), PointF(x + ldata->markerSize, y + ldata->markerSize));
1349 0 : painter->drawLine(PointF(x, y + ldata->markerSize), PointF(x + ldata->markerSize, y));
1350 : }
1351 : }
1352 :
1353 : // Draw barres
1354 0 : for (auto const& i : item->barres()) {
1355 0 : int fret = i.first;
1356 0 : int startString = i.second.startString;
1357 0 : int endString = i.second.endString;
1358 :
1359 0 : double x1 = ldata->stringDist * startString;
1360 0 : double newX2 = endString == -1 ? x2 : ldata->stringDist * endString;
1361 0 : double y = ldata->fretDist * (fret - 1) + ldata->fretDist * .5;
1362 0 : pen.setWidthF(dotd * item->style().styleD(Sid::barreLineWidth));
1363 0 : pen.setCapStyle(PenCapStyle::RoundCap);
1364 0 : painter->setPen(pen);
1365 0 : painter->drawLine(LineF(x1, y, newX2, y));
1366 : }
1367 :
1368 : // Draw fret offset number
1369 0 : if (item->fretOffset() > 0) {
1370 0 : Font scaledFont(item->fretNumFont());
1371 0 : scaledFont.setPointSizeF(scaledFont.pointSizeF() * (item->spatium() / item->defaultSpatium()));
1372 0 : painter->setFont(scaledFont);
1373 0 : String text = String::number(item->fretOffset() + 1);
1374 :
1375 0 : if (item->orientation() == Orientation::VERTICAL) {
1376 0 : if (item->numPos() == 0) {
1377 0 : painter->drawText(RectF(-ldata->stringDist * .4, .0, .0, ldata->fretDist),
1378 : muse::draw::AlignVCenter | muse::draw::AlignRight,
1379 : muse::draw::TextDontClip,
1380 : text);
1381 : } else {
1382 0 : painter->drawText(RectF(x2 + (ldata->stringDist * .4), .0, .0, ldata->fretDist),
1383 : muse::draw::AlignVCenter | muse::draw::AlignLeft,
1384 : muse::draw::TextDontClip,
1385 0 : String::number(item->fretOffset() + 1));
1386 : }
1387 0 : } else if (item->orientation() == Orientation::HORIZONTAL) {
1388 0 : painter->save();
1389 0 : painter->translate(-translation);
1390 0 : painter->rotate(90);
1391 0 : if (item->numPos() == 0) {
1392 0 : painter->drawText(RectF(.0, ldata->stringDist * (item->strings() - 1), .0, .0),
1393 : muse::draw::AlignLeft,
1394 : muse::draw::TextDontClip,
1395 : text);
1396 : } else {
1397 0 : painter->drawText(RectF(.0, .0, .0, .0),
1398 : muse::draw::AlignBottom | muse::draw::AlignLeft,
1399 : muse::draw::TextDontClip,
1400 : text);
1401 : }
1402 0 : painter->restore();
1403 : }
1404 0 : painter->setFont(item->fretNumFont());
1405 0 : }
1406 :
1407 : // NOTE:JT possible future todo - draw fingerings
1408 :
1409 0 : if (item->orientation() == Orientation::HORIZONTAL) {
1410 0 : painter->restore();
1411 : }
1412 0 : }
1413 :
1414 0 : void SingleDraw::draw(const GlissandoSegment* item, Painter* painter, const PaintOptions& opt)
1415 : {
1416 : TRACE_DRAW_ITEM;
1417 :
1418 0 : if (item->pos2().x() <= 0) {
1419 0 : return;
1420 : }
1421 :
1422 0 : painter->save();
1423 0 : double _spatium = item->spatium();
1424 0 : const Glissando* glissando = item->glissando();
1425 :
1426 0 : Pen pen(item->curColor(item->visible(), glissando->lineColor(), opt));
1427 0 : pen.setWidthF(item->absoluteFromSpatium(item->lineWidth()));
1428 0 : pen.setCapStyle(PenCapStyle::FlatCap);
1429 0 : painter->setPen(pen);
1430 :
1431 : // rotate painter so that the line become horizontal
1432 0 : double w = item->pos2().x();
1433 0 : double h = item->pos2().y();
1434 0 : double l = sqrt(w * w + h * h);
1435 0 : double wi = asin(-h / l) * 180.0 / M_PI;
1436 0 : painter->rotate(-wi);
1437 :
1438 0 : if (glissando->glissandoType() == GlissandoType::STRAIGHT) {
1439 0 : painter->drawLine(LineF(0.0, 0.0, l, 0.0));
1440 0 : } else if (glissando->glissandoType() == GlissandoType::WAVY) {
1441 0 : RectF b = item->symBbox(SymId::wiggleTrill);
1442 0 : double a = item->symAdvance(SymId::wiggleTrill);
1443 0 : int n = static_cast<int>(l / a); // always round down (truncate) to avoid overlap
1444 0 : double x = (l - n * a) * 0.5; // centre line in available space
1445 0 : SymIdList ids;
1446 0 : for (int i = 0; i < n; ++i) {
1447 0 : ids.push_back(SymId::wiggleTrill);
1448 : }
1449 :
1450 0 : item->drawSymbols(ids, painter, PointF(x, -(b.y() + b.height() * 0.5)));
1451 0 : }
1452 :
1453 0 : if (glissando->showText()) {
1454 0 : Font f(glissando->fontFace(), Font::Type::Unknown);
1455 0 : f.setPointSizeF(glissando->fontSize() * _spatium / item->defaultSpatium());
1456 0 : f.setBold(glissando->fontStyle() & FontStyle::Bold);
1457 0 : f.setItalic(glissando->fontStyle() & FontStyle::Italic);
1458 0 : f.setUnderline(glissando->fontStyle() & FontStyle::Underline);
1459 0 : f.setStrike(glissando->fontStyle() & FontStyle::Strike);
1460 0 : FontMetrics fm(f);
1461 0 : RectF r = fm.boundingRect(glissando->text());
1462 :
1463 : // if text longer than available space, skip it
1464 0 : if (r.width() < l) {
1465 0 : double yOffset = r.height() + r.y(); // find text descender height
1466 : // raise text slightly above line and slightly more with WAVY than with STRAIGHT
1467 0 : yOffset += _spatium * (glissando->glissandoType() == GlissandoType::WAVY ? 0.4 : 0.1);
1468 :
1469 0 : painter->setFont(f);
1470 :
1471 0 : double x = (l - r.width()) * 0.5;
1472 0 : painter->drawText(PointF(x, -yOffset), glissando->text());
1473 : }
1474 0 : }
1475 0 : painter->restore();
1476 0 : }
1477 :
1478 0 : void SingleDraw::draw(const Stem* item, Painter* painter, const PaintOptions& opt)
1479 : {
1480 : TRACE_DRAW_ITEM;
1481 0 : if (!item->chord()) { // may be need assert?
1482 0 : return;
1483 : }
1484 :
1485 : // hide if second chord of a cross-measure pair
1486 0 : if (item->chord()->crossMeasure() == CrossMeasure::SECOND) {
1487 0 : return;
1488 : }
1489 :
1490 0 : const Stem::LayoutData* ldata = item->ldata();
1491 0 : const Staff* staff = item->staff();
1492 0 : const StaffType* staffType = staff ? staff->staffTypeForElement(item->chord()) : nullptr;
1493 0 : const bool isTablature = staffType && staffType->isTabStaff();
1494 :
1495 0 : painter->setPen(Pen(item->curColor(opt), item->lineWidthMag(), PenStyle::SolidLine, PenCapStyle::FlatCap));
1496 0 : painter->drawLine(ldata->line);
1497 :
1498 0 : if (!isTablature) {
1499 0 : return;
1500 : }
1501 :
1502 : // TODO: adjust bounding rectangle in layout() for dots and for slash
1503 0 : double sp = item->spatium();
1504 0 : bool isUp = item->up();
1505 :
1506 : // slashed half note stem
1507 0 : if (item->chord()->durationType().type() == DurationType::V_HALF
1508 0 : && staffType->minimStyle() == TablatureMinimStyle::SLASHED) {
1509 : // position slashes onto stem
1510 0 : double y = isUp ? -item->length() + score::StemLayout::STAFFTYPE_TAB_SLASH_2STARTY_UP * sp
1511 0 : : item->length() - score::StemLayout::STAFFTYPE_TAB_SLASH_2STARTY_DN * sp;
1512 : // if stems through, try to align slashes within or across lines
1513 0 : if (staffType->stemThrough()) {
1514 0 : double halfLineDist = staffType->lineDistance().val() * sp * 0.5;
1515 0 : double halfSlashHgt = score::StemLayout::STAFFTYPE_TAB_SLASH_2TOTHEIGHT * sp * 0.5;
1516 0 : y = lrint((y + halfSlashHgt) / halfLineDist) * halfLineDist - halfSlashHgt;
1517 : }
1518 : // draw slashes
1519 0 : double hlfWdt= sp * score::StemLayout::STAFFTYPE_TAB_SLASH_WIDTH * 0.5;
1520 0 : double sln = sp * score::StemLayout::STAFFTYPE_TAB_SLASH_SLANTY;
1521 0 : double thk = sp * score::StemLayout::STAFFTYPE_TAB_SLASH_THICK;
1522 0 : double displ = sp * score::StemLayout::STAFFTYPE_TAB_SLASH_DISPL;
1523 0 : PainterPath path;
1524 0 : for (int i = 0; i < 2; ++i) {
1525 0 : path.moveTo(hlfWdt, y); // top-right corner
1526 0 : path.lineTo(hlfWdt, y + thk); // bottom-right corner
1527 0 : path.lineTo(-hlfWdt, y + thk + sln); // bottom-left corner
1528 0 : path.lineTo(-hlfWdt, y + sln); // top-left corner
1529 0 : path.closeSubpath();
1530 0 : y += displ;
1531 : }
1532 0 : painter->setBrush(Brush(item->curColor(opt)));
1533 0 : painter->setNoPen();
1534 0 : painter->drawPath(path);
1535 0 : }
1536 :
1537 : // dots
1538 : // NOT THE BEST PLACE FOR THIS?
1539 : // with tablatures and stems beside staves, dots are not drawn near 'notes', but near stems
1540 0 : int nDots = item->chord()->dots();
1541 0 : if (nDots > 0 && !staffType->stemThrough()) {
1542 0 : double x = item->chord()->dotPosX();
1543 0 : double y = ((score::StemLayout::STAFFTYPE_TAB_DEFAULTSTEMLEN_DN * 0.2) * sp) * (isUp ? -1.0 : 1.0);
1544 0 : double step = item->style().styleS(Sid::dotDotDistance).val() * sp;
1545 0 : for (int dot = 0; dot < nDots; dot++, x += step) {
1546 0 : item->drawSymbol(SymId::augmentationDot, painter, PointF(x, y));
1547 : }
1548 : }
1549 : }
1550 :
1551 0 : void SingleDraw::draw(const StemSlash* item, Painter* painter, const PaintOptions& opt)
1552 : {
1553 : TRACE_DRAW_ITEM;
1554 :
1555 0 : const StemSlash::LayoutData* ldata = item->ldata();
1556 0 : painter->setPen(Pen(item->curColor(opt), ldata->stemWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
1557 0 : painter->drawLine(ldata->line);
1558 0 : }
1559 :
1560 0 : void SingleDraw::draw(const Sticking* item, Painter* painter, const PaintOptions& opt)
1561 : {
1562 : TRACE_DRAW_ITEM;
1563 0 : drawTextBase(item, painter, opt);
1564 0 : }
1565 :
1566 0 : void SingleDraw::draw(const StringTunings* item, Painter* painter, const PaintOptions& opt)
1567 : {
1568 : TRACE_DRAW_ITEM;
1569 0 : drawTextBase(item, painter, opt);
1570 0 : }
1571 :
1572 0 : void SingleDraw::drawTextBase(const TextBase* item, Painter* painter, const PaintOptions& opt)
1573 : {
1574 : TRACE_DRAW_ITEM;
1575 :
1576 0 : painter->save();
1577 0 : painter->rotate(item->textAngle());
1578 :
1579 0 : const TextBase::LayoutData* ldata = item->ldata();
1580 :
1581 0 : if (item->hasFrame()) {
1582 0 : double baseSpatium = DefaultStyle::baseStyle().value(Sid::spatium).toReal();
1583 0 : if (!RealIsNull(item->frameWidth().val())) {
1584 0 : Color fColor = item->curColor(item->visible(), item->frameColor(), opt);
1585 0 : double frameWidthVal = item->frameWidth().val() * (item->sizeIsSpatiumDependent() ? item->spatium() : baseSpatium);
1586 :
1587 0 : Pen pen(fColor, frameWidthVal, PenStyle::SolidLine, PenCapStyle::SquareCap, PenJoinStyle::MiterJoin);
1588 0 : painter->setPen(pen);
1589 0 : } else {
1590 0 : painter->setNoPen();
1591 : }
1592 0 : Color bg(item->bgColor());
1593 0 : painter->setBrush(bg.alpha() ? Brush(bg) : BrushStyle::NoBrush);
1594 0 : if (item->circle()) {
1595 0 : painter->drawEllipse(ldata->frame);
1596 : } else {
1597 0 : double frameRadius = item->frameRound().val() * (item->sizeIsSpatiumDependent() ? item->spatium() : baseSpatium);
1598 0 : painter->drawRoundedRect(ldata->frame, frameRadius, frameRadius);
1599 : }
1600 : }
1601 0 : painter->setBrush(BrushStyle::NoBrush);
1602 0 : painter->setPen(item->textColor(opt));
1603 0 : for (const TextBlock& t : ldata->blocks) {
1604 0 : draw(t, item, painter);
1605 : }
1606 :
1607 0 : painter->restore();
1608 0 : }
1609 :
1610 0 : void SingleDraw::draw(const TextBlock& textBlock, const TextBase* item, muse::draw::Painter* painter)
1611 : {
1612 0 : painter->translate(0.0, textBlock.y());
1613 0 : for (const TextFragment& f : textBlock.fragments()) {
1614 0 : draw(f, item, painter);
1615 : }
1616 0 : painter->translate(0.0, -textBlock.y());
1617 0 : }
1618 :
1619 0 : void SingleDraw::draw(const TextFragment& textFragment, const TextBase* item, muse::draw::Painter* painter)
1620 : {
1621 0 : painter->setFont(textFragment.font(item));
1622 0 : painter->drawText(textFragment.pos, textFragment.text);
1623 0 : }
1624 :
1625 0 : static void setDashAndGapLen(const SLine* line, double& dash, double& gap, Pen& pen)
1626 : {
1627 : static constexpr double DOTTED_DASH_LEN = 0.01;
1628 : static constexpr double DOTTED_GAP_LEN = 1.99;
1629 0 : switch (line->lineStyle()) {
1630 0 : case LineType::SOLID:
1631 0 : break;
1632 0 : case LineType::DASHED:
1633 0 : dash = line->dashLineLen(), gap = line->dashGapLen();
1634 0 : break;
1635 0 : case LineType::DOTTED:
1636 0 : dash = DOTTED_DASH_LEN, gap = DOTTED_GAP_LEN;
1637 0 : pen.setCapStyle(PenCapStyle::RoundCap); // round dots
1638 0 : break;
1639 : }
1640 0 : }
1641 :
1642 0 : static std::vector<double> distributedDashPattern(double dash, double gap, double lineLength)
1643 : {
1644 0 : int numPairs = std::max(1.0, lineLength / (dash + gap));
1645 0 : double newGap = (lineLength - dash * (numPairs + 1)) / numPairs;
1646 :
1647 0 : return { dash, newGap };
1648 : }
1649 :
1650 0 : void SingleDraw::drawTextLineBaseSegment(const TextLineBaseSegment* item, Painter* painter, const PaintOptions& opt)
1651 : {
1652 0 : const TextLineBase* tl = item->textLineBase();
1653 0 : const TextLineBaseSegment::LayoutData* ldata = item->ldata();
1654 :
1655 0 : if (!item->text()->empty()) {
1656 0 : painter->translate(item->text()->pos());
1657 0 : item->text()->setVisible(tl->visible());
1658 0 : draw(item->text(), painter, opt);
1659 0 : painter->translate(-item->text()->pos());
1660 : }
1661 :
1662 0 : if (!item->endText()->empty()) {
1663 0 : painter->translate(item->endText()->pos());
1664 0 : item->endText()->setVisible(tl->visible());
1665 0 : draw(item->endText(), painter, opt);
1666 0 : painter->translate(-item->endText()->pos());
1667 : }
1668 :
1669 0 : if (ldata->npoints == 0) {
1670 0 : return;
1671 : }
1672 :
1673 : // color for line (text color comes from the text properties)
1674 0 : Color color = item->curColor(tl->visible() && tl->lineVisible(), tl->lineColor(), opt);
1675 :
1676 0 : double lineWidth = tl->absoluteFromSpatium(tl->lineWidth());
1677 :
1678 0 : const Pen solidPen(color, lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap, PenJoinStyle::MiterJoin);
1679 0 : Pen pen(solidPen);
1680 :
1681 0 : double dash = 0;
1682 0 : double gap = 0;
1683 :
1684 0 : setDashAndGapLen(tl, dash, gap, pen);
1685 :
1686 0 : const bool isNonSolid = tl->lineStyle() != LineType::SOLID;
1687 :
1688 : // Draw lines
1689 0 : if (item->twoLines()) { // hairpins
1690 0 : if (isNonSolid) {
1691 0 : pen.setDashPattern({ dash, gap });
1692 : }
1693 :
1694 0 : pen.setJoinStyle(PenJoinStyle::BevelJoin);
1695 0 : painter->setPen(pen);
1696 0 : if (!ldata->joinedHairpin.empty() && !isNonSolid) {
1697 0 : painter->drawPolyline(ldata->joinedHairpin);
1698 : } else {
1699 0 : painter->drawLines(&ldata->points[0], 2);
1700 : }
1701 0 : return;
1702 : }
1703 :
1704 0 : int start = 0, end = ldata->npoints;
1705 :
1706 : // Draw begin hook, if it needs to be drawn separately
1707 0 : if (item->isSingleBeginType() && tl->beginHookType() != HookType::NONE) {
1708 0 : if (tl->beginHookType() == HookType::ARROW_FILLED) {
1709 0 : Brush brush;
1710 0 : brush.setStyle(BrushStyle::SolidPattern);
1711 0 : brush.setColor(item->curColor(opt));
1712 0 : painter->setBrush(brush);
1713 0 : painter->setNoPen();
1714 0 : painter->drawPolygon(ldata->beginArrow);
1715 0 : } else if (tl->beginHookType() == HookType::ARROW) {
1716 0 : pen.setJoinStyle(PenJoinStyle::MiterJoin);
1717 0 : painter->setPen(pen);
1718 0 : painter->drawPolyline(ldata->beginArrow);
1719 : } else {
1720 0 : bool isTHook = tl->beginHookType() == HookType::HOOK_90T;
1721 :
1722 0 : if (isNonSolid || isTHook) {
1723 0 : const PointF& p1 = ldata->points[start++];
1724 0 : const PointF& p2 = ldata->points[start++];
1725 :
1726 0 : if (isTHook) {
1727 0 : painter->setPen(solidPen);
1728 : } else {
1729 0 : double hookLength = sqrt(PointF::dotProduct(p2 - p1, p2 - p1));
1730 0 : pen.setDashPattern(distributedDashPattern(dash, gap, hookLength / lineWidth));
1731 0 : painter->setPen(pen);
1732 : }
1733 :
1734 0 : painter->drawLine(p1, p2);
1735 : }
1736 : }
1737 : }
1738 :
1739 : // Draw end hook, if it needs to be drawn separately
1740 0 : if (item->isSingleEndType() && tl->endHookType() != HookType::NONE) {
1741 0 : if (tl->endHookType() == HookType::ARROW_FILLED) {
1742 0 : Brush brush;
1743 0 : brush.setStyle(BrushStyle::SolidPattern);
1744 0 : brush.setColor(item->curColor(opt));
1745 0 : painter->setBrush(brush);
1746 0 : painter->setNoPen();
1747 0 : painter->drawPolygon(ldata->endArrow);
1748 0 : } else if (tl->endHookType() == HookType::ARROW) {
1749 0 : pen.setJoinStyle(PenJoinStyle::MiterJoin);
1750 0 : painter->setPen(pen);
1751 0 : painter->drawPolyline(ldata->endArrow);
1752 : } else {
1753 0 : bool isTHook = tl->endHookType() == HookType::HOOK_90T;
1754 :
1755 0 : if (isNonSolid || isTHook) {
1756 0 : const PointF& p1 = ldata->points[--end];
1757 0 : const PointF& p2 = ldata->points[--end];
1758 :
1759 0 : if (isTHook) {
1760 0 : painter->setPen(solidPen);
1761 : } else {
1762 0 : double hookLength = sqrt(PointF::dotProduct(p2 - p1, p2 - p1));
1763 0 : pen.setDashPattern(distributedDashPattern(dash, gap, hookLength / lineWidth));
1764 0 : painter->setPen(pen);
1765 : }
1766 :
1767 0 : painter->drawLine(p1, p2);
1768 : }
1769 : }
1770 : }
1771 :
1772 : // Draw the rest
1773 0 : if (isNonSolid) {
1774 0 : pen.setDashPattern(distributedDashPattern(dash, gap, ldata->lineLength / lineWidth));
1775 : }
1776 :
1777 0 : painter->setPen(pen);
1778 0 : painter->drawPolyline(&ldata->points[start], end - start);
1779 0 : }
1780 :
1781 0 : void SingleDraw::draw(const GradualTempoChangeSegment* item, Painter* painter, const PaintOptions& opt)
1782 : {
1783 : TRACE_DRAW_ITEM;
1784 0 : drawTextLineBaseSegment(item, painter, opt);
1785 0 : }
1786 :
1787 0 : void SingleDraw::draw(const GuitarBendSegment*, Painter*, const PaintOptions&)
1788 : {
1789 : // TRACE_DRAW_ITEM;
1790 : // To be implemented
1791 0 : }
1792 :
1793 0 : void SingleDraw::draw(const HairpinSegment* item, Painter* painter, const PaintOptions& opt)
1794 : {
1795 : TRACE_DRAW_ITEM;
1796 :
1797 0 : drawTextLineBaseSegment(item, painter, opt);
1798 :
1799 0 : if (item->drawCircledTip()) {
1800 0 : Color color = item->curColor(item->hairpin()->visible(), item->hairpin()->lineColor(), opt);
1801 0 : double w = item->absoluteFromSpatium(item->lineWidth());
1802 0 : if (item->staff()) {
1803 0 : w *= item->staff()->staffMag(item->hairpin()->tick());
1804 : }
1805 :
1806 0 : Pen pen(color, w);
1807 0 : painter->setPen(pen);
1808 0 : painter->setBrush(BrushStyle::NoBrush);
1809 0 : painter->drawEllipse(item->circledTip(), item->circledTipRadius(), item->circledTipRadius());
1810 0 : }
1811 0 : }
1812 :
1813 0 : void SingleDraw::draw(const HammerOnPullOffSegment* item, muse::draw::Painter* painter, const PaintOptions& opt)
1814 : {
1815 0 : draw(toSlurSegment(item), painter, opt);
1816 0 : }
1817 :
1818 0 : void SingleDraw::draw(const HammerOnPullOffText* item, Painter* painter, const PaintOptions& opt)
1819 : {
1820 0 : drawTextBase(item, painter, opt);
1821 0 : }
1822 :
1823 0 : void SingleDraw::draw(const HarpPedalDiagram* item, Painter* painter, const PaintOptions& opt)
1824 : {
1825 : TRACE_DRAW_ITEM;
1826 0 : drawTextBase(item, painter, opt);
1827 0 : }
1828 :
1829 0 : void SingleDraw::draw(const HarmonicMarkSegment* item, Painter* painter, const PaintOptions& opt)
1830 : {
1831 : TRACE_DRAW_ITEM;
1832 0 : drawTextLineBaseSegment(item, painter, opt);
1833 0 : }
1834 :
1835 0 : void SingleDraw::draw(const Harmony* item, Painter* painter, const PaintOptions& opt)
1836 : {
1837 : TRACE_DRAW_ITEM;
1838 :
1839 0 : const Harmony::LayoutData* ldata = item->ldata();
1840 0 : if (ldata->renderItemList().empty()) {
1841 0 : drawTextBase(item, painter, opt);
1842 0 : return;
1843 : }
1844 :
1845 0 : if (item->hasFrame()) {
1846 0 : if (!RealIsNull(item->frameWidth().val())) {
1847 0 : Color color = item->frameColor();
1848 0 : Pen pen(color, item->frameWidth().val() * item->spatium(), PenStyle::SolidLine,
1849 0 : PenCapStyle::SquareCap, PenJoinStyle::MiterJoin);
1850 0 : painter->setPen(pen);
1851 0 : } else {
1852 0 : painter->setNoPen();
1853 : }
1854 0 : Color bg(item->bgColor());
1855 0 : painter->setBrush(bg.alpha() ? Brush(bg) : BrushStyle::NoBrush);
1856 0 : if (item->circle()) {
1857 0 : painter->drawArc(ldata->frame, 0, 5760);
1858 : } else {
1859 0 : double baseSpatium = DefaultStyle::baseStyle().value(Sid::spatium).toReal();
1860 0 : double frameRadius = item->frameRound().val() * (item->sizeIsSpatiumDependent() ? item->spatium() : baseSpatium);
1861 0 : painter->drawRoundedRect(ldata->frame, frameRadius, frameRadius);
1862 : }
1863 : }
1864 0 : painter->setBrush(BrushStyle::NoBrush);
1865 0 : Color color = item->textColor(opt);
1866 0 : painter->setPen(color);
1867 0 : for (const HarmonyRenderItem* renderItem : ldata->renderItemList()) {
1868 0 : if (const TextSegment* ts = dynamic_cast<const TextSegment*>(renderItem)) {
1869 0 : painter->setFont(ts->font());
1870 0 : painter->drawText(ts->pos(), ts->text());
1871 : }
1872 : }
1873 : }
1874 :
1875 0 : void SingleDraw::draw(const Hook* item, Painter* painter, const PaintOptions& opt)
1876 : {
1877 : TRACE_DRAW_ITEM;
1878 0 : painter->setPen(item->curColor(opt));
1879 0 : item->drawSymbol(item->sym(), painter);
1880 0 : }
1881 :
1882 0 : void SingleDraw::draw(const Image* item, Painter* painter, const PaintOptions&)
1883 : {
1884 : TRACE_DRAW_ITEM;
1885 0 : const Image::LayoutData* ldata = item->ldata();
1886 0 : bool emptyImage = false;
1887 0 : if (item->imageType() == ImageType::SVG) {
1888 0 : if (!item->svgRenderer()) {
1889 0 : emptyImage = true;
1890 : } else {
1891 0 : item->svgRenderer()->render(painter, ldata->bbox());
1892 : }
1893 0 : } else if (item->imageType() == ImageType::RASTER) {
1894 0 : if (item->rasterImage() == nullptr) {
1895 0 : emptyImage = true;
1896 : } else {
1897 0 : painter->save();
1898 0 : SizeF s;
1899 0 : if (item->sizeIsSpatium()) {
1900 0 : s = item->size() * item->spatium();
1901 : } else {
1902 0 : s = item->size() * DPMM;
1903 : }
1904 :
1905 0 : painter->scale(s.width() / item->rasterImage()->width(), s.height() / item->rasterImage()->height());
1906 0 : painter->drawPixmap(PointF(0, 0), *item->rasterImage());
1907 :
1908 0 : painter->restore();
1909 : }
1910 : }
1911 :
1912 0 : if (emptyImage) {
1913 0 : painter->setBrush(BrushStyle::NoBrush);
1914 0 : painter->setPen(item->configuration()->defaultColor());
1915 0 : painter->drawRect(ldata->bbox());
1916 0 : painter->drawLine(0.0, 0.0, ldata->bbox().width(), ldata->bbox().height());
1917 0 : painter->drawLine(ldata->bbox().width(), 0.0, 0.0, ldata->bbox().height());
1918 : }
1919 0 : }
1920 :
1921 0 : void SingleDraw::draw(const InstrumentChange* item, Painter* painter, const PaintOptions& opt)
1922 : {
1923 : TRACE_DRAW_ITEM;
1924 0 : drawTextBase(item, painter, opt);
1925 0 : }
1926 :
1927 0 : void SingleDraw::draw(const InstrumentName* item, Painter* painter, const PaintOptions& opt)
1928 : {
1929 : TRACE_DRAW_ITEM;
1930 0 : drawTextBase(item, painter, opt);
1931 0 : }
1932 :
1933 0 : void SingleDraw::draw(const Jump* item, Painter* painter, const PaintOptions& opt)
1934 : {
1935 : TRACE_DRAW_ITEM;
1936 0 : drawTextBase(item, painter, opt);
1937 0 : }
1938 :
1939 0 : void SingleDraw::draw(const KeySig* item, Painter* painter, const PaintOptions& opt)
1940 : {
1941 : TRACE_DRAW_ITEM;
1942 :
1943 0 : const KeySig::LayoutData* ldata = item->ldata();
1944 :
1945 0 : painter->setPen(item->curColor(opt));
1946 0 : double _spatium = item->spatium();
1947 0 : double step = _spatium * 0.5;
1948 0 : int lines = 5;
1949 0 : double ledgerLineWidth = item->style().styleAbsolute(Sid::ledgerLineWidth) * item->mag();
1950 0 : double ledgerExtraLen = item->style().styleS(Sid::ledgerLineLength).val() * _spatium;
1951 0 : for (const KeySym& ks : ldata->keySymbols) {
1952 0 : double x = ks.xPos.toAbsolute(_spatium);
1953 0 : double y = ks.line * step;
1954 0 : item->drawSymbol(ks.sym, painter, PointF(x, y));
1955 : // ledger lines
1956 0 : double _symWidth = item->symWidth(ks.sym);
1957 0 : double x1 = x - ledgerExtraLen;
1958 0 : double x2 = x + _symWidth + ledgerExtraLen;
1959 0 : painter->setPen(Pen(item->curColor(opt), ledgerLineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
1960 0 : for (int i = -2; i >= ks.line; i -= 2) { // above
1961 0 : y = i * step;
1962 0 : painter->drawLine(LineF(x1, y, x2, y));
1963 : }
1964 0 : for (int i = lines * 2; i <= ks.line; i += 2) { // below
1965 0 : y = i * step;
1966 0 : painter->drawLine(LineF(x1, y, x2, y));
1967 : }
1968 : }
1969 :
1970 0 : if (!item->ownershipParent() && (item->isAtonal() || item->isCustom()) && ldata->keySymbols.empty()) {
1971 : // empty custom or atonal key signature - draw something for palette
1972 0 : painter->setPen(item->configuration()->scoreGreyColor());
1973 0 : item->drawSymbol(SymId::timeSigX, painter, PointF(item->symWidth(SymId::timeSigX) * -0.5, 2.0 * item->spatium()));
1974 : }
1975 0 : }
1976 :
1977 0 : void SingleDraw::draw(const LayoutBreak* item, Painter* painter, const PaintOptions&)
1978 : {
1979 : TRACE_DRAW_ITEM;
1980 :
1981 0 : Pen pen(item->configuration()->fontPrimaryColor());
1982 0 : painter->setPen(pen);
1983 :
1984 0 : painter->setFont(item->font());
1985 :
1986 0 : painter->drawSymbol(PointF(0.0, 0.0), item->iconCode());
1987 0 : }
1988 :
1989 0 : void SingleDraw::draw(const LedgerLine* item, Painter* painter, const PaintOptions& opt)
1990 : {
1991 : TRACE_DRAW_ITEM;
1992 0 : const LedgerLine::LayoutData* ldata = item->ldata();
1993 :
1994 0 : painter->setPen(Pen(item->curColor(opt), ldata->lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
1995 0 : if (item->vertical()) {
1996 0 : painter->drawLine(LineF(0.0, 0.0, 0.0, item->len()));
1997 : } else {
1998 0 : painter->drawLine(LineF(0.0, 0.0, item->len(), 0.0));
1999 : }
2000 0 : }
2001 :
2002 0 : void SingleDraw::draw(const LetRingSegment* item, Painter* painter, const PaintOptions& opt)
2003 : {
2004 : TRACE_DRAW_ITEM;
2005 0 : drawTextLineBaseSegment(item, painter, opt);
2006 0 : }
2007 :
2008 0 : void SingleDraw::draw(const Lyrics* item, muse::draw::Painter* painter, const PaintOptions& opt)
2009 : {
2010 : TRACE_DRAW_ITEM;
2011 0 : drawTextBase(item, painter, opt);
2012 0 : }
2013 :
2014 0 : void SingleDraw::draw(const Marker* item, Painter* painter, const PaintOptions& opt)
2015 : {
2016 : TRACE_DRAW_ITEM;
2017 0 : drawTextBase(item, painter, opt);
2018 0 : }
2019 :
2020 0 : void SingleDraw::draw(const MeasureNumber* item, Painter* painter, const PaintOptions& opt)
2021 : {
2022 : TRACE_DRAW_ITEM;
2023 0 : drawTextBase(item, painter, opt);
2024 0 : }
2025 :
2026 0 : void SingleDraw::draw(const MeasureRepeat* item, Painter* painter, const PaintOptions& opt)
2027 : {
2028 : TRACE_DRAW_ITEM;
2029 :
2030 0 : const MeasureRepeat::LayoutData* ldata = item->ldata();
2031 0 : painter->setPen(item->curColor(opt));
2032 0 : item->drawSymbol(ldata->symId, painter);
2033 0 : }
2034 :
2035 0 : void SingleDraw::draw(const OttavaSegment* item, Painter* painter, const PaintOptions& opt)
2036 : {
2037 : TRACE_DRAW_ITEM;
2038 0 : drawTextLineBaseSegment(item, painter, opt);
2039 0 : }
2040 :
2041 0 : void SingleDraw::draw(const PalmMuteSegment* item, Painter* painter, const PaintOptions& opt)
2042 : {
2043 : TRACE_DRAW_ITEM;
2044 0 : drawTextLineBaseSegment(item, painter, opt);
2045 0 : }
2046 :
2047 0 : void SingleDraw::draw(const PedalSegment* item, Painter* painter, const PaintOptions& opt)
2048 : {
2049 : TRACE_DRAW_ITEM;
2050 0 : drawTextLineBaseSegment(item, painter, opt);
2051 0 : }
2052 :
2053 0 : void SingleDraw::draw(const PickScrapeSegment* item, Painter* painter, const PaintOptions& opt)
2054 : {
2055 : TRACE_DRAW_ITEM;
2056 0 : drawTextLineBaseSegment(item, painter, opt);
2057 0 : }
2058 :
2059 0 : void SingleDraw::draw(const PlayCountText* item, Painter* painter, const PaintOptions& opt)
2060 : {
2061 : TRACE_DRAW_ITEM;
2062 0 : drawTextBase(item, painter, opt);
2063 0 : }
2064 :
2065 0 : void SingleDraw::draw(const PlayTechAnnotation* item, Painter* painter, const PaintOptions& opt)
2066 : {
2067 : TRACE_DRAW_ITEM;
2068 0 : drawTextBase(item, painter, opt);
2069 0 : }
2070 :
2071 0 : void SingleDraw::draw(const RasgueadoSegment* item, Painter* painter, const PaintOptions& opt)
2072 : {
2073 : TRACE_DRAW_ITEM;
2074 0 : drawTextLineBaseSegment(item, painter, opt);
2075 0 : }
2076 :
2077 0 : void SingleDraw::draw(const RehearsalMark* item, Painter* painter, const PaintOptions& opt)
2078 : {
2079 : TRACE_DRAW_ITEM;
2080 0 : drawTextBase(item, painter, opt);
2081 0 : }
2082 :
2083 0 : void SingleDraw::draw(const Rest* item, Painter* painter, const PaintOptions& opt)
2084 : {
2085 : TRACE_DRAW_ITEM;
2086 0 : if (item->shouldNotBeDrawn()) {
2087 0 : return;
2088 : }
2089 0 : const Rest::LayoutData* ldata = item->ldata();
2090 0 : painter->setPen(item->curColor(opt));
2091 0 : item->drawSymbol(ldata->sym, painter);
2092 : }
2093 :
2094 0 : void SingleDraw::draw(const ShadowNote* item, Painter* painter, const PaintOptions&)
2095 : {
2096 : TRACE_DRAW_ITEM;
2097 :
2098 0 : if (!item->visible() || !item->isValid()) {
2099 0 : return;
2100 : }
2101 :
2102 0 : PointF ap(item->pagePos());
2103 0 : painter->translate(ap);
2104 0 : double lw = item->style().styleAbsolute(Sid::stemWidth) * item->mag();
2105 0 : Pen pen(item->color(), lw, PenStyle::SolidLine, PenCapStyle::FlatCap);
2106 0 : painter->setPen(pen);
2107 :
2108 0 : bool up = item->computeUp();
2109 :
2110 : // Draw the accidental
2111 0 : SymId acc = Accidental::subtype2symbol(item->accidentalType());
2112 0 : if (acc != SymId::noSym) {
2113 0 : PointF posAcc;
2114 0 : posAcc.rx() -= item->symWidth(acc) + item->style().styleAbsolute(Sid::accidentalNoteDistance) * item->mag();
2115 0 : item->drawSymbol(acc, painter, posAcc);
2116 : }
2117 :
2118 : // Draw the notehead
2119 0 : item->drawSymbol(item->noteheadSymbol(), painter);
2120 :
2121 : // Draw the dots
2122 0 : double sp = item->spatium();
2123 0 : double sp2 = sp / 2;
2124 0 : double noteheadWidth = item->symWidth(item->noteheadSymbol());
2125 :
2126 0 : PointF posDot;
2127 0 : if (item->duration().dots() > 0) {
2128 0 : double d = item->style().styleAbsolute(Sid::dotNoteDistance) * item->mag();
2129 0 : double dd = item->style().styleAbsolute(Sid::dotDotDistance) * item->mag();
2130 0 : posDot.rx() += (noteheadWidth + d);
2131 :
2132 0 : if (item->isRest()) {
2133 0 : posDot.ry() += Rest::getDotline(item->duration().type()) * sp2;
2134 : } else {
2135 0 : posDot.ry() -= (item->lineIndex() % 2 == 0 ? sp2 : 0);
2136 : }
2137 :
2138 0 : if (item->hasFlag() && up) {
2139 0 : posDot.rx() = std::max(posDot.x(), noteheadWidth + item->symBbox(item->flagSym()).right());
2140 : }
2141 :
2142 0 : for (int i = 0; i < item->duration().dots(); i++) {
2143 0 : posDot.rx() += dd * i;
2144 0 : item->drawSymbol(SymId::augmentationDot, painter, posDot);
2145 0 : posDot.rx() -= dd * i;
2146 : }
2147 : }
2148 :
2149 : // Draw stem and flag
2150 0 : if (item->hasStem()) {
2151 0 : double x = up ? (noteheadWidth - (lw / 2)) : lw / 2;
2152 0 : double y1 = item->symSmuflAnchor(item->noteheadSymbol(), up ? SmuflAnchorId::stemUpSE : SmuflAnchorId::stemDownNW).y();
2153 0 : double y2 = (up ? -3.5 : 3.5) * sp;
2154 :
2155 0 : if (item->hasFlag()) {
2156 0 : SymId flag = item->flagSym();
2157 0 : item->drawSymbol(flag, painter, PointF(x - (lw / 2), y2));
2158 0 : y2 += item->symSmuflAnchor(flag, up ? SmuflAnchorId::stemUpNW : SmuflAnchorId::stemDownSW).y();
2159 : }
2160 0 : painter->drawLine(LineF(x, y1, x, y2));
2161 : }
2162 :
2163 : // Draw ledger lines if needed
2164 0 : if (item->ledgerLinesVisible()) {
2165 0 : double extraLen = item->style().styleS(Sid::ledgerLineLength).val() * sp;
2166 0 : double x1 = -extraLen;
2167 0 : double x2 = noteheadWidth + extraLen;
2168 0 : double yOffset = item->staffOffsetY();
2169 0 : double step = sp2 * item->staffType()->lineDistance().val();
2170 :
2171 0 : lw = item->style().styleAbsolute(Sid::ledgerLineWidth) * item->mag();
2172 0 : pen.setWidthF(lw);
2173 0 : painter->setPen(pen);
2174 :
2175 0 : const int topLine = -2 + yOffset / step;
2176 0 : for (int i = topLine; i >= item->lineIndex(); i -= 2) {
2177 0 : double y = step * (i - item->lineIndex());
2178 0 : painter->drawLine(LineF(x1, y, x2, y));
2179 : }
2180 0 : int l = item->staffType()->lines() * 2 + yOffset / step; // first ledger line below staff
2181 0 : for (int i = l; i <= item->lineIndex(); i += 2) {
2182 0 : double y = step * (i - item->lineIndex());
2183 0 : painter->drawLine(LineF(x1, y, x2, y));
2184 : }
2185 : }
2186 :
2187 0 : item->drawArticulations(painter);
2188 :
2189 0 : painter->translate(-ap);
2190 0 : }
2191 :
2192 0 : void SingleDraw::draw(const SlurSegment* item, Painter* painter, const PaintOptions& opt)
2193 : {
2194 : TRACE_DRAW_ITEM;
2195 :
2196 0 : Pen pen(item->curColor(opt));
2197 0 : double mag = item->staff() ? item->staff()->staffMag(item->slur()->tick()) : 1.0;
2198 :
2199 : //Replace generic Qt dash patterns with improved equivalents to show true dots (keep in sync with tie.cpp)
2200 0 : std::vector<double> dotted = { 0.01, 1.99 }; // tighter than Qt PenStyle::DotLine equivalent - would be { 0.01, 2.99 }
2201 0 : std::vector<double> dashed = { 3.00, 3.00 }; // Compensating for caps. Qt default PenStyle::DashLine is { 4.0, 2.0 }
2202 0 : std::vector<double> wideDashed = { 5.00, 6.00 };
2203 :
2204 0 : switch (item->slurTie()->styleType()) {
2205 0 : case SlurStyleType::Solid:
2206 0 : painter->setBrush(Brush(pen.color()));
2207 0 : pen.setCapStyle(PenCapStyle::RoundCap);
2208 0 : pen.setJoinStyle(PenJoinStyle::RoundJoin);
2209 0 : pen.setWidthF(item->style().styleAbsolute(Sid::slurEndWidth) * mag);
2210 0 : break;
2211 0 : case SlurStyleType::Dotted:
2212 0 : painter->setBrush(BrushStyle::NoBrush);
2213 0 : pen.setCapStyle(PenCapStyle::RoundCap); // round dots
2214 0 : pen.setDashPattern(dotted);
2215 0 : pen.setWidthF(item->style().styleAbsolute(Sid::slurDottedWidth) * mag);
2216 0 : break;
2217 0 : case SlurStyleType::Dashed:
2218 0 : painter->setBrush(BrushStyle::NoBrush);
2219 0 : pen.setDashPattern(dashed);
2220 0 : pen.setWidthF(item->style().styleAbsolute(Sid::slurDottedWidth) * mag);
2221 0 : break;
2222 0 : case SlurStyleType::WideDashed:
2223 0 : painter->setBrush(BrushStyle::NoBrush);
2224 0 : pen.setDashPattern(wideDashed);
2225 0 : pen.setWidthF(item->style().styleAbsolute(Sid::slurDottedWidth) * mag);
2226 0 : break;
2227 0 : case SlurStyleType::Undefined:
2228 0 : break;
2229 : }
2230 0 : painter->setPen(pen);
2231 0 : painter->drawPath(item->ldata()->path());
2232 0 : }
2233 :
2234 0 : void SingleDraw::draw(const Spacer* item, Painter* painter, const PaintOptions&)
2235 : {
2236 : TRACE_DRAW_ITEM;
2237 :
2238 0 : auto conf = item->configuration();
2239 :
2240 0 : Pen pen(conf->fontPrimaryColor(), item->spatium() * 0.3);
2241 :
2242 0 : painter->setPen(pen);
2243 0 : painter->setBrush(BrushStyle::NoBrush);
2244 0 : painter->drawPath(item->ldata()->path);
2245 0 : }
2246 :
2247 0 : void SingleDraw::draw(const StaffLines* item, Painter* painter, const PaintOptions& opt)
2248 : {
2249 : TRACE_DRAW_ITEM;
2250 0 : painter->setPen(Pen(item->curColor(opt), item->lw(), PenStyle::SolidLine, PenCapStyle::FlatCap));
2251 0 : painter->drawLines(item->lines());
2252 0 : }
2253 :
2254 0 : void SingleDraw::draw(const StaffState* item, Painter* painter, const PaintOptions&)
2255 : {
2256 : TRACE_DRAW_ITEM;
2257 :
2258 0 : const StaffState::LayoutData* ldata = item->ldata();
2259 0 : auto conf = item->configuration();
2260 :
2261 0 : Pen pen(item->selected() ? conf->selectionColor() : conf->formattingColor(),
2262 0 : ldata->lw, PenStyle::SolidLine, PenCapStyle::RoundCap, PenJoinStyle::RoundJoin);
2263 0 : painter->setPen(pen);
2264 0 : painter->setBrush(BrushStyle::NoBrush);
2265 0 : painter->drawPath(ldata->path);
2266 0 : }
2267 :
2268 0 : void SingleDraw::draw(const StaffText* item, Painter* painter, const PaintOptions& opt)
2269 : {
2270 : TRACE_DRAW_ITEM;
2271 :
2272 0 : drawTextBase(item, painter, opt);
2273 :
2274 0 : if (item->hasSoundFlag()) {
2275 0 : draw(item->soundFlag(), painter, opt);
2276 : }
2277 0 : }
2278 :
2279 0 : void SingleDraw::draw(const StaveSharingLabel* item, muse::draw::Painter* painter, const PaintOptions& opt)
2280 : {
2281 : TRACE_DRAW_ITEM;
2282 :
2283 0 : drawTextBase(item, painter, opt);
2284 0 : }
2285 :
2286 0 : void SingleDraw::draw(const StaffTypeChange* item, Painter* painter, const PaintOptions&)
2287 : {
2288 : TRACE_DRAW_ITEM;
2289 :
2290 0 : auto conf = item->configuration();
2291 :
2292 0 : double _spatium = item->style().spatium();
2293 0 : double h = _spatium * 2.5;
2294 0 : double w = _spatium * 2.5;
2295 0 : double lineDist = 0.35; // line distance for the icon 'staff lines'
2296 : // draw icon rectangle
2297 0 : painter->setPen(Pen(item->selected() ? conf->selectionColor() : conf->formattingColor(),
2298 0 : item->lw(), PenStyle::SolidLine, PenCapStyle::SquareCap, PenJoinStyle::MiterJoin));
2299 0 : painter->setBrush(BrushStyle::NoBrush);
2300 0 : painter->drawRect(0, 0, w, h);
2301 :
2302 : // draw icon contents
2303 0 : int lines = 5;
2304 0 : if (item->staffType()) {
2305 0 : if (item->staffType()->stemless()) { // a single notehead represents a stemless staff
2306 0 : item->drawSymbol(SymId::noteheadBlack, painter, PointF(w * 0.5 - 0.33 * _spatium, h * 0.5), 0.5);
2307 : }
2308 0 : if (item->staffType()->invisible()) { // no lines needed. It's done.
2309 0 : return;
2310 : }
2311 : // show up to 6 lines
2312 0 : lines = std::min(item->staffType()->lines(), 6);
2313 : }
2314 : // calculate starting point Y for the lines from half the icon height (2.5) so staff lines appear vertically centered
2315 0 : double startY = 1.25 - (lines - 1) * lineDist * 0.5;
2316 0 : painter->setPen(Pen(item->selected() ? conf->selectionColor() : conf->formattingColor(),
2317 0 : 2.5, PenStyle::SolidLine, PenCapStyle::SquareCap, PenJoinStyle::MiterJoin));
2318 0 : for (int i=0; i < lines; i++) {
2319 0 : int y = (startY + i * lineDist) * _spatium;
2320 0 : painter->drawLine(0, y, w, y);
2321 : }
2322 0 : }
2323 :
2324 0 : void SingleDraw::draw(const Symbol* item, Painter* painter, const PaintOptions& opt)
2325 : {
2326 : TRACE_DRAW_ITEM;
2327 0 : if (!item->isNoteDot() || !item->staff()->isTabStaff(item->tick())) {
2328 0 : painter->setPen(item->curColor(opt));
2329 0 : if (item->scoreFont()) {
2330 0 : item->scoreFont()->draw(item->sym(), painter, item->magS(), PointF());
2331 : } else {
2332 0 : item->drawSymbol(item->sym(), painter);
2333 : }
2334 : }
2335 0 : }
2336 :
2337 0 : void SingleDraw::draw(const FSymbol* item, Painter* painter, const PaintOptions& opt)
2338 : {
2339 : TRACE_DRAW_ITEM;
2340 :
2341 0 : painter->setFont(item->font());
2342 0 : painter->setPen(item->curColor(opt));
2343 0 : painter->drawText(PointF(0, 0), item->toString());
2344 0 : }
2345 :
2346 0 : void SingleDraw::draw(const SystemDivider* item, Painter* painter, const PaintOptions& opt)
2347 : {
2348 0 : draw(static_cast<const Symbol*>(item), painter, opt);
2349 0 : }
2350 :
2351 0 : void SingleDraw::draw(const SystemText* item, Painter* painter, const PaintOptions& opt)
2352 : {
2353 : TRACE_DRAW_ITEM;
2354 0 : drawTextBase(item, painter, opt);
2355 0 : }
2356 :
2357 0 : void SingleDraw::draw(const SoundFlag* item, Painter* painter, const PaintOptions&)
2358 : {
2359 : TRACE_DRAW_ITEM;
2360 :
2361 0 : painter->setFont(item->iconFont());
2362 0 : painter->drawText(item->ldata()->bbox(), muse::draw::AlignCenter, muse::draw::TextDontClip, Char(item->iconCode()));
2363 0 : }
2364 :
2365 0 : void SingleDraw::draw(const Tapping* item, muse::draw::Painter* painter, const PaintOptions& opt)
2366 : {
2367 0 : drawTextBase(item->text(), painter, opt);
2368 0 : }
2369 :
2370 0 : void SingleDraw::draw(const TempoText* item, Painter* painter, const PaintOptions& opt)
2371 : {
2372 : TRACE_DRAW_ITEM;
2373 0 : drawTextBase(item, painter, opt);
2374 0 : }
2375 :
2376 0 : void SingleDraw::draw(const Text* item, Painter* painter, const PaintOptions& opt)
2377 : {
2378 : TRACE_DRAW_ITEM;
2379 0 : drawTextBase(item, painter, opt);
2380 0 : }
2381 :
2382 0 : void SingleDraw::draw(const TextLineSegment* item, Painter* painter, const PaintOptions& opt)
2383 : {
2384 : TRACE_DRAW_ITEM;
2385 0 : drawTextLineBaseSegment(item, painter, opt);
2386 0 : }
2387 :
2388 0 : void SingleDraw::draw(const TieSegment* item, Painter* painter, const PaintOptions& opt)
2389 : {
2390 : TRACE_DRAW_ITEM;
2391 :
2392 : // hide tie toward the second chord of a cross-measure value
2393 0 : if (item->tie()->endNote() && item->tie()->endNote()->chord()->crossMeasure() == CrossMeasure::SECOND) {
2394 0 : return;
2395 : }
2396 :
2397 0 : Pen pen(item->curColor(opt));
2398 0 : double mag = item->staff() ? item->staff()->staffMag(item->tie()->tick()) : 1.0;
2399 :
2400 : //Replace generic Qt dash patterns with improved equivalents to show true dots (keep in sync with slur.cpp)
2401 0 : std::vector<double> dotted = { 0.01, 1.99 }; // tighter than Qt PenStyle::DotLine equivalent - would be { 0.01, 2.99 }
2402 0 : std::vector<double> dashed = { 3.00, 3.00 }; // Compensating for caps. Qt default PenStyle::DashLine is { 4.0, 2.0 }
2403 0 : std::vector<double> wideDashed = { 5.00, 6.00 };
2404 :
2405 0 : switch (item->slurTie()->styleType()) {
2406 0 : case SlurStyleType::Solid:
2407 0 : painter->setBrush(Brush(pen.color()));
2408 0 : pen.setCapStyle(PenCapStyle::RoundCap);
2409 0 : pen.setJoinStyle(PenJoinStyle::RoundJoin);
2410 0 : pen.setWidthF(item->endWidth() * mag);
2411 0 : break;
2412 0 : case SlurStyleType::Dotted:
2413 0 : painter->setBrush(BrushStyle::NoBrush);
2414 0 : pen.setCapStyle(PenCapStyle::RoundCap); // True dots
2415 0 : pen.setDashPattern(dotted);
2416 0 : pen.setWidthF(item->dottedWidth() * mag);
2417 0 : break;
2418 0 : case SlurStyleType::Dashed:
2419 0 : painter->setBrush(BrushStyle::NoBrush);
2420 0 : pen.setDashPattern(dashed);
2421 0 : pen.setWidthF(item->dottedWidth() * mag);
2422 0 : break;
2423 0 : case SlurStyleType::WideDashed:
2424 0 : painter->setBrush(BrushStyle::NoBrush);
2425 0 : pen.setDashPattern(wideDashed);
2426 0 : pen.setWidthF(item->dottedWidth() * mag);
2427 0 : break;
2428 0 : case SlurStyleType::Undefined:
2429 0 : break;
2430 : }
2431 0 : painter->setPen(pen);
2432 0 : painter->drawPath(item->ldata()->path());
2433 0 : }
2434 :
2435 0 : void SingleDraw::draw(const TimeSig* item, Painter* painter, const PaintOptions& opt)
2436 : {
2437 : TRACE_DRAW_ITEM;
2438 :
2439 0 : if (item->staff() && !const_cast<const Staff*>(item->staff())->staffType(item->tick())->genTimesig()) {
2440 0 : return;
2441 : }
2442 0 : painter->setPen(item->curColor(opt));
2443 :
2444 0 : const TimeSig::LayoutData* ldata = item->ldata();
2445 :
2446 0 : item->drawSymbols(ldata->ns, painter, ldata->pz, item->scale());
2447 0 : item->drawSymbols(ldata->ds, painter, ldata->pn, item->scale());
2448 :
2449 0 : if (item->largeParentheses()) {
2450 0 : item->drawSymbol(SymId::timeSigParensLeft, painter, ldata->pointLargeLeftParen, item->scale().width());
2451 0 : item->drawSymbol(SymId::timeSigParensRight, painter, ldata->pointLargeRightParen, item->scale().width());
2452 : }
2453 : }
2454 :
2455 0 : void SingleDraw::draw(const TremoloSingleChord* item, Painter* painter, const PaintOptions& opt)
2456 : {
2457 : TRACE_DRAW_ITEM;
2458 :
2459 0 : const TremoloSingleChord::LayoutData* ldata = item->ldata();
2460 :
2461 0 : if (item->isBuzzRoll()) {
2462 0 : painter->setPen(item->curColor(opt));
2463 0 : item->drawSymbol(SymId::buzzRoll, painter);
2464 : } else {
2465 0 : painter->setBrush(Brush(item->curColor(opt)));
2466 0 : painter->setNoPen();
2467 0 : painter->drawPath(item->path());
2468 : }
2469 :
2470 : // vertical line (stem)
2471 : {
2472 0 : double x = 0.0; // bbox().width() * .25;
2473 0 : Pen pen(item->curColor(opt), item->absoluteFromSpatium(item->style().styleS(Sid::stemWidth)));
2474 0 : painter->setPen(pen);
2475 0 : const double sp = item->spatium();
2476 0 : if (item->isBuzzRoll()) {
2477 0 : painter->drawLine(LineF(x, -sp, x, ldata->bbox().bottom() + sp));
2478 : } else {
2479 0 : painter->drawLine(LineF(x, -sp * .5, x, item->path().boundingRect().height() + sp));
2480 : }
2481 0 : }
2482 0 : }
2483 :
2484 0 : void SingleDraw::draw(const TremoloTwoChord* item, Painter* painter, const PaintOptions& opt)
2485 : {
2486 : TRACE_DRAW_ITEM;
2487 :
2488 0 : painter->setBrush(Brush(item->curColor(opt)));
2489 0 : painter->setNoPen();
2490 0 : painter->drawPath(item->path());
2491 0 : }
2492 :
2493 0 : void SingleDraw::draw(const TremoloBar* item, Painter* painter, const PaintOptions& opt)
2494 : {
2495 : TRACE_DRAW_ITEM;
2496 0 : const TremoloBar::LayoutData* ldata = item->ldata();
2497 0 : const double lw = item->absoluteFromSpatium(item->lineWidth());
2498 0 : Pen pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::RoundCap, PenJoinStyle::RoundJoin);
2499 0 : painter->setPen(pen);
2500 0 : painter->drawPolyline(ldata->polygon);
2501 0 : }
2502 :
2503 0 : void SingleDraw::draw(const TrillSegment* item, Painter* painter, const PaintOptions& opt)
2504 : {
2505 : TRACE_DRAW_ITEM;
2506 0 : painter->setPen(item->spanner()->curColor(opt));
2507 0 : item->drawSymbols(item->symbols(), painter);
2508 0 : }
2509 :
2510 0 : void SingleDraw::draw(const TripletFeel* item, Painter* painter, const PaintOptions& opt)
2511 : {
2512 : TRACE_DRAW_ITEM;
2513 0 : drawTextBase(item, painter, opt);
2514 0 : }
2515 :
2516 0 : void SingleDraw::draw(const Tuplet* item, Painter* painter, const PaintOptions& opt)
2517 : {
2518 : TRACE_DRAW_ITEM;
2519 :
2520 : // if in a TAB without stems, tuplets are not shown
2521 0 : const StaffType* stt = item->staffType();
2522 0 : if (stt && stt->isTabStaff() && stt->stemless()) {
2523 0 : return;
2524 : }
2525 :
2526 0 : Color color(item->curColor(opt));
2527 0 : if (item->number()) {
2528 0 : painter->setPen(color);
2529 0 : PointF pos(item->number()->pos());
2530 0 : painter->translate(pos);
2531 0 : draw(item->number(), painter, opt);
2532 0 : painter->translate(-pos);
2533 : }
2534 0 : if (item->hasBracket()) {
2535 0 : painter->setPen(Pen(color, item->absoluteFromSpatium(item->bracketWidth()) * item->mag()));
2536 0 : if (!item->number()) {
2537 0 : painter->drawPolyline(item->bracketL, 4);
2538 : } else {
2539 0 : painter->drawPolyline(item->bracketL, 3);
2540 0 : painter->drawPolyline(item->bracketR, 3);
2541 : }
2542 : }
2543 : }
2544 :
2545 0 : void SingleDraw::draw(const VibratoSegment* item, Painter* painter, const PaintOptions& opt)
2546 : {
2547 : TRACE_DRAW_ITEM;
2548 0 : painter->setPen(item->spanner()->curColor(opt));
2549 0 : item->drawSymbols(item->symbols(), painter);
2550 0 : }
2551 :
2552 0 : void SingleDraw::draw(const VoltaSegment* item, Painter* painter, const PaintOptions& opt)
2553 : {
2554 : TRACE_DRAW_ITEM;
2555 0 : drawTextLineBaseSegment(item, painter, opt);
2556 0 : }
2557 :
2558 0 : void SingleDraw::draw(const WhammyBarSegment* item, Painter* painter, const PaintOptions& opt)
2559 : {
2560 : TRACE_DRAW_ITEM;
2561 0 : drawTextLineBaseSegment(item, painter, opt);
2562 0 : }
2563 :
2564 0 : void SingleDraw::setMask(const EngravingItem* item, Painter* painter)
2565 : {
2566 0 : const EngravingItem::LayoutData* ldata = item->ldata();
2567 :
2568 0 : const Shape& mask = ldata->mask();
2569 0 : if (mask.empty()) {
2570 0 : return;
2571 : }
2572 :
2573 0 : RectF background = ldata->bbox().padded(item->spatium());
2574 :
2575 0 : painter->setMask(background, mask.toRects());
2576 : }
|