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 <QtEvents>
25 :
26 : #include "../../../internal/inotationviewcontroller.h"
27 :
28 : #include "modularity/ioc.h"
29 :
30 : #include "async/asyncable.h"
31 :
32 : #include "project/iprojectsession.h"
33 :
34 : #include "notation/inotationinteraction.h"
35 : #include "notation/inotationplayback.h"
36 : #include "notation/inotationconfiguration.h"
37 : #include "notation/inotationcontextconfiguration.h"
38 : #include "notation/types/viewmode.h"
39 :
40 : #include "notationscene/inotationcommandscontroller.h"
41 :
42 : #include "playback/iplaybackcontroller.h"
43 :
44 : #include "global/iglobalconfiguration.h"
45 : #include "ui/idragcontroller.h"
46 : #include "ui/iuiconfiguration.h"
47 : #include "rcommand/icommanddispatcher.h"
48 :
49 : #include "abstractelementpopupmodel.h"
50 :
51 : class QQuickItem;
52 :
53 : namespace mu::notation {
54 : class IControlledView
55 : {
56 : public:
57 12 : virtual ~IControlledView() = default;
58 :
59 : virtual qreal width() const = 0;
60 : virtual qreal height() const = 0;
61 :
62 : virtual muse::PointF viewportTopLeft() const = 0;
63 :
64 : //! muse::Returns true if the canvas has been moved
65 : virtual bool moveCanvas(qreal dx, qreal dy) = 0;
66 : virtual void moveCanvasHorizontal(qreal dx) = 0;
67 : virtual void moveCanvasVertical(qreal dy) = 0;
68 :
69 : virtual muse::RectF notationContentRect() const = 0;
70 : virtual qreal currentScaling() const = 0;
71 : virtual void setScaling(qreal scaling, const muse::PointF& pos, bool overrideZoomType = true) = 0;
72 :
73 : virtual muse::PointF toLogical(const muse::PointF& p) const = 0;
74 : virtual muse::PointF toLogical(const QPointF& p) const = 0;
75 : virtual muse::PointF fromLogical(const muse::PointF& r) const = 0;
76 : virtual muse::RectF fromLogical(const muse::RectF& r) const = 0;
77 :
78 : virtual bool isNoteEnterMode() const = 0;
79 :
80 : virtual void showContextMenu(const ElementType& elementType, const QPointF& pos) = 0;
81 : virtual void hideContextMenu() = 0;
82 :
83 : virtual void showSearch() = 0;
84 :
85 : virtual void showElementPopup(const ElementType& elementType) = 0;
86 : virtual void hideElementPopup(const ElementType& elementType) = 0;
87 : virtual void hideElementPopup(PopupModelType modelType = PopupModelType::TYPE_UNDEFINED) = 0;
88 : virtual void toggleElementPopup(const ElementType& elementType) = 0;
89 :
90 : virtual bool elementPopupIsOpen(const ElementType& elementType) const = 0;
91 :
92 : virtual INotationInteractionPtr notationInteraction() const = 0;
93 : virtual INotationPlaybackPtr notationPlayback() const = 0;
94 :
95 : virtual QQuickItem* asItem() = 0;
96 :
97 : virtual void scheduleRedraw(const muse::RectF& rect = muse::RectF()) = 0;
98 : };
99 :
100 : class NotationViewInputController : public INotationViewController, public muse::Contextable, public muse::async::Asyncable
101 : {
102 : public:
103 : muse::GlobalInject<muse::IGlobalConfiguration> globalConfiguration;
104 : muse::GlobalInject<INotationConfiguration> configuration;
105 : muse::GlobalInject<muse::ui::IUiConfiguration> uiConfiguration;
106 : muse::ContextInject<INotationContextConfiguration> contextConfiguration = { this };
107 : muse::ContextInject<muse::rcommand::ICommandDispatcher> commandDispatcher = { this };
108 : muse::ContextInject<playback::IPlaybackController> playbackController = { this };
109 : muse::ContextInject<project::IProjectSession> projectSession = { this };
110 : muse::ContextInject<muse::ui::IDragController> dragController = { this };
111 : muse::ContextInject<INotationCommandsController> commandsController = { this };
112 :
113 : public:
114 : NotationViewInputController(IControlledView* view, const muse::modularity::ContextPtr& iocCtx);
115 : ~NotationViewInputController();
116 :
117 : void init();
118 : void deinit();
119 :
120 : // INotationViewController
121 : void zoomIn() override;
122 : void zoomOut() override;
123 : void zoomToPageWidth() override;
124 : void zoomToWholePage() override;
125 : void zoomToTwoPages() override;
126 : void setZoom(int zoomPercentage) override;
127 :
128 : void setViewMode(ViewMode viewMode) override;
129 :
130 : void nextScreen() override;
131 : void previousScreen() override;
132 : void nextPage() override;
133 : void previousPage() override;
134 : void startOfScore() override;
135 : void endOfScore() override;
136 :
137 : void openContextMenuOfSelection() override;
138 :
139 : void togglePopupForItemIfSupports(const EngravingItem* item) override;
140 :
141 : void showSearch() override;
142 :
143 : void redrawView() override;
144 : // -----------------------
145 :
146 : void initZoom();
147 : void updateZoomAfterSizeChange();
148 :
149 : void initCanvasPos();
150 :
151 : bool readonly() const;
152 : void setReadonly(bool readonly);
153 :
154 : void pinchToZoom(qreal scaleFactor, const QPointF& pos);
155 : void wheelEvent(QWheelEvent* event);
156 : void mousePressEvent(QMouseEvent* event);
157 : void mouseMoveEvent(QMouseEvent* event);
158 : void mouseReleaseEvent(QMouseEvent* event);
159 : void mouseDoubleClickEvent(QMouseEvent* event);
160 : void hoverMoveEvent(QHoverEvent* event);
161 : void hoverLeaveEvent(QHoverEvent* event);
162 : bool shortcutOverrideEvent(QKeyEvent* event);
163 : void keyPressEvent(QKeyEvent* event);
164 : void keyReleaseEvent(QKeyEvent* event);
165 : void inputMethodEvent(QInputMethodEvent* event);
166 :
167 : bool canHandleInputMethodQuery(Qt::InputMethodQuery query) const;
168 : QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
169 :
170 0 : bool ignoreNextMouseContextMenuEvent() const { return m_ignoreNextMouseContextMenuEvent; }
171 :
172 : void dragEnterEvent(QDragEnterEvent* event);
173 : void dragLeaveEvent(QDragLeaveEvent* event);
174 : void dragMoveEvent(QDragMoveEvent* event);
175 : void dropEvent(QDropEvent* event);
176 :
177 : ElementType selectionType() const;
178 : muse::PointF selectionElementPos() const;
179 :
180 : private:
181 : INotationPtr currentNotation() const;
182 : INotationStylePtr notationStyle() const;
183 : INotationInteractionPtr viewInteraction() const;
184 : const INotationInteraction::HitElementContext& hitElementContext() const;
185 :
186 : void onNotationChanged();
187 :
188 : void doZoomToPageWidth();
189 : void doZoomToWholePage();
190 : void doZoomToTwoPages();
191 : int currentZoomIndex() const;
192 : int currentZoomPercentage() const;
193 : muse::PointF findZoomFocusPoint() const;
194 : void doSetZoom(int zoomPercentage, const muse::PointF& pos);
195 : qreal scalingFromZoomPercentage(int zoomPercentage) const;
196 : int zoomPercentageFromScaling(qreal scaling) const;
197 :
198 : void moveScreen(int direction);
199 : void movePage(int direction);
200 :
201 : void setScaling(qreal scaling, const muse::PointF& pos = muse::PointF(), bool overrideZoomType = true);
202 :
203 : void startDragElements(ElementType elementsType, const muse::PointF& elementsOffset);
204 :
205 : void updateShadowNotePopupVisibility(bool forceHide = false);
206 :
207 : float hitWidth() const;
208 :
209 : struct ClickContext {
210 : muse::PointF logicClickPos;
211 : const QMouseEvent* event = nullptr;
212 : mu::engraving::EngravingItem* hitElement = nullptr;
213 : mu::engraving::staff_idx_t hitStaff = muse::nidx;
214 : bool isHitGrip = false;
215 : };
216 :
217 : void handleClickInNoteInputMode(QMouseEvent* event);
218 : bool mousePress_considerGrip(const ClickContext& ctx); // returns true if event is consumed
219 : bool mousePress_considerDragOutgoingElement(const ClickContext& ctx);
220 : void mousePress_considerSelect(const ClickContext& ctx);
221 : void mousePress_seekSelection(const ClickContext& ctx);
222 : void cycleOverlappingHitElements(const std::vector<EngravingItem*>& hitElements, staff_idx_t hitStaffIndex);
223 : bool mousePress_considerDragOutgoingRange(const ClickContext& ctx);
224 : bool mousePress_considerStartPasteRangeOnRelease(const ClickContext& ctx);
225 : void handleLeftClick(const ClickContext& ctx);
226 : void handleRightClick();
227 : void handleLeftClickRelease(const QPointF& releasePoint);
228 :
229 : bool startTextEditingAllowed() const;
230 : void updateTextCursorPosition();
231 :
232 : bool isAnchorEditingEvent(QKeyEvent* event) const;
233 :
234 : bool tryPercussionShortcut(QKeyEvent* event);
235 :
236 : IControlledView* m_view = nullptr;
237 :
238 : QList<int> m_possibleZoomPercentages;
239 :
240 : bool m_readonly = false;
241 : bool m_isCanvasDragged = false;
242 : bool m_tripleClickPending = false;
243 :
244 : struct MouseDownInfo {
245 : enum DragAction {
246 : DragOutgoingElement,
247 : DragOutgoingRange,
248 : PasteRangeOnRelease,
249 : Other,
250 : Nothing
251 : } dragAction = Other;
252 :
253 : QPointF physicalBeginPoint;
254 : muse::PointF logicalBeginPoint;
255 : } m_mouseDownInfo;
256 :
257 : struct DragMoveEvent {
258 : QPointF position;
259 : Qt::KeyboardModifiers modifiers;
260 : Qt::DropAction dropAction = Qt::DropAction::CopyAction;
261 : QObject* source = nullptr;
262 : };
263 :
264 : bool dropEvent(const DragMoveEvent& event, const QMimeData* mimeData = nullptr);
265 :
266 : std::vector<int> pitchesBeingDragged() const;
267 :
268 : DragMoveEvent m_lastDragMoveEvent;
269 :
270 : const mu::engraving::EngravingItem* m_prevSelectedElement = nullptr;
271 : std::vector<const mu::engraving::EngravingItem*> m_notesBeingDragged;
272 :
273 : bool m_hitElementWasAlreadySingleSelected = false;
274 : bool m_shouldSelectOnLeftClickRelease = false;
275 : bool m_shouldStartEditOnLeftClickRelease = false;
276 : bool m_ignoreNextMouseContextMenuEvent = false;
277 : };
278 : }
|