1
2 //=============================================================================
3 // MuseScore
4 // Music Composition & Notation
5 //
6 // Copyright (C) 2002-2017 Werner Schweer
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License version 2
10 // as published by the Free Software Foundation and appearing in
11 // the file LICENCE.GPL
12 //=============================================================================
13
14 #include "scoreview.h"
15 #include "texttools.h"
16 #include "libmscore/chordrest.h"
17 #include "libmscore/harmony.h"
18 #include "libmscore/score.h"
19 #include "libmscore/segment.h"
20 #include "libmscore/measure.h"
21
22 namespace Ms {
23
24 //---------------------------------------------------------
25 // harmonyTab
26 //---------------------------------------------------------
27
harmonyTab(bool back)28 void ScoreView::harmonyTab(bool back)
29 {
30 Harmony* harmony = toHarmony(editData.element);
31 if (!harmony->parent() || !harmony->parent()->isSegment()) {
32 qDebug("no segment parent");
33 return;
34 }
35 int track = harmony->track();
36 HarmonyType ht = harmony->harmonyType();
37 Tid tid = harmony->tid();
38 Segment* segment = toSegment(harmony->parent());
39 if (!segment) {
40 qDebug("harmonyTicksTab: no segment");
41 return;
42 }
43
44 // moving to next/prev measure
45
46 Measure* measure = segment->measure();
47 if (measure) {
48 if (back)
49 measure = measure->prevMeasure();
50 else
51 measure = measure->nextMeasure();
52 }
53 if (!measure) {
54 qDebug("no prev/next measure");
55 return;
56 }
57
58 segment = measure->findSegment(SegmentType::ChordRest, measure->tick());
59 if (!segment) {
60 qDebug("no ChordRest segment as measure");
61 return;
62 }
63
64 changeState(ViewState::NORMAL);
65
66 // search for next chord name
67 harmony = 0;
68 for (Element* e : segment->annotations()) {
69 if (e->isHarmony() && e->track() == track && toHarmony(e)->tid() == tid) {
70 Harmony* h = toHarmony(e);
71 harmony = h;
72 break;
73 }
74 }
75
76 if (!harmony) {
77 harmony = new Harmony(_score);
78 harmony->setTrack(track);
79 harmony->setParent(segment);
80 harmony->setHarmonyType(ht);
81 _score->startCmd();
82 _score->undoAddElement(harmony);
83 _score->endCmd();
84 }
85
86 _score->select(harmony, SelectType::SINGLE, 0);
87 startEdit(harmony, Grip::NO_GRIP);
88
89 adjustCanvasPosition(harmony, false);
90 TextCursor* cursor = harmony->cursor(editData);
91 cursor->moveCursorToEnd();
92 _score->update();
93 }
94
95 //---------------------------------------------------------
96 // harmonyBeatsTab
97 // manages [;:], moving forward or back to the next beat
98 // and Space/Shift-Space, to stop at next note, rest, harmony or beat.
99 //---------------------------------------------------------
100
harmonyBeatsTab(bool noterest,bool back)101 void ScoreView::harmonyBeatsTab(bool noterest, bool back)
102 {
103 Harmony* harmony = toHarmony(editData.element);
104 if (!harmony->parent() || !harmony->parent()->isSegment()) {
105 qDebug("no segment parent");
106 return;
107 }
108 int track = harmony->track();
109 HarmonyType ht = harmony->harmonyType();
110 Tid tid = harmony->tid();
111 Segment* segment = toSegment(harmony->parent());
112 if (!segment) {
113 qDebug("no segment");
114 return;
115 }
116 Measure* measure = segment->measure();
117 Fraction tick = segment->tick();
118
119 if (back && tick == measure->tick()) {
120 // previous bar, if any
121 measure = measure->prevMeasure();
122 if (!measure) {
123 qDebug("no previous measure");
124 return;
125 }
126 }
127
128 Fraction f = measure->ticks();
129 int ticksPerBeat = f.ticks() / ((f.numerator()>3 && (f.numerator()%3)==0 && f.denominator()>4) ? f.numerator()/3 : f.numerator());
130 Fraction tickInBar = tick - measure->tick();
131 Fraction newTick = measure->tick()
132 + Fraction::fromTicks((
133 (tickInBar.ticks() + (back? -1 : ticksPerBeat)) / ticksPerBeat
134 )
135 * ticksPerBeat);
136
137 changeState(ViewState::NORMAL);
138
139 _score->startCmd();
140 // look for next/prev beat, note, rest or chord
141 for (;;) {
142 segment = back ? segment->prev1(SegmentType::ChordRest) : segment->next1(SegmentType::ChordRest);
143
144 if (!segment || (back ? (segment->tick() < newTick) : (segment->tick() > newTick))) {
145 // no segment or moved past the beat - create new segment
146 if (!back && newTick >= measure->tick() + f) {
147 // next bar, if any
148 measure = measure->nextMeasure();
149 if (!measure) {
150 qDebug("no next measure");
151 return;
152 }
153 }
154 segment = new Segment(measure, SegmentType::ChordRest, newTick - measure->tick());
155 if (!segment) {
156 qDebug("no prev segment");
157 return;
158 }
159 _score->undoAddElement(segment);
160 break;
161 }
162
163 if (segment->tick() == newTick)
164 break;
165
166 if (noterest) {
167 int minTrack = (track / VOICES ) * VOICES;
168 int maxTrack = minTrack + (VOICES-1);
169 if (segment->hasAnnotationOrElement(ElementType::HARMONY, minTrack, maxTrack))
170 break;
171 }
172 }
173
174 // search for next chord name
175 harmony = 0;
176 for (Element* e : segment->annotations()) {
177 if (e->isHarmony() && e->track() == track && toHarmony(e)->tid() == tid) {
178 Harmony* h = toHarmony(e);
179 harmony = h;
180 break;
181 }
182 }
183
184 if (!harmony) {
185 harmony = new Harmony(_score);
186 harmony->setTrack(track);
187 harmony->setParent(segment);
188 harmony->setHarmonyType(ht);
189 _score->undoAddElement(harmony);
190 }
191 _score->endCmd();
192
193 _score->select(harmony, SelectType::SINGLE, 0);
194 startEdit(harmony, Grip::NO_GRIP);
195
196 adjustCanvasPosition(harmony, false);
197 TextCursor* cursor = harmony->cursor(editData);
198 cursor->moveCursorToEnd();
199 _score->update();
200 }
201
202 //---------------------------------------------------------
203 // harmonyTicksTab
204 // manages [Ctrl] [1]-[9], moving forward the given number of ticks
205 //---------------------------------------------------------
206
harmonyTicksTab(const Fraction & ticks)207 void ScoreView::harmonyTicksTab(const Fraction& ticks)
208 {
209 Harmony* harmony = static_cast<Harmony*>(editData.element);
210 if (!harmony->parent() || !harmony->parent()->isSegment()) {
211 qDebug("no segment parent");
212 return;
213 }
214 int track = harmony->track();
215 HarmonyType ht = harmony->harmonyType();
216 Tid tid = harmony->tid();
217 Segment* segment = toSegment(harmony->parent());
218 if (!segment) {
219 qDebug("no segment");
220 return;
221 }
222 Measure* measure = segment->measure();
223
224 Fraction newTick = segment->tick() + ticks;
225
226 // find the measure containing the target tick
227 while (newTick >= measure->tick() + measure->ticks()) {
228 measure = measure->nextMeasure();
229 if (!measure) {
230 qDebug("no next measure");
231 return;
232 }
233 }
234
235 changeState(ViewState::NORMAL);
236
237 // look for a segment at this tick; if none, create one
238 while (segment && segment->tick() < newTick)
239 segment = segment->next1(SegmentType::ChordRest);
240 if (!segment || segment->tick() > newTick) { // no ChordRest segment at this tick
241 segment = new Segment(measure, SegmentType::ChordRest, newTick - measure->tick());
242 _score->startCmd();
243 _score->undoAddElement(segment);
244 _score->endCmd();
245 }
246
247 // search for next chord name
248 harmony = 0;
249 for (Element* e : segment->annotations()) {
250 if (e->isHarmony() && e->track() == track && toHarmony(e)->tid() == tid) {
251 Harmony* h = toHarmony(e);
252 harmony = h;
253 break;
254 }
255 }
256
257 if (!harmony) {
258 harmony = new Harmony(_score);
259 harmony->setTrack(track);
260 harmony->setParent(segment);
261 harmony->setHarmonyType(ht);
262 _score->startCmd();
263 _score->undoAddElement(harmony);
264 _score->endCmd();
265 }
266
267 _score->select(harmony, SelectType::SINGLE, 0);
268 startEdit(harmony, Grip::NO_GRIP);
269
270 adjustCanvasPosition(harmony, false);
271 TextCursor* cursor = harmony->cursor(editData);
272 cursor->moveCursorToEnd();
273 _score->update();
274 }
275
276 }
277
278