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_MATRIX_WIDGET_H
19 #define RG_MATRIX_WIDGET_H
20 
21 #include "base/Event.h"             // for timeT
22 #include "MatrixTool.h"
23 #include "base/MidiTypes.h"         // for MidiByte
24 #include "gui/general/AutoScroller.h"
25 #include "gui/general/SelectionManager.h"
26 
27 #include <vector>
28 
29 #include <QSharedPointer>
30 #include <QTimer>
31 #include <QWidget>
32 
33 class QGraphicsScene;
34 class QGridLayout;
35 class QLabel;
36 class QPushButton;
37 
38 namespace Rosegarden
39 {
40 
41 class RosegardenDocument;
42 class Segment;
43 class MatrixScene;
44 class MatrixToolBox;
45 class MatrixMouseEvent;
46 class SnapGrid;
47 class ZoomableRulerScale;
48 class Panner;
49 class Panned;
50 class EventSelection;
51 class PitchRuler;
52 class MidiKeyMapping;
53 class ControlRulerWidget;
54 class StandardRuler;
55 class TempoRuler;
56 class ChordNameRuler;
57 class Device;
58 class Instrument;
59 class Thumbwheel;
60 
61 
62 /// QWidget that fills the Matrix Editor's (MatrixView) client area.
63 /**
64  * The main Matrix Editor window, MatrixView, owns the only instance
65  * of this class.  See MatrixView::m_matrixWidget.
66  *
67  * MatrixWidget contains the matrix itself (m_view and m_scene).
68  * MatrixWidget also contains all the other parts of the Matrix Editor
69  * that appear around the matrix.  From left to right, top to bottom:
70  *
71  *   - The chord name ruler
72  *   - The tempo ruler
73  *   - The top standard ruler
74  *   - The pitch ruler, m_pianoView (to the left of the matrix)
75  *   - The matrix itself, m_view and m_scene
76  *   - The bottom standard ruler, m_bottomStandardRuler
77  *   - The controls widget, m_controlsWidget (optional)
78  *   - The Segment label, m_segmentLabel
79  *   - The Segment changer, m_segmentChanger (knob in the bottom left corner)
80  *   - The panner, m_hpanner (navigation area)
81  *   - The zoom area, m_HVzoom et al. (knobs in the bottom right corner)
82  *
83  * This class also owns the editing tools.
84  */
85 class MatrixWidget : public QWidget,
86                      public SelectionManager
87 {
88     Q_OBJECT
89 
90 public:
91     MatrixWidget(bool drumMode);
92     virtual ~MatrixWidget() override;
93 
94     Device *getCurrentDevice();
getScene()95     MatrixScene *getScene()  { return m_scene; }
96 
97     /**
98      * Show the pointer.  Used by MatrixView upon construction, this ensures
99      * the pointer is visible initially.
100      */
101     void showInitialPointer();
102 
103     /// Set the Segment(s) to display.
104     /**
105      * ??? Only one caller.  Might want to fold this into the ctor.
106      */
107     void setSegments(RosegardenDocument *document,
108                      std::vector<Segment *> segments);
109     /// MatrixScene::getCurrentSegment()
110     Segment *getCurrentSegment();
111     /// MatrixScene::segmentsContainNotes()
112     bool segmentsContainNotes() const;
113 
114     /// All segments only have a key mapping.
hasOnlyKeyMapping()115     bool hasOnlyKeyMapping() const { return m_onlyKeyMapping; }
116 
getControlsWidget()117     ControlRulerWidget *getControlsWidget()  { return m_controlsWidget; }
118 
119     /// MatrixScene::getSnapGrid()
120     const SnapGrid *getSnapGrid() const;
121     /// MatrixScene::setSnap()
122     void setSnap(timeT);
123 
124     void setChordNameRulerVisible(bool visible);
125     void setTempoRulerVisible(bool visible);
126 
127     /// Show the highlight on the piano/percussion rulers.
128     void showHighlight(bool visible);
129 
130 
131     // SelectionManager interface.
132 
133     // These delegate to MatrixScene, which possesses the selection
134     /// MatrixScene::getSelection()
135     EventSelection *getSelection() const override;
136     /// MatrixScene::setSelection()
137     void setSelection(EventSelection *s, bool preview) override;
138 
139 
140     // Tools
141 
getToolBox()142     MatrixToolBox *getToolBox() { return m_toolBox; }
143 
144     /// Used by the tools to set an appropriate mouse cursor.
145     void setCanvasCursor(QCursor cursor);
146 
isDrumMode()147     bool isDrumMode() const { return m_drumMode; }
148 
149     /// Velocity for new notes.  (And moved notes too.)
getCurrentVelocity()150     int getCurrentVelocity() const { return m_currentVelocity; }
151 
152 
153     // Interface for MatrixView menu commands
154 
155     /// Edit > Select All
156     void selectAll();
157     /// Edit > Clear Selection
158     void clearSelection();
159     /// Move > Previous Segment
160     void previousSegment();
161     /// Move > Next Segment
162     void nextSegment();
163     /// Tools > Draw
164     void setDrawTool();
165     /// Tools > Erase
166     void setEraseTool();
167     /// Tools > Select and Edit
168     void setSelectAndEditTool();
169     /// Tools > Move
170     void setMoveTool();
171     /// Tools > Resize
172     void setResizeTool();
173     /// Tools > Velocity
174     void setVelocityTool();
175     /// Move > Scroll to Follow Playback
176     void setScrollToFollowPlayback(bool);
177     /// View > Rulers > Show Velocity Ruler
178     void showVelocityRuler();
179     /// View > Rulers > Show Pitch Bend Ruler
180     void showPitchBendRuler();
181     /// View > Rulers > Add Control Ruler
182     void addControlRuler(QAction *);
183 
184 signals:
185     void toolChanged(QString);
186 
187     /**
188      * Emitted when the user double-clicks on a note that triggers a
189      * segment.
190      *
191      * RosegardenMainViewWidget::slotEditTriggerSegment() launches the event
192      * editor on the triggered segment in response to this.
193      */
194     void editTriggerSegment(int);
195 
196     /// Forwarded from MatrixScene::segmentDeleted().
197     void segmentDeleted(Segment *);
198     /// Forwarded from MatrixScene::sceneDeleted().
199     void sceneDeleted();
200     /// Forwarded from MatrixScene::selectionChanged()
201     void selectionChanged();
202 
203     void showContextHelp(const QString &);
204 
205 public slots:
206     /// Velocity combo box.
slotSetCurrentVelocity(int velocity)207     void slotSetCurrentVelocity(int velocity)  { m_currentVelocity = velocity; }
208 
209     /// Plays the preview note when using the computer keyboard to enter notes.
210     void slotPlayPreviewNote(Segment *segment, int pitch);
211 
212 protected:
213     // QWidget Override
214     /// Make sure the rulers are in sync when we are shown.
215     void showEvent(QShowEvent *event) override;
216 
217 private slots:
218     /// Called when the document is modified in some way.
219     void slotDocumentModified(bool);
220 
221     /// Connected to Panned::zoomIn() for ctrl+wheel.
222     void slotZoomIn();
223     /// Connected to Panned::zoomOut() for ctrl+wheel.
224     void slotZoomOut();
225 
226     /// Scroll rulers to sync up with view.
227     void slotScrollRulers();
228 
229     // MatrixScene Interface
230     void slotDispatchMousePress(const MatrixMouseEvent *);
231     void slotDispatchMouseMove(const MatrixMouseEvent *);
232     void slotDispatchMouseRelease(const MatrixMouseEvent *);
233     void slotDispatchMouseDoubleClick(const MatrixMouseEvent *);
234 
235     /// Display the playback position pointer.
236     void slotPointerPositionChanged(timeT t);
237     void slotStandardRulerDrag(timeT t);
238     /// Handle StandardRuler startMouseMove()
239     void slotSRStartMouseMove();
240     /// Handle StandardRuler stopMouseMove()
241     void slotSRStopMouseMove();
242 
243     /// Handle ControlRulerWidget::mousePress().
244     void slotCRWMousePress();
245     /// Handle ControlRulerWidget::mouseMove().
246     void slotCRWMouseMove(FollowMode followMode);
247     /// Handle ControlRulerWidget::mouseRelease().
248     void slotCRWMouseRelease();
249 
250     /// Handle TempoRuler::mousePress().
251     void slotTRMousePress();
252     /// Handle TempoRuler::mouseRelease().
253     void slotTRMouseRelease();
254 
255     /// Hide the horizontal scrollbar when not needed.
256     /**
257      * ??? Why do we need to manage this?  We turn off the horizontal
258      *     scrollbar in the ctor with Qt::ScrollBarAlwaysOff.
259      */
260     void slotHScrollBarRangeChanged(int min, int max);
261 
262     // PitchRuler slots
263     /// Draw the highlight as we move from one pitch to the next.
264     void slotHoveredOverKeyChanged(unsigned int);
265     void slotKeyPressed(unsigned int, bool);
266     void slotKeySelected(unsigned int, bool);
267     void slotKeyReleased(unsigned int, bool);
268 
269     /// The horizontal zoom thumbwheel moved
270     void slotHorizontalThumbwheelMoved(int);
271 
272     /// The vertical zoom thumbwheel moved
273     void slotVerticalThumbwheelMoved(int);
274 
275     /// The primary (combined axes) thumbwheel moved
276     void slotPrimaryThumbwheelMoved(int);
277 
278     /// Reset the zoom to 100% and reset the zoomy wheels
279     void slotResetZoomClicked();
280 
281     /// Trap a zoom in from the panner and sync it to the primary thumb wheel
282     void slotSyncPannerZoomIn();
283 
284     /// Trap a zoom out from the panner and sync it to the primary thumb wheel
285     void slotSyncPannerZoomOut();
286 
287     /// The Segment control thumbwheel moved, display a different Segment.
288     void slotSegmentChangerMoved(int);
289 
290     /// The mouse has left the view, hide the highlight note.
291     void slotMouseLeavesView();
292 
293     /// Instrument is being destroyed
294     void slotInstrumentGone();
295 
296 private:
297     // ??? Instead of storing the document, which can change, get the
298     //     document as needed via RosegardenMainWindow::self()->getDocument().
299     RosegardenDocument *m_document; // I do not own this
300 
301     QGridLayout *m_layout; // I own this
302 
303 
304     // View
305 
306     /// QGraphicsScene holding the note Events.
307     MatrixScene *m_scene; // I own this
308 
309     /// The main view of the MatrixScene (m_scene).
310     Panned *m_view; // I own this
311 
312     /// Whether the view will scroll along with the playback position pointer.
313     bool m_playTracking;
314 
315     /// View horizontal zoom factor.
316     double m_hZoomFactor;
317     void setHorizontalZoomFactor(double factor);
318 
319     /// View vertical zoom factor.
320     double m_vZoomFactor;
321     void setVerticalZoomFactor(double factor);
322 
323 
324     // Pointer
325 
326     void updatePointer(timeT t);
327 
328 
329     // Panner (Navigation Area below the matrix)
330 
331     /// Navigation area under the main view.
332     Panner *m_panner; // I own this
333     void zoomInFromPanner();
334     void zoomOutFromPanner();
335 
336     QWidget *m_changerWidget;
337     Thumbwheel *m_segmentChanger;
338     int m_lastSegmentChangerValue;
339     void updateSegmentChangerBackground();
340     QLabel *m_segmentLabel;
341 
342 
343     // Pitch Ruler
344 
345     // This can be nullptr.  It tracks what pitchruler corresponds to.
346     Instrument *m_instrument; // Studio owns this (TBC)
347     /// Key mapping from the Instrument.
348     QSharedPointer<MidiKeyMapping> m_localMapping;
349     /// Either a PercussionPitchRuler or a PianoKeyboard object.
350     PitchRuler *m_pitchRuler; // I own this
351     /// (Re)generate the pitch ruler (useful when key mapping changed)
352     void generatePitchRuler();
353     /// Contains m_pitchRuler.
354     QGraphicsScene *m_pianoScene; // I own this
355     /// Contains m_pianoScene.
356     Panned *m_pianoView; // I own this
357     /// All Segments only have key mappings.  Use a PercussionPitchRuler.
358     bool m_onlyKeyMapping;
359     /// Percussion matrix editor?
360     /**
361      * For the Percussion matrix editor, we ignore key release events from
362      * the PitchRuler.
363      */
364     bool m_drumMode;
365 
366     /// First note selected when doing a run up/down the keyboard.
367     /**
368      * Used to allow selection of a range of pitches by shift-clicking a
369      * note on the pitch ruler then dragging up or down to another note.
370      */
371     MidiByte m_firstNote;
372 
373     /// Last note selected when doing a run up/down the keyboard.
374     /**
375      * Used to prevent redundant note on/offs when doing a run up/down the
376      * pitch ruler.
377      */
378     MidiByte m_lastNote;
379 
380     /// Hide pitch ruler highlight when mouse move is not related to a pitch change.
381     bool m_highlightVisible;
382 
383 
384     // Tools
385 
386     MatrixToolBox *m_toolBox; // I own this
387     MatrixTool *m_currentTool; // Toolbox owns this
388     void setTool(QString name);
389     /// Used by the MatrixMover and MatrixPainter tools for preview notes.
390     int m_currentVelocity;
391 
392 
393     // Zoom Area (to the right of the Panner)
394 
395     /// The big zoom wheel.
396     Thumbwheel *m_HVzoom;
397     /// Used to compute how far the big zoom wheel has moved.
398     int m_lastHVzoomValue;
399     /// Which zoom factor to use.  For the pitch ruler.
400     bool m_lastZoomWasHV;
401     /// Thin horizontal zoom wheel under the big zoom wheel.
402     Thumbwheel *m_Hzoom;
403     /// Used to compute how far the horizontal zoom wheel has moved.
404     int m_lastH;
405     /// Thin vertical zoom wheel to the right of the big zoom wheel.
406     Thumbwheel *m_Vzoom;
407     /// Used to compute how far the vertical zoom wheel has moved.
408     int m_lastV;
409     /// Small reset button to the lower right of the big zoom wheel.
410     QPushButton *m_reset;
411 
412 
413     // Rulers
414 
415     ChordNameRuler *m_chordNameRuler; // I own this
416     TempoRuler *m_tempoRuler; // I own this
417     StandardRuler *m_topStandardRuler; // I own this
418     StandardRuler *m_bottomStandardRuler; // I own this
419     ControlRulerWidget *m_controlsWidget; // I own this
420 
421     /// Used by all rulers to make sure they are all zoomed to the same scale.
422     /**
423      * See MatrixScene::getReferenceScale().
424      */
425     ZoomableRulerScale *m_referenceScale;  // Owned by MatrixScene
426 
427 
428     // Auto-scroll
429 
430     AutoScroller m_autoScroller;
431 
432 };
433 
434 }
435 
436 #endif
437