Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #281639: Cutaway staves - better handling of clefs, barlines... #6409

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions libmscore/barline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ static void undoChangeBarLineType(BarLine* bl, BarLineType barType, bool allStav
}
}
}
else if (segmentType == SegmentType::BarLine) {} //TODO: also allow changes on barlines added by user
}
break;
case BarLineType::START_REPEAT: {
Expand Down Expand Up @@ -534,22 +535,33 @@ void BarLine::draw(QPainter* painter) const
switch (barLineType()) {
case BarLineType::NORMAL: {
qreal lw = score()->styleP(Sid::barWidth) * mag();
// a bar line added to the first cr of a measure is a user BeginBarLine (for ossias / cutaway).
// Normal/broken/dotted barlines overlap previous measure's EndBarLine
int overlap = 1;
if (parent())
overlap = segment()->segmentType() == SegmentType::BeginBarLine && !segment()->measure()->header() ? -1 : 1;
painter->setPen(QPen(curColor(), lw, Qt::SolidLine, Qt::FlatCap));
painter->drawLine(QLineF(lw * .5, y1, lw * .5, y2));
painter->drawLine(QLineF(lw * .5 * overlap, y1, lw * .5 * overlap, y2));
}
break;

case BarLineType::BROKEN: {
qreal lw = score()->styleP(Sid::barWidth) * mag();
int overlap = 1;
if (parent())
overlap = segment()->segmentType() == SegmentType::BeginBarLine && !segment()->measure()->header() ? -1 : 1;
painter->setPen(QPen(curColor(), lw, Qt::DashLine, Qt::FlatCap));
painter->drawLine(QLineF(lw * .5, y1, lw * .5, y2));
painter->drawLine(QLineF(lw * .5 * overlap, y1, lw * .5 * overlap, y2));
}
break;

case BarLineType::DOTTED: {
qreal lw = score()->styleP(Sid::barWidth) * mag();
int overlap = 1;
if (parent())
overlap = segment()->segmentType() == SegmentType::BeginBarLine && !segment()->measure()->header() ? -1 : 1;
painter->setPen(QPen(curColor(), lw, Qt::DotLine, Qt::FlatCap));
painter->drawLine(QLineF(lw * .5, y1, lw * .5, y2));
painter->drawLine(QLineF(lw * .5 * overlap, y1, lw * .5 * overlap, y2));
}
break;

Expand Down Expand Up @@ -1152,7 +1164,7 @@ void BarLine::endEditDrag(EditData& ed)
}

bool localDrag = ed.control() || segment()->isBarLine();
if (localDrag) {
if (localDrag || !generated()) { // Don't set global span from dragging user added (non generated) bar lines
Segment* s = segment();
for (int staffIdx = staffIdx1; staffIdx < staffIdx2; ++staffIdx) {
BarLine* b = toBarLine(s->element(staffIdx * VOICES));
Expand Down
6 changes: 2 additions & 4 deletions libmscore/chordrest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,14 +437,12 @@ Element* ChordRest::drop(EditData& data)
bl->setTrack(staffIdx() * VOICES);
bl->setGenerated(false);

if (tick() == m->tick())
return m->drop(data);

BarLine* obl = 0;
for (Staff* st : staff()->staffList()) {
Score* score = st->score();
Measure* measure = score->tick2measure(m->tick());
Segment* seg = measure->undoGetSegmentR(SegmentType::BarLine, rtick());
SegmentType segmentType = tick() == m->tick() ? SegmentType::BeginBarLine : SegmentType::BarLine;
Segment* seg = measure->undoGetSegmentR(segmentType, rtick());
BarLine* l;
if (obl == 0)
obl = l = bl->clone();
Expand Down
42 changes: 38 additions & 4 deletions libmscore/measure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,8 +250,14 @@ Measure::Measure(const Measure& m)

void Measure::layoutStaffLines()
{
for (MStaff* ms : _mstaves)
ms->lines()->layout();
int staffIdx = 0;
for (MStaff* ms : _mstaves) {
if (score()->staff(staffIdx)->cutaway() && isCourtesyClef(staffIdx))
ms->lines()->layoutPartial(width(), 4.0 ,false); // draw a shortened staff (4.0 sp wide) only for the antecipated Clef.
else
ms->lines()->layout();
staffIdx += 1;
}
}

Copy link
Contributor Author

@elerouxx elerouxx Aug 12, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote this function lines()->layoutPartial() (maybe need a better name) that draws only a certain width of the lines and aligns them to the left or right of a measure. In this specific case I needed just enough lines width to fit any Clef.

On a related topic, I have been looking for a way to overcome MuseScore's limitation of having a staff change in the middle of a measure, since the staff lines are drawn per measure. But I believe this function might give a clue of how that could be done.
The code above would:

  • Loop thru the staffTypes in the measure
  • Keep appending lines to ms->lines, calculating their widths (and yOffsets, etc)
  • Example: if there is a staff change from 5 to 1 line in the middle of the measure:, 6 lines will be added to mslines: 5 from the beginning of the measure to the tick of the stchange, and one from there to the end of the measure width.

//---------------------------------------------------------
Expand Down Expand Up @@ -2088,7 +2094,7 @@ void Measure::readVoice(XmlReader& e, int staffIdx, bool irregular)
// StartRepeatBarLine: at rtick == 0, always BarLineType::START_REPEAT
// BarLine: in the middle of a measure, has no semantic
// EndBarLine: at the end of a measure
// BeginBarLine: first segment of a measure, systemic barline
// BeginBarLine: first segment of a measure, systemic barline (or begin bar line added by user)

SegmentType st = SegmentType::Invalid;
Fraction t = e.tick() - tick();
Expand Down Expand Up @@ -2449,7 +2455,7 @@ bool Measure::visible(int staffIdx) const
}
if (system() && (system()->staves()->empty() || !system()->staff(staffIdx)->show()))
return false;
if (score()->staff(staffIdx)->cutaway() && isEmpty(staffIdx))
if (score()->staff(staffIdx)->cutaway() && isEmpty(staffIdx) && !isCourtesyClef(staffIdx))
return false;
return score()->staff(staffIdx)->show() && _mstaves[staffIdx]->visible();
}
Expand Down Expand Up @@ -2733,6 +2739,34 @@ bool Measure::hasVoice(int track) const
return false;
}

// isCourtesyClef
/// Check if the measure is empty except for a clef before end bar line

bool Measure::isCourtesyClef(int staffIdx) const
{
if (!isEmpty(staffIdx))
return false;
Segment* s = last()->prev();
/*if (s->segmentType() != SegmentType::Clef)
return false;*/
int strack;
int etrack;
if (staffIdx < 0) {
strack = 0;
etrack = score()->nstaves() * VOICES;
}
else {
strack = staffIdx * VOICES;
etrack = strack + VOICES;
}
for (int track = strack; track < etrack; ++track) {
Element* e = s->element(track);
if (e && e->isClef())
return true;
}
return false;
}

//-------------------------------------------------------------------
// isEmpty
/// Check if the measure is filled by a full-measure rest, or is
Expand Down
1 change: 1 addition & 0 deletions libmscore/measure.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ class Measure final : public MeasureBase {
void checkMultiVoices(int staffIdx);
bool hasVoice(int track) const;
bool isEmpty(int staffIdx) const;
bool isCourtesyClef(int staffIdx) const;
bool isFullMeasureRest() const;
bool isRepeatMeasure(const Staff* staff) const;
bool visible(int staffIdx) const;
Expand Down
45 changes: 45 additions & 0 deletions libmscore/stafflines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,51 @@ void StaffLines::layoutForWidth(qreal w)
}
}

//---------------------------------------------------------
// layoutPartial
//---------------------------------------------------------

void StaffLines::layoutPartial(qreal w, qreal wPartial, bool alignLeft)
{
const Staff* s = staff();
qreal _spatium = spatium();
wPartial *= spatium();
qreal dist = _spatium;
setPos(QPointF(0.0, 0.0));
int _lines;
if (s) {
setMag(s->mag(measure()->tick()));
setColor(s->color());
const StaffType* st = s->staffType(measure()->tick());
dist *= st->lineDistance().val();
_lines = st->lines();
rypos() = st->yoffset().val() * _spatium;
}
else {
_lines = 5;
setColor(MScore::defaultColor);
}
lw = score()->styleS(Sid::staffLineWidth).val() * _spatium;
qreal x1 = pos().x();
qreal x2 = x1 + w;
qreal y = pos().y();
bbox().setRect(x1, -lw * .5 + y, w, (_lines-1) * dist + lw);

if (_lines == 1) {
qreal extraSize = _spatium;
bbox().adjust(0, -extraSize, 0, extraSize);
}

lines.clear();
for (int i = 0; i < _lines; ++i) {
if (alignLeft)
lines.push_back(QLineF(x1, y, x1 + wPartial, y));
else
lines.push_back(QLineF(x2-wPartial, y, x2, y));
y += dist;
}
}

//---------------------------------------------------------
// draw
//---------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions libmscore/stafflines.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class StaffLines final : public Element {
Measure* measure() const { return (Measure*)parent(); }
qreal y1() const;
void layoutForWidth(qreal width);
void layoutPartial (qreal width, qreal widthPartial, bool alignRight);
};

} // namespace Ms
Expand Down