Skip to content

Lyrics revamp and new options #22434

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

Merged
merged 6 commits into from
May 15, 2024
Merged
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
2 changes: 1 addition & 1 deletion src/engraving/compat/engravingcompat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ void EngravingCompat::correctPedalEndPoints(MasterScore* score)
for (auto pair : score->spanner()) {
Spanner* spanner = pair.second;
if (spanner->isPedal() && toPedal(spanner)->endHookType() == HookType::HOOK_45) {
ChordRest* endCR = score->findCRinStaff(spanner->tick2(), track2staff(spanner->track()));
ChordRest* endCR = score->findChordRestEndingBeforeTickInStaff(spanner->tick2(), track2staff(spanner->track()));
if (endCR) {
for (EngravingObject* item : spanner->linkList()) {
toSpanner(item)->setTick2(endCR->tick());
Expand Down
2 changes: 1 addition & 1 deletion src/engraving/dom/chordtextlinebase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@ ChordTextLineBase::ChordTextLineBase(const ElementType& type, EngravingItem* par

void ChordTextLineBase::doComputeEndElement()
{
setEndElement(score()->findCRinStaff(tick2(), track2staff(track2())));
setEndElement(score()->findChordRestEndingBeforeTickInStaff(tick2(), track2staff(track2())));
}
}
1 change: 0 additions & 1 deletion src/engraving/dom/engravingitem.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ enum class KerningType
NON_KERNING,
LIMITED_KERNING,
SAME_VOICE_LIMIT,
KERNING_UNTIL_ORIGIN,
ALLOW_COLLISION,
NOT_SET,
};
Expand Down
45 changes: 10 additions & 35 deletions src/engraving/dom/lyrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,26 +176,6 @@ void Lyrics::scanElements(void* data, void (* func)(void*, EngravingItem*), bool
_separator->scanElements(data, func, all); */
}

//---------------------------------------------------------
// layout2
// compute vertical position
//---------------------------------------------------------

void Lyrics::layout2(int nAbove)
{
LayoutData* ldata = mutldata();
double lh = lineSpacing() * style().styleD(Sid::lyricsLineHeight);

if (placeBelow()) {
double yo = segment()->measure()->system()->staff(staffIdx())->bbox().height();
ldata->setPosY(lh * (m_no - nAbove) + yo - chordRest()->y());
ldata->move(styleValue(Pid::OFFSET, Sid::lyricsPosBelow).value<PointF>());
} else {
ldata->setPosY(-lh * (nAbove - m_no - 1) - chordRest()->y());
ldata->move(styleValue(Pid::OFFSET, Sid::lyricsPosAbove).value<PointF>());
}
}

//---------------------------------------------------------
// paste
//---------------------------------------------------------
Expand Down Expand Up @@ -509,6 +489,16 @@ void Lyrics::triggerLayout() const
}
}

double Lyrics::yRelativeToStaff() const
{
return pos().y() + chordRest()->pos().y();
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it return multdata()->posY() instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes it should, but because of this issue, I need this function to return the position including offset, hence why I need to use pos() instead of mutldata()->pos()

}

void Lyrics::setYRelativeToStaff(double y)
{
mutldata()->setPosY(y - chordRest()->pos().y());
}

//---------------------------------------------------------
// forAllLyrics
//---------------------------------------------------------
Expand Down Expand Up @@ -545,21 +535,6 @@ void Lyrics::undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps
}
TextBase::undoChangeProperty(id, v, ps);
return;
} else if (id == Pid::AUTOPLACE && v.toBool() != autoplace()) {
if (v.toBool()) {
// setting autoplace
// reset offset
undoResetProperty(Pid::OFFSET);
} else {
// unsetting autoplace
// rebase offset
PointF off = offset();
double y = pos().y() - propertyDefault(Pid::OFFSET).value<PointF>().y();
off.ry() = placeAbove() ? y : y - staff()->staffHeight();
undoChangeProperty(Pid::OFFSET, off, PropertyFlags::UNSTYLED);
}
TextBase::undoChangeProperty(id, v, ps);
return;
}

TextBase::undoChangeProperty(id, v, ps);
Expand Down
28 changes: 14 additions & 14 deletions src/engraving/dom/lyrics.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ class Lyrics final : public TextBase
Measure* measure() const { return toMeasure(explicitParent()->explicitParent()->explicitParent()); }
ChordRest* chordRest() const { return toChordRest(explicitParent()); }

void layout2(int);

void scanElements(void* data, void (* func)(void*, EngravingItem*), bool all=true) override;

int subtype() const override { return m_no; }
Expand Down Expand Up @@ -105,6 +103,9 @@ class Lyrics final : public TextBase
PropertyValue propertyDefault(Pid id) const override;
void triggerLayout() const override;

double yRelativeToStaff() const;
void setYRelativeToStaff(double y);

protected:
int m_no = 0; // row index
bool m_even = false;
Expand Down Expand Up @@ -150,8 +151,6 @@ class LyricsLine final : public SLine
bool isDash() const { return !isEndMelisma(); }
bool setProperty(Pid propertyId, const PropertyValue& v) override;

PointF linePos(Grip grip, System** system) const override;

protected:
Lyrics* m_nextLyrics = nullptr;

Expand All @@ -173,19 +172,20 @@ class LyricsLineSegment final : public LineSegment

LyricsLineSegment* clone() const override { return new LyricsLineSegment(*this); }

int numOfDashes() const { return m_numOfDashes; }
void setNumOfDashes(int val) { m_numOfDashes = val; }

double dashLength() const { return m_dashLength; }
void setDashLength(double val) { m_dashLength = val; }

// helper functions
LyricsLine* lyricsLine() const { return toLyricsLine(spanner()); }
Lyrics* lyrics() const { return lyricsLine()->lyrics(); }

protected:
int m_numOfDashes = 0;
double m_dashLength = 0.0;
double baseLineShift() const;

struct LayoutData : public LineSegment::LayoutData {
public:
const std::vector<LineF>& dashes() const { return m_dashes; }
void clearDashes() { m_dashes.clear(); }
void addDash(const LineF& dash) { m_dashes.push_back(dash); }
private:
std::vector<LineF> m_dashes;
};
DECLARE_LAYOUTDATA_METHODS(LyricsLineSegment)
};
} // namespace mu::engraving
#endif
68 changes: 14 additions & 54 deletions src/engraving/dom/lyricsline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,68 +118,18 @@ bool LyricsLine::setProperty(Pid propertyId, const engraving::PropertyValue& v)
return true;
}

PointF LyricsLine::linePos(Grip grip, System** system) const
{
if (grip == Grip::START) {
return PointF(); // Start is computed elsewhere
}

EngravingItem* endEl = endElement();
ChordRest* endCr = endEl && endEl->isChordRest() ? toChordRest(endEl) : nullptr;
if (!endCr) {
return PointF();
}

if (endCr->track() != track()) {
EngravingItem* cr = endCr->segment()->elementAt(track());
if (cr) {
endCr = toChordRest(cr);
}
}

Segment* endSeg = endCr->segment();
*system = endSeg->measure()->system();
double x = endSeg->x() + endSeg->measure()->x();
if (endCr) {
if (endCr->isChord()) {
Chord* endChord = toChord(endCr);
Note* endNote = endChord->up() ? endChord->downNote() : endChord->upNote();
x += endNote->x() + endNote->headWidth();
} else {
x += endCr->width();
}
}

return PointF(x, 0.0);
}

void LyricsLine::doComputeEndElement()
{
if (!isEndMelisma()) {
Spanner::doComputeEndElement();
return;
}

// TODO: review this hack
// lyrics endTick should already indicate the segment we want
// except for TEMP_MELISMA_TICKS case
Lyrics* l = lyrics();
Fraction tick = (l->ticks() == Lyrics::TEMP_MELISMA_TICKS) ? l->tick() : l->endTick();
Segment* s = score()->tick2segment(tick, true, SegmentType::ChordRest);
if (!s) {
LOGD("%s no end segment for tick %d", typeName(), tick.ticks());
return;
}
voice_idx_t t = trackZeroVoice(track2());
// take the first chordrest we can find;
// linePos will substitute one in current voice if available
for (voice_idx_t v = 0; v < VOICES; ++v) {
setEndElement(s->element(t + v));
if (endElement()) {
break;
}
setEndElement(score()->findChordRestEndingBeforeTickInTrack(tick2(), track()));

if (!endElement()) {
setEndElement(score()->findChordRestEndingBeforeTickInStaff(tick2(), track2staff(track())));
}
return;
}

//=========================================================
Expand All @@ -191,4 +141,14 @@ LyricsLineSegment::LyricsLineSegment(LyricsLine* sp, System* parent)
{
setGenerated(true);
}

double LyricsLineSegment::baseLineShift() const
{
if (lyricsLine()->isEndMelisma()) {
return -0.5 * lyricsLine()->lineWidth();
}

Lyrics* lyrics = lyricsLine()->lyrics();
return -style().styleD(Sid::lyricsDashYposRatio) * lyrics->fontMetrics().xHeight();
}
}
2 changes: 1 addition & 1 deletion src/engraving/dom/ottava.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,6 @@ PointF Ottava::linePos(Grip grip, System** system) const

void Ottava::doComputeEndElement()
{
setEndElement(score()->findCRinStaff(tick2(), track2staff(track())));
setEndElement(score()->findChordRestEndingBeforeTickInStaff(tick2(), track2staff(track())));
}
}
24 changes: 23 additions & 1 deletion src/engraving/dom/score.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4503,7 +4503,7 @@ ChordRest* Score::findCR(Fraction tick, track_idx_t track) const
// find last chord/rest on staff that ends before tick
//---------------------------------------------------------

ChordRest* Score::findCRinStaff(const Fraction& tick, staff_idx_t staffIdx) const
ChordRest* Score::findChordRestEndingBeforeTickInStaff(const Fraction& tick, staff_idx_t staffIdx) const
{
Fraction ptick = tick - Fraction::fromTicks(1);
Measure* m = tick2measureMM(ptick);
Expand Down Expand Up @@ -4545,6 +4545,28 @@ ChordRest* Score::findCRinStaff(const Fraction& tick, staff_idx_t staffIdx) cons
return 0;
}

ChordRest* Score::findChordRestEndingBeforeTickInTrack(const Fraction& tick, track_idx_t trackIdx) const
{
Measure* measure = tick2measureMM(tick - Fraction::eps());
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you please explain why we need to subtract eps() here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because when tick falls exactly in-between two measures (meaning that one measure ends at tick and the next one starts at tick) tick2Measure returns the next one (which is what we want in 99% of cases). I'm subtracting eps() to make sure that I get the previous one in this case

if (!measure) {
LOGD("findCRinStaff: no measure for tick %d", tick.ticks());
return nullptr;
}

for (const Segment* segment = measure->last(); segment; segment = segment->prev()) {
EngravingItem* item = segment->elementAt(trackIdx);
if (!segment->isChordRestType() || !item) {
continue;
}
ChordRest* chordRest = toChordRest(item);
if (segment->tick() + chordRest->actualTicks() <= tick) {
return chordRest;
}
}

return nullptr;
}

//---------------------------------------------------------
// cmdNextPrevSystem
//---------------------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion src/engraving/dom/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,8 @@ class Score : public EngravingObject
Hairpin* addHairpin(HairpinType, ChordRest* cr1, ChordRest* cr2 = nullptr);

ChordRest* findCR(Fraction tick, track_idx_t track) const;
ChordRest* findCRinStaff(const Fraction& tick, staff_idx_t staffIdx) const;
ChordRest* findChordRestEndingBeforeTickInStaff(const Fraction& tick, staff_idx_t staffIdx) const;
ChordRest* findChordRestEndingBeforeTickInTrack(const Fraction& tick, track_idx_t trackIdx) const;
void insertTime(const Fraction& tickPos, const Fraction& tickLen);

std::shared_ptr<IEngravingFont> engravingFont() const { return m_engravingFont; }
Expand Down
24 changes: 24 additions & 0 deletions src/engraving/dom/textbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2306,6 +2306,30 @@ RectF TextBase::pageRectangle() const
return abbox();
}

void TextBase::computeHighResShape(const FontMetrics& fontMetrics)
{
Shape& highResShape = mutldata()->highResShape.mut_value();
highResShape.clear();
Copy link
Contributor

Choose a reason for hiding this comment

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

It's better to call clear() before reserve()

highResShape.elements().reserve(m_text.size());

for (const TextBlock& block : ldata()->blocks) {
double x = 0;
for (const TextFragment& fragment : block.fragments()) {
x += fragment.pos.x();
size_t textSize = fragment.text.size();
for (int i = 0; i < textSize; ++i) {
Char character = fragment.text.at(i);
RectF characterBoundingRect = fontMetrics.tightBoundingRect(fragment.text.at(i));
characterBoundingRect.translate(x, 0.0);
highResShape.add(characterBoundingRect);
if (i + 1 < textSize) {
x += fontMetrics.horizontalAdvance(character);
}
}
}
}
}

//---------------------------------------------------------
// dragTo
//---------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions src/engraving/dom/textbase.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,9 @@ class TextBase : public EngravingItem

RectF pageRectangle() const;

const Shape& highResShape() const { return ldata()->highResShape.value(); }
void computeHighResShape(const muse::draw::FontMetrics& fontMetrics);

void dragTo(EditData&);

std::vector<LineF> dragAnchorLines() const override;
Expand Down Expand Up @@ -459,6 +462,8 @@ class TextBase : public EngravingItem
size_t rows() const { return blocks.size(); }
const TextBlock& textBlock(size_t i) const { return blocks.at(i); }
TextBlock& textBlock(size_t i) { return blocks[i]; }

ld_field<Shape> highResShape = { "[TextBase] highResShape", Shape() };
};
DECLARE_LAYOUTDATA_METHODS(TextBase)

Expand Down
2 changes: 1 addition & 1 deletion src/engraving/dom/trill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,6 @@ String Trill::accessibleInfo() const

void Trill::doComputeEndElement()
{
setEndElement(score()->findCRinStaff(tick2(), track2staff(track2())));
setEndElement(score()->findChordRestEndingBeforeTickInStaff(tick2(), track2staff(track2())));
}
}
19 changes: 19 additions & 0 deletions src/engraving/infrastructure/shape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,25 @@ Shape Shape::scaled(const SizeF& mag) const
return s;
}

Shape& Shape::adjust(double xp1, double yp1, double xp2, double yp2)
{
for (ShapeElement& element : m_elements) {
element.adjust(xp1, yp1, xp2, yp2);
}
return *this;
}

Shape Shape::adjusted(double xp1, double yp1, double xp2, double yp2) const
{
Shape s;
s.m_elements.reserve(m_elements.size());
for (const ShapeElement& element : m_elements) {
s.add(element.adjusted(xp1, yp1, xp2, yp2));
}

return s;
}

void Shape::invalidateBBox()
{
m_bbox = RectF();
Expand Down
2 changes: 2 additions & 0 deletions src/engraving/infrastructure/shape.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ class Shape
Shape translated(const PointF&) const;
Shape& scale(const SizeF&);
Shape scaled(const SizeF&) const;
Shape& adjust(double xp1, double yp1, double xp2, double yp2);
Shape adjusted(double xp1, double yp1, double xp2, double yp2) const;

const RectF& bbox() const;
double minVerticalDistance(const Shape&) const;
Expand Down
Loading