modifications to region drag implementation
[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 "editor_items.h"
31
32 namespace ARDOUR {
33         class Location;
34 }
35
36 namespace PBD {
37         class StatefulDiffCommand;
38 }
39
40 class PatchChange;
41 class Editor;
42 class EditorCursor;
43 class TimeAxisView;
44 class MidiTimeAxisView;
45 class Drag;
46 class NoteBase;
47
48 /** Class to manage current drags */
49 class DragManager
50 {
51 public:
52
53         DragManager (Editor* e);
54         ~DragManager ();
55
56         bool motion_handler (GdkEvent *, bool);
57
58         void abort ();
59         void add (Drag *);
60         void set (Drag *, GdkEvent *, Gdk::Cursor* c = 0);
61         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
62         bool end_grab (GdkEvent *);
63         bool have_item (ArdourCanvas::Item *) const;
64
65         void mark_double_click ();
66
67         /** @return true if an end drag or abort is in progress */
68         bool ending () const {
69                 return _ending;
70         }
71
72         bool active () const {
73                 return !_drags.empty ();
74         }
75
76         /** @return current pointer x position in canvas coordinates */
77         double current_pointer_x () const {
78                 return _current_pointer_x;
79         }
80
81         /** @return current pointer y position in canvas coordinates */
82         double current_pointer_y () const {
83                 return _current_pointer_y;
84         }
85
86         /** @return current pointer frame */
87         ARDOUR::framepos_t current_pointer_frame () const {
88                 return _current_pointer_frame;
89         }
90
91 private:
92         Editor* _editor;
93         std::list<Drag*> _drags;
94         bool _ending; ///< true if end_grab or abort is in progress, otherwise false
95         double _current_pointer_x; ///< canvas-coordinate space x of the current pointer
96         double _current_pointer_y; ///< canvas-coordinate space y of the current pointer
97         ARDOUR::framepos_t _current_pointer_frame; ///< frame that the pointer is now at
98         bool _old_follow_playhead; ///< state of Editor::follow_playhead() before the drags started
99 };
100
101 /** Abstract base class for dragging of things within the editor */
102 class Drag
103 {
104 public:
105         Drag (Editor *, ArdourCanvas::Item *, bool trackview_only = true);
106         virtual ~Drag () {}
107
108         void set_manager (DragManager* m) {
109                 _drags = m;
110         }
111
112         /** @return the canvas item being dragged */
113         ArdourCanvas::Item* item () const {
114                 return _item;
115         }
116
117         void swap_grab (ArdourCanvas::Item *, Gdk::Cursor *, uint32_t);
118         bool motion_handler (GdkEvent*, bool);
119         void abort ();
120
121         ARDOUR::framepos_t adjusted_frame (ARDOUR::framepos_t, GdkEvent const *, bool snap = true) const;
122         ARDOUR::framepos_t adjusted_current_frame (GdkEvent const *, bool snap = true) const;
123
124         bool was_double_click() const { return _was_double_click; }
125         void set_double_click (bool yn) { _was_double_click = yn; }
126
127         /** Called to start a grab of an item.
128          *  @param e Event that caused the grab to start.
129          *  @param c Cursor to use, or 0.
130          */
131         virtual void start_grab (GdkEvent* e, Gdk::Cursor* c = 0);
132
133         virtual bool end_grab (GdkEvent *);
134
135         /** Called when a drag motion has occurred.
136          *  @param e Event describing the motion.
137          *  @param f true if this is the first movement, otherwise false.
138          */
139         virtual void motion (GdkEvent* e, bool f) = 0;
140
141         /** Called when a drag has finished.
142          *  @param e Event describing the finish.
143          *  @param m true if some movement occurred, otherwise false.
144          */
145         virtual void finished (GdkEvent* e, bool m) = 0;
146
147         /** Called to abort a drag and return things to how
148          *  they were before it started.
149          *  @param m true if some movement occurred, otherwise false.
150          */
151         virtual void aborted (bool m) = 0;
152
153         /** @param m Mouse mode.
154          *  @return true if this drag should happen in this mouse mode.
155          */
156         virtual bool active (Editing::MouseMode m) {
157                 return (m != Editing::MouseGain);
158         }
159
160         /** @return minimum number of frames (in x) and pixels (in y) that should be considered a movement */
161         virtual std::pair<ARDOUR::framecnt_t, int> move_threshold () const {
162                 return std::make_pair (1, 1);
163         }
164
165         virtual bool allow_vertical_autoscroll () const {
166                 return true;
167         }
168
169         /** @return true if x movement matters to this drag */
170         virtual bool x_movement_matters () const {
171                 return true;
172         }
173
174         /** @return true if y movement matters to this drag */
175         virtual bool y_movement_matters () const {
176                 return true;
177         }
178
179         /** Set up the _pointer_frame_offset */
180         virtual void setup_pointer_frame_offset () {
181                 _pointer_frame_offset = 0;
182         }
183
184 protected:
185
186         double grab_x () const {
187                 return _grab_x;
188         }
189
190         double grab_y () const {
191                 return _grab_y;
192         }
193
194         ARDOUR::framepos_t raw_grab_frame () const {
195                 return _raw_grab_frame;
196         }
197
198         ARDOUR::framepos_t grab_frame () const {
199                 return _grab_frame;
200         }
201
202         double last_pointer_x () const {
203                 return _last_pointer_x;
204         }
205
206         double last_pointer_y () const {
207                 return _last_pointer_y;
208         }
209
210         double last_pointer_frame () const {
211                 return _last_pointer_frame;
212         }
213
214         double current_pointer_y () const;
215
216         boost::shared_ptr<ARDOUR::Region> add_midi_region (MidiTimeAxisView*);
217
218         void show_verbose_cursor_time (framepos_t);
219         void show_verbose_cursor_duration (framepos_t, framepos_t, double xoffset = 0);
220         void show_verbose_cursor_text (std::string const &);
221
222         Editor* _editor; ///< our editor
223         DragManager* _drags;
224         ArdourCanvas::Item* _item; ///< our item
225         /** Offset from the mouse's position for the drag to the start of the thing that is being dragged */
226         ARDOUR::framecnt_t _pointer_frame_offset;
227         bool _x_constrained; ///< true if x motion is constrained, otherwise false
228         bool _y_constrained; ///< true if y motion is constrained, otherwise false
229         bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
230
231 private:
232         bool _trackview_only; ///< true if pointer y value should always be relative to the top of the trackview group
233         bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
234         bool _was_double_click; ///< true if drag initiated by a double click event
235         double _grab_x; ///< trackview x of the grab start position
236         double _grab_y; ///< y of the grab start position, possibly adjusted if _trackview_only is true
237         double _last_pointer_x; ///< trackview x of the pointer last time a motion occurred
238         double _last_pointer_y; ///< trackview y of the pointer last time a motion occurred
239         ARDOUR::framepos_t _raw_grab_frame; ///< unsnapped frame that the mouse was at when start_grab was called, or 0
240         ARDOUR::framepos_t _grab_frame; ///< adjusted_frame that the mouse was at when start_grab was called, or 0
241         ARDOUR::framepos_t _last_pointer_frame; ///< adjusted_frame the last time a motion occurred
242 };
243
244 class RegionDrag;
245
246 /** Container for details about a region being dragged */
247 class DraggingView
248 {
249 public:
250         DraggingView (RegionView *, RegionDrag *, TimeAxisView* original_tav);
251
252         RegionView* view; ///< the view
253         /** index into RegionDrag::_time_axis_views of the view that this region is currently being displayed on,
254          *  or -1 if it is not visible.
255          */
256         int time_axis_view;
257         /** layer that this region is currently being displayed on.  This is a double
258             rather than a layer_t as we use fractional layers during drags to allow the user
259             to indicate a new layer to put a region on.
260         */
261         double layer;
262         double initial_y; ///< the initial y position of the view before any reparenting
263         framepos_t initial_position; ///< initial position of the region
264         framepos_t initial_end; ///< initial end position of the region
265         framepos_t anchored_fade_length; ///< fade_length when anchored during drag
266         boost::shared_ptr<ARDOUR::Playlist> initial_playlist;
267         TimeAxisView* initial_time_axis_view;
268 };
269
270 /** Abstract base class for drags that involve region(s) */
271 class RegionDrag : public Drag, public sigc::trackable
272 {
273 public:
274         RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
275         virtual ~RegionDrag () {}
276
277 protected:
278
279         RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
280         std::list<DraggingView> _views; ///< information about all views that are being dragged
281
282         /** a list of the non-hidden TimeAxisViews sorted by editor order key */
283         std::vector<TimeAxisView*> _time_axis_views;
284         int find_time_axis_view (TimeAxisView *) const;
285
286         int _visible_y_low;
287         int _visible_y_high;
288
289         friend class DraggingView;
290
291 private:
292
293         void region_going_away (RegionView *);
294         PBD::ScopedConnection death_connection;
295 };
296
297
298 /** Drags involving region motion from somewhere */
299 class RegionMotionDrag : public RegionDrag
300 {
301 public:
302
303         RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
304         virtual ~RegionMotionDrag () {}
305
306         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
307         virtual void motion (GdkEvent *, bool);
308         virtual void finished (GdkEvent *, bool);
309         virtual void aborted (bool);
310
311         /** @return true if the regions being `moved' came from somewhere on the canvas;
312          *  false if they came from outside (e.g. from the region list).
313          */
314         virtual bool regions_came_from_canvas () const = 0;
315
316 protected:
317
318         double compute_x_delta (GdkEvent const *, ARDOUR::framepos_t *);
319         bool y_movement_allowed (int, double) const;
320
321         bool _brushing;
322         ARDOUR::framepos_t _last_frame_position; ///< last position of the thing being dragged
323         double _total_x_delta;
324         int _last_pointer_time_axis_view;
325         double _last_pointer_layer;
326 };
327
328
329 /** Drags to move (or copy) regions that are already shown in the GUI to
330  *  somewhere different.
331  */
332 class RegionMoveDrag : public RegionMotionDrag
333 {
334 public:
335         RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
336         virtual ~RegionMoveDrag () {}
337
338         void motion (GdkEvent *, bool);
339         void finished (GdkEvent *, bool);
340         void aborted (bool);
341
342         bool regions_came_from_canvas () const {
343                 return true;
344         }
345
346         std::pair<ARDOUR::framecnt_t, int> move_threshold () const {
347                 return std::make_pair (4, 4);
348         }
349
350         void setup_pointer_frame_offset ();
351
352 private:
353         typedef std::set<boost::shared_ptr<ARDOUR::Playlist> > PlaylistSet;
354
355         void finished_no_copy (
356                 bool const,
357                 bool const,
358                 ARDOUR::framecnt_t const
359                 );
360
361         void finished_copy (
362                 bool const,
363                 bool const,
364                 ARDOUR::framecnt_t const
365                 );
366
367         RegionView* insert_region_into_playlist (
368                 boost::shared_ptr<ARDOUR::Region>,
369                 RouteTimeAxisView*,
370                 ARDOUR::layer_t,
371                 ARDOUR::framecnt_t,
372                 PlaylistSet&
373                 );
374
375         void remove_region_from_playlist (
376                 boost::shared_ptr<ARDOUR::Region>,
377                 boost::shared_ptr<ARDOUR::Playlist>,
378                 PlaylistSet& modified_playlists
379                 );
380
381         void add_stateful_diff_commands_for_playlists (PlaylistSet const &);
382
383         void collect_new_region_view (RegionView *);
384         RouteTimeAxisView* create_destination_time_axis (boost::shared_ptr<ARDOUR::Region>, TimeAxisView* original);
385
386         bool _copy;
387         RegionView* _new_region_view;
388 };
389
390 /** Drag to insert a region from somewhere */
391 class RegionInsertDrag : public RegionMotionDrag
392 {
393 public:
394         RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, ARDOUR::framepos_t);
395
396         void finished (GdkEvent *, bool);
397         void aborted (bool);
398
399         bool regions_came_from_canvas () const {
400                 return false;
401         }
402 };
403
404 /** Region drag in splice mode */
405 class RegionSpliceDrag : public RegionMoveDrag
406 {
407 public:
408         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
409
410         void motion (GdkEvent *, bool);
411         void finished (GdkEvent *, bool);
412         void aborted (bool);
413 };
414
415 /** Drags to create regions */
416 class RegionCreateDrag : public Drag
417 {
418 public:
419         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
420
421         void motion (GdkEvent *, bool);
422         void finished (GdkEvent *, bool);
423         void aborted (bool);
424
425 private:
426         MidiTimeAxisView* _view;
427         boost::shared_ptr<ARDOUR::Region> _region;
428 };
429
430 /** Drags to resize MIDI notes */
431 class NoteResizeDrag : public Drag
432 {
433 public:
434         NoteResizeDrag (Editor *, ArdourCanvas::Item *);
435
436         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
437         void motion (GdkEvent *, bool);
438         void finished (GdkEvent *, bool);
439         void aborted (bool);
440
441 private:
442         MidiRegionView*     region;
443         bool                relative;
444         bool                at_front;
445 };
446
447 /** Drags to move MIDI notes */
448 class NoteDrag : public Drag
449 {
450   public:
451         NoteDrag (Editor*, ArdourCanvas::Item*);
452
453         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
454         void motion (GdkEvent *, bool);
455         void finished (GdkEvent *, bool);
456         void aborted (bool);
457
458   private:
459
460         ARDOUR::frameoffset_t total_dx () const;
461         int8_t total_dy () const;
462
463         MidiRegionView* _region;
464         NoteBase* _primary;
465         double _cumulative_dx;
466         double _cumulative_dy;
467         bool _was_selected;
468         double _note_height;
469 };
470
471 class NoteCreateDrag : public Drag
472 {
473 public:
474         NoteCreateDrag (Editor *, ArdourCanvas::Item *, MidiRegionView *);
475         ~NoteCreateDrag ();
476
477         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
478         void motion (GdkEvent *, bool);
479         void finished (GdkEvent *, bool);
480         void aborted (bool);
481
482 private:
483         double y_to_region (double) const;
484         framecnt_t grid_frames (framepos_t) const;
485         
486         MidiRegionView* _region_view;
487         ArdourCanvas::Rectangle* _drag_rect;
488         framepos_t _note[2];
489 };
490
491 /** Drag to move MIDI patch changes */
492 class PatchChangeDrag : public Drag
493 {
494 public:
495         PatchChangeDrag (Editor *, PatchChange *, MidiRegionView *);
496
497         void motion (GdkEvent *, bool);
498         void finished (GdkEvent *, bool);
499         void aborted (bool);
500
501         bool y_movement_matters () const {
502                 return false;
503         }
504
505         void setup_pointer_frame_offset ();
506
507 private:
508         MidiRegionView* _region_view;
509         PatchChange* _patch_change;
510         double _cumulative_dx;
511 };
512
513 /** Container for details about audio regions being dragged along with video */
514 class AVDraggingView
515 {
516 public:
517         AVDraggingView (RegionView *);
518
519         RegionView* view; ///< the view
520         framepos_t initial_position; ///< initial position of the region
521 };
522
523 /** Drag of video offset */
524 class VideoTimeLineDrag : public Drag
525 {
526 public:
527         VideoTimeLineDrag (Editor *e, ArdourCanvas::Item *i);
528
529         void motion (GdkEvent *, bool);
530         void finished (GdkEvent *, bool);
531         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
532
533         bool y_movement_matters () const {
534                 return false;
535         }
536
537         bool allow_vertical_autoscroll () const {
538                 return false;
539         }
540
541         void aborted (bool);
542
543 protected:
544         std::list<AVDraggingView> _views; ///< information about all audio that are being dragged along
545
546 private:
547         ARDOUR::frameoffset_t _startdrag_video_offset;
548         ARDOUR::frameoffset_t _max_backwards_drag;
549 };
550
551 /** Drag to trim region(s) */
552 class TrimDrag : public RegionDrag
553 {
554 public:
555         enum Operation {
556                 StartTrim,
557                 EndTrim,
558                 ContentsTrim,
559         };
560
561         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &, bool preserve_fade_anchor = false);
562
563         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
564         void motion (GdkEvent *, bool);
565         void finished (GdkEvent *, bool);
566         void aborted (bool);
567
568         bool y_movement_matters () const {
569                 return false;
570         }
571
572         void setup_pointer_frame_offset ();
573
574 private:
575
576         Operation _operation;
577         
578         bool _preserve_fade_anchor;
579         bool _jump_position_when_done;
580 };
581
582 /** Meter marker drag */
583 class MeterMarkerDrag : public Drag
584 {
585 public:
586         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
587
588         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
589         void motion (GdkEvent *, bool);
590         void finished (GdkEvent *, bool);
591         void aborted (bool);
592
593         bool allow_vertical_autoscroll () const {
594                 return false;
595         }
596
597         bool y_movement_matters () const {
598                 return false;
599         }
600
601         void setup_pointer_frame_offset ();
602
603 private:
604         MeterMarker* _marker;
605         bool _copy;
606         XMLNode* before_state;
607 };
608
609 /** Tempo marker drag */
610 class TempoMarkerDrag : public Drag
611 {
612 public:
613         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
614
615         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
616         void motion (GdkEvent *, bool);
617         void finished (GdkEvent *, bool);
618         void aborted (bool);
619
620         bool allow_vertical_autoscroll () const {
621                 return false;
622         }
623
624         bool y_movement_matters () const {
625                 return false;
626         }
627
628         void setup_pointer_frame_offset ();
629
630 private:
631         TempoMarker* _marker;
632         bool _copy;
633         XMLNode* before_state;
634 };
635
636
637 /** Drag of the playhead cursor */
638 class CursorDrag : public Drag
639 {
640 public:
641         CursorDrag (Editor *, EditorCursor&, bool);
642
643         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
644         void motion (GdkEvent *, bool);
645         void finished (GdkEvent *, bool);
646         void aborted (bool);
647
648         bool active (Editing::MouseMode) {
649                 return true;
650         }
651
652         bool allow_vertical_autoscroll () const {
653                 return false;
654         }
655
656         bool y_movement_matters () const {
657                 return true;
658         }
659
660 private:
661         void fake_locate (framepos_t);
662
663         EditorCursor& _cursor;
664         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
665         double _grab_zoom; ///< editor frames per unit when our grab started
666 };
667
668 /** Region fade-in drag */
669 class FadeInDrag : public RegionDrag
670 {
671 public:
672         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
673
674         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
675         void motion (GdkEvent *, bool);
676         void finished (GdkEvent *, bool);
677         void aborted (bool);
678
679         bool y_movement_matters () const {
680                 return false;
681         }
682
683         void setup_pointer_frame_offset ();
684 };
685
686 /** Region fade-out drag */
687 class FadeOutDrag : public RegionDrag
688 {
689 public:
690         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
691
692         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
693         void motion (GdkEvent *, bool);
694         void finished (GdkEvent *, bool);
695         void aborted (bool);
696
697         bool y_movement_matters () const {
698                 return false;
699         }
700
701         void setup_pointer_frame_offset ();
702 };
703
704 /** Marker drag */
705 class MarkerDrag : public Drag
706 {
707 public:
708         MarkerDrag (Editor *, ArdourCanvas::Item *);
709         ~MarkerDrag ();
710
711         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
712         void motion (GdkEvent *, bool);
713         void finished (GdkEvent *, bool);
714         void aborted (bool);
715
716         bool allow_vertical_autoscroll () const {
717                 return false;
718         }
719
720         bool y_movement_matters () const {
721                 return false;
722         }
723
724         void setup_pointer_frame_offset ();
725
726 private:
727         void update_item (ARDOUR::Location *);
728
729         Marker* _marker; ///< marker being dragged
730
731         struct CopiedLocationMarkerInfo {
732             ARDOUR::Location* location;
733             std::vector<Marker*> markers;
734             bool    move_both;
735             CopiedLocationMarkerInfo (ARDOUR::Location* l, Marker* m);
736         };
737
738         typedef std::list<CopiedLocationMarkerInfo> CopiedLocationInfo;
739         CopiedLocationInfo _copied_locations;
740         ArdourCanvas::Points _points;
741 };
742
743 /** Control point drag */
744 class ControlPointDrag : public Drag
745 {
746 public:
747         ControlPointDrag (Editor *, ArdourCanvas::Item *);
748
749         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
750         void motion (GdkEvent *, bool);
751         void finished (GdkEvent *, bool);
752         void aborted (bool);
753
754         bool active (Editing::MouseMode m);
755
756 private:
757
758         ControlPoint* _point;
759         double _fixed_grab_x;
760         double _fixed_grab_y;
761         double _cumulative_x_drag;
762         double _cumulative_y_drag;
763         bool     _pushing;
764         uint32_t _final_index;
765         static double _zero_gain_fraction;
766 };
767
768 /** Gain or automation line drag */
769 class LineDrag : public Drag
770 {
771 public:
772         LineDrag (Editor *e, ArdourCanvas::Item *i);
773
774         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
775         void motion (GdkEvent *, bool);
776         void finished (GdkEvent *, bool);
777         void aborted (bool);
778
779         bool active (Editing::MouseMode) {
780                 return true;
781         }
782
783 private:
784
785         AutomationLine* _line;
786         double _fixed_grab_x;
787         double _fixed_grab_y;
788         uint32_t _before;
789         uint32_t _after;
790         double _cumulative_y_drag;
791 };
792
793 /** Transient feature line drags*/
794 class FeatureLineDrag : public Drag
795 {
796 public:
797         FeatureLineDrag (Editor *e, ArdourCanvas::Item *i);
798
799         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
800         void motion (GdkEvent *, bool);
801         void finished (GdkEvent *, bool);
802         void aborted (bool);
803
804         bool active (Editing::MouseMode) {
805                 return true;
806         }
807
808 private:
809
810         ArdourCanvas::Line* _line;
811         AudioRegionView* _arv;
812
813         double _region_view_grab_x;
814         double _cumulative_x_drag;
815
816         float _before;
817         uint32_t _max_x;
818 };
819
820 /** Dragging of a rubberband rectangle for selecting things */
821 class RubberbandSelectDrag : public Drag
822 {
823 public:
824         RubberbandSelectDrag (Editor *, ArdourCanvas::Item *);
825
826         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
827         void motion (GdkEvent *, bool);
828         void finished (GdkEvent *, bool);
829         void aborted (bool);
830
831         std::pair<ARDOUR::framecnt_t, int> move_threshold () const {
832                 return std::make_pair (8, 1);
833         }
834
835         void do_select_things (GdkEvent *, bool);
836
837         /** Select some things within a rectangle.
838          *  @param button_state The button state from the GdkEvent.
839          *  @param x1 The left-hand side of the rectangle in session frames.
840          *  @param x2 The right-hand side of the rectangle in session frames.
841          *  @param y1 The top of the rectangle in trackview coordinates.
842          *  @param y2 The bottom of the rectangle in trackview coordinates.
843          *  @param drag_in_progress true if the drag is currently happening.
844          */
845         virtual void select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress) = 0;
846         
847         virtual void deselect_things () = 0;
848
849   protected:
850         bool _vertical_only;
851 };
852
853 /** A general editor RubberbandSelectDrag (for regions, automation points etc.) */
854 class EditorRubberbandSelectDrag : public RubberbandSelectDrag
855 {
856 public:
857         EditorRubberbandSelectDrag (Editor *, ArdourCanvas::Item *);
858
859         void select_things (int, framepos_t, framepos_t, double, double, bool);
860         void deselect_things ();
861 };
862
863 /** A RubberbandSelectDrag for selecting MIDI notes */
864 class MidiRubberbandSelectDrag : public RubberbandSelectDrag
865 {
866 public:
867         MidiRubberbandSelectDrag (Editor *, MidiRegionView *);
868
869         void select_things (int, framepos_t, framepos_t, double, double, bool);
870         void deselect_things ();
871
872 private:
873         MidiRegionView* _region_view;
874 };
875
876 /** A RubberbandSelectDrag for selecting MIDI notes but with no horizonal component */
877 class MidiVerticalSelectDrag : public RubberbandSelectDrag
878 {
879 public:
880         MidiVerticalSelectDrag (Editor *, MidiRegionView *);
881
882         void select_things (int, framepos_t, framepos_t, double, double, bool);
883         void deselect_things ();
884
885 private:
886         MidiRegionView* _region_view;
887 };
888
889 /** Region drag in time-FX mode */
890 class TimeFXDrag : public RegionDrag
891 {
892 public:
893         TimeFXDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
894
895         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
896         void motion (GdkEvent *, bool);
897         void finished (GdkEvent *, bool);
898         void aborted (bool);
899 };
900
901 /** Scrub drag in audition mode */
902 class ScrubDrag : public Drag
903 {
904 public:
905         ScrubDrag (Editor *, ArdourCanvas::Item *);
906
907         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
908         void motion (GdkEvent *, bool);
909         void finished (GdkEvent *, bool);
910         void aborted (bool);
911 };
912
913 /** Drag in range select mode */
914 class SelectionDrag : public Drag
915 {
916 public:
917         enum Operation {
918                 CreateSelection,
919                 SelectionStartTrim,
920                 SelectionEndTrim,
921                 SelectionMove,
922                 SelectionExtend
923         };
924
925         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
926
927         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
928         void motion (GdkEvent *, bool);
929         void finished (GdkEvent *, bool);
930         void aborted (bool);
931
932         void setup_pointer_frame_offset ();
933
934 private:
935         Operation _operation;
936         bool _add;
937         bool _extend;
938         int _original_pointer_time_axis;
939         int _last_pointer_time_axis;
940         std::list<TimeAxisView*> _added_time_axes;
941         bool _time_selection_at_start;
942         framepos_t start_at_start;
943         framepos_t end_at_start;
944 };
945
946 /** Range marker drag */
947 class RangeMarkerBarDrag : public Drag
948 {
949 public:
950         enum Operation {
951                 CreateRangeMarker,
952                 CreateTransportMarker,
953                 CreateCDMarker
954         };
955
956         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
957
958         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
959         void motion (GdkEvent *, bool);
960         void finished (GdkEvent *, bool);
961         void aborted (bool);
962
963         bool allow_vertical_autoscroll () const {
964                 return false;
965         }
966
967         bool y_movement_matters () const {
968                 return false;
969         }
970
971 private:
972         void update_item (ARDOUR::Location *);
973
974         Operation _operation;
975         ArdourCanvas::Rectangle* _drag_rect;
976         bool _copy;
977 };
978
979 /** Drag of rectangle to set zoom */
980 class MouseZoomDrag : public Drag
981 {
982 public:
983         MouseZoomDrag (Editor *, ArdourCanvas::Item *);
984
985         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
986         void motion (GdkEvent *, bool);
987         void finished (GdkEvent *, bool);
988         void aborted (bool);
989
990         std::pair<ARDOUR::framecnt_t, int> move_threshold () const {
991                 return std::make_pair (4, 4);
992         }
993
994 private:
995         bool _zoom_out;
996 };
997
998 /** Drag of a range of automation data (either on an automation track or region gain),
999  *  changing value but not position.
1000  */
1001 class AutomationRangeDrag : public Drag
1002 {
1003 public:
1004         AutomationRangeDrag (Editor *, AutomationTimeAxisView *, std::list<ARDOUR::AudioRange> const &);
1005         AutomationRangeDrag (Editor *, AudioRegionView *, std::list<ARDOUR::AudioRange> const &);
1006
1007         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
1008         void motion (GdkEvent *, bool);
1009         void finished (GdkEvent *, bool);
1010         void aborted (bool);
1011
1012         bool x_movement_matters () const {
1013                 return false;
1014         }
1015
1016         bool active (Editing::MouseMode) {
1017                 return true;
1018         }
1019
1020 private:
1021         void setup (std::list<boost::shared_ptr<AutomationLine> > const &);
1022         double y_fraction (boost::shared_ptr<AutomationLine>, double global_y_position) const;
1023
1024         std::list<ARDOUR::AudioRange> _ranges;
1025
1026         /** A line that is part of the drag */
1027         struct Line {
1028                 boost::shared_ptr<AutomationLine> line; ///< the line
1029                 std::list<ControlPoint*> points; ///< points to drag on the line
1030                 std::pair<ARDOUR::framepos_t, ARDOUR::framepos_t> range; ///< the range of all points on the line, in session frames
1031                 XMLNode* state; ///< the XML state node before the drag
1032                 double original_fraction; ///< initial y-fraction before the drag
1033         };
1034
1035         std::list<Line> _lines;
1036         double y_origin;
1037         bool _nothing_to_drag;
1038 };
1039
1040 /** Drag of one edge of an xfade
1041  */
1042 class CrossfadeEdgeDrag : public Drag
1043 {
1044   public:
1045         CrossfadeEdgeDrag (Editor*, AudioRegionView*, ArdourCanvas::Item*, bool start);
1046
1047         void start_grab (GdkEvent*, Gdk::Cursor* c = 0);
1048         void motion (GdkEvent*, bool);
1049         void finished (GdkEvent*, bool);
1050         void aborted (bool);
1051         
1052         bool y_movement_matters () const {
1053                 return false;
1054         }
1055
1056         virtual std::pair<ARDOUR::framecnt_t, int> move_threshold () const {
1057                 return std::make_pair (4, 4);
1058         }
1059
1060   private:
1061         AudioRegionView* arv;
1062         bool start;
1063 };
1064
1065 #endif /* __gtk2_ardour_editor_drag_h_ */
1066