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