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 ¬e, 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