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