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 "durationtype.h"
26 : #include "mscore.h"
27 : #include "pitchspelling.h"
28 : #include "../types/types.h"
29 :
30 : #include "selectionfilter.h"
31 :
32 : namespace mu::engraving {
33 : class Score;
34 : class Page;
35 : class System;
36 : class ChordRest;
37 : class EngravingItem;
38 : class Segment;
39 : class Note;
40 : class Measure;
41 : class MeasureBase;
42 : class Chord;
43 : class Tuplet;
44 : class GuitarBend;
45 : class Box;
46 :
47 : //---------------------------------------------------------
48 : // ElementPattern
49 : //---------------------------------------------------------
50 :
51 : struct ElementPattern {
52 : std::vector<EngravingItem*> el;
53 : int type = 0;
54 : int subtype = 0;
55 : staff_idx_t staffStart = 0;
56 : staff_idx_t staffEnd = 0; // exclusive
57 : voice_idx_t voice = 0;
58 : bool subtypeValid = false;
59 : Fraction durationTicks { -1, 1 };
60 : Fraction beat { 0, 0 };
61 : const Measure* measure = nullptr;
62 : const System* system = nullptr;
63 : };
64 :
65 : //---------------------------------------------------------
66 : // NotePattern
67 : //---------------------------------------------------------
68 :
69 : struct NotePattern : ElementPattern {
70 : std::vector<Note*> el;
71 : int pitch = -1;
72 : int string = INVALID_STRING_INDEX;
73 : int tpc = Tpc::TPC_INVALID;
74 : NoteHeadGroup notehead = NoteHeadGroup::HEAD_INVALID;
75 : TDuration durationType = TDuration();
76 : NoteType type = NoteType::INVALID;
77 : };
78 :
79 : //---------------------------------------------------------
80 : // SelState
81 : //---------------------------------------------------------
82 :
83 : enum class SelState : char {
84 : NONE, // nothing is selected
85 : LIST, // disjoint selection
86 : RANGE, // adjacent selection, a range in one or more staves
87 : // is selected
88 : };
89 :
90 : //---------------------------------------------------------
91 : // SelectedSymbol
92 : //---------------------------------------------------------
93 :
94 : struct SelectedSymbol {
95 : track_idx_t track = muse::nidx;
96 : int tickOffset = 0;
97 : int segDelta = 0;
98 : EngravingItem* element = nullptr;
99 : };
100 :
101 : //-------------------------------------------------------------------
102 : // Selection
103 : // For SelState::LIST state only visible elements can be selected
104 : // (no Chord element etc.).
105 : //-------------------------------------------------------------------
106 :
107 : class Selection
108 : {
109 : public:
110 0 : Selection() { m_score = 0; m_state = SelState::NONE; }
111 : Selection(Score*);
112 0 : Score* score() const { return m_score; }
113 9116 : SelState state() const { return m_state; }
114 284 : bool isNone() const { return m_state == SelState::NONE; }
115 9736 : bool isRange() const { return m_state == SelState::RANGE; }
116 1606 : bool isList() const { return m_state == SelState::LIST; }
117 : void setState(SelState s);
118 :
119 : //! NOTE If locked, the selected items should not be changed.
120 : void lock(const String& reason) { m_lockReason = reason; }
121 : void unlock(const String& /*reason*/) { m_lockReason.clear(); } // reason for clarity
122 49276 : bool isLocked() const { return !m_lockReason.isEmpty(); }
123 0 : const String& lockReason() const { return m_lockReason; }
124 :
125 5382 : const std::vector<EngravingItem*>& elements() const { return m_el; }
126 : std::vector<EngravingItem*> elements(ElementType type) const;
127 : std::vector<Note*> noteList(track_idx_t track = muse::nidx) const;
128 :
129 : const std::list<EngravingItem*> uniqueElements() const;
130 : std::vector<Note*> uniqueNotes(track_idx_t track = muse::nidx, bool tied = true) const;
131 :
132 634 : bool isSingle() const { return (m_state == SelState::LIST) && (m_el.size() == 1); }
133 : bool elementsSelected(const ElementTypeSet& types) const;
134 :
135 : void add(EngravingItem*);
136 : void deselectAll();
137 : void remove(EngravingItem*);
138 : void clear();
139 : EngravingItem* element() const;
140 : ChordRest* cr() const;
141 : ChordRest* firstChordRest(track_idx_t track = muse::nidx) const;
142 : ChordRest* lastChordRest(track_idx_t track = muse::nidx) const;
143 : Measure* findMeasure() const;
144 : MeasureBase* startMeasureBase() const;
145 : MeasureBase* endMeasureBase() const;
146 : std::vector<MeasureBase*> measureBasesInSelection() const;
147 : std::vector<System*> selectedSystems() const;
148 : std::vector<Page*> pagesContainingSelection() const;
149 : void update();
150 : void updateState();
151 : void dump();
152 : String mimeType() const;
153 : muse::ByteArray mimeData() const;
154 :
155 118 : Segment* startSegment() const { return m_startSegment; }
156 381 : Segment* endSegment() const { return m_endSegment; }
157 : void setStartSegment(Segment* s);
158 : void setEndSegment(Segment* s);
159 :
160 166 : Box* startBox() const { return m_startBox; }
161 166 : Box* endBox() const { return m_endBox; }
162 :
163 : void setRange(Segment* startSegment, Segment* endSegment, staff_idx_t staffStart, staff_idx_t staffEnd, Box* startBox = nullptr,
164 : Box* endBox = nullptr);
165 : void setRangeTicks(const Fraction& tick1, const Fraction& tick2, staff_idx_t staffStart, staff_idx_t staffEnd, Box* startBox = nullptr,
166 : Box* endBox = nullptr);
167 :
168 0 : Segment* activeSegment() const { return m_activeSegment; }
169 1464 : void setActiveSegment(Segment* s) { m_activeSegment = s; }
170 : ChordRest* activeCR() const;
171 : bool isStartActive() const;
172 : bool isEndActive() const;
173 : ChordRest* currentCR() const;
174 : Fraction tickStart() const;
175 : Fraction tickEnd() const;
176 569 : staff_idx_t staffStart() const { return m_staffStart; }
177 614 : staff_idx_t staffEnd() const { return m_staffEnd; }
178 0 : track_idx_t activeTrack() const { return m_activeTrack; }
179 0 : void setStaffStart(int v) { m_staffStart = v; }
180 0 : void setStaffEnd(int v) { m_staffEnd = v; }
181 1864 : void setActiveTrack(track_idx_t v) { m_activeTrack = v; }
182 : bool canCopy() const;
183 : void updateSelectedElements();
184 : bool measureBaseRange(MeasureBase** mb1, MeasureBase** mb2) const;
185 : void extendRangeSelection(ChordRest* cr);
186 : void extendRangeSelection(Segment* seg, Segment* segAfter, staff_idx_t staffIdx, const Fraction& tick, const Fraction& etick,
187 : Box* box = nullptr);
188 : bool rangeContainsMultiNoteChords() const;
189 :
190 : private:
191 : muse::ByteArray staffMimeData() const;
192 : muse::ByteArray symbolListMimeData() const;
193 : SelectionFilter selectionFilter() const;
194 8021 : bool canSelect(const EngravingItem* e) const { return selectionFilter().canSelect(e); }
195 : bool canSelectNoteIdx(size_t noteIdx, size_t totalNotesInChord, bool rangeContainsMultiNoteChords) const;
196 23867 : bool canSelectVoice(track_idx_t track) const { return selectionFilter().canSelectVoice(track); }
197 : void appendFiltered(EngravingItem* e);
198 : void appendFiltered(const std::unordered_set<EngravingItem*>& elems);
199 : void appendChordRest(ChordRest* cr);
200 : void appendTupletHierarchy(Tuplet* innermostTuplet);
201 : void appendGuitarBend(GuitarBend* guitarBend);
202 :
203 : ChordRest* firstChordRestInRange(track_idx_t preferredTrack = muse::nidx) const;
204 : ChordRest* lastChordRestInRange(track_idx_t preferredTrack = muse::nidx) const;
205 :
206 : void validateBoxesAndSegments(); // Checks that the Boxes/segments match (asserts and clears the Box if not)
207 :
208 : bool rangeIsValid() const;
209 :
210 : Score* m_score = nullptr;
211 : SelState m_state = SelState::NONE;
212 : std::vector<EngravingItem*> m_el; // valid in mode SelState::LIST
213 :
214 : staff_idx_t m_staffStart = 0; // valid if selState is SelState::RANGE
215 : staff_idx_t m_staffEnd = 0;
216 :
217 : Segment* m_startSegment = nullptr;
218 : Segment* m_endSegment = nullptr; // next segment after selection
219 :
220 : Box* m_startBox = nullptr;
221 : Box* m_endBox = nullptr; // the last Box included in the selection
222 :
223 : Fraction m_plannedTick1 { -1, 1 }; // Will be actually selected on updateSelectedElements() call.
224 : Fraction m_plannedTick2 { -1, 1 }; // Used by setRangeTicks() to restore proper selection after
225 : // command end in case some changes are expected to segments'
226 : // structure (e.g. MMRests reconstruction).
227 :
228 : Segment* m_activeSegment = nullptr;
229 : track_idx_t m_activeTrack = 0;
230 :
231 : Fraction m_currentTick; // tracks the most recent selection
232 : track_idx_t m_currentTrack = 0;
233 :
234 : bool m_rangeContainsMultiNoteChords = false; // cached - calculating this isn't free
235 :
236 : String m_lockReason;
237 : };
238 : } // namespace mu::engraving
|