First cut of some Pro-tools inspired editing features; linked play/play range
[ardour.git] / gtk2_ardour / editor_drag.h
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __gtk2_ardour_editor_drag_h_
21 #define __gtk2_ardour_editor_drag_h_
22
23 #include <list>
24
25 #include <gdk/gdk.h>
26 #include <stdint.h>
27
28 #include "ardour/types.h"
29
30 #include "canvas.h"
31 #include "editor_items.h"
32
33 namespace ARDOUR {
34         class Location;
35 }
36
37 class Editor;
38 class EditorCursor;
39 class TimeAxisView;
40
41 /** Abstract base class for dragging of things within the editor */
42 class Drag
43 {
44
45 public:
46         Drag (Editor *, ArdourCanvas::Item *);
47         virtual ~Drag () {}
48
49         /** @return the canvas item being dragged */
50         ArdourCanvas::Item* item () const {
51                 return _item;
52         }
53
54         void swap_grab (ArdourCanvas::Item *, Gdk::Cursor *, uint32_t);
55         void break_drag ();
56
57         bool motion_handler (GdkEvent*, bool);
58
59         /** @return true if an end drag is in progress */
60         bool ending () const {
61                 return _ending;
62         }
63
64         /** @return current pointer x position in trackview coordinates */
65         double current_pointer_x () const {
66                 return _current_pointer_x;
67         }
68
69         /** @return current pointer y position in trackview coordinates */
70         double current_pointer_y () const {
71                 return _current_pointer_y;
72         }
73
74         nframes64_t adjusted_current_frame (GdkEvent const *, bool snap = true) const;
75         
76         /** Called to start a grab of an item.
77          *  @param e Event that caused the grab to start.
78          *  @param c Cursor to use, or 0.
79          */
80         virtual void start_grab (GdkEvent* e, Gdk::Cursor* c = 0);
81
82         virtual bool end_grab (GdkEvent *);
83
84         /** Called when a drag motion has occurred.
85          *  @param e Event describing the motion.
86          *  @param f true if this is the first movement, otherwise false.
87          */
88         virtual void motion (GdkEvent* e, bool f) = 0;
89
90         /** Called when a drag has finished.
91          *  @param e Event describing the finish.
92          *  @param m true if some movement occurred, otherwise false.
93          */
94         virtual void finished (GdkEvent* e, bool m) = 0;
95
96         /** @param m Mouse mode.
97          *  @return true if this drag should happen in this mouse mode.
98          */
99         virtual bool active (Editing::MouseMode m) {
100                 return (m != Editing::MouseGain);
101         }
102
103         /** @return true if a small threshold should be applied before a mouse movement
104          *  is considered a drag, otherwise false.
105          */
106         virtual bool apply_move_threshold () const {
107                 return false;
108         }
109
110         virtual bool allow_vertical_autoscroll () const {
111                 return true;
112         }
113
114 protected:
115
116         double grab_x () const {
117                 return _grab_x;
118         }
119
120         double grab_y () const {
121                 return _grab_y;
122         }
123
124         double grab_frame () const {
125                 return _grab_frame;
126         }
127
128         double last_pointer_x () const {
129                 return _last_pointer_x;
130         }
131
132         double last_pointer_y () const {
133                 return _last_pointer_y;
134         }
135
136         double last_pointer_frame () const {
137                 return _last_pointer_frame;
138         }
139
140         Editor* _editor; ///< our editor
141         ArdourCanvas::Item* _item; ///< our item
142         /** Offset from the mouse's position for the drag to the start of the thing that is being dragged */
143         nframes64_t _pointer_frame_offset;
144         bool _x_constrained; ///< true if x motion is constrained, otherwise false
145         bool _y_constrained; ///< true if y motion is constrained, otherwise false
146         bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
147         bool _have_transaction; ///< true if a transaction has been started, false otherwise. Must be set true by derived class.
148
149 private:
150
151         bool _ending; ///< true if end_grab is in progress, otherwise false
152         bool _had_movement; ///< true if movement has occurred, otherwise false
153         bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
154         double _original_x; ///< original world x of the thing being dragged
155         double _original_y; ///< original world y of the thing being dragged
156         double _grab_x; ///< trackview x of the grab start position
157         double _grab_y; ///< trackview y of the grab start position
158         double _current_pointer_x; ///< trackview x of the current pointer
159         double _current_pointer_y; ///< trackview y of the current pointer
160         double _last_pointer_x; ///< trackview x of the pointer last time a motion occurred
161         double _last_pointer_y; ///< trackview y of the pointer last time a motion occurred
162         nframes64_t _grab_frame; ///< frame that the mouse was at when start_grab was called, or 0
163         nframes64_t _last_pointer_frame; ///< adjusted_current_frame the last time a motion occurred
164         nframes64_t _current_pointer_frame; ///< frame that the pointer is now at
165 };
166
167
168 /** Abstract base class for drags that involve region(s) */
169 class RegionDrag : public Drag, public sigc::trackable
170 {
171 public:
172         RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
173         virtual ~RegionDrag () {}
174
175 protected:
176
177         RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
178         std::list<RegionView*> _views; ///< all views that are being dragged
179
180 private:
181         void region_going_away (RegionView *);
182         PBD::ScopedConnection death_connection;
183 };
184
185
186 /** Drags involving region motion from somewhere */
187 class RegionMotionDrag : public RegionDrag
188 {
189 public:
190
191         RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
192         virtual ~RegionMotionDrag () {}
193
194         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
195         virtual void motion (GdkEvent *, bool);
196         virtual void finished (GdkEvent *, bool) = 0;
197
198 protected:
199         struct TimeAxisViewSummary {
200                 TimeAxisViewSummary () : height_list(512) {}
201
202                 std::bitset<512> tracks;
203                 std::vector<int32_t> height_list;
204                 int visible_y_low;
205                 int visible_y_high;
206         };
207
208         void copy_regions (GdkEvent *);
209         bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
210         std::map<RegionView*, std::pair<RouteTimeAxisView*, int> > find_time_axis_views_and_layers ();
211         double compute_x_delta (GdkEvent const *, nframes64_t *);
212         bool compute_y_delta (
213                 TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
214                 int32_t *, int32_t *, int32_t *
215                 );
216
217         TimeAxisViewSummary get_time_axis_view_summary ();
218         bool x_move_allowed () const;
219
220         TimeAxisView* _dest_trackview;
221         ARDOUR::layer_t _dest_layer;
222         bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
223         bool _brushing;
224         nframes64_t _last_frame_position; ///< last position of the thing being dragged
225 };
226
227
228 /** Drags to move (or copy) regions that are already shown in the GUI to
229  *  somewhere different.
230  */
231 class RegionMoveDrag : public RegionMotionDrag
232 {
233 public:
234         RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
235         virtual ~RegionMoveDrag () {}
236
237         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
238         void motion (GdkEvent *, bool);
239         void finished (GdkEvent *, bool);
240
241         bool apply_move_threshold () const {
242                 return true;
243         }
244
245 private:
246         bool _copy;
247 };
248
249 /** Drag to insert a region from somewhere */
250 class RegionInsertDrag : public RegionMotionDrag
251 {
252 public:
253         RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
254
255         void finished (GdkEvent *, bool);
256 };
257
258 /** Region drag in splice mode */
259 class RegionSpliceDrag : public RegionMoveDrag
260 {
261 public:
262         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
263
264         void motion (GdkEvent *, bool);
265         void finished (GdkEvent *, bool);
266 };
267
268 /** Drags to create regions */
269 class RegionCreateDrag : public Drag
270 {
271 public:
272         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
273
274         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
275         void motion (GdkEvent *, bool);
276         void finished (GdkEvent *, bool);
277
278 private:
279         TimeAxisView* _view;
280         TimeAxisView* _dest_trackview;
281 };
282
283 /** Drags to resize MIDI notes */
284 class NoteResizeDrag : public Drag
285 {
286 public:
287         NoteResizeDrag (Editor *, ArdourCanvas::Item *);
288
289         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
290         void motion (GdkEvent *, bool);
291         void finished (GdkEvent *, bool);
292
293 private:
294         MidiRegionView*     region;
295         bool                relative;
296         bool                at_front;
297 };
298
299 class NoteDrag : public Drag
300 {
301   public:
302         NoteDrag (Editor*, ArdourCanvas::Item*);
303
304         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
305         void motion (GdkEvent *, bool);
306         void finished (GdkEvent *, bool);
307
308   private:
309         MidiRegionView* region;
310         double last_x;
311         double last_y;
312         double drag_delta_x;
313         double drag_delta_note;
314         bool   was_selected;
315 };
316
317 /** Drag of region gain */
318 class RegionGainDrag : public Drag
319 {
320 public:
321         RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
322
323         void motion (GdkEvent *, bool);
324         void finished (GdkEvent *, bool);
325         bool active (Editing::MouseMode m) {
326                 return (m == Editing::MouseGain);
327         }
328 };
329
330 /** Drag to trim region(s) */
331 class TrimDrag : public RegionDrag
332 {
333 public:
334         enum Operation {
335                 StartTrim,
336                 EndTrim,
337                 ContentsTrim,
338         };
339
340         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
341
342         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
343         void motion (GdkEvent *, bool);
344         void finished (GdkEvent *, bool);
345
346 private:
347
348         Operation _operation;
349 };
350
351 /** Meter marker drag */
352 class MeterMarkerDrag : public Drag
353 {
354 public:
355         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
356
357         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
358         void motion (GdkEvent *, bool);
359         void finished (GdkEvent *, bool);
360
361         bool allow_vertical_autoscroll () const {
362                 return false;
363         }
364         
365 private:
366         MeterMarker* _marker;
367         bool _copy;
368 };
369
370 /** Tempo marker drag */
371 class TempoMarkerDrag : public Drag
372 {
373 public:
374         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
375
376         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
377         void motion (GdkEvent *, bool);
378         void finished (GdkEvent *, bool);
379
380         bool allow_vertical_autoscroll () const {
381                 return false;
382         }
383
384 private:
385         TempoMarker* _marker;
386         bool _copy;
387 };
388
389
390 /** Drag of a cursor */
391 class CursorDrag : public Drag
392 {
393 public:
394         CursorDrag (Editor *, ArdourCanvas::Item *, bool);
395
396         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
397         void motion (GdkEvent *, bool);
398         void finished (GdkEvent *, bool);
399
400         bool active (Editing::MouseMode) {
401                 return true;
402         }
403
404         bool allow_vertical_autoscroll () const {
405                 return false;
406         }
407
408 private:
409         EditorCursor* _cursor; ///< cursor being dragged
410         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
411
412 };
413
414 /** Region fade-in drag */
415 class FadeInDrag : public RegionDrag
416 {
417 public:
418         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
419
420         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
421         void motion (GdkEvent *, bool);
422         void finished (GdkEvent *, bool);
423 };
424
425 /** Region fade-out drag */
426 class FadeOutDrag : public RegionDrag
427 {
428 public:
429         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
430
431         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
432         void motion (GdkEvent *, bool);
433         void finished (GdkEvent *, bool);
434 };
435
436 /** Marker drag */
437 class MarkerDrag : public Drag
438 {
439 public:
440         MarkerDrag (Editor *, ArdourCanvas::Item *);
441         ~MarkerDrag ();
442
443         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
444         void motion (GdkEvent *, bool);
445         void finished (GdkEvent *, bool);
446
447         bool allow_vertical_autoscroll () const {
448                 return false;
449         }
450         
451 private:
452         void update_item (ARDOUR::Location *);
453
454         Marker* _marker; ///< marker being dragged
455         std::list<ARDOUR::Location*> _copied_locations;
456         ArdourCanvas::Line* _line;
457         ArdourCanvas::Points _points;
458 };
459
460 /** Control point drag */
461 class ControlPointDrag : public Drag
462 {
463 public:
464         ControlPointDrag (Editor *, ArdourCanvas::Item *);
465
466         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
467         void motion (GdkEvent *, bool);
468         void finished (GdkEvent *, bool);
469
470         bool active (Editing::MouseMode m);
471
472 private:
473
474         ControlPoint* _point;
475         double _time_axis_view_grab_x;
476         double _time_axis_view_grab_y;
477         double _cumulative_x_drag;
478         double _cumulative_y_drag;
479         static double const _zero_gain_fraction;
480 };
481
482 /** Gain or automation line drag */
483 class LineDrag : public Drag
484 {
485 public:
486         LineDrag (Editor *e, ArdourCanvas::Item *i);
487
488         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
489         void motion (GdkEvent *, bool);
490         void finished (GdkEvent *, bool);
491
492         bool active (Editing::MouseMode) {
493                 return true;
494         }
495
496 private:
497
498         AutomationLine* _line;
499         double _time_axis_view_grab_x;
500         double _time_axis_view_grab_y;
501         uint32_t _before;
502         uint32_t _after;
503         double _cumulative_y_drag;
504 };
505
506 /** Dragging of a rubberband rectangle for selecting things */
507 class RubberbandSelectDrag : public Drag
508 {
509 public:
510         RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
511
512         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
513         void motion (GdkEvent *, bool);
514         void finished (GdkEvent *, bool);
515 };
516
517 /** Region drag in time-FX mode */
518 class TimeFXDrag : public RegionDrag
519 {
520 public:
521         TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
522
523         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
524         void motion (GdkEvent *, bool);
525         void finished (GdkEvent *, bool);
526 };
527
528 /** Scrub drag in audition mode */
529 class ScrubDrag : public Drag
530 {
531 public:
532         ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
533
534         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
535         void motion (GdkEvent *, bool);
536         void finished (GdkEvent *, bool);
537 };
538
539 /** Drag in range select mode */
540 class SelectionDrag : public Drag
541 {
542 public:
543         enum Operation {
544                 CreateSelection,
545                 SelectionStartTrim,
546                 SelectionEndTrim,
547                 SelectionMove
548         };
549
550         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
551
552         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
553         void motion (GdkEvent *, bool);
554         void finished (GdkEvent *, bool);
555
556 private:
557         Operation _operation;
558         bool _copy;
559         int _original_pointer_time_axis;
560         int _last_pointer_time_axis;
561         std::list<TimeAxisView*> _added_time_axes;
562 };
563
564 /** Range marker drag */
565 class RangeMarkerBarDrag : public Drag
566 {
567 public:
568         enum Operation {
569                 CreateRangeMarker,
570                 CreateTransportMarker,
571                 CreateCDMarker
572         };
573
574         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
575
576         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
577         void motion (GdkEvent *, bool);
578         void finished (GdkEvent *, bool);
579
580 private:
581         void update_item (ARDOUR::Location *);
582
583         Operation _operation;
584         ArdourCanvas::SimpleRect* _drag_rect;
585         bool _copy;
586 };
587
588 /** Drag of rectangle to set zoom */
589 class MouseZoomDrag : public Drag
590 {
591 public:
592         MouseZoomDrag (Editor* e, ArdourCanvas::Item *i) : Drag (e, i) {}
593
594         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
595         void motion (GdkEvent *, bool);
596         void finished (GdkEvent *, bool);
597 };
598
599 /** Drag of a range of automation data, changing value but not position */
600 class AutomationRangeDrag : public Drag
601 {
602 public:
603         AutomationRangeDrag (Editor *, ArdourCanvas::Item *, std::list<ARDOUR::AudioRange> const &);
604
605         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
606         void motion (GdkEvent *, bool);
607         void finished (GdkEvent *, bool);
608
609 private:
610         std::list<ARDOUR::AudioRange> _ranges;
611         AutomationTimeAxisView* _atav;
612         boost::shared_ptr<AutomationLine> _line;
613         bool _nothing_to_drag;
614 };
615
616 #endif /* __gtk2_ardour_editor_drag_h_ */
617