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_SCENE_H
19 #define RG_NOTATION_SCENE_H
20 
21 #include <QGraphicsScene>
22 #include <QSharedPointer>
23 
24 #include "base/NotationTypes.h"
25 #include "base/Composition.h"
26 #include "gui/general/SelectionManager.h"
27 #include "gui/general/GUIPalette.h"
28 #include "StaffLayout.h"
29 #include "NotePixmapFactory.h"
30 #include "ClefKeyContext.h"
31 
32 class QGraphicsItem;
33 class QGraphicsTextItem;
34 
35 namespace Rosegarden
36 {
37 
38 class NotationStaff;
39 class NotationHLayout;
40 class NotationVLayout;
41 class NotePixmapFactory;
42 class NotationProperties;
43 class NotationMouseEvent;
44 class EventSelection;
45 class Event;
46 class ClefKeyContext;
47 class NotationElement;
48 class NotationWidget;
49 class RosegardenDocument;
50 class Segment;
51 class ViewSegment;
52 class RulerScale;
53 
54 typedef std::map<int, int> TrackIntMap;
55 
56 class NotationScene : public QGraphicsScene,
57                       public CompositionObserver,
58                       public SelectionManager
59 {
60     Q_OBJECT
61 
62 public:
63     NotationScene();
64     ~NotationScene() override;
65 
66     void setNotationWidget(NotationWidget *w);
67     void setStaffs(RosegardenDocument *document, std::vector<Segment *> segments);
68 
69     void createClonesFromRepeatedSegments();
70 
getStaffs()71     std::vector<NotationStaff *> *getStaffs() { return &m_staffs; }
72 
73     /** Returns the total number of staffs irrespective of whether they are
74       * visible individually or not.  This may return a number higher than the
75       * apparent number of staffs, due to segment overlaps.
76       *
77       * If there are five total staffs spread across two apparent staffs, this
78       * returns 5.
79       */
getStaffCount()80     unsigned int getStaffCount() { return m_staffs.size(); }
81 
82     /** Returns the number of staffs that are visible individually as discrete
83      * staffs, irrespective of how many real staffs might be represented by each
84      * apparent staff.
85      *
86      * If there are five total staffs spread across two apparent staffs, this
87      * returns 2.
88      */
getVisibleStaffCount()89     unsigned int getVisibleStaffCount() { return m_visibleStaffs; }
90 
getCurrentStaffNumber()91     int getCurrentStaffNumber() { return m_currentStaff; }
92     NotationStaff *getCurrentStaff();
93     void setCurrentStaff(NotationStaff *);
94 
95     NotationStaff *getStaffAbove(timeT t);
96     NotationStaff *getStaffBelow(timeT t);
97     NotationStaff *getPriorStaffOnTrack();
98     NotationStaff *getNextStaffOnTrack();
99 
100     NotationStaff *getStaffBySegmentMarking(const QString& marking) const;
101 
102     NotationStaff *getStaffForSceneCoords(double x, int y) const;
103 
104     Segment *getCurrentSegment();
105 
106     bool segmentsContainNotes() const;
107 
108     //!!! to keep current staff implementation happy:
isInPrintMode()109     bool isInPrintMode() const { return false; }
getHLayout()110     NotationHLayout *getHLayout() { return m_hlayout; }
getVLayout()111     NotationVLayout *getVLayout() { return m_vlayout; }
getProperties()112     NotationProperties &getProperties() { return *m_properties; }
getDocument()113     RosegardenDocument *getDocument() { return m_document; }
getNotePixmapFactory()114     NotePixmapFactory *getNotePixmapFactory() { return m_notePixmapFactory; }
115 
getSelection()116     EventSelection *getSelection() const override { return m_selection; }
117     void setSelection(EventSelection* s, bool preview) override;
118 
119     timeT getInsertionTime() const;
120 
121     struct CursorCoordinates {
122         QLineF currentStaff;
123         QLineF allStaffs;
124     };
125 
126     CursorCoordinates getCursorCoordinates(timeT t) const;
127     timeT snapTimeToNoteBoundary(timeT t) const;
128 
129     void setSingleSelectedEvent(NotationStaff *staff,
130                                 NotationElement *e,
131                                 bool preview);
132 
133     void setSingleSelectedEvent(Segment *segment,
134                                 Event *e,
135                                 bool preview);
136 
getPageMode()137     StaffLayout::PageMode getPageMode() const { return m_pageMode; }
138     void setPageMode(StaffLayout::PageMode mode);
139 
140     QString getFontName() const;
141     void setFontName(QString);
142 
143     int getFontSize() const;
144     void setFontSize(int);
145 
146     int getHSpacing() const;
147     void setHSpacing(int);
148 
149     int getLeftGutter() const;
150     void setLeftGutter(int);
151 
152     const RulerScale *getRulerScale() const;
153 
154     void suspendLayoutUpdates();
155     void resumeLayoutUpdates();
156 
157     /**
158      * Show and sound the given note.  The height is used for display,
159      * the pitch for performance, so the two need not correspond (e.g.
160      * under ottava there may be octave differences).
161      */
162     void showPreviewNote(NotationStaff *staff, double layoutX,
163                          int pitch, int height,
164                          const Note &note,
165                          bool grace,
166                          Accidental accidental = Accidentals::NoAccidental,
167                          bool cautious = false,
168                          QColor color = GUIPalette::SelectionColor,
169                          int velocity = -1,
170                          bool play = true
171                         );
172 
173     /// Remove any visible preview note
174     void clearPreviewNote(NotationStaff *);
175 
176     void playNote(Segment &segment, int pitch, int velocity = -1);
177 
178     bool constrainToSegmentArea(QPointF &scenePos);
179 
180     // more dubious:
181     void handleEventRemoved(Event *);
areAnnotationsVisible()182     bool areAnnotationsVisible() { return true; }
areLilyPondDirectivesVisible()183     bool areLilyPondDirectivesVisible() { return true; }
184 
getMinTrack()185     int getMinTrack() { return m_minTrack; }
getMaxTrack()186     int getMaxTrack() { return m_maxTrack; }
getTrackHeights()187     TrackIntMap *getTrackHeights() { return &m_trackHeights; }
getTrackCoords()188     TrackIntMap *getTrackCoords() { return &m_trackCoords; }
189 
getClefKeyContext()190     ClefKeyContext * getClefKeyContext() { return m_clefKeyContext; }
updateClefKeyContext()191     void updateClefKeyContext() { m_clefKeyContext->setSegments(this); }
192 
193     /// Return true if element is a clef or a key which already is in use
194     bool isEventRedundant(Event *ev, Segment &seg) const;
195     bool isEventRedundant(Clef &clef, timeT time, Segment &seg) const;
196     bool isEventRedundant(Key &key, timeT time, Segment &seg) const;
197 
198     /// Return the segments about to be deleted if any
getSegmentsDeleted()199     std::vector<Segment *> * getSegmentsDeleted() { return &m_segmentsDeleted; }
200 
201     /// Return true if all segments in scene are about to be deleted
202     /// (Editor needs to be closed)
isSceneEmpty()203     bool isSceneEmpty() { return m_sceneIsEmpty; }
204 
205     /**
206      * Return true if another staff inside the scene than the given one
207      * exists near the given time.
208      */
209     bool isAnotherStaffNearTime(NotationStaff *currentStaff, timeT t);
210 
211    /**
212     * Update the refresh status off all segments on the given track and
213     * for time greater than time.
214     * This method is useful when a clef or key signature has changed as, since
215     * the redundant clefs and keys may be hide, some changes may propagate
216     * across the segments up to the end of the composition.
217     */
218     void updateRefreshStatuses(TrackId track, timeT time);
219 
220     void updatePageSize();
221 
222     /// YG: Only for debug
223     void dumpVectors();
224     void dumpBarDataMap();
225 
226 signals:
227     void mousePressed(const NotationMouseEvent *e);
228     void mouseMoved(const NotationMouseEvent *e);
229     void mouseReleased(const NotationMouseEvent *e);
230     void mouseDoubleClicked(const NotationMouseEvent *e);
231     void wheelTurned(int, const NotationMouseEvent *e);
232 
233     void sceneNeedsRebuilding();
234 
235     void eventRemoved(Event *);
236 
237     //void selectionChanged(); // defined in QGraphicsScene
238     void selectionChanged(EventSelection *);
239 
240     void layoutUpdated(timeT,timeT);
241     void staffsPositionned();
242 
243     void currentStaffChanged();
244     void currentViewSegmentChanged(ViewSegment *);
245 
246     /**
247      * Emitted when the mouse cursor moves to a different height
248      * on the staff
249      *
250      * \a noteName contains the MIDI name of the corresponding note
251      */
252     void hoveredOverNoteChanged(const QString &noteName);
253 
254     /**
255      * Emitted when the mouse cursor moves to a note which is at a
256      * different time
257      *
258      * \a time is set to the absolute time of the note the cursor is
259      * hovering on
260      */
261     void hoveredOverAbsoluteTimeChanged(unsigned int time);
262 
263 public slots:
264     void slotMouseLeavesView();
265 
266 protected slots:
267     void slotCommandExecuted();
268 
269 protected:
270     void mousePressEvent(QGraphicsSceneMouseEvent *) override;
271     void mouseMoveEvent(QGraphicsSceneMouseEvent *) override;
272     void mouseReleaseEvent(QGraphicsSceneMouseEvent *) override;
273     void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *) override;
274     void wheelEvent(QGraphicsSceneWheelEvent *) override;
275 
276     void keyPressEvent(QKeyEvent * keyEvent) override;
277     void keyReleaseEvent(QKeyEvent * keyEvent) override;
278 
279     // CompositionObserver methods
280     void segmentRemoved(const Composition *, Segment *) override;
281     void timeSignatureChanged(const Composition *) override; // CompositionObserver
282     void segmentRepeatChanged(const Composition *, Segment *, bool) override;
283     void segmentRepeatEndChanged(const Composition *, Segment *, timeT) override;
284     void segmentStartChanged(const Composition *, Segment *, timeT) override;
285     void segmentEndMarkerChanged(const Composition *, Segment *, bool) override;
286     void trackChanged(const Composition *, Track *) override;
287 
288 
289 
290 private:
291     void setNotePixmapFactories(QString fontName = "", int size = -1);
292     NotationStaff *getNextStaffVertically(int direction, timeT t);
293     NotationStaff *getNextStaffHorizontally(int direction, bool cycle);
294     NotationStaff *getStaffbyTrackAndTime(const Track *track, timeT targetTime);
295     void initCurrentStaffIndex();
296     void processKeyboardEvent(QKeyEvent * keyEvent);
297 
298     NotationWidget *m_widget; // I do not own this
299 
300     RosegardenDocument *m_document; // I do not own this
301 
302     QSharedPointer<NotationProperties> m_properties;
303 
304     NotePixmapFactory *m_notePixmapFactory; // I own this
305     NotePixmapFactory *m_notePixmapFactorySmall; // I own this
306 
307     std::vector<Segment *> m_externalSegments; // I do not own these
308     std::vector<Segment *> m_clones; // I own these
309     std::vector<Segment *> m_segments; // The concatenation of m_clones
310                                        // and m_externalSegments
311     std::vector<NotationStaff *> m_staffs; // I own these
312 
313     ClefKeyContext *m_clefKeyContext; // I own this
314 
315     EventSelection *m_selection; // I own this
316 
317     NotationHLayout *m_hlayout; // I own this
318     NotationVLayout *m_vlayout; // I own this
319 
320     QGraphicsTextItem *m_title;
321     QGraphicsTextItem *m_subtitle;
322     QGraphicsTextItem *m_composer;
323     QGraphicsTextItem *m_copyright;
324 
325     std::vector<QGraphicsItem *> m_pages;
326     std::vector<QGraphicsItem *> m_pageNumbers;
327 
328     StaffLayout::PageMode m_pageMode;
329     int m_printSize;
330     int m_leftGutter;
331 
332     int m_currentStaff;
333     int m_visibleStaffs;
334 
335     unsigned int m_compositionRefreshStatusId;
336     bool m_timeSignatureChanged;
337 
338     bool m_updatesSuspended;
339 
340     /// Returns the page width according to the layout mode (page/linear)
341     int getPageWidth();
342 
343     /// Returns the page height according to the layout mode (page/linear)
344     int getPageHeight();
345 
346     /// Returns the margins within the page (zero if not in MultiPageMode)
347     void getPageMargins(int &left, int &top);
348 
349     void setupMouseEvent(QGraphicsSceneMouseEvent *, NotationMouseEvent &);
350     void setupMouseEvent(QGraphicsSceneWheelEvent *, NotationMouseEvent &);
351     void setupMouseEvent(QPointF scenePos, Qt::MouseButtons buttons,
352                          Qt::KeyboardModifiers modifiers,
353                          NotationMouseEvent &nme);
354 
355     void checkUpdate();
356     void positionStaffs();
357     void layoutAll();
358     void layout(NotationStaff *singleStaff, timeT start, timeT end);
359 
360     NotationStaff *setSelectionElementStatus(EventSelection *, bool set);
361     void previewSelection(EventSelection *, EventSelection *oldSelection);
362 
363     int m_minTrack;
364     int m_maxTrack;
365 
366     TrackIntMap m_trackHeights;
367     TrackIntMap m_trackCoords;
368 
369     // Remember segments about to be deleted
370     std::vector<Segment *> m_segmentsDeleted;
371 
372     bool m_finished;       // Waiting dtor : don't do too much now
373     bool m_sceneIsEmpty;   // No more segment in scene
374     bool m_showRepeated;   // Repeated segments are visible
375     bool m_editRepeated;   // Direct edition of repeated segments is allowed
376     bool m_haveInittedCurrentStaff;
377 
378     NotationStaff * m_previewNoteStaff;  // Remember where the preview note was
379 
380     // Remember current labels of tracks
381     std::map<int, std::string> m_trackLabels;
382 };
383 
384 }
385 
386 #endif
387