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 "notation.h"
23 :
24 : #include <QGuiApplication>
25 : #include <QScreen>
26 :
27 : #include "engraving/dom/masterscore.h"
28 :
29 : #include "imasternotation.h"
30 : #include "inotationnoteinput.h" // IWYU pragma: keep
31 :
32 : #include "masternotation.h"
33 : #include "notationpainting.h"
34 : #include "notationviewstate.h"
35 : #include "notationsolomutestate.h"
36 : #include "notationinteraction.h"
37 : #include "notationundostack.h"
38 : #include "notationstyle.h"
39 : #include "notationelements.h"
40 : #include "notationaccessibility.h"
41 : #include "notationmidiinput.h"
42 : #include "notationparts.h"
43 : #include "notationtypes.h"
44 :
45 : #include "log.h"
46 :
47 : using namespace mu::notation;
48 : using namespace mu::engraving;
49 :
50 0 : Notation::Notation(MasterNotation* master, const muse::modularity::ContextPtr& iocCtx, mu::engraving::Score* score)
51 : : muse::Contextable(iocCtx)
52 0 : , m_masterNotation(master)
53 : {
54 0 : m_painting = std::make_shared<NotationPainting>(this);
55 0 : m_viewState = std::make_shared<NotationViewState>(this, iocCtx);
56 0 : m_soloMuteState = std::make_shared<NotationSoloMuteState>();
57 0 : m_undoStack = std::make_shared<NotationUndoStack>(this, m_notationChanged);
58 0 : m_interaction = std::make_shared<NotationInteraction>(this, m_undoStack);
59 0 : m_midiInput = std::make_shared<NotationMidiInput>(this, m_interaction, m_undoStack, iocContext());
60 0 : m_accessibility = std::make_shared<NotationAccessibility>(this);
61 0 : m_style = std::make_shared<NotationStyle>(this, m_undoStack);
62 0 : m_parts = std::make_shared<NotationParts>(this, m_interaction, m_undoStack, m_style);
63 0 : m_elements = std::make_shared<NotationElements>(this);
64 :
65 0 : m_interaction->noteInput()->noteAdded().onNotify(this, [this]() {
66 0 : notifyAboutNotationChanged();
67 0 : });
68 :
69 0 : m_interaction->dragChanged().onNotify(this, [this]() {
70 0 : notifyAboutNotationChanged();
71 0 : });
72 :
73 0 : m_interaction->textEditingChanged().onNotify(this, [this]() {
74 0 : notifyAboutNotationChanged();
75 0 : });
76 :
77 0 : m_interaction->dropChanged().onNotify(this, [this]() {
78 0 : notifyAboutNotationChanged();
79 0 : });
80 :
81 0 : m_midiInput->notesReceived().onReceive(this, [this](const std::vector<const Note*>&){
82 0 : notifyAboutNotationChanged();
83 0 : });
84 :
85 0 : m_style->styleChanged().onNotify(this, [this]() {
86 0 : notifyAboutNotationChanged();
87 0 : });
88 :
89 0 : m_parts->partsChanged().onNotify(this, [this]() {
90 0 : notifyAboutNotationChanged();
91 0 : });
92 :
93 0 : configuration()->canvasOrientation().ch.onReceive(this, [this](muse::Orientation) {
94 0 : if (m_score && m_score->autoLayoutEnabled()) {
95 0 : m_score->doLayout();
96 : }
97 0 : });
98 :
99 0 : setScore(score);
100 0 : }
101 :
102 0 : Notation::~Notation()
103 : {
104 : //! Note Dereference internal pointers before the deallocation of mu::engraving::Score* in order to prevent access to dereferenced object
105 : //! Makes sense to use std::shared_ptr<mu::engraving::Score*> ubiquitous instead of the raw pointers
106 0 : m_parts = nullptr;
107 0 : m_undoStack = nullptr;
108 0 : m_interaction = nullptr;
109 0 : m_midiInput = nullptr;
110 0 : m_accessibility = nullptr;
111 0 : m_style = nullptr;
112 0 : m_elements = nullptr;
113 0 : m_painting = nullptr;
114 :
115 : //! NOTE: The master score will be deleted later from ~EngravingProject()
116 : //! Its excerpts will be deleted directly in ~MasterScore()
117 0 : m_score = nullptr;
118 0 : }
119 :
120 0 : const muse::modularity::ContextPtr& Notation::iocContext() const
121 : {
122 0 : return muse::Contextable::iocContext();
123 : }
124 :
125 0 : mu::project::INotationProject* Notation::project() const
126 : {
127 0 : return m_masterNotation ? m_masterNotation->project() : nullptr;
128 : }
129 :
130 0 : IMasterNotationPtr Notation::masterNotation() const
131 : {
132 0 : return m_masterNotation->shared_from_this();
133 : }
134 :
135 0 : void Notation::setScore(Score* score)
136 : {
137 0 : if (m_score == score) {
138 0 : return;
139 : }
140 :
141 0 : m_score = score;
142 0 : m_scoreInited.notify();
143 : }
144 :
145 0 : muse::async::Notification Notation::scoreInited() const
146 : {
147 0 : return m_scoreInited;
148 : }
149 :
150 0 : QString Notation::name() const
151 : {
152 0 : return m_score ? m_score->name().toQString() : QString();
153 : }
154 :
155 0 : QString Notation::projectName() const
156 : {
157 0 : return m_score ? m_score->masterScore()->name().toQString() : QString();
158 : }
159 :
160 0 : QString Notation::projectNameAndPartName() const
161 : {
162 0 : if (!m_score) {
163 0 : return QString();
164 : }
165 :
166 0 : QString result = m_score->masterScore()->name();
167 0 : if (!m_score->isMaster()) {
168 0 : result += " - " + m_score->name().toQString();
169 : }
170 :
171 0 : return result;
172 0 : }
173 :
174 0 : QString Notation::workTitle() const
175 : {
176 0 : if (!m_score) {
177 0 : return QString();
178 : }
179 :
180 0 : QString workTitle = m_score->metaTag(u"workTitle");
181 0 : if (workTitle.isEmpty()) {
182 0 : return m_score->masterScore()->name();
183 : }
184 :
185 0 : return workTitle;
186 0 : }
187 :
188 0 : QString Notation::projectWorkTitle() const
189 : {
190 0 : if (!m_score) {
191 0 : return QString();
192 : }
193 :
194 0 : QString workTitle = m_score->masterScore()->metaTag(u"workTitle");
195 0 : if (workTitle.isEmpty()) {
196 0 : return m_score->masterScore()->name();
197 : }
198 :
199 0 : return workTitle;
200 0 : }
201 :
202 0 : QString Notation::projectWorkTitleAndPartName() const
203 : {
204 0 : if (!m_score) {
205 0 : return QString();
206 : }
207 :
208 0 : QString result = projectWorkTitle();
209 0 : if (!m_score->isMaster()) {
210 0 : result += " - " + name();
211 : }
212 :
213 0 : return result;
214 0 : }
215 :
216 0 : bool Notation::isOpen() const
217 : {
218 0 : const Score* s = score();
219 0 : return s && s->isOpen();
220 : }
221 :
222 0 : void Notation::setIsOpen(bool open)
223 : {
224 0 : if (isOpen() == open) {
225 0 : return;
226 : }
227 :
228 0 : Score* s = score();
229 0 : IF_ASSERT_FAILED(s) {
230 0 : return;
231 : }
232 :
233 0 : s->setIsOpen(open);
234 0 : m_openChanged.notify();
235 : }
236 :
237 0 : muse::async::Notification Notation::openChanged() const
238 : {
239 0 : return m_openChanged;
240 : }
241 :
242 0 : bool Notation::hasVisibleParts() const
243 : {
244 0 : if (!m_parts || !m_parts->hasParts()) {
245 0 : return false;
246 : }
247 :
248 0 : for (const Part* part : m_parts->partList()) {
249 0 : if (part->show()) {
250 0 : return true;
251 : }
252 0 : }
253 :
254 0 : return false;
255 : }
256 :
257 0 : bool Notation::isMaster() const
258 : {
259 0 : return m_score->isMaster();
260 : }
261 :
262 0 : void Notation::notifyAboutNotationChanged(const muse::RectF& updateRect)
263 : {
264 0 : m_notationChanged.send(updateRect);
265 0 : }
266 :
267 0 : void Notation::setViewMode(const ViewMode& viewMode)
268 : {
269 0 : m_painting->setViewMode(viewMode);
270 0 : }
271 :
272 0 : muse::async::Notification Notation::viewModeChanged() const
273 : {
274 0 : return m_painting->viewModeChanged();
275 : }
276 :
277 0 : ViewMode Notation::viewMode() const
278 : {
279 0 : return m_painting->viewMode();
280 : }
281 :
282 0 : INotationPaintingPtr Notation::painting() const
283 : {
284 0 : return m_painting;
285 : }
286 :
287 0 : INotationViewStatePtr Notation::viewState() const
288 : {
289 0 : return m_viewState;
290 : }
291 :
292 0 : INotationSoloMuteStatePtr Notation::soloMuteState() const
293 : {
294 0 : return m_soloMuteState;
295 : }
296 :
297 0 : INotationInteractionPtr Notation::interaction() const
298 : {
299 0 : return m_interaction;
300 : }
301 :
302 0 : INotationMidiInputPtr Notation::midiInput() const
303 : {
304 0 : return m_midiInput;
305 : }
306 :
307 0 : INotationUndoStackPtr Notation::undoStack() const
308 : {
309 0 : return m_undoStack;
310 : }
311 :
312 0 : INotationElementsPtr Notation::elements() const
313 : {
314 0 : return m_elements;
315 : }
316 :
317 0 : INotationStylePtr Notation::style() const
318 : {
319 0 : return m_style;
320 : }
321 :
322 0 : muse::async::Channel<muse::RectF> Notation::notationChanged() const
323 : {
324 0 : return m_notationChanged;
325 : }
326 :
327 0 : INotationAccessibilityPtr Notation::accessibility() const
328 : {
329 0 : return m_accessibility;
330 : }
331 :
332 0 : INotationPartsPtr Notation::parts() const
333 : {
334 0 : return m_parts;
335 : }
336 :
337 0 : Score* Notation::score() const
338 : {
339 0 : return m_score;
340 : }
|