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_NOTATIONSTAFF_H
19 #define RG_NOTATIONSTAFF_H
20 
21 #include "base/ViewSegment.h"
22 #include "base/ViewElement.h"
23 #include "StaffLayout.h"
24 #include <map>
25 #include <set>
26 #include <string>
27 #include <utility>
28 #include "base/Event.h"
29 #include "NotationElement.h"
30 
31 
32 class QPainter;
33 class QGraphicsItem;
34 class StaffLayoutCoords;
35 
36 
37 namespace Rosegarden
38 {
39 
40 class ViewElement;
41 class TimeSignature;
42 class SnapGrid;
43 class Segment;
44 class NotePixmapParameters;
45 class NotePixmapFactory;
46 class Note;
47 class NotationScene;
48 class NotationProperties;
49 class Key;
50 class Event;
51 class Clef;
52 
53 
54 class NotationStaff : public ViewSegment,
55                       public StaffLayout,
56                       public QObject  // Just for tr().  Could be cleaned up.
57 {
58     //Q_OBJECT
59 public:
60     NotationStaff(NotationScene *, Segment *, SnapGrid *,
61                   int id,
62                   NotePixmapFactory *normalFactory,
63                   NotePixmapFactory *smallFactory);
64     ~NotationStaff() override;
65 
66     void setNotePixmapFactories(NotePixmapFactory *normal,
67                                 NotePixmapFactory *small);
68 
69     void setLegerLineCount(int legerLineCount) {
70         if (legerLineCount == -1) m_legerLineCount = 8;
71         else m_legerLineCount = legerLineCount;
72     }
73 
74     void setBarNumbersEvery(int barNumbersEvery) {
75         m_barNumbersEvery = barNumbersEvery;
76     }
77 
78     using StaffLayout::setPageMode;
79     using StaffLayout::setPageWidth;
80     using StaffLayout::setRowsPerPage;
81     using StaffLayout::setRowSpacing;
82     using StaffLayout::setConnectingLineLength;
83 
84     SegmentRefreshStatus &getRefreshStatus() const;
85     void resetRefreshStatus();
86 
87     /**
88      * Gets a read-only reference to the pixmap factory used by the
89      * staff.  (For use by NotationHLayout, principally.)  This
90      * reference isn't const because the NotePixmapFactory maintains
91      * too much state for its methods to be const, but you should
92      * treat the returned reference as if it were const anyway.
93      */
94     NotePixmapFactory& getNotePixmapFactory(bool grace) {
95         return grace ? *m_graceNotePixmapFactory : *m_notePixmapFactory;
96     }
97 
98     void regenerate(timeT from, timeT to, bool secondary);
99 
100     /**
101      * Generate or re-generate items for all the elements between
102      * from and to.  Call this when you've just made a change,
103      * specifying the extents of the change in the from and to
104      * parameters.
105      *
106      * This method does not reposition any elements outside the given
107      * range -- so after any edit that may change the visible extents
108      * of a range, you will then need to call positionElements for the
109      * changed range and the entire remainder of the staff.
110      */
111     void renderElements(NotationElementList::iterator from,
112                                 NotationElementList::iterator to) override;
113 
114     void renderElements(timeT from, timeT to);
115 
116 
117     /**
118      * Assign suitable coordinates to the elements on the staff,
119      * based entirely on the layout X and Y coordinates they were
120      * given by the horizontal and vertical layout processes.
121      *
122      * This is necessary because the items that are being positioned
123      * may have been created either after the layout process completed
124      * (by renderElements) or before (by the previous renderElements
125      * call, if the items are unchanged but have moved) -- so
126      * neither the layout nor renderElements can authoritatively set
127      * their final positions.
128      *
129      * This method also updates the selected-ness of any elements it
130      * sees (i.e. it turns the selected ones blue and the unselected
131      * ones black), and re-generates items for any elements for
132      * which it seems necessary.  In general it will only notice a
133      * element needs regenerating if its position has changed, not if
134      * the nature of the element has changed, so this is no substitute
135      * for calling renderElements.
136      *
137      * The from and to arguments are used to indicate the extents of a
138      * changed area within the staff.  The actual area within which the
139      * elements end up being repositioned will begin at the start of
140      * the bar containing the changed area's start, and will end at the
141      * start of the next bar whose first element hasn't moved, after
142      * the changed area's end.
143      *
144      * Call this after renderElements, or after changing the selection,
145      * passing from and to arguments corresponding to the times of those
146      * passed to renderElements.
147      */
148     void positionElements(timeT from,
149                           timeT to) override;
150 
151     /**
152      * Insert time signature at x-coordinate \a x.
153      * Use a gray color if \a grayed is true.
154      */
155     void insertTimeSignature(double layoutX,
156                                      const TimeSignature &timeSig, bool grayed) override;
157 
158     /**
159      * Delete all time signatures
160      */
161     void deleteTimeSignatures() override;
162 
163     /**
164      * Insert repeated clef and key at start of new line, at x-coordinate \a x.
165      */
166     void insertRepeatedClefAndKey(double layoutX, int barNo) override;
167 
168     /**
169      * Delete all repeated clefs and keys.
170      */
171     void deleteRepeatedClefsAndKeys() override;
172 
173     /**
174      * (Re)draw the staff name from the track's current name
175      */
176     void drawStaffName() override;
177 
178     /**
179      * Return the clef and key in force at the given canvas
180      * coordinates
181      */
182     void getClefAndKeyAtSceneCoords(double x, int y,
183                                     Clef &clef,
184                                     ::Rosegarden::Key &key) const;
185 
186     /**
187      * Return the note name (C4, Bb3, whatever) corresponding to the
188      * given scene coordinates
189      */
190     QString getNoteNameAtSceneCoords(double x, int y,
191                                      Accidental accidental =
192                                      Accidentals::NoAccidental) const;
193 
194     /**
195      * Find the NotationElement whose layout x-coord is closest to x,
196      * without regard to its y-coord.
197      *
198      * If notesAndRestsOnly is true, will return the closest note
199      * or rest but will never return any other kind of element.
200      *
201      * If the closest event is further than \a proximityThreshold
202      * horizontally away from x, in pixels, end() is returned.
203      * (If proximityThreshold is negative, there will be no limit
204      * to the distances that will be considered.)
205      *
206      * Also returns the clef and key in force at the given coordinate.
207      */
208 /*!!!
209     virtual ViewElementList::iterator getClosestElementToLayoutX
210     (double x, Event *&clef, Event *&key,
211      bool notesAndRestsOnly = false,
212      int proximityThreshold = 10);
213 */
214 
215     /**
216      * Find the NotationElement "under" the given layout x-coord,
217      * without regard to its y-coord.
218      *
219      * Also returns the clef and key in force at the given coordinates.
220      */
221     ViewElementList::iterator getElementUnderLayoutX
222     (double x, Event *&clef, Event *&key) override;
223 
224     /**
225      * Draw a note on the staff to show an insert position prior to
226      * an insert.
227      */
228     void showPreviewNote(double layoutX, int heightOnStaff,
229                          const Note &note, bool grace,
230                          Accidental accidental, bool cautious,
231                          QColor color);
232 
233     /**
234      * Remove any visible preview note.
235      */
236     void clearPreviewNote();
237 
238     /**
239      * Overridden from Staff<T>.
240      * We want to avoid wrapping things like controller events, if
241      * our showUnknowns preference is off
242      */
243     bool wrapEvent(Event *) override;
244 
245     /**
246      * Override from Staff<T>
247      * Let tools know if their current element has gone
248      */
249     void eventRemoved(const Segment *, Event *) override;
250 
251     /**
252      * Return the view-local PropertyName definitions for this staff's view
253      */
254     const NotationProperties &getProperties() const;
255 
256     double getBarInset(int barNo, bool isFirstBarInRow) const override;
257 
258     /**
259      * Return the time at the given scene coordinates
260      */
261     timeT getTimeAtSceneCoords(double x, int y) const;
262 
263     bool includesTime(timeT t);
264 
265     timeT getStartTime() const;
266 
267     timeT getEndTime() const;
268 
269     QString getMarking() const { return m_segmentMarking; }
270 
271 protected:
272 
273     ViewElement* makeViewElement(Event*) override;
274 
275     // definition of staff
276     int getLineCount() const         override { return 5; }
277     int getLegerLineCount() const    override { return m_legerLineCount; }
278     int getBottomLineHeight() const  override { return 0; }
279     int getHeightPerLine() const     override { return 2; }
280     int showBarNumbersEvery() const  override { return m_barNumbersEvery; }
281 
282     BarStyle getBarStyle(int barNo) const override;
283 
284     /**
285      * Assign a suitable item to the given element (the clef is
286      * needed in case it's a key event, in which case we need to judge
287      * the correct pitch for the key)
288      */
289     void renderSingleElement(ViewElementList::iterator &,
290                              const Clef &,
291                              const ::Rosegarden::Key &,
292                              bool selected);
293 
294     void setTuplingParameters(NotationElement *, NotePixmapParameters &);
295 
296     /**
297      * Set an item representing the given note event to the given notation element
298      */
299     void renderNote(ViewElementList::iterator &);
300 
301     /**
302      * Return true if the element has a scene item that is already
select_current_set(AggState * aggstate,int setno,bool is_hash)303      * at the correct y-coordinate
304      */
305     bool elementNotMovedInY(NotationElement *);
306 
307     /**
308      * Returns true if the item at the given iterator appears to have
309      * moved horizontally without the spacing around it changing.
310      *
311      * In practice, calculates the offset between the intended layout
312      * and current scene coordinates of the item at the given
313      * iterator, and returns true if this offset is equal to those of
314      * all other following iterators at the same time as well as the
315      * first iterator found at a greater time.
316      */
317     bool elementShiftedOnly(NotationElementList::iterator);
318 
319     bool elementNeedsRegenerating(NotationElementList::iterator);
320 
321     enum FitPolicy {
initialize_phase(AggState * aggstate,int newphase)322         PretendItFittedAllAlong = 0,
323         MoveBackToFit,
324         SplitToFit
325     };
326 
327     /**
328      * Set a single item to a notation element, or split it into bits
329      * if it overruns the end of a row and can be split, and set the
330      * bits separately.
331      */
332     void setItem(NotationElement *, QGraphicsItem *, int z, FitPolicy policy);
333 
334     bool isSelected(NotationElementList::iterator);
335 
336     typedef std::set<QGraphicsItem *> ItemSet;
337     ItemSet m_timeSigs;
338     ItemSet m_repeatedClefsAndKeys;
339 
340     typedef std::pair<int, Clef> ClefChange;
341     std::vector<ClefChange> m_clefChanges;
342 
343     typedef std::pair<int, ::Rosegarden::Key> KeyChange;
344     std::vector<KeyChange> m_keyChanges;
345 
346     void truncateClefsAndKeysAt(int);
347 
348     /**
349      * Verify that a possible Clef or Key in bar is already inserted
350      * in m_clefChange or m_keyChange.
351      * If not, do the insertion.
352      */
353     void checkAndCompleteClefsAndKeys(int bar);
354 
355     NotePixmapFactory *m_notePixmapFactory; // I do not own this
356     NotePixmapFactory *m_graceNotePixmapFactory; // I do not own this
357     QGraphicsItem *m_previewItem;
358     QGraphicsItem *m_staffName;
359     std::string m_staffNameText;
360     NotationScene *m_notationScene;
361     int m_legerLineCount;
362     int m_barNumbersEvery;
363     bool m_colourQuantize;
364     bool m_showUnknowns;
365     bool m_showRanges;
366     bool m_showCollisions;
367     bool m_hideRedundance;
368     bool m_distributeVerses;
369     int m_keySigCancelMode;
370 
371     QPainter *m_printPainter;
372 
373     unsigned int m_refreshStatusId;
374 
375     QString m_segmentMarking;
376 };
377 
378 
379 }
380 
381 #endif
382