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) 2021 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 "notationpainting.h"
23 :
24 : #include <QScreen>
25 :
26 : #include "engraving/dom/score.h"
27 :
28 : #include "notation.h"
29 : #include "notationinteraction.h"
30 :
31 : #include "log.h"
32 :
33 : using namespace mu;
34 : using namespace mu::notation;
35 : using namespace mu::engraving;
36 : using namespace muse::draw;
37 :
38 0 : NotationPainting::NotationPainting(Notation* notation)
39 0 : : muse::Contextable(notation->iocContext())
40 0 : , m_notation(notation)
41 : {
42 0 : }
43 :
44 0 : mu::engraving::Score* NotationPainting::score() const
45 : {
46 0 : return m_notation->score();
47 : }
48 :
49 0 : void NotationPainting::setViewMode(const ViewMode& viewMode)
50 : {
51 0 : if (!score()) {
52 0 : return;
53 : }
54 :
55 0 : if (score()->layoutMode() == viewMode) {
56 0 : return;
57 : }
58 :
59 0 : score()->setLayoutMode(viewMode);
60 0 : score()->doLayout();
61 :
62 0 : m_viewModeChanged.notify();
63 0 : m_notation->notifyAboutNotationChanged();
64 : }
65 :
66 0 : ViewMode NotationPainting::viewMode() const
67 : {
68 0 : if (!score()) {
69 0 : return ViewMode::PAGE;
70 : }
71 :
72 0 : return score()->layoutMode();
73 : }
74 :
75 0 : muse::async::Notification NotationPainting::viewModeChanged() const
76 : {
77 0 : return m_viewModeChanged;
78 : }
79 :
80 0 : int NotationPainting::pageCount() const
81 : {
82 0 : if (!score()) {
83 0 : return 0;
84 : }
85 :
86 0 : return static_cast<int>(score()->npages());
87 : }
88 :
89 0 : SizeF NotationPainting::pageSizeInch() const
90 : {
91 0 : return scoreRenderer()->pageSizeInch(score());
92 : }
93 :
94 0 : SizeF NotationPainting::pageSizeInch(const Options& opt) const
95 : {
96 0 : return scoreRenderer()->pageSizeInch(score(), opt);
97 : }
98 :
99 0 : bool NotationPainting::isPaintPageBorder() const
100 : {
101 0 : switch (score()->layoutMode()) {
102 0 : case engraving::LayoutMode::LINE:
103 : case engraving::LayoutMode::HORIZONTAL_FIXED:
104 : case engraving::LayoutMode::SYSTEM:
105 0 : return false;
106 0 : case engraving::LayoutMode::FLOAT:
107 : case engraving::LayoutMode::PAGE: {
108 0 : return !score()->printing();
109 : }
110 : }
111 0 : return false;
112 : }
113 :
114 0 : void NotationPainting::doPaint(Painter* painter, const Options& opt)
115 : {
116 0 : TRACEFUNC;
117 0 : if (!score()) {
118 0 : return;
119 : }
120 :
121 0 : Options myopt = opt;
122 0 : bool printPageBackground = myopt.printPageBackground;
123 0 : myopt.onPaintPageSheet = [this, printPageBackground](Painter* painter, const Page* page, const RectF& pageRect) {
124 0 : paintPageSheet(painter, page, pageRect, printPageBackground);
125 0 : };
126 :
127 0 : scoreRenderer()->paintScore(painter, score(), myopt);
128 :
129 0 : if (!myopt.isPrinting) {
130 0 : rendering::PaintOptions eopt;
131 0 : eopt.isPrinting = myopt.isPrinting;
132 0 : eopt.invertColors = myopt.invertColors;
133 :
134 0 : static_cast<NotationInteraction*>(m_notation->interaction().get())->paint(painter, eopt);
135 0 : }
136 0 : }
137 :
138 0 : void NotationPainting::paintPageSheet(Painter* painter, const Page* page, const RectF& pageRect, bool printPageBackground) const
139 : {
140 0 : TRACEFUNC;
141 0 : if (score()->printing()) {
142 0 : if (!printPageBackground) {
143 0 : return;
144 : }
145 :
146 0 : painter->fillRect(pageRect, Color::WHITE);
147 0 : return;
148 : }
149 :
150 0 : if (configuration()->foregroundUseColor()) {
151 0 : painter->fillRect(pageRect, configuration()->foregroundColor());
152 : } else {
153 0 : const QPixmap& wallpaper = configuration()->foregroundWallpaper();
154 0 : if (!wallpaper.isNull()) {
155 0 : painter->drawTiledPixmap(pageRect, wallpaper);
156 : } else {
157 : //! NOTE We can use the color from the configuration,
158 : //! but in this case I believe it is better to use the "unassigned" color
159 0 : painter->fillRect(pageRect, Color::WHITE);
160 : }
161 : }
162 :
163 0 : if (!isPaintPageBorder()) {
164 0 : return;
165 : }
166 :
167 0 : const double strokeWidth = 0.07 * DPMM;
168 0 : painter->setBrush(BrushStyle::NoBrush);
169 0 : painter->setPen(Pen(configuration()->borderColor(), strokeWidth));
170 0 : painter->drawRect(pageRect);
171 :
172 0 : if (!score()->showPageborders()) {
173 0 : return;
174 : }
175 :
176 0 : RectF pageContentRect = page->ldata()->bbox().adjusted(page->lm(), page->tm(), -page->rm(), -page->bm());
177 :
178 0 : painter->setBrush(BrushStyle::NoBrush);
179 0 : painter->setPen(Pen(engravingConfiguration()->scoreGreyColor(), strokeWidth));
180 0 : painter->drawRect(pageContentRect);
181 :
182 0 : if (!page->isOdd()) {
183 0 : painter->drawLine(pageContentRect.right(), 0.0, pageContentRect.right(), pageContentRect.bottom());
184 : }
185 0 : }
186 :
187 0 : void NotationPainting::paintView(Painter* painter, const RectF& frameRect, bool isPrinting, bool isAutomation)
188 : {
189 0 : Options opt;
190 0 : opt.isSetViewport = false;
191 0 : opt.isMultiPage = true;
192 0 : opt.frameRect = frameRect;
193 0 : opt.deviceDpi = uiConfiguration()->logicalDpi();
194 0 : opt.isPrinting = isPrinting;
195 0 : opt.invertColors = configuration()->shouldInvertScore();
196 :
197 0 : if (isAutomation) {
198 0 : opt.overrideItemColor = [](const EngravingItem* item, Color defaultColor) {
199 0 : if (item->isDynamic() || item->isHairpinSegment()) {
200 0 : return defaultColor;
201 : }
202 0 : defaultColor.setAlpha(defaultColor.alpha() * 0.4f);
203 0 : return defaultColor;
204 0 : };
205 : }
206 :
207 0 : doPaint(painter, opt);
208 0 : }
209 :
210 0 : void NotationPainting::paintPdf(Painter* painter, const Options& opt)
211 : {
212 0 : Q_ASSERT(opt.deviceDpi > 0);
213 0 : Options myopt = opt;
214 0 : myopt.isSetViewport = true;
215 0 : myopt.isMultiPage = false;
216 0 : myopt.isPrinting = true;
217 0 : doPaint(painter, myopt);
218 0 : }
219 :
220 0 : void NotationPainting::paintPrint(Painter* painter, const Options& opt)
221 : {
222 0 : Q_ASSERT(opt.deviceDpi > 0);
223 0 : Options myopt = opt;
224 0 : myopt.isSetViewport = true;
225 0 : myopt.isMultiPage = false;
226 0 : myopt.isPrinting = true;
227 0 : doPaint(painter, myopt);
228 0 : }
229 :
230 0 : void NotationPainting::paintPng(Painter* painter, const Options& opt)
231 : {
232 0 : Q_ASSERT(opt.deviceDpi > 0);
233 0 : Options myopt = opt;
234 0 : myopt.isSetViewport = true;
235 0 : myopt.isMultiPage = false;
236 0 : myopt.isPrinting = true;
237 0 : doPaint(painter, myopt);
238 0 : }
|