monster commit: transport mgmt changes from 2.X (omnibus edition); make slave use...
[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 item coordinates */
65         double current_pointer_x () const {
66                 return _current_pointer_x;
67         }
68
69         /** @return current pointer y position in item coordinates */
70         double current_pointer_y () const {
71                 return _current_pointer_y;
72         }
73
74         /** @return current pointer frame */
75         nframes64_t current_pointer_frame () const {
76                 return _current_pointer_frame;
77         }
78
79         /** Called to start a grab of an item.
80          *  @param e Event that caused the grab to start.
81          *  @param c Cursor to use, or 0.
82          */
83         virtual void start_grab (GdkEvent* e, Gdk::Cursor* c = 0);
84
85         virtual bool end_grab (GdkEvent *);
86
87         /** Called when a drag motion has occurred.
88          *  @param e Event describing the motion.
89          *  @param f true if this is the first movement, otherwise false.
90          */
91         virtual void motion (GdkEvent* e, bool f) = 0;
92
93         /** Called when a drag has finished.
94          *  @param e Event describing the finish.
95          *  @param m true if some movement occurred, otherwise false.
96          */
97         virtual void finished (GdkEvent* e, bool m) = 0;
98
99         /** @param m Mouse mode.
100          *  @return true if this drag should happen in this mouse mode.
101          */
102         virtual bool active (Editing::MouseMode m) {
103                 return (m != Editing::MouseGain);
104         }
105
106         /** @return true if a small threshold should be applied before a mouse movement
107          *  is considered a drag, otherwise false.
108          */
109         virtual bool apply_move_threshold () const {
110                 return false;
111         }
112
113         virtual bool allow_vertical_autoscroll () const {
114                 return true;
115         }
116
117 protected:
118         nframes64_t adjusted_current_frame (GdkEvent *) const;
119
120         Editor* _editor; ///< our editor
121         ArdourCanvas::Item* _item; ///< our item
122         nframes64_t _pointer_frame_offset; ///< offset from the mouse's position for the drag
123                                            ///< to the start of the thing that is being dragged
124         nframes64_t _last_frame_position; ///< last position of the thing being dragged
125         nframes64_t _grab_frame; ///< frame that the mouse was at when start_grab was called, or 0
126         nframes64_t _last_pointer_frame; ///< frame that the pointer was at last time a motion occurred
127         nframes64_t _current_pointer_frame; ///< frame that the pointer is now at
128         double _original_x; ///< original world x of the thing being dragged
129         double _original_y; ///< original world y of the thing being dragged
130         double _grab_x; ///< item x of the grab start position
131         double _grab_y; ///< item y of the grab start position
132         double _current_pointer_x; ///< item x of the current pointer
133         double _current_pointer_y; ///< item y of the current pointer
134         double _last_pointer_x; ///< item x of the pointer last time a motion occurred
135         double _last_pointer_y; ///< item y of the pointer last time a motion occurred
136         bool _x_constrained; ///< true if x motion is constrained, otherwise false
137         bool _y_constrained; ///< true if y motion is constrained, otherwise false
138         bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
139         bool _have_transaction; ///< true if a transaction has been started, false otherwise. Must be set true by derived class.
140
141 private:
142
143         bool _ending; ///< true if end_grab is in progress, otherwise false
144         bool _had_movement; ///< true if movement has occurred, otherwise false
145         bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
146 };
147
148
149 /** Abstract base class for drags that involve region(s) */
150 class RegionDrag : public Drag, public sigc::trackable
151 {
152 public:
153         RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
154         virtual ~RegionDrag () {}
155
156 protected:
157
158         RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
159         std::list<RegionView*> _views; ///< all views that are being dragged
160
161 private:
162         void region_going_away (RegionView *);
163 };
164
165
166 /** Drags involving region motion from somewhere */
167 class RegionMotionDrag : public RegionDrag
168 {
169 public:
170
171         RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
172         virtual ~RegionMotionDrag () {}
173
174         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
175         virtual void motion (GdkEvent *, bool);
176         virtual void finished (GdkEvent *, bool) = 0;
177
178 protected:
179         struct TimeAxisViewSummary {
180                 TimeAxisViewSummary () : height_list(512) {}
181
182                 std::bitset<512> tracks;
183                 std::vector<int32_t> height_list;
184                 int visible_y_low;
185                 int visible_y_high;
186         };
187
188         void copy_regions (GdkEvent *);
189         bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
190         std::map<RegionView*, std::pair<RouteTimeAxisView*, int> > find_time_axis_views_and_layers ();
191         double compute_x_delta (GdkEvent const *, nframes64_t *);
192         bool compute_y_delta (
193                 TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
194                 int32_t *, int32_t *, int32_t *
195                 );
196
197         TimeAxisViewSummary get_time_axis_view_summary ();
198         bool x_move_allowed () const;
199
200         TimeAxisView* _dest_trackview;
201         ARDOUR::layer_t _dest_layer;
202         bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
203         bool _brushing;
204 };
205
206
207 /** Drags to move (or copy) regions that are already shown in the GUI to
208  *  somewhere different.
209  */
210 class RegionMoveDrag : public RegionMotionDrag
211 {
212 public:
213         RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
214         virtual ~RegionMoveDrag () {}
215
216         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
217         void motion (GdkEvent *, bool);
218         void finished (GdkEvent *, bool);
219
220         bool apply_move_threshold () const {
221                 return true;
222         }
223
224 private:
225         bool _copy;
226 };
227
228 /** Drag to insert a region from somewhere */
229 class RegionInsertDrag : public RegionMotionDrag
230 {
231 public:
232         RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
233
234         void finished (GdkEvent *, bool);
235 };
236
237 /** Region drag in splice mode */
238 class RegionSpliceDrag : public RegionMoveDrag
239 {
240 public:
241         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
242
243         void motion (GdkEvent *, bool);
244         void finished (GdkEvent *, bool);
245 };
246
247 /** Drags to create regions */
248 class RegionCreateDrag : public Drag
249 {
250 public:
251         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
252
253         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
254         void motion (GdkEvent *, bool);
255         void finished (GdkEvent *, bool);
256
257 private:
258         TimeAxisView* _view;
259         TimeAxisView* _dest_trackview;
260 };
261
262 /** Drags to resize MIDI notes */
263 class NoteResizeDrag : public Drag
264 {
265 public:
266         NoteResizeDrag (Editor *, ArdourCanvas::Item *);
267
268         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
269         void motion (GdkEvent *, bool);
270         void finished (GdkEvent *, bool);
271
272 private:
273         MidiRegionView*     region;
274         bool                relative;
275         bool                at_front;
276 };
277
278 class NoteDrag : public Drag
279 {
280   public:
281         NoteDrag (Editor*, ArdourCanvas::Item*);
282
283         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
284         void motion (GdkEvent *, bool);
285         void finished (GdkEvent *, bool);
286
287   private:
288         MidiRegionView* region;
289         double last_x;
290         double last_y;
291         double drag_delta_x;
292         double drag_delta_note;
293         bool   was_selected;
294 };
295
296 /** Drag of region gain */
297 class RegionGainDrag : public Drag
298 {
299 public:
300         RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
301
302         void motion (GdkEvent *, bool);
303         void finished (GdkEvent *, bool);
304         bool active (Editing::MouseMode m) {
305                 return (m == Editing::MouseGain);
306         }
307 };
308
309 /** Drag to trim region(s) */
310 class TrimDrag : public RegionDrag
311 {
312 public:
313         enum Operation {
314                 StartTrim,
315                 EndTrim,
316                 ContentsTrim,
317         };
318
319         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
320
321         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
322         void motion (GdkEvent *, bool);
323         void finished (GdkEvent *, bool);
324
325 private:
326
327         Operation _operation;
328 };
329
330 /** Meter marker drag */
331 class MeterMarkerDrag : public Drag
332 {
333 public:
334         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
335
336         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
337         void motion (GdkEvent *, bool);
338         void finished (GdkEvent *, bool);
339
340 private:
341         MeterMarker* _marker;
342         bool _copy;
343 };
344
345 /** Tempo marker drag */
346 class TempoMarkerDrag : public Drag
347 {
348 public:
349         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
350
351         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
352         void motion (GdkEvent *, bool);
353         void finished (GdkEvent *, bool);
354
355 private:
356         TempoMarker* _marker;
357         bool _copy;
358 };
359
360
361 /** Drag of a cursor */
362 class CursorDrag : public Drag
363 {
364 public:
365         CursorDrag (Editor *, ArdourCanvas::Item *, bool);
366
367         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
368         void motion (GdkEvent *, bool);
369         void finished (GdkEvent *, bool);
370
371         bool active (Editing::MouseMode) {
372                 return true;
373         }
374
375         bool allow_vertical_autoscroll () const {
376                 return false;
377         }
378
379 private:
380         EditorCursor* _cursor; ///< cursor being dragged
381         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
382
383 };
384
385 /** Region fade-in drag */
386 class FadeInDrag : public RegionDrag
387 {
388 public:
389         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
390
391         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
392         void motion (GdkEvent *, bool);
393         void finished (GdkEvent *, bool);
394 };
395
396 /** Region fade-out drag */
397 class FadeOutDrag : public RegionDrag
398 {
399 public:
400         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
401
402         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
403         void motion (GdkEvent *, bool);
404         void finished (GdkEvent *, bool);
405 };
406
407 /** Marker drag */
408 class MarkerDrag : public Drag
409 {
410 public:
411         MarkerDrag (Editor *, ArdourCanvas::Item *);
412         ~MarkerDrag ();
413
414         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
415         void motion (GdkEvent *, bool);
416         void finished (GdkEvent *, bool);
417
418 private:
419         void update_item (ARDOUR::Location *);
420
421         Marker* _marker; ///< marker being dragged
422         std::list<ARDOUR::Location*> _copied_locations;
423         ArdourCanvas::Line* _line;
424         ArdourCanvas::Points _points;
425 };
426
427 /** Control point drag */
428 class ControlPointDrag : public Drag
429 {
430 public:
431         ControlPointDrag (Editor *, ArdourCanvas::Item *);
432
433         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
434         void motion (GdkEvent *, bool);
435         void finished (GdkEvent *, bool);
436
437         bool active (Editing::MouseMode m);
438
439 private:
440
441         ControlPoint* _point;
442         double _cumulative_x_drag;
443         double _cumulative_y_drag;
444         static double const _zero_gain_fraction;
445 };
446
447 /** Gain or automation line drag */
448 class LineDrag : public Drag
449 {
450 public:
451         LineDrag (Editor *e, ArdourCanvas::Item *i);
452
453         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
454         void motion (GdkEvent *, bool);
455         void finished (GdkEvent *, bool);
456
457         bool active (Editing::MouseMode) {
458                 return true;
459         }
460
461 private:
462
463         AutomationLine* _line;
464         uint32_t _before;
465         uint32_t _after;
466         double _cumulative_y_drag;
467 };
468
469 /** Dragging of a rubberband rectangle for selecting things */
470 class RubberbandSelectDrag : public Drag
471 {
472 public:
473         RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
474
475         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
476         void motion (GdkEvent *, bool);
477         void finished (GdkEvent *, bool);
478 };
479
480 /** Region drag in time-FX mode */
481 class TimeFXDrag : public RegionDrag
482 {
483 public:
484         TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
485
486         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
487         void motion (GdkEvent *, bool);
488         void finished (GdkEvent *, bool);
489 };
490
491 /** Scrub drag in audition mode */
492 class ScrubDrag : public Drag
493 {
494 public:
495         ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
496
497         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
498         void motion (GdkEvent *, bool);
499         void finished (GdkEvent *, bool);
500 };
501
502 /** Drag in range select(gc_owner.get()) moAutomatable */
503 class SelectionDrag : public Drag
504 {
505 public:
506         enum Operation {
507                 CreateSelection,
508                 SelectionStartTrim,
509                 SelectionEndTrim,
510                 SelectionMove
511         };
512
513         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
514
515         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
516         void motion (GdkEvent *, bool);
517         void finished (GdkEvent *, bool);
518
519 private:
520         Operation _operation;
521         bool _copy;
522 };
523
524 /** Range marker drag */
525 class RangeMarkerBarDrag : public Drag
526 {
527 public:
528         enum Operation {
529                 CreateRangeMarker,
530                 CreateTransportMarker,
531                 CreateCDMarker
532         };
533
534         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
535
536         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
537         void motion (GdkEvent *, bool);
538         void finished (GdkEvent *, bool);
539
540 private:
541         void update_item (ARDOUR::Location *);
542
543         Operation _operation;
544         ArdourCanvas::SimpleRect* _drag_rect;
545         bool _copy;
546 };
547
548 /* Drag of rectangle to set zoom */
549 class MouseZoomDrag : public Drag
550 {
551 public:
552         MouseZoomDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
553
554         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
555         void motion (GdkEvent *, bool);
556         void finished (GdkEvent *, bool);
557 };
558
559 #endif /* __gtk2_ardour_editor_drag_h_ */
560