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) 2023 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 : #include "capo.h"
24 :
25 : #include "score.h"
26 :
27 : #include "translation.h"
28 :
29 : using namespace mu::engraving;
30 :
31 : static const ElementStyle CAPO_STYLE {
32 : { Sid::staffTextPlacement, Pid::PLACEMENT },
33 : { Sid::staffTextMinDistance, Pid::MIN_DISTANCE },
34 : };
35 :
36 15 : Capo::Capo(DummyParentOr<Segment> parent, TextStyleType textStyleType)
37 15 : : StaffTextBase(ElementType::CAPO, parent, textStyleType, ElementFlag::MOVABLE | ElementFlag::ON_STAFF)
38 : {
39 15 : initElementStyle(&CAPO_STYLE);
40 :
41 15 : m_params.active = true;
42 15 : m_params.fretPosition = 1;
43 15 : }
44 :
45 0 : Capo* Capo::clone() const
46 : {
47 0 : return new Capo(*this);
48 : }
49 :
50 91 : PropertyValue Capo::getProperty(Pid id) const
51 : {
52 91 : if (id == Pid::ACTIVE) {
53 7 : return m_params.active;
54 84 : } else if (id == Pid::CAPO_FRET_POSITION) {
55 7 : return m_params.fretPosition;
56 77 : } else if (id == Pid::CAPO_IGNORED_STRINGS) {
57 0 : std::vector<int> ignoredStrings;
58 0 : ignoredStrings.reserve(m_params.ignoredStrings.size());
59 0 : for (string_idx_t string : m_params.ignoredStrings) {
60 0 : ignoredStrings.push_back(static_cast<int>(string));
61 : }
62 0 : return ignoredStrings;
63 77 : } else if (id == Pid::CAPO_GENERATE_TEXT) {
64 7 : return m_shouldAutomaticallyGenerateText;
65 70 : } else if (id == Pid::CAPO_TRANSPOSE_MODE) {
66 7 : return m_params.transposeMode;
67 : }
68 :
69 63 : return StaffTextBase::getProperty(id);
70 : }
71 :
72 91 : PropertyValue Capo::propertyDefault(Pid id) const
73 : {
74 91 : if (id == Pid::ACTIVE) {
75 7 : return true;
76 84 : } else if (id == Pid::CAPO_FRET_POSITION) {
77 7 : return 1;
78 77 : } else if (id == Pid::CAPO_IGNORED_STRINGS) {
79 0 : return std::vector<int>();
80 77 : } else if (id == Pid::CAPO_GENERATE_TEXT) {
81 7 : return true;
82 70 : } else if (id == Pid::CAPO_TRANSPOSE_MODE) {
83 14 : return CapoParams::TransposeMode::PLAYBACK_ONLY;
84 : }
85 :
86 63 : return StaffTextBase::propertyDefault(id);
87 : }
88 :
89 409 : bool Capo::setProperty(Pid id, const PropertyValue& val)
90 : {
91 409 : if (id == Pid::ACTIVE) {
92 0 : m_params.active = val.toBool();
93 409 : } else if (id == Pid::CAPO_FRET_POSITION) {
94 0 : m_params.fretPosition = val.toInt();
95 409 : } else if (id == Pid::CAPO_IGNORED_STRINGS) {
96 0 : m_params.ignoredStrings.clear();
97 0 : auto ignoredStrings = val.value<std::vector<int> >();
98 0 : for (int string : ignoredStrings) {
99 0 : m_params.ignoredStrings.insert(static_cast<string_idx_t>(string));
100 : }
101 409 : } else if (id == Pid::CAPO_GENERATE_TEXT) {
102 0 : m_shouldAutomaticallyGenerateText = val.toBool();
103 :
104 0 : if (!m_shouldAutomaticallyGenerateText) {
105 0 : setXmlText(m_customText);
106 : }
107 409 : } else if (id == Pid::CAPO_TRANSPOSE_MODE) {
108 3 : m_params.transposeMode = val.value<CapoParams::TransposeMode>();
109 : } else {
110 406 : return StaffTextBase::setProperty(id, val);
111 : }
112 :
113 3 : triggerLayout();
114 :
115 3 : if (Score* s = score()) {
116 3 : s->updateCapo();
117 : }
118 :
119 3 : return true;
120 : }
121 :
122 52 : void Capo::setXmlText(const String& text)
123 : {
124 52 : if (!m_shouldAutomaticallyGenerateText) {
125 0 : m_customText = text;
126 : }
127 :
128 52 : StaffTextBase::setXmlText(text);
129 52 : }
130 :
131 0 : bool Capo::isEditable() const
132 : {
133 0 : return false;
134 : }
135 :
136 47 : const CapoParams& Capo::params() const
137 : {
138 47 : return m_params;
139 : }
140 :
141 15 : void Capo::setParams(const CapoParams& params)
142 : {
143 15 : m_params = params;
144 15 : }
145 :
146 44 : bool Capo::shouldAutomaticallyGenerateText() const
147 : {
148 44 : return m_shouldAutomaticallyGenerateText;
149 : }
150 :
151 44 : muse::String Capo::generateText(size_t stringCount) const
152 : {
153 44 : if (!m_params.active || m_params.fretPosition == 0) {
154 0 : return muse::mtrc("engraving", "No capo");
155 : }
156 :
157 44 : if (m_params.ignoredStrings.empty()) {
158 44 : return muse::mtrc("engraving", "Capo %1").arg(m_params.fretPosition);
159 : }
160 :
161 0 : StringList stringsToApply;
162 :
163 0 : for (string_idx_t idx = 0; idx < stringCount; ++idx) {
164 0 : if (muse::contains(m_params.ignoredStrings, idx)) {
165 0 : continue;
166 : }
167 :
168 0 : stringsToApply.emplace_back(String::number(idx + 1));
169 : }
170 :
171 0 : if (stringsToApply.empty()) {
172 0 : return muse::mtrc("engraving", "No capo");
173 : }
174 :
175 0 : String text = muse::mtrc("engraving", "Partial capo:\nFret %1 on strings %2")
176 0 : .arg(m_params.fretPosition)
177 0 : .arg(stringsToApply.join(u", "));
178 :
179 0 : return text;
180 0 : }
181 :
182 15 : void Capo::added()
183 : {
184 15 : StaffTextBase::added();
185 :
186 15 : if (Score* s = score()) {
187 15 : s->updateCapo();
188 : }
189 15 : }
190 :
191 0 : void Capo::removed()
192 : {
193 0 : StaffTextBase::removed();
194 :
195 0 : if (Score* s = score()) {
196 0 : s->updateCapo();
197 : }
198 0 : }
|