1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 #ifndef RG_NOTATION_WIDGET_H
19 #define RG_NOTATION_WIDGET_H
20 
21 #include "StaffLayout.h"
22 
23 #include "gui/general/AutoScroller.h"
24 #include "base/NotationTypes.h"
25 #include "gui/general/SelectionManager.h"
26 #include "gui/widgets/Thumbwheel.h"
27 
28 #include <QWidget>
29 #include <QPushButton>
30 #include <QBoxLayout>
31 #include <QLabel>
32 
33 #include <vector>
34 
35 class QGridLayout;
36 class QString;
37 class QGraphicsScene;
38 class QTimer;
39 
40 namespace Rosegarden
41 {
42 
43 class Device;
44 class RosegardenDocument;
45 class Segment;
46 class NotationScene;
47 class Note;
48 class NotationToolBox;
49 class NotationTool;
50 class NotationMouseEvent;
51 class NotationStaff;
52 class ViewSegment;
53 class NotationElement;
54 class Panner;
55 class Panned;
56 class ZoomableRulerScale;
57 class StandardRuler;
58 class TempoRuler;
59 class ChordNameRuler;
60 class RawNoteRuler;
61 class ControlRulerWidget;
62 class HeadersGroup;
63 
64 class NotationWidget : public QWidget,
65                        public SelectionManager
66 {
67     Q_OBJECT
68 
69 public:
70     NotationWidget();
71     ~NotationWidget() override;
ExecInitGatherMerge(GatherMerge * node,EState * estate,int eflags)72 
73     // Delete and zero the pointer members if they are allocated.  For
74     // 2-stage deletion.
75     void clearAll();
76 
77     void setSegments(RosegardenDocument *document,
78                      std::vector<Segment *> segments);
79 
80     void scrollToTopLeft();
81 
82     NotationScene *getScene() { return m_scene; }
83     Panned *getView() { return m_view; }
84     ControlRulerWidget *getControlsWidget()
85         { return m_controlRulerWidget; }
86 
87     EventSelection *getSelection() const override;
88     void setSelection(EventSelection* s, bool preview) override;
89 
90     timeT getInsertionTime() const;
91 
92     bool isInChordMode() { return m_chordMode; }
93     bool isInTupletMode() { return m_tupletMode; }
94     bool isInGraceMode() { return m_graceMode; }
95 
96     void setChordMode(bool state = true) { m_chordMode = state; }
97     void setTupletMode(bool state = true) { m_tupletMode = state;}
98     void setTupledCount(const unsigned short n = 2) { m_tupledCount = n;}
99     void setUntupledCount(const unsigned short d = 3) { m_untupledCount = d;}
100     unsigned int getTupledCount() const { return  m_tupledCount;}
101     unsigned int getUntupledCount() const { return  m_untupledCount;}
102     void setGraceMode(bool state = true) { m_graceMode = state; }
103 
104     bool getPlayTracking() const { return m_playTracking; }
105 
106     NotationToolBox *getToolBox() { return m_toolBox; }
107     NotationTool *getCurrentTool() const;
108 
109     void setCanvasCursor(QCursor cursor);
110 
111     Segment *getCurrentSegment();
112     Device  *getCurrentDevice();
113     bool segmentsContainNotes() const;
114 
115     void setTempoRulerVisible(bool visible);
116     void setChordNameRulerVisible(bool visible);
117     void setRawNoteRulerVisible(bool visible);
118     void setHeadersVisible(bool visible);
119     void setHeadersVisibleIfNeeded();
120     void toggleHeadersView();
121 
122     double getViewLeftX();
123     double getViewRightX();
124     int getNotationViewWidth();
125     double getNotationSceneHeight();
126 
127     void suspendLayoutUpdates();
128     void resumeLayoutUpdates();
129 
130     void setPointerPosition(timeT);
131 
132     void setHorizontalZoomFactor(double factor);
133     void setVerticalZoomFactor(double factor);
134 
135     double getHorizontalZoomFactor() const;
136     double getVerticalZoomFactor() const;
137 
138     // used in pitchtracker
139     void addWidgetToBottom(QWidget *bottomWidget);
140 
141     void updateSegmentChangerBackground();
142     void updatePointerPosition(bool moveView = false);
143 
144 signals:
145     void sceneNeedsRebuilding();
146     void toolChanged(QString);
147     void hoveredOverNoteChanged(QString);
148     void headersVisibilityChanged(bool);
149     void showContextHelp(const QString &);
150 
151 public slots:
152     void slotSetTool(QString name);
153     void slotSetSelectTool();
154     void slotSetSelectNoTiesTool();
155     void slotSetEraseTool();
156     void slotSetNoteRestInserter();
157     void slotSetNoteInserter();
158     void slotSetRestInserter();
159     void slotSetInsertedNote(Note::Type type, int dots);
160     void slotSetAccidental(Accidental accidental, bool follow);
161     void slotSetClefInserter();
162     void slotSetInsertedClef(Clef type);
163     void slotSetTextInserter();
164     void slotSetGuitarChordInserter();
165     void slotSetLinearMode();
166     void slotSetContinuousPageMode();
167     void slotSetMultiPageMode();
168     void slotSetFontName(QString);
169     void slotSetFontSize(int);
170     void slotSetPlayTracking(bool);
171     void slotTogglePlayTracking();
172     void slotSetSymbolInserter();
173     void slotSetInsertedSymbol(Symbol type);
174 
175     void slotToggleVelocityRuler();
176     void slotTogglePitchbendRuler();
177     void slotAddControlRuler(QAction*);
178 
179     void slotRegenerateHeaders();
180 
181 private:
182     void showEvent(QShowEvent * event) override;
183     void hideOrShowRulers();
184     bool linearMode() const;   // Return true when notation page layout is linear
185     void updatePointer(timeT t);
186 
187 private slots:
ExecGatherMerge(PlanState * pstate)188     void slotDispatchMousePress(const NotationMouseEvent *);
189     void slotDispatchMouseRelease(const NotationMouseEvent *);
190     void slotDispatchMouseMove(const NotationMouseEvent *);
191     void slotDispatchMouseDoubleClick(const NotationMouseEvent *);
192     void slotDispatchWheelTurned(int, const NotationMouseEvent *);
193 
194     void slotPointerPositionChanged(timeT t);
195 
196     // Standard Ruler
197     void slotStandardRulerDrag(timeT t);
198     void slotSRStartMouseMove();
199     void slotSRStopMouseMove();
200 
201     // ControlRulerWidget
202     void slotCRWMousePress();
203     void slotCRWMouseMove(FollowMode followMode);
204     void slotCRWMouseRelease();
205 
206     // TempoRuler
207     void slotTRMousePress();
208     void slotTRMouseRelease();
209 
210     void slotZoomInFromPanner();
211     void slotZoomOutFromPanner();
212 
213     void slotHScroll();
214     void slotHScrollBarRangeChanged(int min, int max);
215 
216     /// The horizontal zoom thumbwheel moved
217     void slotHorizontalThumbwheelMoved(int);
218 
219     /// The vertical zoom thumbwheel moved
220     void slotVerticalThumbwheelMoved(int);
221 
222     /// The primary (combined axes) thumbwheel moved
223     void slotPrimaryThumbwheelMoved(int);
224 
225     /// Reset the zoom to 100% and reset the zoomy wheels
226     void slotResetZoomClicked();
227 
228     /// Trap a zoom in from the panner and sync it to the primary thumb wheel
229     void slotSyncPannerZoomIn();
230 
231     /// Trap a zoom out from the panner and sync it to the primary thumb wheel
232     void slotSyncPannerZoomOut();
233 
234     void slotGenerateHeaders();
235     void slotShowHeaderToolTip(QString toolTipText);
236     void slotHeadersResized(int width);
237     void slotAdjustHeadersHorizontalPos(bool last);
238     void slotAdjustHeadersVerticalPos(QRectF r);
239     void slotCloseHeaders();
240 
241     /// The segment control thumbwheel moved
242     void slotSegmentChangerMoved(int);
243 
244     void slotStaffChanged();
245 
246     void slotUpdateRawNoteRuler(ViewSegment *);
247     void slotUpdateSegmentChangerBackground();
248     void resizeEvent(QResizeEvent *event) override;
249     void slotResizeTimerDone();
250 
251 signals :
252     void adjustNeeded(bool last);
253     void editElement(NotationStaff *, NotationElement *, bool advanced);
254     void currentSegmentPrior();
255     void currentSegmentNext();
256 
257 private:
258     RosegardenDocument *m_document; // I do not own this
259     Panned *m_view; // I own this
260     Panner *m_hpanner; // I own this
261     NotationScene *m_scene; // I own this
262     int m_leftGutter;
263     NotationToolBox *m_toolBox;
264     NotationTool *m_currentTool;
265     bool m_playTracking;
266 
267     double m_hZoomFactor;
268     double m_vZoomFactor;
269     ZoomableRulerScale *m_referenceScale; // I own this (refers to scene scale)
270 
271     QWidget     *m_panner;
272     QBoxLayout  *m_pannerLayout;
273     Thumbwheel  *m_HVzoom;
274     Thumbwheel  *m_Hzoom;
275     Thumbwheel  *m_Vzoom;
276     QPushButton *m_reset;
277 
278     /** The primary zoom wheel behaves just like using the mouse wheel over any
279      * part of the Panner.  We don't need to keep track of absolute values here,
280      * just whether we rolled up or down.  We'll do that by keeping track of the
281      * last setting and comparing it to see which way it moved.
282      */
283     int m_lastHVzoomValue;
284     bool m_lastZoomWasHV;
285     int m_lastV;
286     int m_lastH;
287 
288     QWidget *m_changerWidget;
ExecEndGatherMerge(GatherMergeState * node)289     Thumbwheel  *m_HsegmentChanger;
290     Thumbwheel  *m_VsegmentChanger;
291     int m_lastSegmentChangerValue;
292 
293     StandardRuler *m_topStandardRuler; // I own this
294     StandardRuler *m_bottomStandardRuler; // I own this
295     TempoRuler *m_tempoRuler; // I own this
296     ChordNameRuler *m_chordNameRuler; // I own this
297     RawNoteRuler *m_rawNoteRuler; // I own this
298     ControlRulerWidget *m_controlRulerWidget; // I own this
299 
300     QLabel *m_segmentLabel;
301 
302     // Track Headers
303     // View > Show Track Headers
304 
ExecShutdownGatherMerge(GatherMergeState * node)305     HeadersGroup *m_headersGroup; // I own this
306     /// Track Headers that appear to the left of the staves.
307     Panned *m_headersView; // I own this
308     QGraphicsScene *m_headersScene; // I own this
309     QWidget *m_headersButtons; // I own this
310     double m_headersLastY;
311     bool m_headersNeedRegeneration;
312     QTimer *m_headersTimer; // I own this
313 
314     QGridLayout *m_layout; // I own this
315 
316     bool m_tempoRulerIsVisible;         // Only valid in linear mode
317     bool m_rawNoteRulerIsVisible;       // Only valid in linear mode
318     bool m_chordNameRulerIsVisible;     // Only valid in linear mode
319     bool m_headersAreVisible;           // Only valid in linear mode
320 
321     bool m_chordMode;
322     bool m_tupletMode;
323     bool m_graceMode;
ExecShutdownGatherMergeWorkers(GatherMergeState * node)324 
325     unsigned short m_tupledCount;
326     unsigned short m_untupledCount;
327 
328     /// Timer to reduce the number of layout resets that occur while resizing.
329     /**
330      * ??? I can't help but wonder if there is a simpler solution where
331      *     we assume the scene (or whatever) is always at the very least
332      *     big enough to fill the user's screen. So the scrollbars are
333      *     always there and there is always empty space to the right
334      *     and below.  This would then prevent the jumping without the
335      *     need for a timer and a layout reset. (I have no idea what I'm
336      *     talking about, so you might need to translate that into
337      *     whatever is actually going on in the code.)  See Bug #1570 for
338      *     details.
339      */
340     QTimer *m_resizeTimer;
341 
ExecReScanGatherMerge(GatherMergeState * node)342     bool m_updatesSuspended;
343 
344     void locatePanner(bool vertical);
345 
346     /**
347      * Widgets vertical positions inside the main QGridLayout
348      */
349     enum {
350         CHORDNAMERULER_ROW,
351         TEMPORULER_ROW,
352         RAWNOTERULER_ROW,
353         TOPRULER_ROW,
354         PANNED_ROW,
355         BOTTOMRULER_ROW,
356         CONTROLS_ROW,
357         HSLIDER_ROW,
358         SEGMENTLABEL_ROW,
359         PANNER_ROW,
360         BOTTOM_ROW
361     };
362 
363     /**
364      * Widgets horizontal positions inside the main QGridLayout
365      */
366     enum {
367         HEADER_COL,
368         MAIN_COL,
369         VPANNER_COL
370     };
371 
372     AutoScroller m_autoScroller;
373 
374 private slots:
375     /// Connected to Panned::zoomIn() for ctrl+wheel.
376     void slotZoomIn();
377     /// Connected to Panned::zoomOut() for ctrl+wheel.
378     void slotZoomOut();
379 
380 };
381 
382 }
383 
384 #endif
385 
386 
387