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