Logo Search packages:      
Sourcecode: rosegarden version File versions  Download package

linedstaff.cpp

// -*- c-basic-offset: 4 -*-

/*
    Rosegarden-4
    A sequencer and musical notation editor.

    This program is Copyright 2000-2006
        Guillaume Laurent   <glaurent@telegraph-road.org>,
        Chris Cannam        <cannam@all-day-breakfast.com>,
        Richard Bown        <bownie@bownie.com>

    The moral right of the authors to claim authorship of this work
    has been asserted.

    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 "colours.h"
#include "rosestrings.h"
#include "rosedebug.h"
#include "SnapGrid.h"
#include <qcanvas.h>
#include <qcolor.h>
#include <qpainter.h>

#include <algorithm>

#include "LayoutEngine.h"
#include "Profiler.h"

// width of pointer
//
const int pointerWidth = 3;

class BarLine : public QCanvasPolygonalItem
{
public:
    BarLine(QCanvas *canvas, double layoutX,
          int barLineHeight, int baseBarThickness, int lineSpacing,
          int inset, LinedStaff::BarStyle style) :
      QCanvasPolygonalItem(canvas),
      m_layoutX(layoutX),
      m_barLineHeight(barLineHeight),
      m_baseBarThickness(baseBarThickness),
      m_lineSpacing(lineSpacing),
      m_inset(inset),
      m_style(style) { }

    double getLayoutX() const { return m_layoutX; }
    
    virtual QPointArray areaPoints() const;
    virtual void drawShape(QPainter &);

protected:
    double m_layoutX;
    int m_barLineHeight;
    int m_baseBarThickness;
    int m_lineSpacing;
    int m_inset;
    LinedStaff::BarStyle m_style;
};


void
BarLine::drawShape(QPainter &painter)
{
    int bx = int(x());
    int by = int(y());

    switch (m_style) {

    case LinedStaff::PlainBar:
      painter.drawRect(bx, by, m_baseBarThickness, m_barLineHeight);
      break;

    case LinedStaff::DoubleBar:
      painter.drawRect(bx, by, m_baseBarThickness, m_barLineHeight);
      painter.drawRect(bx + m_baseBarThickness * 3, by,
                   m_baseBarThickness, m_barLineHeight);
      break;

    case LinedStaff::HeavyDoubleBar:
      bx -= m_baseBarThickness * 5;
      painter.drawRect(bx, by, m_baseBarThickness, m_barLineHeight);
      painter.drawRect(bx + m_baseBarThickness * 3, by,
                   m_baseBarThickness * 3, m_barLineHeight);
      break;

    case LinedStaff::RepeatEndBar:
      bx -= m_baseBarThickness * 5 + m_lineSpacing * 2 / 3;
      painter.drawEllipse(bx, by + m_barLineHeight / 2 - (m_lineSpacing * 2 / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      painter.drawEllipse(bx, by + m_barLineHeight / 2 + (m_lineSpacing / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      bx += m_lineSpacing * 2 / 3;
      painter.drawRect(bx, by, m_baseBarThickness, m_barLineHeight);
      painter.drawRect(bx + m_baseBarThickness * 3, by,
                   m_baseBarThickness * 3, m_barLineHeight);
      break;

    case LinedStaff::RepeatStartBar:

      if (m_inset > 0) {
          painter.drawRect(bx, by, m_baseBarThickness, m_barLineHeight);
          bx += m_inset;
      }

      painter.drawRect(bx, by, m_baseBarThickness * 3, m_barLineHeight);
      painter.drawRect(bx + m_baseBarThickness * 5, by,
                   m_baseBarThickness, m_barLineHeight);
      bx += m_baseBarThickness * 6 + (m_lineSpacing / 3);
      painter.drawEllipse(bx, by + m_barLineHeight / 2 - (m_lineSpacing * 2 / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      painter.drawEllipse(bx, by + m_barLineHeight / 2 + (m_lineSpacing / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      break;

    case LinedStaff::RepeatBothBar:

      if (m_inset > 0) {
          painter.drawRect(bx, by, m_baseBarThickness, m_barLineHeight);
          bx += m_inset;
      }

      bx -= m_baseBarThickness * 4 + m_lineSpacing * 2 / 3;
      painter.drawEllipse(bx, by + m_barLineHeight / 2 - (m_lineSpacing * 2 / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      painter.drawEllipse(bx, by + m_barLineHeight / 2 + (m_lineSpacing / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      bx += m_lineSpacing * 2 / 3;
      painter.drawRect(bx, by, m_baseBarThickness, m_barLineHeight);
      painter.drawRect(bx + m_baseBarThickness * 3, by,
                   m_baseBarThickness * 3, m_barLineHeight);
      painter.drawRect(bx + m_baseBarThickness * 8, by,
                   m_baseBarThickness, m_barLineHeight);
      bx += m_baseBarThickness * 9 + (m_lineSpacing / 3);
      painter.drawEllipse(bx, by + m_barLineHeight / 2 - (m_lineSpacing * 2 / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      painter.drawEllipse(bx, by + m_barLineHeight / 2 + (m_lineSpacing / 3),
                      m_lineSpacing / 3, m_lineSpacing / 3);
      
      break;

    case LinedStaff::NoVisibleBar:
      break;
    }
}

QPointArray
BarLine::areaPoints() const
{
    int bx = int(x());
    int by = int(y());
    int x0 = bx, y0 = by, x1, y1 = by + m_barLineHeight;

    switch (m_style) {

    case LinedStaff::PlainBar:
      x1 = x0 + m_baseBarThickness;
      break;

    case LinedStaff::DoubleBar:
      x1 = x0 + m_baseBarThickness * 4;
      break;

    case LinedStaff::HeavyDoubleBar:
      x0 -= m_baseBarThickness * 6;
      x1 = bx;
      break;

    case LinedStaff::RepeatEndBar:
      x0 -= m_baseBarThickness * 6 + m_lineSpacing * 2 / 3;
      x1 = bx;
      break;

    case LinedStaff::RepeatStartBar:
      x1 = x0 + m_baseBarThickness * 6 + m_lineSpacing * 2 / 3 + m_inset;
      break;

    case LinedStaff::RepeatBothBar:
      x0 -= m_baseBarThickness * 4 + m_lineSpacing * 2 / 3;
      x1 = x0 + m_baseBarThickness * 9 + m_lineSpacing * 2 / 3 + m_inset;
      break;

    case LinedStaff::NoVisibleBar:
      x1 = x0 + 1;
      break;
    }

    QPointArray p(4);
    p[0] = QPoint(x0, y0);
    p[1] = QPoint(x1, y0);
    p[2] = QPoint(x1, y1);
    p[3] = QPoint(x0, y1);
    return p;
}

00203 LinedStaff::LinedStaff(QCanvas *canvas, Rosegarden::Segment *segment,
                          Rosegarden::SnapGrid *snapGrid, int id,
                          int resolution, int lineThickness) :
    Rosegarden::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))
{
    initCursors();
}

00230 LinedStaff::LinedStaff(QCanvas *canvas, Rosegarden::Segment *segment,
                   Rosegarden::SnapGrid *snapGrid,
                   int id, int resolution, int lineThickness,
                   double pageWidth, int rowsPerPage, int rowSpacing) :
    Rosegarden::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))
{
    initCursors();
}

00258 LinedStaff::LinedStaff(QCanvas *canvas, Rosegarden::Segment *segment,
                   Rosegarden::SnapGrid *snapGrid,
                   int id, int resolution, int lineThickness,
                   PageMode pageMode, double pageWidth, int rowsPerPage,
                   int rowSpacing) :
    Rosegarden::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))
{
    initCursors();
}

00287 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(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::Pointer));
    pen.setWidth(pointerWidth);

    m_pointer->setPen(pen);
    m_pointer->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::Pointer));

    pen.setColor(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::InsertCursor));

    m_insertCursor->setPen(pen);
    m_insertCursor->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::InsertCursor));
}

void
00312 LinedStaff::setResolution(int resolution)
{
    m_resolution = resolution;
}

void
00318 LinedStaff::setLineThickness(int lineThickness)
{
    m_lineThickness = lineThickness;
}

void
00324 LinedStaff::setPageMode(PageMode pageMode)
{
    m_pageMode = pageMode;
}

void
00330 LinedStaff::setPageWidth(double pageWidth)
{
    m_pageWidth = pageWidth;
}

void
00336 LinedStaff::setRowsPerPage(int rowsPerPage)
{
    m_rowsPerPage = rowsPerPage;
}

void
00342 LinedStaff::setRowSpacing(int rowSpacing)
{
    m_rowSpacing = rowSpacing;
}

void
00348 LinedStaff::setConnectingLineLength(int connectingLineLength)
{
    m_connectingLineLength = connectingLineLength;
}

int
00354 LinedStaff::getId() const
{
    return m_id;
}

void
00360 LinedStaff::setX(double x)
{
    m_x = x;
}

double
00366 LinedStaff::getX() const
{
    return m_x;
}

void
00372 LinedStaff::setY(int y)
{
    m_y = y;
}

int 
00378 LinedStaff::getY() const
{
    return m_y;
}

void
00384 LinedStaff::setMargin(double margin)
{
    m_margin = margin;
}

double
00390 LinedStaff::getMargin() const
{
    if (m_pageMode != MultiPageMode) return 0;
    return m_margin;
}

void
00397 LinedStaff::setTitleHeight(int titleHeight)
{
    m_titleHeight = titleHeight;
}

int
00403 LinedStaff::getTitleHeight() const
{
    return m_titleHeight;
}

double
00409 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
00425 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 
00443 LinedStaff::getHeightOfRow() const
{
    return getTopLineOffset() + getLegerLineCount() * getLineSpacing()
      + getBarLineHeight() + m_lineThickness;
}

bool
00450 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
00488 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
00509 LinedStaff::getLayoutYForHeight(int h) const
{
    int y = ((getTopLineHeight() - h) * getLineSpacing()) / getHeightPerLine();
    if (h < getTopLineHeight() && (h % getHeightPerLine() != 0)) ++y;

    return y;
}

int
00518 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
00566 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
00616 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
00625 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
00693 LinedStaff::sizeStaff(Rosegarden::HorizontalLayoutEngine &layout)
{
    Rosegarden::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;

    Rosegarden::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;
      Rosegarden::TimeSignature timeSig;
      bool isNew = layout.getTimeSignaturePosition(*this, barNo, timeSig, timeSigX);
      
      if (isNew && barNo < lastBar) {
          currentTimeSignature = timeSig;
          insertTimeSignature(timeSigX, currentTimeSignature);
      }

      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 Rosegarden::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(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::BarLine));
      line->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::BarLine));
    } else {
      line->setPen(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::BarLineIncorrect));
      line->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::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(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::BarLine));
      eline->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::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(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::BeatLine));
          rect->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::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(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::SubBeatLine));
              rect->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::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(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::StaffConnectingLine));
      rect->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::StaffConnectingLine));
      rect->setZ(-3);
      if (hidden) rect->hide();
      else rect->show();
      
      LineRec connectingLine(layoutX, rect);
      m_barConnectingLines.push_back(connectingLine);
    }
}

bool
00967 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 Rosegarden::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++);
}


// m_staffLines[row] must already exist (although it may be empty)

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;
}


// m_staffLines[row] must already exist (although it may be empty)

void
01079 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(Rosegarden::GUIPalette::getColour(Rosegarden::GUIPalette::StaffConnectingTerminatingLine));
      line->setBrush(Rosegarden::GUIPalette::getColour(Rosegarden::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
01185 LinedStaff::setCurrent(bool current)
{
    m_current = current;
    if (m_current) {
      m_insertCursor->show();
    } else {
      m_insertCursor->hide();
    }
}

double
01196 LinedStaff::getLayoutXOfPointer() const
{
    double x = m_pointer->x();
    int row = getRowForCanvasCoords(x, int(m_pointer->y()));
    return getLayoutCoordsForCanvasCoords(x, getCanvasYForTopLine(row)).first;
}

void
01204 LinedStaff::getPointerPosition(double &cx, int &cy) const
{
    cx = m_pointer->x();
    cy = getCanvasYForTopOfStaff(getRowForCanvasCoords(cx, int(m_pointer->y())));
}

double
01211 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;
}

void
01220 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
01232 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
01244 LinedStaff::setPointerPosition(Rosegarden::HorizontalLayoutEngine &layout,
                         Rosegarden::timeT time)
{
    setPointerPosition(layout.getXForTime(time));
}

void
01251 LinedStaff::setPointerPosition(double layoutX)
{
    LinedStaffCoords coords = getCanvasCoordsForLayoutCoords(layoutX, 0);
    setPointerPosition(coords.first, coords.second);
}

void
01258 LinedStaff::hidePointer()
{
    m_pointer->hide();
}

void
01264 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();
}

void
01278 LinedStaff::setInsertCursorPosition(Rosegarden::HorizontalLayoutEngine &layout,
                               Rosegarden::timeT time)
{
    double x = layout.getXForTime(time);
    LinedStaffCoords coords = getCanvasCoordsForLayoutCoords(x, 0);
    setInsertCursorPosition(coords.first, coords.second);
}

void
01287 LinedStaff::hideInsertCursor()
{
    m_insertCursor->hide();
}

void
01293 LinedStaff::renderElements(Rosegarden::ViewElementList::iterator,
                           Rosegarden::ViewElementList::iterator)
{
    // nothing -- we assume rendering will be done by the implementation
    // of positionElements
}

void
01301 LinedStaff::renderAllElements()
{
    renderElements(getViewElementList()->begin(),
                   getViewElementList()->end());
}

void
01308 LinedStaff::positionAllElements()
{
    positionElements(getSegment().getStartTime(),
                 getSegment().getEndTime());
}


Generated by  Doxygen 1.6.0   Back to index