1 //=============================================================================
2 //  MuseScore
3 //  Music Composition & Notation
4 //
5 //  Copyright (C) 2019 Werner Schweer and others
6 //
7 //  This program is free software; you can redistribute it and/or modify
8 //  it under the terms of the GNU General Public License version 2
9 //  as published by the Free Software Foundation and appearing in
10 //  the file LICENCE.GPL
11 //=============================================================================
12 
13 #include "selection.h"
14 #include "score.h"
15 
16 #include "libmscore/undo.h"
17 
18 namespace Ms {
19 namespace PluginAPI {
20 
21 //---------------------------------------------------------
22 //   QmlPlayEventsListAccess::append
23 //---------------------------------------------------------
24 
selectionWrap(Ms::Selection * select)25 Selection* selectionWrap(Ms::Selection* select)
26       {
27       Selection* w = new Selection(select);
28       // All wrapper objects should belong to JavaScript code.
29       QQmlEngine::setObjectOwnership(w, QQmlEngine::JavaScriptOwnership);
30       return w;
31       }
32 
33 //---------------------------------------------------------
34 //   Selection::checkSelectionIsNotLocked
35 //---------------------------------------------------------
36 
checkSelectionIsNotLocked() const37 bool Selection::checkSelectionIsNotLocked() const
38       {
39       if (_select->isLocked()) {
40             qWarning("Cannot change selection: %s", qPrintable(_select->lockReason()));
41             return false;
42             }
43       return true;
44       }
45 
46 //---------------------------------------------------------
47 //   Selection::select
48 ///   Selects the given element. At this point only a
49 ///   limited number of element types is supported, like
50 ///   notes, rests and most of text elements.
51 ///   \param e element to select
52 ///   \param add if \p true, appends an element to already
53 ///   existing selection. If \p false (default), deselects
54 ///   all other elements and selects this element.
55 ///   \return \p true on success, \p false if selection
56 ///   cannot be changed, e.g. due to the ongoing operation
57 ///   on a score (like dragging elements) or incorrect
58 ///   arguments to this function.
59 ///   \since MuseScore 3.5
60 //---------------------------------------------------------
61 
select(Element * elWrapper,bool add)62 bool Selection::select(Element* elWrapper, bool add)
63       {
64       if (!checkSelectionIsNotLocked())
65             return false;
66 
67       if (!elWrapper)
68             return false;
69 
70       Ms::Element* e = elWrapper->element();
71 
72       // Check whether it's safe to select this element:
73       // use types list from UndoMacro for now
74       if (!Ms::UndoMacro::canRecordSelectedElement(e)) {
75             qWarning("Cannot select element of type %s", e->name());
76             return false;
77             }
78 
79       if (e->score() != _select->score() || elWrapper->ownership() != Ownership::SCORE) {
80             qWarning("Selection::select: element does not belong to score");
81             return false;
82             }
83 
84       const SelectType selType = add ? SelectType::ADD : SelectType::SINGLE;
85       e->score()->select(e, selType);
86 
87       return true;
88       }
89 
90 //---------------------------------------------------------
91 //   Selection::selectRange
92 ///   Selects a range in a score
93 ///   \param startTick start tick to be included in selection
94 ///   \param endTick end tick of selection, excluded from selection
95 ///   \param startStaff start staff index, included in selection
96 ///   \param endStaff end staff index, excluded from seleciton
97 ///   \return \p true on success, \p false if selection
98 ///   cannot be changed, e.g. due to the ongoing operation
99 ///   on a score (like dragging elements) or incorrect
100 ///   arguments to this function.
101 ///   \since MuseScore 3.5
102 //---------------------------------------------------------
103 
selectRange(int startTick,int endTick,int startStaff,int endStaff)104 bool Selection::selectRange(int startTick, int endTick, int startStaff, int endStaff)
105       {
106       if (!checkSelectionIsNotLocked())
107             return false;
108 
109       const int nstaves = _select->score()->nstaves();
110 
111       startStaff = qBound(0, startStaff, nstaves - 1);
112       endStaff = qBound(1, endStaff, nstaves);
113 
114       if (startStaff >= endStaff)
115             return false;
116 
117       Ms::Segment* segStart = _select->score()->tick2leftSegmentMM(Ms::Fraction::fromTicks(startTick));
118       Ms::Segment* segEnd = _select->score()->tick2leftSegmentMM(Ms::Fraction::fromTicks(endTick));
119 
120       if (!segStart || (segEnd && !((*segEnd) > (*segStart))))
121             return false;
122 
123       if (segEnd && _select->score()->undoStack()->active())
124             _select->setRangeTicks(segStart->tick(), segEnd->tick(), startStaff, endStaff);
125       else
126             _select->setRange(segStart, segEnd, startStaff, endStaff);
127 
128       return true;
129       }
130 
131 //---------------------------------------------------------
132 //   Selection::deselect
133 ///   Deselects the given element.
134 ///   \return \p true on success, \p false if selection
135 ///   cannot be changed, e.g. due to the ongoing operation
136 ///   on a score (like dragging elements).
137 ///   \since MuseScore 3.5
138 //---------------------------------------------------------
139 
deselect(Element * elWrapper)140 bool Selection::deselect(Element* elWrapper)
141       {
142       if (!checkSelectionIsNotLocked())
143             return false;
144 
145       if (!elWrapper)
146             return false;
147 
148       _select->score()->deselect(elWrapper->element());
149       return true;
150       }
151 
152 //---------------------------------------------------------
153 //   Selection::clear
154 ///   Clears the selection.
155 ///   \return \p true on success, \p false if selection
156 ///   cannot be changed, e.g. due to the ongoing operation
157 ///   on a score (like dragging elements).
158 ///   \since MuseScore 3.5
159 //---------------------------------------------------------
160 
clear()161 bool Selection::clear()
162       {
163       if (!checkSelectionIsNotLocked())
164             return false;
165 
166       _select->deselectAll();
167       return true;
168       }
169 }
170 }
171