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) 2024 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "engravingitempreviewpainter.h"
24 :
25 : #include "engraving/dom/masterscore.h"
26 : #include "engraving/dom/textlinebase.h"
27 : #include "engraving/rendering/paintoptions.h"
28 : #include "engraving/style/defaultstyle.h"
29 :
30 : using namespace mu::notation;
31 : using namespace mu::engraving;
32 : using namespace muse::draw;
33 :
34 : /// Paint `element` centered inside `params.rect`. If `params.numStaffLines >
35 : /// 0`, then the element is only centered horizontally; i.e. vertical alignment
36 : /// is unchanged from the default so that item will appear at the correct height
37 : /// on the staff.
38 0 : void EngravingItemPreviewPainter::paintPreview(std::shared_ptr<engraving::rendering::ISingleRenderer> render,
39 : mu::engraving::EngravingItem* element, PaintParams& params)
40 : {
41 0 : IF_ASSERT_FAILED(element && params.painter) {
42 0 : return;
43 : }
44 :
45 0 : Painter* painter = params.painter;
46 0 : painter->setPen(params.color);
47 :
48 0 : PointF rectOrigin = params.rect.center(); // draw element at center of cell by default
49 0 : if (params.numStaffLines > 0) {
50 0 : const double topLinePos = paintStaff(params); // draw dummy staff lines onto rect.
51 0 : rectOrigin.setY(topLinePos); // vertical position relative to staff instead of cell center.
52 : }
53 :
54 0 : painter->translate(rectOrigin);
55 :
56 0 : painter->translate(params.xoffset * params.spatium, params.yoffset * params.spatium); // additional offset for element only
57 :
58 0 : const Score* score = element->score()->paletteScore() ? element->score()->paletteScore() : element->score();
59 0 : const double sizeRatio = params.spatium / score->style().spatium();
60 0 : painter->scale(sizeRatio, sizeRatio); // scale coordinates so element is drawn at correct size
61 :
62 : // calculate bbox
63 0 : render->layoutItem(element);
64 :
65 0 : PointF elementOrigin = element->ldata()->bbox().center();
66 :
67 0 : if (params.numStaffLines > 0) {
68 : // y = 0 is position of the element's parent.
69 : // If the parent is the staff (or a segment on the staff) then
70 : // y = 0 corresponds to the position of the top staff line.
71 0 : elementOrigin.setY(0.0);
72 : }
73 :
74 : // shift coordinates so element is drawn at correct position
75 0 : painter->translate(-elementOrigin);
76 :
77 0 : paintItem(render, element, params);
78 : }
79 :
80 0 : void EngravingItemPreviewPainter::paintItem(std::shared_ptr<engraving::rendering::ISingleRenderer> render,
81 : mu::engraving::EngravingItem* element, PaintParams& params)
82 : {
83 0 : IF_ASSERT_FAILED(element && params.painter) {
84 0 : return;
85 : }
86 :
87 0 : const auto doPaint = [&](EngravingItem* item) {
88 0 : Painter* painter = params.painter;
89 :
90 0 : painter->save();
91 0 : painter->translate(item->pos()); // necessary for drawing child items
92 :
93 0 : const Color colorBackup = item->getProperty(Pid::COLOR).value<Color>();
94 0 : const Color frameColorBackup = item->getProperty(Pid::FRAME_FG_COLOR).value<Color>();
95 :
96 0 : if (!params.useElementColors) {
97 0 : const Color color = params.color;
98 0 : item->setProperty(Pid::COLOR, color);
99 0 : item->setProperty(Pid::FRAME_FG_COLOR, color);
100 : }
101 :
102 0 : rendering::PaintOptions opt;
103 0 : opt.invertColors = params.colorsInversionEnabled;
104 : // The drawing color has been specified explicitly above, so use it as-is:
105 0 : opt.ignoreDisplayedDefaultColor = !params.useElementColors;
106 :
107 0 : render->drawItem(item, painter, opt);
108 :
109 0 : item->setProperty(Pid::COLOR, colorBackup);
110 0 : item->setProperty(Pid::FRAME_FG_COLOR, frameColorBackup);
111 :
112 0 : painter->restore();
113 0 : };
114 :
115 0 : if (element->isSpanner() && !toSpanner(element)->segmentsEmpty()) {
116 0 : SpannerSegment* spannerSeg = toSpanner(element)->frontSegment();
117 0 : DO_ASSERT(spannerSeg);
118 0 : spannerSeg->scanElements(doPaint);
119 : } else {
120 0 : element->scanElements(doPaint);
121 : }
122 : }
123 :
124 : /// Paint a staff centered within a QRect and return the distance from the
125 : /// top of the QRect to the uppermost staff line.
126 0 : double EngravingItemPreviewPainter::paintStaff(PaintParams& params)
127 : {
128 0 : IF_ASSERT_FAILED(params.painter) {
129 0 : return 0.0;
130 : }
131 :
132 0 : Painter* painter = params.painter;
133 0 : painter->save();
134 :
135 0 : Color staffLinesColor(params.color);
136 0 : staffLinesColor.setAlpha(127); //reduce alpha of staff lines to half
137 0 : Pen pen(staffLinesColor);
138 0 : pen.setWidthF(engraving::DefaultStyle::defaultStyle().styleS(Sid::staffLineWidth).val() * params.spatium);
139 0 : painter->setPen(pen);
140 :
141 0 : const double staffHeight = params.spatium * (params.numStaffLines - 1);
142 0 : const double topLineDist = params.rect.center().y() - (staffHeight / 2.0);
143 :
144 : // lines bounded horizontally by edge of target (with small margin)
145 0 : constexpr double margin = 3.0;
146 0 : const double x1 = params.rect.left() + margin;
147 0 : const double x2 = params.rect.right() - margin;
148 :
149 : // draw staff lines with middle line centered vertically on target
150 0 : double y = topLineDist;
151 0 : for (int i = 0; i < params.numStaffLines; ++i) {
152 0 : painter->drawLine(LineF(x1, y, x2, y));
153 0 : y += params.spatium;
154 : }
155 :
156 0 : painter->restore();
157 0 : return topLineDist;
158 0 : }
|