2cf19b927860d723ffbd423401786be8055578b3
[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         /** Called when a subclass should update the editor's selection following a drag */
114         virtual void update_selection () {}
115
116 protected:
117         nframes64_t adjusted_current_frame (GdkEvent *) const;
118         
119         Editor* _editor; ///< our editor
120         ArdourCanvas::Item* _item; ///< our item
121         nframes64_t _pointer_frame_offset; ///< offset from the mouse's position for the drag
122                                            ///< to the start of the thing that is being dragged
123         nframes64_t _last_frame_position; ///< last position of the thing being dragged
124         nframes64_t _grab_frame; ///< frame that the mouse was at when start_grab was called, or 0
125         nframes64_t _last_pointer_frame; ///< frame that the pointer was at last time a motion occurred
126         nframes64_t _current_pointer_frame; ///< frame that the pointer is now at
127         double _original_x; ///< original world x of the thing being dragged
128         double _original_y; ///< original world y of the thing being dragged
129         double _grab_x; ///< item x of the grab start position
130         double _grab_y; ///< item y of the grab start position
131         double _current_pointer_x; ///< item x of the current pointer
132         double _current_pointer_y; ///< item y of the current pointer
133         double _last_pointer_x; ///< item x of the pointer last time a motion occurred
134         double _last_pointer_y; ///< item y of the pointer last time a motion occurred
135         bool _x_constrained; ///< true if x motion is constrained, otherwise false
136         bool _y_constrained; ///< true if y motion is constrained, otherwise false
137         bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
138
139 private:
140         
141         bool _ending; ///< true if end_grab is in progress, otherwise false
142         bool _had_movement; ///< true if movement has occurred, otherwise false
143         bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
144 };
145
146
147 /** Abstract base class for drags that involve region(s) */
148 class RegionDrag : public Drag, public sigc::trackable
149 {
150 public:
151         RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
152         virtual ~RegionDrag () {}
153
154         void update_selection ();
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*, RouteTimeAxisView*> find_time_axis_views ();
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         virtual bool x_move_allowed () const = 0;
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 x_move_allowed () const;
226
227         bool _copy;
228 };
229
230 /** Drag to insert a region from somewhere */
231 class RegionInsertDrag : public RegionMotionDrag
232 {
233 public:
234         RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
235
236         void finished (GdkEvent *, bool);
237         
238 private:
239         bool x_move_allowed () const;
240 };
241
242 /** Region drag in splice mode */
243 class RegionSpliceDrag : public RegionMoveDrag
244 {
245 public:
246         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
247
248         void motion (GdkEvent *, bool);
249         void finished (GdkEvent *, bool);
250 };
251
252 /** Drags to create regions */
253 class RegionCreateDrag : public Drag
254 {
255 public:
256         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
257
258         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
259         void motion (GdkEvent *, bool);
260         void finished (GdkEvent *, bool);
261
262 private:
263         TimeAxisView* _view;
264         TimeAxisView* _dest_trackview;
265 };
266
267 /** Drag of region gain */
268 class RegionGainDrag : public Drag
269 {
270 public:
271         RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
272
273         void motion (GdkEvent *, bool);
274         void finished (GdkEvent *, bool);
275         bool active (Editing::MouseMode m) {
276                 return (m == Editing::MouseGain);
277         }
278 };
279
280 /** Drag to trim region(s) */
281 class TrimDrag : public RegionDrag
282 {
283 public:
284         enum Operation {
285                 StartTrim,
286                 EndTrim,
287                 ContentsTrim,
288         };
289
290         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
291
292         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
293         void motion (GdkEvent *, bool);
294         void finished (GdkEvent *, bool);
295
296 private:
297
298         Operation _operation;
299 };
300
301 /** Meter marker drag */
302 class MeterMarkerDrag : public Drag
303 {
304 public:
305         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
306
307         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
308         void motion (GdkEvent *, bool);
309         void finished (GdkEvent *, bool);
310
311 private:
312         MeterMarker* _marker;
313         bool _copy;
314 };
315
316 /** Tempo marker drag */
317 class TempoMarkerDrag : public Drag
318 {
319 public:
320         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
321
322         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
323         void motion (GdkEvent *, bool);
324         void finished (GdkEvent *, bool);
325
326 private:
327         TempoMarker* _marker;
328         bool _copy;
329 };
330
331
332 /** Drag of a cursor */
333 class CursorDrag : public Drag
334 {
335 public:
336         CursorDrag (Editor *, ArdourCanvas::Item *, bool);
337
338         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
339         void motion (GdkEvent *, bool);
340         void finished (GdkEvent *, bool);
341
342 private:
343         EditorCursor* _cursor; ///< cursor being dragged
344         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
345         
346 };
347
348 /** Region fade-in drag */
349 class FadeInDrag : public RegionDrag
350 {
351 public:
352         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
353
354         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
355         void motion (GdkEvent *, bool);
356         void finished (GdkEvent *, bool);
357 };
358
359 /** Region fade-out drag */
360 class FadeOutDrag : public RegionDrag
361 {
362 public:
363         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
364
365         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
366         void motion (GdkEvent *, bool);
367         void finished (GdkEvent *, bool);
368 };
369
370 /** Marker drag */
371 class MarkerDrag : public Drag
372 {
373 public:
374         MarkerDrag (Editor *, ArdourCanvas::Item *);
375         ~MarkerDrag ();
376
377         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
378         void motion (GdkEvent *, bool);
379         void finished (GdkEvent *, bool);
380
381 private:
382         void update_item (ARDOUR::Location *);
383         
384         Marker* _marker; ///< marker being dragged
385         std::list<ARDOUR::Location*> _copied_locations;
386         ArdourCanvas::Line* _line;
387         ArdourCanvas::Points _points;
388 };
389
390 /** Control point drag */
391 class ControlPointDrag : public Drag
392 {
393 public:
394         ControlPointDrag (Editor *, ArdourCanvas::Item *);
395
396         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
397         void motion (GdkEvent *, bool);
398         void finished (GdkEvent *, bool);
399
400         bool active (Editing::MouseMode m) {
401                 return (m == Editing::MouseGain);
402         }
403
404 private:
405         
406         ControlPoint* _point;
407         double _cumulative_x_drag;
408         double _cumulative_y_drag;
409         static double const _zero_gain_fraction;
410 };
411
412 /** Gain or automation line drag */
413 class LineDrag : public Drag
414 {
415 public:
416         LineDrag (Editor *e, ArdourCanvas::Item *i);
417
418         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
419         void motion (GdkEvent *, bool);
420         void finished (GdkEvent *, bool);
421         
422         bool active (Editing::MouseMode) {
423                 return true;
424         }
425
426 private:
427
428         AutomationLine* _line;
429         uint32_t _before;
430         uint32_t _after;
431         double _cumulative_y_drag;
432 };
433
434 /** Dragging of a rubberband rectangle for selecting things */
435 class RubberbandSelectDrag : public Drag
436 {
437 public:
438         RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
439
440         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
441         void motion (GdkEvent *, bool);
442         void finished (GdkEvent *, bool);
443 };
444
445 /** Region drag in time-FX mode */
446 class TimeFXDrag : public RegionDrag
447 {
448 public:
449         TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
450
451         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
452         void motion (GdkEvent *, bool);
453         void finished (GdkEvent *, bool);
454 };
455
456 /** Scrub drag in audition mode */
457 class ScrubDrag : public Drag
458 {
459 public:
460         ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
461         
462         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
463         void motion (GdkEvent *, bool);
464         void finished (GdkEvent *, bool);
465 };
466
467 /** Drag in range select(gc_owner.get()) moAutomatable */
468 class SelectionDrag : public Drag
469 {
470 public:
471         enum Operation {
472                 CreateSelection,
473                 SelectionStartTrim,
474                 SelectionEndTrim,
475                 SelectionMove
476         };
477
478         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
479
480         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
481         void motion (GdkEvent *, bool);
482         void finished (GdkEvent *, bool);
483
484 private:
485         Operation _operation;
486         bool _copy;
487 };
488
489 /** Range marker drag */
490 class RangeMarkerBarDrag : public Drag
491 {
492 public:
493         enum Operation {
494                 CreateRangeMarker,
495                 CreateTransportMarker,
496                 CreateCDMarker
497         };
498
499         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
500
501         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
502         void motion (GdkEvent *, bool);
503         void finished (GdkEvent *, bool);
504
505 private:
506         void update_item (ARDOUR::Location *);
507
508         Operation _operation;
509         ArdourCanvas::SimpleRect* _drag_rect;
510         bool _copy;
511 };
512
513 /* Drag of rectangle to set zoom */
514 class MouseZoomDrag : public Drag
515 {
516 public:
517         MouseZoomDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
518
519         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
520         void motion (GdkEvent *, bool);
521         void finished (GdkEvent *, bool);
522 };
523
524 #endif /* __gtk2_ardour_editor_drag_h_ */
525