Skip to content

Commit

Permalink
Merge pull request #4591 from MarcSabatella/left-fingering
Browse files Browse the repository at this point in the history
fingering layout
  • Loading branch information
anatoly-os committed Jan 29, 2019
2 parents c33ac31 + 8942ed8 commit f1550ca
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 52 deletions.
32 changes: 32 additions & 0 deletions libmscore/chord.cpp
Expand Up @@ -47,6 +47,7 @@
#include "stringdata.h"
#include "beam.h"
#include "slur.h"
#include "fingering.h"

namespace Ms {

Expand Down Expand Up @@ -1893,6 +1894,15 @@ void Chord::layoutPitched()
lll = qMax(lll, d);
}
}

// clear fingering layout
for (Element* e : note->el()) {
if (e->isFingering()) {
e->setPos(QPointF());
e->setbbox(QRectF());
}
}

}

//-----------------------------------------
Expand Down Expand Up @@ -1985,6 +1995,28 @@ void Chord::layoutPitched()

for (Note* note : _notes)
note->layout2();

// align fingering
std::vector<Fingering*> alignNote;
qreal xNote = 10000.0;
for (Note* note : _notes) {
bool leftFound = false;
for (Element* e : note->el()) {
if (e->isFingering() && e->autoplace()) {
Fingering* f = toFingering(e);
if (f->layoutType() == ElementType::NOTE && f->tid() == Tid::LH_GUITAR_FINGERING) {
alignNote.push_back(f);
if (!leftFound) {
leftFound = true;
qreal xf = f->ipos().x();
xNote = qMin(xNote, xf);
}
}
}
}
}
for (Fingering* f : alignNote)
f->rxpos() = xNote;
}

//---------------------------------------------------------
Expand Down
148 changes: 112 additions & 36 deletions libmscore/fingering.cpp
Expand Up @@ -19,6 +19,8 @@
#include "part.h"
#include "measure.h"
#include "stem.h"
#include "skyline.h"
#include "system.h"

namespace Ms {

Expand Down Expand Up @@ -46,6 +48,40 @@ Fingering::Fingering(Score* s, ElementFlags ef)
{
}

//---------------------------------------------------------
// layoutType
//---------------------------------------------------------

ElementType Fingering::layoutType()
{
switch (tid()) {
case Tid::FINGERING:
case Tid::RH_GUITAR_FINGERING:
case Tid::STRING_NUMBER:
return ElementType::CHORD;
default:
return ElementType::NOTE;
}
}

//---------------------------------------------------------
// calculatePlacement
//---------------------------------------------------------

void Fingering::calculatePlacement()
{
Note* n = note();
if (!n)
return;
Chord* chord = n->chord();
Staff* staff = chord->staff();
Part* part = staff->part();
int nstaves = part->nstaves();
bool voices = chord->measure()->hasVoices(staff->idx());
bool below = voices ? !chord->up() : (nstaves > 1) && (staff->rstaff() == nstaves - 1);
setPlacement(below ? Placement::BELOW : Placement::ABOVE);
}

//---------------------------------------------------------
// layout
//---------------------------------------------------------
Expand All @@ -63,57 +99,97 @@ void Fingering::layout()
}

TextBase::layout();
rypos() = 0.0; // handle placement below

if (autoplace() && note()) {
Chord* chord = note()->chord();
Staff* staff = chord->staff();
Part* part = staff->part();
int n = part->nstaves();
bool voices = chord->measure()->hasVoices(staff->idx());
bool below = voices ? !chord->up() : (n > 1) && (staff->rstaff() == n-1);
bool tight = voices && !chord->beam();

qreal x = 0.0;
qreal y = 0.0;
qreal headWidth = note()->bboxRightPos();
qreal headHeight = note()->headHeight();
qreal fh = headHeight; // TODO: fingering number height

if (chord->notes().size() == 1) {
x = headWidth * .5;
if (below) {
// place fingering below note
y = fh + spatium() * .4;
Note* n = note();
Chord* chord = n->chord();
bool voices = chord->measure()->hasVoices(chord->staffIdx());
bool tight = voices && chord->notes().size() == 1 && !chord->beam() && tid() != Tid::STRING_NUMBER;

qreal headWidth = n->bboxRightPos();

// temporarily exclude self from chord shape
setAutoplace(false);

if (layoutType() == ElementType::CHORD) {
Stem* stem = chord->stem();
Segment* s = chord->segment();
Measure* m = s->measure();
SysStaff* ss = m->system()->staff(chord->vStaffIdx());
Staff* vStaff = chord->staff(); // TODO: use current height at tick
if (n->mirror())
rxpos() -= n->ipos().x();
rxpos() += headWidth * .5;
if (placeAbove()) {
if (tight) {
y += 0.5 * spatium();
if (chord->stem())
x += 0.5 * spatium();
rxpos() -= 0.8 * spatium();
rypos() -= spatium() * 1.5;
}
else if (chord->stem() && !chord->up()) {
// on stem side
y += chord->stem()->height();
x -= spatium() * .4;
else {
QRectF r = bbox().translated(m->pos() + s->pos() + chord->pos() + n->pos() + pos());
SkylineLine sk(false);
sk.add(r.x(), r.bottom(), r.width());
qreal d = sk.minDistance(ss->skyline().north());
if (d > 0.0)
rypos() -= d + height() * .25;
// force extra space above staff & chord (but not other fingerings)
qreal top;
if (chord->up() && chord->beam() && stem) {
top = stem->y() + stem->bbox().top();
}
else {
Note* un = chord->upNote();
top = qMin(0.0, un->y() + un->bbox().top());
}
top -= spatium() * 0.5;
qreal diff = (bbox().bottom() + ipos().y() + n->y()) - top;
if (diff > 0.0)
rypos() -= diff;
}
}
else {
// place fingering above note
y = -headHeight - spatium() * .4;
if (tight) {
y -= 0.5 * spatium();
if (chord->stem())
x -= 0.5 * spatium();
rxpos() += 0.8 * spatium();
rypos() += spatium() * 1.5;
}
else if (chord->stem() && chord->up()) {
// on stem side
y -= chord->stem()->height();
x += spatium() * .4;
else {
QRectF r = bbox().translated(m->pos() + s->pos() + chord->pos() + n->pos() + pos());
SkylineLine sk(true);
sk.add(r.x(), r.top(), r.width());
qreal d = ss->skyline().south().minDistance(sk);
if (d > 0.0)
rypos() += d + height() * .25;
// force extra space below staff & chord (but not other fingerings)
qreal bottom;
if (!chord->up() && chord->beam() && stem) {
bottom = stem->y() + stem->bbox().bottom();
}
else {
Note* dn = chord->downNote();
bottom = qMax(vStaff->height(), dn->y() + dn->bbox().bottom());
}
bottom += spatium() * 0.5;
qreal diff = bottom - (bbox().top() + ipos().y() + n->y());
if (diff > 0.0)
rypos() += diff;
}
}
}
else {
x -= spatium();
else if (tid() == Tid::LH_GUITAR_FINGERING) {
// place to left of note
qreal left = n->shape().left();
if (left - n->x() > 0.0)
rxpos() -= left;
else
rxpos() -= n->x();
}
rpos() += QPointF(x, y);
// for other fingering styles, do not autoplace

// restore autoplace
setAutoplace(true);
}
}

Expand Down
2 changes: 2 additions & 0 deletions libmscore/fingering.h
Expand Up @@ -31,6 +31,8 @@ class Fingering final : public TextBase {
virtual ElementType type() const override { return ElementType::FINGERING; }

Note* note() const { return toNote(parent()); }
ElementType layoutType();
void calculatePlacement();

virtual void draw(QPainter*) const override;
virtual void layout() override;
Expand Down
36 changes: 26 additions & 10 deletions libmscore/layout.cpp
Expand Up @@ -3530,22 +3530,37 @@ void Score::layoutSystemElements(System* system, LayoutContext& lc)
if (!e || !e->isChordRest() || !score()->staff(e->staffIdx())->show())
continue;
ChordRest* cr = toChordRest(e);

// layout beam
if (isTopBeam(cr)) {
cr->beam()->layout();
cr->beam()->addSkyline(system->staff(cr->beam()->staffIdx())->skyline());
}

// layout fingering a second time (first layout called in note->layout2())
// to finally place fingerings above or below a beam

if (e->isChord()) {
Chord* c = toChord(e);
for (Note* note : c->notes()) {
for (Element* el : note->el()) {
if (el->isFingering())
el->layout();
// layout fingerings placed above/below chord
if (e->isChord()) {
std::list<Fingering*> fingerings;
Chord* c = toChord(e);
for (Note* note : c->notes()) {
for (Element* el : note->el()) {
if (el->isFingering()) {
Fingering* f = toFingering(el);
if (f->layoutType() == ElementType::CHORD) {
if (f->placeAbove())
fingerings.push_back(f);
else
fingerings.push_front(f);
}
}
}
}
for (Fingering* f : fingerings) {
f->layout();
if (f->autoplace() && f->visible()) {
QRectF r = f->bbox().translated(f->pos() + f->note()->pos() + c->pos() + s->pos() + s->measure()->pos());
system->staff(f->note()->chord()->vStaffIdx())->skyline().add(r);
}
}
}
}
}
Expand All @@ -3570,7 +3585,8 @@ void Score::layoutSystemElements(System* system, LayoutContext& lc)
while (de->tuplet() && de->tuplet()->elements().front() == de) {
Tuplet* t = de->tuplet();
t->layout();
system->staff(t->staffIdx())->skyline().add(t->shape().translated(t->pos() + t->measure()->pos()));
if (t->autoplace() && t->visible())
system->staff(t->staffIdx())->skyline().add(t->shape().translated(t->pos() + t->measure()->pos()));
de = t;
}
}
Expand Down
19 changes: 15 additions & 4 deletions libmscore/note.cpp
Expand Up @@ -1007,9 +1007,9 @@ void Note::add(Element* e)
case ElementType::NOTEDOT:
_dots.append(toNoteDot(e));
break;
case ElementType::FINGERING:
case ElementType::SYMBOL:
case ElementType::IMAGE:
case ElementType::FINGERING:
case ElementType::TEXT:
case ElementType::BEND:
_el.push_back(e);
Expand Down Expand Up @@ -2077,8 +2077,17 @@ void Note::layout2()
e->rxpos() -= symWidth(SymId::noteheadParenthesisLeft);
}
}
else
else if (e->isFingering()) {
Fingering* f = toFingering(e);
f->calculatePlacement();
// layout fingerings that are placed relative to notehead
// fingerings placed relative to chord will be laid out later
if (f->layoutType() == ElementType::NOTE)
f->layout();
}
else {
e->layout();
}
}
}

Expand Down Expand Up @@ -3166,8 +3175,10 @@ Shape Note::shape() const
shape.add(symBbox(SymId::augmentationDot).translated(dot->pos()));
if (_accidental)
shape.add(_accidental->bbox().translated(_accidental->pos()));
for (auto e : _el)
shape.add(e->bbox().translated(e->pos()));
for (auto e : _el) {
if (e->autoplace() && e->visible())
shape.add(e->bbox().translated(e->pos()));
}
#endif
return shape;
}
Expand Down
4 changes: 2 additions & 2 deletions libmscore/style.cpp
Expand Up @@ -615,14 +615,14 @@ static const StyleType styleTypes[] {
{ Sid::lhGuitarFingeringFontSpatiumDependent, "lhGuitarFingeringFontSpatiumDependent", true },
{ Sid::lhGuitarFingeringFontStyle, "lhGuitarFingeringFontStyle", int(FontStyle::Normal) },
{ Sid::lhGuitarFingeringColor, "lhGuitarFingeringColor", QColor(0, 0, 0, 255) },
{ Sid::lhGuitarFingeringAlign, "lhGuitarFingeringAlign", QVariant::fromValue(Align::CENTER | Align::VCENTER) },
{ Sid::lhGuitarFingeringAlign, "lhGuitarFingeringAlign", QVariant::fromValue(Align::RIGHT | Align::VCENTER) },
{ Sid::lhGuitarFingeringFrameType, "lhGuitarFingeringFrameType", int(FrameType::NO_FRAME) },
{ Sid::lhGuitarFingeringFramePadding, "lhGuitarFingeringFramePadding", 0.2 },
{ Sid::lhGuitarFingeringFrameWidth, "lhGuitarFingeringFrameWidth", 0.1 },
{ Sid::lhGuitarFingeringFrameRound, "lhGuitarFingeringFrameRound", 0 },
{ Sid::lhGuitarFingeringFrameFgColor, "lhGuitarFingeringFrameFgColor", QColor(0, 0, 0, 255) },
{ Sid::lhGuitarFingeringFrameBgColor, "lhGuitarFingeringFrameBgColor", QColor(255, 255, 255, 0) },
{ Sid::lhGuitarFingeringOffset, "lhGuitarFingeringOffset", QPointF(0.0, 0.0) },
{ Sid::lhGuitarFingeringOffset, "lhGuitarFingeringOffset", QPointF(-0.5, 0.0) },

{ Sid::rhGuitarFingeringFontFace, "rhGuitarFingeringFontFace", "FreeSerif" },
{ Sid::rhGuitarFingeringFontSize, "rhGuitarFingeringFontSize", 8.0 },
Expand Down

0 comments on commit f1550ca

Please sign in to comment.