1612dc0ed1be97c1283ca67d28147945dbe9ef80
[ardour.git] / gtk2_ardour / editor_drag.h
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __gtk2_ardour_editor_drag_h_
21 #define __gtk2_ardour_editor_drag_h_
22
23 #include <list>
24
25 #include <gdk/gdk.h>
26 #include <stdint.h>
27
28 #include "ardour/types.h"
29
30 #include "canvas.h"
31 #include "editor_items.h"
32
33 namespace ARDOUR {
34         class Location;
35 }
36
37 class Editor;
38 class EditorCursor;
39 class TimeAxisView;
40
41 /** Abstract base class for dragging of things within the editor */
42 class Drag
43 {
44
45 public:
46         Drag (Editor *, ArdourCanvas::Item *);
47         virtual ~Drag () {}
48
49         /** @return the canvas item being dragged */
50         ArdourCanvas::Item* item () const {
51                 return _item;
52         }
53
54         void swap_grab (ArdourCanvas::Item *, Gdk::Cursor *, uint32_t);
55         void break_drag ();
56
57         bool motion_handler (GdkEvent*, bool);
58
59         /** @return true if an end drag is in progress */
60         bool ending () const {
61                 return _ending;
62         }
63
64         /** @return current pointer x position in trackview coordinates */
65         double current_pointer_x () const {
66                 return _current_pointer_x;
67         }
68
69         /** @return current pointer y position in trackview coordinates */
70         double current_pointer_y () const {
71                 return _current_pointer_y;
72         }
73
74         nframes64_t adjusted_current_frame (GdkEvent const *, bool snap = true) const;
75         
76         /** Called to start a grab of an item.
77          *  @param e Event that caused the grab to start.
78          *  @param c Cursor to use, or 0.
79          */
80         virtual void start_grab (GdkEvent* e, Gdk::Cursor* c = 0);
81
82         virtual bool end_grab (GdkEvent *);
83
84         /** Called when a drag motion has occurred.
85          *  @param e Event describing the motion.
86          *  @param f true if this is the first movement, otherwise false.
87          */
88         virtual void motion (GdkEvent* e, bool f) = 0;
89
90         /** Called when a drag has finished.
91          *  @param e Event describing the finish.
92          *  @param m true if some movement occurred, otherwise false.
93          */
94         virtual void finished (GdkEvent* e, bool m) = 0;
95
96         /** @param m Mouse mode.
97          *  @return true if this drag should happen in this mouse mode.
98          */
99         virtual bool active (Editing::MouseMode m) {
100                 return (m != Editing::MouseGain);
101         }
102
103         /** @return true if a small threshold should be applied before a mouse movement
104          *  is considered a drag, otherwise false.
105          */
106         virtual bool apply_move_threshold () const {
107                 return false;
108         }
109
110         virtual bool allow_vertical_autoscroll () const {
111                 return true;
112         }
113
114 protected:
115
116         double grab_x () const {
117                 return _grab_x;
118         }
119
120         double grab_y () const {
121                 return _grab_y;
122         }
123
124         double grab_frame () const {
125                 return _grab_frame;
126         }
127
128         double last_pointer_x () const {
129                 return _last_pointer_x;
130         }
131
132         double last_pointer_y () const {
133                 return _last_pointer_y;
134         }
135
136         double last_pointer_frame () const {
137                 return _last_pointer_frame;
138         }
139
140         Editor* _editor; ///< our editor
141         ArdourCanvas::Item* _item; ///< our item
142         /** Offset from the mouse's position for the drag to the start of the thing that is being dragged */
143         nframes64_t _pointer_frame_offset;
144         bool _x_constrained; ///< true if x motion is constrained, otherwise false
145         bool _y_constrained; ///< true if y motion is constrained, otherwise false
146         bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
147         bool _have_transaction; ///< true if a transaction has been started, false otherwise. Must be set true by derived class.
148
149 private:
150
151         bool _ending; ///< true if end_grab is in progress, otherwise false
152         bool _had_movement; ///< true if movement has occurred, otherwise false
153         bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
154         double _original_x; ///< original world x of the thing being dragged
155         double _original_y; ///< original world y of the thing being dragged
156         double _grab_x; ///< trackview x of the grab start position
157         double _grab_y; ///< trackview y of the grab start position
158         double _current_pointer_x; ///< trackview x of the current pointer
159         double _current_pointer_y; ///< trackview y of the current pointer
160         double _last_pointer_x; ///< trackview x of the pointer last time a motion occurred
161         double _last_pointer_y; ///< trackview y of the pointer last time a motion occurred
162         nframes64_t _grab_frame; ///< frame that the mouse was at when start_grab was called, or 0
163         nframes64_t _last_pointer_frame; ///< adjusted_current_frame the last time a motion occurred
164         nframes64_t _current_pointer_frame; ///< frame that the pointer is now at
165 };
166
167
168 /** Abstract base class for drags that involve region(s) */
169 class RegionDrag : public Drag, public sigc::trackable
170 {
171 public:
172         RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
173         virtual ~RegionDrag () {}
174
175 protected:
176
177         RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
178         std::list<RegionView*> _views; ///< all views that are being dragged
179
180 private:
181         void region_going_away (RegionView *);
182         PBD::ScopedConnection death_connection;
183 };
184
185
186 /** Drags involving region motion from somewhere */
187 class RegionMotionDrag : public RegionDrag
188 {
189 public:
190
191         RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
192         virtual ~RegionMotionDrag () {}
193
194         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
195         virtual void motion (GdkEvent *, bool);
196         virtual void finished (GdkEvent *, bool) = 0;
197
198 protected:
199         struct TimeAxisViewSummary {
200                 TimeAxisViewSummary () : height_list(512) {}
201
202                 std::bitset<512> tracks;
203                 std::vector<int32_t> height_list;
204                 int visible_y_low;
205                 int visible_y_high;
206         };
207
208         void copy_regions (GdkEvent *);
209         bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
210         std::map<RegionView*, std::pair<RouteTimeAxisView*, int> > find_time_axis_views_and_layers ();
211         double compute_x_delta (GdkEvent const *, nframes64_t *);
212         bool compute_y_delta (
213                 TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
214                 int32_t *, int32_t *, int32_t *
215                 );
216
217         TimeAxisViewSummary get_time_axis_view_summary ();
218         bool x_move_allowed () const;
219
220         TimeAxisView* _dest_trackview;
221         ARDOUR::layer_t _dest_layer;
222         bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
223         bool _brushing;
224         nframes64_t _last_frame_position; ///< last position of the thing being dragged
225 };
226
227
228 /** Drags to move (or copy) regions that are already shown in the GUI to
229  *  somewhere different.
230  */
231 class RegionMoveDrag : public RegionMotionDrag
232 {
233 public:
234         RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
235         virtual ~RegionMoveDrag () {}
236
237         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
238         void motion (GdkEvent *, bool);
239         void finished (GdkEvent *, bool);
240
241         bool apply_move_threshold () const {
242                 return true;
243         }
244
245 private:
246         bool _copy;
247 };
248
249 /** Drag to insert a region from somewhere */
250 class RegionInsertDrag : public RegionMotionDrag
251 {
252 public:
253         RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
254
255         void finished (GdkEvent *, bool);
256 };
257
258 /** Region drag in splice mode */
259 class RegionSpliceDrag : public RegionMoveDrag
260 {
261 public:
262         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
263
264         void motion (GdkEvent *, bool);
265         void finished (GdkEvent *, bool);
266 };
267
268 /** Drags to create regions */
269 class RegionCreateDrag : public Drag
270 {
271 public:
272         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
273
274         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
275         void motion (GdkEvent *, bool);
276         void finished (GdkEvent *, bool);
277
278 private:
279         TimeAxisView* _view;
280         TimeAxisView* _dest_trackview;
281 };
282
283 /** Drags to resize MIDI notes */
284 class NoteResizeDrag : public Drag
285 {
286 public:
287         NoteResizeDrag (Editor *, ArdourCanvas::Item *);
288
289         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
290         void motion (GdkEvent *, bool);
291         void finished (GdkEvent *, bool);
292
293 private:
294         MidiRegionView*     region;
295         bool                relative;
296         bool                at_front;
297 };
298
299 class NoteDrag : public Drag
300 {
301   public:
302         NoteDrag (Editor*, ArdourCanvas::Item*);
303
304         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
305         void motion (GdkEvent *, bool);
306         void finished (GdkEvent *, bool);
307
308   private:
309         MidiRegionView* region;
310         double last_x;
311         double last_y;
312         double drag_delta_x;
313         double drag_delta_note;
314         bool   was_selected;
315 };
316
317 /** Drag of region gain */
318 class RegionGainDrag : public Drag
319 {
320 public:
321         RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
322
323         void motion (GdkEvent *, bool);
324         void finished (GdkEvent *, bool);
325         bool active (Editing::MouseMode m) {
326                 return (m == Editing::MouseGain);
327         }
328 };
329
330 /** Drag to trim region(s) */
331 class TrimDrag : public RegionDrag
332 {
333 public:
334         enum Operation {
335                 StartTrim,
336                 EndTrim,
337                 ContentsTrim,
338         };
339
340         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
341
342         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
343         void motion (GdkEvent *, bool);
344         void finished (GdkEvent *, bool);
345
346 private:
347
348         Operation _operation;
349 };
350
351 /** Meter marker drag */
352 class MeterMarkerDrag : public Drag
353 {
354 public:
355         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
356
357         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
358         void motion (GdkEvent *, bool);
359         void finished (GdkEvent *, bool);
360
361 private:
362         MeterMarker* _marker;
363         bool _copy;
364 };
365
366 /** Tempo marker drag */
367 class TempoMarkerDrag : public Drag
368 {
369 public:
370         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
371
372         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
373         void motion (GdkEvent *, bool);
374         void finished (GdkEvent *, bool);
375
376 private:
377         TempoMarker* _marker;
378         bool _copy;
379 };
380
381
382 /** Drag of a cursor */
383 class CursorDrag : public Drag
384 {
385 public:
386         CursorDrag (Editor *, ArdourCanvas::Item *, bool);
387
388         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
389         void motion (GdkEvent *, bool);
390         void finished (GdkEvent *, bool);
391
392         bool active (Editing::MouseMode) {
393                 return true;
394         }
395
396         bool allow_vertical_autoscroll () const {
397                 return false;
398         }
399
400 private:
401         EditorCursor* _cursor; ///< cursor being dragged
402         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
403
404 };
405
406 /** Region fade-in drag */
407 class FadeInDrag : public RegionDrag
408 {
409 public:
410         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
411
412         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
413         void motion (GdkEvent *, bool);
414         void finished (GdkEvent *, bool);
415 };
416
417 /** Region fade-out drag */
418 class FadeOutDrag : public RegionDrag
419 {
420 public:
421         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
422
423         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
424         void motion (GdkEvent *, bool);
425         void finished (GdkEvent *, bool);
426 };
427
428 /** Marker drag */
429 class MarkerDrag : public Drag
430 {
431 public:
432         MarkerDrag (Editor *, ArdourCanvas::Item *);
433         ~MarkerDrag ();
434
435         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
436         void motion (GdkEvent *, bool);
437         void finished (GdkEvent *, bool);
438
439 private:
440         void update_item (ARDOUR::Location *);
441
442         Marker* _marker; ///< marker being dragged
443         std::list<ARDOUR::Location*> _copied_locations;
444         ArdourCanvas::Line* _line;
445         ArdourCanvas::Points _points;
446 };
447
448 /** Control point drag */
449 class ControlPointDrag : public Drag
450 {
451 public:
452         ControlPointDrag (Editor *, ArdourCanvas::Item *);
453
454         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
455         void motion (GdkEvent *, bool);
456         void finished (GdkEvent *, bool);
457
458         bool active (Editing::MouseMode m);
459
460 private:
461
462         ControlPoint* _point;
463         double _time_axis_view_grab_x;
464         double _time_axis_view_grab_y;
465         nframes64_t _time_axis_view_grab_frame;
466         double _cumulative_x_drag;
467         double _cumulative_y_drag;
468         static double const _zero_gain_fraction;
469 };
470
471 /** Gain or automation line drag */
472 class LineDrag : public Drag
473 {
474 public:
475         LineDrag (Editor *e, ArdourCanvas::Item *i);
476
477         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
478         void motion (GdkEvent *, bool);
479         void finished (GdkEvent *, bool);
480
481         bool active (Editing::MouseMode) {
482                 return true;
483         }
484
485 private:
486
487         AutomationLine* _line;
488         double _time_axis_view_grab_x;
489         double _time_axis_view_grab_y;
490         uint32_t _before;
491         uint32_t _after;
492         double _cumulative_y_drag;
493 };
494
495 /** Dragging of a rubberband rectangle for selecting things */
496 class RubberbandSelectDrag : public Drag
497 {
498 public:
499         RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
500
501         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
502         void motion (GdkEvent *, bool);
503         void finished (GdkEvent *, bool);
504 };
505
506 /** Region drag in time-FX mode */
507 class TimeFXDrag : public RegionDrag
508 {
509 public:
510         TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
511
512         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
513         void motion (GdkEvent *, bool);
514         void finished (GdkEvent *, bool);
515 };
516
517 /** Scrub drag in audition mode */
518 class ScrubDrag : public Drag
519 {
520 public:
521         ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
522
523         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
524         void motion (GdkEvent *, bool);
525         void finished (GdkEvent *, bool);
526 };
527
528 /** Drag in range select(gc_owner.get()) moAutomatable */
529 class SelectionDrag : public Drag
530 {
531 public:
532         enum Operation {
533                 CreateSelection,
534                 SelectionStartTrim,
535                 SelectionEndTrim,
536                 SelectionMove
537         };
538
539         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
540
541         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
542         void motion (GdkEvent *, bool);
543         void finished (GdkEvent *, bool);
544
545 private:
546         Operation _operation;
547         bool _copy;
548 };
549
550 /** Range marker drag */
551 class RangeMarkerBarDrag : public Drag
552 {
553 public:
554         enum Operation {
555                 CreateRangeMarker,
556                 CreateTransportMarker,
557                 CreateCDMarker
558         };
559
560         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
561
562         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
563         void motion (GdkEvent *, bool);
564         void finished (GdkEvent *, bool);
565
566 private:
567         void update_item (ARDOUR::Location *);
568
569         Operation _operation;
570         ArdourCanvas::SimpleRect* _drag_rect;
571         bool _copy;
572 };
573
574 /* Drag of rectangle to set zoom */
575 class MouseZoomDrag : public Drag
576 {
577 public:
578         MouseZoomDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
579
580         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
581         void motion (GdkEvent *, bool);
582         void finished (GdkEvent *, bool);
583 };
584
585 #endif /* __gtk2_ardour_editor_drag_h_ */
586