diff options
Diffstat (limited to 'src/gui/general/LinedStaff.cpp')
-rw-r--r-- | src/gui/general/LinedStaff.cpp | 1217 |
1 files changed, 1217 insertions, 0 deletions
diff --git a/src/gui/general/LinedStaff.cpp b/src/gui/general/LinedStaff.cpp new file mode 100644 index 0000000..e2e5d12 --- /dev/null +++ b/src/gui/general/LinedStaff.cpp @@ -0,0 +1,1217 @@ +/* -*- 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 "LinedStaff.h" + +#include "misc/Debug.h" +#include "base/Event.h" +#include "base/LayoutEngine.h" +#include "base/NotationTypes.h" +#include "base/Profiler.h" +#include "base/Segment.h" +#include "base/SnapGrid.h" +#include "base/Staff.h" +#include "base/ViewElement.h" +#include "GUIPalette.h" +#include "BarLine.h" +#include <qcanvas.h> +#include <qcolor.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qpen.h> +#include <qrect.h> +#include <qstring.h> +#include <algorithm> + + +namespace Rosegarden +{ + +// width of pointer +// +const int pointerWidth = 3; + + +LinedStaff::LinedStaff(QCanvas *canvas, Segment *segment, + SnapGrid *snapGrid, int id, + int resolution, int lineThickness) : + Staff(*segment), + m_canvas(canvas), + m_snapGrid(snapGrid), + m_id(id), + m_x(0.0), + m_y(0), + m_margin(0.0), + m_titleHeight(0), + m_resolution(resolution), + m_lineThickness(lineThickness), + m_pageMode(LinearMode), + m_pageWidth(2000.0), // fairly arbitrary, but we need something non-zero + m_rowsPerPage(0), + m_rowSpacing(0), + m_connectingLineLength(0), + m_startLayoutX(0), + m_endLayoutX(0), + m_current(false), + m_pointer(new QCanvasLine(canvas)), + m_insertCursor(new QCanvasLine(canvas)), + m_insertCursorTime(segment->getStartTime()), + m_insertCursorTimeValid(false) +{ + initCursors(); +} + +LinedStaff::LinedStaff(QCanvas *canvas, Segment *segment, + SnapGrid *snapGrid, + int id, int resolution, int lineThickness, + double pageWidth, int rowsPerPage, int rowSpacing) : + Staff(*segment), + m_canvas(canvas), + m_snapGrid(snapGrid), + m_id(id), + m_x(0.0), + m_y(0), + m_margin(0.0), + m_titleHeight(0), + m_resolution(resolution), + m_lineThickness(lineThickness), + m_pageMode(rowsPerPage ? MultiPageMode : ContinuousPageMode), + m_pageWidth(pageWidth), + m_rowsPerPage(rowsPerPage), + m_rowSpacing(rowSpacing), + m_connectingLineLength(0), + m_startLayoutX(0), + m_endLayoutX(0), + m_current(false), + m_pointer(new QCanvasLine(canvas)), + m_insertCursor(new QCanvasLine(canvas)), + m_insertCursorTime(segment->getStartTime()), + m_insertCursorTimeValid(false) +{ + initCursors(); +} + +LinedStaff::LinedStaff(QCanvas *canvas, Segment *segment, + SnapGrid *snapGrid, + int id, int resolution, int lineThickness, + PageMode pageMode, double pageWidth, int rowsPerPage, + int rowSpacing) : + Staff(*segment), + m_canvas(canvas), + m_snapGrid(snapGrid), + m_id(id), + m_x(0.0), + m_y(0), + m_margin(0.0), + m_titleHeight(0), + m_resolution(resolution), + m_lineThickness(lineThickness), + m_pageMode(pageMode), + m_pageWidth(pageWidth), + m_rowsPerPage(rowsPerPage), + m_rowSpacing(rowSpacing), + m_connectingLineLength(0), + m_startLayoutX(0), + m_endLayoutX(0), + m_current(false), + m_pointer(new QCanvasLine(canvas)), + m_insertCursor(new QCanvasLine(canvas)), + m_insertCursorTime(segment->getStartTime()), + m_insertCursorTimeValid(false) +{ + initCursors(); +} + +LinedStaff::~LinedStaff() +{ + /*!!! No, the canvas items are all deleted by the canvas on destruction. + + deleteBars(); + for (int i = 0; i < (int)m_staffLines.size(); ++i) clearStaffLineRow(i); + */ +} + +void +LinedStaff::initCursors() +{ + QPen pen(GUIPalette::getColour(GUIPalette::Pointer)); + pen.setWidth(pointerWidth); + + m_pointer->setPen(pen); + m_pointer->setBrush(GUIPalette::getColour(GUIPalette::Pointer)); + + pen.setColor(GUIPalette::getColour(GUIPalette::InsertCursor)); + + m_insertCursor->setPen(pen); + m_insertCursor->setBrush(GUIPalette::getColour(GUIPalette::InsertCursor)); +} + +void +LinedStaff::setResolution(int resolution) +{ + m_resolution = resolution; +} + +void +LinedStaff::setLineThickness(int lineThickness) +{ + m_lineThickness = lineThickness; +} + +void +LinedStaff::setPageMode(PageMode pageMode) +{ + m_pageMode = pageMode; +} + +void +LinedStaff::setPageWidth(double pageWidth) +{ + m_pageWidth = pageWidth; +} + +void +LinedStaff::setRowsPerPage(int rowsPerPage) +{ + m_rowsPerPage = rowsPerPage; +} + +void +LinedStaff::setRowSpacing(int rowSpacing) +{ + m_rowSpacing = rowSpacing; +} + +void +LinedStaff::setConnectingLineLength(int connectingLineLength) +{ + m_connectingLineLength = connectingLineLength; +} + +int +LinedStaff::getId() const +{ + return m_id; +} + +void +LinedStaff::setX(double x) +{ + m_x = x; +} + +double +LinedStaff::getX() const +{ + return m_x; +} + +void +LinedStaff::setY(int y) +{ + m_y = y; +} + +int +LinedStaff::getY() const +{ + return m_y; +} + +void +LinedStaff::setMargin(double margin) +{ + m_margin = margin; +} + +double +LinedStaff::getMargin() const +{ + if (m_pageMode != MultiPageMode) + return 0; + return m_margin; +} + +void +LinedStaff::setTitleHeight(int titleHeight) +{ + m_titleHeight = titleHeight; +} + +int +LinedStaff::getTitleHeight() const +{ + return m_titleHeight; +} + +double +LinedStaff::getTotalWidth() const +{ + switch (m_pageMode) { + + case ContinuousPageMode: + return getCanvasXForRightOfRow(getRowForLayoutX(m_endLayoutX)) - m_x; + + case MultiPageMode: + return getCanvasXForRightOfRow(getRowForLayoutX(m_endLayoutX)) + m_margin - m_x; + + case LinearMode: + default: + return getCanvasXForLayoutX(m_endLayoutX) - m_x; + } +} + +int +LinedStaff::getTotalHeight() const +{ + switch (m_pageMode) { + + case ContinuousPageMode: + return getCanvasYForTopOfStaff(getRowForLayoutX(m_endLayoutX)) + + getHeightOfRow() - m_y; + + case MultiPageMode: + return getCanvasYForTopOfStaff(m_rowsPerPage - 1) + + getHeightOfRow() - m_y; + + case LinearMode: + default: + return getCanvasYForTopOfStaff(0) + getHeightOfRow() - m_y; + } +} + +int +LinedStaff::getHeightOfRow() const +{ + return getTopLineOffset() + getLegerLineCount() * getLineSpacing() + + getBarLineHeight() + m_lineThickness; +} + +bool +LinedStaff::containsCanvasCoords(double x, int y) const +{ + switch (m_pageMode) { + + case ContinuousPageMode: + + for (int row = getRowForLayoutX(m_startLayoutX); + row <= getRowForLayoutX(m_endLayoutX); ++row) { + if (y >= getCanvasYForTopOfStaff(row) && + y < getCanvasYForTopOfStaff(row) + getHeightOfRow()) { + return true; + } + } + + return false; + + case MultiPageMode: + + for (int row = getRowForLayoutX(m_startLayoutX); + row <= getRowForLayoutX(m_endLayoutX); ++row) { + if (y >= getCanvasYForTopOfStaff(row) && + y < getCanvasYForTopOfStaff(row) + getHeightOfRow() && + x >= getCanvasXForLeftOfRow(row) && + x <= getCanvasXForRightOfRow(row)) { + return true; + } + } + + return false; + + case LinearMode: + default: + + return (y >= getCanvasYForTopOfStaff() && + y < getCanvasYForTopOfStaff() + getHeightOfRow()); + } +} + +int +LinedStaff::getCanvasYForHeight(int h, double baseX, int baseY) const +{ + int y; + + // NOTATION_DEBUG << "LinedStaff::getCanvasYForHeight(" << h << "," << baseY + // << ")" << endl; + + if (baseX < 0) + baseX = getX() + getMargin(); + + if (baseY >= 0) { + y = getCanvasYForTopLine(getRowForCanvasCoords(baseX, baseY)); + } else { + y = getCanvasYForTopLine(); + } + + y += getLayoutYForHeight(h); + + return y; +} + +int +LinedStaff::getLayoutYForHeight(int h) const +{ + int y = ((getTopLineHeight() - h) * getLineSpacing()) / getHeightPerLine(); + if (h < getTopLineHeight() && (h % getHeightPerLine() != 0)) + ++y; + + return y; +} + +int +LinedStaff::getHeightAtCanvasCoords(double x, int y) const +{ + //!!! the lazy route: approximate, then get the right value + // by calling getCanvasYForHeight a few times... ugh + + // RG_DEBUG << "\nNotationStaff::heightOfYCoord: y = " << y + // << ", getTopLineOffset() = " << getTopLineOffset() + // << ", getLineSpacing() = " << m_npf->getLineSpacing() + // << endl; + + if (x < 0) + x = getX() + getMargin(); + + int row = getRowForCanvasCoords(x, y); + int ph = (y - getCanvasYForTopLine(row)) * getHeightPerLine() / + getLineSpacing(); + ph = getTopLineHeight() - ph; + + int i; + int mi = -2; + int md = getLineSpacing() * 2; + + int testi = -2; + int testMd = 1000; + + for (i = -1; i <= 1; ++i) { + int d = y - getCanvasYForHeight(ph + i, x, y); + if (d < 0) + d = -d; + if (d < md) { + md = d; + mi = i; + } + if (d < testMd) { + testMd = d; + testi = i; + } + } + + if (mi > -2) { + // RG_DEBUG << "LinedStaff::getHeightAtCanvasCoords: " << y + // << " -> " << (ph + mi) << " (mi is " << mi << ", distance " + // << md << ")" << endl; + // if (mi == 0) { + // RG_DEBUG << "GOOD APPROXIMATION" << endl; + // } else { + // RG_DEBUG << "BAD APPROXIMATION" << endl; + // } + return ph + mi; + } else { + RG_DEBUG << "LinedStaff::getHeightAtCanvasCoords: heuristic got " << ph << ", nothing within range (closest was " << (ph + testi) << " which is " << testMd << " away)" << endl; + return 0; + } +} + +QRect +LinedStaff::getBarExtents(double x, int y) const +{ + int row = getRowForCanvasCoords(x, y); + + for (int i = 1; i < m_barLines.size(); ++i) { + + double layoutX = m_barLines[i]->getLayoutX(); + int barRow = getRowForLayoutX(layoutX); + + if (m_pageMode != LinearMode && (barRow < row)) + continue; + + BarLine *line = m_barLines[i]; + + if (line) { + if (line->x() <= x) + continue; + + return QRect(int(m_barLines[i -1]->x()), + getCanvasYForTopOfStaff(barRow), + int(line->x() - m_barLines[i - 1]->x()), + getHeightOfRow()); + } + } + + // failure + return QRect(int(getX() + getMargin()), getCanvasYForTopOfStaff(), 4, getHeightOfRow()); +} + +double +LinedStaff::getCanvasXForLayoutX(double x) const +{ + switch (m_pageMode) { + + case ContinuousPageMode: + return m_x + x - (m_pageWidth * getRowForLayoutX(x)); + + case MultiPageMode: { + int pageNo = getRowForLayoutX(x) / getRowsPerPage(); + double cx = m_x + x - (m_pageWidth * getRowForLayoutX(x)); + cx += m_margin + (m_margin * 2 + m_pageWidth) * pageNo; + return cx; + } + + case LinearMode: + default: + return m_x + x; + } +} + +LinedStaff::LinedStaffCoords + +LinedStaff::getLayoutCoordsForCanvasCoords(double x, int y) const +{ + int row = getRowForCanvasCoords(x, y); + return LinedStaffCoords + ((row * m_pageWidth) + x - getCanvasXForLeftOfRow(row), + y - getCanvasYForTopOfStaff(row)); +} + +LinedStaff::LinedStaffCoords + +LinedStaff::getCanvasCoordsForLayoutCoords(double x, int y) const +{ + int row = getRowForLayoutX(x); + return LinedStaffCoords + (getCanvasXForLayoutX(x), getCanvasYForTopLine(row) + y); +} + +int +LinedStaff::getRowForCanvasCoords(double x, int y) const +{ + switch (m_pageMode) { + + case ContinuousPageMode: + return ((y - m_y) / m_rowSpacing); + + case MultiPageMode: { + int px = int(x - m_x - m_margin); + int pw = int(m_margin * 2 + m_pageWidth); + if (px < pw) + y -= m_titleHeight; + return (getRowsPerPage() * (px / pw)) + ((y - m_y) / m_rowSpacing); + } + + case LinearMode: + default: + return (int)((x - m_x) / m_pageWidth); + } +} + +int +LinedStaff::getCanvasYForTopOfStaff(int row) const +{ + switch (m_pageMode) { + + case ContinuousPageMode: + if (row <= 0) + return m_y; + else + return m_y + (row * m_rowSpacing); + + case MultiPageMode: + if (row <= 0) + return m_y + m_titleHeight; + else if (row < getRowsPerPage()) + return m_y + ((row % getRowsPerPage()) * m_rowSpacing) + m_titleHeight; + else + return m_y + ((row % getRowsPerPage()) * m_rowSpacing); + + case LinearMode: + default: + return m_y; + } +} + +double +LinedStaff::getCanvasXForLeftOfRow(int row) const +{ + switch (m_pageMode) { + + case ContinuousPageMode: + return m_x; + + case MultiPageMode: + return m_x + m_margin + + (m_margin*2 + m_pageWidth) * (row / getRowsPerPage()); + + case LinearMode: + default: + return m_x + (row * m_pageWidth); + } +} + +void +LinedStaff::sizeStaff(HorizontalLayoutEngine &layout) +{ + Profiler profiler("LinedStaff::sizeStaff", true); + + deleteBars(); + deleteRepeatedClefsAndKeys(); + deleteTimeSignatures(); + + // RG_DEBUG << "LinedStaff::sizeStaff" << endl; + + int lastBar = layout.getLastVisibleBarOnStaff(*this); + + double xleft = 0, xright = 0; + bool haveXLeft = false; + + xright = layout.getBarPosition(lastBar) - 1; + + TimeSignature currentTimeSignature; + + for (int barNo = layout.getFirstVisibleBarOnStaff(*this); + barNo <= lastBar; ++barNo) { + + double x = layout.getBarPosition(barNo); + + if (!haveXLeft) { + xleft = x; + haveXLeft = true; + } + + double timeSigX = 0; + TimeSignature timeSig; + bool isNew = layout.getTimeSignaturePosition(*this, barNo, timeSig, timeSigX); + + if (isNew && barNo < lastBar) { + currentTimeSignature = timeSig; + insertTimeSignature(timeSigX, currentTimeSignature); + RG_DEBUG << "LinedStaff[" << this << "]::sizeStaff: bar no " << barNo << " has time signature at " << timeSigX << endl; + } + + RG_DEBUG << "LinedStaff::sizeStaff: inserting bar at " << x << " on staff " << this << " (isNew " << isNew << ", timeSigX " << timeSigX << ")" << endl; + + bool showBarNo = + (showBarNumbersEvery() > 0 && + ((barNo + 1) % showBarNumbersEvery()) == 0); + + insertBar(x, + ((barNo == lastBar) ? 0 : + (layout.getBarPosition(barNo + 1) - x)), + layout.isBarCorrectOnStaff(*this, barNo - 1), + currentTimeSignature, + barNo, + showBarNo); + } + + m_startLayoutX = xleft; + m_endLayoutX = xright; + + drawStaffName(); + resizeStaffLines(); +} + +void +LinedStaff::deleteBars() +{ + for (BarLineList::iterator i = m_barLines.begin(); + i != m_barLines.end(); ++i) { + (*i)->hide(); + delete *i; + } + + for (LineRecList::iterator i = m_beatLines.begin(); + i != m_beatLines.end(); ++i) { + i->second->hide(); + delete i->second; + } + + for (LineRecList::iterator i = m_barConnectingLines.begin(); + i != m_barConnectingLines.end(); ++i) { + i->second->hide(); + delete i->second; + } + + for (ItemList::iterator i = m_barNumbers.begin(); + i != m_barNumbers.end(); ++i) { + (*i)->hide(); + delete *i; + } + + m_barLines.clear(); + m_beatLines.clear(); + m_barConnectingLines.clear(); + m_barNumbers.clear(); +} + +void +LinedStaff::insertBar(double layoutX, double width, bool isCorrect, + const TimeSignature &timeSig, + int barNo, bool showBarNo) +{ + // RG_DEBUG << "insertBar: " << layoutX << ", " << width + // << ", " << isCorrect << endl; + + int barThickness = m_lineThickness * 5 / 4; + + // hack to ensure the bar line appears on the correct row in + // notation page layouts, with a conditional to prevent us from + // moving the bar and beat lines in the matrix + if (!showBeatLines()) { + if (width > 0.01) { // not final bar in staff + layoutX += 1; + } else { + layoutX -= 1; + } + } + + int row = getRowForLayoutX(layoutX); + double x = getCanvasXForLayoutX(layoutX); + int y = getCanvasYForTopLine(row); + + bool firstBarInRow = false, lastBarInRow = false; + + if (m_pageMode != LinearMode && + (getRowForLayoutX(layoutX) > + getRowForLayoutX(layoutX - getMargin() - 2))) + firstBarInRow = true; + + if (m_pageMode != LinearMode && + width > 0.01 && // width == 0 for final bar in staff + (getRowForLayoutX(layoutX) < + getRowForLayoutX(layoutX + width + getMargin() + 2))) + lastBarInRow = true; + + BarStyle style = getBarStyle(barNo); + + if (style == RepeatBothBar && firstBarInRow) + style = RepeatStartBar; + + if (firstBarInRow) + insertRepeatedClefAndKey(layoutX, barNo); + + // If we're supposed to be hiding bar lines, we do just that -- + // create them as normal, then hide them. We can't simply not + // create them because we rely on this to find bar extents for + // things like double-click selection in notation. + bool hidden = false; + if (style == PlainBar && timeSig.hasHiddenBars()) + hidden = true; + + double inset = 0.0; + if (style == RepeatStartBar || style == RepeatBothBar) { + inset = getBarInset(barNo, firstBarInRow); + } + + BarLine *line = new BarLine(m_canvas, layoutX, + getBarLineHeight(), barThickness, getLineSpacing(), + (int)inset, style); + + line->moveBy(x, y); + + if (isCorrect) { + line->setPen(GUIPalette::getColour(GUIPalette::BarLine)); + line->setBrush(GUIPalette::getColour(GUIPalette::BarLine)); + } else { + line->setPen(GUIPalette::getColour(GUIPalette::BarLineIncorrect)); + line->setBrush(GUIPalette::getColour(GUIPalette::BarLineIncorrect)); + } + + line->setZ( -1); + if (hidden) + line->hide(); + else + line->show(); + + // The bar lines have to be in order of layout-x (there's no + // such interesting stipulation for beat or connecting lines) + BarLineList::iterator insertPoint = lower_bound + (m_barLines.begin(), m_barLines.end(), line, compareBars); + m_barLines.insert(insertPoint, line); + + if (lastBarInRow) { + + double xe = x + width - barThickness; + style = getBarStyle(barNo + 1); + if (style == RepeatBothBar) + style = RepeatEndBar; + + BarLine *eline = new BarLine(m_canvas, layoutX, + getBarLineHeight(), barThickness, getLineSpacing(), + 0, style); + eline->moveBy(xe, y); + + eline->setPen(GUIPalette::getColour(GUIPalette::BarLine)); + eline->setBrush(GUIPalette::getColour(GUIPalette::BarLine)); + + eline->setZ( -1); + if (hidden) + eline->hide(); + else + eline->show(); + + BarLineList::iterator insertPoint = lower_bound + (m_barLines.begin(), m_barLines.end(), eline, compareBars); + m_barLines.insert(insertPoint, eline); + } + + if (showBarNo) { + + QFont font; + font.setPixelSize(m_resolution * 3 / 2); + QFontMetrics metrics(font); + QString text = QString("%1").arg(barNo + 1); + + QCanvasItem *barNoText = new QCanvasText(text, font, m_canvas); + barNoText->setX(x); + barNoText->setY(y - metrics.height() - m_resolution * 2); + barNoText->setZ( -1); + if (hidden) + barNoText->hide(); + else + barNoText->show(); + + m_barNumbers.push_back(barNoText); + } + + QCanvasRectangle *rect = 0; + + if (showBeatLines()) { + + double gridLines; // number of grid lines per bar may be fractional + + // If the snap time is zero we default to beat markers + // + if (m_snapGrid && m_snapGrid->getSnapTime(x)) + gridLines = double(timeSig.getBarDuration()) / + double(m_snapGrid->getSnapTime(x)); + else + gridLines = timeSig.getBeatsPerBar(); + + double dx = width / gridLines; + + for (int gridLine = hidden ? 0 : 1; gridLine < gridLines; ++gridLine) { + + rect = new QCanvasRectangle + (0, 0, barThickness, getBarLineHeight(), m_canvas); + + rect->moveBy(x + gridLine * dx, y); + + double currentGrid = gridLines / double(timeSig.getBeatsPerBar()); + + rect->setPen(GUIPalette::getColour(GUIPalette::BeatLine)); + rect->setBrush(GUIPalette::getColour(GUIPalette::BeatLine)); + + // Reset to SubBeatLine colour if we're not a beat line - avoid div by zero! + // + if (currentGrid > 1.0 && double(gridLine) / currentGrid != gridLine / int(currentGrid)) { + rect->setPen(GUIPalette::getColour(GUIPalette::SubBeatLine)); + rect->setBrush(GUIPalette::getColour(GUIPalette::SubBeatLine)); + } + + rect->setZ( -1); + rect->show(); // show beat lines even if the bar lines are hidden + + LineRec beatLine(layoutX + gridLine * dx, rect); + m_beatLines.push_back(beatLine); + } + } + + if (m_connectingLineLength > 0) { + + rect = new QCanvasRectangle + (0, 0, barThickness, m_connectingLineLength, m_canvas); + + rect->moveBy(x, y); + + rect->setPen(GUIPalette::getColour(GUIPalette::StaffConnectingLine)); + rect->setBrush(GUIPalette::getColour(GUIPalette::StaffConnectingLine)); + rect->setZ( -3); + if (hidden) + rect->hide(); + else + rect->show(); + + LineRec connectingLine(layoutX, rect); + m_barConnectingLines.push_back(connectingLine); + } +} + +bool +LinedStaff::compareBars(const BarLine *barLine1, const BarLine *barLine2) +{ + return (barLine1->getLayoutX() < barLine2->getLayoutX()); +} + +bool +LinedStaff::compareBarToLayoutX(const BarLine *barLine1, int x) +{ + return (barLine1->getLayoutX() < x); +} + +void +LinedStaff::deleteTimeSignatures() +{ + // default implementation is empty +} + +void +LinedStaff::insertTimeSignature(double, const TimeSignature &) +{ + // default implementation is empty +} + +void +LinedStaff::deleteRepeatedClefsAndKeys() +{ + // default implementation is empty +} + +void +LinedStaff::insertRepeatedClefAndKey(double, int) +{ + // default implementation is empty +} + +void +LinedStaff::drawStaffName() +{ + // default implementation is empty +} + +void +LinedStaff::resizeStaffLines() +{ + int firstRow = getRowForLayoutX(m_startLayoutX); + int lastRow = getRowForLayoutX(m_endLayoutX); + + RG_DEBUG << "LinedStaff::resizeStaffLines: firstRow " + << firstRow << ", lastRow " << lastRow + << " (startLayoutX " << m_startLayoutX + << ", endLayoutX " << m_endLayoutX << ")" << endl; + + assert(lastRow >= firstRow); + + int i; + while ((int)m_staffLines.size() <= lastRow) { + m_staffLines.push_back(ItemList()); + m_staffConnectingLines.push_back(0); + } + + // Remove all the staff lines that precede the start of the staff + + for (i = 0; i < firstRow; ++i) + clearStaffLineRow(i); + + // now i == firstRow + + while (i <= lastRow) { + + double x0; + double x1; + + if (i == firstRow) { + x0 = getCanvasXForLayoutX(m_startLayoutX); + } else { + x0 = getCanvasXForLeftOfRow(i); + } + + if (i == lastRow) { + x1 = getCanvasXForLayoutX(m_endLayoutX); + } else { + x1 = getCanvasXForRightOfRow(i); + } + + resizeStaffLineRow(i, x0, x1 - x0); + + ++i; + } + + // now i == lastRow + 1 + + while (i < (int)m_staffLines.size()) + clearStaffLineRow(i++); +} + +void +LinedStaff::clearStaffLineRow(int row) +{ + for (int h = 0; h < (int)m_staffLines[row].size(); ++h) { + delete m_staffLines[row][h]; + } + m_staffLines[row].clear(); + + delete m_staffConnectingLines[row]; + m_staffConnectingLines[row] = 0; +} + +void +LinedStaff::resizeStaffLineRow(int row, double x, double length) +{ + // RG_DEBUG << "LinedStaff::resizeStaffLineRow: row " + // << row << ", x " << x << ", length " + // << length << endl; + + + // If the resolution is 8 or less, we want to reduce the blackness + // of the staff lines somewhat to make them less intrusive + + int level = 0; + int z = 2; + if (m_resolution < 6) { + z = -1; + level = (9 - m_resolution) * 32; + if (level > 200) + level = 200; + } + + QColor lineColour(level, level, level); + + int h; + + /*!!! No longer really good enough. But we could potentially use the + bar positions to sort this out + + if (m_pageMode && row > 0 && offset == 0.0) { + offset = (double)m_npf->getBarMargin() / 2; + length -= offset; + } + */ + + int y; + + delete m_staffConnectingLines[row]; + + if (m_pageMode != LinearMode && m_connectingLineLength > 0.1) { + + // rather arbitrary (dup in insertBar) + int barThickness = m_resolution / 12 + 1; + y = getCanvasYForTopLine(row); + QCanvasRectangle *line = new QCanvasRectangle + (int(x + length), y, barThickness, m_connectingLineLength, m_canvas); + line->setPen(GUIPalette::getColour(GUIPalette::StaffConnectingTerminatingLine)); + line->setBrush(GUIPalette::getColour(GUIPalette::StaffConnectingTerminatingLine)); + line->setZ( -2); + line->show(); + m_staffConnectingLines[row] = line; + + } else { + m_staffConnectingLines[row] = 0; + } + + while ((int)m_staffLines[row].size() <= getLineCount() * m_lineThickness) { + m_staffLines[row].push_back(0); + } + + int lineIndex = 0; + + for (h = 0; h < getLineCount(); ++h) { + + y = getCanvasYForHeight + (getBottomLineHeight() + getHeightPerLine() * h, + x, getCanvasYForTopLine(row)); + + if (elementsInSpaces()) { + y -= getLineSpacing() / 2 + 1; + } + + // RG_DEBUG << "LinedStaff: drawing line from (" + // << x << "," << y << ") to (" << (x+length-1) + // << "," << y << ")" << endl; + + QCanvasItem *line; + delete m_staffLines[row][lineIndex]; + m_staffLines[row][lineIndex] = 0; + + if (m_lineThickness > 1) { + QCanvasRectangle *rline = new QCanvasRectangle + (int(x), y, int(length), m_lineThickness, m_canvas); + rline->setPen(lineColour); + rline->setBrush(lineColour); + line = rline; + } else { + QCanvasLine *lline = new QCanvasLine(m_canvas); + lline->setPoints(int(x), y, int(x + length), y); + lline->setPen(lineColour); + line = lline; + } + + // if (j > 0) line->setSignificant(false); + + line->setZ(z); + m_staffLines[row][lineIndex] = line; + line->show(); + + ++lineIndex; + } + + while (lineIndex < (int)m_staffLines[row].size()) { + delete m_staffLines[row][lineIndex]; + m_staffLines[row][lineIndex] = 0; + ++lineIndex; + } +} + +void +LinedStaff::setCurrent(bool current) +{ + m_current = current; + if (m_current) { + m_insertCursor->show(); + } else { + m_insertCursor->hide(); + } +} + +double +LinedStaff::getLayoutXOfPointer() const +{ + double x = m_pointer->x(); + int row = getRowForCanvasCoords(x, int(m_pointer->y())); + return getLayoutCoordsForCanvasCoords(x, getCanvasYForTopLine(row)).first; +} + +void +LinedStaff::getPointerPosition(double &cx, int &cy) const +{ + cx = m_pointer->x(); + cy = getCanvasYForTopOfStaff(getRowForCanvasCoords(cx, int(m_pointer->y()))); +} + +double +LinedStaff::getLayoutXOfInsertCursor() const +{ + if (!m_current) return -1; + double x = m_insertCursor->x(); + int row = getRowForCanvasCoords(x, int(m_insertCursor->y())); + return getLayoutCoordsForCanvasCoords(x, getCanvasYForTopLine(row)).first; +} + +timeT +LinedStaff::getInsertCursorTime(HorizontalLayoutEngine &layout) const +{ + if (m_insertCursorTimeValid) return m_insertCursorTime; + return layout.getTimeForX(getLayoutXOfInsertCursor()); +} + +void +LinedStaff::getInsertCursorPosition(double &cx, int &cy) const +{ + if (!m_current) { + cx = -1; + cy = -1; + return ; + } + cx = m_insertCursor->x(); + cy = getCanvasYForTopOfStaff(getRowForCanvasCoords(cx, int(m_insertCursor->y()))); +} + +void +LinedStaff::setPointerPosition(double canvasX, int canvasY) +{ + int row = getRowForCanvasCoords(canvasX, canvasY); + canvasY = getCanvasYForTopOfStaff(row); + m_pointer->setX(int(canvasX)); + m_pointer->setY(int(canvasY)); + m_pointer->setZ( -30); // behind everything else + m_pointer->setPoints(0, 0, 0, getHeightOfRow() /* - 1 */); + m_pointer->show(); +} + +void +LinedStaff::setPointerPosition(HorizontalLayoutEngine &layout, + timeT time) +{ + setPointerPosition(layout.getXForTime(time)); +} + +void +LinedStaff::setPointerPosition(double layoutX) +{ + LinedStaffCoords coords = getCanvasCoordsForLayoutCoords(layoutX, 0); + setPointerPosition(coords.first, coords.second); +} + +void +LinedStaff::hidePointer() +{ + m_pointer->hide(); +} + +void +LinedStaff::setInsertCursorPosition(double canvasX, int canvasY) +{ + if (!m_current) return; + + int row = getRowForCanvasCoords(canvasX, canvasY); + canvasY = getCanvasYForTopOfStaff(row); + m_insertCursor->setX(canvasX); + m_insertCursor->setY(canvasY); + m_insertCursor->setZ( -28); // behind everything else except playback pointer + m_insertCursor->setPoints(0, 0, 0, getHeightOfRow() - 1); + m_insertCursor->show(); + m_insertCursorTimeValid = false; +} + +void +LinedStaff::setInsertCursorPosition(HorizontalLayoutEngine &layout, + timeT time) +{ + double x = layout.getXForTime(time); + LinedStaffCoords coords = getCanvasCoordsForLayoutCoords(x, 0); + setInsertCursorPosition(coords.first, coords.second); + m_insertCursorTime = time; + m_insertCursorTimeValid = true; +} + +void +LinedStaff::hideInsertCursor() +{ + m_insertCursor->hide(); +} + +void +LinedStaff::renderElements(ViewElementList::iterator, + ViewElementList::iterator) +{ + // nothing -- we assume rendering will be done by the implementation + // of positionElements +} + +void +LinedStaff::renderAllElements() +{ + renderElements(getViewElementList()->begin(), + getViewElementList()->end()); +} + +void +LinedStaff::positionAllElements() +{ + positionElements(getSegment().getStartTime(), + getSegment().getEndTime()); +} + +} |