You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/gui/general/LinedStaff.cpp

1216 lines
31 KiB

/*
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.
*/
#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 <tqcanvas.h>
#include <tqcolor.h>
#include <tqfont.h>
#include <tqfontmetrics.h>
#include <tqpen.h>
#include <tqrect.h>
#include <tqstring.h>
#include <algorithm>
namespace Rosegarden
{
// width of pointer
//
const int pointerWidth = 3;
LinedStaff::LinedStaff(TQCanvas *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 TQCanvasLine(canvas)),
m_insertCursor(new TQCanvasLine(canvas)),
m_insertCursorTime(segment->getStartTime()),
m_insertCursorTimeValid(false)
{
initCursors();
}
LinedStaff::LinedStaff(TQCanvas *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 TQCanvasLine(canvas)),
m_insertCursor(new TQCanvasLine(canvas)),
m_insertCursorTime(segment->getStartTime()),
m_insertCursorTimeValid(false)
{
initCursors();
}
LinedStaff::LinedStaff(TQCanvas *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 TQCanvasLine(canvas)),
m_insertCursor(new TQCanvasLine(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()
{
TQPen 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;
}
}
TQRect
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 TQRect(int(m_barLines[i -1]->x()),
getCanvasYForTopOfStaff(barRow),
int(line->x() - m_barLines[i - 1]->x()),
getHeightOfRow());
}
}
// failure
return TQRect(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) {
TQFont font;
font.setPixelSize(m_resolution * 3 / 2);
TQFontMetrics metrics(font);
TQString text = TQString("%1").arg(barNo + 1);
TQCanvasItem *barNoText = new TQCanvasText(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);
}
TQCanvasRectangle *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 TQCanvasRectangle
(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 TQCanvasRectangle
(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;
}
TQColor 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);
TQCanvasRectangle *line = new TQCanvasRectangle
(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;
TQCanvasItem *line;
delete m_staffLines[row][lineIndex];
m_staffLines[row][lineIndex] = 0;
if (m_lineThickness > 1) {
TQCanvasRectangle *rline = new TQCanvasRectangle
(int(x), y, int(length), m_lineThickness, m_canvas);
rline->setPen(lineColour);
rline->setBrush(lineColour);
line = rline;
} else {
TQCanvasLine *lline = new TQCanvasLine(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());
}
}