summaryrefslogtreecommitdiffstats
path: root/src/gui/editors/notation/NotationStaff.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/editors/notation/NotationStaff.cpp')
-rw-r--r--src/gui/editors/notation/NotationStaff.cpp2300
1 files changed, 2300 insertions, 0 deletions
diff --git a/src/gui/editors/notation/NotationStaff.cpp b/src/gui/editors/notation/NotationStaff.cpp
new file mode 100644
index 0000000..c5219b4
--- /dev/null
+++ b/src/gui/editors/notation/NotationStaff.cpp
@@ -0,0 +1,2300 @@
+/* -*- 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 <[email protected]>,
+ Chris Cannam <[email protected]>,
+ Richard Bown <[email protected]>
+
+ 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.
+*/
+
+
+#include "NotationStaff.h"
+#include "misc/Debug.h"
+#include <kapplication.h>
+
+#include <klocale.h>
+#include "misc/Strings.h"
+#include "document/ConfigGroups.h"
+#include "base/Composition.h"
+#include "base/Device.h"
+#include "base/Event.h"
+#include "base/Exception.h"
+#include "base/Instrument.h"
+#include "base/MidiDevice.h"
+#include "base/MidiTypes.h"
+#include "base/NotationQuantizer.h"
+#include "base/NotationRules.h"
+#include "base/NotationTypes.h"
+#include "base/Profiler.h"
+#include "base/Segment.h"
+#include "base/Selection.h"
+#include "base/SnapGrid.h"
+#include "base/Staff.h"
+#include "base/Studio.h"
+#include "base/Track.h"
+#include "base/ViewElement.h"
+#include "document/RosegardenGUIDoc.h"
+#include "gui/editors/guitar/Chord.h"
+#include "gui/general/LinedStaff.h"
+#include "gui/general/PixmapFunctions.h"
+#include "gui/general/ProgressReporter.h"
+#include "gui/kdeext/QCanvasSimpleSprite.h"
+#include "NotationChord.h"
+#include "NotationElement.h"
+#include "NotationProperties.h"
+#include "NotationView.h"
+#include "NoteFontFactory.h"
+#include "NotePixmapFactory.h"
+#include "NotePixmapParameters.h"
+#include "NoteStyleFactory.h"
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <qcanvas.h>
+#include <qpainter.h>
+#include <qpoint.h>
+#include <qrect.h>
+
+
+namespace Rosegarden
+{
+
+NotationStaff::NotationStaff(QCanvas *canvas, Segment *segment,
+ SnapGrid *snapGrid, int id,
+ NotationView *view,
+ std::string fontName, int resolution) :
+ ProgressReporter(0),
+ LinedStaff(canvas, segment, snapGrid, id, resolution,
+ resolution / 16 + 1, // line thickness
+ LinearMode, 0, 0, // pageMode, pageWidth and pageHeight set later
+ 0 // row spacing
+ ),
+ m_notePixmapFactory(0),
+ m_graceNotePixmapFactory(0),
+ m_previewSprite(0),
+ m_staffName(0),
+ m_notationView(view),
+ m_legerLineCount(8),
+ m_barNumbersEvery(0),
+ m_colourQuantize(true),
+ m_showUnknowns(true),
+ m_showRanges(true),
+ m_showCollisions(true),
+ m_printPainter(0),
+ m_ready(false),
+ m_lastRenderedBar(0)
+{
+ KConfig *config = kapp->config();
+ config->setGroup(NotationViewConfigGroup);
+ m_colourQuantize = config->readBoolEntry("colourquantize", false);
+
+ // Shouldn't change these during the lifetime of the staff, really:
+ m_showUnknowns = config->readBoolEntry("showunknowns", false);
+ m_showRanges = config->readBoolEntry("showranges", true);
+ m_showCollisions = config->readBoolEntry("showcollisions", true);
+
+ m_keySigCancelMode = config->readNumEntry("keysigcancelmode", 1);
+
+ changeFont(fontName, resolution);
+}
+
+NotationStaff::~NotationStaff()
+{
+ deleteTimeSignatures();
+ delete m_notePixmapFactory;
+ delete m_graceNotePixmapFactory;
+}
+
+void
+NotationStaff::changeFont(std::string fontName, int size)
+{
+ setResolution(size);
+
+ delete m_notePixmapFactory;
+ m_notePixmapFactory = new NotePixmapFactory(fontName, size);
+
+ std::vector<int> sizes = NoteFontFactory::getScreenSizes(fontName);
+ int graceSize = size;
+ for (unsigned int i = 0; i < sizes.size(); ++i) {
+ if (sizes[i] == size || sizes[i] > size*3 / 4)
+ break;
+ graceSize = sizes[i];
+ }
+ delete m_graceNotePixmapFactory;
+ m_graceNotePixmapFactory = new NotePixmapFactory(fontName, graceSize);
+
+ setLineThickness(m_notePixmapFactory->getStaffLineThickness());
+}
+
+void
+NotationStaff::insertTimeSignature(double layoutX,
+ const TimeSignature &timeSig)
+{
+ if (timeSig.isHidden())
+ return ;
+
+ m_notePixmapFactory->setSelected(false);
+ QCanvasPixmap *pixmap = m_notePixmapFactory->makeTimeSigPixmap(timeSig);
+ QCanvasTimeSigSprite *sprite =
+ new QCanvasTimeSigSprite(layoutX, pixmap, m_canvas);
+
+ LinedStaffCoords sigCoords =
+ getCanvasCoordsForLayoutCoords(layoutX, getLayoutYForHeight(4));
+
+ sprite->move(sigCoords.first, (double)sigCoords.second);
+ sprite->show();
+ m_timeSigs.insert(sprite);
+}
+
+void
+NotationStaff::deleteTimeSignatures()
+{
+ // NOTATION_DEBUG << "NotationStaff::deleteTimeSignatures()" << endl;
+
+ for (SpriteSet::iterator i = m_timeSigs.begin();
+ i != m_timeSigs.end(); ++i) {
+ delete *i;
+ }
+
+ m_timeSigs.clear();
+}
+
+void
+NotationStaff::insertRepeatedClefAndKey(double layoutX, int barNo)
+{
+ bool needClef = false, needKey = false;
+ timeT t;
+
+ timeT barStart = getSegment().getComposition()->getBarStart(barNo);
+
+ Clef clef = getSegment().getClefAtTime(barStart, t);
+ if (t < barStart)
+ needClef = true;
+
+ ::Rosegarden::Key key = getSegment().getKeyAtTime(barStart, t);
+ if (t < barStart)
+ needKey = true;
+
+ double dx = m_notePixmapFactory->getBarMargin() / 2;
+
+ if (!m_notationView->isInPrintMode())
+ m_notePixmapFactory->setShaded(true);
+
+ if (needClef) {
+
+ int layoutY = getLayoutYForHeight(clef.getAxisHeight());
+
+ LinedStaffCoords coords =
+ getCanvasCoordsForLayoutCoords(layoutX + dx, layoutY);
+
+ QCanvasPixmap *pixmap = m_notePixmapFactory->makeClefPixmap(clef);
+
+ QCanvasNonElementSprite *sprite =
+ new QCanvasNonElementSprite(pixmap, m_canvas);
+
+ sprite->move(coords.first, coords.second);
+ sprite->show();
+ m_repeatedClefsAndKeys.insert(sprite);
+
+ dx += pixmap->width() + m_notePixmapFactory->getNoteBodyWidth() * 2 / 3;
+ }
+
+ if (needKey) {
+
+ int layoutY = getLayoutYForHeight(12);
+
+ LinedStaffCoords coords =
+ getCanvasCoordsForLayoutCoords(layoutX + dx, layoutY);
+
+ QCanvasPixmap *pixmap = m_notePixmapFactory->makeKeyPixmap(key, clef);
+
+ QCanvasNonElementSprite *sprite =
+ new QCanvasNonElementSprite(pixmap, m_canvas);
+
+ sprite->move(coords.first, coords.second);
+ sprite->show();
+ m_repeatedClefsAndKeys.insert(sprite);
+
+ dx += pixmap->width();
+ }
+
+ /* attempt to blot out things like slurs & ties that overrun this area: doesn't work
+
+ if (m_notationView->isInPrintMode() && (needClef || needKey)) {
+
+ int layoutY = getLayoutYForHeight(14);
+ int h = getLayoutYForHeight(-8) - layoutY;
+
+ LinedStaffCoords coords =
+ getCanvasCoordsForLayoutCoords(layoutX, layoutY);
+
+ QCanvasRectangle *rect = new QCanvasRectangle(coords.first, coords.second,
+ dx, h, m_canvas);
+ rect->setPen(Qt::black);
+ rect->setBrush(Qt::white);
+ rect->setZ(1);
+ rect->show();
+
+ m_repeatedClefsAndKeys.insert(rect);
+ }
+ */
+
+ m_notePixmapFactory->setShaded(false);
+}
+
+void
+NotationStaff::deleteRepeatedClefsAndKeys()
+{
+ for (ItemSet::iterator i = m_repeatedClefsAndKeys.begin();
+ i != m_repeatedClefsAndKeys.end(); ++i) {
+ delete *i;
+ }
+
+ m_repeatedClefsAndKeys.clear();
+}
+
+void
+NotationStaff::drawStaffName()
+{
+ delete m_staffName;
+
+ m_staffNameText =
+ getSegment().getComposition()->
+ getTrackById(getSegment().getTrack())->getLabel();
+
+ QCanvasPixmap *map =
+ m_notePixmapFactory->makeTextPixmap
+ (Text(m_staffNameText, Text::StaffName));
+
+ m_staffName = new QCanvasStaffNameSprite(map, m_canvas);
+
+ int layoutY = getLayoutYForHeight(3);
+ LinedStaffCoords coords = getCanvasCoordsForLayoutCoords(0, layoutY);
+ m_staffName->move(getX() + getMargin() + m_notePixmapFactory->getNoteBodyWidth(),
+ coords.second - map->height() / 2);
+ m_staffName->show();
+}
+
+bool
+NotationStaff::isStaffNameUpToDate()
+{
+ return (m_staffNameText ==
+ getSegment().getComposition()->
+ getTrackById(getSegment().getTrack())->getLabel());
+}
+
+timeT
+NotationStaff::getTimeAtCanvasCoords(double cx, int cy) const
+{
+ LinedStaffCoords layoutCoords = getLayoutCoordsForCanvasCoords(cx, cy);
+ RulerScale * rs = m_notationView->getHLayout();
+ return rs->getTimeForX(layoutCoords.first);
+}
+
+void
+NotationStaff::getClefAndKeyAtCanvasCoords(double cx, int cy,
+ Clef &clef,
+ ::Rosegarden::Key &key) const
+{
+ LinedStaffCoords layoutCoords = getLayoutCoordsForCanvasCoords(cx, cy);
+ int i;
+
+ for (i = 0; i < m_clefChanges.size(); ++i) {
+ if (m_clefChanges[i].first > layoutCoords.first)
+ break;
+ clef = m_clefChanges[i].second;
+ }
+
+ for (i = 0; i < m_keyChanges.size(); ++i) {
+ if (m_keyChanges[i].first > layoutCoords.first)
+ break;
+ key = m_keyChanges[i].second;
+ }
+}
+
+ViewElementList::iterator
+NotationStaff::getClosestElementToLayoutX(double x,
+ Event *&clef,
+ Event *&key,
+ bool notesAndRestsOnly,
+ int proximityThreshold)
+{
+ START_TIMING;
+
+ double minDist = 10e9, prevDist = 10e9;
+
+ NotationElementList *notes = getViewElementList();
+ NotationElementList::iterator it, result;
+
+ // TODO: this is grossly inefficient
+
+ for (it = notes->begin(); it != notes->end(); ++it) {
+ NotationElement *el = static_cast<NotationElement*>(*it);
+
+ bool before = ((*it)->getLayoutX() < x);
+
+ if (!el->isNote() && !el->isRest()) {
+ if (before) {
+ if ((*it)->event()->isa(Clef::EventType)) {
+ clef = (*it)->event();
+ } else if ((*it)->event()->isa(::Rosegarden::Key::EventType)) {
+ key = (*it)->event();
+ }
+ }
+ if (notesAndRestsOnly)
+ continue;
+ }
+
+ double dx = x - (*it)->getLayoutX();
+ if (dx < 0)
+ dx = -dx;
+
+ if (dx < minDist) {
+ minDist = dx;
+ result = it;
+ } else if (!before) {
+ break;
+ }
+
+ prevDist = dx;
+ }
+
+ if (proximityThreshold > 0 && minDist > proximityThreshold) {
+ NOTATION_DEBUG << "NotationStaff::getClosestElementToLayoutX() : element is too far away : "
+ << minDist << endl;
+ return notes->end();
+ }
+
+ NOTATION_DEBUG << "NotationStaff::getClosestElementToLayoutX: found element at layout " << (*result)->getLayoutX() << " - we're at layout " << x << endl;
+
+ PRINT_ELAPSED("NotationStaff::getClosestElementToLayoutX");
+
+ return result;
+}
+
+ViewElementList::iterator
+NotationStaff::getElementUnderLayoutX(double x,
+ Event *&clef,
+ Event *&key)
+{
+ NotationElementList *notes = getViewElementList();
+ NotationElementList::iterator it;
+
+ // TODO: this is grossly inefficient
+
+ for (it = notes->begin(); it != notes->end(); ++it) {
+ NotationElement* el = static_cast<NotationElement*>(*it);
+
+ bool before = ((*it)->getLayoutX() <= x);
+
+ if (!el->isNote() && !el->isRest()) {
+ if (before) {
+ if ((*it)->event()->isa(Clef::EventType)) {
+ clef = (*it)->event();
+ } else if ((*it)->event()->isa(::Rosegarden::Key::EventType)) {
+ key = (*it)->event();
+ }
+ }
+ }
+
+ double airX, airWidth;
+ el->getLayoutAirspace(airX, airWidth);
+ if (x >= airX && x < airX + airWidth) {
+ return it;
+ } else if (!before) {
+ if (it != notes->begin())
+ --it;
+ return it;
+ }
+ }
+
+ return notes->end();
+}
+
+std::string
+NotationStaff::getNoteNameAtCanvasCoords(double x, int y,
+ Accidental) const
+{
+ Clef clef;
+ ::Rosegarden::Key key;
+ getClefAndKeyAtCanvasCoords(x, y, clef, key);
+
+ KConfig *config = kapp->config();
+ config->setGroup(GeneralOptionsConfigGroup);
+ int baseOctave = config->readNumEntry("midipitchoctave", -2);
+
+ Pitch p(getHeightAtCanvasCoords(x, y), clef, key);
+ //!!! i18n() how?
+ return p.getAsString(key.isSharp(), true, baseOctave);
+}
+
+void
+NotationStaff::renderElements(NotationElementList::iterator from,
+ NotationElementList::iterator to)
+{
+ // NOTATION_DEBUG << "NotationStaff " << this << "::renderElements()" << endl;
+ Profiler profiler("NotationStaff::renderElements");
+
+ emit setOperationName(i18n("Rendering staff %1...").arg(getId() + 1));
+ emit setProgress(0);
+
+ throwIfCancelled();
+
+ // These are only used when rendering keys, and we don't have the
+ // right start data here so we choose not to render keys at all in
+ // this method (see below) so that we can pass bogus clef and key
+ // data to renderSingleElement
+ Clef currentClef;
+ ::Rosegarden::Key currentKey;
+
+ int elementCount = 0;
+ timeT endTime =
+ (to != getViewElementList()->end() ? (*to)->getViewAbsoluteTime() :
+ getSegment().getEndMarkerTime());
+ timeT startTime = (from != to ? (*from)->getViewAbsoluteTime() : endTime);
+
+ for (NotationElementList::iterator it = from, nextIt = from;
+ it != to; it = nextIt) {
+
+ ++nextIt;
+
+ if (isDirectlyPrintable(*it)) {
+ // notes are renderable direct to the printer, so don't render
+ // them to the canvas here
+ continue;
+ }
+
+ if ((*it)->event()->isa(::Rosegarden::Key::EventType)) {
+ // force rendering in positionElements instead
+ NotationElement* el = static_cast<NotationElement*>(*it);
+ el->removeCanvasItem();
+ continue;
+ }
+
+ bool selected = isSelected(it);
+ // NOTATION_DEBUG << "Rendering at " << (*it)->getAbsoluteTime()
+ // << " (selected = " << selected << ")" << endl;
+
+ renderSingleElement(it, currentClef, currentKey, selected);
+
+ if ((endTime > startTime) &&
+ (++elementCount % 200 == 0)) {
+
+ timeT myTime = (*it)->getViewAbsoluteTime();
+ emit setProgress((myTime - startTime) * 100 / (endTime - startTime));
+ throwIfCancelled();
+ }
+ }
+
+ // NOTATION_DEBUG << "NotationStaff " << this << "::renderElements: "
+ // << elementCount << " elements rendered" << endl;
+}
+
+void
+NotationStaff::renderPrintable(timeT from, timeT to)
+{
+ if (!m_printPainter)
+ return ;
+
+ Profiler profiler("NotationStaff::renderElements");
+
+ emit setOperationName(i18n("Rendering notes on staff %1...").arg(getId() + 1));
+ emit setProgress(0);
+
+ throwIfCancelled();
+
+ // These are only used when rendering keys, and we don't do that
+ // here, so we don't care what they are
+ Clef currentClef;
+ ::Rosegarden::Key currentKey;
+
+ Composition *composition = getSegment().getComposition();
+ NotationElementList::iterator beginAt =
+ getViewElementList()->findTime(composition->getBarStartForTime(from));
+ NotationElementList::iterator endAt =
+ getViewElementList()->findTime(composition->getBarEndForTime(to));
+
+ int elementCount = 0;
+
+ for (NotationElementList::iterator it = beginAt, nextIt = beginAt;
+ it != endAt; it = nextIt) {
+
+ ++nextIt;
+
+ if (!isDirectlyPrintable(*it)) {
+ continue;
+ }
+
+ bool selected = isSelected(it);
+ // NOTATION_DEBUG << "Rendering at " << (*it)->getAbsoluteTime()
+ // << " (selected = " << selected << ")" << endl;
+
+ renderSingleElement(it, currentClef, currentKey, selected);
+
+ if ((to > from) && (++elementCount % 200 == 0)) {
+
+ timeT myTime = (*it)->getViewAbsoluteTime();
+ emit setProgress((myTime - from) * 100 / (to - from));
+ throwIfCancelled();
+ }
+ }
+
+ // NOTATION_DEBUG << "NotationStaff " << this << "::renderElements: "
+ // << elementCount << " elements rendered" << endl;
+}
+
+const NotationProperties &
+NotationStaff::getProperties() const
+{
+ return m_notationView->getProperties();
+}
+
+void
+NotationStaff::positionElements(timeT from, timeT to)
+{
+ // NOTATION_DEBUG << "NotationStaff " << this << "::positionElements()"
+ // << from << " -> " << to << endl;
+ Profiler profiler("NotationStaff::positionElements");
+
+ // Following 4 lines are a workaround to not have m_clefChanges and
+ // m_keyChanges truncated when positionElements() is called with
+ // args outside current segment.
+ // Maybe a better fix would be not to call positionElements() with
+ // such args ...
+ int startTime = getSegment().getStartTime();
+ if (from < startTime) from = startTime;
+ if (to < startTime) to = startTime;
+ if (to == from) return;
+
+ emit setOperationName(i18n("Positioning staff %1...").arg(getId() + 1));
+ emit setProgress(0);
+ throwIfCancelled();
+
+ const NotationProperties &properties(getProperties());
+
+ int elementsPositioned = 0;
+ int elementsRendered = 0; // diagnostic
+
+ Composition *composition = getSegment().getComposition();
+
+ timeT nextBarTime = composition->getBarEndForTime(to);
+
+ NotationElementList::iterator beginAt =
+ getViewElementList()->findTime(composition->getBarStartForTime(from));
+
+ NotationElementList::iterator endAt =
+ getViewElementList()->findTime(composition->getBarEndForTime(to));
+
+ if (beginAt == getViewElementList()->end())
+ return ;
+
+ truncateClefsAndKeysAt(static_cast<int>((*beginAt)->getLayoutX()));
+
+ Clef currentClef; // used for rendering key sigs
+ bool haveCurrentClef = false;
+
+ ::Rosegarden::Key currentKey;
+ bool haveCurrentKey = false;
+
+ for (NotationElementList::iterator it = beginAt, nextIt = beginAt;
+ it != endAt; it = nextIt) {
+
+ NotationElement * el = static_cast<NotationElement*>(*it);
+
+ ++nextIt;
+
+ if (el->event()->isa(Clef::EventType)) {
+
+ currentClef = Clef(*el->event());
+ m_clefChanges.push_back(ClefChange(int(el->getLayoutX()),
+ currentClef));
+ haveCurrentClef = true;
+
+ } else if (el->event()->isa(::Rosegarden::Key::EventType)) {
+
+ m_keyChanges.push_back
+ (KeyChange(int(el->getLayoutX()),
+ ::Rosegarden::Key(*el->event())));
+
+ if (!haveCurrentClef) { // need this to know how to present the key
+ currentClef = getSegment().getClefAtTime
+ (el->event()->getAbsoluteTime());
+ haveCurrentClef = true;
+ }
+
+ if (!haveCurrentKey) { // stores the key _before_ this one
+ currentKey = getSegment().getKeyAtTime
+ (el->event()->getAbsoluteTime() - 1);
+ haveCurrentKey = true;
+ }
+
+ } else if (isDirectlyPrintable(el)) {
+ // these are rendered by renderPrintable for printing
+ continue;
+ }
+
+ bool selected = isSelected(it);
+ bool needNewSprite = (selected != el->isSelected());
+
+ if (!el->getCanvasItem()) {
+
+ needNewSprite = true;
+
+ } else if (el->isNote() && !el->isRecentlyRegenerated()) {
+
+ // If the note's y-coordinate has changed, we should
+ // redraw it -- its stem direction may have changed, or it
+ // may need leger lines. This will happen e.g. if the
+ // user inserts a new clef; unfortunately this means
+ // inserting clefs is rather slow.
+
+ needNewSprite = needNewSprite || !elementNotMovedInY(el);
+
+ if (!needNewSprite) {
+
+ // If the event is a beamed or tied-forward note, then
+ // we might need a new sprite if the distance from
+ // this note to the next has changed (because the beam
+ // or tie is part of the note's sprite).
+
+ bool spanning = false;
+ (void)(el->event()->get
+ <Bool>
+ (properties.BEAMED, spanning));
+ if (!spanning) {
+ (void)(el->event()->get
+ <Bool>(BaseProperties::TIED_FORWARD, spanning));
+ }
+
+ if (spanning) {
+ needNewSprite =
+ (el->getViewAbsoluteTime() < nextBarTime ||
+ !elementShiftedOnly(it));
+ }
+ }
+
+ } else if (el->event()->isa(Indication::EventType) &&
+ !el->isRecentlyRegenerated()) {
+ needNewSprite = true;
+ }
+
+ if (needNewSprite) {
+ renderSingleElement(it, currentClef, currentKey, selected);
+ ++elementsRendered;
+ }
+
+ if (el->event()->isa(::Rosegarden::Key::EventType)) {
+ // update currentKey after rendering, not before
+ currentKey = ::Rosegarden::Key(*el->event());
+ }
+
+ if (!needNewSprite) {
+ LinedStaffCoords coords = getCanvasCoordsForLayoutCoords
+ (el->getLayoutX(), (int)el->getLayoutY());
+ el->reposition(coords.first, (double)coords.second);
+ }
+
+ el->setSelected(selected);
+
+ if ((to > from) &&
+ (++elementsPositioned % 300 == 0)) {
+ timeT myTime = el->getViewAbsoluteTime();
+ emit setProgress((myTime - from) * 100 / (to - from));
+ throwIfCancelled();
+ }
+ }
+
+ // NOTATION_DEBUG << "NotationStaff " << this << "::positionElements "
+ // << from << " -> " << to << ": "
+ // << elementsPositioned << " elements positioned, "
+ // << elementsRendered << " re-rendered"
+ // << endl;
+
+ // NotePixmapFactory::dumpStats(std::cerr);
+}
+
+void
+NotationStaff::truncateClefsAndKeysAt(int x)
+{
+ for (FastVector<ClefChange>::iterator i = m_clefChanges.begin();
+ i != m_clefChanges.end(); ++i) {
+ if (i->first >= x) {
+ m_clefChanges.erase(i, m_clefChanges.end());
+ break;
+ }
+ }
+
+ for (FastVector<KeyChange>::iterator i = m_keyChanges.begin();
+ i != m_keyChanges.end(); ++i) {
+ if (i->first >= x) {
+ m_keyChanges.erase(i, m_keyChanges.end());
+ break;
+ }
+ }
+}
+
+NotationElementList::iterator
+NotationStaff::findUnchangedBarStart(timeT from)
+{
+ NotationElementList *nel = (NotationElementList *)getViewElementList();
+
+ // Track back bar-by-bar until we find one whose start position
+ // hasn't changed
+
+ NotationElementList::iterator beginAt = nel->begin();
+ do {
+ from = getSegment().getComposition()->getBarStartForTime(from - 1);
+ beginAt = nel->findTime(from);
+ } while (beginAt != nel->begin() &&
+ (beginAt == nel->end() || !elementNotMoved(static_cast<NotationElement*>(*beginAt))));
+
+ return beginAt;
+}
+
+NotationElementList::iterator
+NotationStaff::findUnchangedBarEnd(timeT to)
+{
+ NotationElementList *nel = (NotationElementList *)getViewElementList();
+
+ // Track forward to the end, similarly. Here however it's very
+ // common for all the positions to have changed right up to the
+ // end of the piece; so we save time by assuming that to be the
+ // case if we get more than (arbitrary) 3 changed bars.
+
+ // We also record the start of the bar following the changed
+ // section, for later use.
+
+ NotationElementList::iterator endAt = nel->end();
+
+ int changedBarCount = 0;
+ NotationElementList::iterator candidate = nel->end();
+ do {
+ candidate = nel->findTime(getSegment().getBarEndForTime(to));
+ if (candidate != nel->end()) {
+ to = (*candidate)->getViewAbsoluteTime();
+ }
+ ++changedBarCount;
+ } while (changedBarCount < 4 &&
+ candidate != nel->end() &&
+ !elementNotMoved(static_cast<NotationElement*>(*candidate)));
+
+ if (changedBarCount < 4)
+ return candidate;
+ else
+ return endAt;
+}
+
+bool
+NotationStaff::elementNotMoved(NotationElement *elt)
+{
+ if (!elt->getCanvasItem())
+ return false;
+
+ LinedStaffCoords coords = getCanvasCoordsForLayoutCoords
+ (elt->getLayoutX(), (int)elt->getLayoutY());
+
+ bool ok =
+ (int)(elt->getCanvasX()) == (int)(coords.first) &&
+ (int)(elt->getCanvasY()) == (int)(coords.second);
+
+ if (!ok) {
+ NOTATION_DEBUG
+ << "elementNotMoved: elt at " << elt->getViewAbsoluteTime() <<
+ ", ok is " << ok << endl;
+ NOTATION_DEBUG << "(cf " << (int)(elt->getCanvasX()) << " vs "
+ << (int)(coords.first) << ", "
+ << (int)(elt->getCanvasY()) << " vs "
+ << (int)(coords.second) << ")" << endl;
+ } else {
+ NOTATION_DEBUG << "elementNotMoved: elt at " << elt->getViewAbsoluteTime()
+ << " is ok" << endl;
+ }
+
+ return ok;
+}
+
+bool
+NotationStaff::elementNotMovedInY(NotationElement *elt)
+{
+ if (!elt->getCanvasItem())
+ return false;
+
+ LinedStaffCoords coords = getCanvasCoordsForLayoutCoords
+ (elt->getLayoutX(), (int)elt->getLayoutY());
+
+ bool ok = (int)(elt->getCanvasY()) == (int)(coords.second);
+
+ // if (!ok) {
+ // NOTATION_DEBUG
+ // << "elementNotMovedInY: elt at " << elt->getAbsoluteTime() <<
+ // ", ok is " << ok << endl;
+ // NOTATION_DEBUG << "(cf " << (int)(elt->getCanvasY()) << " vs "
+ // << (int)(coords.second) << ")" << std::endl;
+ // }
+ return ok;
+}
+
+bool
+NotationStaff::elementShiftedOnly(NotationElementList::iterator i)
+{
+ int shift = 0;
+ bool ok = false;
+
+ for (NotationElementList::iterator j = i;
+ j != getViewElementList()->end(); ++j) {
+
+ NotationElement *elt = static_cast<NotationElement*>(*j);
+ if (!elt->getCanvasItem())
+ break;
+
+ LinedStaffCoords coords = getCanvasCoordsForLayoutCoords
+ (elt->getLayoutX(), (int)elt->getLayoutY());
+
+ // regard any shift in y as suspicious
+ if ((int)(elt->getCanvasY()) != (int)(coords.second))
+ break;
+
+ int myShift = (int)(elt->getCanvasX()) - (int)(coords.first);
+ if (j == i)
+ shift = myShift;
+ else if (myShift != shift)
+ break;
+
+ if (elt->getViewAbsoluteTime() > (*i)->getViewAbsoluteTime()) {
+ // all events up to and including this one have passed
+ ok = true;
+ break;
+ }
+ }
+
+ if (!ok) {
+ NOTATION_DEBUG
+ << "elementShiftedOnly: elt at " << (*i)->getViewAbsoluteTime()
+ << ", ok is " << ok << endl;
+ }
+
+ return ok;
+}
+
+bool
+NotationStaff::isDirectlyPrintable(ViewElement *velt)
+{
+ if (!m_printPainter)
+ return false;
+ return (velt->event()->isa(Note::EventType) ||
+ velt->event()->isa(Note::EventRestType) ||
+ velt->event()->isa(Text::EventType) ||
+ velt->event()->isa(Indication::EventType));
+}
+
+void
+NotationStaff::renderSingleElement(ViewElementList::iterator &vli,
+ const Clef &currentClef,
+ const ::Rosegarden::Key &currentKey,
+ bool selected)
+{
+ const NotationProperties &properties(getProperties());
+ static NotePixmapParameters restParams(Note::Crotchet, 0);
+
+ NotationElement* elt = static_cast<NotationElement*>(*vli);
+
+ bool invisible = false;
+ if (elt->event()->get
+ <Bool>(BaseProperties::INVISIBLE, invisible) && invisible) {
+ if (m_printPainter)
+ return ;
+ KConfig *config = kapp->config();
+ config->setGroup("Notation Options");
+ bool showInvisibles = config->readBoolEntry("showinvisibles", true);
+ if (!showInvisibles)
+ return ;
+ }
+
+ try {
+ m_notePixmapFactory->setNoteStyle
+ (NoteStyleFactory::getStyleForEvent(elt->event()));
+
+ } catch (NoteStyleFactory::StyleUnavailable u) {
+
+ std::cerr << "WARNING: Note style unavailable: "
+ << u.getMessage() << std::endl;
+
+ static bool warned = false;
+ if (!warned) {
+ KMessageBox::error(0, i18n(strtoqstr(u.getMessage())));
+ warned = true;
+ }
+ }
+
+ try {
+
+ QCanvasPixmap *pixmap = 0;
+
+ m_notePixmapFactory->setSelected(selected);
+ m_notePixmapFactory->setShaded(invisible);
+ int z = selected ? 3 : 0;
+
+ // these are actually only used for the printer stuff
+ LinedStaffCoords coords;
+ if (m_printPainter)
+ coords = getCanvasCoordsForLayoutCoords
+ (elt->getLayoutX(), (int)elt->getLayoutY());
+
+ FitPolicy policy = PretendItFittedAllAlong;
+
+ if (elt->isNote()) {
+
+ renderNote(vli);
+
+ } else if (elt->isRest()) {
+
+ bool ignoreRest = false;
+ // NotationHLayout sets this property if it finds the rest
+ // in the middle of a chord -- Quantizer still sometimes gets
+ // this wrong
+ elt->event()->get
+ <Bool>(properties.REST_TOO_SHORT, ignoreRest);
+
+ if (!ignoreRest) {
+
+ Note::Type note = elt->event()->get
+ <Int>(BaseProperties::NOTE_TYPE);
+ int dots = elt->event()->get
+ <Int>(BaseProperties::NOTE_DOTS);
+ restParams.setNoteType(note);
+ restParams.setDots(dots);
+ setTuplingParameters(elt, restParams);
+ restParams.setQuantized(false);
+ bool restOutside = false;
+ elt->event()->get
+ <Bool>(properties.REST_OUTSIDE_STAVE,
+ restOutside);
+ restParams.setRestOutside(restOutside);
+ if (restOutside) {
+ NOTATION_DEBUG << "NotationStaff::renderSingleElement() : rest outside staff" << endl;
+ if (note == Note::DoubleWholeNote) {
+ NOTATION_DEBUG << "NotationStaff::renderSingleElement() : breve rest needs leger lines" << endl;
+ restParams.setLegerLines(5);
+ }
+ }
+
+ if (m_printPainter) {
+ m_notePixmapFactory->drawRest
+ (restParams,
+ *m_printPainter, int(coords.first), coords.second);
+ } else {
+ pixmap = m_notePixmapFactory->makeRestPixmap(restParams);
+ }
+ }
+
+ } else if (elt->event()->isa(Clef::EventType)) {
+
+ pixmap = m_notePixmapFactory->makeClefPixmap
+ (Clef(*elt->event()));
+
+ } else if (elt->event()->isa(::Rosegarden::Key::EventType)) {
+
+ ::Rosegarden::Key key(*elt->event());
+ ::Rosegarden::Key cancelKey = currentKey;
+
+ if (m_keySigCancelMode == 0) { // only when entering C maj / A min
+
+ if (key.getAccidentalCount() != 0)
+ cancelKey = ::Rosegarden::Key();
+
+ } else if (m_keySigCancelMode == 1) { // only when reducing acc count
+
+ if (!(key.isSharp() == cancelKey.isSharp() &&
+ key.getAccidentalCount() < cancelKey.getAccidentalCount())) {
+ cancelKey = ::Rosegarden::Key();
+ }
+ }
+
+ pixmap = m_notePixmapFactory->makeKeyPixmap
+ (key, currentClef, cancelKey);
+
+ } else if (elt->event()->isa(Text::EventType)) {
+
+ policy = MoveBackToFit;
+
+ if (elt->event()->has(Text::TextTypePropertyName) &&
+ elt->event()->get
+ <String>
+ (Text::TextTypePropertyName) ==
+ Text::Annotation &&
+ !m_notationView->areAnnotationsVisible()) {
+
+ // nothing I guess
+
+ }
+ else if (elt->event()->has(Text::TextTypePropertyName) &&
+ elt->event()->get
+ <String>
+ (Text::TextTypePropertyName) ==
+ Text::LilyPondDirective &&
+ !m_notationView->areLilyPondDirectivesVisible()) {
+
+ // nothing here either
+
+ }
+ else {
+
+ try {
+ if (m_printPainter) {
+ Text text(*elt->event());
+ int length = m_notePixmapFactory->getTextWidth(text);
+ for (double w = -1, inc = 0; w != 0; inc += w) {
+ w = setPainterClipping(m_printPainter,
+ elt->getLayoutX(),
+ int(elt->getLayoutY()),
+ int(inc), length, coords,
+ policy);
+ m_notePixmapFactory->drawText
+ (text, *m_printPainter, int(coords.first), coords.second);
+ m_printPainter->restore();
+ }
+ } else {
+ pixmap = m_notePixmapFactory->makeTextPixmap
+ (Text(*elt->event()));
+ }
+ } catch (Exception e) { // Text ctor failed
+ NOTATION_DEBUG << "Bad text event" << endl;
+ }
+ }
+
+ } else if (elt->event()->isa(Indication::EventType)) {
+
+ policy = SplitToFit;
+
+ try {
+ Indication indication(*elt->event());
+
+ timeT indicationDuration = indication.getIndicationDuration();
+ timeT indicationEndTime =
+ elt->getViewAbsoluteTime() + indicationDuration;
+
+ NotationElementList::iterator indicationEnd =
+ getViewElementList()->findTime(indicationEndTime);
+
+ std::string indicationType = indication.getIndicationType();
+
+ int length, y1;
+
+ if ((indicationType == Indication::Slur ||
+ indicationType == Indication::PhrasingSlur) &&
+ indicationEnd != getViewElementList()->begin()) {
+ --indicationEnd;
+ }
+
+ if ((indicationType != Indication::Slur &&
+ indicationType != Indication::PhrasingSlur) &&
+ indicationEnd != getViewElementList()->begin() &&
+ (indicationEnd == getViewElementList()->end() ||
+ indicationEndTime ==
+ getSegment().getBarStartForTime(indicationEndTime))) {
+
+ while (indicationEnd == getViewElementList()->end() ||
+ (*indicationEnd)->getViewAbsoluteTime() >= indicationEndTime)
+ --indicationEnd;
+
+ double x, w;
+ static_cast<NotationElement *>(*indicationEnd)->
+ getLayoutAirspace(x, w);
+ length = (int)(x + w - elt->getLayoutX() -
+ m_notePixmapFactory->getBarMargin());
+
+ } else {
+
+ length = (int)((*indicationEnd)->getLayoutX() -
+ elt->getLayoutX());
+
+ if (indication.isOttavaType()) {
+ length -= m_notePixmapFactory->getNoteBodyWidth();
+ }
+ }
+
+ y1 = (int)(*indicationEnd)->getLayoutY();
+
+ if (length < m_notePixmapFactory->getNoteBodyWidth()) {
+ length = m_notePixmapFactory->getNoteBodyWidth();
+ }
+
+ if (indicationType == Indication::Crescendo ||
+ indicationType == Indication::Decrescendo) {
+
+ if (m_printPainter) {
+ for (double w = -1, inc = 0; w != 0; inc += w) {
+ w = setPainterClipping(m_printPainter,
+ elt->getLayoutX(),
+ int(elt->getLayoutY()),
+ int(inc), length, coords,
+ policy);
+ m_notePixmapFactory->drawHairpin
+ (length, indicationType == Indication::Crescendo,
+ *m_printPainter, int(coords.first), coords.second);
+ m_printPainter->restore();
+ }
+ } else {
+ pixmap = m_notePixmapFactory->makeHairpinPixmap
+ (length, indicationType == Indication::Crescendo);
+ }
+
+ } else if (indicationType == Indication::Slur ||
+ indicationType == Indication::PhrasingSlur) {
+
+ bool above = true;
+ long dy = 0;
+ long length = 10;
+
+ elt->event()->get
+ <Bool>(properties.SLUR_ABOVE, above);
+ elt->event()->get
+ <Int>(properties.SLUR_Y_DELTA, dy);
+ elt->event()->get
+ <Int>(properties.SLUR_LENGTH, length);
+
+ if (m_printPainter) {
+ for (double w = -1, inc = 0; w != 0; inc += w) {
+ w = setPainterClipping(m_printPainter,
+ elt->getLayoutX(),
+ int(elt->getLayoutY()),
+ int(inc), length, coords,
+ policy);
+ m_notePixmapFactory->drawSlur
+ (length, dy, above,
+ indicationType == Indication::PhrasingSlur,
+ *m_printPainter, int(coords.first), coords.second);
+ m_printPainter->restore();
+ }
+ } else {
+ pixmap = m_notePixmapFactory->makeSlurPixmap
+ (length, dy, above,
+ indicationType == Indication::PhrasingSlur);
+ }
+
+ } else {
+
+ int octaves = indication.getOttavaShift();
+
+ if (octaves != 0) {
+ if (m_printPainter) {
+ for (double w = -1, inc = 0; w != 0; inc += w) {
+ w = setPainterClipping(m_printPainter,
+ elt->getLayoutX(),
+ int(elt->getLayoutY()),
+ int(inc), length, coords,
+ policy);
+ m_notePixmapFactory->drawOttava
+ (length, octaves,
+ *m_printPainter, int(coords.first), coords.second);
+ m_printPainter->restore();
+ }
+ } else {
+ pixmap = m_notePixmapFactory->makeOttavaPixmap
+ (length, octaves);
+ }
+ } else {
+
+ NOTATION_DEBUG
+ << "Unrecognised indicationType " << indicationType << endl;
+ if (m_showUnknowns) {
+ pixmap = m_notePixmapFactory->makeUnknownPixmap();
+ }
+ }
+ }
+ } catch (...) {
+ NOTATION_DEBUG << "Bad indication!" << endl;
+ }
+
+ } else if (elt->event()->isa(Controller::EventType)) {
+
+ bool isSustain = false;
+
+ long controlNumber = 0;
+ elt->event()->get
+ <Int>(Controller::NUMBER, controlNumber);
+
+ Studio *studio = &m_notationView->getDocument()->getStudio();
+ Track *track = getSegment().getComposition()->getTrackById
+ (getSegment().getTrack());
+
+ if (track) {
+
+ Instrument *instrument = studio->getInstrumentById
+ (track->getInstrument());
+ if (instrument) {
+ MidiDevice *device = dynamic_cast<MidiDevice *>
+ (instrument->getDevice());
+ if (device) {
+ for (ControlList::const_iterator i =
+ device->getControlParameters().begin();
+ i != device->getControlParameters().end(); ++i) {
+ if (i->getType() == Controller::EventType &&
+ i->getControllerValue() == controlNumber) {
+ if (i->getName() == "Sustain" ||
+ strtoqstr(i->getName()) == i18n("Sustain")) {
+ isSustain = true;
+ }
+ break;
+ }
+ }
+ } else if (instrument->getDevice() &&
+ instrument->getDevice()->getType() == Device::SoftSynth) {
+ if (controlNumber == 64) {
+ isSustain = true;
+ }
+ }
+ }
+ }
+
+ if (isSustain) {
+ long value = 0;
+ elt->event()->get
+ <Int>(Controller::VALUE, value);
+ if (value > 0) {
+ pixmap = m_notePixmapFactory->makePedalDownPixmap();
+ } else {
+ pixmap = m_notePixmapFactory->makePedalUpPixmap();
+ }
+
+ } else {
+
+ if (m_showUnknowns) {
+ pixmap = m_notePixmapFactory->makeUnknownPixmap();
+ }
+ }
+ } else if (elt->event()->isa(Guitar::Chord::EventType)) {
+
+ // Create a guitar chord pixmap
+ try {
+
+ Guitar::Chord chord (*elt->event());
+
+ /* UNUSED - for printing, just use a large pixmap as below
+ if (m_printPainter) {
+
+ int length = m_notePixmapFactory->getTextWidth(text);
+ for (double w = -1, inc = 0; w != 0; inc += w) {
+ w = setPainterClipping(m_printPainter,
+ elt->getLayoutX(),
+ int(elt->getLayoutY()),
+ int(inc), length, coords,
+ policy);
+ m_notePixmapFactory->drawText
+ (text, *m_printPainter, int(coords.first), coords.second);
+ m_printPainter->restore();
+ }
+ } else {
+ */
+
+ pixmap = m_notePixmapFactory->makeGuitarChordPixmap (chord.getFingering(),
+ int(coords.first),
+ coords.second);
+ // }
+ } catch (Exception e) { // GuitarChord ctor failed
+ NOTATION_DEBUG << "Bad guitar chord event" << endl;
+ }
+
+ } else {
+
+ if (m_showUnknowns) {
+ pixmap = m_notePixmapFactory->makeUnknownPixmap();
+ }
+ }
+
+ // Show the result, one way or another
+
+ if (elt->isNote()) {
+
+ // No need, we already set and showed it in renderNote
+
+ } else if (pixmap) {
+
+ setPixmap(elt, pixmap, z, policy);
+
+ } else {
+ elt->removeCanvasItem();
+ }
+
+ // NOTATION_DEBUG << "NotationStaff::renderSingleElement: Setting selected at " << elt->getAbsoluteTime() << " to " << selected << endl;
+
+ } catch (...) {
+ std::cerr << "Event lacks the proper properties: "
+ << std::endl;
+ elt->event()->dump(std::cerr);
+ }
+
+ m_notePixmapFactory->setSelected(false);
+ m_notePixmapFactory->setShaded(false);
+}
+
+double
+NotationStaff::setPainterClipping(QPainter *painter, double lx, int ly,
+ double dx, double w, LinedStaffCoords &coords,
+ FitPolicy policy)
+{
+ painter->save();
+
+ // NOTATION_DEBUG << "NotationStaff::setPainterClipping: lx " << lx << ", dx " << dx << ", w " << w << endl;
+
+ coords = getCanvasCoordsForLayoutCoords(lx + dx, ly);
+ int row = getRowForLayoutX(lx + dx);
+ double rightMargin = getCanvasXForRightOfRow(row);
+ double available = rightMargin - coords.first;
+
+ // NOTATION_DEBUG << "NotationStaff::setPainterClipping: row " << row << ", rightMargin " << rightMargin << ", available " << available << endl;
+
+ switch (policy) {
+
+ case SplitToFit: {
+ bool fit = (w - dx <= available + m_notePixmapFactory->getNoteBodyWidth());
+ if (dx > 0.01 || !fit) {
+ int clipLeft = int(coords.first), clipWidth = int(available);
+ if (dx < 0.01) {
+ // never clip the left side of the first part of something
+ clipWidth += clipLeft;
+ clipLeft = 0;
+ }
+ QRect clip(clipLeft, coords.second - getRowSpacing() / 2,
+ clipWidth, getRowSpacing());
+ painter->setClipRect(clip, QPainter::CoordPainter);
+ coords.first -= dx;
+ }
+ if (fit) {
+ return 0.0;
+ }
+ return available;
+ }
+
+ case MoveBackToFit:
+ if (w - dx > available + m_notePixmapFactory->getNoteBodyWidth()) {
+ coords.first -= (w - dx) - available;
+ }
+ return 0.0;
+
+ default:
+ return 0.0;
+ }
+}
+
+void
+NotationStaff::setPixmap(NotationElement *elt, QCanvasPixmap *pixmap, int z,
+ FitPolicy policy)
+{
+ double layoutX = elt->getLayoutX();
+ int layoutY = (int)elt->getLayoutY();
+
+ elt->removeCanvasItem();
+
+ while (1) {
+
+ LinedStaffCoords coords =
+ getCanvasCoordsForLayoutCoords(layoutX, layoutY);
+
+ double canvasX = coords.first;
+ int canvasY = coords.second;
+
+ QCanvasItem *item = 0;
+
+ if (m_pageMode == LinearMode || policy == PretendItFittedAllAlong) {
+
+ item = new QCanvasNotationSprite(*elt, pixmap, m_canvas);
+
+ } else {
+
+ int row = getRowForLayoutX(layoutX);
+ double rightMargin = getCanvasXForRightOfRow(row);
+ double extent = canvasX + pixmap->width();
+
+ // NOTATION_DEBUG << "NotationStaff::setPixmap: row " << row << ", right margin " << rightMargin << ", extent " << extent << endl;
+
+ if (extent > rightMargin + m_notePixmapFactory->getNoteBodyWidth()) {
+
+ if (policy == SplitToFit) {
+
+ // NOTATION_DEBUG << "splitting at " << (rightMargin-canvasX) << endl;
+
+ std::pair<QPixmap, QPixmap> split =
+ PixmapFunctions::splitPixmap(*pixmap,
+ int(rightMargin - canvasX));
+
+ QCanvasPixmap *leftCanvasPixmap = new QCanvasPixmap
+ (split.first, QPoint(pixmap->offsetX(), pixmap->offsetY()));
+
+ QCanvasPixmap *rightCanvasPixmap = new QCanvasPixmap
+ (split.second, QPoint(0, pixmap->offsetY()));
+
+ item = new QCanvasNotationSprite(*elt, leftCanvasPixmap, m_canvas);
+ item->setZ(z);
+
+ if (elt->getCanvasItem()) {
+ elt->addCanvasItem(item, canvasX, canvasY);
+ } else {
+ elt->setCanvasItem(item, canvasX, canvasY);
+ }
+
+ item->show();
+
+ delete pixmap;
+ pixmap = rightCanvasPixmap;
+
+ layoutX += rightMargin - canvasX + 0.01; // ensure flip to next row
+
+ continue;
+
+ } else { // policy == MoveBackToFit
+
+ item = new QCanvasNotationSprite(*elt, pixmap, m_canvas);
+ elt->setLayoutX(elt->getLayoutX() - (extent - rightMargin));
+ coords = getCanvasCoordsForLayoutCoords(layoutX, layoutY);
+ canvasX = coords.first;
+ }
+ } else {
+ item = new QCanvasNotationSprite(*elt, pixmap, m_canvas);
+ }
+ }
+
+ item->setZ(z);
+ if (elt->getCanvasItem()) {
+ elt->addCanvasItem(item, canvasX, canvasY);
+ } else {
+ elt->setCanvasItem(item, canvasX, canvasY);
+ }
+ item->show();
+ break;
+ }
+}
+
+void
+NotationStaff::renderNote(ViewElementList::iterator &vli)
+{
+ NotationElement* elt = static_cast<NotationElement*>(*vli);
+
+ const NotationProperties &properties(getProperties());
+ static NotePixmapParameters params(Note::Crotchet, 0);
+
+ Note::Type note = elt->event()->get
+ <Int>(BaseProperties::NOTE_TYPE);
+ int dots = elt->event()->get
+ <Int>(BaseProperties::NOTE_DOTS);
+
+ Accidental accidental = Accidentals::NoAccidental;
+ (void)elt->event()->get
+ <String>(properties.DISPLAY_ACCIDENTAL, accidental);
+
+ bool cautionary = false;
+ if (accidental != Accidentals::NoAccidental) {
+ (void)elt->event()->get
+ <Bool>(properties.DISPLAY_ACCIDENTAL_IS_CAUTIONARY,
+ cautionary);
+ }
+
+ bool up = true;
+ // (void)(elt->event()->get<Bool>(properties.STEM_UP, up));
+ (void)(elt->event()->get
+ <Bool>(properties.VIEW_LOCAL_STEM_UP, up));
+
+ bool flag = true;
+ (void)(elt->event()->get
+ <Bool>(properties.DRAW_FLAG, flag));
+
+ bool beamed = false;
+ (void)(elt->event()->get
+ <Bool>(properties.BEAMED, beamed));
+
+ bool shifted = false;
+ (void)(elt->event()->get
+ <Bool>(properties.NOTE_HEAD_SHIFTED, shifted));
+
+ bool dotShifted = false;
+ (void)(elt->event()->get
+ <Bool>(properties.NOTE_DOT_SHIFTED, dotShifted));
+
+ long stemLength = m_notePixmapFactory->getNoteBodyHeight();
+ (void)(elt->event()->get
+ <Int>(properties.UNBEAMED_STEM_LENGTH, stemLength));
+
+ long heightOnStaff = 0;
+ int legerLines = 0;
+
+ (void)(elt->event()->get
+ <Int>(properties.HEIGHT_ON_STAFF, heightOnStaff));
+ if (heightOnStaff < 0) {
+ legerLines = heightOnStaff;
+ } else if (heightOnStaff > 8) {
+ legerLines = heightOnStaff - 8;
+ }
+
+ long slashes = 0;
+ (void)(elt->event()->get
+ <Int>(properties.SLASHES, slashes));
+
+ bool quantized = false;
+ if (m_colourQuantize && !elt->isTuplet()) {
+ quantized =
+ (elt->getViewAbsoluteTime() != elt->event()->getAbsoluteTime() ||
+ elt->getViewDuration() != elt->event()->getDuration());
+ }
+ params.setQuantized(quantized);
+
+ bool trigger = false;
+ if (elt->event()->has(BaseProperties::TRIGGER_SEGMENT_ID))
+ trigger = true;
+ params.setTrigger(trigger);
+
+ bool inRange = true;
+ Pitch p(*elt->event());
+ Segment *segment = &getSegment();
+ if (m_showRanges) {
+ int pitch = p.getPerformancePitch();
+ if (pitch > segment->getHighestPlayable() ||
+ pitch < segment->getLowestPlayable()) {
+ inRange = false;
+ }
+ }
+ params.setInRange(inRange);
+
+ params.setNoteType(note);
+ params.setDots(dots);
+ params.setAccidental(accidental);
+ params.setAccidentalCautionary(cautionary);
+ params.setNoteHeadShifted(shifted);
+ params.setNoteDotShifted(dotShifted);
+ params.setDrawFlag(flag);
+ params.setDrawStem(true);
+ params.setStemGoesUp(up);
+ params.setLegerLines(legerLines);
+ params.setSlashes(slashes);
+ params.setBeamed(false);
+ params.setIsOnLine(heightOnStaff % 2 == 0);
+ params.removeMarks();
+ params.setSafeVertDistance(0);
+
+ bool primary = false;
+ int safeVertDistance = 0;
+
+ if (elt->event()->get
+ <Bool>(properties.CHORD_PRIMARY_NOTE, primary)
+ && primary) {
+
+ long marks = 0;
+ elt->event()->get
+ <Int>(properties.CHORD_MARK_COUNT, marks);
+ if (marks) {
+ NotationChord chord(*getViewElementList(), vli,
+ m_segment.getComposition()->getNotationQuantizer(),
+ properties);
+ params.setMarks(chord.getMarksForChord());
+ }
+
+ // params.setMarks(Marks::getMarks(*elt->event()));
+
+ if (up && note < Note::Semibreve) {
+ safeVertDistance = m_notePixmapFactory->getStemLength();
+ safeVertDistance = std::max(safeVertDistance, int(stemLength));
+ }
+ }
+
+ long tieLength = 0;
+ (void)(elt->event()->get<Int>(properties.TIE_LENGTH, tieLength));
+ if (tieLength > 0) {
+ params.setTied(true);
+ params.setTieLength(tieLength);
+ } else {
+ params.setTied(false);
+ }
+
+ if (elt->event()->has(BaseProperties::TIE_IS_ABOVE)) {
+ params.setTiePosition
+ (true, elt->event()->get<Bool>(BaseProperties::TIE_IS_ABOVE));
+ } else {
+ params.setTiePosition(false, false); // the default
+ }
+
+ long accidentalShift = 0;
+ bool accidentalExtra = false;
+ if (elt->event()->get<Int>(properties.ACCIDENTAL_SHIFT, accidentalShift)) {
+ elt->event()->get<Bool>(properties.ACCIDENTAL_EXTRA_SHIFT, accidentalExtra);
+ }
+ params.setAccidentalShift(accidentalShift);
+ params.setAccExtraShift(accidentalExtra);
+
+ double airX, airWidth;
+ elt->getLayoutAirspace(airX, airWidth);
+ params.setWidth(int(airWidth));
+
+ if (beamed) {
+
+ if (elt->event()->get<Bool>(properties.CHORD_PRIMARY_NOTE, primary)
+ && primary) {
+
+ int myY = elt->event()->get<Int>(properties.BEAM_MY_Y);
+
+ stemLength = myY - (int)elt->getLayoutY();
+ if (stemLength < 0)
+ stemLength = -stemLength;
+
+ int nextBeamCount =
+ elt->event()->get
+ <Int>(properties.BEAM_NEXT_BEAM_COUNT);
+ int width =
+ elt->event()->get
+ <Int>(properties.BEAM_SECTION_WIDTH);
+ int gradient =
+ elt->event()->get
+ <Int>(properties.BEAM_GRADIENT);
+
+ bool thisPartialBeams(false), nextPartialBeams(false);
+ (void)elt->event()->get
+ <Bool>
+ (properties.BEAM_THIS_PART_BEAMS, thisPartialBeams);
+ (void)elt->event()->get
+ <Bool>
+ (properties.BEAM_NEXT_PART_BEAMS, nextPartialBeams);
+
+ params.setBeamed(true);
+ params.setNextBeamCount(nextBeamCount);
+ params.setThisPartialBeams(thisPartialBeams);
+ params.setNextPartialBeams(nextPartialBeams);
+ params.setWidth(width);
+ params.setGradient((double)gradient / 100.0);
+ if (up)
+ safeVertDistance = stemLength;
+
+ }
+ else {
+ params.setBeamed(false);
+ params.setDrawStem(false);
+ }
+ }
+
+ if (heightOnStaff < 7) {
+ int gap = (((7 - heightOnStaff) * m_notePixmapFactory->getLineSpacing()) / 2);
+ if (safeVertDistance < gap)
+ safeVertDistance = gap;
+ }
+
+ params.setStemLength(stemLength);
+ params.setSafeVertDistance(safeVertDistance);
+ setTuplingParameters(elt, params);
+
+ NotePixmapFactory *factory = m_notePixmapFactory;
+
+ if (elt->isGrace()) {
+ // lift this code from elsewhere to fix #1930309, and it seems to work a
+ // treat, as y'all Wrongpondians are wont to say
+ params.setLegerLines(heightOnStaff < 0 ? heightOnStaff :
+ heightOnStaff > 8 ? heightOnStaff - 8 : 0);
+ m_graceNotePixmapFactory->setSelected(m_notePixmapFactory->isSelected());
+ m_graceNotePixmapFactory->setShaded(m_notePixmapFactory->isShaded());
+ factory = m_graceNotePixmapFactory;
+ }
+
+ if (m_printPainter) {
+
+ // Return no canvas item, but instead render straight to
+ // the printer.
+
+ LinedStaffCoords coords = getCanvasCoordsForLayoutCoords
+ (elt->getLayoutX(), (int)elt->getLayoutY());
+
+ // We don't actually know how wide the note drawing will be,
+ // but we should be able to use a fairly pessimistic estimate
+ // without causing any problems
+ int length = tieLength + 10 * m_notePixmapFactory->getNoteBodyWidth();
+
+ for (double w = -1, inc = 0; w != 0; inc += w) {
+
+ w = setPainterClipping(m_printPainter,
+ elt->getLayoutX(),
+ int(elt->getLayoutY()),
+ int(inc), length, coords,
+ SplitToFit);
+
+ factory->drawNote
+ (params, *m_printPainter, int(coords.first), coords.second);
+
+ m_printPainter->restore(); // save() called by setPainterClipping
+ }
+
+ } else {
+
+ // The normal on-screen case
+
+ bool collision = false;
+ QCanvasItem * haloItem = 0;
+ if (m_showCollisions) {
+ collision = elt->isColliding();
+ if (collision) {
+ // Make collision halo
+ QCanvasPixmap *haloPixmap = factory->makeNoteHaloPixmap(params);
+ haloItem = new QCanvasNotationSprite(*elt, haloPixmap, m_canvas);
+ haloItem->setZ(-1);
+ }
+ }
+
+ QCanvasPixmap *pixmap = factory->makeNotePixmap(params);
+
+ int z = 0;
+ if (factory->isSelected())
+ z = 3;
+ else if (quantized)
+ z = 2;
+
+ setPixmap(elt, pixmap, z, SplitToFit);
+
+ if (collision) {
+ // Display collision halo
+ LinedStaffCoords coords =
+ getCanvasCoordsForLayoutCoords(elt->getLayoutX(),
+ elt->getLayoutY());
+ double canvasX = coords.first;
+ int canvasY = coords.second;
+ elt->addCanvasItem(haloItem, canvasX, canvasY);
+ haloItem->show();
+ }
+ }
+}
+
+void
+NotationStaff::setTuplingParameters(NotationElement *elt,
+ NotePixmapParameters &params)
+{
+ const NotationProperties &properties(getProperties());
+
+ params.setTupletCount(0);
+ long tuplingLineY = 0;
+ bool tupled = (elt->event()->get
+ <Int>(properties.TUPLING_LINE_MY_Y, tuplingLineY));
+
+ if (tupled) {
+
+ long tuplingLineWidth = 0;
+ if (!elt->event()->get
+ <Int>(properties.TUPLING_LINE_WIDTH, tuplingLineWidth)) {
+ std::cerr << "WARNING: Tupled event at " << elt->event()->getAbsoluteTime() << " has no tupling line width" << std::endl;
+ }
+
+ long tuplingLineGradient = 0;
+ if (!(elt->event()->get
+ <Int>(properties.TUPLING_LINE_GRADIENT,
+ tuplingLineGradient))) {
+ std::cerr << "WARNING: Tupled event at " << elt->event()->getAbsoluteTime() << " has no tupling line gradient" << std::endl;
+ }
+
+ bool tuplingLineFollowsBeam = false;
+ elt->event()->get
+ <Bool>(properties.TUPLING_LINE_FOLLOWS_BEAM,
+ tuplingLineFollowsBeam);
+
+ long tupletCount;
+ if (elt->event()->get<Int>
+ (BaseProperties::BEAMED_GROUP_UNTUPLED_COUNT, tupletCount)) {
+
+ params.setTupletCount(tupletCount);
+ params.setTuplingLineY(tuplingLineY - (int)elt->getLayoutY());
+ params.setTuplingLineWidth(tuplingLineWidth);
+ params.setTuplingLineGradient(double(tuplingLineGradient) / 100.0);
+ params.setTuplingLineFollowsBeam(tuplingLineFollowsBeam);
+ }
+ }
+}
+
+bool
+NotationStaff::isSelected(NotationElementList::iterator it)
+{
+ const EventSelection *selection =
+ m_notationView->getCurrentSelection();
+ return selection && selection->contains((*it)->event());
+}
+
+void
+NotationStaff::showPreviewNote(double layoutX, int heightOnStaff,
+ const Note &note, bool grace)
+{
+ NotePixmapFactory *npf = m_notePixmapFactory;
+ if (grace) npf = m_graceNotePixmapFactory;
+
+ NotePixmapParameters params(note.getNoteType(), note.getDots());
+ NotationRules rules;
+
+ params.setAccidental(Accidentals::NoAccidental);
+ params.setNoteHeadShifted(false);
+ params.setDrawFlag(true);
+ params.setDrawStem(true);
+ params.setStemGoesUp(rules.isStemUp(heightOnStaff));
+ params.setLegerLines(heightOnStaff < 0 ? heightOnStaff :
+ heightOnStaff > 8 ? heightOnStaff - 8 : 0);
+ params.setBeamed(false);
+ params.setIsOnLine(heightOnStaff % 2 == 0);
+ params.setTied(false);
+ params.setBeamed(false);
+ params.setTupletCount(0);
+ params.setSelected(false);
+ params.setHighlighted(true);
+
+ delete m_previewSprite;
+ m_previewSprite = new QCanvasSimpleSprite
+ (npf->makeNotePixmap(params), m_canvas);
+
+ int layoutY = getLayoutYForHeight(heightOnStaff);
+ LinedStaffCoords coords = getCanvasCoordsForLayoutCoords(layoutX, layoutY);
+
+ m_previewSprite->move(coords.first, (double)coords.second);
+ m_previewSprite->setZ(4);
+ m_previewSprite->show();
+ m_canvas->update();
+}
+
+void
+NotationStaff::clearPreviewNote()
+{
+ delete m_previewSprite;
+ m_previewSprite = 0;
+}
+
+bool
+NotationStaff::wrapEvent(Event *e)
+{
+ bool wrap = true;
+
+ /*!!! always wrap unknowns, just don't necessarily render them?
+
+ if (!m_showUnknowns) {
+ std::string etype = e->getType();
+ if (etype != Note::EventType &&
+ etype != Note::EventRestType &&
+ etype != Clef::EventType &&
+ etype != Key::EventType &&
+ etype != Indication::EventType &&
+ etype != Text::EventType) {
+ wrap = false;
+ }
+ }
+ */
+
+ if (wrap)
+ wrap = Staff::wrapEvent(e);
+
+ return wrap;
+}
+
+void
+NotationStaff::eventRemoved(const Segment *segment,
+ Event *event)
+{
+ LinedStaff::eventRemoved(segment, event);
+ m_notationView->handleEventRemoved(event);
+}
+
+void
+NotationStaff::markChanged(timeT from, timeT to, bool movedOnly)
+{
+ // first time through this, m_ready is false -- we mark it true
+
+ NOTATION_DEBUG << "NotationStaff::markChanged (" << from << " -> " << to << ") " << movedOnly << endl;
+
+ drawStaffName();//!!!
+
+ if (from == to) {
+
+ m_status.clear();
+
+ if (!movedOnly && m_ready) { // undo all the rendering we've already done
+ for (NotationElementList::iterator i = getViewElementList()->begin();
+ i != getViewElementList()->end(); ++i) {
+ static_cast<NotationElement *>(*i)->removeCanvasItem();
+ }
+
+ m_clefChanges.clear();
+ m_keyChanges.clear();
+ }
+
+ drawStaffName();
+
+ } else {
+
+ Segment *segment = &getSegment();
+ Composition *composition = segment->getComposition();
+
+ NotationElementList::iterator unchanged = findUnchangedBarEnd(to);
+
+ int finalBar;
+ if (unchanged == getViewElementList()->end()) {
+ finalBar = composition->getBarNumber(segment->getEndMarkerTime());
+ } else {
+ finalBar = composition->getBarNumber((*unchanged)->getViewAbsoluteTime());
+ }
+
+ int fromBar = composition->getBarNumber(from);
+ int toBar = composition->getBarNumber(to);
+ if (finalBar < toBar)
+ finalBar = toBar;
+
+ for (int bar = fromBar; bar <= finalBar; ++bar) {
+
+ if (bar > toBar)
+ movedOnly = true;
+
+ // NOTATION_DEBUG << "bar " << bar << " status " << m_status[bar] << endl;
+
+ if (bar >= m_lastRenderCheck.first &&
+ bar <= m_lastRenderCheck.second) {
+
+ // NOTATION_DEBUG << "bar " << bar << " rendering and positioning" << endl;
+
+ if (!movedOnly || m_status[bar] == UnRendered) {
+ renderElements
+ (getViewElementList()->findTime(composition->getBarStart(bar)),
+ getViewElementList()->findTime(composition->getBarEnd(bar)));
+ }
+ positionElements(composition->getBarStart(bar),
+ composition->getBarEnd(bar));
+ m_status[bar] = Positioned;
+
+ } else if (!m_ready) {
+ // NOTATION_DEBUG << "bar " << bar << " rendering and positioning" << endl;
+
+ // first time through -- we don't need a separate render phase,
+ // only to mark as not yet positioned
+ m_status[bar] = Rendered;
+
+ } else if (movedOnly) {
+ if (m_status[bar] == Positioned) {
+ // NOTATION_DEBUG << "bar " << bar << " marking unpositioned" << endl;
+ m_status[bar] = Rendered;
+ }
+
+ } else {
+ // NOTATION_DEBUG << "bar " << bar << " marking unrendered" << endl;
+
+ m_status[bar] = UnRendered;
+ }
+ }
+ }
+
+ m_ready = true;
+}
+
+void
+NotationStaff::setPrintPainter(QPainter *painter)
+{
+ m_printPainter = painter;
+}
+
+bool
+NotationStaff::checkRendered(timeT from, timeT to)
+{
+ if (!m_ready)
+ return false;
+ Composition *composition = getSegment().getComposition();
+ if (!composition) {
+ NOTATION_DEBUG << "NotationStaff::checkRendered: warning: segment has no composition -- is my paint event late?" << endl;
+ return false;
+ }
+
+ // NOTATION_DEBUG << "NotationStaff::checkRendered: " << from << " -> " << to << endl;
+
+ int fromBar = composition->getBarNumber(from);
+ int toBar = composition->getBarNumber(to);
+ bool something = false;
+
+ if (fromBar > toBar)
+ std::swap(fromBar, toBar);
+
+ for (int bar = fromBar; bar <= toBar; ++bar) {
+ // NOTATION_DEBUG << "NotationStaff::checkRendered: bar " << bar << " status "
+ // << m_status[bar] << endl;
+
+ switch (m_status[bar]) {
+
+ case UnRendered:
+ renderElements
+ (getViewElementList()->findTime(composition->getBarStart(bar)),
+ getViewElementList()->findTime(composition->getBarEnd(bar)));
+
+ case Rendered:
+ positionElements
+ (composition->getBarStart(bar),
+ composition->getBarEnd(bar));
+ m_lastRenderedBar = bar;
+
+ something = true;
+
+ case Positioned:
+ break;
+ }
+
+ m_status[bar] = Positioned;
+ }
+
+ m_lastRenderCheck = std::pair<int, int>(fromBar, toBar);
+ return something;
+}
+
+bool
+NotationStaff::doRenderWork(timeT from, timeT to)
+{
+ if (!m_ready)
+ return true;
+ Composition *composition = getSegment().getComposition();
+
+ int fromBar = composition->getBarNumber(from);
+ int toBar = composition->getBarNumber(to);
+
+ if (fromBar > toBar)
+ std::swap(fromBar, toBar);
+
+ for (int bar = fromBar; bar <= toBar; ++bar) {
+
+ switch (m_status[bar]) {
+
+ case UnRendered:
+ renderElements
+ (getViewElementList()->findTime(composition->getBarStart(bar)),
+ getViewElementList()->findTime(composition->getBarEnd(bar)));
+ m_status[bar] = Rendered;
+ return true;
+
+ case Rendered:
+ positionElements
+ (composition->getBarStart(bar),
+ composition->getBarEnd(bar));
+ m_status[bar] = Positioned;
+ m_lastRenderedBar = bar;
+ return true;
+
+ case Positioned:
+ // The bars currently displayed are rendered before the others.
+ // Later, when preceding bars are rendered, truncateClefsAndKeysAt()
+ // is called and possible clefs and/or keys from the bars previously
+ // rendered may be lost. Following code should restore these clefs
+ // and keys in m_clefChanges and m_keyChanges lists.
+ if (bar > m_lastRenderedBar)
+ checkAndCompleteClefsAndKeys(bar);
+ continue;
+ }
+ }
+
+ return false;
+}
+
+void
+NotationStaff::checkAndCompleteClefsAndKeys(int bar)
+{
+ // Look for Clef or Key in current bar
+ Composition *composition = getSegment().getComposition();
+ timeT barStartTime = composition->getBarStart(bar);
+ timeT barEndTime = composition->getBarEnd(bar);
+
+ for (ViewElementList::iterator it =
+ getViewElementList()->findTime(barStartTime);
+ (it != getViewElementList()->end())
+ && ((*it)->getViewAbsoluteTime() < barEndTime); ++it) {
+ if ((*it)->event()->isa(Clef::EventType)) {
+ // Clef found
+ Clef clef = *(*it)->event();
+
+ // Is this clef already in m_clefChanges list ?
+ int xClef = int((*it)->getLayoutX());
+ bool found = false;
+ for (int i = 0; i < m_clefChanges.size(); ++i) {
+ if ( (m_clefChanges[i].first == xClef)
+ && (m_clefChanges[i].second == clef)) {
+ found = true;
+ break;
+ }
+ }
+
+ // If not, add it
+ if (!found) {
+ m_clefChanges.push_back(ClefChange(xClef, clef));
+ }
+
+ } else if ((*it)->event()->isa(::Rosegarden::Key::EventType)) {
+ ::Rosegarden::Key key = *(*it)->event();
+
+ // Is this key already in m_keyChanges list ?
+ int xKey = int((*it)->getLayoutX());
+ bool found = false;
+ for (int i = 0; i < m_keyChanges.size(); ++i) {
+ if ( (m_keyChanges[i].first == xKey)
+ && (m_keyChanges[i].second == key)) {
+ found = true;
+ break;
+ }
+ }
+
+ // If not, add it
+ if (!found) {
+ m_keyChanges.push_back(KeyChange(xKey, key));
+ }
+ }
+ }
+}
+
+LinedStaff::BarStyle
+NotationStaff::getBarStyle(int barNo) const
+{
+ const Segment *s = &getSegment();
+ Composition *c = s->getComposition();
+
+ int firstBar = c->getBarNumber(s->getStartTime());
+ int lastNonEmptyBar = c->getBarNumber(s->getEndMarkerTime() - 1);
+
+ // Currently only the first and last bar in a segment have any
+ // possibility of getting special treatment:
+ if (barNo > firstBar && barNo <= lastNonEmptyBar)
+ return PlainBar;
+
+ // First and last bar in a repeating segment get repeat bars.
+
+ if (s->isRepeating()) {
+ if (barNo == firstBar)
+ return RepeatStartBar;
+ else if (barNo == lastNonEmptyBar + 1)
+ return RepeatEndBar;
+ }
+
+ if (barNo <= lastNonEmptyBar)
+ return PlainBar;
+
+ // Last bar on a given track gets heavy double bars. Exploit the
+ // fact that Composition's iterator returns segments in track
+ // order.
+
+ Segment *lastSegmentOnTrack = 0;
+
+ for (Composition::iterator i = c->begin(); i != c->end(); ++i) {
+ if ((*i)->getTrack() == s->getTrack()) {
+ lastSegmentOnTrack = *i;
+ } else if (lastSegmentOnTrack != 0) {
+ break;
+ }
+ }
+
+ if (&getSegment() == lastSegmentOnTrack)
+ return HeavyDoubleBar;
+ else
+ return PlainBar;
+}
+
+double
+NotationStaff::getBarInset(int barNo, bool isFirstBarInRow) const
+{
+ LinedStaff::BarStyle style = getBarStyle(barNo);
+
+ NOTATION_DEBUG << "getBarInset(" << barNo << "," << isFirstBarInRow << ")" << endl;
+
+ if (!(style == RepeatStartBar || style == RepeatBothBar))
+ return 0.0;
+
+ const Segment &s = getSegment();
+ Composition *composition = s.getComposition();
+ timeT barStart = composition->getBarStart(barNo);
+
+ double inset = 0.0;
+
+ NOTATION_DEBUG << "ready" << endl;
+
+ bool haveKey = false, haveClef = false;
+
+ ::Rosegarden::Key key;
+ ::Rosegarden::Key cancelKey;
+ Clef clef;
+
+ for (Segment::iterator i = s.findTime(barStart);
+ s.isBeforeEndMarker(i) && ((*i)->getNotationAbsoluteTime() == barStart);
+ ++i) {
+
+ NOTATION_DEBUG << "type " << (*i)->getType() << " at " << (*i)->getNotationAbsoluteTime() << endl;
+
+ if ((*i)->isa(::Rosegarden::Key::EventType)) {
+
+ try {
+ key = ::Rosegarden::Key(**i);
+
+ if (barNo > composition->getBarNumber(s.getStartTime())) {
+ cancelKey = s.getKeyAtTime(barStart - 1);
+ }
+
+ if (m_keySigCancelMode == 0) { // only when entering C maj / A min
+
+ if (key.getAccidentalCount() != 0)
+ cancelKey = ::Rosegarden::Key();
+
+ } else if (m_keySigCancelMode == 1) { // only when reducing acc count
+
+ if (!(key.isSharp() == cancelKey.isSharp() &&
+ key.getAccidentalCount() < cancelKey.getAccidentalCount())) {
+ cancelKey = ::Rosegarden::Key();
+ }
+ }
+
+ haveKey = true;
+
+ } catch (...) {
+ NOTATION_DEBUG << "getBarInset: Bad key in event" << endl;
+ }
+
+ } else if ((*i)->isa(Clef::EventType)) {
+
+ try {
+ clef = Clef(**i);
+ haveClef = true;
+ } catch (...) {
+ NOTATION_DEBUG << "getBarInset: Bad clef in event" << endl;
+ }
+ }
+ }
+
+ if (isFirstBarInRow) {
+ if (!haveKey) {
+ key = s.getKeyAtTime(barStart);
+ haveKey = true;
+ }
+ if (!haveClef) {
+ clef = s.getClefAtTime(barStart);
+ haveClef = true;
+ }
+ }
+
+ if (haveKey) {
+ inset += m_notePixmapFactory->getKeyWidth(key, cancelKey);
+ }
+ if (haveClef) {
+ inset += m_notePixmapFactory->getClefWidth(clef);
+ }
+ if (haveClef || haveKey) {
+ inset += m_notePixmapFactory->getBarMargin() / 3;
+ }
+ if (haveClef && haveKey) {
+ inset += m_notePixmapFactory->getNoteBodyWidth() / 2;
+ }
+
+ NOTATION_DEBUG << "getBarInset(" << barNo << "," << isFirstBarInRow << "): inset " << inset << endl;
+
+
+ return inset;
+}
+
+Rosegarden::ViewElement* NotationStaff::makeViewElement(Rosegarden::Event* e)
+{
+ return new NotationElement(e);
+}
+
+}