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