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_
29 #include "ardour/types.h"
32 #include "editor_items.h"
39 class StatefulDiffCommand
;
44 class CanvasNoteEvent
;
45 class CanvasPatchChange
;
52 class MidiTimeAxisView
;
55 /** Class to manage current drags */
60 DragManager (Editor
* e
);
63 bool motion_handler (GdkEvent
*, bool);
67 void set (Drag
*, GdkEvent
*, Gdk::Cursor
* c
= 0);
68 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
69 bool end_grab (GdkEvent
*);
70 bool have_item (ArdourCanvas::Item
*) const;
72 /** @return true if an end drag or abort is in progress */
73 bool ending () const {
77 bool active () const {
78 return !_drags
.empty ();
81 /** @return current pointer x position in trackview coordinates */
82 double current_pointer_x () const {
83 return _current_pointer_x
;
86 /** @return current pointer y position in trackview coordinates */
87 double current_pointer_y () const {
88 return _current_pointer_y
;
91 /** @return current pointer frame */
92 ARDOUR::framepos_t
current_pointer_frame () const {
93 return _current_pointer_frame
;
98 std::list
<Drag
*> _drags
;
99 bool _ending
; ///< true if end_grab or abort is in progress, otherwise false
100 double _current_pointer_x
; ///< trackview x of the current pointer
101 double _current_pointer_y
; ///< trackview y of the current pointer
102 ARDOUR::framepos_t _current_pointer_frame
; ///< frame that the pointer is now at
103 bool _old_follow_playhead
; ///< state of Editor::follow_playhead() before the drags started
106 /** Abstract base class for dragging of things within the editor */
110 Drag (Editor
*, ArdourCanvas::Item
*);
113 void set_manager (DragManager
* m
) {
117 /** @return the canvas item being dragged */
118 ArdourCanvas::Item
* item () const {
122 void swap_grab (ArdourCanvas::Item
*, Gdk::Cursor
*, uint32_t);
123 bool motion_handler (GdkEvent
*, bool);
126 ARDOUR::framepos_t
adjusted_frame (ARDOUR::framepos_t
, GdkEvent
const *, bool snap
= true) const;
127 ARDOUR::framepos_t
adjusted_current_frame (GdkEvent
const *, bool snap
= true) const;
129 /** Called to start a grab of an item.
130 * @param e Event that caused the grab to start.
131 * @param c Cursor to use, or 0.
133 virtual void start_grab (GdkEvent
* e
, Gdk::Cursor
* c
= 0);
135 virtual bool end_grab (GdkEvent
*);
137 /** Called when a drag motion has occurred.
138 * @param e Event describing the motion.
139 * @param f true if this is the first movement, otherwise false.
141 virtual void motion (GdkEvent
* e
, bool f
) = 0;
143 /** Called when a drag has finished.
144 * @param e Event describing the finish.
145 * @param m true if some movement occurred, otherwise false.
147 virtual void finished (GdkEvent
* e
, bool m
) = 0;
149 /** Called to abort a drag and return things to how
150 * they were before it started.
151 * @param m true if some movement occurred, otherwise false.
153 virtual void aborted (bool m
) = 0;
155 /** @param m Mouse mode.
156 * @return true if this drag should happen in this mouse mode.
158 virtual bool active (Editing::MouseMode m
) {
159 return (m
!= Editing::MouseGain
);
162 /** @return minimum number of frames (in x) and pixels (in y) that should be considered a movement */
163 virtual std::pair
<ARDOUR::framecnt_t
, int> move_threshold () const {
164 return std::make_pair (1, 1);
167 virtual bool allow_vertical_autoscroll () const {
171 /** @return true if x movement matters to this drag */
172 virtual bool x_movement_matters () const {
176 /** @return true if y movement matters to this drag */
177 virtual bool y_movement_matters () const {
181 /** Set up the _pointer_frame_offset */
182 virtual void setup_pointer_frame_offset () {
183 _pointer_frame_offset
= 0;
188 double grab_x () const {
192 double grab_y () const {
196 ARDOUR::framepos_t
raw_grab_frame () const {
197 return _raw_grab_frame
;
200 ARDOUR::framepos_t
grab_frame () const {
204 double last_pointer_x () const {
205 return _last_pointer_x
;
208 double last_pointer_y () const {
209 return _last_pointer_y
;
212 double last_pointer_frame () const {
213 return _last_pointer_frame
;
216 Editor
* _editor
; ///< our editor
218 ArdourCanvas::Item
* _item
; ///< our item
219 /** Offset from the mouse's position for the drag to the start of the thing that is being dragged */
220 ARDOUR::framecnt_t _pointer_frame_offset
;
221 bool _x_constrained
; ///< true if x motion is constrained, otherwise false
222 bool _y_constrained
; ///< true if y motion is constrained, otherwise false
223 bool _was_rolling
; ///< true if the session was rolling before the drag started, otherwise false
227 bool _move_threshold_passed
; ///< true if the move threshold has been passed, otherwise false
228 double _grab_x
; ///< trackview x of the grab start position
229 double _grab_y
; ///< trackview y of the grab start position
230 double _last_pointer_x
; ///< trackview x of the pointer last time a motion occurred
231 double _last_pointer_y
; ///< trackview y of the pointer last time a motion occurred
232 ARDOUR::framepos_t _raw_grab_frame
; ///< unsnapped frame that the mouse was at when start_grab was called, or 0
233 ARDOUR::framepos_t _grab_frame
; ///< adjusted_frame that the mouse was at when start_grab was called, or 0
234 ARDOUR::framepos_t _last_pointer_frame
; ///< adjusted_frame the last time a motion occurred
239 /** Container for details about a region being dragged */
242 DraggingView (RegionView
*, RegionDrag
*);
244 RegionView
* view
; ///< the view
245 /** index into RegionDrag::_time_axis_views of the view that this region is currently beind displayed on */
247 /** layer that this region is currently being displayed on */
248 ARDOUR::layer_t layer
;
249 double initial_y
; ///< the initial y position of the view before any reparenting
250 framepos_t initial_position
; ///< initial position of the region
251 framepos_t initial_end
; ///< initial end position of the region
252 boost::shared_ptr
<ARDOUR::Playlist
> initial_playlist
;
255 /** Abstract base class for drags that involve region(s) */
256 class RegionDrag
: public Drag
, public sigc::trackable
259 RegionDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &);
260 virtual ~RegionDrag () {}
264 RegionView
* _primary
; ///< the view that was clicked on (or whatever) to start the drag
265 std::list
<DraggingView
> _views
; ///< information about all views that are being dragged
267 /** a list of the non-hidden TimeAxisViews sorted by editor order key */
268 std::vector
<TimeAxisView
*> _time_axis_views
;
269 int find_time_axis_view (TimeAxisView
*) const;
274 friend class DraggingView
;
278 void region_going_away (RegionView
*);
279 PBD::ScopedConnection death_connection
;
283 /** Drags involving region motion from somewhere */
284 class RegionMotionDrag
: public RegionDrag
288 RegionMotionDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &, bool);
289 virtual ~RegionMotionDrag () {}
291 virtual void start_grab (GdkEvent
*, Gdk::Cursor
*);
292 virtual void motion (GdkEvent
*, bool);
293 virtual void finished (GdkEvent
*, bool) = 0;
294 virtual void aborted (bool);
296 /** @return true if the regions being `moved' came from somewhere on the canvas;
297 * false if they came from outside (e.g. from the region list).
299 virtual bool regions_came_from_canvas () const = 0;
303 double compute_x_delta (GdkEvent
const *, ARDOUR::framecnt_t
*);
304 bool y_movement_allowed (int, ARDOUR::layer_t
) const;
307 ARDOUR::framepos_t _last_frame_position
; ///< last position of the thing being dragged
308 double _total_x_delta
;
309 int _last_pointer_time_axis_view
;
310 ARDOUR::layer_t _last_pointer_layer
;
314 /** Drags to move (or copy) regions that are already shown in the GUI to
315 * somewhere different.
317 class RegionMoveDrag
: public RegionMotionDrag
320 RegionMoveDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &, bool, bool);
321 virtual ~RegionMoveDrag () {}
323 void motion (GdkEvent
*, bool);
324 void finished (GdkEvent
*, bool);
327 bool regions_came_from_canvas () const {
331 std::pair
<ARDOUR::framecnt_t
, int> move_threshold () const {
332 return std::make_pair (4, 4);
335 void setup_pointer_frame_offset ();
338 typedef std::set
<boost::shared_ptr
<ARDOUR::Playlist
> > PlaylistSet
;
340 void finished_no_copy (
343 ARDOUR::framecnt_t
const
349 ARDOUR::framecnt_t
const
352 RegionView
* insert_region_into_playlist (
353 boost::shared_ptr
<ARDOUR::Region
>,
360 void remove_region_from_playlist (
361 boost::shared_ptr
<ARDOUR::Region
>,
362 boost::shared_ptr
<ARDOUR::Playlist
>,
363 PlaylistSet
& modified_playlists
366 void add_stateful_diff_commands_for_playlists (PlaylistSet
const &);
368 void collect_new_region_view (RegionView
*);
371 RegionView
* _new_region_view
;
374 /** Drag to insert a region from somewhere */
375 class RegionInsertDrag
: public RegionMotionDrag
378 RegionInsertDrag (Editor
*, boost::shared_ptr
<ARDOUR::Region
>, RouteTimeAxisView
*, ARDOUR::framepos_t
);
380 void finished (GdkEvent
*, bool);
383 bool regions_came_from_canvas () const {
388 /** Region drag in splice mode */
389 class RegionSpliceDrag
: public RegionMoveDrag
392 RegionSpliceDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &);
394 void motion (GdkEvent
*, bool);
395 void finished (GdkEvent
*, bool);
399 /** Drags to create regions */
400 class RegionCreateDrag
: public Drag
403 RegionCreateDrag (Editor
*, ArdourCanvas::Item
*, TimeAxisView
*);
405 void motion (GdkEvent
*, bool);
406 void finished (GdkEvent
*, bool);
410 MidiTimeAxisView
* _view
;
411 boost::shared_ptr
<ARDOUR::Region
> _region
;
415 /** Drags to resize MIDI notes */
416 class NoteResizeDrag
: public Drag
419 NoteResizeDrag (Editor
*, ArdourCanvas::Item
*);
421 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
422 void motion (GdkEvent
*, bool);
423 void finished (GdkEvent
*, bool);
427 MidiRegionView
* region
;
432 /** Drags to move MIDI notes */
433 class NoteDrag
: public Drag
436 NoteDrag (Editor
*, ArdourCanvas::Item
*);
438 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
439 void motion (GdkEvent
*, bool);
440 void finished (GdkEvent
*, bool);
445 ARDOUR::frameoffset_t
total_dx () const;
446 int8_t total_dy () const;
448 MidiRegionView
* _region
;
449 Gnome::Canvas::CanvasNoteEvent
* _primary
;
450 double _cumulative_dx
;
451 double _cumulative_dy
;
456 /** Drag to move MIDI patch changes */
457 class PatchChangeDrag
: public Drag
460 PatchChangeDrag (Editor
*, ArdourCanvas::CanvasPatchChange
*, MidiRegionView
*);
462 void motion (GdkEvent
*, bool);
463 void finished (GdkEvent
*, bool);
466 bool y_movement_matters () const {
470 void setup_pointer_frame_offset ();
473 MidiRegionView
* _region_view
;
474 ArdourCanvas::CanvasPatchChange
* _patch_change
;
475 double _cumulative_dx
;
478 /** Drag of region gain */
479 class RegionGainDrag
: public Drag
482 RegionGainDrag (Editor
*, ArdourCanvas::Item
*);
484 void motion (GdkEvent
*, bool);
485 void finished (GdkEvent
*, bool);
486 bool active (Editing::MouseMode m
) {
487 return (m
== Editing::MouseGain
);
493 /** Drag to trim region(s) */
494 class TrimDrag
: public RegionDrag
503 TrimDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &);
505 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
506 void motion (GdkEvent
*, bool);
507 void finished (GdkEvent
*, bool);
510 bool y_movement_matters () const {
514 void setup_pointer_frame_offset ();
518 Operation _operation
;
521 /** Meter marker drag */
522 class MeterMarkerDrag
: public Drag
525 MeterMarkerDrag (Editor
*, ArdourCanvas::Item
*, bool);
527 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
528 void motion (GdkEvent
*, bool);
529 void finished (GdkEvent
*, bool);
532 bool allow_vertical_autoscroll () const {
536 bool y_movement_matters () const {
540 void setup_pointer_frame_offset ();
543 MeterMarker
* _marker
;
547 /** Tempo marker drag */
548 class TempoMarkerDrag
: public Drag
551 TempoMarkerDrag (Editor
*, ArdourCanvas::Item
*, bool);
553 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
554 void motion (GdkEvent
*, bool);
555 void finished (GdkEvent
*, bool);
558 bool allow_vertical_autoscroll () const {
562 bool y_movement_matters () const {
566 void setup_pointer_frame_offset ();
569 TempoMarker
* _marker
;
574 /** Drag of the playhead cursor */
575 class CursorDrag
: public Drag
578 CursorDrag (Editor
*, ArdourCanvas::Item
*, bool);
580 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
581 void motion (GdkEvent
*, bool);
582 void finished (GdkEvent
*, bool);
585 bool active (Editing::MouseMode
) {
589 bool allow_vertical_autoscroll () const {
593 bool y_movement_matters () const {
598 void fake_locate (framepos_t
);
600 bool _stop
; ///< true to stop the transport on starting the drag, otherwise false
603 /** Region fade-in drag */
604 class FadeInDrag
: public RegionDrag
607 FadeInDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &);
609 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
610 void motion (GdkEvent
*, bool);
611 void finished (GdkEvent
*, bool);
614 bool y_movement_matters () const {
618 void setup_pointer_frame_offset ();
621 /** Region fade-out drag */
622 class FadeOutDrag
: public RegionDrag
625 FadeOutDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &);
627 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
628 void motion (GdkEvent
*, bool);
629 void finished (GdkEvent
*, bool);
632 bool y_movement_matters () const {
636 void setup_pointer_frame_offset ();
640 class MarkerDrag
: public Drag
643 MarkerDrag (Editor
*, ArdourCanvas::Item
*);
646 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
647 void motion (GdkEvent
*, bool);
648 void finished (GdkEvent
*, bool);
651 bool allow_vertical_autoscroll () const {
655 bool y_movement_matters () const {
659 void setup_pointer_frame_offset ();
662 void update_item (ARDOUR::Location
*);
664 Marker
* _marker
; ///< marker being dragged
665 std::list
<ARDOUR::Location
*> _copied_locations
;
666 ArdourCanvas::Points _points
;
669 /** Control point drag */
670 class ControlPointDrag
: public Drag
673 ControlPointDrag (Editor
*, ArdourCanvas::Item
*);
675 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
676 void motion (GdkEvent
*, bool);
677 void finished (GdkEvent
*, bool);
680 bool active (Editing::MouseMode m
);
684 ControlPoint
* _point
;
685 double _fixed_grab_x
;
686 double _fixed_grab_y
;
687 double _cumulative_x_drag
;
688 double _cumulative_y_drag
;
689 static double const _zero_gain_fraction
;
692 /** Gain or automation line drag */
693 class LineDrag
: public Drag
696 LineDrag (Editor
*e
, ArdourCanvas::Item
*i
);
698 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
699 void motion (GdkEvent
*, bool);
700 void finished (GdkEvent
*, bool);
703 bool active (Editing::MouseMode
) {
709 AutomationLine
* _line
;
710 double _fixed_grab_x
;
711 double _fixed_grab_y
;
714 double _cumulative_y_drag
;
717 /** Transient feature line drags*/
718 class FeatureLineDrag
: public Drag
721 FeatureLineDrag (Editor
*e
, ArdourCanvas::Item
*i
);
723 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
724 void motion (GdkEvent
*, bool);
725 void finished (GdkEvent
*, bool);
728 bool active (Editing::MouseMode
) {
734 ArdourCanvas::Line
* _line
;
735 AudioRegionView
* _arv
;
737 double _region_view_grab_x
;
738 double _cumulative_x_drag
;
744 /** Dragging of a rubberband rectangle for selecting things */
745 class RubberbandSelectDrag
: public Drag
748 RubberbandSelectDrag (Editor
*, ArdourCanvas::Item
*);
750 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
751 void motion (GdkEvent
*, bool);
752 void finished (GdkEvent
*, bool);
755 std::pair
<ARDOUR::framecnt_t
, int> move_threshold () const {
756 return std::make_pair (8, 1);
760 /** Region drag in time-FX mode */
761 class TimeFXDrag
: public RegionDrag
764 TimeFXDrag (Editor
*, ArdourCanvas::Item
*, RegionView
*, std::list
<RegionView
*> const &);
766 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
767 void motion (GdkEvent
*, bool);
768 void finished (GdkEvent
*, bool);
772 /** Scrub drag in audition mode */
773 class ScrubDrag
: public Drag
776 ScrubDrag (Editor
*, ArdourCanvas::Item
*);
778 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
779 void motion (GdkEvent
*, bool);
780 void finished (GdkEvent
*, bool);
784 /** Drag in range select mode */
785 class SelectionDrag
: public Drag
795 SelectionDrag (Editor
*, ArdourCanvas::Item
*, Operation
);
797 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
798 void motion (GdkEvent
*, bool);
799 void finished (GdkEvent
*, bool);
802 void setup_pointer_frame_offset ();
805 Operation _operation
;
807 int _original_pointer_time_axis
;
808 int _last_pointer_time_axis
;
809 std::list
<TimeAxisView
*> _added_time_axes
;
812 /** Range marker drag */
813 class RangeMarkerBarDrag
: public Drag
818 CreateTransportMarker
,
822 RangeMarkerBarDrag (Editor
*, ArdourCanvas::Item
*, Operation
);
824 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
825 void motion (GdkEvent
*, bool);
826 void finished (GdkEvent
*, bool);
829 bool allow_vertical_autoscroll () const {
833 bool y_movement_matters () const {
838 void update_item (ARDOUR::Location
*);
840 Operation _operation
;
841 ArdourCanvas::SimpleRect
* _drag_rect
;
845 /** Drag of rectangle to set zoom */
846 class MouseZoomDrag
: public Drag
849 MouseZoomDrag (Editor
*, ArdourCanvas::Item
*);
851 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
852 void motion (GdkEvent
*, bool);
853 void finished (GdkEvent
*, bool);
856 std::pair
<ARDOUR::framecnt_t
, int> move_threshold () const {
857 return std::make_pair (4, 4);
864 /** Drag of a range of automation data, changing value but not position */
865 class AutomationRangeDrag
: public Drag
868 AutomationRangeDrag (Editor
*, ArdourCanvas::Item
*, std::list
<ARDOUR::AudioRange
> const &);
870 void start_grab (GdkEvent
*, Gdk::Cursor
* c
= 0);
871 void motion (GdkEvent
*, bool);
872 void finished (GdkEvent
*, bool);
875 bool x_movement_matters () const {
880 std::list
<ARDOUR::AudioRange
> _ranges
;
881 AutomationTimeAxisView
* _atav
;
883 /** A line that is part of the drag */
885 boost::shared_ptr
<AutomationLine
> line
; ///< the line
886 std::list
<ControlPoint
*> points
; ///< points to drag on the line
887 std::pair
<ARDOUR::framepos_t
, ARDOUR::framepos_t
> range
; ///< the range of all points on the line, in session frames
888 XMLNode
* state
; ///< the XML state node before the drag
891 std::list
<Line
> _lines
;
893 bool _nothing_to_drag
;
896 #endif /* __gtk2_ardour_editor_drag_h_ */