1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A MIDI and audio sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7
8 Other copyrights also apply to some parts of this work. Please
9 see the AUTHORS file and individual file headers for details.
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version. See the file
15 COPYING included with this distribution for more information.
16 */
17
18
19 #include "ClefInsertionCommand.h"
20
21 #include "misc/Strings.h"
22 #include "base/Event.h"
23 #include "base/NotationTypes.h"
24 #include "base/Segment.h"
25 #include "base/SegmentNotationHelper.h"
26 #include "base/BaseProperties.h"
27 #include "document/BasicCommand.h"
28 #include "base/Selection.h"
29 #include <QString>
30
31
32 namespace Rosegarden
33 {
34
35 using namespace BaseProperties;
36
ClefInsertionCommand(Segment & segment,timeT time,Clef clef,bool shouldChangeOctave,bool shouldTranspose)37 ClefInsertionCommand::ClefInsertionCommand(Segment &segment, timeT time,
38 Clef clef,
39 bool shouldChangeOctave,
40 bool shouldTranspose) :
41 BasicCommand(getThisGlobalName(&clef), segment, time,
42 ((shouldChangeOctave || shouldTranspose) ?
43 segment.getEndTime() : time + 1)),
44 m_clef(clef),
45 m_shouldChangeOctave(shouldChangeOctave),
46 m_shouldTranspose(shouldTranspose),
47 m_lastInsertedEvent(nullptr)
48 {
49 // nothing
50 }
51
~ClefInsertionCommand()52 ClefInsertionCommand::~ClefInsertionCommand()
53 {
54 // nothing
55 }
56
57 EventSelection *
getSubsequentSelection()58 ClefInsertionCommand::getSubsequentSelection()
59 {
60 EventSelection *selection = new EventSelection(getSegment());
61 selection->addEvent(getLastInsertedEvent());
62 return selection;
63 }
64
65 QString
getThisGlobalName(Clef * clef)66 ClefInsertionCommand::getThisGlobalName(Clef *clef)
67 {
68 return getGlobalName(clef);
69 }
70
71 QString
getGlobalName(Clef *)72 ClefInsertionCommand::getGlobalName(Clef *)
73 {
74 /* doesn't handle octave offset -- leave it for now
75 if (clef) {
76 QString name(strtoqstr(clef->getClefType()));
77 name = name.left(1).toUpper() + name.right(name.length()-1);
78 return tr("Change to %1 Cle&f...").arg(name);
79 } else {
80 */
81 return tr("Add Cle&f Change...");
82 /*
83 }
84 */
85 }
86
87 timeT
getRelayoutEndTime()88 ClefInsertionCommand::getRelayoutEndTime()
89 {
90 // Inserting a clef can change the y-coord of every subsequent note
91 return getSegment().getEndTime();
92 }
93
94 void
modifySegment()95 ClefInsertionCommand::modifySegment()
96 {
97 SegmentNotationHelper helper(getSegment());
98 Clef oldClef(getSegment().getClefAtTime(getStartTime()));
99
100 Segment::iterator i = getSegment().findTime(getStartTime());
101 while (getSegment().isBeforeEndMarker(i)) {
102 if ((*i)->getAbsoluteTime() > getStartTime()) {
103 break;
104 }
105 if ((*i)->isa(Clef::EventType)) {
106 getSegment().erase(i);
107 break;
108 }
109 ++i;
110 }
111
112 i = helper.insertClef(getStartTime(), m_clef);
113 if (i != helper.segment().end())
114 m_lastInsertedEvent = *i;
115
116 if (m_clef != oldClef) {
117
118 int semitones = 0;
119
120 if (m_shouldChangeOctave) {
121 semitones += 12 * (m_clef.getOctave() - oldClef.getOctave());
122 }
123 if (m_shouldTranspose) {
124 semitones -= m_clef.getPitchOffset() - oldClef.getPitchOffset();
125 }
126
127 if (semitones != 0) {
128 while (i != helper.segment().end()) {
129 if ((*i)->isa(Note::EventType)) {
130 long pitch = 0;
131 if ((*i)->get
132 <Int>(PITCH, pitch)) {
133 pitch += semitones;
134 (*i)->set
135 <Int>(PITCH, pitch);
136 }
137 } else if (*i != m_lastInsertedEvent && (*i)->isa(Clef::EventType)) {
138 // Stop changing octaves when next clef is encountered.
139 break;
140 }
141 ++i;
142 }
143 }
144 }
145 }
146
ClefLinkInsertionCommand(Segment & segment,timeT time,Clef clef,bool shouldChangeOctave,bool shouldTranspose)147 ClefLinkInsertionCommand::ClefLinkInsertionCommand(Segment &segment,
148 timeT time,
149 Clef clef,
150 bool shouldChangeOctave,
151 bool shouldTranspose) :
152 ClefInsertionCommand(segment,time,clef,shouldChangeOctave,shouldTranspose)
153 {
154 setUpdateLinks(false);
155 };
156
~ClefLinkInsertionCommand()157 ClefLinkInsertionCommand::~ClefLinkInsertionCommand()
158 {
159 // nothing
160 }
161
162 QString
getThisGlobalName(Clef * clef)163 ClefLinkInsertionCommand::getThisGlobalName(Clef *clef)
164 {
165 return getGlobalName(clef);
166 }
167
168 QString
getGlobalName(Clef *)169 ClefLinkInsertionCommand::getGlobalName(Clef */* clef */)
170 {
171 return tr("Add Cl&ef Change for linked segment...");
172 }
173
174 void
modifySegment()175 ClefLinkInsertionCommand::modifySegment()
176 {
177 ClefInsertionCommand::modifySegment();
178 if (m_lastInsertedEvent && m_lastInsertedEvent->isa(Clef::EventType)) {
179 //add a property so this event is ignored when updating linked segs
180 m_lastInsertedEvent->set<Bool>(LINKED_SEGMENT_IGNORE_UPDATE, true);
181 }
182 }
183
184 }
185