Skip to content

Commit

Permalink
fix #271529: incorrect stem position for some noteheads in layout
Browse files Browse the repository at this point in the history
Manually merged changes from musescore#3653 to 2.3
  • Loading branch information
anatoly-os committed May 10, 2018
1 parent 7345a8c commit b7c679b
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 35 deletions.
2 changes: 1 addition & 1 deletion libmscore/beam.cpp
Expand Up @@ -1911,7 +1911,7 @@ qDebug("create stem in layout beam, track %d", c->track());
if (c->hook())
score()->undoRemoveElement(c->hook());

QPointF stemPos(c->stemPos());
QPointF stemPos(c->stemPosX() + c->pagePos().x(), c->stemPos().y());
qreal x2 = stemPos.x() - _pagePos.x();
qreal y1 = (x2 - x1) * slope + py1 + _pagePos.y();
qreal y2 = stemPos.y();
Expand Down
16 changes: 8 additions & 8 deletions libmscore/chord.cpp
Expand Up @@ -734,7 +734,8 @@ void Chord::addLedgerLines()

// check if note horiz. pos. is outside current range
// if more length on the right, increase range
x = note->pos().x();
// ledger lines need the leftmost point of the notehead with a respect of bbox
x = note->pos().x() + note->bboxXShift();
if (x-extraLen < minX) {
minX = x - extraLen;
// minXr = minX - extraLen;
Expand Down Expand Up @@ -1154,10 +1155,9 @@ qreal Chord::centerX() const
return staff()->staffType()->chordStemPosX(this) * spatium();

const Note* note = up() ? upNote() : downNote();
qreal x = note->pos().x();
x += note->headWidth() * .5;
qreal x = note->pos().x() + note->noteheadCenterX();
if (note->mirror()) {
x += note->headWidth() * (up() ? -1.0 : 1.0);
x += note->headBodyWidth() * (up() ? -1.0 : 1.0);
}
return x;
}
Expand Down Expand Up @@ -1872,10 +1872,10 @@ void Chord::layoutPitched()
if (sc->notes().size() > 1) {
// some notes may be further to the right than start note
// allow overlap with those notes to count toward the minimum
qreal snEnd = sn->x() + sn->headWidth();
qreal snEnd = sn->x() + sn->bboxRightPos();
qreal scEnd = snEnd;
for (Note* n : sc->notes())
scEnd = qMax(scEnd, n->x() + n->headWidth());
scEnd = qMax(scEnd, n->x() + n->bboxRightPos());
overlap += scEnd - snEnd;
}
}
Expand Down Expand Up @@ -2798,9 +2798,9 @@ QPointF Chord::layoutArticulation(Articulation* a)
}
if (!staff()->isTabStaff() && !alignToStem) {
if (up())
pos.rx() -= upNote()->headWidth() * .5; // move half-a-note-head to left
pos.rx() -= upNote()->headBodyWidth() * .5; // move half-a-note-head to left
else
pos.rx() += upNote()->headWidth() * .5; // move half-a-note-head to right
pos.rx() += upNote()->headBodyWidth() * .5; // move half-a-note-head to right
}
a->setPos(pos);
a->adjustReadPos();
Expand Down
6 changes: 3 additions & 3 deletions libmscore/chordline.cpp
Expand Up @@ -117,12 +117,12 @@ void ChordLine::layout()
QPointF p(note->pos());
// chordlines to the right of the note
if (_chordLineType == ChordLineType::FALL || _chordLineType == ChordLineType::DOIT)
setPos(p.x() + note->headWidth() + _spatium * .2, p.y());
setPos(p.x() + note->bboxRightPos() + _spatium * .2, p.y());
// chordlines to the left of the note
if (_chordLineType == ChordLineType::PLOP)
setPos(p.x() + note->headWidth() * .25, p.y() - note->headHeight() * .75);
setPos(p.x() + note->bboxRightPos() * .25, p.y() - note->headHeight() * .75);
if (_chordLineType == ChordLineType::SCOOP) {
qreal x = p.x() + (chord()->up() ? note->headWidth() * .25 : _spatium * -.2);
qreal x = p.x() + (chord()->up() ? note->bboxRightPos() * .25 : _spatium * -.2);
setPos(x, p.y() + note->headHeight() * .75);
}
}
Expand Down
30 changes: 13 additions & 17 deletions libmscore/layout.cpp
Expand Up @@ -609,7 +609,7 @@ qreal Score::layoutChords2(QList<Note*>& notes, bool up)

// accumulate return value
if (!mirror)
maxWidth = qMax(maxWidth, note->headWidth());
maxWidth = qMax(maxWidth, note->bboxRightPos());

// prepare for next iteration
lvisible = note->visible();
Expand Down Expand Up @@ -827,36 +827,29 @@ void Score::layoutChords3(QList<Note*>& notes, Staff* staff, Segment* segment)
++nAcc;
}

qreal hw = note->headWidth(); // actual head width, including note & chord mag
Chord* chord = note->chord();
bool _up = chord->up();
qreal stemX = chord->stemPosX(); // stem position for nominal notehead, but allowing for mag

qreal overlapMirror;
if (chord->stem()) {
qreal stemWidth = chord->stem()->lineWidth();
qreal stemWidth5 = stemWidth * 0.5;
chord->stem()->rxpos() = _up ? stemX - stemWidth5 : stemWidth5;
chord->stem()->rxpos() = _up ? chord->stemPosX() - stemWidth5 : stemWidth5;
overlapMirror = stemWidth;
}
else if (chord->durationType().headType() == NoteHead::Type::HEAD_WHOLE)
overlapMirror = styleD(StyleIdx::stemWidth) * chord->mag() * sp;
else
overlapMirror = 0.0;

qreal x;
qreal x = 0.0;
if (note->mirror()) {
if (_up)
x = stemX - overlapMirror;
else
x = stemX - hw + overlapMirror;
}
else {
if (_up)
x = stemX - hw;
x = chord->stemPosX() - overlapMirror;
else
x = 0.0;
x = -note->headBodyWidth() + overlapMirror;
}
else if (_up)
x = chord->stemPosX() - note->headBodyWidth();

note->rypos() = (note->line() + stepOffset) * stepDistance;
note->rxpos() = x;
Expand All @@ -877,13 +870,16 @@ void Score::layoutChords3(QList<Note*>& notes, Staff* staff, Segment* segment)
//if (chord->stem())
// chord->stem()->rxpos() = _up ? x + hw - stemWidth5 : x + stemWidth5;

qreal xx = x + hw + chord->pos().x();
qreal xx = x + chord->stemPosX() + chord->pos().x();

if (chord->dots()) {
if (chord->up())
upDotPosX = qMax(upDotPosX, xx);
else
downDotPosX = qMax(downDotPosX, xx);
else {
qreal noteheadShift = note->headBodyWidth();
downDotPosX = qMax(downDotPosX, xx + noteheadShift);
}

MScore::Direction dotPosition = note->userDotPosition();

if (dotPosition == MScore::Direction::AUTO && nNotes > 1 && note->visible() && !note->dotsHidden()) {
Expand Down
2 changes: 1 addition & 1 deletion libmscore/line.cpp
Expand Up @@ -614,7 +614,7 @@ QPointF SLine::linePos(Grip grip, System** sys) const
// chord bbox() is unreliable, look at notes
// this also allows us to more easily ignore ledger lines
for (Note* n : static_cast<Chord*>(cr)->notes())
maxRight = qMax(maxRight, cr->x() + n->x() + n->headWidth());
maxRight = qMax(maxRight, cr->x() + n->x() + n->bboxRightPos());
}
else {
// rest - won't normally happen
Expand Down
46 changes: 45 additions & 1 deletion libmscore/note.cpp
Expand Up @@ -458,10 +458,33 @@ SymId Note::noteHead() const
return t;
}

//---------------------------------------------------------
// bboxRightPos
//
// returns the x of the symbol bbox. It is different from headWidth() because zero point could be different from leftmost bbox position.
//---------------------------------------------------------

qreal Note::bboxRightPos() const
{
const auto& bbox = score()->scoreFont()->bbox(noteHead(), magS());
return bbox.right();
}

//---------------------------------------------------------
// headBodyWidth
//
// returns the width of the notehead "body". It is actual for slashed noteheads like -O-, where O is body.
//---------------------------------------------------------

qreal Note::headBodyWidth() const
{
return headWidth() + 2 * bboxXShift();
}

//---------------------------------------------------------
// headWidth
//
// returns the width of the notehead symbol
// returns the width of the symbol bbox
// or the width of the string representation of the fret mark
//---------------------------------------------------------

Expand All @@ -470,6 +493,27 @@ qreal Note::headWidth() const
return symWidth(noteHead());
}

//---------------------------------------------------------
// bboxXShift
//
// returns the x shift of the notehead bounding box
//---------------------------------------------------------
qreal Note::bboxXShift() const
{
const auto& bbox = score()->scoreFont()->bbox(noteHead(), magS());
return bbox.bottomLeft().x();
}

//---------------------------------------------------------
// noteheadCenterX
//
// returns the x coordinate of the notehead center related to the basepoint of the notehead bbox
//---------------------------------------------------------
qreal Note::noteheadCenterX() const
{
return score()->scoreFont()->width(noteHead(), magS()) / 2 + bboxXShift();
}

//---------------------------------------------------------
// tabHeadWidth
//---------------------------------------------------------
Expand Down
4 changes: 4 additions & 0 deletions libmscore/note.h
Expand Up @@ -271,6 +271,10 @@ class Note : public Element {
qreal tabHeadHeight(StaffType* tab = 0) const;
QPointF stemDownNW() const;
QPointF stemUpSE() const;
qreal bboxXShift() const;
qreal noteheadCenterX() const;
qreal bboxRightPos() const;
qreal headBodyWidth() const;

SymId noteHead() const;
NoteHead::Group headGroup() const { return _headGroup; }
Expand Down
6 changes: 3 additions & 3 deletions libmscore/slur.cpp
Expand Up @@ -765,7 +765,7 @@ void Slur::slurPosChord(SlurPos* sp)
}
Note* _startNote = stChord->downNote();
Note* _endNote = enChord->downNote();
qreal hw = _startNote->headWidth();
qreal hw = _startNote->bboxRightPos();
qreal __up = _up ? -1.0 : 1.0;
qreal _spatium = spatium();

Expand Down Expand Up @@ -920,7 +920,7 @@ void Slur::slurPos(SlurPos* sp)
bool stemPos = false; // p1 starts at chord stem side

// default positions
xo = hw1 * .5;
xo = hw1 * .5 + (note1 ? note1->bboxXShift() : 0.0);
if (note1)
yo = note1->pos().y();
else if (_up)
Expand Down Expand Up @@ -1016,7 +1016,7 @@ void Slur::slurPos(SlurPos* sp)
if (sa2 == SlurAnchor::NONE) {

// default positions
xo = hw2 * .5;
xo = hw2 * .5 + (note2 ? note2->bboxXShift() : 0.0);
if (note2)
yo = note2->pos().y();
else if (_up)
Expand Down
2 changes: 1 addition & 1 deletion libmscore/stemslash.cpp
Expand Up @@ -60,7 +60,7 @@ void StemSlash::layout()
y += l * 1.2;
h2 = l * .4;
}
qreal w = chord()->upNote()->headWidth() * .7;
qreal w = chord()->upNote()->bboxRightPos() * .7;
setLine(QLineF(QPointF(x + w, y - h2), QPointF(x - w, y + h2)));
adjustReadPos();
}
Expand Down

0 comments on commit b7c679b

Please sign in to comment.