79e01154719f52519d1ad609c267ed6d1831c96a
[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 () 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 _copy; ///< true if we're copying the things that we're dragging
138         bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
139
140 private:
141         
142         bool _ending; ///< true if end_grab is in progress, otherwise false
143         bool _had_movement; ///< true if movement has occurred, otherwise false
144         bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
145 };
146
147
148 /** Abstract base class for drags that involve region(s) */
149 class RegionDrag : public Drag, public sigc::trackable
150 {
151 public:
152         RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
153         virtual ~RegionDrag () {}
154
155         void update_selection ();
156
157 protected:
158         
159         RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
160         std::list<RegionView*> _views; ///< all views that are being dragged
161
162 private:
163         void region_going_away (RegionView *);
164 };
165
166
167 /** Drags to move regions */
168 class RegionMoveDrag : public RegionDrag
169 {
170 public:
171         RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
172         virtual ~RegionMoveDrag () {}
173
174         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
175         virtual void motion (GdkEvent *, bool);
176         virtual void finished (GdkEvent *, bool);
177         bool apply_move_threshold () const {
178                 return true;
179         }
180
181 protected:
182
183         bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
184
185         TimeAxisView* _dest_trackview;
186         ARDOUR::layer_t _dest_layer;
187
188 private:
189
190         void copy_regions (GdkEvent *);
191         bool y_movement_disallowed (int, int, int, int, int, std::bitset<512> const &, std::vector<int32_t> const &) const;
192
193         bool _brushing;
194 };
195
196 /** Region drag in splice mode */
197 class RegionSpliceDrag : public RegionMoveDrag
198 {
199 public:
200         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
201
202         void motion (GdkEvent *, bool);
203         void finished (GdkEvent *, bool);
204 };
205
206 /** Drags to create regions */
207 class RegionCreateDrag : public Drag
208 {
209 public:
210         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
211
212         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
213         void motion (GdkEvent *, bool);
214         void finished (GdkEvent *, bool);
215
216 private:
217         TimeAxisView* _view;
218         TimeAxisView* _dest_trackview;
219 };
220
221 /** Drag of region gain */
222 class RegionGainDrag : public Drag
223 {
224 public:
225         RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
226
227         void motion (GdkEvent *, bool);
228         void finished (GdkEvent *, bool);
229         bool active (Editing::MouseMode m) {
230                 return (m == Editing::MouseGain);
231         }
232 };
233
234 /** Drag to trim region(s) */
235 class TrimDrag : public RegionDrag
236 {
237 public:
238         enum Operation {
239                 StartTrim,
240                 EndTrim,
241                 ContentsTrim,
242         };
243
244         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
245
246         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
247         void motion (GdkEvent *, bool);
248         void finished (GdkEvent *, bool);
249
250 private:
251
252         Operation _operation;
253 };
254
255 /** Meter marker drag */
256 class MeterMarkerDrag : public Drag
257 {
258 public:
259         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
260
261         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
262         void motion (GdkEvent *, bool);
263         void finished (GdkEvent *, bool);
264
265 private:
266         MeterMarker* _marker;
267 };
268
269 /** Tempo marker drag */
270 class TempoMarkerDrag : public Drag
271 {
272 public:
273         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
274
275         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
276         void motion (GdkEvent *, bool);
277         void finished (GdkEvent *, bool);
278
279 private:
280         TempoMarker* _marker;
281 };
282
283
284 /** Drag of a cursor */
285 class CursorDrag : public Drag
286 {
287 public:
288         CursorDrag (Editor *, ArdourCanvas::Item *, bool);
289
290         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
291         void motion (GdkEvent *, bool);
292         void finished (GdkEvent *, bool);
293
294 private:
295         EditorCursor* _cursor; ///< cursor being dragged
296         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
297         
298 };
299
300 /** Region fade-in drag */
301 class FadeInDrag : public RegionDrag
302 {
303 public:
304         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
305
306         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
307         void motion (GdkEvent *, bool);
308         void finished (GdkEvent *, bool);
309 };
310
311 /** Region fade-out drag */
312 class FadeOutDrag : public RegionDrag
313 {
314 public:
315         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
316
317         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
318         void motion (GdkEvent *, bool);
319         void finished (GdkEvent *, bool);
320 };
321
322 /** Marker drag */
323 class MarkerDrag : public Drag
324 {
325 public:
326         MarkerDrag (Editor *, ArdourCanvas::Item *);
327         ~MarkerDrag ();
328
329         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
330         void motion (GdkEvent *, bool);
331         void finished (GdkEvent *, bool);
332
333 private:
334         void update_item (ARDOUR::Location *);
335         
336         Marker* _marker; ///< marker being dragged
337         std::list<ARDOUR::Location*> _copied_locations;
338         ArdourCanvas::Line* _line;
339         ArdourCanvas::Points _points;
340 };
341
342 /** Control point drag */
343 class ControlPointDrag : public Drag
344 {
345 public:
346         ControlPointDrag (Editor *, ArdourCanvas::Item *);
347
348         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
349         void motion (GdkEvent *, bool);
350         void finished (GdkEvent *, bool);
351
352 private:
353         
354         ControlPoint* _point;
355         double _cumulative_x_drag;
356         double _cumulative_y_drag;
357         static double const _zero_gain_fraction;
358 };
359
360 /** Gain or automation line drag */
361 class LineDrag : public Drag
362 {
363 public:
364         LineDrag (Editor *e, ArdourCanvas::Item *i);
365
366         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
367         void motion (GdkEvent *, bool);
368         void finished (GdkEvent *, bool);
369
370 private:
371
372         AutomationLine* _line;
373         uint32_t _before;
374         uint32_t _after;
375         double _cumulative_y_drag;
376 };
377
378 /** Dragging of a rubberband rectangle for selecting things */
379 class RubberbandSelectDrag : public Drag
380 {
381 public:
382         RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
383
384         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
385         void motion (GdkEvent *, bool);
386         void finished (GdkEvent *, bool);
387 };
388
389 /** Region drag in time-FX mode */
390 class TimeFXDrag : public RegionDrag
391 {
392 public:
393         TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
394
395         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
396         void motion (GdkEvent *, bool);
397         void finished (GdkEvent *, bool);
398 };
399
400 /** Drag in range selection mode */
401 class SelectionDrag : public Drag
402 {
403 public:
404         enum Operation {
405                 CreateSelection,
406                 SelectionStartTrim,
407                 SelectionEndTrim,
408                 SelectionMove
409         };
410
411         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
412
413         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
414         void motion (GdkEvent *, bool);
415         void finished (GdkEvent *, bool);
416
417 private:
418         Operation _operation;
419 };
420
421 /** Range marker drag */
422 class RangeMarkerBarDrag : public Drag
423 {
424 public:
425         enum Operation {
426                 CreateRangeMarker,
427                 CreateTransportMarker,
428                 CreateCDMarker
429         };
430
431         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
432
433         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
434         void motion (GdkEvent *, bool);
435         void finished (GdkEvent *, bool);
436
437 private:
438         void update_item (ARDOUR::Location *);
439
440         Operation _operation;
441         ArdourCanvas::SimpleRect* _drag_rect;
442 };
443
444 /* Drag of rectangle to set zoom */
445 class MouseZoomDrag : public Drag
446 {
447 public:
448         MouseZoomDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
449
450         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
451         void motion (GdkEvent *, bool);
452         void finished (GdkEvent *, bool);
453 };
454
455 #endif /* __gtk2_ardour_editor_drag_h_ */
456