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