diff options
Diffstat (limited to 'src/gui/editors/notation/NotationStaff.h')
-rw-r--r-- | src/gui/editors/notation/NotationStaff.h | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/src/gui/editors/notation/NotationStaff.h b/src/gui/editors/notation/NotationStaff.h new file mode 100644 index 0000000..4a0302c --- /dev/null +++ b/src/gui/editors/notation/NotationStaff.h @@ -0,0 +1,488 @@ +/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ + +/* + Rosegarden + A MIDI and audio sequencer and musical notation editor. + + This program is Copyright 2000-2008 + Guillaume Laurent <glaurent@telegraph-road.org>, + Chris Cannam <cannam@all-day-breakfast.com>, + Richard Bown <richard.bown@ferventsoftware.com> + + The moral rights of Guillaume Laurent, Chris Cannam, and Richard + Bown to claim authorship of this work have been asserted. + + Other copyrights also apply to some parts of this work. Please + see the AUTHORS file and individual file headers for details. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. See the file + COPYING included with this distribution for more information. +*/ + +#ifndef _RG_NOTATIONSTAFF_H_ +#define _RG_NOTATIONSTAFF_H_ + +#include "base/FastVector.h" +#include "base/Staff.h" +#include "base/ViewElement.h" +#include "gui/general/LinedStaff.h" +#include "gui/general/ProgressReporter.h" +#include <map> +#include <set> +#include <string> +#include <utility> +#include "base/Event.h" +#include "NotationElement.h" + + +class QPainter; +class QCanvasPixmap; +class QCanvasItem; +class QCanvas; +class LinedStaffCoords; + + +namespace Rosegarden +{ + +class ViewElement; +class TimeSignature; +class SnapGrid; +class Segment; +class QCanvasSimpleSprite; +class NotePixmapParameters; +class NotePixmapFactory; +class Note; +class NotationView; +class NotationProperties; +class Key; +class Event; +class Clef; + + +/** + * The Staff is a repository for information about the notation + * representation of a single Segment. This includes all of the + * NotationElements representing the Events on that Segment, the staff + * lines, as well as basic positional and size data. This class + * used to be in gui/staff.h, but it's been moved and renamed + * following the introduction of the core Staff base class, and + * much of the functionality has been extracted into the LinedStaff + * base class. + */ + +class NotationStaff : public ProgressReporter, public LinedStaff +{ +public: + + /** + * Creates a new NotationStaff for the specified Segment + * \a id is the id of the staff in the NotationView + */ + NotationStaff(QCanvas *, Segment *, SnapGrid *, + int id, NotationView *view, + std::string fontName, int resolution); + virtual ~NotationStaff(); + + /** + * Changes the resolution of the note pixmap factory and the + * staff lines, etc + */ + virtual void changeFont(std::string fontName, int resolution); + + void setLegerLineCount(int legerLineCount) { + if (legerLineCount == -1) m_legerLineCount = 8; + else m_legerLineCount = legerLineCount; + } + + void setBarNumbersEvery(int barNumbersEvery) { + m_barNumbersEvery = barNumbersEvery; + } + + LinedStaff::setPageMode; + LinedStaff::setPageWidth; + LinedStaff::setRowsPerPage; + LinedStaff::setRowSpacing; + LinedStaff::setConnectingLineLength; + + /** + * Gets a read-only reference to the pixmap factory used by the + * staff. (For use by NotationHLayout, principally.) This + * reference isn't const because the NotePixmapFactory maintains + * too much state for its methods to be const, but you should + * treat the returned reference as if it were const anyway. + */ + virtual NotePixmapFactory& getNotePixmapFactory(bool grace) { + return grace ? *m_graceNotePixmapFactory : *m_notePixmapFactory; + } + + /** + * Generate or re-generate sprites for all the elements between + * from and to. Call this when you've just made a change, + * specifying the extents of the change in the from and to + * parameters. + * + * This method does not reposition any elements outside the given + * range -- so after any edit that may change the visible extents + * of a range, you will then need to call positionElements for the + * changed range and the entire remainder of the staff. + */ + virtual void renderElements(NotationElementList::iterator from, + NotationElementList::iterator to); + + + /** + * Assign suitable coordinates to the elements on the staff, + * based entirely on the layout X and Y coordinates they were + * given by the horizontal and vertical layout processes. + * + * This is necessary because the sprites that are being positioned + * may have been created either after the layout process completed + * (by renderElements) or before (by the previous renderElements + * call, if the sprites are unchanged but have moved) -- so + * neither the layout nor renderElements can authoritatively set + * their final positions. + * + * This method also updates the selected-ness of any elements it + * sees (i.e. it turns the selected ones blue and the unselected + * ones black), and re-generates sprites for any elements for + * which it seems necessary. In general it will only notice a + * element needs regenerating if its position has changed, not if + * the nature of the element has changed, so this is no substitute + * for calling renderElements. + * + * The from and to arguments are used to indicate the extents of a + * changed area within the staff. The actual area within which the + * elements end up being repositioned will begin at the start of + * the bar containing the changed area's start, and will end at the + * start of the next bar whose first element hasn't moved, after + * the changed area's end. + * + * Call this after renderElements, or after changing the selection, + * passing from and to arguments corresponding to the times of those + * passed to renderElements. + */ + virtual void positionElements(timeT from, + timeT to); + + /** + * Re-render and position elements as necessary, based on the + * given extents and any information obtained from calls to + * markChanged(). This provides a render-on-demand mechanism. If + * you are going to use this rendering mechanism, it's generally + * wise to avoid explicitly calling + * renderElements/positionElements as well. + * + * Returns true if something needed re-rendering. + */ + virtual bool checkRendered(timeT from, + timeT to); + + /** + * Find something between the given times that has not yet been + * rendered, and render a small amount of it. Return true if it + * found something to do. This is to be used as a background work + * procedure for rendering not-yet-visible areas of notation. + */ + virtual bool doRenderWork(timeT from, + timeT to); + + /** + * Mark a region of staff as changed, for use by the on-demand + * rendering mechanism. If fromBar == toBar == -1, mark the + * entire staff as changed (and recover the memory used for its + * elements). Pass movedOnly as true to indicate that elements + * have not changed but only been repositioned, for example as a + * consequence of a modification on another staff that caused a + * relayout. + */ + virtual void markChanged(timeT from = 0, + timeT to = 0, + bool movedOnly = false); + + /** + * Set a painter as the printer output. If this painter is + * non-null, subsequent renderElements calls will only render + * those elements that cannot be rendered directly to a print + * painter; those that can, will be rendered by renderPrintable() + * instead. + */ + virtual void setPrintPainter(QPainter *painter); + + /** + * Render to the current print painter those elements that can be + * rendered directly to a print painter. If no print painter is + * set, do nothing. + */ + virtual void renderPrintable(timeT from, + timeT to); + + /** + * Insert time signature at x-coordinate \a x. + */ + virtual void insertTimeSignature(double layoutX, + const TimeSignature &timeSig); + + /** + * Delete all time signatures + */ + virtual void deleteTimeSignatures(); + + /** + * Insert repeated clef and key at start of new line, at x-coordinate \a x. + */ + virtual void insertRepeatedClefAndKey(double layoutX, int barNo); + + /** + * Delete all repeated clefs and keys. + */ + virtual void deleteRepeatedClefsAndKeys(); + + /** + * (Re)draw the staff name from the track's current name + */ + virtual void drawStaffName(); + + /** + * Return true if the staff name as currently drawn is up-to-date + * with that in the composition + */ + virtual bool isStaffNameUpToDate(); + + /** + * Return the clef and key in force at the given canvas + * coordinates + */ + virtual void getClefAndKeyAtCanvasCoords(double x, int y, + Clef &clef, + ::Rosegarden::Key &key) const; + + /** + * Return the note name (C4, Bb3, whatever) corresponding to the + * given canvas coordinates + */ + virtual std::string getNoteNameAtCanvasCoords + (double x, int y, + Accidental accidental = + Accidentals::NoAccidental) const; + + /** + * Find the NotationElement whose layout x-coord is closest to x, + * without regard to its y-coord. + * + * If notesAndRestsOnly is true, will return the closest note + * or rest but will never return any other kind of element. + * + * If the closest event is further than \a proximityThreshold + * horizontally away from x, in pixels, end() is returned. + * (If proximityThreshold is negative, there will be no limit + * to the distances that will be considered.) + * + * Also returns the clef and key in force at the given coordinate. + */ + virtual ViewElementList::iterator getClosestElementToLayoutX + (double x, Event *&clef, Event *&key, + bool notesAndRestsOnly = false, + int proximityThreshold = 10); + + /** + * Find the NotationElement "under" the given layout x-coord, + * without regard to its y-coord. + * + * Also returns the clef and key in force at the given coordinates. + */ + virtual ViewElementList::iterator getElementUnderLayoutX + (double x, Event *&clef, Event *&key); + + /** + * Draw a note on the staff to show an insert position prior to + * an insert. + */ + virtual void showPreviewNote(double layoutX, int heightOnStaff, + const Note ¬e, bool grace); + + /** + * Remove any visible preview note. + */ + virtual void clearPreviewNote(); + + /** + * Overridden from Staff<T>. + * We want to avoid wrapping things like controller events, if + * our showUnknowns preference is off + */ + virtual bool wrapEvent(Event *); + + /** + * Override from Staff<T> + * Let tools know if their current element has gone + */ + virtual void eventRemoved(const Segment *, Event *); + + /** + * Return the view-local PropertyName definitions for this staff's view + */ + const NotationProperties &getProperties() const; + + virtual double getBarInset(int barNo, bool isFirstBarInRow) const; + + /** + * Return the time at the given canvas coordinates + */ + timeT getTimeAtCanvasCoords(double x, int y) const; + +protected: + + virtual ViewElement* makeViewElement(Event*); + + // definition of staff + virtual int getLineCount() const { return 5; } + virtual int getLegerLineCount() const { return m_legerLineCount; } + virtual int getBottomLineHeight() const { return 0; } + virtual int getHeightPerLine() const { return 2; } + virtual int showBarNumbersEvery() const { return m_barNumbersEvery; } + + virtual BarStyle getBarStyle(int barNo) const; + + /** + * Assign a suitable sprite to the given element (the clef is + * needed in case it's a key event, in which case we need to judge + * the correct pitch for the key) + */ + virtual void renderSingleElement(ViewElementList::iterator &, + const Clef &, + const ::Rosegarden::Key &, + bool selected); + + bool isDirectlyPrintable(ViewElement *elt); + + void setTuplingParameters(NotationElement *, NotePixmapParameters &); + + /** + * Set a sprite representing the given note event to the given notation element + */ + virtual void renderNote(ViewElementList::iterator &); + + /** + * Return a NotationElementList::iterator pointing to the + * start of a bar prior to the given time that doesn't appear + * to have been affected by any changes around that time + */ + NotationElementList::iterator findUnchangedBarStart(timeT); + + /** + * Return a NotationElementList::iterator pointing to the + * end of a bar subsequent to the given time that doesn't appear + * to have been affected by any changes around that time + */ + NotationElementList::iterator findUnchangedBarEnd(timeT); + + /** + * Return true if the element has a canvas item that is already + * at the correct coordinates + */ + virtual bool elementNotMoved(NotationElement *); + + /** + * Return true if the element has a canvas item that is already + * at the correct y-coordinate + */ + virtual bool elementNotMovedInY(NotationElement *); + + /** + * Returns true if the item at the given iterator appears to have + * moved horizontally without the spacing around it changing. + * + * In practice, calculates the offset between the intended layout + * and current canvas coordinates of the item at the given + * iterator, and returns true if this offset is equal to those of + * all other following iterators at the same time as well as the + * first iterator found at a greater time. + */ + virtual bool elementShiftedOnly(NotationElementList::iterator); + + enum FitPolicy { + PretendItFittedAllAlong = 0, + MoveBackToFit, + SplitToFit + }; + + /** + * Prepare a painter to draw an object of logical width w at + * layout-x coord x, starting at offset dx into the object, by + * setting the painter's clipping so as to crop the object at the + * right edge of the row if it would otherwise overrun. The + * return value is the amount of the object visible on this row + * (i.e. the increment in offset for the next call to this method) + * or zero if no crop was necessary. The canvas coords at which + * the object should subsequently be drawn are returned in coords. + * + * This function calls painter.save(), and the caller must call + * painter.restore() after use. + */ + virtual double setPainterClipping(QPainter *, double layoutX, int layoutY, + double dx, double w, LinedStaffCoords &coords, + FitPolicy policy); + + /** + * Set a single pixmap to a notation element, or split it into + * bits if it overruns the end of a row and set the bits + * separately. + */ + virtual void setPixmap(NotationElement *, QCanvasPixmap *, int z, + FitPolicy policy); + + bool isSelected(NotationElementList::iterator); + + typedef std::set<QCanvasSimpleSprite *> SpriteSet; + SpriteSet m_timeSigs; + + typedef std::set<QCanvasItem *> ItemSet; + ItemSet m_repeatedClefsAndKeys; + + typedef std::pair<int, Clef> ClefChange; + FastVector<ClefChange> m_clefChanges; + + typedef std::pair<int, ::Rosegarden::Key> KeyChange; + FastVector<KeyChange> m_keyChanges; + + void truncateClefsAndKeysAt(int); + + /** Verify that a possible Clef or Key in bar is already inserted + * in m_clefChange or m_keyChange. + * If not, do the insertion. + */ + void checkAndCompleteClefsAndKeys(int bar); + + NotePixmapFactory *m_notePixmapFactory; + NotePixmapFactory *m_graceNotePixmapFactory; + QCanvasSimpleSprite *m_previewSprite; + QCanvasSimpleSprite *m_staffName; + std::string m_staffNameText; + NotationView *m_notationView; + int m_legerLineCount; + int m_barNumbersEvery; + bool m_colourQuantize; + bool m_showUnknowns; + bool m_showRanges; + bool m_showCollisions; + int m_keySigCancelMode; + + QPainter *m_printPainter; + + enum BarStatus { UnRendered = 0, Rendered, Positioned }; + typedef std::map<int, BarStatus> BarStatusMap; + BarStatusMap m_status; + std::pair<int, int> m_lastRenderCheck; + bool m_ready; + + int m_lastRenderedBar; +}; + + +} + +#endif |