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 ¬e, 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 ¬eName); 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