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) 2026 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 : #include "notationcommandsstate.h"
23 :
24 : #include "global/containers.h"
25 :
26 : #include "../notationcommands.h"
27 : #include "rcommand/commandtypes.h"
28 :
29 : using namespace muse;
30 : using namespace muse::rcommand;
31 : using namespace mu::notation;
32 : using namespace mu::engraving;
33 :
34 : static const muse::Uri PROJECT_PAGE_URI("musescore://notation");
35 :
36 : template<typename Map>
37 0 : static inline auto commands(const Map& m) -> std::vector<typename Map::key_type>
38 : {
39 0 : std::vector<typename Map::key_type> result;
40 0 : result.reserve(m.size());
41 0 : for (const auto& p : m) {
42 0 : result.push_back(p.first);
43 : }
44 0 : return result;
45 0 : }
46 :
47 : static const std::vector<Command> HAS_SELECTION_REQUIRED_COMMANDS = {
48 : CUT_COMMAND,
49 : COPY_COMMAND,
50 : COPY_PASTE_SWAP_COMMAND,
51 : DELETE_COMMAND,
52 : FlipCommand::id,
53 : FLIP_HORIZONTALLY_COMMAND,
54 : GOTO_NEXT_SEGMENT_ELEMENT_COMMAND,
55 : GOTO_PREV_SEGMENT_ELEMENT_COMMAND,
56 : GOTO_UPNOTE_IN_CHORD_COMMAND,
57 : GOTO_DOWNNOTE_IN_CHORD_COMMAND,
58 : GOTO_TOPNOTE_IN_CHORD_COMMAND,
59 : GOTO_BOTTOMNOTE_IN_CHORD_COMMAND,
60 : SELECT_SIMILAR_COMMAND,
61 : SELECT_SIMILAR_IN_STAFF_COMMAND,
62 : SELECT_SIMILAR_IN_RANGE_COMMAND,
63 : SELECT_NOTES_IN_CHORD_COMMAND,
64 : OPEN_SELECTION_OPTIONS_COMMAND,
65 : SET_DOUBLE_DURATION_COMMAND,
66 : SET_HALVE_DURATION_COMMAND,
67 : SET_DOUBLE_DURATION_DOTTED_COMMAND,
68 : SET_HALVE_DURATION_DOTTED_COMMAND,
69 : TOGGLE_SNAP_TO_PREV_COMMAND,
70 : TOGGLE_SNAP_TO_NEXT_COMMAND,
71 : MIRROR_NOTEHEAD_COMMAND,
72 : MOVE_UP_COMMAND,
73 : MOVE_DOWN_COMMAND,
74 : INCREASE_DYNAMIC_COMMAND,
75 : DECREASE_DYNAMIC_COMMAND
76 : };
77 :
78 : static const std::vector<Command> UNDO_REDO_COMMANDS = {
79 : UNDO_COMMAND,
80 : REDO_COMMAND
81 : };
82 :
83 : static const std::vector<Command> TEXT_EDITING_COMMANDS = {
84 : EDITTEXT_TOGGLE_BOLD_COMMAND,
85 : EDITTEXT_TOGGLE_ITALIC_COMMAND,
86 : EDITTEXT_TOGGLE_UNDERLINE_COMMAND,
87 : EDITTEXT_TOGGLE_STRIKE_COMMAND,
88 : EDITTEXT_TOGGLE_SUBSCRIPT_COMMAND,
89 : EDITTEXT_TOGGLE_SUPERSCRIPT_COMMAND,
90 : EDITTEXT_NEXT_ELEMENT_COMMAND,
91 : EDITTEXT_PREV_ELEMENT_COMMAND,
92 : EDITTEXT_NEXT_WORD_COMMAND,
93 : EDITTEXT_NEXT_BEAT_COMMAND,
94 : EDITTEXT_PREV_BEAT_COMMAND,
95 : EDITTEXT_ADVANCE_LONGA_COMMAND,
96 : EDITTEXT_ADVANCE_BREVE_COMMAND,
97 : EDITTEXT_ADVANCE_1_COMMAND,
98 : EDITTEXT_ADVANCE_2_COMMAND,
99 : EDITTEXT_ADVANCE_4_COMMAND,
100 : EDITTEXT_ADVANCE_8_COMMAND,
101 : EDITTEXT_ADVANCE_16_COMMAND,
102 : EDITTEXT_ADVANCE_32_COMMAND,
103 : EDITTEXT_ADVANCE_64_COMMAND,
104 : };
105 :
106 : static const std::vector<Command> LYRICS_EDITING_COMMANDS = {
107 : EDITLYRIC_NEXT_VERSE_COMMAND,
108 : EDITLYRIC_PREV_VERSE_COMMAND,
109 : EDITLYRIC_NEXT_SYLLABLE_COMMAND,
110 : EDITLYRIC_ADD_MELISMA_COMMAND,
111 : EDITLYRIC_ADD_VERSE_COMMAND
112 : };
113 :
114 : static const std::vector<Command> NOT_TEXT_EDITING_COMMANDS = {
115 : TOGGLE_MMREST_COMMAND,
116 : };
117 :
118 : static const std::map<Command, NoteInputMethod> NOTE_INPUT_COMMANDS = {
119 : { TOGGLE_NOTE_INPUT_COMMAND, NoteInputMethod::UNKNOWN },
120 : { TOGGLE_NOTE_INPUT_BY_NOTE_NAME_COMMAND, NoteInputMethod::BY_NOTE_NAME },
121 : { TOGGLE_NOTE_INPUT_BY_DURATION_COMMAND, NoteInputMethod::BY_DURATION },
122 : { TOGGLE_NOTE_INPUT_RHYTHM_COMMAND, NoteInputMethod::RHYTHM },
123 : { TOGGLE_NOTE_INPUT_REPITCH_COMMAND, NoteInputMethod::REPITCH },
124 : { TOGGLE_NOTE_INPUT_REALTIME_AUTO_COMMAND, NoteInputMethod::REALTIME_AUTO },
125 : { TOGGLE_NOTE_INPUT_REALTIME_MANUAL_COMMAND, NoteInputMethod::REALTIME_MANUAL },
126 : { TOGGLE_NOTE_INPUT_TIMEWISE_COMMAND, NoteInputMethod::TIMEWISE }
127 : };
128 :
129 : static const std::map<Command, DurationType> DURATION_COMMANDS = {
130 : { SET_DURATION_LONGA_COMMAND, DurationType::V_LONG },
131 : { SET_DURATION_BREVE_COMMAND, DurationType::V_BREVE },
132 : { SET_DURATION_WHOLE_COMMAND, DurationType::V_WHOLE },
133 : { SET_DURATION_HALF_COMMAND, DurationType::V_HALF },
134 : { SET_DURATION_QUARTER_COMMAND, DurationType::V_QUARTER },
135 : { SET_DURATION_EIGHTH_COMMAND, DurationType::V_EIGHTH },
136 : { SET_DURATION_16TH_COMMAND, DurationType::V_16TH },
137 : { SET_DURATION_32ND_COMMAND, DurationType::V_32ND },
138 : { SET_DURATION_64TH_COMMAND, DurationType::V_64TH },
139 : { SET_DURATION_128TH_COMMAND, DurationType::V_128TH },
140 : { SET_DURATION_256TH_COMMAND, DurationType::V_256TH },
141 : { SET_DURATION_512TH_COMMAND, DurationType::V_512TH },
142 : { SET_DURATION_1024TH_COMMAND, DurationType::V_1024TH }
143 : };
144 :
145 : static const std::map<Command, int> DOT_COUNT_COMMANDS = {
146 : { TOGGLE_DOT_COMMAND, 1 },
147 : { TOGGLE_DOT2_COMMAND, 2 },
148 : { TOGGLE_DOT3_COMMAND, 3 },
149 : { TOGGLE_DOT4_COMMAND, 4 }
150 : };
151 :
152 : static const std::map<Command, AccidentalType> ACCIDENTAL_COMMANDS = {
153 : { TOGGLE_FLAT2_COMMAND, AccidentalType::FLAT2 },
154 : { TOGGLE_FLAT_COMMAND, AccidentalType::FLAT },
155 : { TOGGLE_NAT_COMMAND, AccidentalType::NATURAL },
156 : { TOGGLE_SHARP_COMMAND, AccidentalType::SHARP },
157 : { TOGGLE_SHARP2_COMMAND, AccidentalType::SHARP2 }
158 : };
159 :
160 : static const std::vector<Command> ADD_COMMANDS = {
161 : TOGGLE_TIE_COMMAND,
162 : ADD_SLUR_COMMAND,
163 : TOGGLE_LV_COMMAND
164 : };
165 :
166 : static const std::map<Command, SymId> ADD_ARTICULATION_COMMANDS = {
167 : { TOGGLE_MARCATO_COMMAND, SymId::articMarcatoAbove },
168 : { TOGGLE_SFORZATO_COMMAND, SymId::articAccentAbove },
169 : { TOGGLE_TENUTO_COMMAND, SymId::articTenutoAbove },
170 : { TOGGLE_STACCATO_COMMAND, SymId::articStaccatoAbove }
171 : };
172 :
173 : static const std::map<Command, voice_idx_t> VOICE_COMMANDS = {
174 : { USE_VOICE_1_COMMAND, 0 },
175 : { USE_VOICE_2_COMMAND, 1 },
176 : { USE_VOICE_3_COMMAND, 2 },
177 : { USE_VOICE_4_COMMAND, 3 }
178 : };
179 :
180 : static const std::vector<Command> NOTE_COMMANDS = {
181 : AddNoteCommand::id,
182 : ENTER_NOTE_C_COMMAND,
183 : ENTER_NOTE_D_COMMAND,
184 : ENTER_NOTE_E_COMMAND,
185 : ENTER_NOTE_F_COMMAND,
186 : ENTER_NOTE_G_COMMAND,
187 : ENTER_NOTE_A_COMMAND,
188 : ENTER_NOTE_B_COMMAND,
189 : ENTER_REST_COMMAND,
190 : ADD_NOTE_C_COMMAND,
191 : ADD_NOTE_D_COMMAND,
192 : ADD_NOTE_E_COMMAND,
193 : ADD_NOTE_F_COMMAND,
194 : ADD_NOTE_G_COMMAND,
195 : ADD_NOTE_A_COMMAND,
196 : ADD_NOTE_B_COMMAND,
197 : INSERT_NOTE_C_COMMAND,
198 : INSERT_NOTE_D_COMMAND,
199 : INSERT_NOTE_E_COMMAND,
200 : INSERT_NOTE_F_COMMAND,
201 : INSERT_NOTE_G_COMMAND,
202 : INSERT_NOTE_A_COMMAND,
203 : INSERT_NOTE_B_COMMAND
204 : };
205 :
206 : static const std::vector<Command> NOTE_OR_REST_SELECTED_COMMANDS = {
207 : OPEN_TUPLET_CONFIGURE_COMMAND,
208 : ADD_TUPLET_COMMAND,
209 : ADD_DUPLET_COMMAND,
210 : ADD_TRIPLET_COMMAND,
211 : ADD_QUADRUPLET_COMMAND,
212 : ADD_QUINTUPLET_COMMAND,
213 : ADD_SEXTUPLET_COMMAND,
214 : ADD_SEPTUPLET_COMMAND,
215 : ADD_OCTUPLET_COMMAND,
216 : ADD_NONUPLET_COMMAND,
217 : ADD_DYNAMIC_COMMAND,
218 : ADD_HAIRPIN_COMMAND,
219 : ADD_HAIRPIN_REVERSE_COMMAND
220 : };
221 :
222 : static const std::map<Command, MoveSelectionType> MOVE_SELECTION_COMMANDS = {
223 : { GOTO_FIRST_ELEMENT_COMMAND, MoveSelectionType::EngravingItem },
224 : { GOTO_LAST_ELEMENT_COMMAND, MoveSelectionType::EngravingItem },
225 : { GOTO_NEXT_ELEMENT_COMMAND, MoveSelectionType::EngravingItem },
226 : { GOTO_PREV_ELEMENT_COMMAND, MoveSelectionType::EngravingItem },
227 : { GOTO_NEXT_TRACK_COMMAND, MoveSelectionType::Track },
228 : { GOTO_PREV_TRACK_COMMAND, MoveSelectionType::Track },
229 : { GOTO_NEXT_FRAME_COMMAND, MoveSelectionType::Frame },
230 : { GOTO_PREV_FRAME_COMMAND, MoveSelectionType::Frame },
231 : { GOTO_NEXT_SYSTEM_COMMAND, MoveSelectionType::System },
232 : { GOTO_PREV_SYSTEM_COMMAND, MoveSelectionType::System }
233 : };
234 :
235 : static const std::vector<Command> LAYOUT_BREAK_COMMANDS = {
236 : TOGGLE_SYSTEM_BREAK_COMMAND,
237 : TOGGLE_PAGE_BREAK_COMMAND,
238 : TOGGLE_SECTION_BREAK_COMMAND
239 : };
240 :
241 : static const std::map<Command, ScoreConfigType> SCORE_CONFIG_COMMANDS = {
242 : { SHOW_INVISIBLE_COMMAND, ScoreConfigType::ShowInvisibleElements },
243 : { SHOW_UNPRINTABLE_COMMAND, ScoreConfigType::ShowUnprintableElements },
244 : { SHOW_FRAMES_COMMAND, ScoreConfigType::ShowFrames },
245 : { SHOW_PAGEBORDERS_COMMAND, ScoreConfigType::ShowPageMargins },
246 : { SHOW_SOUNDFLAGS_COMMAND, ScoreConfigType::ShowSoundFlags },
247 : { SHOW_IRREGULAR_COMMAND, ScoreConfigType::MarkIrregularMeasures }
248 : };
249 :
250 : static const std::vector<Command> STYLE_COMMANDS = {
251 : TOGGLE_CONCERT_PITCH_COMMAND
252 : };
253 :
254 : static const std::vector<Command> TAB_COMMANDS = {
255 : SET_DURATION_WHOLE_TAB_COMMAND,
256 : SET_DURATION_HALF_TAB_COMMAND,
257 : SET_DURATION_QUARTER_TAB_COMMAND,
258 : SET_DURATION_EIGHTH_TAB_COMMAND,
259 : SET_DURATION_16TH_TAB_COMMAND,
260 : SET_DURATION_32ND_TAB_COMMAND,
261 : SET_DURATION_64TH_TAB_COMMAND,
262 : SET_DURATION_128TH_TAB_COMMAND,
263 : SET_DURATION_256TH_TAB_COMMAND,
264 : SET_DURATION_512TH_TAB_COMMAND,
265 : SET_DURATION_1024TH_TAB_COMMAND,
266 : ENTER_REST_TAB_COMMAND,
267 : ENTER_FRET_0_COMMAND,
268 : ENTER_FRET_1_COMMAND,
269 : ENTER_FRET_2_COMMAND,
270 : ENTER_FRET_3_COMMAND,
271 : ENTER_FRET_4_COMMAND,
272 : ENTER_FRET_5_COMMAND,
273 : ENTER_FRET_6_COMMAND,
274 : ENTER_FRET_7_COMMAND,
275 : ENTER_FRET_8_COMMAND,
276 : ENTER_FRET_9_COMMAND,
277 : ENTER_FRET_10_COMMAND,
278 : ENTER_FRET_11_COMMAND,
279 : ENTER_FRET_12_COMMAND,
280 : ENTER_FRET_13_COMMAND,
281 : ENTER_FRET_14_COMMAND,
282 : GOTO_STRING_ABOVE_COMMAND,
283 : GOTO_STRING_BELOW_COMMAND
284 : };
285 :
286 : static const std::vector<Command> DEBUG_COMMANDS = {
287 : SHOW_ELEMENT_BOUNDING_RECTS_COMMAND,
288 : COLOR_ELEMENT_SHAPES_COMMAND,
289 : SHOW_SEGMENT_SHAPES_COMMAND,
290 : COLOR_SEGMENT_SHAPES_COMMAND,
291 : SHOW_SKYLINES_COMMAND,
292 : SHOW_SYSTEM_BOUNDING_RECTS_COMMAND,
293 : SHOW_ELEMENT_MASKS_COMMAND,
294 : SHOW_LINE_ATTACH_POINTS_COMMAND,
295 : MARK_EMPTY_STAFF_COMMAND,
296 : MARK_CORRUPTED_MEASURES_COMMAND,
297 : SHOW_GAP_RESTS_COMMAND,
298 : SHOW_ORIGIN_AND_COMBINED_COMMAND,
299 : };
300 :
301 0 : std::string NotationCommandsState::moduleName() const
302 : {
303 0 : return "notation";
304 : }
305 :
306 0 : void NotationCommandsState::init()
307 : {
308 0 : m_moduleRegister = commandsRegister()->moduleRegister(moduleName());
309 0 : IF_ASSERT_FAILED(m_moduleRegister) {
310 0 : return;
311 : }
312 :
313 0 : projectSession()->projectChanged().onNotify(this, [this]() {
314 0 : updateCommandStates();
315 0 : });
316 :
317 0 : if (interactive()) {
318 0 : interactive()->opened().onReceive(this, [this](const muse::Uri&) {
319 0 : updateCommandStates();
320 0 : });
321 : }
322 :
323 0 : controller()->selectionChanged().onNotify(this, [this]() {
324 0 : updateCommandStates(HAS_SELECTION_REQUIRED_COMMANDS);
325 0 : updateCommandStates(ADD_COMMANDS);
326 0 : updateCommandStates({ TOGGLE_REST_COMMAND });
327 0 : updateCommandStates(commands(VOICE_COMMANDS));
328 0 : updateCommandStates(NOTE_OR_REST_SELECTED_COMMANDS);
329 0 : updateCommandStates(commands(MOVE_SELECTION_COMMANDS));
330 0 : updateCommandStates(LAYOUT_BREAK_COMMANDS);
331 0 : updateCommandStates(TAB_COMMANDS);
332 0 : });
333 :
334 0 : controller()->stackChanged().onNotify(this, [this]() {
335 0 : updateCommandStates(UNDO_REDO_COMMANDS);
336 0 : });
337 :
338 0 : controller()->textEditingChanged().onReceive(this, [this](bool) {
339 0 : updateCommandStates(TEXT_EDITING_COMMANDS);
340 0 : updateCommandStates(LYRICS_EDITING_COMMANDS);
341 0 : updateCommandStates(LAYOUT_BREAK_COMMANDS);
342 0 : updateCommandStates(NOT_TEXT_EDITING_COMMANDS);
343 0 : });
344 :
345 0 : controller()->isNoteInputAllowedChanged().onReceive(this, [this](bool) {
346 0 : updateCommandStates(commands(NOTE_INPUT_COMMANDS));
347 0 : });
348 :
349 0 : controller()->noteInputStateChanged().onNotify(this, [this]() {
350 0 : updateCommandStates(commands(NOTE_INPUT_COMMANDS));
351 0 : updateCommandStates(commands(DURATION_COMMANDS));
352 0 : updateCommandStates(commands(DOT_COUNT_COMMANDS));
353 0 : updateCommandStates({ TOGGLE_REST_COMMAND });
354 0 : updateCommandStates(commands(ACCIDENTAL_COMMANDS));
355 0 : updateCommandStates({ REALTIME_ADVANCE_COMMAND });
356 0 : updateCommandStates(ADD_COMMANDS);
357 0 : updateCommandStates(commands(ADD_ARTICULATION_COMMANDS));
358 0 : updateCommandStates(commands(VOICE_COMMANDS));
359 0 : updateCommandStates(NOTE_COMMANDS);
360 0 : updateCommandStates(NOTE_OR_REST_SELECTED_COMMANDS);
361 0 : updateCommandStates(TAB_COMMANDS);
362 0 : });
363 :
364 0 : controller()->scoreConfigChanged().onReceive(this, [this](ScoreConfigType configType) {
365 0 : updateCommandStates({ muse::key(SCORE_CONFIG_COMMANDS, configType) });
366 0 : });
367 :
368 0 : controller()->notationStyleChanged().onNotify(this, [this]() {
369 0 : updateCommandStates(STYLE_COMMANDS);
370 0 : });
371 :
372 0 : controller()->automationModeEnabledChanged().onNotify(this, [this]() {
373 0 : updateCommandStates({ TOGGLE_AUTOMATION_COMMAND });
374 0 : });
375 :
376 0 : controller()->debuggingOptionsChanged().onNotify(this, [this]() {
377 0 : updateCommandStates(DEBUG_COMMANDS);
378 0 : });
379 :
380 0 : updateCommandStates();
381 : }
382 :
383 0 : void NotationCommandsState::deinit()
384 : {
385 0 : projectSession()->projectChanged().disconnect(this);
386 0 : if (interactive()) {
387 0 : interactive()->opened().disconnect(this);
388 : }
389 0 : controller()->selectionChanged().disconnect(this);
390 0 : controller()->stackChanged().disconnect(this);
391 0 : controller()->textEditingChanged().disconnect(this);
392 0 : controller()->isNoteInputAllowedChanged().disconnect(this);
393 0 : controller()->noteInputStateChanged().disconnect(this);
394 0 : controller()->scoreConfigChanged().disconnect(this);
395 0 : controller()->notationStyleChanged().disconnect(this);
396 0 : controller()->automationModeEnabledChanged().disconnect(this);
397 0 : controller()->debuggingOptionsChanged().disconnect(this);
398 0 : }
399 :
400 0 : void NotationCommandsState::updateCommandStates(const std::vector<Command>& commands)
401 : {
402 0 : IF_ASSERT_FAILED(m_moduleRegister) {
403 0 : return;
404 : }
405 :
406 0 : const auto& commandList = commands.empty() ? m_moduleRegister->commandList() : commands;
407 :
408 0 : for (const auto& command : commandList) {
409 0 : CommandState newState = commandState(command);
410 0 : if (m_commandStates[command] != newState) {
411 0 : m_commandStates[command] = newState;
412 0 : m_commandStateChanged.send(command, newState);
413 : }
414 : }
415 : }
416 :
417 0 : CommandState NotationCommandsState::doCommandState(const Command& command) const
418 : {
419 0 : if (!isProjectOpened()) {
420 0 : return CommandState(false, false);
421 : }
422 :
423 0 : if (muse::contains(HAS_SELECTION_REQUIRED_COMMANDS, command)) {
424 0 : return CommandState(controller()->hasSelection(), false);
425 : }
426 :
427 0 : if (muse::contains(MOVE_SELECTION_COMMANDS, command)) {
428 0 : return CommandState(controller()->isMoveSelectionAvailable(MOVE_SELECTION_COMMANDS.at(command)), false);
429 : }
430 :
431 0 : if (command == UNDO_COMMAND) {
432 0 : return CommandState(controller()->canUndo(), false);
433 : }
434 0 : if (command == REDO_COMMAND) {
435 0 : return CommandState(controller()->canRedo(), false);
436 : }
437 :
438 0 : if (muse::contains(NOTE_COMMANDS, command)) {
439 0 : return CommandState(controller()->isNoteInputActionAllowed(), false);
440 : }
441 :
442 0 : if (muse::contains(TEXT_EDITING_COMMANDS, command)) {
443 0 : return CommandState(controller()->isTextEditing(), false);
444 : }
445 :
446 0 : if (muse::contains(LYRICS_EDITING_COMMANDS, command)) {
447 0 : return CommandState(controller()->isLyricsEditing(), false);
448 : }
449 :
450 0 : if (muse::contains(NOT_TEXT_EDITING_COMMANDS, command)) {
451 0 : return CommandState(!controller()->isTextEditing(), false);
452 : }
453 :
454 0 : if (muse::contains(NOTE_INPUT_COMMANDS, command)) {
455 0 : return CommandState(controller()->isNoteInputAllowed(),
456 0 : controller()->isNoteInputMode() && controller()->noteInputMethod() == NOTE_INPUT_COMMANDS.at(command));
457 0 : } else if (command == REALTIME_ADVANCE_COMMAND) {
458 0 : return CommandState(controller()->isNoteInputMode(), false);
459 : }
460 :
461 0 : if (muse::contains(DURATION_COMMANDS, command)) {
462 0 : return CommandState(true, controller()->currentDurationType() == DURATION_COMMANDS.at(command));
463 : }
464 :
465 0 : if (muse::contains(DOT_COUNT_COMMANDS, command)) {
466 0 : return CommandState(true, controller()->currentDotCount() == DOT_COUNT_COMMANDS.at(command));
467 : }
468 :
469 0 : if (command == TOGGLE_REST_COMMAND) {
470 0 : return CommandState(true, controller()->currentIsRest());
471 : }
472 :
473 0 : if (muse::contains(ACCIDENTAL_COMMANDS, command)) {
474 0 : return CommandState(true, controller()->currentAccidentalType() == ACCIDENTAL_COMMANDS.at(command));
475 : }
476 :
477 0 : if (command == TOGGLE_TIE_COMMAND) {
478 0 : return CommandState(true, controller()->selectionHasTie());
479 : }
480 0 : if (command == ADD_SLUR_COMMAND) {
481 0 : return CommandState(true, controller()->selectionHasSlur());
482 : }
483 0 : if (command == TOGGLE_LV_COMMAND) {
484 0 : return CommandState(true, controller()->selectionHasLaissezVib());
485 : }
486 :
487 0 : if (muse::contains(ADD_ARTICULATION_COMMANDS, command)) {
488 0 : return CommandState(true, controller()->currentArticulations().contains(ADD_ARTICULATION_COMMANDS.at(command)));
489 : }
490 :
491 0 : if (muse::contains(VOICE_COMMANDS, command)) {
492 0 : return CommandState(true, controller()->currentVoice() == VOICE_COMMANDS.at(command));
493 : }
494 :
495 0 : if (command == ADD_DYNAMIC_COMMAND) {
496 0 : return CommandState(controller()->isNoteOrRestSelected() || controller()->isHairpinSelected(), false);
497 : }
498 :
499 0 : if (muse::contains(NOTE_OR_REST_SELECTED_COMMANDS, command)) {
500 0 : return CommandState(controller()->isNoteOrRestSelected(), false);
501 : }
502 :
503 0 : if (muse::contains(LAYOUT_BREAK_COMMANDS, command)) {
504 0 : return CommandState(controller()->isToggleLayoutBreakAvailable(), false);
505 : }
506 :
507 0 : if (muse::contains(SCORE_CONFIG_COMMANDS, command)) {
508 0 : return CommandState(true, controller()->scoreConfig().isShown(SCORE_CONFIG_COMMANDS.at(command)));
509 : }
510 :
511 0 : if (muse::contains(STYLE_COMMANDS, command)) {
512 0 : auto style = controller()->notationStyle();
513 0 : return CommandState(true, style ? style->styleValue(StyleId::concertPitch).toBool() : false);
514 0 : }
515 :
516 0 : if (muse::contains(TAB_COMMANDS, command)) {
517 0 : return CommandState(controller()->isTablatureStaff(), false);
518 : }
519 :
520 0 : if (command == TOGGLE_AUTOMATION_COMMAND) {
521 0 : return CommandState(true, controller()->isAutomationModeEnabled());
522 : }
523 :
524 0 : if (muse::contains(DEBUG_COMMANDS, command)) {
525 0 : return CommandState(true, controller()->isDebuggingCommandEnabled(command));
526 : }
527 :
528 0 : return CommandState(true, false);
529 : }
530 :
531 0 : CommandState NotationCommandsState::commandState(const Command& command) const
532 : {
533 0 : CommandState state = doCommandState(command);
534 : // LOGDA() << "command: " << command
535 : // << ", enabled: " << state.enabled
536 : // << ", checked: " << state.checked;
537 0 : return state;
538 : }
539 :
540 0 : async::Channel<Command, CommandState> NotationCommandsState::commandStateChanged() const
541 : {
542 0 : return m_commandStateChanged;
543 : }
544 :
545 0 : bool NotationCommandsState::isProjectOpened() const
546 : {
547 0 : if (!projectSession()->project()) {
548 0 : return false;
549 : }
550 :
551 0 : if (!interactive() || !interactive()->isOpened(PROJECT_PAGE_URI).val) {
552 0 : return false;
553 : }
554 :
555 0 : return true;
556 : }
|