fully implement and deploy explicit x-thread signal connection syntax (testing comes...
[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         PBD::ScopedConnection death_connection;
164 };
165
166
167 /** Drags involving region motion from somewhere */
168 class RegionMotionDrag : public RegionDrag
169 {
170 public:
171
172         RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
173         virtual ~RegionMotionDrag () {}
174
175         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
176         virtual void motion (GdkEvent *, bool);
177         virtual void finished (GdkEvent *, bool) = 0;
178
179 protected:
180         struct TimeAxisViewSummary {
181                 TimeAxisViewSummary () : height_list(512) {}
182
183                 std::bitset<512> tracks;
184                 std::vector<int32_t> height_list;
185                 int visible_y_low;
186                 int visible_y_high;
187         };
188
189         void copy_regions (GdkEvent *);
190         bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
191         std::map<RegionView*, std::pair<RouteTimeAxisView*, int> > find_time_axis_views_and_layers ();
192         double compute_x_delta (GdkEvent const *, nframes64_t *);
193         bool compute_y_delta (
194                 TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
195                 int32_t *, int32_t *, int32_t *
196                 );
197
198         TimeAxisViewSummary get_time_axis_view_summary ();
199         bool x_move_allowed () const;
200
201         TimeAxisView* _dest_trackview;
202         ARDOUR::layer_t _dest_layer;
203         bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
204         bool _brushing;
205 };
206
207
208 /** Drags to move (or copy) regions that are already shown in the GUI to
209  *  somewhere different.
210  */
211 class RegionMoveDrag : public RegionMotionDrag
212 {
213 public:
214         RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
215         virtual ~RegionMoveDrag () {}
216
217         virtual void start_grab (GdkEvent *, Gdk::Cursor *);
218         void motion (GdkEvent *, bool);
219         void finished (GdkEvent *, bool);
220
221         bool apply_move_threshold () const {
222                 return true;
223         }
224
225 private:
226         bool _copy;
227 };
228
229 /** Drag to insert a region from somewhere */
230 class RegionInsertDrag : public RegionMotionDrag
231 {
232 public:
233         RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
234
235         void finished (GdkEvent *, bool);
236 };
237
238 /** Region drag in splice mode */
239 class RegionSpliceDrag : public RegionMoveDrag
240 {
241 public:
242         RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
243
244         void motion (GdkEvent *, bool);
245         void finished (GdkEvent *, bool);
246 };
247
248 /** Drags to create regions */
249 class RegionCreateDrag : public Drag
250 {
251 public:
252         RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
253
254         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
255         void motion (GdkEvent *, bool);
256         void finished (GdkEvent *, bool);
257
258 private:
259         TimeAxisView* _view;
260         TimeAxisView* _dest_trackview;
261 };
262
263 /** Drags to resize MIDI notes */
264 class NoteResizeDrag : public Drag
265 {
266 public:
267         NoteResizeDrag (Editor *, ArdourCanvas::Item *);
268
269         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
270         void motion (GdkEvent *, bool);
271         void finished (GdkEvent *, bool);
272
273 private:
274         MidiRegionView*     region;
275         bool                relative;
276         bool                at_front;
277 };
278
279 class NoteDrag : public Drag
280 {
281   public:
282         NoteDrag (Editor*, ArdourCanvas::Item*);
283
284         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
285         void motion (GdkEvent *, bool);
286         void finished (GdkEvent *, bool);
287
288   private:
289         MidiRegionView* region;
290         double last_x;
291         double last_y;
292         double drag_delta_x;
293         double drag_delta_note;
294         bool   was_selected;
295 };
296
297 /** Drag of region gain */
298 class RegionGainDrag : public Drag
299 {
300 public:
301         RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
302
303         void motion (GdkEvent *, bool);
304         void finished (GdkEvent *, bool);
305         bool active (Editing::MouseMode m) {
306                 return (m == Editing::MouseGain);
307         }
308 };
309
310 /** Drag to trim region(s) */
311 class TrimDrag : public RegionDrag
312 {
313 public:
314         enum Operation {
315                 StartTrim,
316                 EndTrim,
317                 ContentsTrim,
318         };
319
320         TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
321
322         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
323         void motion (GdkEvent *, bool);
324         void finished (GdkEvent *, bool);
325
326 private:
327
328         Operation _operation;
329 };
330
331 /** Meter marker drag */
332 class MeterMarkerDrag : public Drag
333 {
334 public:
335         MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
336
337         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
338         void motion (GdkEvent *, bool);
339         void finished (GdkEvent *, bool);
340
341 private:
342         MeterMarker* _marker;
343         bool _copy;
344 };
345
346 /** Tempo marker drag */
347 class TempoMarkerDrag : public Drag
348 {
349 public:
350         TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
351
352         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
353         void motion (GdkEvent *, bool);
354         void finished (GdkEvent *, bool);
355
356 private:
357         TempoMarker* _marker;
358         bool _copy;
359 };
360
361
362 /** Drag of a cursor */
363 class CursorDrag : public Drag
364 {
365 public:
366         CursorDrag (Editor *, ArdourCanvas::Item *, bool);
367
368         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
369         void motion (GdkEvent *, bool);
370         void finished (GdkEvent *, bool);
371
372         bool active (Editing::MouseMode) {
373                 return true;
374         }
375
376         bool allow_vertical_autoscroll () const {
377                 return false;
378         }
379
380 private:
381         EditorCursor* _cursor; ///< cursor being dragged
382         bool _stop; ///< true to stop the transport on starting the drag, otherwise false
383
384 };
385
386 /** Region fade-in drag */
387 class FadeInDrag : public RegionDrag
388 {
389 public:
390         FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
391
392         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
393         void motion (GdkEvent *, bool);
394         void finished (GdkEvent *, bool);
395 };
396
397 /** Region fade-out drag */
398 class FadeOutDrag : public RegionDrag
399 {
400 public:
401         FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
402
403         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
404         void motion (GdkEvent *, bool);
405         void finished (GdkEvent *, bool);
406 };
407
408 /** Marker drag */
409 class MarkerDrag : public Drag
410 {
411 public:
412         MarkerDrag (Editor *, ArdourCanvas::Item *);
413         ~MarkerDrag ();
414
415         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
416         void motion (GdkEvent *, bool);
417         void finished (GdkEvent *, bool);
418
419 private:
420         void update_item (ARDOUR::Location *);
421
422         Marker* _marker; ///< marker being dragged
423         std::list<ARDOUR::Location*> _copied_locations;
424         ArdourCanvas::Line* _line;
425         ArdourCanvas::Points _points;
426 };
427
428 /** Control point drag */
429 class ControlPointDrag : public Drag
430 {
431 public:
432         ControlPointDrag (Editor *, ArdourCanvas::Item *);
433
434         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
435         void motion (GdkEvent *, bool);
436         void finished (GdkEvent *, bool);
437
438         bool active (Editing::MouseMode m);
439
440 private:
441
442         ControlPoint* _point;
443         double _cumulative_x_drag;
444         double _cumulative_y_drag;
445         static double const _zero_gain_fraction;
446 };
447
448 /** Gain or automation line drag */
449 class LineDrag : public Drag
450 {
451 public:
452         LineDrag (Editor *e, ArdourCanvas::Item *i);
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) {
459                 return true;
460         }
461
462 private:
463
464         AutomationLine* _line;
465         uint32_t _before;
466         uint32_t _after;
467         double _cumulative_y_drag;
468 };
469
470 /** Dragging of a rubberband rectangle for selecting things */
471 class RubberbandSelectDrag : public Drag
472 {
473 public:
474         RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
475
476         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
477         void motion (GdkEvent *, bool);
478         void finished (GdkEvent *, bool);
479 };
480
481 /** Region drag in time-FX mode */
482 class TimeFXDrag : public RegionDrag
483 {
484 public:
485         TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
486
487         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
488         void motion (GdkEvent *, bool);
489         void finished (GdkEvent *, bool);
490 };
491
492 /** Scrub drag in audition mode */
493 class ScrubDrag : public Drag
494 {
495 public:
496         ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
497
498         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
499         void motion (GdkEvent *, bool);
500         void finished (GdkEvent *, bool);
501 };
502
503 /** Drag in range select(gc_owner.get()) moAutomatable */
504 class SelectionDrag : public Drag
505 {
506 public:
507         enum Operation {
508                 CreateSelection,
509                 SelectionStartTrim,
510                 SelectionEndTrim,
511                 SelectionMove
512         };
513
514         SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
515
516         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
517         void motion (GdkEvent *, bool);
518         void finished (GdkEvent *, bool);
519
520 private:
521         Operation _operation;
522         bool _copy;
523 };
524
525 /** Range marker drag */
526 class RangeMarkerBarDrag : public Drag
527 {
528 public:
529         enum Operation {
530                 CreateRangeMarker,
531                 CreateTransportMarker,
532                 CreateCDMarker
533         };
534
535         RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
536
537         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
538         void motion (GdkEvent *, bool);
539         void finished (GdkEvent *, bool);
540
541 private:
542         void update_item (ARDOUR::Location *);
543
544         Operation _operation;
545         ArdourCanvas::SimpleRect* _drag_rect;
546         bool _copy;
547 };
548
549 /* Drag of rectangle to set zoom */
550 class MouseZoomDrag : public Drag
551 {
552 public:
553         MouseZoomDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
554
555         void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
556         void motion (GdkEvent *, bool);
557         void finished (GdkEvent *, bool);
558 };
559
560 #endif /* __gtk2_ardour_editor_drag_h_ */
561