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 : #pragma once
23 :
24 : #include <QTimer>
25 : #include <QElapsedTimer>
26 : #include <qqmlintegration.h>
27 :
28 : #include "uicomponents/qml/Muse/UiComponents/quickpaintedview.h"
29 :
30 : #include "async/asyncable.h"
31 :
32 : #include "modularity/ioc.h"
33 : #include "notation/inotationconfiguration.h"
34 : #include "notation/inotationcontextconfiguration.h"
35 : #include "project/iprojectsession.h"
36 : #include "ui/imainwindow.h"
37 : #include "ui/iuiconfiguration.h"
38 : #include "playback/iplaybackcontroller.h"
39 :
40 : #include "notationscene/inotationsceneconfiguration.h"
41 : #include "notationviewinputcontroller.h"
42 : #include "notationautomationcontroller.h"
43 : #include "noteinputcursor.h"
44 : #include "notationruler.h"
45 : #include "playbackcursor.h"
46 : #include "loopmarker.h"
47 : #include "continuouspanel.h"
48 : #include "abstractelementpopupmodel.h"
49 :
50 : namespace mu::notation {
51 : class AbstractNotationPaintView : public muse::uicomponents::QuickPaintedView, public IControlledView, public muse::Contextable,
52 : public muse::async::Asyncable
53 : {
54 : Q_OBJECT
55 : QML_ELEMENT;
56 : QML_UNCREATABLE("Not creatable as it is an abstract base class")
57 :
58 : Q_PROPERTY(qreal startHorizontalScrollPosition READ startHorizontalScrollPosition NOTIFY horizontalScrollChanged)
59 : Q_PROPERTY(qreal horizontalScrollbarSize READ horizontalScrollbarSize NOTIFY horizontalScrollChanged)
60 : Q_PROPERTY(qreal startVerticalScrollPosition READ startVerticalScrollPosition NOTIFY verticalScrollChanged)
61 : Q_PROPERTY(qreal verticalScrollbarSize READ verticalScrollbarSize NOTIFY verticalScrollChanged)
62 :
63 : Q_PROPERTY(QVariant matrix READ matrix NOTIFY matrixChanged)
64 : Q_PROPERTY(QRectF viewport READ viewport_property NOTIFY viewportChanged)
65 :
66 : Q_PROPERTY(bool publishMode READ publishMode WRITE setPublishMode NOTIFY publishModeChanged)
67 : Q_PROPERTY(bool automationMode READ automationMode NOTIFY automationModeChanged)
68 :
69 : Q_PROPERTY(bool isMainView READ isMainView WRITE setIsMainView NOTIFY isMainViewChanged)
70 :
71 : Q_PROPERTY(bool readOnly READ readonly WRITE setReadonly NOTIFY readonlyChanged)
72 :
73 : muse::GlobalInject<INotationConfiguration> notationConfiguration;
74 : muse::GlobalInject<INotationSceneConfiguration> configuration;
75 : muse::GlobalInject<engraving::IEngravingConfiguration> engravingConfiguration;
76 : muse::GlobalInject<muse::ui::IUiConfiguration> uiConfiguration;
77 : muse::ContextInject<INotationContextConfiguration> notationContextConfiguration = { this };
78 : muse::ContextInject<project::IProjectSession> projectSession = { this };
79 : muse::ContextInject<muse::ui::IMainWindow> mainWindow = { this };
80 : muse::ContextInject<playback::IPlaybackState> playbackState = { this };
81 :
82 : public:
83 : explicit AbstractNotationPaintView(QQuickItem* parent = nullptr);
84 : ~AbstractNotationPaintView() override;
85 :
86 : Q_INVOKABLE void load();
87 :
88 : Q_INVOKABLE void scrollHorizontal(qreal position);
89 : Q_INVOKABLE void scrollVertical(qreal position);
90 :
91 : Q_INVOKABLE void zoomIn();
92 : Q_INVOKABLE void zoomOut();
93 :
94 : Q_INVOKABLE void selectOnNavigationActive();
95 :
96 : Q_INVOKABLE void forceFocusIn();
97 :
98 : Q_INVOKABLE void onContextMenuIsOpenChanged(bool open);
99 0 : Q_INVOKABLE void onElementPopupIsOpenChanged(const PopupModelType& popupType = PopupModelType::TYPE_UNDEFINED);
100 :
101 : Q_INVOKABLE void setPlaybackCursorItem(QQuickItem* cursor);
102 :
103 : qreal width() const override;
104 : qreal height() const override;
105 :
106 : muse::PointF toLogical(const muse::PointF& point) const override;
107 : muse::PointF toLogical(const QPointF& point) const override;
108 : muse::RectF toLogical(const muse::RectF& rect) const;
109 :
110 : muse::PointF fromLogical(const muse::PointF& point) const override;
111 : muse::RectF fromLogical(const muse::RectF& rect) const override;
112 :
113 : Q_INVOKABLE bool moveCanvas(qreal dx, qreal dy) override;
114 : void moveCanvasVertical(qreal dy) override;
115 : void moveCanvasHorizontal(qreal dx) override;
116 :
117 : qreal currentScaling() const override;
118 : void setScaling(qreal scaling, const muse::PointF& pos, bool overrideZoomType = true) override;
119 : void scale(qreal factor, const muse::PointF& pos, bool overrideZoomType = true);
120 :
121 : Q_INVOKABLE void pinchToZoom(qreal scaleFactor, const QPointF& pos);
122 :
123 : bool isNoteEnterMode() const override;
124 :
125 : void showContextMenu(const ElementType& elementType, const QPointF& pos) override;
126 : void hideContextMenu() override;
127 :
128 : void showSearch() override;
129 :
130 : void showElementPopup(const ElementType& elementType) override;
131 : void hideElementPopup(const ElementType& elementType) override;
132 : void hideElementPopup(PopupModelType modelType = PopupModelType::TYPE_UNDEFINED) override;
133 : void toggleElementPopup(const ElementType& elementType) override;
134 :
135 : bool elementPopupIsOpen(const ElementType& elementType) const override;
136 :
137 : INotationInteractionPtr notationInteraction() const override;
138 : INotationPlaybackPtr notationPlayback() const override;
139 :
140 : QQuickItem* asItem() override;
141 :
142 : void scheduleRedraw(const muse::RectF& rect = muse::RectF()) override;
143 :
144 : qreal startHorizontalScrollPosition() const;
145 : qreal horizontalScrollbarSize() const;
146 : qreal startVerticalScrollPosition() const;
147 : qreal verticalScrollbarSize() const;
148 :
149 : QVariant matrix() const;
150 :
151 : muse::PointF viewportTopLeft() const override;
152 : muse::RectF viewport() const;
153 : QRectF viewport_property() const;
154 :
155 : bool publishMode() const;
156 : void setPublishMode(bool arg);
157 :
158 : bool automationMode() const;
159 :
160 : bool isMainView() const;
161 : void setIsMainView(bool isMainView);
162 :
163 : bool readonly() const;
164 : void setReadonly(bool readonly);
165 :
166 : signals:
167 : void showContextMenuRequested(int elementType, const QPointF& viewPos);
168 : void hideContextMenuRequested();
169 :
170 : void showSearchRequested();
171 :
172 : void showElementPopupRequested(mu::notation::AbstractElementPopupModel::PopupModelType modelType);
173 : void hideElementPopupRequested();
174 : void isPopupOpenChanged(bool isPopupOpen);
175 :
176 : void horizontalScrollChanged();
177 : void verticalScrollChanged();
178 :
179 : void backgroundColorChanged(QColor color);
180 : void matrixChanged();
181 : void viewportChanged();
182 : void publishModeChanged();
183 : void automationModeChanged();
184 :
185 : void activeFocusRequested();
186 :
187 : void isMainViewChanged(bool isMainView);
188 :
189 : void readonlyChanged();
190 :
191 : protected:
192 : INotationPtr notation() const;
193 : void setNotation(INotationPtr notation);
194 :
195 : NotationViewInputController* inputController() const;
196 :
197 : void setMatrix(const muse::draw::Transform& matrix);
198 :
199 : void moveCanvasToCenter();
200 : bool moveCanvasToPosition(const muse::PointF& logicPos);
201 :
202 : muse::RectF notationContentRect() const override;
203 :
204 : // Draw
205 : void paint(QPainter* painter) override;
206 :
207 : virtual void onNotationSetup();
208 :
209 : virtual void onLoadNotation(INotationPtr notation);
210 : virtual void onUnloadNotation(INotationPtr notation);
211 :
212 : virtual void initZoomAndPosition();
213 :
214 : virtual void onMatrixChanged(const muse::draw::Transform& oldMatrix, const muse::draw::Transform& newMatrix, bool overrideZoomType);
215 :
216 : protected slots:
217 : virtual void onViewSizeChanged();
218 :
219 : private:
220 : INotationNoteInputPtr notationNoteInput() const;
221 : INotationElementsPtr notationElements() const;
222 : INotationStylePtr notationStyle() const;
223 : INotationSelectionPtr notationSelection() const;
224 : INotationAutomationPtr notationAutomation() const;
225 :
226 : void clear();
227 : void initBackground();
228 : void initNavigatorOrientation();
229 :
230 : void onCurrentNotationChanged();
231 : bool isInited() const;
232 :
233 : bool doMoveCanvas(qreal dx, qreal dy);
234 :
235 : muse::RectF correctDrawRect(const muse::RectF& rect) const;
236 :
237 : // Input
238 : void wheelEvent(QWheelEvent* event) override;
239 : void mousePressEvent(QMouseEvent* event) override;
240 : void mouseMoveEvent(QMouseEvent* event) override;
241 : void mouseDoubleClickEvent(QMouseEvent* event) override;
242 : void mouseReleaseEvent(QMouseEvent* event) override;
243 : void hoverMoveEvent(QHoverEvent* event) override;
244 : void hoverLeaveEvent(QHoverEvent* event) override;
245 : bool event(QEvent* event) override;
246 : bool shortcutOverride(QKeyEvent* event);
247 : void keyPressEvent(QKeyEvent* event) override;
248 : void keyReleaseEvent(QKeyEvent* event) override;
249 : void dragEnterEvent(QDragEnterEvent* event) override;
250 : void dragLeaveEvent(QDragLeaveEvent* event) override;
251 : void dragMoveEvent(QDragMoveEvent* event) override;
252 : void dropEvent(QDropEvent* event) override;
253 : void inputMethodEvent(QInputMethodEvent* event) override;
254 : QVariant inputMethodQuery(Qt::InputMethodQuery query) const override;
255 :
256 : bool ensureViewportInsideScrollableArea();
257 :
258 : muse::RectF scrollableAreaRect() const;
259 :
260 : qreal horizontalScrollableSize() const;
261 : qreal verticalScrollableSize() const;
262 :
263 : bool adjustCanvasPosition(const muse::RectF& logicRect, bool adjustVertically = true);
264 : bool adjustCanvasPositionSmoothPan(const muse::RectF& cursorRect);
265 :
266 : void onNoteInputStateChanged();
267 :
268 : void onShowItemRequested(const INotationInteraction::ShowItemRequest& request);
269 :
270 : void onPlayingChanged();
271 : void updatePlaybackCursorInterpolated();
272 : void movePlaybackCursor(muse::midi::tick_t tick);
273 : bool shouldAdjustCanvasVerticallyDuringPlayback(const muse::RectF& cursorRect);
274 :
275 : void onPlaybackCursorRectChanged();
276 :
277 : void updateLoopMarkers();
278 : void updateShadowNoteVisibility();
279 :
280 : const Page* pageByPoint(const muse::PointF& point) const;
281 : muse::PointF alignToCurrentPageBorder(const muse::RectF& showRect, const muse::PointF& pos) const;
282 :
283 : void paintBackground(const muse::RectF& rect, muse::draw::Painter* painter);
284 :
285 : muse::PointF canvasCenter() const;
286 : std::pair<qreal, qreal> constraintCanvas(qreal dx, qreal dy) const;
287 :
288 : INotationPtr m_notation;
289 : muse::draw::Transform m_matrix;
290 :
291 : bool m_loadCalled = false;
292 : std::unique_ptr<NotationViewInputController> m_inputController;
293 : QQuickItem* m_automationLinesContainer = nullptr;
294 : std::unique_ptr<NotationAutomationController> m_notationAutomationController;
295 : std::unique_ptr<PlaybackCursor> m_playbackCursor;
296 : std::unique_ptr<NoteInputCursor> m_noteInputCursor;
297 : std::unique_ptr<NotationRuler> m_ruler;
298 : std::unique_ptr<LoopMarker> m_loopInMarker;
299 : std::unique_ptr<LoopMarker> m_loopOutMarker;
300 : std::unique_ptr<ContinuousPanel> m_continuousPanel;
301 :
302 : qreal m_previousVerticalScrollPosition = 0;
303 : qreal m_previousHorizontalScrollPosition = 0;
304 :
305 : bool m_readonly = false;
306 : bool m_publishMode = false;
307 : int m_lastAcceptedKey = -1;
308 : bool m_isMainView = false;
309 :
310 : bool m_autoScrollEnabled = true;
311 : bool m_isAutomaticallyPanEnabled = false;
312 : bool m_isSmoothPanningEnabled = false;
313 : QTimer m_enableAutoScrollTimer;
314 :
315 : PopupModelType m_currentElementPopupType = PopupModelType::TYPE_UNDEFINED;
316 : bool m_isContextMenuOpen = false;
317 :
318 : muse::RectF m_shadowNoteRect;
319 : muse::RectF m_previewMeasureRect;
320 :
321 : struct PageCache {
322 : const Page* page = nullptr;
323 : std::optional<bool> adjustVerticallyDuringPlayback;
324 :
325 0 : void clear()
326 : {
327 0 : *this = PageCache();
328 0 : }
329 : } mutable m_pageCache;
330 :
331 : QQuickItem* m_playbackCursorItem = nullptr;
332 :
333 : muse::secs_t m_lastPlaybackPosition = 0.;
334 : qint64 m_lastPlaybackPositionUpdateTimeNs = 0;
335 : QTimer m_updatePlaybackCursorInterpolatedTimer;
336 : QElapsedTimer m_elapsedTimer;
337 : };
338 : }
|