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 : #pragma once
23 :
24 : #include <vector>
25 :
26 : #include "chordlist.h"
27 : #include "parenthesis.h"
28 : #include "draw/types/font.h"
29 :
30 : #include "textbase.h"
31 : #include "score.h"
32 :
33 : #include "pitchspelling.h"
34 : #include "realizedharmony.h"
35 :
36 : namespace mu::engraving {
37 : struct ChordDescription;
38 : class ParsedChord;
39 : class Score;
40 : class Transaction;
41 :
42 : enum class HarmonyType : unsigned char {
43 : STANDARD,
44 : ROMAN,
45 : NASHVILLE
46 : };
47 :
48 : enum class HarmonyRenderItemType : unsigned char {
49 : TEXT,
50 : PAREN
51 : };
52 :
53 : struct HarmonyRenderItem {
54 10618 : virtual ~HarmonyRenderItem() = default;
55 10746 : HarmonyRenderItem(bool align, double _x, double _y)
56 10746 : : m_hAlign(align), m_pos(_x, _y) {}
57 :
58 18034 : PointF pos() const { return m_pos + m_offset; }
59 10842 : double x() const { return m_pos.x(); }
60 35530 : double y() const { return m_pos.y(); }
61 10802 : void movex(double v) { m_pos.rx() += v; }
62 30 : void movey(double v) { m_pos.ry() += v; }
63 32 : void setx(double v) { m_pos.rx() = v; }
64 64 : void sety(double v) { m_pos.ry() = v; }
65 10746 : void setOffset(const PointF& p) { m_offset = p; }
66 :
67 : virtual double height() const = 0;
68 :
69 10746 : bool align() const { return m_hAlign; }
70 :
71 : virtual RectF boundingRect() const = 0;
72 : virtual RectF tightBoundingRect() const = 0;
73 :
74 : virtual double leftPadding() const = 0;
75 : virtual double rightPadding() const = 0;
76 :
77 : virtual HarmonyRenderItemType type() const = 0;
78 :
79 : private:
80 : bool m_hAlign = true;
81 : PointF m_offset; // Offset for placing within the TextBase.
82 : PointF m_pos; // Position of segments relative to Harmony position
83 : };
84 :
85 : struct ChordSymbolParen : HarmonyRenderItem {
86 64 : ChordSymbolParen(Parenthesis* p, bool hAlign, double _x, double _y)
87 64 : : HarmonyRenderItem(hAlign, _x, _y), parenItem(p) {}
88 96 : ~ChordSymbolParen() { delete parenItem; }
89 :
90 0 : RectF boundingRect() const override { return parenItem->shape().bbox(); }
91 64 : RectF tightBoundingRect() const override { return parenItem->shape().bbox(); }
92 :
93 : double top = DBL_MAX;
94 : double bottom = -DBL_MAX;
95 : double closingParenPos = -DBL_MAX;
96 :
97 : Parenthesis* parenItem = nullptr;
98 :
99 128 : double height() const override { return parenItem->height(); }
100 :
101 64 : double leftPadding() const override { return parenItem->direction() == DirectionH::LEFT ? OUTER_PADDING : INNER_PADDING; }
102 32 : double rightPadding() const override { return parenItem->direction() == DirectionH::LEFT ? INNER_PADDING : OUTER_PADDING; }
103 :
104 96 : HarmonyRenderItemType type() const override { return HarmonyRenderItemType::PAREN; }
105 :
106 : private:
107 : static constexpr double INNER_PADDING = 0.05;
108 : static constexpr double OUTER_PADDING = 0.1;
109 : };
110 :
111 : //---------------------------------------------------------
112 : // TextSegment
113 : //---------------------------------------------------------
114 :
115 : struct TextSegment : HarmonyRenderItem {
116 : double width() const;
117 : double capHeight() const;
118 : RectF boundingRect() const override;
119 : RectF tightBoundingRect() const override;
120 :
121 10682 : void setText(const String& t) { m_text = t; }
122 89830 : String text() const { return m_text; }
123 :
124 96 : muse::draw::Font font() const { return m_font; }
125 : void setFont(const muse::draw::Font& f);
126 :
127 7122 : double leftPadding() const override { return 0.0; }
128 7154 : double rightPadding() const override { return 0.0; }
129 :
130 28518 : double height() const override { return tightBoundingRect().height(); }
131 :
132 14276 : HarmonyRenderItemType type() const override { return HarmonyRenderItemType::TEXT; }
133 :
134 10682 : TextSegment(const String& s, const muse::draw::Font& f, double _x, double _y, bool align)
135 10682 : : HarmonyRenderItem(align, _x, _y) { setText(s); setFont(f); }
136 :
137 : private:
138 : muse::draw::Font m_font;
139 : String m_text;
140 : };
141 :
142 : class HDegree;
143 :
144 : //---------------------------------------------------------
145 : // @@ HarmonyInfo
146 : // Contains all identifying information for a chord. The Harmony DOM class can have many of these
147 : // as polychords
148 : //
149 : // @P m_bassTpc int bass note as "tonal pitch class"
150 : // @P m_rootTpc int root note as "tonal pitch class"
151 : // @P m_id int harmony identifier
152 : // @P m_textName String plaintext representation of chord
153 : // @P m_parsedChord ParsedChord* parsed representation of the plaintext chord
154 : //---------------------------------------------------------
155 :
156 : class HarmonyInfo
157 : {
158 : public:
159 : HarmonyInfo(int id, int rootTpc, int bassTpc, String textName, ParsedChord* pc, Score* score)
160 : : m_id(id), m_rootTpc(rootTpc), m_bassTpc(bassTpc), m_textName(textName), m_parsedChord(pc), m_score(score) {}
161 1078 : HarmonyInfo(Score* score)
162 1078 : : m_score(score) {}
163 : HarmonyInfo(const HarmonyInfo& h);
164 : ~HarmonyInfo();
165 :
166 7621 : int id() const { return m_id; }
167 367 : void setId(int v) { m_id = v; }
168 :
169 9284 : int rootTpc() const { return m_rootTpc; }
170 1187 : void setRootTpc(int v) { m_rootTpc = v; }
171 :
172 6087 : int bassTpc() const { return m_bassTpc; }
173 416 : void setBassTpc(int v) { m_bassTpc = v; }
174 :
175 3291 : String textName() const { return m_textName; }
176 756 : void setTextName(const String& v) { m_textName = v; }
177 :
178 19012 : ChordList* chordList() const { return m_score ? m_score->chordList() : nullptr; }
179 :
180 : const ChordDescription* descr() const;
181 : const ChordDescription* descr(const String&, const ParsedChord* pc = 0) const;
182 : const ChordDescription* getDescription();
183 : const ChordDescription* getDescription(const String&, const ParsedChord* pc = 0);
184 : const ChordDescription* generateDescription();
185 :
186 150 : void setParsedChord(ParsedChord* v) { m_parsedChord = v; }
187 1300 : ParsedChord* parsedChord() const { return m_parsedChord; }
188 : ParsedChord* getParsedChord();
189 :
190 : bool hasModifiers() const;
191 :
192 : private:
193 : int m_id = -1; // >0 = id of matched chord from chord list, if applicable
194 : // -1 = invalid chord
195 : // <-10000 = private id of generated chord or matched chord with no id
196 : int m_rootTpc = Tpc::TPC_INVALID; // root note for chord
197 : int m_bassTpc = Tpc::TPC_INVALID; // bass note or chord bass; used for "slash" chords
198 : // or notation of bass note in chord
199 :
200 : String m_textName; // name recognized from chord list, read from score file, or constructed from imported source
201 : // Also stores the whole RNA string to be rendered
202 : ParsedChord* m_parsedChord = nullptr; // parsed form of chord
203 : Score* m_score = nullptr;
204 : };
205 :
206 : //---------------------------------------------------------
207 : // @@ Harmony
208 : // This DOM class represents the chord symbol in the score. It contains the necessary information to
209 : // layout standard chords and polychords
210 : //---------------------------------------------------------
211 :
212 : class Harmony final : public TextBase
213 : {
214 2201 : OBJECT_ALLOCATOR(engraving, Harmony)
215 33394 : DECLARE_CLASSOF(ElementType::HARMONY)
216 :
217 : public:
218 : Harmony(EngravingObject* parent = 0); // Segment or FretDiagram
219 : Harmony(const Harmony&);
220 : ~Harmony();
221 :
222 44 : Harmony* clone() const override { return new Harmony(*this); }
223 :
224 : int id() const; // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
225 :
226 0 : bool play() const { return m_play; }
227 :
228 3 : void setBassCase(NoteCaseType c) { m_bassCase = c; }
229 748 : NoteCaseType bassCase() const { return m_bassCase; }
230 3 : void setRootCase(NoteCaseType c) { m_rootCase = c; }
231 749 : NoteCaseType rootCase() const { return m_rootCase; }
232 :
233 : Segment* getParentSeg() const;
234 : FretDiagram* getParentFretDiagram() const;
235 : Harmony* findNext() const;
236 : Harmony* findPrev() const;
237 : Fraction ticksTillNext(int utick, bool stopAtMeasureEnd = false) const;
238 :
239 : RealizedHarmony& realizedHarmony();
240 : const RealizedHarmony& getRealizedHarmony() const;
241 :
242 0 : bool isEditable() const override { return !isInFretBox(); }
243 : void startEdit(EditData&) override;
244 : bool isEditAllowed(EditData&) const override;
245 : bool edit(EditData&) override;
246 : void endEdit(EditData&) override;
247 :
248 : bool isPlayable() const override;
249 :
250 : bool isRealizable() const;
251 : bool isInFretBox() const;
252 :
253 : int bassTpc() const; // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
254 : int rootTpc() const; // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
255 : void addDegree(const HDegree& d);
256 : const std::vector<HDegree>& degreeList() const;
257 21382 : HarmonyType harmonyType() const { return m_harmonyType; }
258 : void setHarmonyType(HarmonyType val);
259 :
260 : const ParsedChord* parsedForm() const; // WILL BE DEPRECATED AFTER RelaizedHarmony IS UPDATED
261 :
262 : void afterRead();
263 : void render();
264 :
265 3759 : bool isPolychord() const { return m_chords.size() > 1; }
266 17189 : const std::vector<HarmonyInfo*> chords() const { return m_chords; }
267 990 : void addChord(HarmonyInfo* info) { m_chords.push_back(info); }
268 :
269 : bool hasModifiers() const;
270 :
271 : String displayText() const;
272 : String harmonyName() const;
273 :
274 : double baseLine() const override;
275 : void spatiumChanged(double oldValue, double newValue) override;
276 : void localSpatiumChanged(double oldValue, double newValue) override;
277 : void setHarmony(const String& s);
278 :
279 542 : int subtype() const override { return static_cast<int>(harmonyType()); }
280 :
281 : TranslatableString typeUserName() const override;
282 : String accessibleInfo() const override;
283 : String generateScreenReaderInfo() const;
284 : String screenReaderInfo() const override;
285 :
286 : bool acceptDrop(EditData&) const override;
287 : EngravingItem* drop(Transaction& tx, EditData&) override;
288 :
289 : void undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps) override;
290 : using EngravingObject::undoChangeProperty;
291 : PropertyValue getProperty(Pid propertyId) const override;
292 : bool setProperty(Pid propertyId, const PropertyValue& v) override;
293 : PropertyValue propertyDefault(Pid id) const override;
294 :
295 : bool positionRelativeToNoteheadRest() const override;
296 :
297 : double mag() const override;
298 :
299 55 : double bassScale() const { return m_bassScale; }
300 1134 : void setBassScale(double v) { m_bassScale = v; }
301 :
302 : Color curColor(const rendering::PaintOptions& opt) const override;
303 : void setColor(const Color& color) override;
304 :
305 0 : bool doNotStackModifiers() const { return m_doNotStackModifiers; }
306 :
307 : NoteCaseType rootRenderCase(HarmonyInfo* info) const;
308 : NoteCaseType bassRenderCase() const;
309 :
310 81560 : FontStyle fontStyle() const override { return m_fontStyle; }
311 37381 : String family() const override { return m_fontFamily; }
312 24066 : double size() const override { return m_fontSize; }
313 :
314 1226 : void setFontStyle(const FontStyle& val) override { m_fontStyle = val; }
315 1226 : void setFamily(const String& val) override { m_fontFamily = val; }
316 1226 : void setSize(const double& val) override { m_fontSize = val; }
317 :
318 : struct LayoutData : public TextBase::LayoutData {
319 : ld_field<double> harmonyHeight = { "[Harmony] harmonyHeight", 0.0 }; // used for calculating the height is frame while editing.
320 : ld_field<std::vector<LineF> > polychordDividerLines = { "[Harmony] polychordDividerLine", std::vector<LineF>() };
321 : ld_field<double> polychordDividerOffset = { "[Harmony] polychordDividerOffset", 0.0 };
322 : ld_field<double> baseline = { "[Harmony] baseline", 0.0 };
323 : ld_field<std::vector<muse::draw::Font> > fontList = "[Harmony] fontList"; // temp values used in render()
324 : ld_field<std::vector<HarmonyRenderItem*> > renderItemList = "[Harmony] renderItemList"; // rendered chord
325 : };
326 32296 : DECLARE_LAYOUTDATA_METHODS(Harmony)
327 :
328 : private:
329 : std::vector<HarmonyInfo*> m_chords;
330 :
331 : const std::vector<const ChordDescription*> parseHarmony(const String& s, bool syntaxOnly = false);
332 : const ChordDescription* parseSingleHarmony(const String& s, HarmonyInfo* info, bool syntaxOnly = false);
333 :
334 : Sid getPropertyStyle(Pid) const override;
335 :
336 : Harmony* findInSeg(Segment* seg) const;
337 :
338 : bool m_isMisspelled = false; // show spell check warning
339 : HarmonyType m_harmonyType = HarmonyType::STANDARD; // used to control rendering, transposition, export, etc.
340 :
341 : mutable RealizedHarmony m_realizedHarmony; // the realized harmony used for playback
342 :
343 : std::vector<HDegree> m_degreeList;
344 :
345 : bool m_play = true; // whether or not to play back the harmony
346 : bool m_doNotStackModifiers = false;
347 :
348 : NoteCaseType m_rootCase = NoteCaseType::AUTO;
349 : NoteCaseType m_bassCase = NoteCaseType::AUTO; // case as typed
350 :
351 : double m_bassScale = 1.0;
352 :
353 : // Overridden textbase properties to apply to whole item
354 : double m_fontSize = 10.0;
355 : String m_fontFamily = u"";
356 : FontStyle m_fontStyle;
357 : };
358 : } // namespace mu::engraving
|