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;
59 std::pair<nframes64_t, nframes64_t> extent () const;
61 /** @return true if an end drag or break_drag is in progress */
62 bool ending () const {
66 bool active () const {
67 return !_drags.empty ();
70 /** @return current pointer x position in trackview coordinates */
71 double current_pointer_x () const {
72 return _current_pointer_x;
75 /** @return current pointer y position in trackview coordinates */
76 double current_pointer_y () const {
77 return _current_pointer_y;
80 /** @return current pointer frame */
81 nframes64_t current_pointer_frame () const {
82 return _current_pointer_frame;
87 std::list<Drag*> _drags;
88 bool _ending; ///< true if end_grab or break_drag is in progress, otherwise false
89 double _current_pointer_x; ///< trackview x of the current pointer
90 double _current_pointer_y; ///< trackview y of the current pointer
91 nframes64_t _current_pointer_frame; ///< frame that the pointer is now at
94 /** Abstract base class for dragging of things within the editor */
98 Drag (Editor *, ArdourCanvas::Item *);
101 void set_manager (DragManager* m) {
105 /** @return the canvas item being dragged */
106 ArdourCanvas::Item* item () const {
110 void swap_grab (ArdourCanvas::Item *, Gdk::Cursor *, uint32_t);
111 bool motion_handler (GdkEvent*, bool);
114 nframes64_t adjusted_frame (nframes64_t, GdkEvent const *, bool snap = true) const;
115 nframes64_t adjusted_current_frame (GdkEvent const *, bool snap = true) const;
117 /** Called to start a grab of an item.
118 * @param e Event that caused the grab to start.
119 * @param c Cursor to use, or 0.
121 virtual void start_grab (GdkEvent* e, Gdk::Cursor* c = 0);
123 virtual bool end_grab (GdkEvent *);
125 /** Called when a drag motion has occurred.
126 * @param e Event describing the motion.
127 * @param f true if this is the first movement, otherwise false.
129 virtual void motion (GdkEvent* e, bool f) = 0;
131 /** Called when a drag has finished.
132 * @param e Event describing the finish.
133 * @param m true if some movement occurred, otherwise false.
135 virtual void finished (GdkEvent* e, bool m) = 0;
137 /** Called to abort a drag and return things to how
138 * they were before it started.
140 virtual void aborted () = 0;
142 /** @param m Mouse mode.
143 * @return true if this drag should happen in this mouse mode.
145 virtual bool active (Editing::MouseMode m) {
146 return (m != Editing::MouseGain);
149 /** @return minimum number of frames (in x) and pixels (in y) that should be considered a movement */
150 virtual std::pair<nframes64_t, int> move_threshold () const {
151 return std::make_pair (1, 1);
154 virtual bool allow_vertical_autoscroll () const {
158 /** @return true if x movement matters to this drag */
159 virtual bool x_movement_matters () const {
163 /** @return true if y movement matters to this drag */
164 virtual bool y_movement_matters () const {
168 /** @return current x extent of the thing being dragged; ie
169 * a pair of (leftmost_position, rightmost_position)
171 virtual std::pair<nframes64_t, nframes64_t> extent () const;
175 double grab_x () const {
179 double grab_y () const {
183 double grab_frame () const {
187 double last_pointer_x () const {
188 return _last_pointer_x;
191 double last_pointer_y () const {
192 return _last_pointer_y;
195 double last_pointer_frame () const {
196 return _last_pointer_frame;
199 Editor* _editor; ///< our editor
201 ArdourCanvas::Item* _item; ///< our item
202 /** Offset from the mouse's position for the drag to the start of the thing that is being dragged */
203 nframes64_t _pointer_frame_offset;
204 bool _x_constrained; ///< true if x motion is constrained, otherwise false
205 bool _y_constrained; ///< true if y motion is constrained, otherwise false
206 bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
210 bool _move_threshold_passed; ///< true if the move threshold has been passed, otherwise false
211 double _grab_x; ///< trackview x of the grab start position
212 double _grab_y; ///< trackview y of the grab start position
213 double _last_pointer_x; ///< trackview x of the pointer last time a motion occurred
214 double _last_pointer_y; ///< trackview y of the pointer last time a motion occurred
215 nframes64_t _grab_frame; ///< adjusted_frame that the mouse was at when start_grab was called, or 0
216 nframes64_t _last_pointer_frame; ///< adjusted_frame the last time a motion occurred
220 /** Abstract base class for drags that involve region(s) */
221 class RegionDrag : public Drag, public sigc::trackable
224 RegionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
225 virtual ~RegionDrag () {}
227 virtual std::pair<nframes64_t, nframes64_t> extent () const;
231 RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag
232 std::list<RegionView*> _views; ///< all views that are being dragged
235 void region_going_away (RegionView *);
236 PBD::ScopedConnection death_connection;
240 /** Drags involving region motion from somewhere */
241 class RegionMotionDrag : public RegionDrag
245 RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
246 virtual ~RegionMotionDrag () {}
248 virtual void start_grab (GdkEvent *, Gdk::Cursor *);
249 virtual void motion (GdkEvent *, bool);
250 virtual void finished (GdkEvent *, bool) = 0;
251 virtual void aborted ();
254 struct TimeAxisViewSummary {
255 TimeAxisViewSummary () : height_list(512) {}
257 std::bitset<512> tracks;
258 std::vector<int32_t> height_list;
263 void copy_regions (GdkEvent *);
264 bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
265 std::map<RegionView*, std::pair<RouteTimeAxisView*, int> > find_time_axis_views_and_layers ();
266 double compute_x_delta (GdkEvent const *, nframes64_t *);
267 bool compute_y_delta (
268 TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
269 int32_t *, int32_t *, int32_t *
272 TimeAxisViewSummary get_time_axis_view_summary ();
273 bool x_move_allowed () const;
275 TimeAxisView* _dest_trackview;
276 ARDOUR::layer_t _dest_layer;
277 bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
279 nframes64_t _last_frame_position; ///< last position of the thing being dragged
280 double _total_x_delta;
284 /** Drags to move (or copy) regions that are already shown in the GUI to
285 * somewhere different.
287 class RegionMoveDrag : public RegionMotionDrag
290 RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
291 virtual ~RegionMoveDrag () {}
293 virtual void start_grab (GdkEvent *, Gdk::Cursor *);
294 void motion (GdkEvent *, bool);
295 void finished (GdkEvent *, bool);
298 std::pair<nframes64_t, int> move_threshold () const {
299 return std::make_pair (4, 4);
306 /** Drag to insert a region from somewhere */
307 class RegionInsertDrag : public RegionMotionDrag
310 RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
312 void finished (GdkEvent *, bool);
316 /** Region drag in splice mode */
317 class RegionSpliceDrag : public RegionMoveDrag
320 RegionSpliceDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
322 void motion (GdkEvent *, bool);
323 void finished (GdkEvent *, bool);
327 /** Drags to create regions */
328 class RegionCreateDrag : public Drag
331 RegionCreateDrag (Editor *, ArdourCanvas::Item *, TimeAxisView *);
333 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
334 void motion (GdkEvent *, bool);
335 void finished (GdkEvent *, bool);
340 TimeAxisView* _dest_trackview;
343 /** Drags to resize MIDI notes */
344 class NoteResizeDrag : public Drag
347 NoteResizeDrag (Editor *, ArdourCanvas::Item *);
349 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
350 void motion (GdkEvent *, bool);
351 void finished (GdkEvent *, bool);
355 MidiRegionView* region;
360 class NoteDrag : public Drag
363 NoteDrag (Editor*, ArdourCanvas::Item*);
365 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
366 void motion (GdkEvent *, bool);
367 void finished (GdkEvent *, bool);
371 MidiRegionView* region;
375 double drag_delta_note;
379 /** Drag of region gain */
380 class RegionGainDrag : public Drag
383 RegionGainDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
385 void motion (GdkEvent *, bool);
386 void finished (GdkEvent *, bool);
387 bool active (Editing::MouseMode m) {
388 return (m == Editing::MouseGain);
394 /** Drag to trim region(s) */
395 class TrimDrag : public RegionDrag
404 TrimDrag (Editor *, ArdourCanvas::Item *, RegionView*, std::list<RegionView*> const &);
406 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
407 void motion (GdkEvent *, bool);
408 void finished (GdkEvent *, bool);
411 bool y_movement_matters () const {
415 std::pair<nframes64_t, nframes64_t> extent () const;
419 Operation _operation;
420 bool _have_transaction; ///< true if a transaction has been started, false otherwise. Must be set true by derived class.
423 /** Meter marker drag */
424 class MeterMarkerDrag : public Drag
427 MeterMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
429 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
430 void motion (GdkEvent *, bool);
431 void finished (GdkEvent *, bool);
434 bool allow_vertical_autoscroll () const {
438 bool y_movement_matters () const {
443 MeterMarker* _marker;
447 /** Tempo marker drag */
448 class TempoMarkerDrag : public Drag
451 TempoMarkerDrag (Editor *, ArdourCanvas::Item *, bool);
453 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
454 void motion (GdkEvent *, bool);
455 void finished (GdkEvent *, bool);
458 bool allow_vertical_autoscroll () const {
462 bool y_movement_matters () const {
467 TempoMarker* _marker;
472 /** Drag of a cursor */
473 class CursorDrag : public Drag
476 CursorDrag (Editor *, ArdourCanvas::Item *, bool);
478 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
479 void motion (GdkEvent *, bool);
480 void finished (GdkEvent *, bool);
483 bool active (Editing::MouseMode) {
487 bool allow_vertical_autoscroll () const {
491 bool y_movement_matters () const {
496 EditorCursor* _cursor; ///< cursor being dragged
497 bool _stop; ///< true to stop the transport on starting the drag, otherwise false
501 /** Region fade-in drag */
502 class FadeInDrag : public RegionDrag
505 FadeInDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
507 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
508 void motion (GdkEvent *, bool);
509 void finished (GdkEvent *, bool);
512 bool y_movement_matters () const {
517 /** Region fade-out drag */
518 class FadeOutDrag : public RegionDrag
521 FadeOutDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &);
523 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
524 void motion (GdkEvent *, bool);
525 void finished (GdkEvent *, bool);
528 bool y_movement_matters () const {
534 class MarkerDrag : public Drag
537 MarkerDrag (Editor *, ArdourCanvas::Item *);
540 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
541 void motion (GdkEvent *, bool);
542 void finished (GdkEvent *, bool);
545 bool allow_vertical_autoscroll () const {
549 bool y_movement_matters () const {
554 void update_item (ARDOUR::Location *);
556 Marker* _marker; ///< marker being dragged
557 std::list<ARDOUR::Location*> _copied_locations;
558 ArdourCanvas::Line* _line;
559 ArdourCanvas::Points _points;
562 /** Control point drag */
563 class ControlPointDrag : public Drag
566 ControlPointDrag (Editor *, ArdourCanvas::Item *);
568 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
569 void motion (GdkEvent *, bool);
570 void finished (GdkEvent *, bool);
573 bool active (Editing::MouseMode m);
577 ControlPoint* _point;
578 double _time_axis_view_grab_x;
579 double _time_axis_view_grab_y;
580 double _cumulative_x_drag;
581 double _cumulative_y_drag;
582 static double const _zero_gain_fraction;
585 /** Gain or automation line drag */
586 class LineDrag : public Drag
589 LineDrag (Editor *e, ArdourCanvas::Item *i);
591 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
592 void motion (GdkEvent *, bool);
593 void finished (GdkEvent *, bool);
596 bool active (Editing::MouseMode) {
602 AutomationLine* _line;
603 double _time_axis_view_grab_x;
604 double _time_axis_view_grab_y;
607 double _cumulative_y_drag;
610 /** Dragging of a rubberband rectangle for selecting things */
611 class RubberbandSelectDrag : public Drag
614 RubberbandSelectDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
616 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
617 void motion (GdkEvent *, bool);
618 void finished (GdkEvent *, bool);
621 std::pair<nframes64_t, int> move_threshold () const {
622 return std::make_pair (8, 1);
626 /** Region drag in time-FX mode */
627 class TimeFXDrag : public RegionDrag
630 TimeFXDrag (Editor *e, ArdourCanvas::Item *i, RegionView* p, std::list<RegionView*> const & v) : RegionDrag (e, i, p, v) {}
632 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
633 void motion (GdkEvent *, bool);
634 void finished (GdkEvent *, bool);
638 /** Scrub drag in audition mode */
639 class ScrubDrag : public Drag
642 ScrubDrag (Editor *e, ArdourCanvas::Item *i) : Drag (e, i) {}
644 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
645 void motion (GdkEvent *, bool);
646 void finished (GdkEvent *, bool);
650 /** Drag in range select mode */
651 class SelectionDrag : public Drag
661 SelectionDrag (Editor *, ArdourCanvas::Item *, Operation);
663 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
664 void motion (GdkEvent *, bool);
665 void finished (GdkEvent *, bool);
669 Operation _operation;
671 int _original_pointer_time_axis;
672 int _last_pointer_time_axis;
673 std::list<TimeAxisView*> _added_time_axes;
676 /** Range marker drag */
677 class RangeMarkerBarDrag : public Drag
682 CreateTransportMarker,
686 RangeMarkerBarDrag (Editor *, ArdourCanvas::Item *, Operation);
688 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
689 void motion (GdkEvent *, bool);
690 void finished (GdkEvent *, bool);
693 bool allow_vertical_autoscroll () const {
697 bool y_movement_matters () const {
702 void update_item (ARDOUR::Location *);
704 Operation _operation;
705 ArdourCanvas::SimpleRect* _drag_rect;
709 /** Drag of rectangle to set zoom */
710 class MouseZoomDrag : public Drag
713 MouseZoomDrag (Editor* e, ArdourCanvas::Item *i) : Drag (e, i) {}
715 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
716 void motion (GdkEvent *, bool);
717 void finished (GdkEvent *, bool);
721 /** Drag of a range of automation data, changing value but not position */
722 class AutomationRangeDrag : public Drag
725 AutomationRangeDrag (Editor *, ArdourCanvas::Item *, std::list<ARDOUR::AudioRange> const &);
727 void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
728 void motion (GdkEvent *, bool);
729 void finished (GdkEvent *, bool);
732 bool x_movement_matters () const {
737 std::list<ARDOUR::AudioRange> _ranges;
738 AutomationTimeAxisView* _atav;
739 boost::shared_ptr<AutomationLine> _line;
740 bool _nothing_to_drag;
743 #endif /* __gtk2_ardour_editor_drag_h_ */