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.
1218 lines
31 KiB
1218 lines
31 KiB
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
|
|
|
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
|
|
#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 &tqlayout)
|
|
{
|
|
Profiler profiler("LinedStaff::sizeStaff", true);
|
|
|
|
deleteBars();
|
|
deleteRepeatedClefsAndKeys();
|
|
deleteTimeSignatures();
|
|
|
|
// RG_DEBUG << "LinedStaff::sizeStaff" << endl;
|
|
|
|
int lastBar = tqlayout.getLastVisibleBarOnStaff(*this);
|
|
|
|
double xleft = 0, xright = 0;
|
|
bool haveXLeft = false;
|
|
|
|
xright = tqlayout.getBarPosition(lastBar) - 1;
|
|
|
|
TimeSignature currentTimeSignature;
|
|
|
|
for (int barNo = tqlayout.getFirstVisibleBarOnStaff(*this);
|
|
barNo <= lastBar; ++barNo) {
|
|
|
|
double x = tqlayout.getBarPosition(barNo);
|
|
|
|
if (!haveXLeft) {
|
|
xleft = x;
|
|
haveXLeft = true;
|
|
}
|
|
|
|
double timeSigX = 0;
|
|
TimeSignature timeSig;
|
|
bool isNew = tqlayout.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 :
|
|
(tqlayout.getBarPosition(barNo + 1) - x)),
|
|
tqlayout.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 tqlayout-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 &tqlayout) const
|
|
{
|
|
if (m_insertCursorTimeValid) return m_insertCursorTime;
|
|
return tqlayout.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 &tqlayout,
|
|
timeT time)
|
|
{
|
|
setPointerPosition(tqlayout.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 &tqlayout,
|
|
timeT time)
|
|
{
|
|
double x = tqlayout.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());
|
|
}
|
|
|
|
}
|