16ef6c4678781498e058358cf262f897fae20231
[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         bool motion_handler (GdkEvent*, bool);
56         void break_drag ();
57
58         /** @return true if an end drag is in progress */
59         bool ending () const {
60                 return _ending;
61         }
62
63         /** @return current pointer x position in trackview coordinates */
64         double current_pointer_x () const {
65                 return _current_pointer_x;
66         }
67
68         /** @return current pointer y position in trackview coordinates */
69         double current_pointer_y () const {
70                 return _current_pointer_y;
71         }
72
73         nframes64_t adjusted_frame (nframes64_t, GdkEvent const *, bool snap = true) const;
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         /** Called to abort a drag and return things to how
97          *  they were before it started.
98          */
99         virtual void aborted () = 0;
100
101         /** @param m Mouse mode.
102          *  @return true if this drag should happen in this mouse mode.
103          */
104         virtual bool active (Editing::MouseMode m) {
105                 return (m != Editing::MouseGain);
106         }
107
108         /** @return minimum number of frames (in x) and pixels (in y) that should be considered a movement */
109         virtual std::pair<nframes64_t, int> move_threshold () const {
110                 return std::make_pair (1, 1);
111         }
112
113         virtual bool allow_vertical_autoscroll () const {
114                 return true;
115         }
116
117         /** @return true if x movement matters to this drag */
118         virtual bool x_movement_matters () const {
119                 return true;
120         }
121
122         /** @return true if y movement matters to this drag */
123         virtual bool y_movement_matters () const {
124                 return true;
125         }
126
127         /** @return current x extent of the thing being dragged; ie
128          *  a pair of (leftmost_position, rightmost_position)
129          */
130         virtual std::pair<nframes64_t, nframes64_t> extent () const;
131
132 protected:
133
134         double grab_x () const {
135                 return _grab_x;
136         }
137
138         double grab_y () const {
139                 return _grab_y;
140         }
141
142         double grab_frame () const {
143                 return _grab_frame;
144         }
145
146         double last_pointer_x () const {
147                 return _last_pointer_x;
148         }
149
150         double last_pointer_y () const {
151                 return _last_pointer_y;
152         }
153
154         double last_pointer_frame () const {
155                 return _last_pointer_frame;
156         }
157
158         Editor* _editor; ///< our editor
159         ArdourCanvas::Item* _item; ///< our item
160         /** Offset from the mouse's position for the drag to the start of the thing that is being dragged */
161         nframes64_t _pointer_frame_offset;
162         bool _x_constrained; ///< true if x motion is constrained, otherwise false
163         bool _y_constrained; ///< true if y motion is constrained, otherwise false
164         bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
165         bool _have_transaction; ///< true if a transaction has been started, false otherwise. Must be set true by derived class.
166
167 private:
168
169         bool _ending; ///< true if end_grab or break_drag is in progress, otherwise false
170         bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
171         double _grab_x; ///< trackview x of the grab start position
172         double _grab_y; ///< trackview y of the grab start position
173         double _current_pointer_x; ///< trackview x of the current pointer
174         double _current_pointer_y; ///< trackview y of the current pointer
175         double _last_pointer_x; ///< trackview x of the pointer last time a motion occurred
176         double _last_pointer_y; ///< trackview y of the pointer last time a motion occurred
177         nframes64_t _grab_frame; ///< adjusted_frame that the mouse was at when start_grab was called, or 0
178         nframes64_t _last_pointer_frame; ///< adjusted_frame the last time a motion occurred
179         nframes64_t _current_pointer_frame; ///< frame that the pointer is now at
180 };
181
182
183 /** Abstract base class for drags that involve region(s) */
184 class RegionDrag : public Drag, public sigc::trackable
185 {
186 public:
187         RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
188         virtual ~RegionDrag () {}
189
190         std::pair<nframes64_t, nframes64_t> extent () const;
191
192 protected:
193
194         RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
195         std::list<RegionView*> _views; ///< all views that are being dragged
196
197 private:
198         void region_going_away (RegionView *);
199         PBD::ScopedConnection death_connection;
200 };
201
202
203 /** Drags involving region motion from somewhere */
204 class RegionMotionDrag : public RegionDrag
205 {
206 public:
207
208         RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
209         virtual ~RegionMotionDrag () {}
210
211         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
212         virtual void motion (GdkEvent *, bool);
213         virtual void finished (GdkEvent *, bool) = 0;
214         virtual void aborted ();
215
216 protected:
217         struct TimeAxisViewSummary {
218                 TimeAxisViewSummary () : height_list(512) {}
219
220                 std::bitset<512> tracks;
221                 std::vector<int32_t> height_list;
222                 int visible_y_low;
223                 int visible_y_high;
224         };
225
226         void copy_regions (GdkEvent *);
227         bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
228         std::map<RegionView*, std::pair<RouteTimeAxisView*, int> > find_time_axis_views_and_layers ();
229         double compute_x_delta (GdkEvent const *, nframes64_t *);
230         bool compute_y_delta (
231                 TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
232                 int32_t *, int32_t *, int32_t *
233                 );
234
235         TimeAxisViewSummary get_time_axis_view_summary ();
236         bool x_move_allowed () const;
237
238         TimeAxisView* _dest_trackview;
239         ARDOUR::layer_t _dest_layer;
240         bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
241         bool _brushing;
242         nframes64_t _last_frame_position; ///< last position of the thing being dragged
243         double _total_x_delta;
244 };
245
246
247 /** Drags to move (or copy) regions that are already shown in the GUI to
248  *  somewhere different.
249  */
250 class RegionMoveDrag : public RegionMotionDrag
251 {
252 public:
253         RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
254         virtual ~RegionMoveDrag () {}
255
256         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
257         void motion (GdkEvent *, bool);
258         void finished (GdkEvent *, bool);
259         void aborted ();
260
261         std::pair<nframes64_t, int> move_threshold () const {
262                 return std::make_pair (4, 4);
263         }
264
265 private:
266         bool _copy;
267 };
268
269 /** Drag to insert a region from somewhere */
270 class RegionInsertDrag : public RegionMotionDrag
271 {
272 public:
273         RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
274
275         void finished (GdkEvent *, bool);
276         void aborted ();
277 };
278
279 /** Region drag in splice mode */
280 class RegionSpliceDrag : public RegionMoveDrag
281 {
282 public:
283         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
284
285         void motion (GdkEvent *, bool);
286         void finished (GdkEvent *, bool);
287         void aborted ();
288 };
289
290 /** Drags to create regions */
291 class RegionCreateDrag : public Drag
292 {
293 public:
294         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
295
296         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
297         void motion (GdkEvent *, bool);
298         void finished (GdkEvent *, bool);
299         void aborted ();
300
301 private:
302         TimeAxisView* _view;
303         TimeAxisView* _dest_trackview;
304 };
305
306 /** Drags to resize MIDI notes */
307 class NoteResizeDrag : public Drag
308 {
309 public:
310         NoteResizeDrag (Editor *, ArdourCanvas::Item *);
311
312         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
313         void motion (GdkEvent *, bool);
314         void finished (GdkEvent *, bool);
315         void aborted ();
316
317 private:
318         MidiRegionView*     region;
319         bool                relative;
320         bool                at_front;
321 };
322
323 class NoteDrag : public Drag
324 {
325   public:
326         NoteDrag (Editor*, ArdourCanvas::Item*);
327
328         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
329         void motion (GdkEvent *, bool);
330         void finished (GdkEvent *, bool);
331         void aborted ();
332
333   private:
334         MidiRegionView* region;
335         double last_x;
336         double last_y;
337         double drag_delta_x;
338         double drag_delta_note;
339         bool   was_selected;
340 };
341
342 /** Drag of region gain */
343 class RegionGainDrag : public Drag
344 {
345 public:
346         RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
347
348         void motion (GdkEvent *, bool);
349         void finished (GdkEvent *, bool);
350         bool active (Editing::MouseMode m) {
351                 return (m == Editing::MouseGain);
352         }
353
354         void aborted ();
355 };
356
357 /** Drag to trim region(s) */
358 class TrimDrag : public RegionDrag
359 {
360 public:
361         enum Operation {
362                 StartTrim,
363                 EndTrim,
364                 ContentsTrim,
365         };
366
367         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
368
369         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
370         void motion (GdkEvent *, bool);
371         void finished (GdkEvent *, bool);
372         void aborted ();
373
374         bool y_movement_matters () const {
375                 return false;
376         }
377
378 private:
379
380         Operation _operation;
381 };
382
383 /** Meter marker drag */
384 class MeterMarkerDrag : public Drag
385 {
386 public:
387         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
388
389         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
390         void motion (GdkEvent *, bool);
391         void finished (GdkEvent *, bool);
392         void aborted ();
393
394         bool allow_vertical_autoscroll () const {
395                 return false;
396         }
397
398         bool y_movement_matters () const {
399                 return false;
400         }
401         
402 private:
403         MeterMarker* _marker;
404         bool _copy;
405 };
406
407 /** Tempo marker drag */
408 class TempoMarkerDrag : public Drag
409 {
410 public:
411         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
412
413         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
414         void motion (GdkEvent *, bool);
415         void finished (GdkEvent *, bool);
416         void aborted ();
417
418         bool allow_vertical_autoscroll () const {
419                 return false;
420         }
421
422         bool y_movement_matters () const {
423                 return false;
424         }
425
426 private:
427         TempoMarker* _marker;
428         bool _copy;
429 };
430
431
432 /** Drag of a cursor */
433 class CursorDrag : public Drag
434 {
435 public:
436         CursorDrag (Editor *, ArdourCanvas::Item *, bool);
437
438         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
439         void motion (GdkEvent *, bool);
440         void finished (GdkEvent *, bool);
441         void aborted ();
442
443         bool active (Editing::MouseMode) {
444                 return true;
445         }
446
447         bool allow_vertical_autoscroll () const {
448                 return false;
449         }
450
451         bool y_movement_matters () const {
452                 return false;
453         }
454
455 private:
456         EditorCursor* _cursor; ///< cursor being dragged
457         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
458
459 };
460
461 /** Region fade-in drag */
462 class FadeInDrag : public RegionDrag
463 {
464 public:
465         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
466
467         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
468         void motion (GdkEvent *, bool);
469         void finished (GdkEvent *, bool);
470         void aborted ();
471
472         bool y_movement_matters () const {
473                 return false;
474         }
475 };
476
477 /** Region fade-out drag */
478 class FadeOutDrag : public RegionDrag
479 {
480 public:
481         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
482
483         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
484         void motion (GdkEvent *, bool);
485         void finished (GdkEvent *, bool);
486         void aborted ();
487
488         bool y_movement_matters () const {
489                 return false;
490         }
491 };
492
493 /** Marker drag */
494 class MarkerDrag : public Drag
495 {
496 public:
497         MarkerDrag (Editor *, ArdourCanvas::Item *);
498         ~MarkerDrag ();
499
500         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
501         void motion (GdkEvent *, bool);
502         void finished (GdkEvent *, bool);
503         void aborted ();
504
505         bool allow_vertical_autoscroll () const {
506                 return false;
507         }
508
509         bool y_movement_matters () const {
510                 return false;
511         }
512         
513 private:
514         void update_item (ARDOUR::Location *);
515
516         Marker* _marker; ///< marker being dragged
517         std::list<ARDOUR::Location*> _copied_locations;
518         ArdourCanvas::Line* _line;
519         ArdourCanvas::Points _points;
520 };
521
522 /** Control point drag */
523 class ControlPointDrag : public Drag
524 {
525 public:
526         ControlPointDrag (Editor *, ArdourCanvas::Item *);
527
528         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
529         void motion (GdkEvent *, bool);
530         void finished (GdkEvent *, bool);
531         void aborted ();
532
533         bool active (Editing::MouseMode m);
534
535 private:
536
537         ControlPoint* _point;
538         double _time_axis_view_grab_x;
539         double _time_axis_view_grab_y;
540         double _cumulative_x_drag;
541         double _cumulative_y_drag;
542         static double const _zero_gain_fraction;
543 };
544
545 /** Gain or automation line drag */
546 class LineDrag : public Drag
547 {
548 public:
549         LineDrag (Editor *e, ArdourCanvas::Item *i);
550
551         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
552         void motion (GdkEvent *, bool);
553         void finished (GdkEvent *, bool);
554         void aborted ();
555
556         bool active (Editing::MouseMode) {
557                 return true;
558         }
559
560 private:
561
562         AutomationLine* _line;
563         double _time_axis_view_grab_x;
564         double _time_axis_view_grab_y;
565         uint32_t _before;
566         uint32_t _after;
567         double _cumulative_y_drag;
568 };
569
570 /** Dragging of a rubberband rectangle for selecting things */
571 class RubberbandSelectDrag : public Drag
572 {
573 public:
574         RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
575
576         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
577         void motion (GdkEvent *, bool);
578         void finished (GdkEvent *, bool);
579         void aborted ();
580 };
581
582 /** Region drag in time-FX mode */
583 class TimeFXDrag : public RegionDrag
584 {
585 public:
586         TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
587
588         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
589         void motion (GdkEvent *, bool);
590         void finished (GdkEvent *, bool);
591         void aborted ();
592 };
593
594 /** Scrub drag in audition mode */
595 class ScrubDrag : public Drag
596 {
597 public:
598         ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
599
600         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
601         void motion (GdkEvent *, bool);
602         void finished (GdkEvent *, bool);
603         void aborted ();
604 };
605
606 /** Drag in range select mode */
607 class SelectionDrag : public Drag
608 {
609 public:
610         enum Operation {
611                 CreateSelection,
612                 SelectionStartTrim,
613                 SelectionEndTrim,
614                 SelectionMove
615         };
616
617         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
618
619         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
620         void motion (GdkEvent *, bool);
621         void finished (GdkEvent *, bool);
622         void aborted ();
623
624 private:
625         Operation _operation;
626         bool _copy;
627         int _original_pointer_time_axis;
628         int _last_pointer_time_axis;
629         std::list<TimeAxisView*> _added_time_axes;
630 };
631
632 /** Range marker drag */
633 class RangeMarkerBarDrag : public Drag
634 {
635 public:
636         enum Operation {
637                 CreateRangeMarker,
638                 CreateTransportMarker,
639                 CreateCDMarker
640         };
641
642         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
643
644         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
645         void motion (GdkEvent *, bool);
646         void finished (GdkEvent *, bool);
647         void aborted ();
648
649         bool allow_vertical_autoscroll () const {
650                 return false;
651         }
652
653         bool y_movement_matters () const {
654                 return false;
655         }
656
657 private:
658         void update_item (ARDOUR::Location *);
659
660         Operation _operation;
661         ArdourCanvas::SimpleRect* _drag_rect;
662         bool _copy;
663 };
664
665 /** Drag of rectangle to set zoom */
666 class MouseZoomDrag : public Drag
667 {
668 public:
669         MouseZoomDrag (Editor* e, ArdourCanvas::Item *i) : Drag (e, i) {}
670
671         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
672         void motion (GdkEvent *, bool);
673         void finished (GdkEvent *, bool);
674         void aborted ();
675 };
676
677 /** Drag of a range of automation data, changing value but not position */
678 class AutomationRangeDrag : public Drag
679 {
680 public:
681         AutomationRangeDrag (Editor *, ArdourCanvas::Item *, std::list<ARDOUR::AudioRange> const &);
682
683         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
684         void motion (GdkEvent *, bool);
685         void finished (GdkEvent *, bool);
686         void aborted ();
687
688         bool x_movement_matters () const {
689                 return false;
690         }
691
692 private:
693         std::list<ARDOUR::AudioRange> _ranges;
694         AutomationTimeAxisView* _atav;
695         boost::shared_ptr<AutomationLine> _line;
696         bool _nothing_to_drag;
697 };
698
699 #endif /* __gtk2_ardour_editor_drag_h_ */
700