Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #pragma once
24 :
25 : #include "../types/types.h"
26 : #include "line.h"
27 : #include "textbase.h"
28 :
29 : namespace mu::engraving {
30 : class Transaction;
31 :
32 : //---------------------------------------------------------
33 : // Lyrics
34 : //---------------------------------------------------------
35 :
36 : class LyricsLine;
37 :
38 : class Lyrics final : public TextBase
39 : {
40 6202 : OBJECT_ALLOCATOR(engraving, Lyrics)
41 1525 : DECLARE_CLASSOF(ElementType::LYRICS)
42 :
43 : public:
44 :
45 : // MELISMA FIRST UNDERSCORE:
46 : // used as_ticks value to mark a melisma for which only the first chord has been spanned so far
47 : // and to give the user a visible feedback that the underscore has been actually entered;
48 : // it should be cleared to 0 at some point, so that it will not be carried over
49 : // if the melisma is not extended beyond a single chord, but no suitable place to do this
50 : // has been identified yet.
51 : static constexpr Fraction TEMP_MELISMA_TICKS = Fraction::eps(); // THIS WAS A HORRIBLE HACK. At some point we must remove it and replace it with a proper solution. (M.S.)
52 :
53 : ~Lyrics();
54 :
55 1329 : Lyrics* clone() const override { return new Lyrics(*this); }
56 : bool acceptDrop(EditData&) const override;
57 : EngravingItem* drop(Transaction& tx, EditData&) override;
58 :
59 845 : Segment* segment() const { return toSegment(ownershipParent()->ownershipParent()); }
60 2 : Measure* measure() const { return toMeasure(ownershipParent()->ownershipParent()->ownershipParent()); }
61 11286 : ChordRest* chordRest() const { return toChordRest(ownershipParent()); }
62 :
63 1306 : int subtype() const override { return m_verse; }
64 : TranslatableString subtypeUserName() const override;
65 529 : void setVerse(int n) { m_verse = n; }
66 26143 : int verse() const { return m_verse; }
67 1258 : bool isEven() const { return m_verse % 2; }
68 574 : void setSyllabic(LyricsSyllabic s) { m_syllabic = s; }
69 20671 : LyricsSyllabic syllabic() const { return m_syllabic; }
70 : void add(EngravingItem*) override;
71 : void remove(EngravingItem*) override;
72 : bool isEditAllowed(EditData&) const override;
73 : void endEdit(EditData&) override;
74 :
75 4940 : bool positionRelativeToNoteheadRest() const override { return true; }
76 :
77 14088 : const Fraction& ticks() const { return m_ticks; }
78 63 : void setTicks(const Fraction& tick) { m_ticks = tick; }
79 : Fraction endTick() const;
80 : void removeFromScore();
81 :
82 : void adjustPrevious();
83 :
84 2180 : bool needRemoveInvalidSegments() const { return m_needRemoveInvalidSegments; }
85 : void setNeedRemoveInvalidSegments();
86 : void removeInvalidSegments();
87 :
88 31931 : LyricsLine* separator() const { return m_separator; }
89 243 : void setSeparator(LyricsLine* s) { m_separator = s; }
90 :
91 : bool isMelisma() const;
92 :
93 0 : bool allowTimeAnchor() const override { return false; }
94 :
95 : using EngravingObject::undoChangeProperty;
96 : void paste(const String& txt) override;
97 :
98 : PropertyValue getProperty(Pid propertyId) const override;
99 : bool setProperty(Pid propertyId, const PropertyValue&) override;
100 : PropertyValue propertyDefault(Pid id) const override;
101 : void undoChangeProperty(Pid id, const PropertyValue&, PropertyFlags ps) override;
102 : void reset() override;
103 : void triggerLayout() const override;
104 :
105 : double yRelativeToStaff() const;
106 : void setYRelativeToStaff(double y);
107 :
108 4780 : bool avoidBarlines() const { return m_avoidBarlines; }
109 : void setAvoidBarlines(bool v) { m_avoidBarlines = v; }
110 :
111 : private:
112 :
113 : friend class Factory;
114 : Lyrics(DummyParentOr<ChordRest> parent);
115 : Lyrics(const Lyrics&);
116 :
117 : int m_verse = 0; // row index
118 : Fraction m_ticks; // if > 0 then draw an underline to tick() + _ticks (melisma)
119 : LyricsSyllabic m_syllabic = LyricsSyllabic::SINGLE;
120 : LyricsLine* m_separator = nullptr;
121 : bool m_needRemoveInvalidSegments = false;
122 : bool m_avoidBarlines = true;
123 : };
124 :
125 : //---------------------------------------------------------
126 : // LyricsLine
127 : /// \cond PLUGIN_API \private \endcond
128 : //---------------------------------------------------------
129 :
130 : class LyricsLine : public SLine
131 : {
132 483 : OBJECT_ALLOCATOR(engraving, LyricsLine)
133 2553 : DECLARE_CLASSOF(ElementType::LYRICSLINE)
134 :
135 : public:
136 : LyricsLine(DummyParentOr<EngravingItem> parent);
137 : LyricsLine(const LyricsLine&);
138 :
139 0 : LyricsLine* clone() const override { return new LyricsLine(*this); }
140 :
141 752 : Anchor anchor() const override { return Anchor::SEGMENT; }
142 :
143 : LineSegment* createLineSegment() override;
144 : void removeUnmanaged() override;
145 :
146 19835 : virtual Lyrics* lyrics() const { return toLyrics(ownershipParent()); }
147 916 : Lyrics* nextLyrics() const { return m_nextLyrics; }
148 228 : void setNextLyrics(Lyrics* l) { m_nextLyrics = l; }
149 7203 : virtual bool isEndMelisma() const { return lyrics() && lyrics()->ticks().isNotZero(); }
150 328 : bool isDash() const { return !isEndMelisma(); }
151 :
152 : bool setProperty(Pid propertyId, const PropertyValue& v) override;
153 : PropertyValue propertyDefault(Pid id) const override;
154 : Sid getPropertyStyle(Pid) const override;
155 :
156 : protected:
157 11 : LyricsLine(const ElementType& type, DummyParentOr<EngravingItem> parent, ElementFlags = ElementFlag::NOTHING);
158 :
159 767 : bool isInSpannerMap() const override { return false; }
160 :
161 : Lyrics* m_nextLyrics = nullptr;
162 :
163 : void doComputeEndElement() override;
164 : };
165 :
166 : //---------------------------------------------------------
167 : // LyricsLineSegment
168 : /// \cond PLUGIN_API \private \endcond
169 : //---------------------------------------------------------
170 :
171 : class LyricsLineSegment : public LineSegment
172 : {
173 489 : OBJECT_ALLOCATOR(engraving, LyricsLineSegment)
174 : DECLARE_CLASSOF(ElementType::LYRICSLINE_SEGMENT)
175 :
176 : public:
177 : LyricsLineSegment(LyricsLine*);
178 :
179 0 : LyricsLineSegment* clone() const override { return new LyricsLineSegment(*this); }
180 :
181 4912 : LyricsLine* lyricsLine() const { return toLyricsLine(spanner()); }
182 2825 : virtual Lyrics* lyrics() const { return lyricsLine()->lyrics(); }
183 :
184 : virtual double baseLineShift() const;
185 :
186 665 : virtual int verse() const { return lyrics()->verse(); }
187 524 : virtual bool lyricsPlaceAbove() const { return lyrics()->placeAbove(); }
188 678 : virtual bool lyricsAddToSkyline() const { return lyrics()->addToSkyline(); }
189 339 : virtual double lineSpacing() const { return lyrics()->lineSpacing(); }
190 0 : Color color() const override { return lyrics()->color(); }
191 :
192 : PropertyValue getProperty(Pid propertyId) const override;
193 : bool setProperty(Pid propertyId, const PropertyValue&) override;
194 : PropertyValue propertyDefault(Pid propertyId) const override;
195 : EngravingObject* propertyDelegate(Pid propertyId) const override;
196 :
197 0 : bool allowTimeAnchor() const override { return false; }
198 :
199 0 : virtual bool isEditAllowed(EditData&) const override { return false; }
200 :
201 : struct LayoutData : public LineSegment::LayoutData {
202 : public:
203 0 : const std::vector<LineF>& dashes() const { return m_dashes; }
204 348 : void clearDashes() { m_dashes.clear(); }
205 365 : void addDash(const LineF& dash) { m_dashes.push_back(dash); }
206 : private:
207 : std::vector<LineF> m_dashes;
208 : };
209 1674 : DECLARE_LAYOUTDATA_METHODS(LyricsLineSegment)
210 :
211 : protected:
212 : LyricsLineSegment(const ElementType& type, LyricsLine* sp, ElementFlags f = ElementFlag::NOTHING);
213 : void rebaseAnchors(EditData&, Grip) override;
214 : };
215 :
216 : class PartialLyricsLine final : public LyricsLine
217 : {
218 20 : OBJECT_ALLOCATOR(engraving, PartialLyricsLine)
219 : DECLARE_CLASSOF(ElementType::PARTIAL_LYRICSLINE)
220 :
221 : public:
222 : PartialLyricsLine(DummyParentOr<EngravingItem> parent);
223 : PartialLyricsLine(const PartialLyricsLine&);
224 0 : PartialLyricsLine* clone() const override { return new PartialLyricsLine(*this); }
225 : LineSegment* createLineSegment() override;
226 :
227 15 : Lyrics* lyrics() const override { return nullptr; }
228 :
229 5 : void setIsEndMelisma(bool val) { m_isEndMelisma = val; }
230 60 : bool isEndMelisma() const override { return m_isEndMelisma; }
231 :
232 2 : void setVerse(int val) { m_verse = val; }
233 33 : int verse() const { return m_verse; }
234 :
235 4 : void setCenterBetweenStaves(AutoOnOff v) { m_centerBetweenStaves = v; }
236 9 : AutoOnOff centerBetweenStaves() const { return m_centerBetweenStaves; }
237 :
238 : PropertyValue getProperty(Pid propertyId) const override;
239 : bool setProperty(Pid propertyId, const PropertyValue&) override;
240 : PropertyValue propertyDefault(Pid propertyId) const override;
241 : Sid getPropertyStyle(Pid propertyId) const override;
242 : void undoChangeProperty(Pid id, const PropertyValue&, PropertyFlags ps) override;
243 : void reset() override;
244 :
245 : Lyrics* findLyricsInPreviousRepeatSeg() const;
246 : Lyrics* findAdjacentLyricsOrDefault() const;
247 :
248 : protected:
249 : void doComputeEndElement() override;
250 4 : bool isInSpannerMap() const override { return true; }
251 :
252 : private:
253 : bool m_isEndMelisma = false;
254 : int m_verse = 0;
255 : AutoOnOff m_centerBetweenStaves = AutoOnOff::AUTO;
256 : };
257 :
258 : class PartialLyricsLineSegment final : public LyricsLineSegment
259 : {
260 4 : OBJECT_ALLOCATOR(engraving, PartialLyricsLineSegment)
261 : DECLARE_CLASSOF(ElementType::PARTIAL_LYRICSLINE_SEGMENT)
262 :
263 : public:
264 : PartialLyricsLineSegment(PartialLyricsLine*);
265 :
266 0 : LyricsLineSegment* clone() const override { return new PartialLyricsLineSegment(*this); }
267 :
268 51 : PartialLyricsLine* lyricsLine() const { return toPartialLyricsLine(spanner()); }
269 0 : Lyrics* lyrics() const override { return nullptr; }
270 :
271 15 : int verse() const override { return lyricsLine()->verse(); }
272 : double lineSpacing() const override;
273 6 : bool lyricsPlaceAbove() const override { return lyricsLine()->placeAbove(); }// Delegate?
274 12 : bool lyricsAddToSkyline() const override { return lyricsLine()->addToSkyline(); }
275 0 : Color color() const override { return lyricsLine()->color(); }
276 : double baseLineShift() const override;
277 :
278 : EngravingObject* propertyDelegate(Pid) const override;
279 : };
280 : } // namespace mu::engraving
|