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