Skip to content

Commit ade96c4

Browse files
authored
Merge pull request #31429 from miiizen/31398-editLyricLines
Make lyric lines selectable and editable
2 parents ffaed61 + 2fa0deb commit ade96c4

36 files changed

+556
-106
lines changed

src/engraving/dom/factory.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ EngravingItem* Factory::doCreateItem(ElementType type, EngravingItem* parent)
222222
case ElementType::GUITAR_BEND: return new GuitarBend(parent->isNote() ? toNote(parent) : dummy->note());
223223
case ElementType::TREMOLOBAR: return new TremoloBar(parent);
224224
case ElementType::LYRICS: return new Lyrics(parent->isChordRest() ? toChordRest(parent) : dummy->chord());
225+
case ElementType::LYRICSLINE: return new LyricsLine(parent);
225226
case ElementType::FIGURED_BASS: return new FiguredBass(parent->isSegment() ? toSegment(parent) : dummy->segment());
226227
case ElementType::STEM: return new Stem(parent->isChord() ? toChord(parent) : dummy->chord());
227228
case ElementType::SLUR: return new Slur(parent);
@@ -247,7 +248,6 @@ EngravingItem* Factory::doCreateItem(ElementType type, EngravingItem* parent)
247248
case ElementType::PARTIAL_LYRICSLINE: return new PartialLyricsLine(parent);
248249
case ElementType::PARENTHESIS: return new Parenthesis(parent);
249250

250-
case ElementType::LYRICSLINE:
251251
case ElementType::TEXTLINE_BASE:
252252
case ElementType::TEXTLINE_SEGMENT:
253253
case ElementType::GLISSANDO_SEGMENT:
@@ -446,6 +446,9 @@ MAKE_ITEM_IMPL(LayoutBreak, MeasureBase)
446446
CREATE_ITEM_IMPL(Lyrics, ElementType::LYRICS, ChordRest, isAccessibleEnabled)
447447
COPY_ITEM_IMPL(Lyrics)
448448

449+
CREATE_ITEM_IMPL(LyricsLine, ElementType::LYRICSLINE, EngravingItem, isAccessibleEnabled)
450+
COPY_ITEM_IMPL(LyricsLine)
451+
449452
CREATE_ITEM_IMPL(Measure, ElementType::MEASURE, System, isAccessibleEnabled)
450453
COPY_ITEM_IMPL(Measure)
451454

src/engraving/dom/factory.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ class Factory
129129
static Lyrics* createLyrics(ChordRest* parent, bool isAccessibleEnabled = true);
130130
static Lyrics* copyLyrics(const Lyrics& src);
131131

132+
static LyricsLine* createLyricsLine(EngravingItem* parent, bool isAccessibleEnabled = true);
133+
static LyricsLine* copyLyricsLine(const LyricsLine& src);
134+
132135
static Measure* createMeasure(System* parent, bool isAccessibleEnabled = true);
133136
static Measure* copyMeasure(const Measure& src);
134137

src/engraving/dom/line.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -596,14 +596,6 @@ void LineSegment::rebaseAnchors(EditData& ed, Grip grip)
596596
return;
597597
}
598598

599-
if (isTrillSegment()) {
600-
EngravingItem* startElement = spanner()->startElement();
601-
if (startElement && startElement->isChord() && toChord(startElement)->staffMove() != 0) {
602-
// This trill is on a cross-staff chord. Don't try to rebase its anchors when dragging.
603-
return;
604-
}
605-
}
606-
607599
// don't change anchors on keyboard adjustment or if Ctrl is pressed
608600
// (Ctrl+Left/Right is handled elsewhere!)
609601
if (ed.key == Key_Left || ed.key == Key_Right || ed.key == Key_Up || ed.key == Key_Down || ed.modifiers & ControlModifier) {

src/engraving/dom/line.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ class LineSegment : public SpannerSegment
7979

8080
protected:
8181
virtual void rebaseOffsetsOnAnchorChanged(Grip grip, const PointF& oldPos, System* sys);
82+
virtual void rebaseAnchors(EditData&, Grip);
8283

8384
private:
8485
void undoMoveStartEndAndSnappedItems(EditData& ed, bool moveStart, bool moveEnd, Segment* s1, Segment* s2);
@@ -90,7 +91,6 @@ class LineSegment : public SpannerSegment
9091
static PointF deltaRebaseRight(const Segment* oldSeg, const Segment* newSeg);
9192
static Fraction lastSegmentEndTick(const Segment* lastSeg, const Spanner* s);
9293
LineSegment* rebaseAnchor(Grip grip, Segment* newSeg);
93-
void rebaseAnchors(EditData&, Grip);
9494
};
9595

9696
//---------------------------------------------------------

src/engraving/dom/lyrics.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,13 @@ TranslatableString Lyrics::subtypeUserName() const
9191

9292
void Lyrics::add(EngravingItem* el)
9393
{
94-
LOGD("Lyrics::add: unknown element %s", el->typeName());
94+
if (el->isLyricsLine()) {
95+
LyricsLine* separator = toLyricsLine(el);
96+
m_separator = separator;
97+
score()->addUnmanagedSpanner(separator);
98+
} else {
99+
LOGD("Lyrics::add: unknown element %s", el->typeName());
100+
}
95101
}
96102

97103
//---------------------------------------------------------
@@ -107,7 +113,6 @@ void Lyrics::remove(EngravingItem* el)
107113
// be sure each finds a clean context
108114
LyricsLine* separ = m_separator;
109115
m_separator = 0;
110-
separ->resetExplicitParent();
111116
separ->removeUnmanaged();
112117
}
113118
} else {

src/engraving/dom/lyrics.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,6 @@ class Lyrics final : public TextBase
104104
bool avoidBarlines() const { return m_avoidBarlines; }
105105
void setAvoidBarlines(bool v) { m_avoidBarlines = v; }
106106

107-
protected:
108-
109107
private:
110108

111109
friend class Factory;
@@ -140,14 +138,15 @@ class LyricsLine : public SLine
140138

141139
LineSegment* createLineSegment(System* parent) override;
142140
void removeUnmanaged() override;
143-
void styleChanged() override;
144141

145142
virtual Lyrics* lyrics() const { return toLyrics(explicitParent()); }
146143
Lyrics* nextLyrics() const { return m_nextLyrics; }
147144
void setNextLyrics(Lyrics* l) { m_nextLyrics = l; }
148145
virtual bool isEndMelisma() const { return lyrics() && lyrics()->ticks().isNotZero(); }
149146
bool isDash() const { return !isEndMelisma(); }
150147
bool setProperty(Pid propertyId, const PropertyValue& v) override;
148+
PropertyValue propertyDefault(Pid id) const override;
149+
Sid getPropertyStyle(Pid) const override;
151150

152151
protected:
153152
LyricsLine(const ElementType& type, EngravingItem* parent, ElementFlags = ElementFlag::NOTHING);
@@ -182,10 +181,15 @@ class LyricsLineSegment : public LineSegment
182181
virtual bool lyricsAddToSkyline() const { return lyrics()->addToSkyline(); }
183182
virtual double lineSpacing() const { return lyrics()->lineSpacing(); }
184183
Color color() const override { return lyrics()->color(); }
185-
int gripsCount() const override { return 0; }
186-
Grip initialEditModeGrip() const override { return Grip::NO_GRIP; }
187-
Grip defaultGrip() const override { return Grip::NO_GRIP; }
188-
bool needStartEditingAfterSelecting() const override { return false; }
184+
185+
PropertyValue getProperty(Pid propertyId) const override;
186+
bool setProperty(Pid propertyId, const PropertyValue&) override;
187+
PropertyValue propertyDefault(Pid propertyId) const override;
188+
EngravingObject* propertyDelegate(Pid propertyId) const override;
189+
190+
bool allowTimeAnchor() const override { return false; }
191+
192+
virtual bool isEditAllowed(EditData&) const override { return false; }
189193

190194
struct LayoutData : public LineSegment::LayoutData {
191195
public:
@@ -199,6 +203,7 @@ class LyricsLineSegment : public LineSegment
199203

200204
protected:
201205
LyricsLineSegment(const ElementType& type, LyricsLine* sp, System* parent, ElementFlags f = ElementFlag::NOTHING);
206+
void rebaseAnchors(EditData&, Grip) override;
202207
};
203208

204209
class PartialLyricsLine final : public LyricsLine

src/engraving/dom/lyricsline.cpp

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -40,24 +40,28 @@ namespace mu::engraving {
4040
// LyricsLine
4141
//---------------------------------------------------------
4242

43+
static const ElementStyle lyricsLineElementStyle {
44+
{ Sid::lyricsDashLineThickness, Pid::LINE_WIDTH }
45+
};
46+
4347
LyricsLine::LyricsLine(EngravingItem* parent)
44-
: SLine(ElementType::LYRICSLINE, parent, ElementFlag::NOT_SELECTABLE)
48+
: SLine(ElementType::LYRICSLINE, parent)
4549
{
46-
setGenerated(true); // no need to save it, as it can be re-generated
4750
setDiagonal(false);
48-
setLineWidth(style().styleS(Sid::lyricsDashLineThickness));
51+
initElementStyle(&lyricsLineElementStyle);
4952
setAnchor(Spanner::Anchor::SEGMENT);
5053
m_nextLyrics = 0;
54+
setGenerated(true); // no need to save it, as it can be re-generated
5155
}
5256

5357
LyricsLine::LyricsLine(const ElementType& type, EngravingItem* parent, ElementFlags f)
5458
: SLine(type, parent, f)
5559
{
56-
setGenerated(true); // no need to save it, as it can be re-generated
5760
setDiagonal(false);
58-
setLineWidth(style().styleS(Sid::lyricsDashLineThickness));
61+
initElementStyle(&lyricsLineElementStyle);
5962
setAnchor(Spanner::Anchor::SEGMENT);
6063
m_nextLyrics = 0;
64+
setGenerated(true); // no need to save it, as it can be re-generated
6165
}
6266

6367
LyricsLine::LyricsLine(const LyricsLine& g)
@@ -66,15 +70,6 @@ LyricsLine::LyricsLine(const LyricsLine& g)
6670
m_nextLyrics = 0;
6771
}
6872

69-
//---------------------------------------------------------
70-
// styleChanged
71-
//---------------------------------------------------------
72-
73-
void LyricsLine::styleChanged()
74-
{
75-
setLineWidth(style().styleS(Sid::lyricsDashLineThickness));
76-
}
77-
7873
//---------------------------------------------------------
7974
// createLineSegment
8075
//---------------------------------------------------------
@@ -128,6 +123,25 @@ bool LyricsLine::setProperty(Pid propertyId, const engraving::PropertyValue& v)
128123
return true;
129124
}
130125

126+
PropertyValue LyricsLine::propertyDefault(Pid id) const
127+
{
128+
switch (id) {
129+
case Pid::LINE_WIDTH:
130+
return styleValue(Pid::LINE_WIDTH, getPropertyStyle(Pid::LINE_WIDTH));
131+
default:
132+
return SLine::propertyDefault(id);
133+
}
134+
}
135+
136+
Sid LyricsLine::getPropertyStyle(Pid propertyId) const
137+
{
138+
if (propertyId == Pid::LINE_WIDTH) {
139+
return isEndMelisma() ? Sid::lyricsLineThickness : Sid::lyricsDashLineThickness;
140+
}
141+
142+
return SLine::getPropertyStyle(propertyId);
143+
}
144+
131145
void LyricsLine::doComputeEndElement()
132146
{
133147
if (!isEndMelisma()) {
@@ -146,8 +160,14 @@ void LyricsLine::doComputeEndElement()
146160
// LyricsLineSegment
147161
//=========================================================
148162

163+
void LyricsLineSegment::rebaseAnchors(EditData&, Grip)
164+
{
165+
// Don't rebase lyric line anchors on drag
166+
return;
167+
}
168+
149169
LyricsLineSegment::LyricsLineSegment(LyricsLine* sp, System* parent)
150-
: LineSegment(ElementType::LYRICSLINE_SEGMENT, sp, parent, ElementFlag::ON_STAFF | ElementFlag::NOT_SELECTABLE)
170+
: LineSegment(ElementType::LYRICSLINE_SEGMENT, sp, parent, ElementFlag::ON_STAFF)
151171
{
152172
setGenerated(true);
153173
}
@@ -168,6 +188,42 @@ double LyricsLineSegment::baseLineShift() const
168188
return -style().styleD(Sid::lyricsDashYposRatio) * segLyrics->fontMetrics().xHeight();
169189
}
170190

191+
PropertyValue LyricsLineSegment::getProperty(Pid propertyId) const
192+
{
193+
if (EngravingObject* delegate = propertyDelegate(propertyId)) {
194+
return delegate->getProperty(propertyId);
195+
}
196+
197+
return LineSegment::getProperty(propertyId);
198+
}
199+
200+
bool LyricsLineSegment::setProperty(Pid propertyId, const PropertyValue& val)
201+
{
202+
if (EngravingObject* delegate = propertyDelegate(propertyId)) {
203+
return delegate->setProperty(propertyId, val);
204+
}
205+
206+
return LineSegment::setProperty(propertyId, val);
207+
}
208+
209+
PropertyValue LyricsLineSegment::propertyDefault(Pid propertyId) const
210+
{
211+
if (EngravingObject* delegate = propertyDelegate(propertyId)) {
212+
return delegate->propertyDefault(propertyId);
213+
}
214+
215+
return LineSegment::propertyDefault(propertyId);
216+
}
217+
218+
EngravingObject* LyricsLineSegment::propertyDelegate(Pid propertyId) const
219+
{
220+
if (propertyId == Pid::GENERATED) {
221+
return lyricsLine();
222+
}
223+
224+
return LineSegment::propertyDelegate(propertyId);
225+
}
226+
171227
//=========================================================
172228
// PartialLyricsLine
173229
//=========================================================
@@ -251,7 +307,6 @@ void PartialLyricsLine::doComputeEndElement()
251307

252308
static const ElementStyle partialLyricsLineSegmentElementStyle {
253309
{ Sid::lyricsPlacement, Pid::PLACEMENT },
254-
{ Sid::lyricsPosBelow, Pid::OFFSET },
255310
{ Sid::lyricsMinTopDistance, Pid::MIN_DISTANCE },
256311
};
257312

src/engraving/dom/trill.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ void TrillSegment::symbolLine(SymId start, SymId fill, SymId end)
121121
setbbox(r);
122122
}
123123

124+
void TrillSegment::rebaseAnchors(EditData& ed, Grip grip)
125+
{
126+
EngravingItem* startElement = spanner()->startElement();
127+
if (startElement && startElement->isChord() && toChord(startElement)->staffMove() != 0) {
128+
// This trill is on a cross-staff chord. Don't try to rebase its anchors when dragging.
129+
return;
130+
}
131+
132+
LineSegment::rebaseAnchors(ed, grip);
133+
}
134+
124135
//---------------------------------------------------------
125136
// scanElements
126137
//---------------------------------------------------------

src/engraving/dom/trill.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ class TrillSegment final : public LineSegment
5858
void symbolLine(SymId start, SymId fill);
5959
void symbolLine(SymId start, SymId fill, SymId end);
6060

61+
protected:
62+
void rebaseAnchors(EditData& ed, Grip grip) override;
63+
6164
private:
6265
Sid getPropertyStyle(Pid) const override;
6366

src/engraving/dom/utils.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1866,4 +1866,33 @@ std::vector<EngravingItem*> filterTargetElements(const Selection& sel, Engraving
18661866
}
18671867
return result;
18681868
}
1869+
1870+
Lyrics* searchNextLyrics(Segment* s, staff_idx_t staffIdx, int verse, PlacementV p)
1871+
{
1872+
Lyrics* l = nullptr;
1873+
const Segment* originalSeg = s;
1874+
while ((s = s->next1(SegmentType::ChordRest))) {
1875+
if (!segmentsAreAdjacentInRepeatStructure(originalSeg, s)) {
1876+
return nullptr;
1877+
}
1878+
1879+
track_idx_t strack = staffIdx * VOICES;
1880+
track_idx_t etrack = strack + VOICES;
1881+
// search through all tracks of current staff looking for a lyric in specified verse
1882+
for (track_idx_t track = strack; track < etrack; ++track) {
1883+
ChordRest* cr = toChordRest(s->element(track));
1884+
if (cr) {
1885+
// cr with lyrics found, but does it have a syllable in specified verse?
1886+
l = cr->lyrics(verse, p);
1887+
if (l) {
1888+
break;
1889+
}
1890+
}
1891+
}
1892+
if (l) {
1893+
break;
1894+
}
1895+
}
1896+
return l;
1897+
}
18691898
}

0 commit comments

Comments
 (0)