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 : #include "tdraw.h"
23 :
24 : #include "defer.h"
25 :
26 : #include "draw/fontmetrics.h"
27 : #include "draw/svgrenderer.h"
28 :
29 : #include "iengravingconfiguration.h" // IWYU pragma: keep
30 : #include "iengravingcontextconfiguration.h" // IWYU pragma: keep
31 :
32 : #include "rendering/paintoptions.h"
33 : #include "style/style.h"
34 : #include "style/defaultstyle.h"
35 :
36 : #include "dom/accidental.h"
37 : #include "dom/actionicon.h"
38 : #include "dom/ambitus.h"
39 : #include "dom/arpeggio.h"
40 : #include "dom/chordbracket.h"
41 : #include "dom/articulation.h"
42 :
43 : #include "dom/bagpembell.h"
44 : #include "dom/barline.h"
45 : #include "dom/beam.h"
46 : #include "dom/bend.h"
47 : #include "dom/box.h"
48 : #include "dom/bracket.h"
49 : #include "dom/breath.h"
50 :
51 : #include "dom/chord.h"
52 : #include "dom/chordline.h"
53 : #include "dom/clef.h"
54 : #include "dom/capo.h"
55 :
56 : #include "dom/deadslapped.h"
57 : #include "dom/dynamic.h"
58 :
59 : #include "dom/expression.h"
60 :
61 : #include "dom/fermata.h"
62 : #include "dom/figuredbass.h"
63 : #include "dom/fingering.h"
64 : #include "dom/fret.h"
65 :
66 : #include "dom/glissando.h"
67 : #include "dom/gradualtempochange.h"
68 : #include "dom/guitarbend.h"
69 :
70 : #include "dom/hairpin.h"
71 : #include "dom/hammeronpulloff.h"
72 : #include "dom/harppedaldiagram.h"
73 : #include "dom/harmonicmark.h"
74 : #include "dom/harmony.h"
75 : #include "dom/hook.h"
76 :
77 : #include "dom/image.h"
78 : #include "dom/instrchange.h"
79 : #include "dom/instrumentname.h"
80 :
81 : #include "dom/jump.h"
82 :
83 : #include "dom/keysig.h"
84 :
85 : #include "dom/laissezvib.h"
86 : #include "dom/lasso.h"
87 : #include "dom/layoutbreak.h"
88 : #include "dom/ledgerline.h"
89 : #include "dom/letring.h"
90 : #include "dom/lyrics.h"
91 :
92 : #include "dom/marker.h"
93 : #include "dom/measurenumber.h"
94 : #include "dom/measurerepeat.h"
95 : #include "dom/mmrest.h"
96 : #include "dom/mmrestrange.h"
97 :
98 : #include "dom/note.h"
99 : #include "dom/notedot.h"
100 : #include "dom/noteline.h"
101 :
102 : #include "dom/ornament.h"
103 : #include "dom/ottava.h"
104 :
105 : #include "dom/page.h"
106 : #include "dom/pagelockindicator.h"
107 : #include "dom/parenthesis.h"
108 : #include "dom/partialtie.h"
109 : #include "dom/palmmute.h"
110 : #include "dom/part.h"
111 : #include "dom/pedal.h"
112 : #include "dom/pickscrape.h"
113 : #include "dom/playcounttext.h"
114 : #include "dom/playtechannotation.h"
115 :
116 : #include "dom/rasgueado.h"
117 : #include "dom/rehearsalmark.h"
118 : #include "dom/rest.h"
119 :
120 : #include "dom/score.h"
121 : #include "dom/shadownote.h"
122 : #include "dom/slur.h"
123 : #include "dom/spacer.h"
124 : #include "dom/staff.h"
125 : #include "dom/stafflines.h"
126 : #include "dom/staffstate.h"
127 : #include "dom/stafftext.h"
128 : #include "dom/stafftype.h"
129 : #include "dom/stafftypechange.h"
130 : #include "dom/staffvisibilityindicator.h"
131 : #include "dom/stavesharinglabel.h"
132 : #include "dom/stem.h"
133 : #include "dom/stemslash.h"
134 : #include "dom/sticking.h"
135 : #include "dom/stringtunings.h"
136 : #include "dom/symbol.h"
137 : #include "dom/systemdivider.h"
138 : #include "dom/systemlockindicator.h"
139 : #include "dom/systemtext.h"
140 : #include "dom/soundflag.h"
141 :
142 : #include "dom/tabdurationsymbol.h"
143 : #include "dom/tapping.h"
144 : #include "dom/tempotext.h"
145 : #include "dom/text.h"
146 : #include "dom/textbase.h"
147 : #include "dom/textline.h"
148 : #include "dom/textlinebase.h"
149 : #include "dom/tie.h"
150 : #include "dom/timesig.h"
151 : #include "dom/anchors.h"
152 : #include "dom/tremolosinglechord.h"
153 : #include "dom/tremolotwochord.h"
154 : #include "dom/tremolobar.h"
155 : #include "dom/trill.h"
156 : #include "dom/tripletfeel.h"
157 : #include "dom/tuplet.h"
158 :
159 : #include "dom/vibrato.h"
160 : #include "dom/volta.h"
161 :
162 : #include "dom/whammybar.h"
163 :
164 : #include "editing/mscoreview.h"
165 : #include "editing/navigation.h"
166 :
167 : #include "infrastructure/rtti.h"
168 :
169 : #include "stemlayout.h"
170 :
171 : // dev
172 : #include "dom/system.h"
173 : #include "dom/measure.h"
174 : #include "dom/segment.h"
175 : #include "dom/chord.h"
176 :
177 : using namespace mu::engraving;
178 : using namespace mu::engraving::rtti;
179 : using namespace mu::engraving::rendering::score;
180 : using namespace muse;
181 : using namespace muse::draw;
182 :
183 380 : void TDraw::drawItem(const EngravingItem* item, Painter* painter, const PaintOptions& opt)
184 : {
185 380 : switch (item->type()) {
186 94 : case ElementType::ACCIDENTAL: draw(item_cast<const Accidental*>(item), painter, opt);
187 94 : break;
188 0 : case ElementType::ACTION_ICON: draw(item_cast<const ActionIcon*>(item), painter, opt);
189 0 : break;
190 0 : case ElementType::AMBITUS: draw(item_cast<const Ambitus*>(item), painter, opt);
191 0 : break;
192 0 : case ElementType::ARPEGGIO: draw(item_cast<const Arpeggio*>(item), painter, opt);
193 0 : break;
194 0 : case ElementType::CHORD_BRACKET: draw(item_cast<const ChordBracket*>(item), painter, opt);
195 0 : break;
196 0 : case ElementType::ARTICULATION: draw(item_cast<const Articulation*>(item), painter, opt);
197 0 : break;
198 :
199 0 : case ElementType::BAGPIPE_EMBELLISHMENT: draw(item_cast<const BagpipeEmbellishment*>(item), painter, opt);
200 0 : break;
201 30 : case ElementType::BAR_LINE: draw(item_cast<const BarLine*>(item), painter, opt);
202 30 : break;
203 0 : case ElementType::BEAM: draw(item_cast<const Beam*>(item), painter, opt);
204 0 : break;
205 0 : case ElementType::BEND: draw(item_cast<const Bend*>(item), painter, opt);
206 0 : break;
207 0 : case ElementType::HBOX: draw(item_cast<const HBox*>(item), painter, opt);
208 0 : break;
209 0 : case ElementType::VBOX: draw(item_cast<const VBox*>(item), painter, opt);
210 0 : break;
211 0 : case ElementType::FBOX: draw(item_cast<const FBox*>(item), painter, opt);
212 0 : break;
213 0 : case ElementType::TBOX: draw(item_cast<const TBox*>(item), painter, opt);
214 0 : break;
215 0 : case ElementType::BRACKET: draw(item_cast<const Bracket*>(item), painter, opt);
216 0 : break;
217 0 : case ElementType::BREATH: draw(item_cast<const Breath*>(item), painter, opt);
218 0 : break;
219 :
220 0 : case ElementType::CHORDLINE: draw(item_cast<const ChordLine*>(item), painter, opt);
221 0 : break;
222 10 : case ElementType::CLEF: draw(item_cast<const Clef*>(item), painter, opt);
223 10 : break;
224 0 : case ElementType::CAPO: draw(item_cast<const Capo*>(item), painter, opt);
225 0 : break;
226 :
227 0 : case ElementType::DEAD_SLAPPED: draw(item_cast<const DeadSlapped*>(item), painter, opt);
228 0 : break;
229 0 : case ElementType::DYNAMIC: draw(item_cast<const Dynamic*>(item), painter, opt);
230 0 : break;
231 :
232 0 : case ElementType::EXPRESSION: draw(item_cast<const Expression*>(item), painter, opt);
233 0 : break;
234 :
235 0 : case ElementType::FERMATA: draw(item_cast<const Fermata*>(item), painter, opt);
236 0 : break;
237 0 : case ElementType::FIGURED_BASS: draw(item_cast<const FiguredBass*>(item), painter, opt);
238 0 : break;
239 0 : case ElementType::FINGERING: draw(item_cast<const Fingering*>(item), painter, opt);
240 0 : break;
241 0 : case ElementType::FRET_DIAGRAM: draw(item_cast<const FretDiagram*>(item), painter, opt);
242 0 : break;
243 0 : case ElementType::FSYMBOL: draw(item_cast<const FSymbol*>(item), painter, opt);
244 0 : break;
245 :
246 0 : case ElementType::GLISSANDO_SEGMENT: draw(item_cast<const GlissandoSegment*>(item), painter, opt);
247 0 : break;
248 0 : case ElementType::GRADUAL_TEMPO_CHANGE_SEGMENT: draw(item_cast<const GradualTempoChangeSegment*>(item), painter, opt);
249 0 : break;
250 0 : case ElementType::GUITAR_BEND_SEGMENT: draw(item_cast<const GuitarBendSegment*>(item), painter, opt);
251 0 : break;
252 0 : case ElementType::GUITAR_BEND_HOLD_SEGMENT: draw(item_cast<const GuitarBendHoldSegment*>(item), painter, opt);
253 0 : break;
254 0 : case ElementType::GUITAR_BEND_TEXT: drawTextBase(toTextBase(item), painter, opt);
255 0 : break;
256 :
257 0 : case ElementType::HAIRPIN_SEGMENT: draw(item_cast<const HairpinSegment*>(item), painter, opt);
258 0 : break;
259 0 : case ElementType::HAMMER_ON_PULL_OFF_SEGMENT: draw(item_cast<const HammerOnPullOffSegment*>(item), painter, opt);
260 0 : break;
261 0 : case ElementType::HAMMER_ON_PULL_OFF_TEXT: draw(item_cast<const HammerOnPullOffText*>(item), painter, opt);
262 0 : break;
263 0 : case ElementType::HARP_DIAGRAM: draw(item_cast<const HarpPedalDiagram*>(item), painter, opt);
264 0 : break;
265 0 : case ElementType::HARMONIC_MARK_SEGMENT: draw(item_cast<const HarmonicMarkSegment*>(item), painter, opt);
266 0 : break;
267 0 : case ElementType::HARMONY: draw(item_cast<const Harmony*>(item), painter, opt);
268 0 : break;
269 0 : case ElementType::HOOK: draw(item_cast<const Hook*>(item), painter, opt);
270 0 : break;
271 :
272 0 : case ElementType::IMAGE: draw(item_cast<const Image*>(item), painter, opt);
273 0 : break;
274 0 : case ElementType::INSTRUMENT_CHANGE: draw(item_cast<const InstrumentChange*>(item), painter, opt);
275 0 : break;
276 0 : case ElementType::INSTRUMENT_NAME: draw(item_cast<const InstrumentName*>(item), painter, opt);
277 0 : break;
278 :
279 0 : case ElementType::JUMP: draw(item_cast<const Jump*>(item), painter, opt);
280 0 : break;
281 :
282 0 : case ElementType::KEYSIG: draw(item_cast<const KeySig*>(item), painter, opt);
283 0 : break;
284 0 : case ElementType::LAISSEZ_VIB_SEGMENT: draw(item_cast<const LaissezVibSegment*>(item), painter, opt);
285 0 : break;
286 0 : case ElementType::LASSO: draw(item_cast<const Lasso*>(item), painter, opt);
287 0 : break;
288 0 : case ElementType::LAYOUT_BREAK: draw(item_cast<const LayoutBreak*>(item), painter, opt);
289 0 : break;
290 24 : case ElementType::LEDGER_LINE: draw(item_cast<const LedgerLine*>(item), painter, opt);
291 24 : break;
292 0 : case ElementType::LET_RING_SEGMENT: draw(item_cast<const LetRingSegment*>(item), painter, opt);
293 0 : break;
294 0 : case ElementType::LYRICS: draw(item_cast<const Lyrics*>(item), painter, opt);
295 0 : break;
296 0 : case ElementType::LYRICSLINE_SEGMENT: draw(item_cast<const LyricsLineSegment*>(item), painter, opt);
297 0 : break;
298 0 : case ElementType::PARTIAL_LYRICSLINE_SEGMENT: draw(item_cast<const LyricsLineSegment*>(item), painter, opt);
299 0 : break;
300 :
301 0 : case ElementType::MARKER: draw(item_cast<const Marker*>(item), painter, opt);
302 0 : break;
303 0 : case ElementType::MEASURE_NUMBER: draw(item_cast<const MeasureNumber*>(item), painter, opt);
304 0 : break;
305 0 : case ElementType::MEASURE_REPEAT: draw(item_cast<const MeasureRepeat*>(item), painter, opt);
306 0 : break;
307 0 : case ElementType::MMREST: draw(item_cast<const MMRest*>(item), painter, opt);
308 0 : break;
309 0 : case ElementType::MMREST_RANGE: draw(item_cast<const MMRestRange*>(item), painter, opt);
310 0 : break;
311 :
312 127 : case ElementType::NOTE: draw(item_cast<const Note*>(item), painter, opt);
313 127 : break;
314 0 : case ElementType::NOTEDOT: draw(item_cast<const NoteDot*>(item), painter, opt);
315 0 : break;
316 0 : case ElementType::NOTEHEAD: draw(item_cast<const NoteHead*>(item), painter, opt);
317 0 : break;
318 0 : case ElementType::NOTELINE_SEGMENT: draw(item_cast<const NoteLineSegment*>(item), painter, opt);
319 0 : break;
320 :
321 0 : case ElementType::ORNAMENT: draw(item_cast<const Ornament*>(item), painter, opt);
322 0 : break;
323 0 : case ElementType::OTTAVA_SEGMENT: draw(item_cast<const OttavaSegment*>(item), painter, opt);
324 0 : break;
325 0 : case ElementType::PAGE_LOCK_INDICATOR: draw(item_cast<const PageLockIndicator*>(item), painter, opt);
326 0 : break;
327 0 : case ElementType::PARENTHESIS: draw(item_cast<const Parenthesis*>(item), painter, opt);
328 0 : break;
329 0 : case ElementType::PARTIAL_TIE_SEGMENT: draw(item_cast<const PartialTieSegment*>(item), painter, opt);
330 0 : break;
331 0 : case ElementType::PALM_MUTE_SEGMENT: draw(item_cast<const PalmMuteSegment*>(item), painter, opt);
332 0 : break;
333 0 : case ElementType::PEDAL_SEGMENT: draw(item_cast<const PedalSegment*>(item), painter, opt);
334 0 : break;
335 0 : case ElementType::PICK_SCRAPE_SEGMENT: draw(item_cast<const PickScrapeSegment*>(item), painter, opt);
336 0 : break;
337 0 : case ElementType::PLAY_COUNT_TEXT: draw(item_cast<const PlayCountText*>(item), painter, opt);
338 0 : break;
339 0 : case ElementType::PLAYTECH_ANNOTATION: draw(item_cast<const PlayTechAnnotation*>(item), painter, opt);
340 0 : break;
341 :
342 0 : case ElementType::RASGUEADO_SEGMENT: draw(item_cast<const RasgueadoSegment*>(item), painter, opt);
343 0 : break;
344 0 : case ElementType::REHEARSAL_MARK: draw(item_cast<const RehearsalMark*>(item), painter, opt);
345 0 : break;
346 0 : case ElementType::REST: draw(item_cast<const Rest*>(item), painter, opt);
347 0 : break;
348 :
349 0 : case ElementType::SHADOW_NOTE: draw(item_cast<const ShadowNote*>(item), painter, opt);
350 0 : break;
351 0 : case ElementType::SLUR_SEGMENT: draw(item_cast<const SlurSegment*>(item), painter, opt);
352 0 : break;
353 0 : case ElementType::SPACER: draw(item_cast<const Spacer*>(item), painter, opt);
354 0 : break;
355 20 : case ElementType::STAFF_LINES: draw(item_cast<const StaffLines*>(item), painter, opt);
356 20 : break;
357 0 : case ElementType::STAFF_STATE: draw(item_cast<const StaffState*>(item), painter, opt);
358 0 : break;
359 0 : case ElementType::STAFF_TEXT: draw(item_cast<const StaffText*>(item), painter, opt);
360 0 : break;
361 0 : case ElementType::STAVE_SHARING_LABEL: draw(item_cast<const StaveSharingLabel*>(item), painter, opt);
362 0 : break;
363 0 : case ElementType::STAFFTYPE_CHANGE: draw(item_cast<const StaffTypeChange*>(item), painter, opt);
364 0 : break;
365 0 : case ElementType::STAFF_VISIBILITY_INDICATOR: draw(item_cast<const StaffVisibilityIndicator*>(item), painter, opt);
366 0 : break;
367 60 : case ElementType::STEM: draw(item_cast<const Stem*>(item), painter, opt);
368 60 : break;
369 0 : case ElementType::STEM_SLASH: draw(item_cast<const StemSlash*>(item), painter, opt);
370 0 : break;
371 0 : case ElementType::STICKING: draw(item_cast<const Sticking*>(item), painter, opt);
372 0 : break;
373 0 : case ElementType::STRING_TUNINGS: draw(item_cast<const StringTunings*>(item), painter, opt);
374 0 : break;
375 0 : case ElementType::SYMBOL: draw(item_cast<const Symbol*>(item), painter, opt);
376 0 : break;
377 0 : case ElementType::SYSTEM_DIVIDER: draw(item_cast<const SystemDivider*>(item), painter, opt);
378 0 : break;
379 0 : case ElementType::SYSTEM_TEXT: draw(item_cast<const SystemText*>(item), painter, opt);
380 0 : break;
381 0 : case ElementType::SYSTEM_LOCK_INDICATOR: draw(item_cast<const SystemLockIndicator*>(item), painter, opt);
382 0 : break;
383 0 : case ElementType::SOUND_FLAG: draw(item_cast<const SoundFlag*>(item), painter, opt);
384 0 : break;
385 :
386 0 : case ElementType::TAB_DURATION_SYMBOL: draw(item_cast<const TabDurationSymbol*>(item), painter, opt);
387 0 : break;
388 0 : case ElementType::TAPPING: draw(toTapping(item), painter, opt);
389 0 : break;
390 0 : case ElementType::TAPPING_HALF_SLUR_SEGMENT: draw(toSlurSegment(item), painter, opt);
391 0 : break;
392 0 : case ElementType::TEMPO_TEXT: draw(item_cast<const TempoText*>(item), painter, opt);
393 0 : break;
394 0 : case ElementType::TEXT: draw(item_cast<const Text*>(item), painter, opt);
395 0 : break;
396 0 : case ElementType::TEXTLINE_SEGMENT: draw(item_cast<const TextLineSegment*>(item), painter, opt);
397 0 : break;
398 0 : case ElementType::TIE_SEGMENT: draw(item_cast<const TieSegment*>(item), painter, opt);
399 0 : break;
400 10 : case ElementType::TIMESIG: draw(item_cast<const TimeSig*>(item), painter, opt);
401 10 : break;
402 0 : case ElementType::TIME_TICK_ANCHOR: draw(item_cast<const TimeTickAnchor*>(item), painter, opt);
403 0 : break;
404 0 : case ElementType::TREMOLO_SINGLECHORD: draw(item_cast<const TremoloSingleChord*>(item), painter, opt);
405 0 : break;
406 0 : case ElementType::TREMOLO_TWOCHORD: draw(item_cast<const TremoloTwoChord*>(item), painter, opt);
407 0 : break;
408 0 : case ElementType::TREMOLOBAR: draw(item_cast<const TremoloBar*>(item), painter, opt);
409 0 : break;
410 0 : case ElementType::TRILL_SEGMENT: draw(item_cast<const TrillSegment*>(item), painter, opt);
411 0 : break;
412 0 : case ElementType::TRIPLET_FEEL: draw(item_cast<const TripletFeel*>(item), painter, opt);
413 0 : break;
414 0 : case ElementType::TUPLET: draw(item_cast<const Tuplet*>(item), painter, opt);
415 0 : break;
416 :
417 0 : case ElementType::VIBRATO_SEGMENT: draw(item_cast<const VibratoSegment*>(item), painter, opt);
418 0 : break;
419 0 : case ElementType::VOLTA_SEGMENT: draw(item_cast<const VoltaSegment*>(item), painter, opt);
420 0 : break;
421 :
422 0 : case ElementType::WHAMMY_BAR_SEGMENT: draw(item_cast<const WhammyBarSegment*>(item), painter, opt);
423 0 : break;
424 :
425 5 : case ElementType::PAGE:
426 : case ElementType::SYSTEM:
427 : case ElementType::MEASURE:
428 : case ElementType::SEGMENT:
429 : case ElementType::CHORD:
430 : case ElementType::GRACE_NOTES_GROUP:
431 5 : break;
432 :
433 0 : default:
434 0 : NOT_IMPLEMENTED << " type: " << item->typeName();
435 0 : UNREACHABLE;
436 : }
437 380 : }
438 :
439 94 : void TDraw::draw(const Accidental* item, Painter* painter, const PaintOptions& opt)
440 : {
441 : TRACE_DRAW_ITEM;
442 94 : IF_ASSERT_FAILED(item->ldata()) {
443 0 : return;
444 : }
445 :
446 94 : painter->setPen(item->curColor(opt));
447 188 : for (const Accidental::LayoutData::Sym& e : item->ldata()->syms) {
448 94 : item->drawSymbol(e.sym, painter, PointF(e.x, e.y));
449 : }
450 : }
451 :
452 0 : void TDraw::draw(const ActionIcon* item, Painter* painter, const PaintOptions&)
453 : {
454 : TRACE_DRAW_ITEM;
455 0 : const ActionIcon::LayoutData* ldata = item->ldata();
456 0 : painter->setFont(item->iconFont());
457 0 : painter->drawText(ldata->bbox(), muse::draw::AlignCenter, muse::draw::TextDontClip, Char(item->icon()));
458 0 : }
459 :
460 0 : void TDraw::draw(const Ambitus* item, Painter* painter, const PaintOptions& opt)
461 : {
462 : TRACE_DRAW_ITEM;
463 :
464 0 : const Ambitus::LayoutData* ldata = item->ldata();
465 0 : IF_ASSERT_FAILED(ldata) {
466 0 : return;
467 : }
468 :
469 0 : double spatium = item->spatium();
470 0 : double lw = item->lineWidth().val() * spatium;
471 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
472 :
473 0 : item->drawSymbol(item->noteHead(), painter, ldata->topPos);
474 0 : item->drawSymbol(item->noteHead(), painter, ldata->bottomPos);
475 0 : if (item->hasLine()) {
476 0 : painter->drawLine(ldata->line);
477 : }
478 :
479 : // draw ledger lines (if not in a palette)
480 0 : if (item->segment() && item->track() != muse::nidx) {
481 0 : Fraction tick = item->segment()->tick();
482 0 : Staff* staff = item->score()->staff(item->staffIdx());
483 0 : double lineDist = staff->lineDistance(tick);
484 0 : int numOfLines = staff->lines(tick);
485 0 : double step = lineDist * spatium;
486 0 : double stepTolerance = step * 0.1;
487 0 : double ledgerLineLength = item->style().styleS(Sid::ledgerLineLength).val() * spatium;
488 0 : double ledgerLineWidth = item->style().styleS(Sid::ledgerLineWidth).val() * spatium;
489 0 : painter->setPen(Pen(item->curColor(opt), ledgerLineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
490 :
491 0 : if (ldata->topPos.y() - stepTolerance <= -step) {
492 0 : double xMin = ldata->topPos.x() - ledgerLineLength;
493 0 : double xMax = ldata->topPos.x() + item->headWidth() + ledgerLineLength;
494 0 : for (double y = -step; y >= ldata->topPos.y() - stepTolerance; y -= step) {
495 0 : painter->drawLine(PointF(xMin, y), PointF(xMax, y));
496 : }
497 : }
498 :
499 0 : if (ldata->bottomPos.y() + stepTolerance >= numOfLines * step) {
500 0 : double xMin = ldata->bottomPos.x() - ledgerLineLength;
501 0 : double xMax = ldata->bottomPos.x() + item->headWidth() + ledgerLineLength;
502 0 : for (double y = numOfLines * step; y <= ldata->bottomPos.y() + stepTolerance; y += step) {
503 0 : painter->drawLine(PointF(xMin, y), PointF(xMax, y));
504 : }
505 : }
506 : }
507 : }
508 :
509 0 : void TDraw::draw(const Arpeggio* item, Painter* painter, const PaintOptions& opt)
510 : {
511 : TRACE_DRAW_ITEM;
512 :
513 0 : const Arpeggio::LayoutData* ldata = item->ldata();
514 0 : IF_ASSERT_FAILED(ldata) {
515 0 : return;
516 : }
517 :
518 0 : const double y1 = ldata->bbox().top();
519 0 : const double y2 = ldata->bbox().bottom();
520 0 : const double lineWidth = item->style().styleAbsolute(Sid::arpeggioLineWidth);
521 :
522 0 : painter->setPen(Pen(item->curColor(opt), lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
523 0 : painter->save();
524 :
525 0 : switch (item->arpeggioType()) {
526 0 : case ArpeggioType::NORMAL:
527 : case ArpeggioType::UP:
528 : {
529 0 : const RectF& r = ldata->symsBBox;
530 0 : painter->rotate(-90.0);
531 0 : item->drawSymbols(ldata->symbols, painter, PointF(-r.right() - y1, -r.bottom() + r.height()));
532 0 : } break;
533 :
534 0 : case ArpeggioType::DOWN:
535 : {
536 0 : const RectF& r = ldata->symsBBox;
537 0 : painter->rotate(90.0);
538 0 : item->drawSymbols(ldata->symbols, painter, PointF(-r.left() + y1, -r.top() - r.height()));
539 0 : } break;
540 :
541 0 : case ArpeggioType::UP_STRAIGHT:
542 : {
543 0 : const RectF& r = ldata->symsBBox;
544 0 : double x1 = item->spatium() * 0.5;
545 0 : item->drawSymbol(SymId::arrowheadBlackUp, painter, PointF(x1 - r.width() * 0.5, y1 - r.top()));
546 0 : double ny1 = y1 - r.top() * 0.5;
547 0 : painter->drawLine(LineF(x1, ny1, x1, y2));
548 0 : } break;
549 :
550 0 : case ArpeggioType::DOWN_STRAIGHT:
551 : {
552 0 : const RectF& r = ldata->symsBBox;
553 0 : double x1 = item->spatium() * 0.5;
554 0 : item->drawSymbol(SymId::arrowheadBlackDown, painter, PointF(x1 - r.width() * 0.5, y2 - r.bottom()));
555 0 : double ny2 = y2 + r.top() * 0.5;
556 0 : painter->drawLine(LineF(x1, y1, x1, ny2));
557 0 : } break;
558 :
559 0 : case ArpeggioType::BRACKET:
560 : {
561 0 : double w = item->style().styleS(Sid::arpeggioHookLen).val() * item->spatium();
562 0 : painter->drawLine(LineF(0.0, y1, w, y1));
563 0 : painter->drawLine(LineF(0.0, y2, w, y2));
564 0 : painter->drawLine(LineF(0.0, y1 - lineWidth / 2, 0.0, y2 + lineWidth / 2));
565 0 : } break;
566 : }
567 0 : painter->restore();
568 : }
569 :
570 0 : void TDraw::draw(const ChordBracket* item, muse::draw::Painter* painter, const PaintOptions& opt)
571 : {
572 0 : const Arpeggio::LayoutData* ldata = item->ldata();
573 :
574 0 : const double lineWidth = item->style().styleAbsolute(Sid::chordBracketLineWidth);
575 0 : painter->setPen(Pen(item->curColor(opt), lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
576 :
577 0 : const double halfLineWidth = 0.5 * lineWidth;
578 0 : const double y1 = ldata->bbox().top() + halfLineWidth;
579 0 : const double y2 = ldata->bbox().bottom() - halfLineWidth;
580 :
581 0 : double w = item->absoluteFromSpatium(item->hookLength());
582 :
583 0 : if (item->hookPos() != DirectionV::DOWN) {
584 0 : painter->drawLine(LineF(0.0, y1, w, y1));
585 : }
586 0 : if (item->hookPos() != DirectionV::UP) {
587 0 : painter->drawLine(LineF(0.0, y2, w, y2));
588 : }
589 :
590 0 : const double x = item->rightSide() ? w - halfLineWidth : halfLineWidth;
591 0 : painter->drawLine(LineF(x, y1, x, y2));
592 0 : }
593 :
594 0 : void TDraw::draw(const Articulation* item, Painter* painter, const PaintOptions& opt)
595 : {
596 : TRACE_DRAW_ITEM;
597 :
598 0 : painter->setPen(item->curColor(opt));
599 :
600 0 : if (item->textType() == ArticulationTextType::NO_TEXT) {
601 0 : item->drawSymbol(item->symId(), painter);
602 : } else {
603 0 : drawTextBase(item->text(), painter, opt);
604 : }
605 0 : }
606 :
607 0 : void TDraw::draw(const Ornament* item, Painter* painter, const PaintOptions& opt)
608 : {
609 0 : draw(static_cast<const Articulation*>(item), painter, opt);
610 0 : }
611 :
612 0 : void TDraw::draw(const BagpipeEmbellishment* item, Painter* painter, const PaintOptions& opt)
613 : {
614 : TRACE_DRAW_ITEM;
615 :
616 0 : const BagpipeEmbellishment::LayoutData* data = item->ldata();
617 0 : IF_ASSERT_FAILED(data) {
618 0 : return;
619 : }
620 0 : const BagpipeEmbellishment::LayoutData::BeamData& dataBeam = data->beamData;
621 :
622 0 : Pen pen(item->curColor(opt), data->stemLineW, PenStyle::SolidLine, PenCapStyle::FlatCap);
623 0 : painter->setPen(pen);
624 :
625 : // draw the notes including stem, (optional) flag and (optional) ledger line
626 0 : for (const auto& p : data->notesData) {
627 0 : const BagpipeEmbellishment::LayoutData::NoteData& noteData = p.second;
628 :
629 : // Draw Grace Note
630 : {
631 : // draw head
632 0 : item->drawSymbol(data->headsym, painter, noteData.headXY);
633 :
634 : // draw stem
635 0 : painter->drawLine(noteData.stemLine);
636 :
637 0 : if (data->isDrawFlag) {
638 : // draw flag
639 0 : item->drawSymbol(data->flagsym, painter, noteData.flagXY);
640 : }
641 : }
642 :
643 : // draw the ledger line for high A
644 0 : if (!noteData.ledgerLine.isNull()) {
645 0 : painter->drawLine(noteData.ledgerLine);
646 : }
647 : }
648 :
649 0 : if (data->isDrawBeam) {
650 0 : Pen beamPen(item->curColor(opt), dataBeam.width, PenStyle::SolidLine, PenCapStyle::FlatCap);
651 0 : painter->setPen(beamPen);
652 : // draw the beams
653 0 : auto drawBeams = [](Painter* painter, const double spatium,
654 : const double x1, const double x2, double y)
655 : {
656 : // draw the beams
657 0 : painter->drawLine(LineF(x1, y, x2, y));
658 0 : y += spatium / 1.5;
659 0 : painter->drawLine(LineF(x1, y, x2, y));
660 0 : y += spatium / 1.5;
661 0 : painter->drawLine(LineF(x1, y, x2, y));
662 0 : };
663 :
664 0 : drawBeams(painter, data->spatium, dataBeam.x1, dataBeam.x2, dataBeam.y);
665 0 : }
666 0 : }
667 :
668 0 : static void drawDots(const BarLine* item, Painter* painter, double x)
669 : {
670 0 : double spatium = item->spatium();
671 :
672 : double y1l;
673 : double y2l;
674 0 : if (item->ownershipParent() == 0) { // for use in palette (always Bravura)
675 : //Bravura shifted repeatDot symbol 0.5sp upper in the font itself (1.272)
676 0 : y1l = 1.5 * spatium;
677 0 : y2l = 2.5 * spatium;
678 : } else {
679 0 : const StaffType* st = item->staffType();
680 0 : const int lines = st->lines();
681 0 : const double lineDistance = item->absoluteFromSpatium(st->lineDistance());
682 :
683 0 : y1l = (static_cast<double>((lines - 1) / 2) - 0.5) * lineDistance;
684 0 : y2l = (static_cast<double>(lines / 2) + 0.5) * lineDistance;
685 :
686 : //adjust for staffType offset
687 0 : double stYOffset = item->staffOffsetY();
688 0 : y1l += stYOffset;
689 0 : y2l += stYOffset;
690 : }
691 :
692 0 : item->drawSymbol(SymId::repeatDot, painter, PointF(x, y1l));
693 0 : item->drawSymbol(SymId::repeatDot, painter, PointF(x, y2l));
694 0 : }
695 :
696 0 : static void drawTips(const BarLine* item, const BarLine::LayoutData* data, Painter* painter, bool reversed, double x)
697 : {
698 0 : if (reversed) {
699 0 : if (item->isTop()) {
700 0 : item->drawSymbol(SymId::reversedBracketTop, painter, PointF(x - item->symWidth(SymId::reversedBracketTop), data->y1));
701 : }
702 0 : if (item->isBottom()) {
703 0 : item->drawSymbol(SymId::reversedBracketBottom, painter, PointF(x - item->symWidth(SymId::reversedBracketBottom), data->y2));
704 : }
705 : } else {
706 0 : if (item->isTop()) {
707 0 : item->drawSymbol(SymId::bracketTop, painter, PointF(x, data->y1));
708 : }
709 0 : if (item->isBottom()) {
710 0 : item->drawSymbol(SymId::bracketBottom, painter, PointF(x, data->y2));
711 : }
712 : }
713 0 : }
714 :
715 30 : void TDraw::draw(const BarLine* item, Painter* painter, const PaintOptions& opt)
716 : {
717 : TRACE_DRAW_ITEM;
718 :
719 30 : const BarLine::LayoutData* data = item->ldata();
720 30 : IF_ASSERT_FAILED(data) {
721 30 : return;
722 : }
723 :
724 30 : painter->save();
725 30 : DEFER {
726 30 : painter->restore();
727 30 : };
728 :
729 30 : setMask(item, painter);
730 :
731 30 : switch (item->barLineType()) {
732 20 : case BarLineType::NORMAL: {
733 20 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
734 20 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
735 20 : painter->drawLine(LineF(lw * .5, data->y1, lw * .5, data->y2));
736 : }
737 20 : break;
738 :
739 0 : case BarLineType::BROKEN: {
740 0 : double lw = item->style().styleAbsolute(Sid::dashBarWidth) * item->mag();
741 0 : double dl = RealIsNull(lw) ? 0.0 : item->style().styleAbsolute(Sid::dashBarDash) * item->mag() / lw;
742 0 : double gl = RealIsNull(lw) ? 0.0 : item->style().styleAbsolute(Sid::dashBarGap) * item->mag() / lw;
743 0 : Pen pen(item->curColor(opt), lw, PenStyle::DashLine, PenCapStyle::FlatCap);
744 0 : pen.setDashPattern({ dl, gl });
745 0 : painter->setPen(pen);
746 0 : painter->drawLine(LineF(lw * .5, data->y1, lw * .5, data->y2));
747 0 : }
748 0 : break;
749 :
750 0 : case BarLineType::DOTTED: {
751 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
752 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::DotLine, PenCapStyle::FlatCap));
753 0 : painter->drawLine(LineF(lw * .5, data->y1, lw * .5, data->y2));
754 : }
755 0 : break;
756 :
757 10 : case BarLineType::END: {
758 10 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
759 10 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
760 10 : double x = lw * .5;
761 10 : painter->drawLine(LineF(x, data->y1, x, data->y2));
762 :
763 10 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
764 10 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
765 10 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
766 10 : painter->drawLine(LineF(x, data->y1, x, data->y2));
767 : }
768 10 : break;
769 :
770 0 : case BarLineType::DOUBLE: {
771 0 : double lw = item->style().styleAbsolute(Sid::doubleBarWidth) * item->mag();
772 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
773 0 : double x = lw * .5;
774 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
775 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::doubleBarDistance) + (lw * .5)) * item->mag();
776 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
777 : }
778 0 : break;
779 :
780 0 : case BarLineType::REVERSE_END: {
781 0 : double lw = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
782 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
783 0 : double x = lw * .5;
784 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
785 :
786 0 : double lw2 = item->style().styleAbsolute(Sid::barWidth) * item->mag();
787 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
788 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
789 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
790 : }
791 0 : break;
792 :
793 0 : case BarLineType::HEAVY: {
794 0 : double lw = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
795 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
796 0 : painter->drawLine(LineF(lw * .5, data->y1, lw * .5, data->y2));
797 : }
798 0 : break;
799 :
800 0 : case BarLineType::DOUBLE_HEAVY: {
801 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
802 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
803 0 : double x = lw2 * .5;
804 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
805 0 : x += ((lw2 * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
806 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
807 : }
808 0 : break;
809 :
810 0 : case BarLineType::START_REPEAT: {
811 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
812 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
813 0 : double x = lw2 * .5;
814 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
815 :
816 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
817 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
818 0 : x += ((lw2 * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw * .5)) * item->mag();
819 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
820 :
821 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::repeatBarlineDotSeparation)) * item->mag();
822 0 : drawDots(item, painter, x);
823 :
824 0 : if (item->style().styleB(Sid::repeatBarTips)) {
825 0 : drawTips(item, data, painter, false, 0.0);
826 : }
827 : }
828 0 : break;
829 :
830 0 : case BarLineType::END_REPEAT: {
831 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
832 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
833 :
834 0 : double x = 0.0;
835 0 : drawDots(item, painter, x);
836 :
837 0 : x += item->symBbox(SymId::repeatDot).width();
838 0 : x += (item->style().styleAbsolute(Sid::repeatBarlineDotSeparation) + (lw * .5)) * item->mag();
839 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
840 :
841 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
842 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
843 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
844 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
845 :
846 0 : if (item->style().styleB(Sid::repeatBarTips)) {
847 0 : drawTips(item, data, painter, true, x + lw2 * .5);
848 : }
849 : }
850 0 : break;
851 0 : case BarLineType::END_START_REPEAT: {
852 0 : double lw = item->style().styleAbsolute(Sid::barWidth) * item->mag();
853 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
854 :
855 0 : double x = 0.0;
856 0 : drawDots(item, painter, x);
857 :
858 0 : x += item->symBbox(SymId::repeatDot).width();
859 0 : x += (item->style().styleAbsolute(Sid::repeatBarlineDotSeparation) + (lw * .5)) * item->mag();
860 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
861 :
862 0 : double lw2 = item->style().styleAbsolute(Sid::endBarWidth) * item->mag();
863 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw2 * .5)) * item->mag();
864 0 : painter->setPen(Pen(item->curColor(opt), lw2, PenStyle::SolidLine, PenCapStyle::FlatCap));
865 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
866 :
867 0 : if (item->style().styleB(Sid::repeatBarTips)) {
868 0 : drawTips(item, data, painter, true, x + lw2 * .5);
869 : }
870 :
871 0 : painter->setPen(Pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::FlatCap));
872 0 : x += ((lw2 * .5) + item->style().styleAbsolute(Sid::endBarDistance) + (lw * .5)) * item->mag();
873 0 : painter->drawLine(LineF(x, data->y1, x, data->y2));
874 :
875 0 : x += ((lw * .5) + item->style().styleAbsolute(Sid::repeatBarlineDotSeparation)) * item->mag();
876 0 : drawDots(item, painter, x);
877 :
878 0 : if (item->style().styleB(Sid::repeatBarTips)) {
879 0 : drawTips(item, data, painter, false, 0.0);
880 : }
881 : }
882 0 : break;
883 : }
884 :
885 : // draw irregular measure mark
886 :
887 30 : if (opt.isPrinting || !item->score()->markIrregularMeasures()) {
888 30 : return;
889 : }
890 :
891 0 : const Segment* s = item->segment();
892 0 : if (s && (s->isEndBarLineType() || s->isStartRepeatBarLineType())) {
893 0 : const Measure* measure = s->measure();
894 0 : if (s->isStartRepeatBarLineType()) {
895 0 : const Measure* prevMeasure = measure ? measure->prevMeasure() : nullptr;
896 0 : if (!prevMeasure) {
897 0 : return;
898 : }
899 0 : if (const BarLine* prevEndBl = prevMeasure->endBarLine(item->staffIdx())) {
900 0 : if (prevEndBl->segment() && prevEndBl->segment()->enabled()) {
901 0 : return;
902 : }
903 : }
904 0 : measure = prevMeasure;
905 : }
906 :
907 0 : if (measure && measure->isIrregular() && !measure->isMMRest()) {
908 0 : painter->setPen(item->configuration()->invisibleColor());
909 0 : Font f(u"Edwin", Font::Type::Text);
910 0 : f.setPointSizeF(12 * item->spatium() / item->defaultSpatium());
911 0 : f.setBold(true);
912 0 : Char ch = measure->ticks() > measure->timesig() ? u'+' : u'-';
913 0 : RectF r = FontMetrics(f).boundingRect(ch);
914 :
915 0 : painter->setFont(f);
916 0 : painter->drawText(-r.width(), -item->spatium(), ch);
917 0 : }
918 : }
919 30 : }
920 :
921 0 : void TDraw::draw(const Beam* item, Painter* painter, const PaintOptions& opt)
922 : {
923 : TRACE_DRAW_ITEM;
924 0 : if (item->beamSegments().empty()) {
925 0 : return;
926 : }
927 0 : painter->setBrush(Brush(item->curColor(opt)));
928 0 : painter->setNoPen();
929 :
930 : // make beam thickness independent of slant
931 : // (expression can be simplified?)
932 :
933 0 : const LineF bs = item->beamSegments().front()->line;
934 0 : double d = (std::abs(bs.y2() - bs.y1())) / (bs.x2() - bs.x1());
935 0 : if (item->beamSegments().size() > 1 && d > M_PI / 6.0) {
936 0 : d = M_PI / 6.0;
937 : }
938 0 : double ww = (item->beamWidth() / 2.0) / sin(M_PI_2 - atan(d));
939 :
940 0 : for (const BeamSegment* bs1 : item->beamSegments()) {
941 0 : painter->drawPolygon(
942 0 : PolygonF({
943 0 : PointF(bs1->line.x1(), bs1->line.y1() - ww),
944 0 : PointF(bs1->line.x2(), bs1->line.y2() - ww),
945 0 : PointF(bs1->line.x2(), bs1->line.y2() + ww),
946 0 : PointF(bs1->line.x1(), bs1->line.y1() + ww),
947 0 : }),
948 : FillRule::OddEvenFill);
949 : }
950 : }
951 :
952 0 : void TDraw::draw(const Bend* item, Painter* painter, const PaintOptions& opt)
953 : {
954 : TRACE_DRAW_ITEM;
955 :
956 0 : const Bend::LayoutData* data = item->ldata();
957 0 : IF_ASSERT_FAILED(data) {
958 0 : return;
959 : }
960 :
961 0 : double spatium = item->spatium();
962 0 : double lw = item->absoluteFromSpatium(item->lineWidth());
963 :
964 0 : Pen pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::RoundCap, PenJoinStyle::RoundJoin);
965 0 : painter->setPen(pen);
966 0 : painter->setBrush(Brush(item->curColor(opt)));
967 :
968 0 : Font f = item->font(spatium);
969 :
970 0 : double x = data->noteWidth + spatium * .2;
971 0 : double y = -spatium * .8;
972 : double x2, y2;
973 :
974 0 : double aw = item->style().styleAbsolute(Sid::bendArrowWidth);
975 0 : PolygonF arrowUp;
976 0 : arrowUp << PointF(0, 0) << PointF(aw * .5, aw) << PointF(-aw * .5, aw);
977 0 : PolygonF arrowDown;
978 0 : arrowDown << PointF(0, 0) << PointF(aw * .5, -aw) << PointF(-aw * .5, -aw);
979 :
980 0 : size_t n = item->points().size();
981 0 : for (size_t pt = 0; pt < n - 1; ++pt) {
982 0 : int pitch = item->points()[pt].pitch;
983 0 : if (pt == 0 && pitch) {
984 0 : y2 = -data->notePos.y() - spatium * 2;
985 0 : x2 = x;
986 0 : painter->drawLine(LineF(x, y, x2, y2));
987 :
988 0 : painter->setBrush(item->curColor(opt));
989 0 : painter->drawPolygon(arrowUp.translated(x2, y2));
990 :
991 0 : int idx = (pitch + 12) / 25;
992 0 : const char* l = item->label[idx];
993 0 : painter->setFont(f);
994 0 : painter->drawText(RectF(x2, y2, .0, .0),
995 : muse::draw::AlignHCenter | muse::draw::AlignBottom,
996 : muse::draw::TextDontClip,
997 0 : String::fromAscii(l));
998 :
999 0 : y = y2;
1000 : }
1001 0 : if (pitch == item->points()[pt + 1].pitch) {
1002 0 : if (pt == (n - 2)) {
1003 0 : break;
1004 : }
1005 0 : x2 = x + spatium;
1006 0 : y2 = y;
1007 0 : painter->drawLine(LineF(x, y, x2, y2));
1008 0 : } else if (pitch < item->points()[pt + 1].pitch) {
1009 : // up
1010 0 : x2 = x + spatium * .5;
1011 0 : y2 = -data->notePos.y() - spatium * 2;
1012 0 : double dx = x2 - x;
1013 0 : double dy = y2 - y;
1014 :
1015 0 : PainterPath path;
1016 0 : path.moveTo(x, y);
1017 0 : path.cubicTo(x + dx / 2, y, x2, y + dy / 4, x2, y2);
1018 0 : painter->setBrush(BrushStyle::NoBrush);
1019 0 : painter->drawPath(path);
1020 :
1021 0 : painter->setBrush(item->curColor(opt));
1022 0 : painter->drawPolygon(arrowUp.translated(x2, y2));
1023 :
1024 0 : int idx = (item->points()[pt + 1].pitch + 12) / 25;
1025 0 : const char* l = item->label[idx];
1026 0 : double ty = y2; // - _spatium;
1027 0 : painter->setFont(f);
1028 0 : painter->drawText(RectF(x2, ty, .0, .0),
1029 : muse::draw::AlignHCenter | muse::draw::AlignBottom,
1030 : muse::draw::TextDontClip,
1031 0 : String::fromAscii(l));
1032 0 : } else {
1033 : // down
1034 0 : x2 = x + spatium * .5;
1035 0 : y2 = y + spatium * 3;
1036 0 : double dx = x2 - x;
1037 0 : double dy = y2 - y;
1038 :
1039 0 : PainterPath path;
1040 0 : path.moveTo(x, y);
1041 0 : path.cubicTo(x + dx / 2, y, x2, y + dy / 4, x2, y2);
1042 0 : painter->setBrush(BrushStyle::NoBrush);
1043 0 : painter->drawPath(path);
1044 :
1045 0 : painter->setBrush(item->curColor(opt));
1046 0 : painter->drawPolygon(arrowDown.translated(x2, y2));
1047 0 : }
1048 0 : x = x2;
1049 0 : y = y2;
1050 : }
1051 0 : }
1052 :
1053 0 : void TDraw::draw(const Box* item, Painter* painter, const PaintOptions& opt)
1054 : {
1055 : TRACE_DRAW_ITEM;
1056 0 : if (opt.isPrinting) {
1057 0 : return;
1058 : }
1059 :
1060 0 : const Box::LayoutData* ldata = item->ldata();
1061 :
1062 0 : const bool showHighlightedFrame = item->selected() || item->dropTarget();
1063 0 : const bool showFrame = showHighlightedFrame || (item->score() ? item->score()->showFrames() : false);
1064 :
1065 0 : if (showFrame) {
1066 0 : double lineWidth = item->defaultSpatium() * .10;
1067 0 : Pen pen;
1068 0 : pen.setWidthF(lineWidth);
1069 0 : pen.setJoinStyle(PenJoinStyle::RoundJoin);
1070 0 : pen.setCapStyle(PenCapStyle::RoundCap);
1071 0 : pen.setColor(showHighlightedFrame
1072 0 : ? item->configuration()->selectionColor()
1073 0 : : item->configuration()->frameColor());
1074 0 : pen.setDashPattern({ 5, 5 });
1075 :
1076 0 : painter->setBrush(BrushStyle::NoBrush);
1077 0 : painter->setPen(pen);
1078 0 : lineWidth *= 0.5;
1079 0 : painter->drawRect(ldata->bbox().adjusted(lineWidth, lineWidth, -lineWidth, -lineWidth));
1080 0 : }
1081 : }
1082 :
1083 0 : void TDraw::draw(const HBox* item, Painter* painter, const PaintOptions& opt)
1084 : {
1085 0 : draw(static_cast<const Box*>(item), painter, opt);
1086 0 : }
1087 :
1088 0 : void TDraw::draw(const VBox* item, Painter* painter, const PaintOptions& opt)
1089 : {
1090 0 : draw(static_cast<const Box*>(item), painter, opt);
1091 0 : }
1092 :
1093 0 : void TDraw::draw(const FBox* item, Painter* painter, const PaintOptions& opt)
1094 : {
1095 0 : draw(static_cast<const Box*>(item), painter, opt);
1096 0 : }
1097 :
1098 0 : void TDraw::draw(const TBox* item, Painter* painter, const PaintOptions& opt)
1099 : {
1100 0 : draw(static_cast<const Box*>(item), painter, opt);
1101 0 : }
1102 :
1103 0 : void TDraw::draw(const Bracket* item, Painter* painter, const PaintOptions& opt)
1104 : {
1105 : TRACE_DRAW_ITEM;
1106 0 : const Bracket::LayoutData* ldata = item->ldata();
1107 0 : IF_ASSERT_FAILED(ldata) {
1108 0 : return;
1109 : }
1110 :
1111 0 : switch (item->bracketType()) {
1112 0 : case BracketType::BRACE: {
1113 0 : if (ldata->braceSymbol == SymId::noSym) {
1114 0 : painter->setNoPen();
1115 0 : painter->setBrush(Brush(item->curColor(opt)));
1116 0 : painter->drawPath(ldata->path);
1117 : } else {
1118 0 : double h = ldata->bracketHeight;
1119 0 : double glyphHeight = item->symHeight(ldata->braceSymbol);
1120 0 : double mag = h / glyphHeight;
1121 0 : painter->setPen(item->curColor(opt));
1122 0 : painter->save();
1123 0 : painter->scale(item->magx(), mag);
1124 0 : item->drawSymbol(ldata->braceSymbol, painter, PointF(0.0, glyphHeight));
1125 0 : painter->restore();
1126 : }
1127 : }
1128 0 : break;
1129 0 : case BracketType::NORMAL: {
1130 0 : double h = ldata->bracketHeight;
1131 0 : double spatium = item->spatium();
1132 0 : double w = item->style().styleAbsolute(Sid::bracketWidth);
1133 0 : double bd = (item->style().styleSt(Sid::musicalSymbolFont) == "Leland") ? spatium * .5 : spatium * .25;
1134 0 : Pen pen(item->curColor(opt), w, PenStyle::SolidLine, PenCapStyle::FlatCap);
1135 0 : painter->setPen(pen);
1136 0 : painter->drawLine(LineF(0.0, -bd - w * .5, 0.0, h + bd + w * .5));
1137 0 : double x = -w * .5;
1138 0 : double y1 = -bd;
1139 0 : double y2 = h + bd;
1140 0 : item->drawSymbol(SymId::bracketTop, painter, PointF(x, y1));
1141 0 : item->drawSymbol(SymId::bracketBottom, painter, PointF(x, y2));
1142 0 : }
1143 0 : break;
1144 0 : case BracketType::SQUARE:
1145 : {
1146 0 : double h = ldata->bracketHeight;
1147 0 : double lineW = item->style().styleAbsolute(Sid::staffLineWidth);
1148 0 : double bracketWidth = ldata->bracketWidth - lineW / 2;
1149 0 : Pen pen(item->curColor(opt), lineW, PenStyle::SolidLine, PenCapStyle::FlatCap);
1150 0 : painter->setPen(pen);
1151 0 : painter->drawLine(LineF(0.0, 0.0, 0.0, h));
1152 0 : painter->drawLine(LineF(-lineW / 2, 0.0, lineW / 2 + bracketWidth, 0.0));
1153 0 : painter->drawLine(LineF(-lineW / 2, h, lineW / 2 + bracketWidth, h));
1154 0 : }
1155 0 : break;
1156 0 : case BracketType::LINE: {
1157 0 : double h = ldata->bracketHeight;
1158 0 : double w = 0.67 * item->style().styleAbsolute(Sid::bracketWidth);
1159 0 : Pen pen(item->curColor(opt), w, PenStyle::SolidLine, PenCapStyle::FlatCap);
1160 0 : painter->setPen(pen);
1161 0 : double bd = item->style().styleAbsolute(Sid::staffLineWidth) * 0.5;
1162 0 : painter->drawLine(LineF(0.0, -bd, 0.0, h + bd));
1163 0 : }
1164 0 : break;
1165 0 : case BracketType::GROUP:
1166 : {
1167 0 : if (!item->bracketItem()->showBracket() && (!item->score()->isShowInvisible() || opt.isPrinting)) {
1168 0 : return;
1169 : }
1170 :
1171 0 : painter->save();
1172 0 : setMask(item, painter);
1173 :
1174 0 : double h = ldata->bracketHeight;
1175 0 : double lineW = item->style().styleAbsolute(Sid::groupBracketLineWidth);
1176 0 : double hookLen = item->style().styleAbsolute(Sid::groupBracketHookLen);
1177 0 : Color color = item->curColor(item->visible() && item->bracketItem()->showBracket(), opt);
1178 0 : Pen pen(color, lineW, PenStyle::SolidLine, PenCapStyle::FlatCap);
1179 0 : painter->setPen(pen);
1180 0 : painter->drawLine(LineF(0.5 * lineW, 0.0, 0.5 * lineW, h));
1181 0 : painter->drawLine(LineF(0.0, 0.0, hookLen, 0.0));
1182 0 : painter->drawLine(LineF(0.0, h, hookLen, h));
1183 :
1184 0 : painter->restore();
1185 0 : }
1186 0 : break;
1187 0 : case BracketType::NO_BRACKET:
1188 0 : break;
1189 : }
1190 : }
1191 :
1192 0 : void TDraw::draw(const Breath* item, Painter* painter, const PaintOptions& opt)
1193 : {
1194 : TRACE_DRAW_ITEM;
1195 0 : painter->setPen(item->curColor(opt));
1196 0 : item->drawSymbol(item->symId(), painter);
1197 0 : }
1198 :
1199 0 : void TDraw::draw(const ChordLine* item, Painter* painter, const PaintOptions& opt)
1200 : {
1201 : TRACE_DRAW_ITEM;
1202 0 : const ChordLine::LayoutData* ldata = item->ldata();
1203 0 : IF_ASSERT_FAILED(ldata) {
1204 0 : return;
1205 : }
1206 :
1207 0 : painter->setPen(Pen(item->curColor(opt), item->style().styleAbsolute(Sid::chordlineThickness) * item->mag(), PenStyle::SolidLine));
1208 0 : painter->setBrush(BrushStyle::NoBrush);
1209 0 : if (!item->isWavy()) {
1210 0 : painter->drawPath(ldata->path);
1211 : } else {
1212 0 : painter->save();
1213 0 : painter->rotate((item->chordLineType() == ChordLineType::FALL ? 1 : -1));
1214 0 : item->drawSymbol(item->waveSym(), painter);
1215 0 : painter->restore();
1216 : }
1217 : }
1218 :
1219 10 : void TDraw::draw(const Clef* item, Painter* painter, const PaintOptions& opt)
1220 : {
1221 : TRACE_DRAW_ITEM;
1222 10 : const Clef::LayoutData* ldata = item->ldata();
1223 10 : IF_ASSERT_FAILED(ldata) {
1224 0 : return;
1225 : }
1226 :
1227 10 : if (ldata->symId == SymId::noSym || (item->staff() && !const_cast<const Staff*>(item->staff())->staffType(item->tick())->genClef())) {
1228 0 : return;
1229 : }
1230 :
1231 10 : painter->setPen(item->curColor(opt));
1232 10 : item->drawSymbol(ldata->symId, painter);
1233 : }
1234 :
1235 0 : void TDraw::draw(const Capo* item, Painter* painter, const PaintOptions& opt)
1236 : {
1237 0 : drawTextBase(item, painter, opt);
1238 0 : }
1239 :
1240 0 : void TDraw::draw(const DeadSlapped* item, Painter* painter, const PaintOptions& opt)
1241 : {
1242 : TRACE_DRAW_ITEM;
1243 0 : const DeadSlapped::LayoutData* ldata = item->ldata();
1244 0 : IF_ASSERT_FAILED(ldata) {
1245 0 : return;
1246 : }
1247 :
1248 0 : painter->setPen(PenStyle::NoPen);
1249 0 : painter->setBrush(item->curColor(opt));
1250 0 : painter->drawPath(ldata->path1);
1251 0 : painter->drawPath(ldata->path2);
1252 : }
1253 :
1254 0 : void TDraw::draw(const Dynamic* item, Painter* painter, const PaintOptions& opt)
1255 : {
1256 0 : drawTextBase(item, painter, opt);
1257 0 : }
1258 :
1259 0 : void TDraw::draw(const Expression* item, Painter* painter, const PaintOptions& opt)
1260 : {
1261 0 : drawTextBase(item, painter, opt);
1262 0 : }
1263 :
1264 0 : void TDraw::draw(const Fermata* item, Painter* painter, const PaintOptions& opt)
1265 : {
1266 : TRACE_DRAW_ITEM;
1267 0 : painter->setPen(item->curColor(opt));
1268 0 : item->drawSymbol(item->symId(), painter);
1269 0 : }
1270 :
1271 0 : void TDraw::draw(const FiguredBass* item, Painter* painter, const PaintOptions& opt)
1272 : {
1273 : TRACE_DRAW_ITEM;
1274 0 : const FiguredBass::LayoutData* ldata = item->ldata();
1275 : // if not printing, draw duration line(s)
1276 0 : if (!opt.isPrinting && item->score()->showUnprintable()) {
1277 0 : for (double len : ldata->lineLengths) {
1278 0 : if (len > 0) {
1279 0 : painter->setPen(Pen(item->configuration()->invisibleColor(), 3));
1280 0 : painter->drawLine(0.0, -2, len, -2); // -2: 2 rast. un. above digits
1281 : }
1282 : }
1283 : }
1284 :
1285 0 : if (item->items().size() < 1) { // if not parseable into f.b. items
1286 0 : drawTextBase(item, painter, opt); // draw as standard text
1287 : } else {
1288 0 : for (FiguredBassItem* fi : item->items()) { // if parseable into f.b. items
1289 0 : painter->translate(fi->pos()); // draw each item in its proper position
1290 0 : draw(fi, painter, opt);
1291 0 : painter->translate(-fi->pos());
1292 : }
1293 : }
1294 0 : }
1295 :
1296 0 : void TDraw::draw(const FiguredBassItem* item, Painter* painter, const PaintOptions& opt)
1297 : {
1298 : TRACE_DRAW_ITEM;
1299 :
1300 0 : const FiguredBassItem::LayoutData* ldata = item->ldata();
1301 0 : int font = 0;
1302 0 : double _spatium = item->spatium();
1303 : // set font from general style
1304 0 : Font f(FiguredBass::FBFonts().at(font).family, Font::Type::Tablature);
1305 :
1306 : // (use the same font selection as used in layout() above)
1307 0 : double m = item->style().styleD(Sid::figuredBassFontSize) * item->spatium() / item->defaultSpatium();
1308 0 : f.setPointSizeF(m);
1309 :
1310 0 : painter->setFont(f);
1311 0 : painter->setBrush(BrushStyle::NoBrush);
1312 0 : Pen pen(item->figuredBass()->curColor(opt), FiguredBass::FB_CONTLINE_THICKNESS.toAbsolute(_spatium), PenStyle::SolidLine,
1313 0 : PenCapStyle::RoundCap);
1314 0 : painter->setPen(pen);
1315 0 : painter->drawText(ldata->bbox(),
1316 : muse::draw::AlignLeft | muse::draw::AlignTop,
1317 : muse::draw::TextDontClip,
1318 0 : ldata->displayText);
1319 :
1320 : // continuation line
1321 0 : double lineEndX = 0.0;
1322 0 : if (item->contLine() != FiguredBassItem::ContLine::NONE) {
1323 0 : double lineStartX = ldata->textWidth; // by default, line starts right after text
1324 0 : if (lineStartX > 0.0) {
1325 0 : lineStartX += FiguredBass::FB_CONTLINE_LEFT_PADDING.toAbsolute(_spatium); // if some text, give some room after it
1326 : }
1327 0 : lineEndX = item->figuredBass()->ldata()->printedLineLength; // by default, line ends with item duration
1328 0 : if (lineEndX - lineStartX < 1.0) { // if line length < 1 sp, ignore it
1329 0 : lineEndX = 0.0;
1330 : }
1331 :
1332 : // if extended cont.line and no closing parenthesis: look at next FB element
1333 0 : if (item->contLine() > FiguredBassItem::ContLine::SIMPLE && item->parenth5() == FiguredBassItem::Parenthesis::NONE) {
1334 : FiguredBass* nextFB;
1335 : // if there is a contiguous FB element
1336 0 : if ((nextFB = item->figuredBass()->nextFiguredBass()) != 0) {
1337 : // retrieve the X position (in page coords) of a possible cont. line of nextFB
1338 : // on the same line of 'this'
1339 0 : PointF pgPos = item->pagePos();
1340 0 : double nextContPageX = nextFB->additionalContLineX(pgPos.y());
1341 : // if an additional cont. line has been found, extend up to its initial X coord
1342 0 : if (nextContPageX > 0) {
1343 0 : lineEndX = nextContPageX - pgPos.x() + FiguredBass::FB_CONTLINE_OVERLAP.toAbsolute(_spatium);
1344 : }
1345 : // with a little bit of overlap
1346 : else {
1347 0 : lineEndX = item->figuredBass()->ldata()->lineLength(0); // if none found, draw to the duration end
1348 : }
1349 : }
1350 : }
1351 : // if some line, draw it
1352 0 : if (lineEndX > 0.0) {
1353 0 : double h = ldata->bbox().height() * FiguredBass::FB_CONTLINE_HEIGHT;
1354 0 : painter->drawLine(lineStartX, h, lineEndX - ldata->pos().x(), h);
1355 : }
1356 : }
1357 :
1358 : // closing cont.line parenthesis
1359 0 : if (item->parenth5() != FiguredBassItem::Parenthesis::NONE) {
1360 0 : int x = lineEndX > 0.0 ? lineEndX : ldata->textWidth;
1361 0 : painter->drawText(RectF(x, 0, ldata->bbox().width(), ldata->bbox().height()),
1362 : muse::draw::AlignLeft | muse::draw::AlignTop,
1363 : muse::draw::TextDontClip,
1364 0 : Char(FiguredBass::FBFonts().at(font).displayParenthesis[int(item->parenth5())].unicode()));
1365 : }
1366 0 : }
1367 :
1368 0 : void TDraw::draw(const Fingering* item, Painter* painter, const PaintOptions& opt)
1369 : {
1370 : TRACE_DRAW_ITEM;
1371 0 : drawTextBase(item, painter, opt);
1372 0 : }
1373 :
1374 0 : void TDraw::draw(const FretDiagram* item, Painter* painter, const PaintOptions& opt)
1375 : {
1376 : TRACE_DRAW_ITEM;
1377 0 : const FretDiagram::LayoutData* ldata = item->ldata();
1378 0 : PointF translation = -PointF(ldata->stringDist * (item->strings() - 1), 0);
1379 0 : if (item->orientation() == Orientation::HORIZONTAL) {
1380 0 : painter->save();
1381 0 : painter->rotate(-90);
1382 0 : painter->translate(translation);
1383 : }
1384 :
1385 : // Init pen and other values
1386 0 : Pen pen(item->curColor(opt));
1387 0 : pen.setCapStyle(PenCapStyle::FlatCap);
1388 0 : painter->setBrush(Brush(Color(painter->pen().color())));
1389 :
1390 : // x2 is the x val of the rightmost string
1391 0 : double x2 = (item->strings() - 1) * ldata->stringDist;
1392 :
1393 : // Draw the nut
1394 0 : pen.setWidthF(ldata->nutLineWidth);
1395 0 : painter->setPen(pen);
1396 0 : double nutY = ldata->nutY;
1397 0 : painter->drawLine(LineF(-ldata->stringLineWidth * .5, nutY, x2 + ldata->stringLineWidth * .5, nutY));
1398 :
1399 : // Draw strings and frets
1400 0 : pen.setWidthF(ldata->stringLineWidth);
1401 0 : painter->setPen(pen);
1402 :
1403 : // y2 is the y val of the bottom fretline
1404 0 : double y1 = ldata->stringExtendTop;
1405 0 : double y2 = ldata->fretDist * item->frets() + 0.5 * ldata->stringLineWidth + ldata->stringExtendBottom;
1406 0 : for (int i = 0; i < item->strings(); ++i) {
1407 0 : double x = ldata->stringDist * i;
1408 0 : painter->drawLine(LineF(x, y1, x, y2));
1409 : }
1410 0 : for (int i = 1; i <= item->frets(); ++i) {
1411 0 : double y = ldata->fretDist * i;
1412 0 : painter->drawLine(LineF(0.0, y, x2, y));
1413 : }
1414 :
1415 : // dotd is the diameter of a dot
1416 0 : double dotd = ldata->dotDiameter;
1417 :
1418 : // Draw dots, sym pen is used to draw them (and markers)
1419 0 : Pen symPen(pen);
1420 0 : symPen.setCapStyle(PenCapStyle::FlatCap);
1421 : // Raise the miter limit so the triangle's apex isn't bevelled (needs ~2.24)
1422 0 : symPen.setJoinStyle(PenJoinStyle::MiterJoin);
1423 0 : symPen.setMiterLimit(3.0);
1424 0 : double symPenWidth = ldata->stringLineWidth * 1.2;
1425 0 : symPen.setWidthF(symPenWidth);
1426 :
1427 0 : for (auto const& i : item->dots()) {
1428 0 : for (auto const& d : i.second) {
1429 0 : if (!d.exists()) {
1430 0 : continue;
1431 : }
1432 :
1433 0 : int string = i.first;
1434 0 : int fret = d.fret - 1;
1435 :
1436 : // Calculate coords of the top left corner of the dot
1437 0 : double x = ldata->stringDist * string - dotd * .5;
1438 0 : double y = ldata->fretDist * fret + ldata->fretDist * .5 - dotd * .5;
1439 :
1440 : // Draw different symbols
1441 0 : painter->setPen(symPen);
1442 0 : switch (d.dtype) {
1443 0 : case FretDotType::CROSS:
1444 : // Give the cross a slightly larger width
1445 0 : symPen.setWidthF(symPenWidth * 1.5);
1446 0 : painter->setPen(symPen);
1447 0 : painter->drawLine(LineF(x, y, x + dotd, y + dotd));
1448 0 : painter->drawLine(LineF(x + dotd, y, x, y + dotd));
1449 0 : symPen.setWidthF(symPenWidth);
1450 0 : break;
1451 0 : case FretDotType::SQUARE:
1452 0 : painter->setBrush(BrushStyle::NoBrush);
1453 0 : painter->drawRect(RectF(x, y, dotd, dotd));
1454 0 : break;
1455 0 : case FretDotType::TRIANGLE:
1456 0 : painter->setBrush(BrushStyle::NoBrush);
1457 0 : painter->drawPolygon(PolygonF({ PointF(x, y + dotd), PointF(x + .5 * dotd, y), PointF(x + dotd, y + dotd) }));
1458 0 : break;
1459 0 : case FretDotType::NORMAL:
1460 : default:
1461 0 : painter->setBrush(symPen.color());
1462 0 : painter->setNoPen();
1463 0 : painter->drawEllipse(RectF(x, y, dotd, dotd));
1464 0 : break;
1465 : }
1466 : }
1467 : }
1468 :
1469 : // Draw markers
1470 0 : symPen.setWidthF(ldata->stringLineWidth * 1.2);
1471 0 : painter->setBrush(BrushStyle::NoBrush);
1472 0 : painter->setPen(symPen);
1473 0 : for (auto const& i : item->markers()) {
1474 0 : int string = i.first;
1475 0 : FretItem::Marker marker = i.second;
1476 0 : if (!marker.exists()) {
1477 0 : continue;
1478 : }
1479 :
1480 0 : double x = ldata->stringDist * string - ldata->markerSize * .5;
1481 0 : double y = ldata->markerY;
1482 0 : if (marker.mtype == FretMarkerType::CIRCLE) {
1483 0 : painter->drawEllipse(RectF(x, y, ldata->markerSize, ldata->markerSize));
1484 0 : } else if (marker.mtype == FretMarkerType::CROSS) {
1485 0 : painter->drawLine(PointF(x, y), PointF(x + ldata->markerSize, y + ldata->markerSize));
1486 0 : painter->drawLine(PointF(x, y + ldata->markerSize), PointF(x + ldata->markerSize, y));
1487 : }
1488 : }
1489 :
1490 : // Draw barres
1491 0 : for (auto const& i : item->barres()) {
1492 0 : int fret = i.first;
1493 0 : int startString = i.second.startString;
1494 0 : int endString = i.second.endString;
1495 :
1496 0 : double x1 = ldata->stringDist * startString;
1497 0 : double newX2 = endString == -1 ? x2 : ldata->stringDist * endString;
1498 0 : double y = ldata->fretDist * (fret - 1) + ldata->fretDist * .5;
1499 0 : if (item->style().styleB(Sid::barreAppearanceSlur)) {
1500 0 : pen.setWidthF(0.25 * ldata->stringLineWidth);
1501 0 : pen.setCapStyle(PenCapStyle::RoundCap);
1502 0 : pen.setJoinStyle(PenJoinStyle::RoundJoin);
1503 0 : painter->setPen(pen);
1504 0 : painter->setBrush(Brush(pen.color()));
1505 0 : for (const PainterPath& path : ldata->slurPaths) {
1506 0 : painter->drawPath(path);
1507 : }
1508 : } else {
1509 0 : pen.setWidthF(dotd * item->style().styleD(Sid::barreLineWidth));
1510 0 : pen.setCapStyle(PenCapStyle::RoundCap);
1511 0 : painter->setPen(pen);
1512 0 : painter->drawLine(LineF(x1, y, newX2, y));
1513 : }
1514 : }
1515 :
1516 : // Draw fret offset number
1517 0 : if (item->fretOffset() > 0) {
1518 0 : Font scaledFont(item->fretNumFont());
1519 0 : scaledFont.setPointSizeF(scaledFont.pointSizeF() * (item->spatium() / item->defaultSpatium()));
1520 0 : painter->setFont(scaledFont);
1521 0 : String text = ldata->fretText;
1522 :
1523 0 : if (item->orientation() == Orientation::VERTICAL) {
1524 0 : if (item->numPos() == 0) {
1525 0 : painter->drawText(RectF(-ldata->fretNumPadding, .0, .0, ldata->fretDist),
1526 : muse::draw::AlignVCenter | muse::draw::AlignRight,
1527 : muse::draw::TextDontClip,
1528 : text);
1529 : } else {
1530 0 : painter->drawText(RectF(x2 + ldata->fretNumPadding, .0, .0, ldata->fretDist),
1531 : muse::draw::AlignVCenter | muse::draw::AlignLeft,
1532 : muse::draw::TextDontClip,
1533 : text);
1534 : }
1535 0 : } else if (item->orientation() == Orientation::HORIZONTAL) {
1536 0 : painter->save();
1537 0 : painter->translate(-translation);
1538 0 : painter->rotate(90);
1539 0 : if (item->numPos() == 0) {
1540 0 : painter->drawText(RectF(.0, ldata->stringDist * (item->strings() - 1), .0, .0),
1541 : muse::draw::AlignLeft,
1542 : muse::draw::TextDontClip,
1543 : text);
1544 : } else {
1545 0 : painter->drawText(RectF(.0, .0, .0, .0),
1546 : muse::draw::AlignBottom | muse::draw::AlignLeft,
1547 : muse::draw::TextDontClip,
1548 : text);
1549 : }
1550 0 : painter->restore();
1551 : }
1552 0 : painter->setFont(item->fretNumFont());
1553 0 : }
1554 :
1555 0 : for (const FretDiagram::FingeringItem& fingeringItem : item->ldata()->fingeringItems) {
1556 0 : painter->save();
1557 :
1558 0 : Font scaledFont(item->fingeringFont());
1559 0 : scaledFont.setPointSizeF(scaledFont.pointSizeF() * (item->spatium() / item->defaultSpatium()));
1560 0 : painter->setFont(scaledFont);
1561 0 : if (item->orientation() == Orientation::HORIZONTAL) {
1562 0 : painter->translate(-translation);
1563 0 : painter->rotate(90);
1564 : }
1565 :
1566 0 : painter->drawText(fingeringItem.pos, fingeringItem.fingerNumber);
1567 :
1568 0 : painter->restore();
1569 0 : }
1570 :
1571 0 : if (item->orientation() == Orientation::HORIZONTAL) {
1572 0 : painter->restore();
1573 : }
1574 0 : }
1575 :
1576 0 : static void setDashAndGapLen(const SLine* line, double& dash, double& gap, Pen& pen)
1577 : {
1578 : static constexpr double DOTTED_DASH_LEN = 0.01;
1579 : static constexpr double DOTTED_GAP_LEN = 1.99;
1580 0 : switch (line->lineStyle()) {
1581 0 : case LineType::SOLID:
1582 0 : break;
1583 0 : case LineType::DASHED:
1584 0 : dash = line->dashLineLen(), gap = line->dashGapLen();
1585 0 : break;
1586 0 : case LineType::DOTTED:
1587 0 : dash = DOTTED_DASH_LEN, gap = DOTTED_GAP_LEN;
1588 0 : pen.setCapStyle(PenCapStyle::RoundCap); // round dots
1589 0 : break;
1590 : }
1591 0 : }
1592 :
1593 0 : static std::vector<double> distributedDashPattern(double dash, double gap, double lineLength)
1594 : {
1595 0 : int numPairs = std::max(1.0, lineLength / (dash + gap));
1596 0 : double newGap = (lineLength - dash * (numPairs + 1)) / numPairs;
1597 :
1598 0 : return { dash, newGap };
1599 : }
1600 :
1601 0 : void TDraw::draw(const GlissandoSegment* item, Painter* painter, const PaintOptions& opt)
1602 : {
1603 : TRACE_DRAW_ITEM;
1604 :
1605 0 : if (item->pos2().x() <= 0) {
1606 0 : return;
1607 : }
1608 :
1609 0 : painter->save();
1610 0 : double _spatium = item->spatium();
1611 0 : const Glissando* glissando = item->glissando();
1612 :
1613 0 : Pen pen(item->curColor(item->getProperty(Pid::VISIBLE).toBool(), item->getProperty(Pid::COLOR).value<Color>(), opt));
1614 0 : pen.setWidthF(item->absoluteFromSpatium(item->lineWidth()));
1615 0 : pen.setCapStyle(PenCapStyle::FlatCap);
1616 0 : painter->setPen(pen);
1617 :
1618 : // rotate painter so that the line become horizontal
1619 0 : double w = item->pos2().x();
1620 0 : double h = item->pos2().y();
1621 0 : double l = sqrt(w * w + h * h);
1622 0 : double wi = asin(-h / l) * 180.0 / M_PI;
1623 0 : painter->rotate(-wi);
1624 :
1625 0 : if (glissando->glissandoType() == GlissandoType::STRAIGHT) {
1626 0 : const bool isNonSolid = glissando->lineStyle() != LineType::SOLID;
1627 0 : if (isNonSolid) {
1628 0 : double lineWidth = glissando->absoluteFromSpatium(glissando->lineWidth());
1629 0 : double dash = 0;
1630 0 : double gap = 0;
1631 0 : setDashAndGapLen(glissando, dash, gap, pen);
1632 0 : pen.setDashPattern(distributedDashPattern(dash, gap, l / lineWidth));
1633 0 : painter->setPen(pen);
1634 : }
1635 :
1636 0 : painter->drawLine(LineF(0.0, 0.0, l, 0.0));
1637 0 : } else if (glissando->glissandoType() == GlissandoType::WAVY) {
1638 0 : RectF b = item->symBbox(SymId::wiggleGlissando);
1639 0 : double a = item->symAdvance(SymId::wiggleGlissando);
1640 0 : int n = static_cast<int>(l / a); // always round down (truncate) to avoid overlap
1641 0 : double x = (l - n * a) * 0.5; // centre line in available space
1642 0 : SymIdList ids;
1643 0 : for (int i = 0; i < n; ++i) {
1644 0 : ids.push_back(SymId::wiggleGlissando);
1645 : }
1646 :
1647 0 : item->score()->engravingFont()->draw(ids, painter, item->magS(), PointF(x, -(b.y() + b.height() * 0.5)));
1648 0 : }
1649 :
1650 0 : if (glissando->showText()) {
1651 0 : Font f(glissando->fontFace(), Font::Type::Unknown);
1652 0 : f.setPointSizeF(glissando->fontSize() * _spatium / item->defaultSpatium());
1653 0 : f.setBold(glissando->fontStyle() & FontStyle::Bold);
1654 0 : f.setItalic(glissando->fontStyle() & FontStyle::Italic);
1655 0 : f.setUnderline(glissando->fontStyle() & FontStyle::Underline);
1656 0 : f.setStrike(glissando->fontStyle() & FontStyle::Strike);
1657 0 : FontMetrics fm(f);
1658 0 : RectF r = fm.boundingRect(glissando->text());
1659 :
1660 : // if text longer than available space, skip it
1661 0 : if (r.width() < l) {
1662 0 : double x = (l - r.width()) * 0.5;
1663 0 : double yOffset = r.height() + r.y(); // find text descender height
1664 : // raise text slightly above line and slightly more with WAVY than with STRAIGHT
1665 0 : yOffset += _spatium * (glissando->glissandoType() == GlissandoType::WAVY ? 0.4 : 0.1);
1666 :
1667 0 : painter->setFont(f);
1668 0 : painter->drawText(PointF(x, -yOffset), glissando->text());
1669 : }
1670 0 : }
1671 0 : painter->restore();
1672 0 : }
1673 :
1674 0 : void TDraw::draw(const GuitarBendSegment* item, Painter* painter, const PaintOptions& opt)
1675 : {
1676 : TRACE_DRAW_ITEM;
1677 :
1678 0 : bool tabStaff = item->staff()->isTabStaff(item->tick());
1679 0 : GuitarBend* bend = item->guitarBend();
1680 :
1681 0 : Pen pen(item->curColor(opt));
1682 0 : if (bend->bendType() == GuitarBendType::SCOOP) {
1683 0 : painter->setPen(pen);
1684 0 : item->drawSymbol(SymId::guitarVibratoBarScoop, painter);
1685 0 : return;
1686 : }
1687 :
1688 0 : pen.setWidthF(item->lineWidth());
1689 0 : pen.setCapStyle(PenCapStyle::FlatCap);
1690 0 : pen.setJoinStyle(bend->bendType() == GuitarBendType::DIP ? PenJoinStyle::BevelJoin : PenJoinStyle::MiterJoin);
1691 0 : pen.setColor(item->curColor(opt));
1692 0 : if (tabStaff && bend->bendType() == GuitarBendType::PRE_DIVE) {
1693 0 : const PainterPath& path = item->ldata()->path();
1694 0 : if (path.elementCount() > 1) {
1695 0 : double lineLength = std::abs(item->ldata()->path().elementAt(1).y);
1696 0 : pen.setDashPattern(distributedDashPattern(3, 3, lineLength / pen.widthF()));
1697 : } else {
1698 0 : pen.setDashPattern({ 3, 3 });
1699 : }
1700 : }
1701 0 : painter->setPen(pen);
1702 :
1703 0 : Brush brush;
1704 0 : brush.setStyle(BrushStyle::NoBrush);
1705 0 : painter->setBrush(brush);
1706 :
1707 0 : painter->drawPath(item->ldata()->path());
1708 :
1709 0 : if (tabStaff) {
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(item->ldata()->arrow());
1715 : }
1716 0 : }
1717 :
1718 0 : void TDraw::draw(const GuitarBendHoldSegment* item, Painter* painter, const PaintOptions& opt)
1719 : {
1720 : TRACE_DRAW_ITEM;
1721 :
1722 0 : Pen pen(item->curColor(item->visible(), opt));
1723 0 : if (!item->ldata()->symIds().empty()) {
1724 0 : painter->setPen(pen);
1725 0 : item->drawSymbols(item->ldata()->symIds(), painter);
1726 0 : return;
1727 : }
1728 :
1729 0 : pen.setWidthF(item->lineWidth());
1730 0 : pen.setCapStyle(PenCapStyle::FlatCap);
1731 :
1732 0 : switch (item->getProperty(Pid::LINE_STYLE).value<LineType>()) {
1733 0 : case LineType::DASHED:
1734 : {
1735 0 : double dash = item->dashLength();
1736 0 : pen.setDashPattern(distributedDashPattern(dash, dash, item->pos2().x() / pen.widthF()));
1737 0 : break;
1738 : }
1739 0 : case LineType::DOTTED:
1740 0 : pen.setCapStyle(PenCapStyle::RoundCap); // True dots
1741 0 : pen.setDashPattern({ 0.01, 1.99 });
1742 0 : break;
1743 0 : default:
1744 0 : break;
1745 : }
1746 :
1747 0 : pen.setJoinStyle(PenJoinStyle::MiterJoin);
1748 0 : painter->setPen(pen);
1749 :
1750 0 : painter->drawLine(PointF(), item->pos2());
1751 0 : }
1752 :
1753 0 : void TDraw::drawTextBase(const TextBase* item, Painter* painter, const PaintOptions& opt)
1754 : {
1755 : TRACE_DRAW_ITEM;
1756 :
1757 0 : painter->save();
1758 0 : painter->rotate(item->textAngle());
1759 :
1760 0 : const TextBase::LayoutData* ldata = item->ldata();
1761 0 : if (item->hasFrame()) {
1762 0 : double baseSpatium = DefaultStyle::baseStyle().value(Sid::spatium).toReal();
1763 0 : if (!RealIsNull(item->frameWidth().val())) {
1764 0 : Color fColor = item->curColor(item->visible(), item->frameColor(), opt);
1765 0 : double frameWidthVal = item->frameWidth().val() * (item->sizeIsSpatiumDependent() ? item->spatium() : baseSpatium);
1766 :
1767 0 : Pen pen(fColor, frameWidthVal, PenStyle::SolidLine, PenCapStyle::SquareCap, PenJoinStyle::MiterJoin);
1768 0 : painter->setPen(pen);
1769 0 : } else {
1770 0 : painter->setNoPen();
1771 : }
1772 0 : Color bg(item->bgColor());
1773 0 : painter->setBrush(bg.alpha() ? Brush(bg) : BrushStyle::NoBrush);
1774 0 : if (item->circle()) {
1775 0 : painter->drawEllipse(ldata->frame);
1776 : } else {
1777 0 : double frameRadius = item->frameRound().val() * (item->sizeIsSpatiumDependent() ? item->spatium() : baseSpatium);
1778 0 : painter->drawRoundedRect(ldata->frame, frameRadius, frameRadius);
1779 : }
1780 : }
1781 0 : painter->setBrush(BrushStyle::NoBrush);
1782 0 : painter->setPen(item->textColor(opt));
1783 0 : for (const TextBlock& t : ldata->blocks) {
1784 0 : draw(t, item, painter);
1785 : }
1786 :
1787 0 : painter->restore();
1788 0 : }
1789 :
1790 0 : void TDraw::draw(const TextBlock& textBlock, const TextBase* item, Painter* painter)
1791 : {
1792 0 : painter->translate(0.0, textBlock.y());
1793 0 : for (const TextFragment& f : textBlock.fragments()) {
1794 0 : draw(f, item, painter);
1795 : }
1796 0 : painter->translate(0.0, -textBlock.y());
1797 0 : }
1798 :
1799 0 : void TDraw::draw(const TextFragment& textFragment, const TextBase* item, muse::draw::Painter* painter)
1800 : {
1801 0 : painter->setFont(textFragment.font(item));
1802 0 : painter->drawText(textFragment.pos, textFragment.text);
1803 0 : }
1804 :
1805 0 : void TDraw::drawTextLineBaseSegment(const TextLineBaseSegment* item, Painter* painter, const PaintOptions& opt)
1806 : {
1807 0 : const TextLineBase* tl = item->textLineBase();
1808 0 : const TextLineBaseSegment::LayoutData* ldata = item->ldata();
1809 :
1810 0 : if (!item->text()->empty()) {
1811 0 : painter->translate(item->text()->pos());
1812 0 : item->text()->setVisible(tl->visible());
1813 0 : draw(item->text(), painter, opt);
1814 0 : painter->translate(-item->text()->pos());
1815 : }
1816 :
1817 0 : if (!item->endText()->empty()) {
1818 0 : painter->translate(item->endText()->pos());
1819 0 : item->endText()->setVisible(tl->visible());
1820 0 : draw(item->endText(), painter, opt);
1821 0 : painter->translate(-item->endText()->pos());
1822 : }
1823 :
1824 0 : if (ldata->npoints == 0
1825 0 : || ((opt.isPrinting || (item->score() && !item->score()->isShowInvisible()))
1826 0 : && !tl->lineVisible())) {
1827 0 : return;
1828 : }
1829 :
1830 : // color for line (text color comes from the text properties)
1831 0 : Color color = item->curColor(tl->visible() && tl->lineVisible(), tl->lineColor(), opt);
1832 :
1833 0 : double lineWidth = tl->absoluteFromSpatium(tl->lineWidth());
1834 :
1835 0 : const Pen solidPen(color, lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap, PenJoinStyle::MiterJoin);
1836 0 : Pen pen(solidPen);
1837 :
1838 0 : double dash = 0;
1839 0 : double gap = 0;
1840 :
1841 0 : setDashAndGapLen(tl, dash, gap, pen);
1842 :
1843 0 : const bool isNonSolid = tl->lineStyle() != LineType::SOLID;
1844 :
1845 : // Draw lines
1846 0 : if (item->twoLines()) { // hairpins
1847 0 : if (isNonSolid) {
1848 0 : pen.setDashPattern({ dash, gap });
1849 : }
1850 :
1851 0 : pen.setJoinStyle(PenJoinStyle::BevelJoin);
1852 0 : painter->setPen(pen);
1853 0 : if (!ldata->joinedHairpin.empty() && !isNonSolid) {
1854 0 : painter->drawPolyline(ldata->joinedHairpin);
1855 : } else {
1856 0 : painter->drawLines(&ldata->points[0], 2);
1857 : }
1858 0 : return;
1859 : }
1860 :
1861 0 : int start = 0, end = ldata->npoints;
1862 :
1863 : // Draw begin hook, if it needs to be drawn separately
1864 0 : if (item->isSingleBeginType() && tl->beginHookType() != HookType::NONE) {
1865 0 : if (tl->beginHookType() == HookType::ARROW_FILLED) {
1866 0 : Brush brush;
1867 0 : brush.setStyle(BrushStyle::SolidPattern);
1868 0 : brush.setColor(color);
1869 0 : painter->setBrush(brush);
1870 0 : painter->setNoPen();
1871 0 : painter->drawPolygon(ldata->beginArrow);
1872 0 : } else if (tl->beginHookType() == HookType::ARROW) {
1873 0 : pen.setJoinStyle(PenJoinStyle::MiterJoin);
1874 0 : painter->setPen(pen);
1875 0 : painter->drawPolyline(ldata->beginArrow);
1876 : } else {
1877 0 : bool isTHook = tl->beginHookType() == HookType::HOOK_90T;
1878 :
1879 0 : if (isNonSolid || isTHook) {
1880 0 : const PointF& p1 = ldata->points[start++];
1881 0 : const PointF& p2 = ldata->points[start++];
1882 :
1883 0 : if (isTHook) {
1884 0 : painter->setPen(solidPen);
1885 : } else {
1886 0 : double hookLength = sqrt(PointF::dotProduct(p2 - p1, p2 - p1));
1887 0 : pen.setDashPattern(distributedDashPattern(dash, gap, hookLength / lineWidth));
1888 0 : painter->setPen(pen);
1889 : }
1890 :
1891 0 : painter->drawLine(p1, p2);
1892 : }
1893 : }
1894 : }
1895 :
1896 : // Draw end hook, if it needs to be drawn separately
1897 0 : if (item->isSingleEndType() && tl->endHookType() != HookType::NONE) {
1898 0 : if (tl->endHookType() == HookType::ARROW_FILLED) {
1899 0 : Brush brush;
1900 0 : brush.setStyle(BrushStyle::SolidPattern);
1901 0 : brush.setColor(color);
1902 0 : painter->setBrush(brush);
1903 0 : painter->setNoPen();
1904 0 : painter->drawPolygon(ldata->endArrow);
1905 0 : } else if (tl->endHookType() == HookType::ARROW) {
1906 0 : pen.setJoinStyle(PenJoinStyle::MiterJoin);
1907 0 : painter->setPen(pen);
1908 0 : painter->drawPolyline(ldata->endArrow);
1909 : } else {
1910 0 : bool isTHook = tl->endHookType() == HookType::HOOK_90T;
1911 :
1912 0 : if (isNonSolid || isTHook) {
1913 0 : const PointF& p1 = ldata->points[--end];
1914 0 : const PointF& p2 = ldata->points[--end];
1915 :
1916 0 : if (isTHook) {
1917 0 : painter->setPen(solidPen);
1918 : } else {
1919 0 : double hookLength = sqrt(PointF::dotProduct(p2 - p1, p2 - p1));
1920 0 : pen.setDashPattern(distributedDashPattern(dash, gap, hookLength / lineWidth));
1921 0 : painter->setPen(pen);
1922 : }
1923 :
1924 0 : painter->drawLine(p1, p2);
1925 : }
1926 : }
1927 : }
1928 :
1929 : // Draw the rest
1930 0 : if (isNonSolid) {
1931 0 : pen.setDashPattern(distributedDashPattern(dash, gap, ldata->lineLength / lineWidth));
1932 : }
1933 :
1934 0 : painter->setPen(pen);
1935 0 : painter->drawPolyline(&ldata->points[start], end - start);
1936 0 : }
1937 :
1938 0 : void TDraw::draw(const GradualTempoChangeSegment* item, Painter* painter, const PaintOptions& opt)
1939 : {
1940 : TRACE_DRAW_ITEM;
1941 0 : drawTextLineBaseSegment(item, painter, opt);
1942 0 : }
1943 :
1944 0 : void TDraw::draw(const HairpinSegment* item, Painter* painter, const PaintOptions& opt)
1945 : {
1946 : TRACE_DRAW_ITEM;
1947 :
1948 0 : drawTextLineBaseSegment(item, painter, opt);
1949 :
1950 0 : if (item->drawCircledTip()) {
1951 0 : Color color = item->curColor(item->hairpin()->visible(), item->hairpin()->lineColor(), opt);
1952 0 : double w = item->absoluteFromSpatium(item->lineWidth());
1953 0 : if (item->staff()) {
1954 0 : w *= item->staff()->staffMag(item->hairpin()->tick());
1955 : }
1956 :
1957 0 : Pen pen(color, w);
1958 0 : painter->setPen(pen);
1959 0 : painter->setBrush(BrushStyle::NoBrush);
1960 0 : painter->drawEllipse(item->circledTip(), item->circledTipRadius(), item->circledTipRadius());
1961 0 : }
1962 0 : }
1963 :
1964 0 : void TDraw::draw(const HammerOnPullOffSegment* item, muse::draw::Painter* painter, const PaintOptions& opt)
1965 : {
1966 0 : draw(toSlurSegment(item), painter, opt);
1967 0 : }
1968 :
1969 0 : void TDraw::draw(const HammerOnPullOffText* item, muse::draw::Painter* painter, const PaintOptions& opt)
1970 : {
1971 : TRACE_DRAW_ITEM;
1972 0 : drawTextBase(item, painter, opt);
1973 0 : }
1974 :
1975 0 : void TDraw::draw(const HarpPedalDiagram* item, Painter* painter, const PaintOptions& opt)
1976 : {
1977 : TRACE_DRAW_ITEM;
1978 0 : drawTextBase(item, painter, opt);
1979 0 : }
1980 :
1981 0 : void TDraw::draw(const HarmonicMarkSegment* item, Painter* painter, const PaintOptions& opt)
1982 : {
1983 : TRACE_DRAW_ITEM;
1984 0 : drawTextLineBaseSegment(item, painter, opt);
1985 0 : }
1986 :
1987 0 : void TDraw::draw(const Harmony* item, Painter* painter, const PaintOptions& opt)
1988 : {
1989 : TRACE_DRAW_ITEM;
1990 :
1991 0 : const Harmony::LayoutData* ldata = item->ldata();
1992 :
1993 0 : if (ldata->renderItemList().empty()) {
1994 0 : drawTextBase(item, painter, opt);
1995 0 : return;
1996 : }
1997 :
1998 0 : if (item->hasFrame()) {
1999 0 : if (!RealIsNull(item->frameWidth().val())) {
2000 0 : Color color = item->frameColor();
2001 0 : Pen pen(color, item->frameWidth().val() * item->spatium(), PenStyle::SolidLine,
2002 0 : PenCapStyle::SquareCap, PenJoinStyle::MiterJoin);
2003 0 : painter->setPen(pen);
2004 0 : } else {
2005 0 : painter->setNoPen();
2006 : }
2007 0 : Color bg(item->bgColor());
2008 0 : painter->setBrush(bg.alpha() ? Brush(bg) : BrushStyle::NoBrush);
2009 0 : if (item->circle()) {
2010 0 : painter->drawArc(ldata->frame, 0, 5760);
2011 : } else {
2012 0 : double baseSpatium = DefaultStyle::baseStyle().value(Sid::spatium).toReal();
2013 0 : double frameRadius = item->frameRound().val() * (item->sizeIsSpatiumDependent() ? item->spatium() : baseSpatium);
2014 0 : painter->drawRoundedRect(ldata->frame, frameRadius, frameRadius);
2015 : }
2016 : }
2017 0 : painter->setBrush(BrushStyle::NoBrush);
2018 0 : Color color = item->textColor(opt);
2019 0 : painter->setPen(color);
2020 0 : for (const HarmonyRenderItem* renderItem : ldata->renderItemList()) {
2021 0 : if (const TextSegment* ts = dynamic_cast<const TextSegment*>(renderItem)) {
2022 0 : painter->setFont(ts->font());
2023 0 : painter->drawText(ts->pos(), ts->text());
2024 0 : } else if (const ChordSymbolParen* parenItem = dynamic_cast<const ChordSymbolParen*>(renderItem)) {
2025 0 : Parenthesis* p = parenItem->parenItem;
2026 0 : painter->translate(parenItem->pos());
2027 0 : draw(p, painter, opt);
2028 0 : painter->translate(-parenItem->pos());
2029 : }
2030 : }
2031 :
2032 0 : if (item->isPolychord()) {
2033 0 : Pen pen(painter->pen());
2034 0 : pen.setWidthF(item->absoluteFromSpatium(item->style().styleS(Sid::polychordDividerThickness)));
2035 0 : pen.setColor(color);
2036 0 : painter->setPen(pen);
2037 0 : for (const LineF& line : ldata->polychordDividerLines()) {
2038 0 : painter->drawLine(line.translated(PointF(0.0, ldata->polychordDividerOffset)));
2039 : }
2040 0 : }
2041 : }
2042 :
2043 0 : void TDraw::draw(const Hook* item, Painter* painter, const PaintOptions& opt)
2044 : {
2045 : TRACE_DRAW_ITEM;
2046 : // hide if belonging to the second chord of a cross-measure pair
2047 0 : if (item->chord() && item->chord()->crossMeasure() == CrossMeasure::SECOND) {
2048 0 : return;
2049 : }
2050 :
2051 0 : painter->setPen(item->curColor(opt));
2052 0 : item->drawSymbol(item->sym(), painter);
2053 : }
2054 :
2055 0 : void TDraw::draw(const Image* item, Painter* painter, const PaintOptions& opt)
2056 : {
2057 : TRACE_DRAW_ITEM;
2058 0 : const Image::LayoutData* ldata = item->ldata();
2059 0 : bool emptyImage = false;
2060 0 : if (item->imageType() == ImageType::SVG) {
2061 0 : if (!item->svgRenderer()) {
2062 0 : emptyImage = true;
2063 : } else {
2064 0 : item->svgRenderer()->render(painter, ldata->bbox());
2065 : }
2066 0 : } else if (item->imageType() == ImageType::RASTER) {
2067 0 : if (item->rasterImage() == nullptr) {
2068 0 : emptyImage = true;
2069 : } else {
2070 0 : painter->save();
2071 0 : SizeF s;
2072 0 : if (item->sizeIsSpatium()) {
2073 0 : s = item->size() * item->spatium();
2074 : } else {
2075 0 : s = item->size() * DPMM;
2076 : }
2077 0 : painter->scale(s.width() / item->rasterImage()->width(), s.height() / item->rasterImage()->height());
2078 0 : painter->drawPixmap(PointF(0, 0), *item->rasterImage());
2079 0 : painter->restore();
2080 : }
2081 : }
2082 :
2083 0 : if (emptyImage) {
2084 0 : painter->setBrush(BrushStyle::NoBrush);
2085 0 : painter->setPen(item->configuration()->defaultColor());
2086 0 : painter->drawRect(ldata->bbox());
2087 0 : painter->drawLine(0.0, 0.0, ldata->bbox().width(), ldata->bbox().height());
2088 0 : painter->drawLine(ldata->bbox().width(), 0.0, 0.0, ldata->bbox().height());
2089 : }
2090 0 : if (item->selected() && !opt.isPrinting) {
2091 0 : painter->setBrush(BrushStyle::NoBrush);
2092 0 : painter->setPen(item->configuration()->selectionColor());
2093 0 : painter->drawRect(ldata->bbox());
2094 : }
2095 0 : }
2096 :
2097 0 : void TDraw::draw(const InstrumentChange* item, Painter* painter, const PaintOptions& opt)
2098 : {
2099 : TRACE_DRAW_ITEM;
2100 0 : drawTextBase(item, painter, opt);
2101 0 : }
2102 :
2103 0 : void TDraw::draw(const InstrumentName* item, Painter* painter, const PaintOptions& opt)
2104 : {
2105 : TRACE_DRAW_ITEM;
2106 0 : drawTextBase(item, painter, opt);
2107 0 : }
2108 :
2109 0 : void TDraw::draw(const Jump* item, Painter* painter, const PaintOptions& opt)
2110 : {
2111 : TRACE_DRAW_ITEM;
2112 0 : drawTextBase(item, painter, opt);
2113 0 : }
2114 :
2115 0 : void TDraw::draw(const KeySig* item, Painter* painter, const PaintOptions& opt)
2116 : {
2117 : TRACE_DRAW_ITEM;
2118 0 : const KeySig::LayoutData* ldata = item->ldata();
2119 :
2120 0 : painter->setPen(item->curColor(opt));
2121 0 : double _spatium = item->spatium();
2122 0 : double step = _spatium * (item->staff() ? item->staff()->staffTypeForElement(item)->lineDistance().val() * 0.5 : 0.5);
2123 0 : int lines = item->staff() ? item->staff()->staffTypeForElement(item)->lines() : 5;
2124 0 : double ledgerLineWidth = item->style().styleAbsolute(Sid::ledgerLineWidth) * item->mag();
2125 0 : double ledgerExtraLen = item->style().styleS(Sid::ledgerLineLength).val() * _spatium;
2126 0 : for (const KeySym& ks : ldata->keySymbols) {
2127 0 : double x = ks.xPos.toAbsolute(_spatium);
2128 0 : double y = ks.line * step;
2129 0 : item->drawSymbol(ks.sym, painter, PointF(x, y));
2130 : // ledger lines
2131 0 : double _symWidth = item->symWidth(ks.sym);
2132 0 : double x1 = x - ledgerExtraLen;
2133 0 : double x2 = x + _symWidth + ledgerExtraLen;
2134 0 : painter->setPen(Pen(item->curColor(opt), ledgerLineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
2135 0 : for (int i = -2; i >= ks.line; i -= 2) { // above
2136 0 : y = i * step;
2137 0 : painter->drawLine(LineF(x1, y, x2, y));
2138 : }
2139 0 : for (int i = lines * 2; i <= ks.line; i += 2) { // below
2140 0 : y = i * step;
2141 0 : painter->drawLine(LineF(x1, y, x2, y));
2142 : }
2143 : }
2144 0 : }
2145 :
2146 0 : void TDraw::draw(const LaissezVibSegment* item, muse::draw::Painter* painter, const PaintOptions& opt)
2147 : {
2148 0 : const LaissezVibSegment::LayoutData* ldata = item->ldata();
2149 0 : if (item->score()->style().styleB(Sid::laissezVibUseSmuflSym)) {
2150 0 : painter->setPen(item->curColor(opt));
2151 0 : item->drawSymbol(ldata->symbol, painter);
2152 : } else {
2153 0 : draw(static_cast<const TieSegment*>(item), painter, opt);
2154 : }
2155 0 : }
2156 :
2157 0 : void TDraw::draw(const Lasso* item, Painter* painter, const PaintOptions&)
2158 : {
2159 : TRACE_DRAW_ITEM;
2160 0 : const Lasso::LayoutData* ldata = item->ldata();
2161 0 : painter->setBrush(Brush(item->configuration()->lassoColor()));
2162 : // always 2 pixel width
2163 0 : double w = 2.0 / painter->worldTransform().m11() * item->contextConfiguration()->guiScaling();
2164 0 : painter->setPen(Pen(item->configuration()->selectionColor(), w));
2165 0 : painter->drawRect(ldata->bbox());
2166 0 : }
2167 :
2168 0 : void TDraw::draw(const LayoutBreak* item, Painter* painter, const PaintOptions& opt)
2169 : {
2170 : TRACE_DRAW_ITEM;
2171 :
2172 0 : if (opt.isPrinting || !item->score()->showUnprintable()) {
2173 0 : return;
2174 : }
2175 :
2176 0 : Color selectionColor = opt.invertColors ? item->configuration()->indicatorIconInvertedSelectionColor()
2177 0 : : item->configuration()->selectionColor();
2178 0 : Color color = item->selected() ? selectionColor : item->configuration()->formattingColor();
2179 0 : Pen pen(color);
2180 0 : painter->setPen(pen);
2181 0 : painter->setFont(item->font());
2182 0 : painter->drawSymbol(PointF(), item->iconCode());
2183 0 : }
2184 :
2185 24 : void TDraw::draw(const LedgerLine* item, Painter* painter, const PaintOptions& opt)
2186 : {
2187 : TRACE_DRAW_ITEM;
2188 :
2189 24 : if (item->chord()->crossMeasure() == CrossMeasure::SECOND) {
2190 0 : return;
2191 : }
2192 :
2193 24 : const LedgerLine::LayoutData* ldata = item->ldata();
2194 :
2195 24 : painter->setPen(Pen(item->curColor(opt), ldata->lineWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
2196 24 : if (item->vertical()) {
2197 0 : painter->drawLine(LineF(0.0, 0.0, 0.0, item->len()));
2198 : } else {
2199 24 : painter->drawLine(LineF(0.0, 0.0, item->len(), 0.0));
2200 : }
2201 : }
2202 :
2203 0 : void TDraw::draw(const LetRingSegment* item, Painter* painter, const PaintOptions& opt)
2204 : {
2205 : TRACE_DRAW_ITEM;
2206 0 : drawTextLineBaseSegment(item, painter, opt);
2207 0 : }
2208 :
2209 0 : void TDraw::draw(const Lyrics* item, Painter* painter, const PaintOptions& opt)
2210 : {
2211 : TRACE_DRAW_ITEM;
2212 0 : drawTextBase(item, painter, opt);
2213 0 : }
2214 :
2215 0 : void TDraw::draw(const LyricsLineSegment* item, Painter* painter, const PaintOptions& opt)
2216 : {
2217 : TRACE_DRAW_ITEM;
2218 :
2219 0 : Pen pen(item->curColor(opt));
2220 0 : pen.setWidthF(item->absoluteFromSpatium(item->lineWidth()));
2221 0 : pen.setCapStyle(PenCapStyle::FlatCap);
2222 0 : painter->setPen(pen);
2223 0 : for (const LineF& dash : item->ldata()->dashes()) {
2224 0 : painter->drawLine(dash);
2225 : }
2226 0 : }
2227 :
2228 0 : void TDraw::draw(const Marker* item, Painter* painter, const PaintOptions& opt)
2229 : {
2230 : TRACE_DRAW_ITEM;
2231 0 : drawTextBase(item, painter, opt);
2232 0 : }
2233 :
2234 0 : void TDraw::draw(const MeasureNumber* item, Painter* painter, const PaintOptions& opt)
2235 : {
2236 : TRACE_DRAW_ITEM;
2237 0 : drawTextBase(item, painter, opt);
2238 0 : }
2239 :
2240 0 : void TDraw::draw(const MeasureRepeat* item, Painter* painter, const PaintOptions& opt)
2241 : {
2242 : TRACE_DRAW_ITEM;
2243 :
2244 0 : const MeasureRepeat::LayoutData* ldata = item->ldata();
2245 :
2246 0 : painter->setPen(item->curColor(opt));
2247 0 : item->drawSymbol(ldata->symId, painter);
2248 :
2249 0 : if (!ldata->numberSym.empty()) {
2250 0 : PointF numberPos = item->numberPosition(item->symBbox(ldata->numberSym));
2251 0 : item->drawSymbols(ldata->numberSym, painter, numberPos);
2252 : }
2253 :
2254 0 : if (item->style().styleB(Sid::fourMeasureRepeatShowExtenders) && item->numMeasures() == 4) {
2255 0 : double hBarThickness = item->style().styleAbsolute(Sid::mmRestHBarThickness);
2256 0 : Pen pen(painter->pen());
2257 0 : pen.setCapStyle(PenCapStyle::FlatCap);
2258 0 : pen.setWidthF(hBarThickness);
2259 0 : painter->setPen(pen);
2260 :
2261 0 : painter->drawLine(ldata->extenderLineLeft);
2262 0 : painter->drawLine(ldata->extenderLineRight);
2263 0 : }
2264 0 : }
2265 :
2266 0 : void TDraw::draw(const MMRest* item, Painter* painter, const PaintOptions& opt)
2267 : {
2268 : TRACE_DRAW_ITEM;
2269 0 : if (item->shouldNotBeDrawn() || (item->track() % VOICES)) { //only on voice 1
2270 0 : return;
2271 : }
2272 :
2273 0 : const MMRest::LayoutData* ldata = item->ldata();
2274 :
2275 0 : double _spatium = item->spatium();
2276 :
2277 : // draw number
2278 0 : painter->setPen(item->curColor(opt));
2279 0 : RectF numberBox = item->symBbox(ldata->numberSym);
2280 0 : PointF numberPos = item->numberPos();
2281 0 : if (item->showNumber()) {
2282 0 : item->drawSymbols(ldata->numberSym, painter, numberPos);
2283 : }
2284 :
2285 0 : numberBox.translate(numberPos);
2286 :
2287 0 : if (item->isOldStyle()) {
2288 : // draw rest symbols
2289 0 : double x = (ldata->restWidth - ldata->symsWidth) * 0.5;
2290 0 : double spacing = item->style().styleAbsolute(Sid::mmRestOldStyleSpacing);
2291 0 : for (SymId sym : ldata->restSyms) {
2292 0 : double y = (sym == SymId::restWhole ? -_spatium : 0);
2293 0 : item->drawSymbol(sym, painter, PointF(x, y));
2294 0 : x += item->symBbox(sym).width() + spacing;
2295 : }
2296 : } else {
2297 0 : double mag = item->staff()->staffMag(item->tick());
2298 0 : Pen pen(painter->pen());
2299 0 : pen.setCapStyle(PenCapStyle::FlatCap);
2300 :
2301 : // draw horizontal line
2302 0 : double hBarThickness = item->style().styleAbsolute(Sid::mmRestHBarThickness) * mag;
2303 0 : if (hBarThickness) { // don't draw at all if 0, QPainter interprets 0 pen width differently
2304 0 : pen.setWidthF(hBarThickness);
2305 0 : painter->setPen(pen);
2306 0 : double halfHBarThickness = hBarThickness * .5;
2307 0 : if (item->showNumber() // avoid painting line through number
2308 0 : && item->style().styleB(Sid::mmRestNumberMaskHBar)
2309 0 : && numberBox.bottom() >= -halfHBarThickness
2310 0 : && numberBox.top() <= halfHBarThickness) {
2311 0 : double gapDistance = (numberBox.width() + _spatium) * .5;
2312 0 : double midpoint = ldata->restWidth * .5;
2313 0 : painter->drawLine(LineF(0.0, 0.0, midpoint - gapDistance, 0.0));
2314 0 : painter->drawLine(LineF(midpoint + gapDistance, 0.0, ldata->restWidth, 0.0));
2315 : } else {
2316 0 : painter->drawLine(LineF(0.0, 0.0, ldata->restWidth, 0.0));
2317 : }
2318 : }
2319 :
2320 : // draw vertical lines
2321 0 : double vStrokeThickness = item->style().styleAbsolute(Sid::mmRestHBarVStrokeThickness) * mag;
2322 0 : if (vStrokeThickness) { // don't draw at all if 0, QPainter interprets 0 pen width differently
2323 0 : pen.setWidthF(vStrokeThickness);
2324 0 : painter->setPen(pen);
2325 0 : double halfVStrokeHeight = item->style().styleAbsolute(Sid::mmRestHBarVStrokeHeight) * .5 * mag;
2326 0 : painter->drawLine(LineF(0.0, -halfVStrokeHeight, 0.0, halfVStrokeHeight));
2327 0 : painter->drawLine(LineF(ldata->restWidth, -halfVStrokeHeight, ldata->restWidth, halfVStrokeHeight));
2328 : }
2329 0 : }
2330 : }
2331 :
2332 0 : void TDraw::draw(const MMRestRange* item, Painter* painter, const PaintOptions& opt)
2333 : {
2334 : TRACE_DRAW_ITEM;
2335 0 : drawTextBase(item, painter, opt);
2336 0 : }
2337 :
2338 127 : void TDraw::draw(const Note* item, Painter* painter, const PaintOptions& opt)
2339 : {
2340 : TRACE_DRAW_ITEM;
2341 127 : if (item->hidden()) {
2342 0 : return;
2343 : }
2344 :
2345 127 : const Note::LayoutData* ldata = item->ldata();
2346 :
2347 127 : const auto config = item->configuration();
2348 127 : const StaffType* staffType = item->staff() ? item->staff()->staffTypeForElement(item) : nullptr;
2349 :
2350 127 : const bool isTabStaff = staffType && staffType->isTabStaff();
2351 127 : const bool negativeFret = isTabStaff && item->negativeFretUsed();
2352 127 : const bool useCriticalColor = negativeFret && !item->deadNote() && !opt.isPrinting;
2353 :
2354 127 : painter->setPen(useCriticalColor ? config->criticalColor() : item->curColor(opt));
2355 :
2356 : // tablature
2357 127 : if (isTabStaff) {
2358 0 : if (item->displayFret() == Note::DisplayFretOption::Hide || item->shouldHideFret()) {
2359 0 : return;
2360 : }
2361 0 : const Staff* st = item->staff();
2362 0 : const StaffType* tab = st->staffTypeForElement(item);
2363 :
2364 0 : if (!opt.isPrinting && item->score()->showUnprintable() && (negativeFret || item->fretConflict())) { // fret conflict
2365 0 : painter->save();
2366 0 : painter->setPen(config->criticalColor());
2367 0 : painter->setBrush(config->criticalBackgroundColor());
2368 0 : painter->drawRect(ldata->bbox());
2369 0 : painter->restore();
2370 : }
2371 :
2372 0 : Font f(tab->fretFont());
2373 0 : f.setPointSizeF(f.pointSizeF() * item->magS());
2374 0 : painter->setFont(f);
2375 :
2376 0 : const double startPosX = ldata->bbox().x();
2377 0 : const double yOffset = tab->fretFontYOffset();
2378 0 : painter->drawText(PointF(startPosX, yOffset * item->magS()), item->fretString());
2379 0 : }
2380 : // NOT tablature
2381 : else {
2382 : // skip drawing, if second note of a cross-measure value
2383 127 : if (item->chord() && item->chord()->crossMeasure() == CrossMeasure::SECOND) {
2384 0 : return;
2385 : }
2386 : // warn if pitch extends usable range of instrument
2387 : // by coloring the notehead
2388 254 : if (item->chord() && item->chord()->segment() && item->staff() && !opt.isPrinting
2389 254 : && MScore::warnPitchRange && !item->staff()->isDrumStaff(item->chord()->tick())) {
2390 0 : const Instrument* in = item->originPart()->instrument(item->chord()->tick());
2391 0 : int i = item->ppitch();
2392 0 : if (i < in->minPitchP() || i > in->maxPitchP()) {
2393 0 : painter->setPen(item->selected() ? config->criticalSelectedColor() : config->criticalColor());
2394 0 : } else if (i < in->minPitchA() || i > in->maxPitchA()) {
2395 0 : painter->setPen(item->selected() ? config->warningSelectedColor() : config->warningColor());
2396 : }
2397 : }
2398 : // Warn if notes are unplayable based on previous harp diagram setting
2399 254 : if (item->chord() && item->chord()->segment() && item->staff() && !opt.isPrinting
2400 254 : && !item->staff()->isDrumStaff(item->chord()->tick())) {
2401 0 : HarpPedalDiagram* prevDiagram = item->originPart()->currentHarpDiagram(item->chord()->segment()->tick());
2402 0 : if (prevDiagram && !prevDiagram->isTpcPlayable(item->tpc())) {
2403 0 : painter->setPen(item->selected() ? config->criticalSelectedColor() : config->criticalColor());
2404 : }
2405 : }
2406 : // draw blank notehead to avoid staff and ledger lines
2407 127 : if (ldata->cachedSymNull.value() != SymId::noSym) {
2408 0 : painter->save();
2409 0 : painter->setPen(config->noteBackgroundColor());
2410 0 : item->drawSymbol(ldata->cachedSymNull.value(), painter);
2411 0 : painter->restore();
2412 : }
2413 127 : item->drawSymbol(ldata->cachedNoteheadSym.value(), painter);
2414 : }
2415 127 : }
2416 :
2417 0 : void TDraw::draw(const NoteDot* item, Painter* painter, const PaintOptions& opt)
2418 : {
2419 : TRACE_DRAW_ITEM;
2420 0 : if (item->note() && item->note()->dotsHidden()) { // don't draw dot if note is hidden
2421 0 : return;
2422 0 : } else if (item->rest() && item->rest()->isGap()) { // don't draw dot for gap rests
2423 0 : return;
2424 : }
2425 0 : const Note* n = item->note();
2426 0 : Fraction tick = n ? n->chord()->tick() : item->rest()->tick();
2427 : // always draw dot for non-tab
2428 : // for tab, draw if on a note and stems through staff or on a rest and rests shown
2429 0 : if (!item->staff()->isTabStaff(tick)
2430 0 : || (n && item->staff()->staffType(tick)->stemThrough())
2431 0 : || (!n && item->staff()->staffType(tick)->showRests())) {
2432 0 : painter->setPen(item->curColor(opt));
2433 0 : item->drawSymbol(SymId::augmentationDot, painter);
2434 : }
2435 : }
2436 :
2437 0 : void TDraw::draw(const NoteHead* item, Painter* painter, const PaintOptions& opt)
2438 : {
2439 0 : draw(static_cast<const Symbol*>(item), painter, opt);
2440 0 : }
2441 :
2442 0 : void TDraw::draw(const NoteLineSegment* item, Painter* painter, const PaintOptions& opt)
2443 : {
2444 : TRACE_DRAW_ITEM;
2445 0 : drawTextLineBaseSegment(item, painter, opt);
2446 0 : }
2447 :
2448 0 : void TDraw::draw(const OttavaSegment* item, Painter* painter, const PaintOptions& opt)
2449 : {
2450 : TRACE_DRAW_ITEM;
2451 0 : drawTextLineBaseSegment(item, painter, opt);
2452 0 : }
2453 :
2454 0 : void TDraw::draw(const PageLockIndicator* item, Painter* painter, const PaintOptions& opt)
2455 : {
2456 : TRACE_DRAW_ITEM;
2457 :
2458 0 : if (opt.isPrinting || !item->score()->showUnprintable()) {
2459 0 : return;
2460 : }
2461 :
2462 0 : Color selectionColor = opt.invertColors ? item->configuration()->indicatorIconInvertedSelectionColor()
2463 0 : : item->configuration()->selectionColor();
2464 0 : Color color = item->selected() ? selectionColor : item->configuration()->formattingColor();
2465 0 : Pen pen(color);
2466 0 : painter->setPen(pen);
2467 0 : painter->setFont(item->font());
2468 0 : painter->drawSymbol(PointF(), item->iconCode());
2469 :
2470 0 : if (item->selected()) {
2471 0 : Color lockedAreaColor = selectionColor;
2472 0 : lockedAreaColor.setAlpha(opt.invertColors ? 90 : 38);
2473 0 : Brush brush(lockedAreaColor);
2474 0 : painter->setBrush(brush);
2475 0 : painter->setNoPen();
2476 0 : double radius = 0.5 * item->spatium();
2477 :
2478 0 : PainterPath path;
2479 0 : path.setFillRule(PainterPath::FillRule::OddEvenFill);
2480 0 : path.addRoundedRect(item->ldata()->rangeRect, radius, radius);
2481 0 : path.addRect(item->ldata()->innerRangeRect);
2482 0 : painter->drawPath(path);
2483 0 : }
2484 0 : }
2485 :
2486 0 : void TDraw::draw(const Parenthesis* item, muse::draw::Painter* painter, const PaintOptions& opt)
2487 : {
2488 : TRACE_DRAW_ITEM;
2489 :
2490 0 : EngravingObject* parent = item->ownershipParent();
2491 0 : TimeSig* parentTs = parent && parent->isTimeSig() ? toTimeSig(parent) : nullptr;
2492 :
2493 0 : if (parentTs && !parentTs->showOnThisStaff()) {
2494 0 : return;
2495 : }
2496 :
2497 0 : Color penColor = item->curColor(opt);
2498 :
2499 0 : Pen pen(penColor);
2500 :
2501 0 : if (item->ldata()->symId != SymId::noSym) {
2502 0 : painter->setPen(pen);
2503 0 : item->drawSymbol(item->ldata()->symId, painter, PointF(), item->ldata()->symScale);
2504 0 : return;
2505 : }
2506 :
2507 0 : painter->setBrush(Brush(pen.color()));
2508 0 : pen.setCapStyle(PenCapStyle::RoundCap);
2509 0 : pen.setJoinStyle(PenJoinStyle::RoundJoin);
2510 0 : pen.setWidthF(item->ldata()->endPointThickness * item->spatium() * item->ldata()->intrinsicMag());
2511 :
2512 0 : painter->setPen(pen);
2513 0 : painter->drawPath(item->ldata()->path());
2514 0 : }
2515 :
2516 0 : void TDraw::draw(const PartialTieSegment* item, muse::draw::Painter* painter, const PaintOptions& opt)
2517 : {
2518 0 : draw(static_cast<const TieSegment*>(item), painter, opt);
2519 0 : }
2520 :
2521 0 : void TDraw::draw(const PalmMuteSegment* item, Painter* painter, const PaintOptions& opt)
2522 : {
2523 : TRACE_DRAW_ITEM;
2524 0 : drawTextLineBaseSegment(item, painter, opt);
2525 0 : }
2526 :
2527 0 : void TDraw::draw(const PedalSegment* item, Painter* painter, const PaintOptions& opt)
2528 : {
2529 : TRACE_DRAW_ITEM;
2530 0 : drawTextLineBaseSegment(item, painter, opt);
2531 0 : }
2532 :
2533 0 : void TDraw::draw(const PickScrapeSegment* item, Painter* painter, const PaintOptions& opt)
2534 : {
2535 : TRACE_DRAW_ITEM;
2536 0 : drawTextLineBaseSegment(item, painter, opt);
2537 0 : }
2538 :
2539 0 : void TDraw::draw(const PlayCountText* item, muse::draw::Painter* painter, const PaintOptions& opt)
2540 : {
2541 : TRACE_DRAW_ITEM;
2542 0 : drawTextBase(item, painter, opt);
2543 0 : }
2544 :
2545 0 : void TDraw::draw(const PlayTechAnnotation* item, Painter* painter, const PaintOptions& opt)
2546 : {
2547 : TRACE_DRAW_ITEM;
2548 0 : drawTextBase(item, painter, opt);
2549 0 : }
2550 :
2551 0 : void TDraw::draw(const RasgueadoSegment* item, Painter* painter, const PaintOptions& opt)
2552 : {
2553 : TRACE_DRAW_ITEM;
2554 0 : drawTextLineBaseSegment(item, painter, opt);
2555 0 : }
2556 :
2557 0 : void TDraw::draw(const RehearsalMark* item, Painter* painter, const PaintOptions& opt)
2558 : {
2559 : TRACE_DRAW_ITEM;
2560 0 : drawTextBase(item, painter, opt);
2561 0 : }
2562 :
2563 0 : void TDraw::draw(const Rest* item, Painter* painter, const PaintOptions& opt)
2564 : {
2565 : TRACE_DRAW_ITEM;
2566 :
2567 0 : if (item->isGap()) {
2568 0 : drawDebugGapRest(item, painter);
2569 0 : return;
2570 : }
2571 :
2572 0 : if (item->shouldNotBeDrawn()) {
2573 0 : return;
2574 : }
2575 :
2576 0 : const Rest::LayoutData* ldata = item->ldata();
2577 :
2578 0 : painter->setPen(item->curColor(opt));
2579 :
2580 0 : if (DeadSlapped* ds = item->deadSlapped()) {
2581 0 : draw(ds, painter, opt);
2582 : } else {
2583 0 : item->drawSymbol(ldata->sym, painter);
2584 : }
2585 : }
2586 :
2587 0 : void TDraw::drawDebugGapRest(const Rest* item, muse::draw::Painter* painter)
2588 : {
2589 0 : IF_ASSERT_FAILED(item->debugDrawGap()) {
2590 0 : return;
2591 : }
2592 :
2593 0 : painter->setPen(Color::RED);
2594 0 : item->drawSymbol(item->ldata()->sym, painter);
2595 : }
2596 :
2597 : //! NOTE May be removed later (should be only single mode)
2598 0 : void TDraw::draw(const ShadowNote* item, Painter* painter, const PaintOptions&)
2599 : {
2600 : TRACE_DRAW_ITEM;
2601 :
2602 0 : if (!item->visible() || !item->isValid()) {
2603 0 : return;
2604 : }
2605 :
2606 0 : PointF ap(item->pagePos());
2607 0 : painter->translate(ap);
2608 0 : double lw = item->style().styleAbsolute(Sid::stemWidth) * item->mag();
2609 0 : Pen pen(item->color(), lw, PenStyle::SolidLine, PenCapStyle::FlatCap);
2610 0 : painter->setPen(pen);
2611 :
2612 0 : bool up = item->computeUp();
2613 :
2614 : // Draw the accidental
2615 0 : SymId acc = Accidental::subtype2symbol(item->accidentalType());
2616 0 : if (acc != SymId::noSym) {
2617 0 : PointF posAcc;
2618 0 : posAcc.rx() -= item->symWidth(acc) + item->style().styleAbsolute(Sid::accidentalNoteDistance) * item->mag();
2619 0 : item->drawSymbol(acc, painter, posAcc);
2620 : }
2621 :
2622 : // Draw the notehead
2623 0 : item->drawSymbol(item->noteheadSymbol(), painter);
2624 :
2625 : // Draw the dots
2626 0 : double sp = item->spatium();
2627 0 : double sp2 = sp / 2;
2628 0 : double noteheadWidth = item->symWidth(item->noteheadSymbol());
2629 :
2630 0 : PointF posDot;
2631 0 : if (item->duration().dots() > 0) {
2632 0 : double d = item->style().styleAbsolute(Sid::dotNoteDistance) * item->mag();
2633 0 : double dd = item->style().styleAbsolute(Sid::dotDotDistance) * item->mag();
2634 0 : posDot.rx() += (noteheadWidth + d);
2635 :
2636 0 : if (item->isRest()) {
2637 0 : posDot.ry() += Rest::getDotline(item->duration().type()) * sp2;
2638 : } else {
2639 0 : posDot.ry() -= (item->lineIndex() % 2 == 0 ? sp2 : 0);
2640 : }
2641 :
2642 0 : if (item->hasFlag() && up) {
2643 0 : posDot.rx() = std::max(posDot.x(), noteheadWidth + item->symBbox(item->flagSym()).right());
2644 : }
2645 :
2646 0 : for (int i = 0; i < item->duration().dots(); i++) {
2647 0 : posDot.rx() += dd * i;
2648 0 : item->drawSymbol(SymId::augmentationDot, painter, posDot);
2649 0 : posDot.rx() -= dd * i;
2650 : }
2651 : }
2652 :
2653 : // Draw stem and flag
2654 0 : if (item->hasStem()) {
2655 0 : double x = item->symSmuflAnchor(item->noteheadSymbol(), up ? SmuflAnchorId::stemUpSE : SmuflAnchorId::stemDownNW).x();
2656 0 : x += up ? -0.5 * lw : 0.5 * lw;
2657 0 : double y1 = item->symSmuflAnchor(item->noteheadSymbol(), up ? SmuflAnchorId::stemUpSE : SmuflAnchorId::stemDownNW).y();
2658 0 : double y2 = (up ? -3.5 : 3.5) * sp;
2659 :
2660 0 : if (item->hasFlag()) {
2661 0 : SymId flag = item->flagSym();
2662 0 : item->drawSymbol(flag, painter, PointF(x - (lw / 2), y2));
2663 0 : y2 += item->symSmuflAnchor(flag, up ? SmuflAnchorId::stemUpNW : SmuflAnchorId::stemDownSW).y();
2664 : }
2665 0 : painter->drawLine(LineF(x, y1, x, y2));
2666 : }
2667 :
2668 : // Draw ledger lines if needed
2669 0 : if (item->ledgerLinesVisible()) {
2670 0 : double extraLen = item->style().styleS(Sid::ledgerLineLength).val() * sp;
2671 0 : double x1 = -extraLen;
2672 0 : double x2 = noteheadWidth + extraLen;
2673 0 : double yOffset = item->staffOffsetY();
2674 0 : double step = sp2 * item->staffType()->lineDistance().val();
2675 :
2676 0 : lw = item->style().styleAbsolute(Sid::ledgerLineWidth) * item->mag();
2677 0 : pen.setWidthF(lw);
2678 0 : painter->setPen(pen);
2679 :
2680 0 : const int topLine = -2 + yOffset / step;
2681 0 : for (int i = topLine; i >= item->lineIndex(); i -= 2) {
2682 0 : double y = step * (i - item->lineIndex());
2683 0 : painter->drawLine(LineF(x1, y, x2, y));
2684 : }
2685 0 : int l = item->staffType()->lines() * 2 + yOffset / step; // first ledger line below staff
2686 0 : for (int i = l; i <= item->lineIndex(); i += 2) {
2687 0 : double y = step * (i - item->lineIndex());
2688 0 : painter->drawLine(LineF(x1, y, x2, y));
2689 : }
2690 : }
2691 :
2692 0 : item->drawArticulations(painter);
2693 :
2694 0 : painter->translate(-ap);
2695 0 : }
2696 :
2697 0 : void TDraw::draw(const SlurSegment* item, Painter* painter, const PaintOptions& opt)
2698 : {
2699 : TRACE_DRAW_ITEM;
2700 :
2701 0 : painter->save();
2702 0 : setMask(item, painter);
2703 :
2704 0 : Pen pen(item->curColor(opt));
2705 0 : double mag = item->staff() ? item->staff()->staffMag(item->slur()->tick()) : 1.0;
2706 :
2707 : //Replace generic Qt dash patterns with improved equivalents to show true dots (keep in sync with tie.cpp)
2708 0 : std::vector<double> dotted = { 0.01, 1.99 }; // tighter than Qt PenStyle::DotLine equivalent - would be { 0.01, 2.99 }
2709 0 : std::vector<double> dashed = { 3.00, 3.00 }; // Compensating for caps. Qt default PenStyle::DashLine is { 4.0, 2.0 }
2710 0 : std::vector<double> wideDashed = { 5.00, 6.00 };
2711 :
2712 0 : switch (item->slurTie()->styleType()) {
2713 0 : case SlurStyleType::Solid:
2714 0 : painter->setBrush(Brush(pen.color()));
2715 0 : pen.setCapStyle(PenCapStyle::RoundCap);
2716 0 : pen.setJoinStyle(PenJoinStyle::RoundJoin);
2717 0 : pen.setWidthF(item->endWidth() * mag);
2718 0 : break;
2719 0 : case SlurStyleType::Dotted:
2720 0 : painter->setBrush(BrushStyle::NoBrush);
2721 0 : pen.setCapStyle(PenCapStyle::RoundCap); // round dots
2722 0 : pen.setDashPattern(dotted);
2723 0 : pen.setWidthF(item->dottedWidth() * mag);
2724 0 : break;
2725 0 : case SlurStyleType::Dashed:
2726 0 : painter->setBrush(BrushStyle::NoBrush);
2727 0 : pen.setDashPattern(dashed);
2728 0 : pen.setWidthF(item->dottedWidth() * mag);
2729 0 : break;
2730 0 : case SlurStyleType::WideDashed:
2731 0 : painter->setBrush(BrushStyle::NoBrush);
2732 0 : pen.setDashPattern(wideDashed);
2733 0 : pen.setWidthF(item->dottedWidth() * mag);
2734 0 : break;
2735 0 : case SlurStyleType::Undefined:
2736 0 : break;
2737 : }
2738 0 : painter->setPen(pen);
2739 0 : painter->drawPath(item->ldata()->path());
2740 :
2741 0 : painter->restore();
2742 0 : }
2743 :
2744 0 : void TDraw::draw(const Spacer* item, Painter* painter, const PaintOptions& opt)
2745 : {
2746 : TRACE_DRAW_ITEM;
2747 0 : if (opt.isPrinting || !item->score()->showUnprintable()) {
2748 0 : return;
2749 : }
2750 :
2751 0 : auto conf = item->configuration();
2752 :
2753 0 : Pen pen(item->selected() ? conf->selectionColor() : conf->formattingColor(), item->spatium()* 0.3);
2754 :
2755 0 : painter->setPen(pen);
2756 0 : painter->setBrush(BrushStyle::NoBrush);
2757 0 : painter->drawPath(item->ldata()->path);
2758 0 : }
2759 :
2760 20 : void TDraw::draw(const StaffLines* item, Painter* painter, const PaintOptions& opt)
2761 : {
2762 : TRACE_DRAW_ITEM;
2763 20 : painter->save();
2764 :
2765 20 : setMask(item, painter);
2766 :
2767 20 : painter->setPen(Pen(item->curColor(opt), item->lw(), PenStyle::SolidLine, PenCapStyle::FlatCap));
2768 20 : painter->drawLines(item->lines());
2769 :
2770 20 : painter->restore();
2771 20 : }
2772 :
2773 0 : void TDraw::draw(const StaffState* item, Painter* painter, const PaintOptions& opt)
2774 : {
2775 : TRACE_DRAW_ITEM;
2776 0 : if (opt.isPrinting || !item->score()->showUnprintable()) {
2777 0 : return;
2778 : }
2779 :
2780 0 : const StaffState::LayoutData* ldata = item->ldata();
2781 0 : auto conf = item->configuration();
2782 :
2783 0 : Pen pen(item->selected() ? conf->selectionColor() : conf->formattingColor(),
2784 0 : ldata->lw, PenStyle::SolidLine, PenCapStyle::RoundCap, PenJoinStyle::RoundJoin);
2785 0 : painter->setPen(pen);
2786 0 : painter->setBrush(BrushStyle::NoBrush);
2787 0 : painter->drawPath(ldata->path);
2788 0 : }
2789 :
2790 0 : void TDraw::draw(const StaffText* item, Painter* painter, const PaintOptions& opt)
2791 : {
2792 : TRACE_DRAW_ITEM;
2793 :
2794 0 : drawTextBase(item, painter, opt);
2795 :
2796 0 : if (item->hasSoundFlag()) {
2797 0 : draw(item->soundFlag(), painter, opt);
2798 : }
2799 0 : }
2800 :
2801 0 : void TDraw::draw(const StaveSharingLabel* item, muse::draw::Painter* painter, const PaintOptions& opt)
2802 : {
2803 : TRACE_DRAW_ITEM;
2804 :
2805 0 : drawTextBase(item, painter, opt);
2806 0 : }
2807 :
2808 0 : void TDraw::draw(const StaffTypeChange* item, Painter* painter, const PaintOptions& opt)
2809 : {
2810 : TRACE_DRAW_ITEM;
2811 :
2812 0 : if (opt.isPrinting || !item->score()->showUnprintable()) {
2813 0 : return;
2814 : }
2815 :
2816 0 : auto conf = item->configuration();
2817 :
2818 0 : double _spatium = item->style().spatium();
2819 0 : double h = _spatium * 2.5;
2820 0 : double w = _spatium * 2.5;
2821 0 : double lineDist = 0.35; // line distance for the icon 'staff lines'
2822 : // draw icon rectangle
2823 0 : painter->setPen(Pen(item->selected() ? conf->selectionColor() : conf->formattingColor(),
2824 0 : item->lw(), PenStyle::SolidLine, PenCapStyle::SquareCap, PenJoinStyle::MiterJoin));
2825 0 : painter->setBrush(BrushStyle::NoBrush);
2826 0 : painter->drawRect(0, 0, w, h);
2827 :
2828 : // draw icon contents
2829 0 : int lines = 5;
2830 0 : if (item->staffType()) {
2831 0 : if (item->staffType()->stemless()) { // a single notehead represents a stemless staff
2832 0 : item->drawSymbol(SymId::noteheadBlack, painter, PointF(w * 0.5 - 0.33 * _spatium, h * 0.5), 0.5);
2833 : }
2834 0 : if (item->staffType()->invisible()) { // no lines needed. It's done.
2835 0 : return;
2836 : }
2837 : // show up to 6 lines
2838 0 : lines = std::min(item->staffType()->lines(), 6);
2839 : }
2840 : // calculate starting point Y for the lines from half the icon height (2.5) so staff lines appear vertically centered
2841 0 : double startY = 1.25 - (lines - 1) * lineDist * 0.5;
2842 0 : painter->setPen(Pen(item->selected() ? conf->selectionColor() : conf->formattingColor(),
2843 0 : 2.5, PenStyle::SolidLine, PenCapStyle::SquareCap, PenJoinStyle::MiterJoin));
2844 0 : for (int i=0; i < lines; i++) {
2845 0 : int y = (startY + i * lineDist) * _spatium;
2846 0 : painter->drawLine(0, y, w, y);
2847 : }
2848 0 : }
2849 :
2850 60 : void TDraw::draw(const Stem* item, Painter* painter, const PaintOptions& opt)
2851 : {
2852 : TRACE_DRAW_ITEM;
2853 60 : if (!item->chord()) { // may be need assert?
2854 0 : return;
2855 : }
2856 :
2857 : // hide if second chord of a cross-measure pair
2858 60 : if (item->chord()->crossMeasure() == CrossMeasure::SECOND) {
2859 0 : return;
2860 : }
2861 :
2862 60 : const Stem::LayoutData* ldata = item->ldata();
2863 :
2864 60 : const Staff* staff = item->staff();
2865 60 : const StaffType* staffType = staff ? staff->staffTypeForElement(item->chord()) : nullptr;
2866 60 : const bool isTablature = staffType && staffType->isTabStaff();
2867 :
2868 60 : painter->setPen(Pen(item->curColor(opt), item->lineWidthMag(), PenStyle::SolidLine, PenCapStyle::FlatCap));
2869 60 : painter->drawLine(ldata->line);
2870 :
2871 60 : if (!isTablature) {
2872 60 : return;
2873 : }
2874 :
2875 : // TODO: adjust bounding rectangle in layout() for dots and for slash
2876 0 : double sp = item->spatium();
2877 0 : bool isUp = item->up();
2878 :
2879 : // slashed half note stem
2880 0 : if (item->chord()->durationType().type() == DurationType::V_HALF
2881 0 : && staffType->minimStyle() == TablatureMinimStyle::SLASHED) {
2882 : // position slashes onto stem
2883 0 : double y = isUp ? -item->length() + StemLayout::STAFFTYPE_TAB_SLASH_2STARTY_UP * sp
2884 0 : : item->length() - StemLayout::STAFFTYPE_TAB_SLASH_2STARTY_DN * sp;
2885 : // if stems through, try to align slashes within or across lines
2886 0 : if (staffType->stemThrough()) {
2887 0 : double halfLineDist = staffType->lineDistance().val() * sp * 0.5;
2888 0 : double halfSlashHgt = StemLayout::STAFFTYPE_TAB_SLASH_2TOTHEIGHT * sp * 0.5;
2889 0 : y = lrint((y + halfSlashHgt) / halfLineDist) * halfLineDist - halfSlashHgt;
2890 : }
2891 : // draw slashes
2892 0 : double hlfWdt= sp * StemLayout::STAFFTYPE_TAB_SLASH_WIDTH * 0.5;
2893 0 : double sln = sp * StemLayout::STAFFTYPE_TAB_SLASH_SLANTY;
2894 0 : double thk = sp * StemLayout::STAFFTYPE_TAB_SLASH_THICK;
2895 0 : double displ = sp * StemLayout::STAFFTYPE_TAB_SLASH_DISPL;
2896 0 : PainterPath path;
2897 0 : for (int i = 0; i < 2; ++i) {
2898 0 : path.moveTo(hlfWdt, y); // top-right corner
2899 0 : path.lineTo(hlfWdt, y + thk); // bottom-right corner
2900 0 : path.lineTo(-hlfWdt, y + thk + sln); // bottom-left corner
2901 0 : path.lineTo(-hlfWdt, y + sln); // top-left corner
2902 0 : path.closeSubpath();
2903 0 : y += displ;
2904 : }
2905 0 : painter->setBrush(Brush(item->curColor(opt)));
2906 0 : painter->setNoPen();
2907 0 : painter->drawPath(path);
2908 0 : }
2909 :
2910 : // dots
2911 : // NOT THE BEST PLACE FOR THIS?
2912 : // with tablatures and stems beside staves, dots are not drawn near 'notes', but near stems
2913 0 : int nDots = item->chord()->dots();
2914 0 : if (nDots > 0 && !staffType->stemThrough()) {
2915 0 : double x = item->chord()->dotPosX();
2916 0 : double y = ((StemLayout::STAFFTYPE_TAB_DEFAULTSTEMLEN_DN * 0.2) * sp) * (isUp ? -1.0 : 1.0);
2917 0 : double step = item->style().styleS(Sid::dotDotDistance).val() * sp;
2918 0 : for (int dot = 0; dot < nDots; dot++, x += step) {
2919 0 : item->drawSymbol(SymId::augmentationDot, painter, PointF(x, y));
2920 : }
2921 : }
2922 : }
2923 :
2924 0 : void TDraw::draw(const StemSlash* item, Painter* painter, const PaintOptions& opt)
2925 : {
2926 : TRACE_DRAW_ITEM;
2927 0 : const StemSlash::LayoutData* ldata = item->ldata();
2928 0 : painter->setPen(Pen(item->curColor(opt), ldata->stemWidth, PenStyle::SolidLine, PenCapStyle::FlatCap));
2929 0 : painter->drawLine(ldata->line);
2930 0 : }
2931 :
2932 0 : void TDraw::draw(const Sticking* item, Painter* painter, const PaintOptions& opt)
2933 : {
2934 : TRACE_DRAW_ITEM;
2935 0 : drawTextBase(item, painter, opt);
2936 0 : }
2937 :
2938 0 : void TDraw::draw(const StringTunings* item, Painter* painter, const PaintOptions& opt)
2939 : {
2940 : TRACE_DRAW_ITEM;
2941 :
2942 0 : if (item->noStringVisible()) {
2943 0 : const TextBase::LayoutData* data = item->ldata();
2944 :
2945 0 : const double spatium = item->spatium();
2946 0 : const double lineWidth = spatium * .15;
2947 :
2948 0 : const Pen pen(item->curColor(opt), lineWidth, PenStyle::SolidLine, PenCapStyle::RoundCap, PenJoinStyle::RoundJoin);
2949 0 : painter->setPen(pen);
2950 0 : painter->setBrush(Brush(item->curColor(opt)));
2951 :
2952 0 : const RectF rect = data->bbox();
2953 :
2954 0 : const double x = rect.x();
2955 0 : const double y = rect.y();
2956 0 : const double width = rect.width();
2957 0 : const double height = rect.height();
2958 0 : const double topPartHeight = height * .66;
2959 0 : const double cornerRadius = height * .1;
2960 :
2961 0 : PainterPath path;
2962 0 : path.moveTo(x, y);
2963 0 : path.arcTo(x, y + (topPartHeight - 2 * cornerRadius), 2 * cornerRadius, 2 * cornerRadius, 180.0, 90.0);
2964 0 : path.arcTo(x + width - 2 * cornerRadius, y + (topPartHeight - 2 * cornerRadius), 2 * cornerRadius, 2 * cornerRadius, 270, 90);
2965 0 : path.lineTo(x + width, y);
2966 0 : path.moveTo(x + width / 2, y + topPartHeight);
2967 0 : path.lineTo(x + width / 2, y + height);
2968 :
2969 0 : painter->setBrush(BrushStyle::NoBrush);
2970 0 : painter->drawPath(path);
2971 0 : } else {
2972 0 : drawTextBase(item, painter, opt);
2973 : }
2974 0 : }
2975 :
2976 0 : void TDraw::draw(const Symbol* item, Painter* painter, const PaintOptions& opt)
2977 : {
2978 : TRACE_DRAW_ITEM;
2979 0 : bool tabStaff = item->staff() ? item->staff()->isTabStaff(item->tick()) : false;
2980 :
2981 0 : if (!item->isNoteDot() || !tabStaff) {
2982 0 : painter->setPen(item->curColor(opt));
2983 0 : if (item->scoreFont()) {
2984 0 : item->scoreFont()->draw(item->sym(), painter, item->magS() * item->symbolsSize(), PointF(), item->symAngle());
2985 : } else {
2986 0 : item->drawSymbol(item->sym(), painter);
2987 : }
2988 : }
2989 0 : }
2990 :
2991 0 : void TDraw::draw(const FSymbol* item, Painter* painter, const PaintOptions& opt)
2992 : {
2993 : TRACE_DRAW_ITEM;
2994 :
2995 0 : painter->setFont(item->font());
2996 0 : painter->setPen(item->curColor(opt));
2997 0 : painter->drawText(PointF(0, 0), item->toString());
2998 0 : }
2999 :
3000 0 : void TDraw::draw(const SystemDivider* item, Painter* painter, const PaintOptions& opt)
3001 : {
3002 0 : draw(static_cast<const Symbol*>(item), painter, opt);
3003 0 : }
3004 :
3005 0 : void TDraw::draw(const SystemText* item, Painter* painter, const PaintOptions& opt)
3006 : {
3007 0 : drawTextBase(item, painter, opt);
3008 0 : }
3009 :
3010 0 : void TDraw::draw(const IndicatorIcon* item, muse::draw::Painter* painter, const PaintOptions& opt)
3011 : {
3012 : TRACE_DRAW_ITEM;
3013 :
3014 0 : if (opt.isPrinting || !item->score()->showUnprintable()) {
3015 0 : return;
3016 : }
3017 :
3018 0 : Color selectionColor = opt.invertColors ? item->configuration()->indicatorIconInvertedSelectionColor()
3019 0 : : item->configuration()->selectionColor();
3020 0 : Color color = item->selected() ? selectionColor : item->configuration()->formattingColor();
3021 0 : Pen pen(color);
3022 0 : painter->setPen(pen);
3023 0 : painter->setFont(item->font());
3024 0 : painter->drawSymbol(PointF(), item->iconCode());
3025 :
3026 0 : if (item->isSystemLockIndicator() && item->selected()) {
3027 0 : const SystemLockIndicator* sli = toSystemLockIndicator(item);
3028 :
3029 0 : Color lockedAreaColor = selectionColor;
3030 0 : lockedAreaColor.setAlpha(opt.invertColors ? 90 : 38);
3031 0 : Brush brush(lockedAreaColor);
3032 0 : painter->setBrush(brush);
3033 0 : painter->setNoPen();
3034 0 : double radius = 0.5 * sli->spatium();
3035 :
3036 0 : painter->drawRoundedRect(sli->ldata()->rangeRect, radius, radius);
3037 0 : }
3038 0 : }
3039 :
3040 0 : void TDraw::draw(const SoundFlag* item, Painter* painter, const PaintOptions& opt)
3041 : {
3042 : TRACE_DRAW_ITEM;
3043 :
3044 0 : if (item->shouldHide()) {
3045 0 : return;
3046 : }
3047 :
3048 0 : painter->setNoPen();
3049 0 : painter->setBrush(item->iconBackgroundColor());
3050 0 : painter->drawEllipse(item->ldata()->bbox().adjusted(-4.0, -4.0, 4.0, 4.0));
3051 :
3052 0 : painter->setFont(item->iconFont());
3053 0 : painter->setPen(!item->selected() ? item->curColor(true, opt) : Color::WHITE);
3054 0 : painter->drawText(item->ldata()->bbox(), muse::draw::AlignCenter, muse::draw::TextDontClip, Char(item->iconCode()));
3055 : }
3056 :
3057 0 : void TDraw::draw(const TabDurationSymbol* item, Painter* painter, const PaintOptions& opt)
3058 : {
3059 : TRACE_DRAW_ITEM;
3060 :
3061 0 : if (!item->tab()) {
3062 0 : return;
3063 : }
3064 :
3065 0 : const TabDurationSymbol::LayoutData* ldata = item->ldata();
3066 :
3067 0 : if (item->isRepeat() && (item->tab()->symRepeat() == TablatureSymbolRepeat::SYSTEM)) {
3068 0 : Chord* chord = toChord(item->ownershipParent());
3069 0 : ChordRest* prevCR = Navigation::prevChordRest(chord);
3070 0 : if (prevCR && (chord->measure()->system() == prevCR->measure()->system())) {
3071 0 : return;
3072 : }
3073 : }
3074 :
3075 0 : double mag = item->magS();
3076 0 : double imag = 1.0 / mag;
3077 :
3078 0 : Pen pen(item->curColor(opt));
3079 0 : painter->setPen(pen);
3080 0 : painter->scale(mag, mag);
3081 0 : if (ldata->beamGrid == TabBeamGrid::NONE) {
3082 : // if no beam grid, draw symbol
3083 0 : painter->setFont(item->tab()->durationFont());
3084 0 : painter->drawText(PointF(0.0, 0.0), item->text());
3085 : } else {
3086 : // if beam grid, draw stem line
3087 0 : const TablatureDurationFont& font = item->tab()->tabDurationFont();
3088 0 : double _spatium = item->spatium();
3089 0 : pen.setCapStyle(PenCapStyle::FlatCap);
3090 0 : pen.setWidthF(font.gridStemWidth.toAbsolute(_spatium));
3091 0 : painter->setPen(pen);
3092 : // take stem height from bbox, but de-magnify it, as drawing is already magnified
3093 0 : double h = ldata->bbox().y() / mag;
3094 0 : painter->drawLine(PointF(0.0, h), PointF(0.0, 0.0));
3095 : // if beam grid is medial/final, draw beam lines too: lines go from mid of
3096 : // previous stem (delta x stored in _beamLength) to mid of this' stem (0.0)
3097 0 : if (ldata->beamGrid == TabBeamGrid::MEDIALFINAL) {
3098 0 : pen.setWidthF(font.gridBeamWidth.toAbsolute(_spatium));
3099 0 : painter->setPen(pen);
3100 : // lower height available to beams by half a beam width,
3101 : // so that top beam upper border aligns with stem top
3102 0 : h += (font.gridBeamWidth.toAbsolute(_spatium)) * 0.5;
3103 : // draw beams equally spaced within the stem height (this is
3104 : // different from modern engraving, but common in historic prints)
3105 0 : double step = -h / ldata->beamLevel;
3106 0 : double y = h;
3107 0 : for (int i = 0; i < ldata->beamLevel; i++, y += step) {
3108 0 : painter->drawLine(PointF(ldata->beamLength, y), PointF(0.0, y));
3109 : }
3110 : }
3111 : }
3112 0 : painter->scale(imag, imag);
3113 0 : }
3114 :
3115 0 : void TDraw::draw(const Tapping* item, muse::draw::Painter* painter, const PaintOptions& opt)
3116 : {
3117 0 : painter->setPen(item->curColor(opt));
3118 0 : if (item->ldata()->symId != SymId::noSym) {
3119 0 : item->drawSymbol(item->ldata()->symId, painter);
3120 0 : } else if (TappingText* text = item->text()) {
3121 0 : painter->translate(text->pos());
3122 0 : drawTextBase(text, painter, opt);
3123 0 : painter->translate(-text->pos());
3124 : } else {
3125 0 : assert(false && "Drawing Tapping item without text or symbol");
3126 : }
3127 0 : }
3128 :
3129 0 : void TDraw::draw(const TempoText* item, Painter* painter, const PaintOptions& opt)
3130 : {
3131 : TRACE_DRAW_ITEM;
3132 0 : drawTextBase(item, painter, opt);
3133 0 : }
3134 :
3135 0 : void TDraw::draw(const Text* item, Painter* painter, const PaintOptions& opt)
3136 : {
3137 : TRACE_DRAW_ITEM;
3138 0 : drawTextBase(item, painter, opt);
3139 0 : }
3140 :
3141 0 : void TDraw::draw(const TextLineSegment* item, Painter* painter, const PaintOptions& opt)
3142 : {
3143 : TRACE_DRAW_ITEM;
3144 0 : drawTextLineBaseSegment(item, painter, opt);
3145 0 : }
3146 :
3147 0 : void TDraw::draw(const TieSegment* item, Painter* painter, const PaintOptions& opt)
3148 : {
3149 : TRACE_DRAW_ITEM;
3150 :
3151 : // hide tie toward the second chord of a cross-measure value
3152 0 : if (item->tie()->endNote() && item->tie()->endNote()->chord()->crossMeasure() == CrossMeasure::SECOND) {
3153 0 : return;
3154 : }
3155 :
3156 0 : painter->save();
3157 :
3158 0 : setMask(item, painter);
3159 :
3160 0 : Color penColor = item->curColor(item->getProperty(Pid::VISIBLE).toBool(), item->getProperty(Pid::COLOR).value<Color>(), opt);
3161 0 : if (!opt.isPrinting && item->ldata()->allJumpPointsInactive) {
3162 0 : penColor.setAlpha(std::min(penColor.alpha(), 85));
3163 : }
3164 :
3165 0 : Pen pen(penColor);
3166 0 : double mag = item->staff() ? item->staff()->staffMag(item->tie()->tick()) : 1.0;
3167 : //Replace generic Qt dash patterns with improved equivalents to show true dots (keep in sync with slur.cpp)
3168 0 : std::vector<double> dotted = { 0.01, 1.99 }; // tighter than Qt PenStyle::DotLine equivalent - would be { 0.01, 2.99 }
3169 0 : std::vector<double> dashed = { 3.00, 3.00 }; // Compensating for caps. Qt default PenStyle::DashLine is { 4.0, 2.0 }
3170 0 : std::vector<double> wideDashed = { 5.00, 6.00 };
3171 :
3172 0 : switch (item->slurTie()->styleType()) {
3173 0 : case SlurStyleType::Solid:
3174 0 : painter->setBrush(Brush(pen.color()));
3175 0 : pen.setCapStyle(PenCapStyle::RoundCap);
3176 0 : pen.setJoinStyle(PenJoinStyle::RoundJoin);
3177 0 : pen.setWidthF(item->endWidth() * mag);
3178 0 : break;
3179 0 : case SlurStyleType::Dotted:
3180 0 : painter->setBrush(BrushStyle::NoBrush);
3181 0 : pen.setCapStyle(PenCapStyle::RoundCap); // True dots
3182 0 : pen.setDashPattern(dotted);
3183 0 : pen.setWidthF(item->dottedWidth() * mag);
3184 0 : break;
3185 0 : case SlurStyleType::Dashed:
3186 0 : painter->setBrush(BrushStyle::NoBrush);
3187 0 : pen.setDashPattern(dashed);
3188 0 : pen.setWidthF(item->dottedWidth() * mag);
3189 0 : break;
3190 0 : case SlurStyleType::WideDashed:
3191 0 : painter->setBrush(BrushStyle::NoBrush);
3192 0 : pen.setDashPattern(wideDashed);
3193 0 : pen.setWidthF(item->dottedWidth() * mag);
3194 0 : break;
3195 0 : case SlurStyleType::Undefined:
3196 0 : break;
3197 : }
3198 0 : painter->setPen(pen);
3199 0 : painter->drawPath(item->ldata()->path());
3200 :
3201 0 : painter->restore();
3202 0 : }
3203 :
3204 10 : void TDraw::draw(const TimeSig* item, Painter* painter, const PaintOptions& opt)
3205 : {
3206 : TRACE_DRAW_ITEM;
3207 :
3208 10 : if (item->staff() && !const_cast<const Staff*>(item->staff())->staffType(item->tick())->genTimesig()) {
3209 0 : return;
3210 : }
3211 10 : if (!item->showOnThisStaff()) {
3212 0 : return;
3213 : }
3214 10 : painter->setPen(item->curColor(opt));
3215 :
3216 10 : const TimeSig::LayoutData* ldata = item->ldata();
3217 :
3218 10 : item->drawSymbols(ldata->ns, painter, ldata->pz, item->scale());
3219 10 : item->drawSymbols(ldata->ds, painter, ldata->pn, item->scale());
3220 :
3221 10 : if (item->largeParentheses()) {
3222 0 : item->drawSymbol(SymId::timeSigParensLeft, painter, ldata->pointLargeLeftParen, item->scale().width());
3223 0 : item->drawSymbol(SymId::timeSigParensRight, painter, ldata->pointLargeRightParen, item->scale().width());
3224 : }
3225 : }
3226 :
3227 0 : void TDraw::draw(const TimeTickAnchor* item, Painter* painter, const PaintOptions& opt)
3228 : {
3229 0 : if (opt.isPrinting) {
3230 0 : return;
3231 : }
3232 :
3233 0 : TimeTickAnchor::DrawRegion drawRegion = item->drawRegion();
3234 :
3235 0 : if (drawRegion == TimeTickAnchor::DrawRegion::OUT_OF_RANGE) {
3236 0 : return;
3237 : }
3238 :
3239 0 : Color voiceColor = item->configuration()->voiceColor(item->voiceIdx());
3240 :
3241 : static constexpr double TINT_MAIN_DARKER = 0.45;
3242 : static constexpr double TINT_MAIN_LIGHTER = 0.55;
3243 : static constexpr double TINT_EXTENDED_DARKER = 0.75;
3244 : static constexpr double TINT_EXTENDED_LIGHTER = 0.85;
3245 :
3246 : double tint = drawRegion == TimeTickAnchor::DrawRegion::MAIN_REGION
3247 0 : ? item->ldata()->darker() ? TINT_MAIN_DARKER : TINT_MAIN_LIGHTER
3248 0 : : item->ldata()->darker() ? TINT_EXTENDED_DARKER : TINT_EXTENDED_LIGHTER;
3249 :
3250 0 : voiceColor.applyTint(tint);
3251 :
3252 0 : Brush brush;
3253 0 : brush.setColor(voiceColor);
3254 0 : brush.setStyle(BrushStyle::SolidPattern);
3255 0 : painter->setBrush(brush);
3256 0 : painter->setNoPen();
3257 :
3258 0 : painter->drawRect(item->ldata()->bbox());
3259 0 : }
3260 :
3261 0 : void TDraw::draw(const TremoloSingleChord* item, Painter* painter, const PaintOptions& opt)
3262 : {
3263 : TRACE_DRAW_ITEM;
3264 :
3265 0 : if (item->isBuzzRoll()) {
3266 0 : painter->setPen(item->curColor(opt));
3267 0 : item->drawSymbol(SymId::buzzRoll, painter);
3268 : } else {
3269 0 : painter->setBrush(Brush(item->curColor(opt)));
3270 0 : painter->setNoPen();
3271 0 : painter->drawPath(item->path());
3272 : }
3273 0 : }
3274 :
3275 0 : void TDraw::draw(const TremoloTwoChord* item, Painter* painter, const PaintOptions& opt)
3276 : {
3277 : TRACE_DRAW_ITEM;
3278 :
3279 0 : const TremoloTwoChord::LayoutData* ldata = item->ldata();
3280 :
3281 0 : if (!item->beamSegments().empty()) {
3282 : // two-note trems act like beams
3283 :
3284 : // make beam thickness independent of slant
3285 : // (expression can be simplified?)
3286 0 : const LineF bs = item->beamSegments().front()->line;
3287 0 : double d = (std::abs(bs.y2() - bs.y1())) / (bs.x2() - bs.x1());
3288 0 : if (item->beamSegments().size() > 1 && d > M_PI / 6.0) {
3289 0 : d = M_PI / 6.0;
3290 : }
3291 0 : double ww = (ldata->beamWidth / 2.0) / sin(M_PI_2 - atan(d));
3292 0 : painter->setBrush(Brush(item->curColor(opt)));
3293 0 : painter->setNoPen();
3294 0 : for (const BeamSegment* bs1 : item->beamSegments()) {
3295 0 : painter->drawPolygon(
3296 0 : PolygonF({
3297 0 : PointF(bs1->line.x1(), bs1->line.y1() - ww),
3298 0 : PointF(bs1->line.x2(), bs1->line.y2() - ww),
3299 0 : PointF(bs1->line.x2(), bs1->line.y2() + ww),
3300 0 : PointF(bs1->line.x1(), bs1->line.y1() + ww),
3301 0 : }),
3302 : FillRule::OddEvenFill);
3303 : }
3304 : }
3305 0 : }
3306 :
3307 0 : void TDraw::draw(const TremoloBar* item, Painter* painter, const PaintOptions& opt)
3308 : {
3309 : TRACE_DRAW_ITEM;
3310 0 : const TremoloBar::LayoutData* ldata = item->ldata();
3311 0 : const double lw = item->absoluteFromSpatium(item->lineWidth());
3312 0 : Pen pen(item->curColor(opt), lw, PenStyle::SolidLine, PenCapStyle::RoundCap, PenJoinStyle::RoundJoin);
3313 0 : painter->setPen(pen);
3314 0 : painter->drawPolyline(ldata->polygon);
3315 0 : }
3316 :
3317 0 : void TDraw::draw(const TrillSegment* item, Painter* painter, const PaintOptions& opt)
3318 : {
3319 : TRACE_DRAW_ITEM;
3320 0 : painter->setPen(item->spanner()->curColor(opt));
3321 0 : item->drawSymbols(item->symbols(), painter);
3322 0 : }
3323 :
3324 0 : void TDraw::draw(const TripletFeel* item, Painter* painter, const PaintOptions& opt)
3325 : {
3326 : TRACE_DRAW_ITEM;
3327 0 : drawTextBase(item, painter, opt);
3328 0 : }
3329 :
3330 0 : void TDraw::draw(const Tuplet* item, Painter* painter, const PaintOptions& opt)
3331 : {
3332 : TRACE_DRAW_ITEM;
3333 :
3334 : // if in a TAB without stems, tuplets are not shown
3335 0 : const StaffType* stt = item->staffType();
3336 0 : if (stt && stt->isTabStaff() && stt->stemless()) {
3337 0 : return;
3338 : }
3339 :
3340 0 : Color color(item->curColor(opt));
3341 0 : if (item->number()) {
3342 0 : painter->setPen(color);
3343 0 : PointF pos(item->number()->pos());
3344 0 : painter->translate(pos);
3345 0 : draw(item->number(), painter, opt);
3346 0 : painter->translate(-pos);
3347 : }
3348 0 : if (item->hasBracket()) {
3349 0 : Pen pen(color, item->absoluteFromSpatium(item->bracketWidth()));
3350 0 : pen.setJoinStyle(PenJoinStyle::MiterJoin);
3351 0 : pen.setCapStyle(PenCapStyle::FlatCap);
3352 0 : painter->setPen(pen);
3353 0 : if (!item->number()) {
3354 0 : painter->drawPolyline(item->bracketL, 4);
3355 : } else {
3356 0 : painter->drawPolyline(item->bracketL, 3);
3357 0 : painter->drawPolyline(item->bracketR, 3);
3358 : }
3359 0 : }
3360 : }
3361 :
3362 0 : void TDraw::draw(const VibratoSegment* item, Painter* painter, const PaintOptions& opt)
3363 : {
3364 : TRACE_DRAW_ITEM;
3365 0 : painter->setPen(item->spanner()->curColor(opt));
3366 0 : item->drawSymbols(item->symbols(), painter);
3367 0 : }
3368 :
3369 0 : void TDraw::draw(const VoltaSegment* item, Painter* painter, const PaintOptions& opt)
3370 : {
3371 : TRACE_DRAW_ITEM;
3372 0 : drawTextLineBaseSegment(item, painter, opt);
3373 0 : }
3374 :
3375 0 : void TDraw::draw(const WhammyBarSegment* item, Painter* painter, const PaintOptions& opt)
3376 : {
3377 : TRACE_DRAW_ITEM;
3378 0 : drawTextLineBaseSegment(item, painter, opt);
3379 0 : }
3380 :
3381 50 : void TDraw::setMask(const EngravingItem* item, Painter* painter)
3382 : {
3383 50 : const EngravingItem::LayoutData* ldata = item->ldata();
3384 :
3385 50 : const Shape& mask = ldata->mask();
3386 50 : if (mask.empty()) {
3387 50 : return;
3388 : }
3389 :
3390 0 : RectF background = ldata->bbox().padded(item->spatium());
3391 :
3392 0 : painter->setMask(background, mask.toRects());
3393 : }
|