2 Copyright (C) 2009 Paul Davis
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.
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.
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.
20 #ifndef __gtk2_ardour_editor_drag_h_
21 #define __gtk2_ardour_editor_drag_h_
28 #include "ardour/types.h"
31 #include "editor_items.h"
42 /** Class to manage current drags */
47 DragManager (Editor* e);
50 bool motion_handler (GdkEvent *, bool);
55 void set (Drag *, GdkEvent *, Gdk::Cursor* c = 0);
56 void start_grab (GdkEvent *);
57 bool end_grab (GdkEvent *);
58 bool have_item (ArdourCanvas::Item *) const;
60 /** @return true if an end drag or break_drag is in progress */
61 bool ending () const {
65 bool active () const {
66 return !_drags.empty ();
69 /** @return current pointer x position in trackview coordinates */
70 double current_pointer_x () const {
71 return _current_pointer_x;
74 /** @return current pointer y position in trackview coordinates */
75 double current_pointer_y () const {
76 return _current_pointer_y;
79 /** @return current pointer frame */
80 nframes64_t current_pointer_frame () const {
81 return _current_pointer_frame;
86 std::list<Drag*> _drags;
87 bool _ending; ///< true if end_grab or break_drag is in progress, otherwise false
88 double _current_pointer_x; ///< trackview x of the current pointer
89 double _current_pointer_y; ///< trackview y of the current pointer
90 nframes64_t _current_pointer_frame; ///< frame that the pointer is now at
93 /** Abstract base class for dragging of things within the editor */
97 Drag (Editor *, ArdourCanvas::Item *);
100 void set_manager (DragManager* m) {
104 /** @return the canvas item being dragged */
105 ArdourCanvas::Item* item () const {
109 void swap_grab (ArdourCanvas::Item *, Gdk::Cursor *, uint32_t);
110 bool motion_handler (GdkEvent*, bool);
113 nframes64_t adjusted_frame (nframes64_t, GdkEvent const *, bool snap = true) const;
114 nframes64_t adjusted_current_frame (GdkEvent const *, bool snap = true) const;
116 /** Called to start a grab of an item.
117 * @param e Event that caused the grab to start.
118 * @param c Cursor to use, or 0.
120 virtual void start_grab (GdkEvent* e, Gdk::Cursor* c = 0);
122 virtual bool end_grab (GdkEvent *);
124 /** Called when a drag motion has occurred.
125 * @param e Event describing the motion.
126 * @param f true if this is the first movement, otherwise false.
128 virtual void motion (GdkEvent* e, bool f) = 0;
130 /** Called when a drag has finished.
131 * @param e Event describing the finish.
132 * @param m true if some movement occurred, otherwise false.
134 virtual void finished (GdkEvent* e, bool m) = 0;
136 /** Called to abort a drag and return things to how
137 * they were before it started.
139 virtual void aborted () = 0;
141 /** @param m Mouse mode.
142 * @return true if this drag should happen in this mouse mode.
144 virtual bool active (Editing::MouseMode m) {
145 return (m != Editing::MouseGain);
148 /** @return minimum number of frames (in x) and pixels (in y) that should be considered a movement */
149 virtual std::pair<nframes64_t, int> move_threshold () const {
150 return std::make_pair (1, 1);
153 virtual bool allow_vertical_autoscroll () const {
157 /** @return true if x movement matters to this drag */
158 virtual bool x_movement_matters () const {
162 /** @return true if y movement matters to this drag */
163 virtual bool y_movement_matters () const {
169 double grab_x () const {
173 double grab_y () const {
177 double grab_frame () const {
181 double last_pointer_x () const {
182 return _last_pointer_x;
185 double last_pointer_y () const {
186 return _last_pointer_y;
189 double last_pointer_frame () const {
190 return _last_pointer_frame;
193 Editor* _editor; ///< our editor
195 ArdourCanvas::Item* _item; ///< our item
196 /** Offset from the mouse's position for the drag to the start of the thing that is being dragged */
197 nframes64_t _pointer_frame_offset;
198 bool _x_constrained; ///< true if x motion is constrained, otherwise false
199 bool _y_constrained; ///< true if y motion is constrained, otherwise false
200 bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
204 bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
205 double _grab_x; ///< trackview x of the grab start position
206 double _grab_y; ///< trackview y of the grab start position
207 double _last_pointer_x; ///< trackview x of the pointer last time a motion occurred
208 double _last_pointer_y; ///< trackview y of the pointer last time a motion occurred
209 nframes64_t _grab_frame; ///< adjusted_frame that the mouse was at when start_grab was called, or 0
210 nframes64_t _last_pointer_frame; ///< adjusted_frame the last time a motion occurred
214 /** Abstract base class for drags that involve region(s) */
215 class RegionDrag : public Drag, public sigc::trackable
218 RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
219 virtual ~RegionDrag () {}
223 RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
224 std::list<RegionView*> _views; ///< all views that are being dragged
227 void region_going_away (RegionView *);
228 PBD::ScopedConnection death_connection;
232 /** Drags involving region motion from somewhere */
233 class RegionMotionDrag : public RegionDrag
237 RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
238 virtual ~RegionMotionDrag () {}
240 virtual void start_grab (GdkEvent *, Gdk::Cursor *);
241 virtual void motion (GdkEvent *, bool);
242 virtual void finished (GdkEvent *, bool) = 0;
243 virtual void aborted ();
246 struct TimeAxisViewSummary {
247 TimeAxisViewSummary () : height_list(512) {}
249 std::bitset<512> tracks;
250 std::vector<int32_t> height_list;
255 void copy_regions (GdkEvent *);
256 bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
257 std::map<RegionView*, std::pair<RouteTimeAxisView*, int> > find_time_axis_views_and_layers ();
258 double compute_x_delta (GdkEvent const *, nframes64_t *);
259 bool compute_y_delta (
260 TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
261 int32_t *, int32_t *, int32_t *
264 TimeAxisViewSummary get_time_axis_view_summary ();
265 bool x_move_allowed () const;
267 TimeAxisView* _dest_trackview;
268 ARDOUR::layer_t _dest_layer;
269 bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
271 nframes64_t _last_frame_position; ///< last position of the thing being dragged
272 double _total_x_delta;
276 /** Drags to move (or copy) regions that are already shown in the GUI to
277 * somewhere different.
279 class RegionMoveDrag : public RegionMotionDrag
282 RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
283 virtual ~RegionMoveDrag () {}
285 virtual void start_grab (GdkEvent *, Gdk::Cursor *);
286 void motion (GdkEvent *, bool);
287 void finished (GdkEvent *, bool);
290 std::pair<nframes64_t, int> move_threshold () const {
291 return std::make_pair (4, 4);
298 /** Drag to insert a region from somewhere */
299 class RegionInsertDrag : public RegionMotionDrag
302 RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
304 void finished (GdkEvent *, bool);
308 /** Region drag in splice mode */
309 class RegionSpliceDrag : public RegionMoveDrag
312 RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
314 void motion (GdkEvent *, bool);
315 void finished (GdkEvent *, bool);
319 /** Drags to create regions */
320 class RegionCreateDrag : public Drag
323 RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
325 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
326 void motion (GdkEvent *, bool);
327 void finished (GdkEvent *, bool);
332 TimeAxisView* _dest_trackview;
335 /** Drags to resize MIDI notes */
336 class NoteResizeDrag : public Drag
339 NoteResizeDrag (Editor *, ArdourCanvas::Item *);
341 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
342 void motion (GdkEvent *, bool);
343 void finished (GdkEvent *, bool);
347 MidiRegionView* region;
352 class NoteDrag : public Drag
355 NoteDrag (Editor*, ArdourCanvas::Item*);
357 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
358 void motion (GdkEvent *, bool);
359 void finished (GdkEvent *, bool);
363 MidiRegionView* region;
367 double drag_delta_note;
371 /** Drag of region gain */
372 class RegionGainDrag : public Drag
375 RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
377 void motion (GdkEvent *, bool);
378 void finished (GdkEvent *, bool);
379 bool active (Editing::MouseMode m) {
380 return (m == Editing::MouseGain);
386 /** Drag to trim region(s) */
387 class TrimDrag : public RegionDrag
396 TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
398 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
399 void motion (GdkEvent *, bool);
400 void finished (GdkEvent *, bool);
403 bool y_movement_matters () const {
409 Operation _operation;
410 bool _have_transaction; ///< true if a transaction has been started, false otherwise. Must be set true by derived class.
413 /** Meter marker drag */
414 class MeterMarkerDrag : public Drag
417 MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
419 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
420 void motion (GdkEvent *, bool);
421 void finished (GdkEvent *, bool);
424 bool allow_vertical_autoscroll () const {
428 bool y_movement_matters () const {
433 MeterMarker* _marker;
437 /** Tempo marker drag */
438 class TempoMarkerDrag : public Drag
441 TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
443 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
444 void motion (GdkEvent *, bool);
445 void finished (GdkEvent *, bool);
448 bool allow_vertical_autoscroll () const {
452 bool y_movement_matters () const {
457 TempoMarker* _marker;
462 /** Drag of a cursor */
463 class CursorDrag : public Drag
466 CursorDrag (Editor *, ArdourCanvas::Item *, bool);
468 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
469 void motion (GdkEvent *, bool);
470 void finished (GdkEvent *, bool);
473 bool active (Editing::MouseMode) {
477 bool allow_vertical_autoscroll () const {
481 bool y_movement_matters () const {
486 EditorCursor* _cursor; ///< cursor being dragged
487 bool _stop; ///< true to stop the transport on starting the drag, otherwise false
491 /** Region fade-in drag */
492 class FadeInDrag : public RegionDrag
495 FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
497 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
498 void motion (GdkEvent *, bool);
499 void finished (GdkEvent *, bool);
502 bool y_movement_matters () const {
507 /** Region fade-out drag */
508 class FadeOutDrag : public RegionDrag
511 FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
513 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
514 void motion (GdkEvent *, bool);
515 void finished (GdkEvent *, bool);
518 bool y_movement_matters () const {
524 class MarkerDrag : public Drag
527 MarkerDrag (Editor *, ArdourCanvas::Item *);
530 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
531 void motion (GdkEvent *, bool);
532 void finished (GdkEvent *, bool);
535 bool allow_vertical_autoscroll () const {
539 bool y_movement_matters () const {
544 void update_item (ARDOUR::Location *);
546 Marker* _marker; ///< marker being dragged
547 std::list<ARDOUR::Location*> _copied_locations;
548 ArdourCanvas::Line* _line;
549 ArdourCanvas::Points _points;
552 /** Control point drag */
553 class ControlPointDrag : public Drag
556 ControlPointDrag (Editor *, ArdourCanvas::Item *);
558 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
559 void motion (GdkEvent *, bool);
560 void finished (GdkEvent *, bool);
563 bool active (Editing::MouseMode m);
567 ControlPoint* _point;
568 double _time_axis_view_grab_x;
569 double _time_axis_view_grab_y;
570 double _cumulative_x_drag;
571 double _cumulative_y_drag;
572 static double const _zero_gain_fraction;
575 /** Gain or automation line drag */
576 class LineDrag : public Drag
579 LineDrag (Editor *e, ArdourCanvas::Item *i);
581 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
582 void motion (GdkEvent *, bool);
583 void finished (GdkEvent *, bool);
586 bool active (Editing::MouseMode) {
592 AutomationLine* _line;
593 double _time_axis_view_grab_x;
594 double _time_axis_view_grab_y;
597 double _cumulative_y_drag;
600 /** Dragging of a rubberband rectangle for selecting things */
601 class RubberbandSelectDrag : public Drag
604 RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
606 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
607 void motion (GdkEvent *, bool);
608 void finished (GdkEvent *, bool);
611 std::pair<nframes64_t, int> move_threshold () const {
612 return std::make_pair (8, 1);
616 /** Region drag in time-FX mode */
617 class TimeFXDrag : public RegionDrag
620 TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
622 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
623 void motion (GdkEvent *, bool);
624 void finished (GdkEvent *, bool);
628 /** Scrub drag in audition mode */
629 class ScrubDrag : public Drag
632 ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
634 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
635 void motion (GdkEvent *, bool);
636 void finished (GdkEvent *, bool);
640 /** Drag in range select mode */
641 class SelectionDrag : public Drag
651 SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
653 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
654 void motion (GdkEvent *, bool);
655 void finished (GdkEvent *, bool);
659 Operation _operation;
661 int _original_pointer_time_axis;
662 int _last_pointer_time_axis;
663 std::list<TimeAxisView*> _added_time_axes;
666 /** Range marker drag */
667 class RangeMarkerBarDrag : public Drag
672 CreateTransportMarker,
676 RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
678 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
679 void motion (GdkEvent *, bool);
680 void finished (GdkEvent *, bool);
683 bool allow_vertical_autoscroll () const {
687 bool y_movement_matters () const {
692 void update_item (ARDOUR::Location *);
694 Operation _operation;
695 ArdourCanvas::SimpleRect* _drag_rect;
699 /** Drag of rectangle to set zoom */
700 class MouseZoomDrag : public Drag
703 MouseZoomDrag (Editor* e, ArdourCanvas::Item *i) : Drag (e, i) {}
705 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
706 void motion (GdkEvent *, bool);
707 void finished (GdkEvent *, bool);
711 /** Drag of a range of automation data, changing value but not position */
712 class AutomationRangeDrag : public Drag
715 AutomationRangeDrag (Editor *, ArdourCanvas::Item *, std::list<ARDOUR::AudioRange> const &);
717 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
718 void motion (GdkEvent *, bool);
719 void finished (GdkEvent *, bool);
722 bool x_movement_matters () const {
727 std::list<ARDOUR::AudioRange> _ranges;
728 AutomationTimeAxisView* _atav;
729 boost::shared_ptr<AutomationLine> _line;
730 bool _nothing_to_drag;
733 #endif /* __gtk2_ardour_editor_drag_h_ */