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
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 "editbeam.h"
24 :
25 : #include "../dom/chordrest.h"
26 : #include "../dom/groups.h"
27 : #include "../dom/score.h"
28 : #include "../dom/segment.h"
29 : #include "../dom/select.h"
30 : #include "../dom/utils.h"
31 :
32 : #include "navigation.h"
33 :
34 : #include "log.h"
35 :
36 : using namespace mu::engraving;
37 :
38 : //---------------------------------------------------------
39 : // setBeamMode
40 : //---------------------------------------------------------
41 :
42 5 : void EditBeam::setBeamMode(Transaction&, Score* score, BeamMode mode)
43 : {
44 10 : for (ChordRest* cr : score->getSelectedChordRests()) {
45 5 : if (cr) {
46 5 : cr->undoChangeProperty(Pid::BEAM_MODE, mode);
47 : }
48 5 : }
49 5 : }
50 :
51 : //---------------------------------------------------------
52 : // beamSelectedRange
53 : //---------------------------------------------------------
54 :
55 0 : void EditBeam::beamSelectedRange(Transaction& tx, Score* score)
56 : {
57 0 : if (!score->selection().isRange()) {
58 0 : return;
59 : }
60 :
61 0 : resetBeamMode(tx, score);
62 :
63 0 : const track_idx_t startTrack = staff2track(score->selection().staffStart());
64 0 : const track_idx_t endTrack = staff2track(score->selection().staffEnd());
65 0 : const SelectionFilter filter = score->selectionFilter();
66 :
67 0 : for (staff_idx_t trackIdx = startTrack; trackIdx < endTrack; ++trackIdx) {
68 0 : if (!filter.canSelectVoice(trackIdx)) {
69 0 : continue;
70 : }
71 :
72 0 : ChordRest* firstChordRest = score->selection().firstChordRest(trackIdx);
73 0 : ChordRest* lastChordRest = score->selection().lastChordRest(trackIdx);
74 :
75 0 : if (!firstChordRest || !lastChordRest) {
76 0 : continue;
77 : }
78 :
79 0 : ChordRest* prev = Navigation::prevChordRest(firstChordRest);
80 0 : ChordRest* cr = firstChordRest;
81 0 : BeamMode actualBeamMode = Groups::actualBeamMode(cr, prev);
82 0 : if (actualBeamMode != BeamMode::BEGIN) {
83 0 : cr->undoChangeProperty(Pid::BEAM_MODE, BeamMode::BEGIN);
84 : }
85 :
86 0 : while (cr != lastChordRest) {
87 0 : prev = cr;
88 0 : cr = Navigation::nextChordRest(cr);
89 0 : actualBeamMode = Groups::actualBeamMode(cr, prev);
90 0 : if (actualBeamMode == BeamMode::BEGIN || actualBeamMode == BeamMode::NONE) {
91 0 : cr->undoChangeProperty(Pid::BEAM_MODE, BeamMode::MID);
92 : }
93 : }
94 :
95 0 : prev = cr;
96 0 : cr = Navigation::nextChordRest(cr);
97 0 : if (cr) {
98 0 : actualBeamMode = Groups::actualBeamMode(cr, prev);
99 0 : if (actualBeamMode != BeamMode::BEGIN && actualBeamMode != BeamMode::NONE) {
100 0 : cr->undoChangeProperty(Pid::BEAM_MODE, BeamMode::BEGIN);
101 : }
102 : }
103 : }
104 : }
105 :
106 : //---------------------------------------------------------
107 : // resetBeamMode
108 : //---------------------------------------------------------
109 :
110 1 : void EditBeam::resetBeamMode(Transaction&, Score* score)
111 : {
112 1 : bool noSelection = score->selection().isNone();
113 1 : if (noSelection) {
114 1 : score->cmdSelectAll();
115 0 : } else if (!score->selection().isRange()) {
116 0 : LOGD("no system or staff selected");
117 0 : return;
118 : }
119 :
120 1 : ChordRest* firstCr = score->selection().firstChordRest();
121 1 : if (!firstCr) {
122 0 : LOGD("no chord/rest in selection");
123 0 : return;
124 : }
125 :
126 1 : const track_idx_t trackStart = staff2track(score->selection().staffStart());
127 1 : const track_idx_t trackEnd = staff2track(score->selection().staffEnd());
128 1 : const Fraction endTick = score->selection().tickEnd();
129 1 : const SelectionFilter filter = score->selectionFilter();
130 :
131 3 : for (Segment* seg = firstCr->segment(); seg && seg->tick() < endTick; seg = seg->next1(SegmentType::ChordRest)) {
132 10 : for (track_idx_t track = trackStart; track < trackEnd; ++track) {
133 8 : if (!filter.canSelectVoice(track)) {
134 0 : continue;
135 : }
136 :
137 8 : ChordRest* cr = toChordRest(seg->element(track));
138 8 : if (!cr) {
139 6 : continue;
140 : }
141 2 : if (cr->isChord()) {
142 2 : if (cr->beamMode() != BeamMode::AUTO) {
143 2 : cr->undoChangeProperty(Pid::BEAM_MODE, BeamMode::AUTO);
144 : }
145 0 : } else if (cr->isRest()) {
146 0 : if (cr->beamMode() != BeamMode::NONE) {
147 0 : cr->undoChangeProperty(Pid::BEAM_MODE, BeamMode::NONE);
148 : }
149 : }
150 : }
151 : }
152 :
153 1 : if (noSelection) {
154 1 : score->deselectAll();
155 : }
156 : }
|