1 /*
2 Copyright (C) 2005-2008 Remon Sijrier
3
4 This file is part of Traverso
5
6 Traverso is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 */
21
22 #include "MoveClip.h"
23
24 #include "AudioClip.h"
25 #include "AudioClipManager.h"
26 #include "ContextPointer.h"
27 #include "InputEngine.h"
28 #include "SnapList.h"
29 #include "Sheet.h"
30 #include "Track.h"
31 #include "TimeLine.h"
32
33 #include "ClipsViewPort.h"
34 #include "SheetView.h"
35 #include "TrackView.h"
36 #include "AudioClipView.h"
37
38 #include "Zoom.h"
39
40
41 // Always put me below _all_ includes, this is needed
42 // in case we run with memory leak detection enabled!
43 #include "Debugger.h"
44
45 /**
46 * \class MoveClip
47 \brief A Command class for Dragging or Copy-dragging an AudioClip
48
49 \sa TraversoCommands
50 */
51
52
53 /**
54 * Creates a Move Clip or Copy Clip Command object.
55 */
MoveClip(ViewItem * view,QVariantList args)56 MoveClip::MoveClip(ViewItem* view, QVariantList args)
57 : Command(view->get_context(), "")
58 , d(new Data)
59 {
60 QString action = "move"; // default action!
61
62 if (args.size() > 0) {
63 action = args.at(0).toString();
64 }
65 if (args.size() > 1) {
66 d->verticalOnly = args.at(1).toBool();
67 } else {
68 d->verticalOnly = false;
69 }
70
71 QString des;
72 if (action == "copy") {
73 des = tr("Copy Clip");
74 m_actionType = COPY;
75 } else if (action == "move") {
76 des = tr("Move Clip");
77 m_actionType = MOVE;
78 } else if (action == "move_to_start") {
79 des = tr("Move Clip To Start");
80 m_actionType = MOVE_TO_START;
81 } else if (action == "move_to_end") {
82 des = tr("Move Clip To End");
83 m_actionType = MOVE_TO_END;
84 } else if (action == "fold_sheet") {
85 des = tr("Fold Sheet");
86 m_actionType = FOLD_SHEET;
87 } else if (action == "fold_track") {
88 des = tr("Fold Track");
89 m_actionType = FOLD_TRACK;
90 } else if (action == "fold_markers") {
91 des = tr("Fold Markers");
92 m_actionType = FOLD_MARKERS;
93 } else {
94 PERROR("MoveClip: Unknown action type: %s", QS_C(action));
95 }
96
97 setText(des);
98
99 if (m_actionType == FOLD_SHEET || m_actionType == FOLD_TRACK || m_actionType == FOLD_MARKERS) {
100
101 QList<AudioClip*> movingClips;
102 QList<Track*> tracks;
103
104 if (m_actionType == FOLD_TRACK) {
105 TrackView* tv = qobject_cast<TrackView*>(view);
106 Q_ASSERT(tv);
107 d->sv= tv->get_sheetview();
108 tracks.append(tv->get_track());
109 } else if (m_actionType == FOLD_SHEET) {
110 d->sv = qobject_cast<SheetView*>(view);
111 Q_ASSERT(d->sv);
112 tracks = d->sv->get_sheet()->get_tracks();
113 } else {
114 d->sv = qobject_cast<SheetView*>(view->get_sheetview());
115 Q_ASSERT(d->sv);
116 }
117
118 TimeRef currentLocation = TimeRef(cpointer().on_first_input_event_scene_x() * d->sv->timeref_scalefactor);
119
120 if (d->sv->get_trackview_under(cpointer().scene_pos())) {
121 d->pointedTrackIndex = d->sv->get_trackview_under(cpointer().scene_pos())->get_track()->get_sort_index();
122 } else {
123 d->pointedTrackIndex = 0;
124 }
125
126 if (m_actionType == FOLD_SHEET || m_actionType == FOLD_MARKERS) {
127 QList<Marker*> movingMarkers = d->sv->get_sheet()->get_timeline()->get_markers();
128 foreach(Marker* marker, movingMarkers) {
129 if (marker->get_when() > currentLocation) {
130 MarkerAndOrigin markerAndOrigin;
131 markerAndOrigin.marker = marker;
132 markerAndOrigin.origin = marker->get_when();
133 m_markers.append(markerAndOrigin);
134 }
135 }
136 }
137
138 if (m_actionType == FOLD_SHEET || m_actionType == FOLD_TRACK) {
139 foreach(Track* track, tracks) {
140 QList<AudioClip*> clips = track->get_cliplist();
141 foreach(AudioClip* clip, clips) {
142 if (clip->get_track_end_location() > currentLocation) {
143 movingClips.append(clip);
144 }
145 }
146 }
147 }
148
149 m_group.set_clips(movingClips);
150
151 } else {
152 AudioClipView* cv = qobject_cast<AudioClipView*>(view);
153 Q_ASSERT(cv);
154 d->sv = cv->get_sheetview();
155 AudioClip* clip = cv->get_clip();
156 if (clip->is_selected()) {
157 QList<AudioClip*> selected;
158 clip->get_sheet()->get_audioclip_manager()->get_selected_clips(selected);
159 m_group.set_clips(selected);
160 } else {
161 m_group.add_clip(clip);
162 }
163 d->pointedTrackIndex = clip->get_track()->get_sort_index();
164 }
165
166 m_origTrackIndex = m_newTrackIndex = m_group.get_track_index();
167 if (m_group.get_size() == 0 && m_markers.count() > 0) {
168 m_trackStartLocation = m_markers[0].origin;
169 } else {
170 m_trackStartLocation = m_group.get_track_start_location();
171 }
172 m_sheet = d->sv->get_sheet();
173 d->zoom = 0;
174 }
175
~MoveClip()176 MoveClip::~MoveClip()
177 {
178 if (d) {
179 if (d->zoom) {
180 delete d->zoom;
181 }
182 delete d;
183 }
184 }
185
begin_hold()186 int MoveClip::begin_hold()
187 {
188 if ((!m_group.get_size() || m_group.is_locked()) && !m_markers.count()) {
189 return -1;
190 }
191
192 if (m_actionType == COPY) {
193 // FIXME Memory leak here!
194 QList<AudioClip*> newclips = m_group.copy_clips();
195 m_group.set_clips(newclips);
196 m_group.add_all_clips_to_tracks();
197 m_group.move_to(m_origTrackIndex, m_trackStartLocation + TimeRef(d->sv->timeref_scalefactor * 3));
198 }
199
200 m_group.set_as_moving(true);
201
202 d->sv->stop_follow_play_head();
203 d->sv->start_shuttle(true, true);
204 d->sceneXStartPos = cpointer().on_first_input_event_scene_x();
205
206 return 1;
207 }
208
209
finish_hold()210 int MoveClip::finish_hold()
211 {
212 m_group.set_as_moving(false);
213
214 d->sv->start_shuttle(false);
215
216 return 1;
217 }
218
219
prepare_actions()220 int MoveClip::prepare_actions()
221 {
222 if (d->zoom) {
223 delete d->zoom;
224 }
225 delete d;
226 d = 0;
227
228 if (m_actionType == COPY) {
229 m_group.remove_all_clips_from_tracks();
230 }
231
232 if (m_origTrackIndex == m_newTrackIndex && m_posDiff == TimeRef() &&
233 ! (m_actionType == COPY || m_actionType == MOVE_TO_START || m_actionType == MOVE_TO_END) ) {
234 return -1;
235 }
236
237 return 1;
238 }
239
240
do_action()241 int MoveClip::do_action()
242 {
243 PENTER;
244 if (m_actionType == MOVE || m_actionType == FOLD_SHEET || m_actionType == FOLD_TRACK) {
245 m_group.move_to(m_newTrackIndex, m_trackStartLocation + m_posDiff);
246 }
247 else if (m_actionType == COPY) {
248 m_group.add_all_clips_to_tracks();
249 m_group.move_to(m_newTrackIndex, m_trackStartLocation + m_posDiff);
250 }
251 else if (m_actionType == MOVE_TO_START) {
252 move_to_start(false);
253 }
254 else if (m_actionType == MOVE_TO_END) {
255 move_to_end(false);
256 }
257
258 foreach(MarkerAndOrigin markerAndOrigin, m_markers) {
259 markerAndOrigin.marker->set_when(markerAndOrigin.origin + m_posDiff);
260 }
261
262 return 1;
263 }
264
265
undo_action()266 int MoveClip::undo_action()
267 {
268 PENTER;
269
270 if (m_actionType == COPY) {
271 m_group.remove_all_clips_from_tracks();
272 } else {
273 m_group.move_to(m_origTrackIndex, m_trackStartLocation);
274 }
275
276 foreach(MarkerAndOrigin markerAndOrigin, m_markers) {
277 markerAndOrigin.marker->set_when(markerAndOrigin.origin);
278 }
279
280 return 1;
281 }
282
cancel_action()283 void MoveClip::cancel_action()
284 {
285 finish_hold();
286 undo_action();
287 }
288
jog()289 int MoveClip::jog()
290 {
291 if (d->zoom) {
292 d->zoom->jog();
293 return 0;
294 }
295
296 TrackView* trackView = d->sv->get_trackview_under(cpointer().scene_pos());
297 int deltaTrackIndex = 0;
298 if (trackView/* && !(m_actionType == FOLD_SHEET)*/) {
299 deltaTrackIndex = trackView->get_track()->get_sort_index() - d->pointedTrackIndex;
300 m_group.check_valid_track_index_delta(deltaTrackIndex);
301 m_newTrackIndex = m_newTrackIndex + deltaTrackIndex;
302 d->pointedTrackIndex = trackView->get_track()->get_sort_index();
303 }
304
305 // Calculate the distance moved based on the current scene x pos and the initial one.
306 // Only assign if we the movements is allowed in horizontal direction
307 TimeRef diff_f;
308 if (!d->verticalOnly) {
309 diff_f = (cpointer().scene_x() - d->sceneXStartPos) * d->sv->timeref_scalefactor;
310 }
311
312 // If the moved distance (diff_f) makes as go beyond the left most position (== 0, or TimeRef())
313 // set the newTrackStartLocation to 0. Else calculate it based on the original track start location
314 // and the distance moved.
315 TimeRef newTrackStartLocation;
316 if (diff_f < TimeRef() && m_trackStartLocation < (-1 * diff_f)) {
317 newTrackStartLocation = qint64(0);
318 } else {
319 newTrackStartLocation = m_trackStartLocation + diff_f;
320 }
321
322 // substract the snap distance, if snap is turned on.
323 if (m_sheet->is_snap_on() && !d->verticalOnly) {
324 newTrackStartLocation -= m_sheet->get_snap_list()->calculate_snap_diff(newTrackStartLocation, newTrackStartLocation + m_group.get_length());
325 }
326
327 // Now that the new track start location is known, the position diff can be calculated
328 m_posDiff = newTrackStartLocation - m_trackStartLocation;
329
330 // and used to move the group to it's new location.
331 m_group.move_to(m_newTrackIndex, m_trackStartLocation + m_posDiff);
332
333 // and used to move the markers
334 foreach(MarkerAndOrigin markerAndOrigin, m_markers) {
335 markerAndOrigin.marker->set_when(markerAndOrigin.origin + m_posDiff);
336 }
337
338 d->sv->update_shuttle_factor();
339
340 cpointer().get_viewport()->set_holdcursor_pos(d->sv->get_clips_viewport()->mapToScene(cpointer().pos()).toPoint());
341 cpointer().get_viewport()->set_holdcursor_text(timeref_to_text(newTrackStartLocation, d->sv->timeref_scalefactor));
342
343
344 return 1;
345 }
346
347
next_snap_pos(bool autorepeat)348 void MoveClip::next_snap_pos(bool autorepeat)
349 {
350 Q_UNUSED(autorepeat);
351 do_prev_next_snap(m_sheet->get_snap_list()->next_snap_pos(m_group.get_track_start_location()),
352 m_sheet->get_snap_list()->next_snap_pos(m_group.get_track_end_location()));
353 }
354
prev_snap_pos(bool autorepeat)355 void MoveClip::prev_snap_pos(bool autorepeat)
356 {
357 Q_UNUSED(autorepeat);
358 do_prev_next_snap(m_sheet->get_snap_list()->prev_snap_pos(m_group.get_track_start_location()),
359 m_sheet->get_snap_list()->prev_snap_pos(m_group.get_track_end_location()));
360 }
361
do_prev_next_snap(TimeRef trackStartLocation,TimeRef trackEndLocation)362 void MoveClip::do_prev_next_snap(TimeRef trackStartLocation, TimeRef trackEndLocation)
363 {
364 if (d->verticalOnly) return;
365 ie().bypass_jog_until_mouse_movements_exceeded_manhattenlength();
366 trackStartLocation -= m_sheet->get_snap_list()->calculate_snap_diff(trackStartLocation, trackEndLocation);
367 m_posDiff = trackStartLocation - m_trackStartLocation;
368 do_move();
369 }
370
move_to_start(bool autorepeat)371 void MoveClip::move_to_start(bool autorepeat)
372 {
373 Q_UNUSED(autorepeat);
374 m_group.move_to(m_group.get_track_index(), TimeRef());
375 }
376
move_to_end(bool autorepeat)377 void MoveClip::move_to_end(bool autorepeat)
378 {
379 Q_UNUSED(autorepeat);
380 m_group.move_to(m_group.get_track_index(), m_sheet->get_last_location());
381 }
382
move_up(bool autorepeat)383 void MoveClip::move_up(bool autorepeat)
384 {
385 Q_UNUSED(autorepeat);
386 ie().bypass_jog_until_mouse_movements_exceeded_manhattenlength();
387 int deltaTrackIndex = -1;
388 m_group.check_valid_track_index_delta(deltaTrackIndex);
389 m_newTrackIndex = m_newTrackIndex + deltaTrackIndex;
390 do_move();
391 }
392
move_down(bool autorepeat)393 void MoveClip::move_down(bool autorepeat)
394 {
395 Q_UNUSED(autorepeat);
396 ie().bypass_jog_until_mouse_movements_exceeded_manhattenlength();
397 int deltaTrackIndex = 1;
398 m_group.check_valid_track_index_delta(deltaTrackIndex);
399 m_newTrackIndex = m_newTrackIndex + deltaTrackIndex;
400 do_move();
401 }
402
move_left(bool autorepeat)403 void MoveClip::move_left(bool autorepeat)
404 {
405 Q_UNUSED(autorepeat);
406 if (d->verticalOnly) return;
407 ie().bypass_jog_until_mouse_movements_exceeded_manhattenlength();
408 m_posDiff -= d->sv->timeref_scalefactor;
409 do_move();
410 }
411
move_right(bool autorepeat)412 void MoveClip::move_right(bool autorepeat)
413 {
414 Q_UNUSED(autorepeat);
415 if (d->verticalOnly) return;
416 ie().bypass_jog_until_mouse_movements_exceeded_manhattenlength();
417 m_posDiff += d->sv->timeref_scalefactor;
418 do_move();
419 }
420
start_zoom(bool autorepeat)421 void MoveClip::start_zoom(bool autorepeat)
422 {
423 if (autorepeat) return;
424
425 if (!d->zoom) {
426 d->zoom = new Zoom(d->sv, QList<QVariant>() << "HJogZoom" << "1.2" << "0.2");
427 d->zoom->begin_hold();
428 cpointer().get_viewport()->set_holdcursor(":/cursorZoomHorizontal");
429 d->sv->start_shuttle(false);
430 } else {
431 cpointer().get_viewport()->set_holdcursor(":/cursorHoldLrud");
432 d->sv->start_shuttle(true, true);
433 }
434 }
435
set_cursor_shape(int useX,int useY)436 void MoveClip::set_cursor_shape(int useX, int useY)
437 {
438 if (useX && useY) {
439 cpointer().get_viewport()->set_holdcursor(":/cursorHoldLrud");
440 } else if (useX) {
441 cpointer().get_viewport()->set_holdcursor(":/cursorHoldLr");
442 } else {
443 cpointer().get_viewport()->set_holdcursor(":/cursorHoldUd");
444 }
445 }
446
toggle_vertical_only(bool autorepeat)447 void MoveClip::toggle_vertical_only(bool autorepeat)
448 {
449 if (autorepeat) return;
450
451 d->verticalOnly = !d->verticalOnly;
452 if (d->verticalOnly) {
453 set_cursor_shape(0, 1);
454 } else {
455 set_cursor_shape(1, 1);
456 }
457 }
458
do_move()459 void MoveClip::do_move()
460 {
461 m_group.move_to(m_newTrackIndex, m_trackStartLocation + m_posDiff);
462 if (d) {
463 cpointer().get_viewport()->set_holdcursor_text(timeref_to_text(m_trackStartLocation + m_posDiff, d->sv->timeref_scalefactor));
464 }
465 }
466