ContentEdit drag on empty MIDI track should not create new midi regions
[ardour.git] / gtk2_ardour / editor_mouse.cc
1 /*
2     Copyright (C) 2000-2001 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 #include <cassert>
21 #include <cstdlib>
22 #include <stdint.h>
23 #include <cmath>
24 #include <set>
25 #include <string>
26 #include <algorithm>
27 #include <bitset>
28
29 #include "pbd/error.h"
30 #include "pbd/enumwriter.h"
31 #include "pbd/memento_command.h"
32 #include "pbd/basename.h"
33 #include "pbd/stateful_diff_command.h"
34
35 #include "gtkmm2ext/bindings.h"
36 #include "gtkmm2ext/utils.h"
37 #include "gtkmm2ext/tearoff.h"
38
39 #include "canvas/canvas.h"
40
41 #include "ardour/audioregion.h"
42 #include "ardour/operations.h"
43 #include "ardour/playlist.h"
44 #include "ardour/profile.h"
45 #include "ardour/region_factory.h"
46 #include "ardour/route.h"
47 #include "ardour/session.h"
48 #include "ardour/types.h"
49
50 #include "ardour_ui.h"
51 #include "actions.h"
52 #include "editor.h"
53 #include "time_axis_view.h"
54 #include "audio_time_axis.h"
55 #include "audio_region_view.h"
56 #include "midi_region_view.h"
57 #include "marker.h"
58 #include "streamview.h"
59 #include "region_gain_line.h"
60 #include "automation_time_axis.h"
61 #include "control_point.h"
62 #include "prompter.h"
63 #include "selection.h"
64 #include "keyboard.h"
65 #include "editing.h"
66 #include "rgb_macros.h"
67 #include "control_point_dialog.h"
68 #include "editor_drag.h"
69 #include "automation_region_view.h"
70 #include "edit_note_dialog.h"
71 #include "mouse_cursors.h"
72 #include "editor_cursors.h"
73 #include "verbose_cursor.h"
74 #include "note.h"
75
76 #include "i18n.h"
77
78 using namespace std;
79 using namespace ARDOUR;
80 using namespace PBD;
81 using namespace Gtk;
82 using namespace Editing;
83 using Gtkmm2ext::Keyboard;
84
85 bool
86 Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const
87 {
88         /* gdk_window_get_pointer() has X11's XQueryPointer semantics in that it only
89            pays attentions to subwindows. this means that menu windows are ignored, and 
90            if the pointer is in a menu, the return window from the call will be the
91            the regular subwindow *under* the menu.
92
93            this matters quite a lot if the pointer is moving around in a menu that overlaps
94            the track canvas because we will believe that we are within the track canvas
95            when we are not. therefore, we track enter/leave events for the track canvas
96            and allow that to override the result of gdk_window_get_pointer().
97         */
98
99         if (!within_track_canvas) {
100                 return false;
101         }
102
103         int x, y;
104         Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->_track_canvas->get_window();
105
106         if (!canvas_window) {
107                 return false;
108         }
109
110         Glib::RefPtr<const Gdk::Window> pointer_window = Gdk::Display::get_default()->get_window_at_pointer (x, y);
111
112         if (!pointer_window) {
113                 return false;
114         }
115
116         if (pointer_window != canvas_window) {
117                 in_track_canvas = false;
118                 return false;
119         }
120
121         in_track_canvas = true;
122
123         GdkEvent event;
124         event.type = GDK_BUTTON_RELEASE;
125         event.button.x = x;
126         event.button.y = y;
127
128         where = window_event_sample (&event, 0, 0);
129
130         return true;
131 }
132
133 framepos_t
134 Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
135 {
136         ArdourCanvas::Duple d;
137
138         if (!gdk_event_get_coords (event, &d.x, &d.y)) {
139                 return 0;
140         }
141
142         /* event coordinates are in window units, so convert to canvas
143          */
144
145         d = _track_canvas->window_to_canvas (d);
146
147         if (pcx) {
148                 *pcx = d.x;
149         }
150
151         if (pcy) {
152                 *pcy = d.y;
153         }
154
155         return pixel_to_sample (d.x);
156 }
157
158 framepos_t
159 Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) const
160 {
161         double x;
162         double y;
163
164         /* event coordinates are already in canvas units */
165
166         if (!gdk_event_get_coords (event, &x, &y)) {
167                 cerr << "!NO c COORDS for event type " << event->type << endl;
168                 return 0;
169         }
170
171         if (pcx) {
172                 *pcx = x;
173         }
174
175         if (pcy) {
176                 *pcy = y;
177         }
178
179         /* note that pixel_to_sample_from_event() never returns less than zero, so even if the pixel
180            position is negative (as can be the case with motion events in particular),
181            the frame location is always positive.
182         */
183
184         return pixel_to_sample_from_event (x);
185 }
186
187 void
188 Editor::set_current_trimmable (boost::shared_ptr<Trimmable> t)
189 {
190         boost::shared_ptr<Trimmable> st = _trimmable.lock();
191
192         if (!st || st == t) {
193                 _trimmable = t;
194         }
195 }
196
197 void
198 Editor::set_current_movable (boost::shared_ptr<Movable> m)
199 {
200         boost::shared_ptr<Movable> sm = _movable.lock();
201
202         if (!sm || sm != m) {
203                 _movable = m;
204         }
205 }
206
207 void
208 Editor::mouse_mode_object_range_toggled()
209 {
210         MouseMode m = mouse_mode;
211         
212         Glib::RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
213         assert (act);
214         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
215         assert (tact);
216
217         set_mouse_mode(m, true);  //call this so the button styles can get updated
218 }
219
220 static Glib::RefPtr<Action>
221 get_mouse_mode_action(MouseMode m)
222 {
223         switch (m) {
224         case MouseRange:
225                 return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range"));
226         case MouseObject:
227                 return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object"));
228         case MouseCut:
229                 return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-cut"));
230         case MouseDraw:
231                 return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw"));
232         case MouseTimeFX:
233                 return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx"));
234         case MouseContent:
235                 return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-content"));
236         case MouseAudition:
237                 return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-audition"));
238         }
239         return Glib::RefPtr<Action>();
240 }
241
242 void
243 Editor::set_mouse_mode (MouseMode m, bool force)
244 {
245         if (_drags->active ()) {
246                 return;
247         }
248
249         if (!force && m == mouse_mode) {
250                 return;
251         }
252
253         if (ARDOUR::Profile->get_mixbus()) {
254                 if ( m == MouseCut) m = MouseObject;
255         }
256
257         Glib::RefPtr<Action>       act  = get_mouse_mode_action(m);
258         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
259
260         /* go there and back to ensure that the toggled handler is called to set up mouse_mode */
261         tact->set_active (false);
262         tact->set_active (true);
263
264         //NOTE:  this will result in a call to mouse_mode_toggled which does the heavy lifting
265 }
266
267 void
268 Editor::mouse_mode_toggled (MouseMode m)
269 {
270         if (ARDOUR::Profile->get_mixbus()) {
271                 if ( m == MouseCut)  m = MouseObject;
272         }
273
274         Glib::RefPtr<Action>       act  = get_mouse_mode_action(m);
275         Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
276
277         if (!tact->get_active()) {
278                 /* this was just the notification that the old mode has been
279                  * left. we'll get called again with the new mode active in a
280                  * jiffy.
281                  */
282                 return;
283         }
284
285         if (_session && mouse_mode == MouseAudition) {
286                 /* stop transport and reset default speed to avoid oddness with
287                    auditioning */
288                 _session->request_transport_speed (0.0, true);
289         }
290
291         const bool was_internal = internal_editing();
292
293         mouse_mode = m;
294
295         /* Switch snap type/mode if we're moving to/from an internal tool.  Note
296            this must toggle the actions and not call set_snap_*() directly,
297            otherwise things get out of sync and the combo box stops working. */
298         if (!was_internal && internal_editing()) {
299                 snap_type_action(internal_snap_type)->set_active(true);
300                 snap_mode_action(internal_snap_mode)->set_active(true);
301         } else if (was_internal && !internal_editing()) {
302                 snap_type_action(pre_internal_snap_type)->set_active(true);
303                 snap_mode_action(pre_internal_snap_mode)->set_active(true);
304         }
305
306         instant_save ();
307
308         /* this should generate a new enter event which will
309            trigger the appropiate cursor.
310         */
311
312         if (_track_canvas) {
313                 _track_canvas->re_enter ();
314         }
315
316         set_gain_envelope_visibility ();
317         
318         update_time_selection_display ();
319
320         update_all_enter_cursors ();
321
322         MouseModeChanged (); /* EMIT SIGNAL */
323 }
324
325 bool
326 Editor::internal_editing() const
327 {
328         return mouse_mode == Editing::MouseContent || mouse_mode == Editing::MouseDraw;
329 }
330
331 void
332 Editor::update_time_selection_display ()
333 {
334         switch (mouse_mode) {
335         case MouseRange:
336                 selection->clear_objects ();
337                 selection->ClearMidiNoteSelection ();  /* EMIT SIGNAL */
338                 break;
339         case MouseObject:
340                 selection->clear_time ();
341                 selection->clear_tracks ();
342                 selection->ClearMidiNoteSelection ();  /* EMIT SIGNAL */
343                 break;
344         case MouseDraw:
345                 /* Clear regions, but not time or tracks, since that
346                  would destroy the range selection rectangle, which we need to stick
347                  around for AutomationRangeDrag. */
348                 selection->clear_regions ();
349                 selection->clear_playlists ();
350                 break;
351         case MouseContent:
352                 /* This handles internal edit.
353                    Clear everything except points and notes. 
354                 */
355                 selection->clear_regions();
356                 selection->clear_lines();
357                 selection->clear_playlists ();
358
359                 selection->clear_time ();
360                 selection->clear_tracks ();
361                 break;
362
363         case MouseTimeFX:
364                 /* We probably want to keep region selection */
365                 selection->clear_points ();
366                 selection->clear_lines();
367                 selection->clear_playlists ();
368
369                 selection->clear_time ();
370                 selection->clear_tracks ();
371                 break;
372
373         case MouseAudition:
374                 /*Don't lose lines or points if no action in this mode */
375                 selection->clear_regions ();
376                 selection->clear_playlists ();
377                 selection->clear_time ();
378                 selection->clear_tracks ();
379                 break;
380
381         default:
382                 /*Clear everything */
383                 selection->clear_objects();
384                 selection->clear_time ();
385                 selection->clear_tracks ();
386                 break;
387         }
388 }
389
390 void
391 Editor::step_mouse_mode (bool next)
392 {
393         const int n_mouse_modes = (int)MouseContent + 1;
394         int       current       = (int)current_mouse_mode();
395         if (next) {
396                 set_mouse_mode((MouseMode)((current + 1) % n_mouse_modes));
397         } else {
398                 set_mouse_mode((MouseMode)((current + n_mouse_modes - 1) % n_mouse_modes));
399         }
400 }
401
402 void
403 Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemType item_type)
404 {
405         /* in object/audition/timefx/gain-automation mode,
406            any button press sets the selection if the object
407            can be selected. this is a bit of hack, because
408            we want to avoid this if the mouse operation is a
409            region alignment.
410
411            note: not dbl-click or triple-click
412
413            Also note that there is no region selection in internal edit mode, otherwise
414            for operations operating on the selection (e.g. cut) it is not obvious whether
415            to cut notes or regions.
416         */
417
418         MouseMode eff_mouse_mode = effective_mouse_mode ();
419
420         if (eff_mouse_mode == MouseCut) {
421                 /* never change selection in cut mode */
422                 return;
423         }
424
425         if (get_smart_mode() && eff_mouse_mode == MouseRange && event->button.button == 3 && item_type == RegionItem) {
426                 /* context clicks are always about object properties, even if
427                    we're in range mode within smart mode.
428                 */
429                 eff_mouse_mode = MouseObject;
430         }
431
432         /* special case: allow drag of region fade in/out in object mode with join object/range enabled */
433         if (get_smart_mode()) {
434                 switch (item_type) {
435                   case FadeInHandleItem:
436                   case FadeInTrimHandleItem:
437                   case FadeOutHandleItem:
438                   case FadeOutTrimHandleItem:
439                           eff_mouse_mode = MouseObject;
440                           break;
441                 default:
442                         break;
443                 }
444         }
445
446         if (((mouse_mode != MouseObject) &&
447              (mouse_mode != MouseAudition || item_type != RegionItem) &&
448              (mouse_mode != MouseTimeFX || item_type != RegionItem) &&
449              (mouse_mode != MouseDraw)) ||
450             ((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3)) {
451                 return;
452         }
453
454         if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
455
456                 if ((event->button.state & Keyboard::RelevantModifierKeyMask) && event->button.button != 1) {
457
458                         /* almost no selection action on modified button-2 or button-3 events */
459
460                         if (item_type != RegionItem && event->button.button != 2) {
461                                 return;
462                         }
463                 }
464         }
465
466         Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
467         bool press = (event->type == GDK_BUTTON_PRESS);
468
469         if (press) {
470                 _mouse_changed_selection = false;
471         }
472
473         switch (item_type) {
474         case RegionItem:
475                 if (press) {
476                         if (eff_mouse_mode != MouseRange) {
477                                 _mouse_changed_selection = set_selected_regionview_from_click (press, op);
478                         } else {
479                                 /* don't change the selection unless the
480                                    clicked track is not currently selected. if
481                                    so, "collapse" the selection to just this
482                                    track
483                                 */
484                                 if (!selection->selected (clicked_axisview)) {
485                                         set_selected_track_as_side_effect (Selection::Set);
486                                 }
487                         }
488                 } else {
489                         if (eff_mouse_mode != MouseRange) {
490                                 _mouse_changed_selection |= set_selected_regionview_from_click (press, op);
491                         }
492                 }
493                 break;
494
495         case RegionViewNameHighlight:
496         case RegionViewName:
497         case LeftFrameHandle:
498         case RightFrameHandle:
499         case FadeInHandleItem:
500         case FadeInTrimHandleItem:
501         case FadeInItem:
502         case FadeOutHandleItem:
503         case FadeOutTrimHandleItem:
504         case FadeOutItem:
505         case StartCrossFadeItem:
506         case EndCrossFadeItem:
507                 if (get_smart_mode() || eff_mouse_mode != MouseRange) {
508                         _mouse_changed_selection |= set_selected_regionview_from_click (press, op);
509                 } else if (event->type == GDK_BUTTON_PRESS) {
510                         set_selected_track_as_side_effect (op);
511                 }
512                 break;
513
514         case ControlPointItem:
515                 set_selected_track_as_side_effect (op);
516                 if (eff_mouse_mode != MouseRange) {
517                         _mouse_changed_selection |= set_selected_control_point_from_click (press, op);
518                 }
519                 break;
520
521         case StreamItem:
522                 /* for context click, select track */
523                 if (event->button.button == 3) {
524                         selection->clear_tracks ();
525                         set_selected_track_as_side_effect (op);
526
527                         /* We won't get a release.*/
528                         begin_reversible_selection_op (_("Button 3 Menu Select"));
529                         commit_reversible_selection_op ();
530                 }
531                 break;
532
533         case AutomationTrackItem:
534                 set_selected_track_as_side_effect (op);
535                 break;
536
537         default:
538                 break;
539         }
540
541         if ((!press) && _mouse_changed_selection) {
542                 begin_reversible_selection_op (_("Button Selection"));
543                 commit_reversible_selection_op ();
544                 _mouse_changed_selection = false;
545         }
546 }
547
548 bool
549 Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
550 {
551         /* single mouse clicks on any of these item types operate
552            independent of mouse mode, mostly because they are
553            not on the main track canvas or because we want
554            them to be modeless.
555         */
556
557         NoteBase* note = NULL;
558
559         switch (item_type) {
560         case PlayheadCursorItem:
561                 _drags->set (new CursorDrag (this, *playhead_cursor, true), event);
562                 return true;
563
564         case MarkerItem:
565                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
566                         hide_marker (item, event);
567                 } else {
568                         _drags->set (new MarkerDrag (this, item), event);
569                 }
570                 return true;
571
572         case TempoMarkerItem:
573         {
574                 _drags->set (
575                         new TempoMarkerDrag (
576                                 this,
577                                 item,
578                                 Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)
579                                 ),
580                         event
581                         );
582                 return true;
583         }
584
585         case MeterMarkerItem:
586         {
587                 _drags->set (
588                         new MeterMarkerDrag (
589                                 this,
590                                 item,
591                                 Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)
592                                 ),
593                         event
594                         );
595                 return true;
596         }
597
598         case VideoBarItem:
599                 _drags->set (new VideoTimeLineDrag (this, item), event);
600                 return true;
601                 break;
602
603         case MarkerBarItem:
604         case TempoBarItem:
605         case MeterBarItem:
606         case TimecodeRulerItem:
607         case SamplesRulerItem:
608         case MinsecRulerItem:
609         case BBTRulerItem:
610                 if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
611                         _drags->set (new CursorDrag (this, *playhead_cursor, false), event);
612                 }
613                 return true;
614                 break;
615
616
617         case RangeMarkerBarItem:
618                 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) {
619                         _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateSkipMarker), event);
620                 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
621                         _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateRangeMarker), event);
622                 } else {
623                         _drags->set (new CursorDrag (this, *playhead_cursor, false), event);
624                 }
625                 return true;
626                 break;
627
628         case CdMarkerBarItem:
629                 if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
630                         _drags->set (new CursorDrag (this, *playhead_cursor, false), event);
631                 } else {
632                         _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateCDMarker), event);
633                 }
634                 return true;
635                 break;
636
637         case TransportMarkerBarItem:
638                 if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
639                         _drags->set (new CursorDrag (this, *playhead_cursor, false), event);
640                 } else {
641                         _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateTransportMarker), event);
642                 }
643                 return true;
644                 break;
645
646         default:
647                 break;
648         }
649
650         if (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
651                 /* special case: allow trim of range selections in joined object mode;
652                    in theory eff should equal MouseRange in this case, but it doesn't
653                    because entering the range selection canvas item results in entered_regionview
654                    being set to 0, so update_join_object_range_location acts as if we aren't
655                    over a region.
656                 */
657                 if (item_type == StartSelectionTrimItem) {
658                         _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionStartTrim), event);
659                 } else if (item_type == EndSelectionTrimItem) {
660                         _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionEndTrim), event);
661                 }
662         }
663
664         Editing::MouseMode eff = effective_mouse_mode ();
665
666         /* special case: allow drag of region fade in/out in object mode with join object/range enabled */
667         if (get_smart_mode()) { 
668                 switch (item_type) {
669                   case FadeInHandleItem:
670                   case FadeInTrimHandleItem:
671                   case FadeOutHandleItem:
672                   case FadeOutTrimHandleItem:
673                         eff = MouseObject;
674                         break;
675                 default:
676                         break;
677                 }
678         }
679
680         switch (eff) {
681         case MouseRange:
682                 switch (item_type) {
683                 case StartSelectionTrimItem:
684                         _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionStartTrim), event);
685                         break;
686
687                 case EndSelectionTrimItem:
688                         _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionEndTrim), event);
689                         break;
690
691                 case SelectionItem:
692                         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
693                                 start_selection_grab (item, event);
694                                 return true;
695                         } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
696                                 /* grab selection for moving */
697                                 _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionMove), event);
698                         } else {
699                                 /* this was debated, but decided the more common action was to
700                                    make a new selection */
701                                 _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
702                         }
703                         break;
704
705                 case StreamItem:
706                         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) {
707                                 _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event);
708                         } else {
709                                 _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
710                         }
711                         return true;
712                         break;
713
714                 case RegionViewNameHighlight:
715                         if (!clicked_regionview->region()->locked()) {
716                                 _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
717                                 return true;
718                         }
719                         break;
720
721                 default:
722                         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) {
723                                 _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event);
724                         } else {
725                                 _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
726                         }
727                 }
728                 return true;
729                 break;
730
731         case MouseCut:
732                 switch (item_type) {
733                 case RegionItem:
734                 case FadeInHandleItem:
735                 case FadeOutHandleItem:
736                 case LeftFrameHandle:
737                 case RightFrameHandle:
738                 case FeatureLineItem:
739                 case RegionViewNameHighlight:
740                 case RegionViewName:
741                 case StreamItem:
742                 case AutomationTrackItem:
743                         _drags->set (new RegionCutDrag (this, item, canvas_event_sample (event)), event, get_canvas_cursor());
744                         return true;
745                         break;
746                 default:
747                         break;
748                 }
749                 break;
750
751         case MouseContent:
752                 switch (item_type) {
753                 case NoteItem:
754                         /* Existing note: allow trimming/motion */
755                         if ((note = reinterpret_cast<NoteBase*> (item->get_data ("notebase")))) {
756                                 if (note->big_enough_to_trim() && note->mouse_near_ends()) {
757                                         _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
758                                 } else {
759                                         _drags->set (new NoteDrag (this, item), event);
760                                 }
761                         }
762                         return true;
763
764                 case ControlPointItem:
765                         _drags->set (new ControlPointDrag (this, item), event);
766                         return true;
767                         break;
768
769                 case StreamItem:
770                         //in the past, we created a new midi region here, but perhaps that is best left to the Draw mode
771                         break;
772
773                 case AutomationTrackItem:
774                         /* rubberband drag to select automation points */
775                         _drags->set (new EditorRubberbandSelectDrag (this, item), event);
776                         return true;
777                         break;
778
779                 case RegionItem:
780                         if (dynamic_cast<AutomationRegionView*>(clicked_regionview)) {
781                                 /* rubberband drag to select automation points */
782                                 _drags->set (new EditorRubberbandSelectDrag (this, item), event);
783                                 return true;
784                         }
785                         break;
786
787                 default:
788                         break;
789                 }
790                 break;
791
792         case MouseObject:
793                 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) &&
794                     event->type == GDK_BUTTON_PRESS) {
795
796                         _drags->set (new EditorRubberbandSelectDrag (this, item), event);
797
798                 } else if (event->type == GDK_BUTTON_PRESS) {
799
800                         switch (item_type) {
801                         case FadeInHandleItem:
802                         {
803                                 _drags->set (new FadeInDrag (this, item, reinterpret_cast<RegionView*> (item->get_data("regionview")), selection->regions), event, _cursors->fade_in);
804                                 return true;
805                         }
806
807                         case FadeOutHandleItem:
808                         {
809                                 _drags->set (new FadeOutDrag (this, item, reinterpret_cast<RegionView*> (item->get_data("regionview")), selection->regions), event, _cursors->fade_out);
810                                 return true;
811                         }
812
813                         case StartCrossFadeItem:
814                         case EndCrossFadeItem:
815                                 /* we might allow user to grab inside the fade to trim a region with preserve_fade_anchor.  for not this is not fully implemented */ 
816 //                              if (!clicked_regionview->region()->locked()) {
817 //                                      _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer(), true), event);
818 //                                      return true;
819 //                              }
820                                 break;
821
822                         case FeatureLineItem:
823                         {
824                                 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) {
825                                         remove_transient(item);
826                                         return true;
827                                 }
828
829                                 _drags->set (new FeatureLineDrag (this, item), event);
830                                 return true;
831                                 break;
832                         }
833
834                         case RegionItem:
835                                 if (dynamic_cast<AutomationRegionView*> (clicked_regionview)) {
836                                         /* click on an automation region view; do nothing here and let the ARV's signal handler
837                                            sort it out.
838                                         */
839                                         break;
840                                 }
841
842                                 /* click on a normal region view */
843                                 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
844                                         add_region_copy_drag (item, event, clicked_regionview);
845                                 } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
846                                         add_region_brush_drag (item, event, clicked_regionview);
847                                 } else {
848                                         add_region_drag (item, event, clicked_regionview);
849                                 }
850
851
852                                 _drags->start_grab (event);
853                                 return true;
854                                 break;
855
856                         case RegionViewNameHighlight:
857                         case LeftFrameHandle:
858                         case RightFrameHandle:
859                                 if (!clicked_regionview->region()->locked()) {
860                                         _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
861                                         return true;
862                                 }
863                                 break;
864
865                         case FadeInTrimHandleItem:
866                         case FadeOutTrimHandleItem:
867                                 if (!clicked_regionview->region()->locked()) {
868                                         _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer(), true), event);
869                                         return true;
870                                 }
871                                 break;
872
873                         case RegionViewName:
874                         {
875                                 /* rename happens on edit clicks */
876                                 if (clicked_regionview->get_name_highlight()) {
877                                         _drags->set (new TrimDrag (this, clicked_regionview->get_name_highlight(), clicked_regionview, selection->regions.by_layer()), event);
878                                         return true;
879                                 }
880                                 break;
881                         }
882
883                         case ControlPointItem:
884                                 _drags->set (new ControlPointDrag (this, item), event);
885                                 return true;
886                                 break;
887
888                         case AutomationLineItem:
889                                 _drags->set (new LineDrag (this, item), event);
890                                 return true;
891                                 break;
892
893                         case StreamItem:
894                                 _drags->set (new EditorRubberbandSelectDrag (this, item), event);
895                                 return true;
896
897                         case AutomationTrackItem:
898                         {
899                                 TimeAxisView* parent = clicked_axisview->get_parent ();
900                                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (clicked_axisview);
901                                 assert (atv);
902                                 if (parent && dynamic_cast<MidiTimeAxisView*> (parent) && atv->show_regions ()) {
903
904                                         RouteTimeAxisView* p = dynamic_cast<RouteTimeAxisView*> (parent);
905                                         assert (p);
906                                         boost::shared_ptr<Playlist> pl = p->track()->playlist ();
907                                         if (pl->n_regions() == 0) {
908                                                 /* Parent has no regions; create one so that we have somewhere to put automation */
909                                                 _drags->set (new RegionCreateDrag (this, item, parent), event);
910                                         } else {
911                                                 /* See if there's a region before the click that we can extend, and extend it if so */
912                                                 framepos_t const t = canvas_event_sample (event);
913                                                 boost::shared_ptr<Region> prev = pl->find_next_region (t, End, -1);
914                                                 if (!prev) {
915                                                         _drags->set (new RegionCreateDrag (this, item, parent), event);
916                                                 } else {
917                                                         prev->set_length (t - prev->position ());
918                                                 }
919                                         }
920                                 } else {
921                                         /* rubberband drag to select automation points */
922                                         _drags->set (new EditorRubberbandSelectDrag (this, item), event);
923                                 }
924                                 break;
925                         }
926
927                         case SelectionItem:
928                         {
929                                 break;
930                         }
931
932                         case MarkerBarItem:
933
934                                 break;
935
936                         default:
937                                 break;
938                         }
939                 }
940                 return true;
941                 break;
942
943         case MouseDraw:
944                 switch (item_type) {
945                 case GainLineItem:
946                         _drags->set (new LineDrag (this, item), event);
947                         return true;
948
949                 case ControlPointItem:
950                         _drags->set (new ControlPointDrag (this, item), event);
951                         return true;
952                         break;
953
954                 case SelectionItem:
955                 {
956                         if (dynamic_cast<AudioRegionView*>(clicked_regionview) ||
957                             dynamic_cast<AutomationRegionView*>(clicked_regionview)) {
958                                 _drags->set (new AutomationRangeDrag (this, clicked_regionview, selection->time),
959                                              event, _cursors->up_down);
960                         } else {
961                                 double const y = event->button.y;
962                                 pair<TimeAxisView*, int> tvp = trackview_by_y_position (y, false);
963                                 if (tvp.first) {
964                                         AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first);
965                                         if ( atv) {
966                                                 /* smart "join" mode: drag automation */
967                                                 _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down);
968                                         }
969                                 }
970                         }
971                         return true;
972                         break;
973                 }
974
975                 case AutomationLineItem:
976                         _drags->set (new LineDrag (this, item), event);
977                         break;
978
979                 case NoteItem:
980                         if ((note = reinterpret_cast<NoteBase*>(item->get_data ("notebase")))) {
981                                 if (note->big_enough_to_trim() && note->mouse_near_ends()) {
982                                         /* Note is big and pointer is near the end, trim */
983                                         _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
984                                 } else {
985                                         /* Drag note */
986                                         _drags->set (new NoteDrag (this, item), event);
987                                 }
988                                 return true;
989                         }
990                         return true;
991
992                 case StreamItem:
993                         if (dynamic_cast<MidiTimeAxisView*> (clicked_axisview)) {
994                                 _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event);
995                         }
996                         return true;
997
998                 default:
999                         break;
1000                 }
1001                 return true;
1002                 break;
1003
1004         case MouseTimeFX:
1005                 if (item_type == NoteItem) {
1006                         /* resize-drag notes */
1007                         if ((note = reinterpret_cast<NoteBase*>(item->get_data ("notebase")))) {
1008                                 if (note->big_enough_to_trim()) {
1009                                         _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor());
1010                                 }
1011                         }
1012                         return true;
1013                 } else if (clicked_regionview) {
1014                         /* do time-FX  */
1015                         _drags->set (new TimeFXDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
1016                         return true;
1017                 }
1018                 break;
1019
1020         case MouseAudition:
1021                 _drags->set (new ScrubDrag (this, item), event, _cursors->transparent);
1022                 scrub_reversals = 0;
1023                 scrub_reverse_distance = 0;
1024                 last_scrub_x = event->button.x;
1025                 scrubbing_direction = 0;
1026                 return true;
1027                 break;
1028
1029         default:
1030                 break;
1031         }
1032
1033         return false;
1034 }
1035
1036 bool
1037 Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1038 {
1039         Editing::MouseMode const eff = effective_mouse_mode ();
1040         switch (eff) {
1041         case MouseObject:
1042                 switch (item_type) {
1043                 case RegionItem:
1044                         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
1045                                 add_region_copy_drag (item, event, clicked_regionview);
1046                         } else {
1047                                 add_region_drag (item, event, clicked_regionview);
1048                         }
1049                         _drags->start_grab (event);
1050                         return true;
1051                         break;
1052                 case ControlPointItem:
1053                         _drags->set (new ControlPointDrag (this, item), event);
1054                         return true;
1055                         break;
1056
1057                 default:
1058                         break;
1059                 }
1060
1061                 switch (item_type) {
1062                 case RegionViewNameHighlight:
1063                         _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
1064                         return true;
1065                         break;
1066
1067                 case LeftFrameHandle:
1068                 case RightFrameHandle:
1069                         _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
1070                         return true;
1071                         break;
1072
1073                 case RegionViewName:
1074                         _drags->set (new TrimDrag (this, clicked_regionview->get_name_highlight(), clicked_regionview, selection->regions.by_layer()), event);
1075                         return true;
1076                         break;
1077
1078                 default:
1079                         break;
1080                 }
1081
1082                 break;
1083
1084         case MouseDraw:
1085                 return false;
1086
1087         case MouseRange:
1088                 /* relax till release */
1089                 return true;
1090                 break;
1091
1092         default:
1093                 break;
1094         }
1095
1096         return false;
1097 }
1098    
1099 bool
1100 Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1101 {
1102         if (event->type == GDK_2BUTTON_PRESS) {
1103                 _drags->mark_double_click ();
1104                 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1105                 return true;
1106         }
1107
1108         if (event->type != GDK_BUTTON_PRESS) {
1109                 return false;
1110         }
1111
1112         _track_canvas->grab_focus();
1113
1114         if (_session && _session->actively_recording()) {
1115                 return true;
1116         }
1117
1118         button_selection (item, event, item_type);
1119
1120         if (!_drags->active () &&
1121             (Keyboard::is_delete_event (&event->button) ||
1122              Keyboard::is_context_menu_event (&event->button) ||
1123              Keyboard::is_edit_event (&event->button))) {
1124
1125                 /* handled by button release */
1126                 return true;
1127         }
1128
1129         //not rolling, range mode click + join_play_range :  locate the PH here
1130         if ( !_drags->active () && !_session->transport_rolling() && ( effective_mouse_mode() == MouseRange ) && ARDOUR_UI::config()->get_follow_edits() ) {
1131                 framepos_t where = canvas_event_sample (event);
1132                 snap_to(where);
1133                 _session->request_locate (where, false);
1134         }
1135
1136         switch (event->button.button) {
1137         case 1:
1138                 return button_press_handler_1 (item, event, item_type);
1139                 break;
1140
1141         case 2:
1142                 return button_press_handler_2 (item, event, item_type);
1143                 break;
1144
1145         case 3:
1146                 break;
1147
1148         default:
1149                 return button_press_dispatch (&event->button);
1150                 break;
1151
1152         }
1153
1154         return false;
1155 }
1156
1157 bool
1158 Editor::button_press_dispatch (GdkEventButton* ev)
1159 {
1160         /* this function is intended only for buttons 4 and above.
1161          */
1162
1163         Gtkmm2ext::MouseButton b (ev->state, ev->button);
1164         return button_bindings->activate (b, Gtkmm2ext::Bindings::Press);
1165 }
1166
1167 bool
1168 Editor::button_release_dispatch (GdkEventButton* ev)
1169 {
1170         /* this function is intended only for buttons 4 and above.
1171          */
1172
1173         Gtkmm2ext::MouseButton b (ev->state, ev->button);
1174         return button_bindings->activate (b, Gtkmm2ext::Bindings::Release);
1175 }
1176
1177 bool
1178 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1179 {
1180         framepos_t where = canvas_event_sample (event);
1181         AutomationTimeAxisView* atv = 0;
1182
1183         _press_cursor_ctx.reset();
1184
1185         /* no action if we're recording */
1186
1187         if (_session && _session->actively_recording()) {
1188                 return true;
1189         }
1190
1191         bool were_dragging = false;
1192
1193         if (!Keyboard::is_context_menu_event (&event->button)) {
1194
1195                 /* see if we're finishing a drag */
1196                 
1197                 if (_drags->active ()) {
1198                         bool const r = _drags->end_grab (event);
1199                         if (r) {
1200                                 /* grab dragged, so do nothing else */
1201                                 return true;
1202                         }
1203                         
1204                         were_dragging = true;
1205                 }
1206
1207                 update_region_layering_order_editor ();
1208         }
1209
1210         /* edit events get handled here */
1211
1212         if (!_drags->active () && Keyboard::is_edit_event (&event->button)) {
1213                 switch (item_type) {
1214                 case RegionItem:
1215                         show_region_properties ();
1216                         break;
1217
1218                 case TempoMarkerItem: {
1219                         Marker* marker;
1220                         TempoMarker* tempo_marker;
1221                         
1222                         if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
1223                                 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
1224                                 abort(); /*NOTREACHED*/
1225                         }
1226                         
1227                         if ((tempo_marker = dynamic_cast<TempoMarker*> (marker)) == 0) {
1228                                 fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg;
1229                                 abort(); /*NOTREACHED*/
1230                         }
1231                         
1232                         edit_tempo_marker (*tempo_marker);
1233                         break;
1234                 }
1235
1236                 case MeterMarkerItem: {
1237                         Marker* marker;
1238                         MeterMarker* meter_marker;
1239                         
1240                         if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) {
1241                                 fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg;
1242                                 abort(); /*NOTREACHED*/
1243                         }
1244                         
1245                         if ((meter_marker = dynamic_cast<MeterMarker*> (marker)) == 0) {
1246                                 fatal << _("programming error: marker for meter is not a meter marker!") << endmsg;
1247                                 abort(); /*NOTREACHED*/
1248                         }
1249                         edit_meter_marker (*meter_marker);
1250                         break;
1251                 }
1252
1253                 case RegionViewName:
1254                         if (clicked_regionview->name_active()) {
1255                                 return mouse_rename_region (item, event);
1256                         }
1257                         break;
1258
1259                 case ControlPointItem:
1260                         edit_control_point (item);
1261                         break;
1262
1263                 default:
1264                         break;
1265                 }
1266                 return true;
1267         }
1268
1269         /* context menu events get handled here */
1270         if (Keyboard::is_context_menu_event (&event->button)) {
1271
1272                 context_click_event = *event;
1273
1274                 if (!_drags->active ()) {
1275
1276                         /* no matter which button pops up the context menu, tell the menu
1277                            widget to use button 1 to drive menu selection.
1278                         */
1279
1280                         switch (item_type) {
1281                         case FadeInItem:
1282                         case FadeInHandleItem:
1283                         case FadeInTrimHandleItem:
1284                         case StartCrossFadeItem:
1285                                 popup_xfade_in_context_menu (1, event->button.time, item, item_type);
1286                                 break;
1287
1288                         case FadeOutItem:
1289                         case FadeOutHandleItem:
1290                         case FadeOutTrimHandleItem:
1291                         case EndCrossFadeItem:
1292                                 popup_xfade_out_context_menu (1, event->button.time, item, item_type);
1293                                 break;
1294
1295                         case LeftFrameHandle:
1296                         case RightFrameHandle:
1297                                 break;
1298
1299                         case StreamItem:
1300                                 popup_track_context_menu (1, event->button.time, item_type, false);
1301                                 break;
1302
1303                         case RegionItem:
1304                         case RegionViewNameHighlight:
1305                         case RegionViewName:
1306                                 popup_track_context_menu (1, event->button.time, item_type, false);
1307                                 break;
1308
1309                         case SelectionItem:
1310                                 popup_track_context_menu (1, event->button.time, item_type, true);
1311                                 break;
1312                                 
1313                         case AutomationTrackItem:
1314                                 popup_track_context_menu (1, event->button.time, item_type, false);
1315                                 break;
1316
1317                         case MarkerBarItem:
1318                         case RangeMarkerBarItem:
1319                         case TransportMarkerBarItem:
1320                         case CdMarkerBarItem:
1321                         case TempoBarItem:
1322                         case MeterBarItem:
1323                         case VideoBarItem:
1324                         case TimecodeRulerItem:
1325                         case SamplesRulerItem:
1326                         case MinsecRulerItem:
1327                         case BBTRulerItem:
1328                                 popup_ruler_menu (where, item_type);
1329                                 break;
1330
1331                         case MarkerItem:
1332                                 marker_context_menu (&event->button, item);
1333                                 break;
1334
1335                         case TempoMarkerItem:
1336                                 tempo_or_meter_marker_context_menu (&event->button, item);
1337                                 break;
1338
1339                         case MeterMarkerItem:
1340                                 tempo_or_meter_marker_context_menu (&event->button, item);
1341                                 break;
1342
1343                         case CrossfadeViewItem:
1344                                 popup_track_context_menu (1, event->button.time, item_type, false);
1345                                 break;
1346
1347                         case ControlPointItem:
1348                                 popup_control_point_context_menu (item, event);
1349                                 break;
1350
1351                         case NoteItem:
1352                                 if (internal_editing()) {
1353                                         popup_note_context_menu (item, event);
1354                                 }
1355                                 break;
1356
1357                         default:
1358                                 break;
1359                         }
1360
1361                         return true;
1362                 }
1363         }
1364
1365         /* delete events get handled here */
1366
1367         Editing::MouseMode const eff = effective_mouse_mode ();
1368
1369         if (!_drags->active () && Keyboard::is_delete_event (&event->button)) {
1370
1371                 switch (item_type) {
1372                 case TempoMarkerItem:
1373                         remove_tempo_marker (item);
1374                         break;
1375
1376                 case MeterMarkerItem:
1377                         remove_meter_marker (item);
1378                         break;
1379
1380                 case MarkerItem:
1381                         remove_marker (*item, event);
1382                         break;
1383
1384                 case RegionItem:
1385                         if (eff == MouseObject) {
1386                                 remove_clicked_region ();
1387                         }
1388                         break;
1389
1390                 case ControlPointItem:
1391                         remove_control_point (item);
1392                         break;
1393
1394                 case NoteItem:
1395                         remove_midi_note (item, event);
1396                         break;
1397
1398                 default:
1399                         break;
1400                 }
1401                 return true;
1402         }
1403
1404         switch (event->button.button) {
1405         case 1:
1406
1407                 switch (item_type) {
1408                 /* see comments in button_press_handler */
1409                 case PlayheadCursorItem:
1410                 case MarkerItem:
1411                 case GainLineItem:
1412                 case AutomationLineItem:
1413                 case StartSelectionTrimItem:
1414                 case EndSelectionTrimItem:
1415                         return true;
1416
1417                 case MarkerBarItem:
1418                         if (!_dragging_playhead) {
1419                                 snap_to_with_modifier (where, event, RoundNearest, true);
1420                                 mouse_add_new_marker (where);
1421                         }
1422                         return true;
1423
1424                 case CdMarkerBarItem:
1425                         if (!_dragging_playhead) {
1426                                 // if we get here then a dragged range wasn't done
1427                                 snap_to_with_modifier (where, event, RoundNearest, true);
1428                                 mouse_add_new_marker (where, true);
1429                         }
1430                         return true;
1431
1432                 case TempoBarItem:
1433                         if (!_dragging_playhead) {
1434                                 snap_to_with_modifier (where, event);
1435                                 mouse_add_new_tempo_event (where);
1436                         }
1437                         return true;
1438
1439                 case MeterBarItem:
1440                         if (!_dragging_playhead) {
1441                                 mouse_add_new_meter_event (pixel_to_sample (event->button.x));
1442                         }
1443                         return true;
1444                         break;
1445
1446                 case TimecodeRulerItem:
1447                 case SamplesRulerItem:
1448                 case MinsecRulerItem:
1449                 case BBTRulerItem:
1450                         return true;
1451                         break;
1452
1453                 default:
1454                         break;
1455                 }
1456
1457                 switch (eff) {
1458                 case MouseDraw:
1459                         switch (item_type) {
1460                         case RegionItem:
1461                         {
1462                                 /* check that we didn't drag before releasing, since
1463                                    its really annoying to create new control
1464                                    points when doing this.
1465                                 */
1466                                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (clicked_regionview);
1467                                 if (!were_dragging && arv) {
1468                                         bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
1469                                         arv->add_gain_point_event (item, event, with_guard_points);
1470                                 }
1471                                 return true;
1472                                 break;
1473                         }
1474
1475                         case AutomationTrackItem: {
1476                                 bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
1477                                 atv = dynamic_cast<AutomationTimeAxisView*>(clicked_axisview);
1478                                 if (atv) {
1479                                         atv->add_automation_event (event, where, event->button.y, with_guard_points);
1480                                 }
1481                                 return true;
1482                                 break;
1483                         }
1484                         default:
1485                                 break;
1486                         }
1487                         break;
1488
1489                 case MouseAudition:
1490                         if (scrubbing_direction == 0) {
1491                                 /* no drag, just a click */
1492                                 switch (item_type) {
1493                                 case RegionItem:
1494                                         play_selected_region ();
1495                                         break;
1496                                 default:
1497                                         break;
1498                                 }
1499                         } else {
1500                                 /* make sure we stop */
1501                                 _session->request_transport_speed (0.0);
1502                         }
1503                         break;
1504
1505                 default:
1506                         break;
1507
1508                 }
1509
1510                 /* do any (de)selection operations that should occur on button release */
1511                 button_selection (item, event, item_type);
1512
1513                 return true;
1514                 break;
1515
1516
1517         case 2:
1518                 switch (eff) {
1519
1520                 case MouseObject:
1521                         switch (item_type) {
1522                         case RegionItem:
1523                                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1524                                         raise_region ();
1525                                 } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::TertiaryModifier|Keyboard::SecondaryModifier))) {
1526                                         lower_region ();
1527                                 } else {
1528                                         // Button2 click is unused
1529                                 }
1530                                 return true;
1531
1532                                 break;
1533
1534                         default:
1535                                 break;
1536                         }
1537                         break;
1538
1539                 case MouseDraw:
1540                         return true;
1541                         
1542                 case MouseRange:
1543                         // x_style_paste (where, 1.0);
1544                         return true;
1545                         break;
1546
1547                 default:
1548                         break;
1549                 }
1550
1551                 break;
1552
1553         case 3:
1554                 break;
1555
1556         default:
1557                 break;
1558         }
1559
1560         return false;
1561 }
1562
1563 bool
1564 Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
1565 {
1566         ControlPoint* cp;
1567         Marker * marker;
1568         double fraction;
1569         bool ret = true;
1570
1571         /* by the time we reach here, entered_regionview and entered trackview
1572          * will have already been set as appropriate. Things are done this 
1573          * way because this method isn't passed a pointer to a variable type of
1574          * thing that is entered (which may or may not be canvas item).
1575          * (e.g. the actual entered regionview)
1576          */
1577
1578         choose_canvas_cursor_on_entry (item_type);
1579
1580         switch (item_type) {
1581         case ControlPointItem:
1582                 if (mouse_mode == MouseDraw || mouse_mode == MouseObject) {
1583                         cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
1584                         cp->show ();
1585
1586                         fraction = 1.0 - (cp->get_y() / cp->line().height());
1587
1588                         _verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction));
1589                         _verbose_cursor->show ();
1590                 }
1591                 break;
1592
1593         case GainLineItem:
1594                 if (mouse_mode == MouseDraw) {
1595                         ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1596                         if (line) {
1597                                 line->set_outline_color (ARDOUR_UI::config()->color ("entered gain line"));
1598                         }
1599                 }
1600                 break;
1601
1602         case AutomationLineItem:
1603                 if (mouse_mode == MouseDraw || mouse_mode == MouseObject) {
1604                         ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1605                         if (line) {
1606                                 line->set_outline_color (ARDOUR_UI::config()->color ("entered automation line"));
1607                         }
1608                 }
1609                 break;
1610
1611         case AutomationTrackItem:
1612                 AutomationTimeAxisView* atv;
1613                 if ((atv = static_cast<AutomationTimeAxisView*>(item->get_data ("trackview"))) != 0) {
1614                         clear_entered_track = false;
1615                         set_entered_track (atv);
1616                 }
1617                 break;
1618
1619         case MarkerItem:
1620                 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1621                         break;
1622                 }
1623                 entered_marker = marker;
1624                 marker->set_color_rgba (ARDOUR_UI::config()->color ("entered marker"));
1625                 // fall through
1626         case MeterMarkerItem:
1627         case TempoMarkerItem:
1628                 break;
1629
1630         case FadeInHandleItem:
1631         case FadeInTrimHandleItem:
1632                 if (mouse_mode == MouseObject) {
1633                         ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
1634                         if (rect) {
1635                                 RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview"));
1636                                 rect->set_fill_color (rv->get_fill_color());
1637                         }
1638                 }
1639                 break;
1640
1641         case FadeOutHandleItem:
1642         case FadeOutTrimHandleItem:
1643                 if (mouse_mode == MouseObject) {
1644                         ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
1645                         if (rect) {
1646                                 RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview"));
1647                                 rect->set_fill_color (rv->get_fill_color ());
1648                         }
1649                 }
1650                 break;
1651
1652         case FeatureLineItem:
1653         {
1654                 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1655                 line->set_outline_color (0xFF0000FF);
1656         }
1657         break;
1658
1659         case SelectionItem:
1660                 break;
1661
1662         default:
1663                 break;
1664         }
1665
1666         /* third pass to handle entered track status in a comprehensible way.
1667          */
1668
1669         switch (item_type) {
1670         case GainLineItem:
1671         case AutomationLineItem:
1672         case ControlPointItem:
1673                 /* these do not affect the current entered track state */
1674                 clear_entered_track = false;
1675                 break;
1676
1677         case AutomationTrackItem:
1678                 /* handled above already */
1679                 break;
1680
1681         default:
1682
1683                 break;
1684         }
1685
1686         return ret;
1687 }
1688
1689 bool
1690 Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
1691 {
1692         AutomationLine* al;
1693         Marker *marker;
1694         Location *loc;
1695         bool is_start;
1696         bool ret = true;
1697
1698         if (!_enter_stack.empty()) {
1699                 _enter_stack.pop_back();
1700         }
1701
1702         switch (item_type) {
1703         case ControlPointItem:
1704                 _verbose_cursor->hide (); 
1705                 break;
1706
1707         case GainLineItem:
1708         case AutomationLineItem:
1709                 al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
1710                 {
1711                         ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1712                         if (line) {
1713                                 line->set_outline_color (al->get_line_color());
1714                         }
1715                 }
1716                 break;
1717
1718         case MarkerItem:
1719                 if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
1720                         break;
1721                 }
1722                 entered_marker = 0;
1723                 if ((loc = find_location_from_marker (marker, is_start)) != 0) {
1724                         location_flags_changed (loc);
1725                 }
1726                 // fall through
1727         case MeterMarkerItem:
1728         case TempoMarkerItem:
1729                 break;
1730
1731         case FadeInTrimHandleItem:
1732         case FadeOutTrimHandleItem:
1733         case FadeInHandleItem:
1734         case FadeOutHandleItem:
1735         {
1736                 ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item);
1737                 if (rect) {
1738                         rect->set_fill_color (ARDOUR_UI::config()->color ("inactive fade handle"));
1739                 }
1740         }
1741         break;
1742
1743         case AutomationTrackItem:
1744                 break;
1745
1746         case FeatureLineItem:
1747         {
1748                 ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
1749                 line->set_outline_color (ARDOUR_UI::config()->color ("zero line"));
1750         }
1751         break;
1752
1753         default:
1754                 break;
1755         }
1756
1757         return ret;
1758 }
1759
1760 void
1761 Editor::scrub (framepos_t frame, double current_x)
1762 {
1763         double delta;
1764
1765         if (scrubbing_direction == 0) {
1766                 /* first move */
1767                 _session->request_locate (frame, false);
1768                 _session->request_transport_speed (0.1);
1769                 scrubbing_direction = 1;
1770
1771         } else {
1772
1773                 if (last_scrub_x > current_x) {
1774
1775                         /* pointer moved to the left */
1776
1777                         if (scrubbing_direction > 0) {
1778
1779                                 /* we reversed direction to go backwards */
1780
1781                                 scrub_reversals++;
1782                                 scrub_reverse_distance += (int) (last_scrub_x - current_x);
1783
1784                         } else {
1785
1786                                 /* still moving to the left (backwards) */
1787
1788                                 scrub_reversals = 0;
1789                                 scrub_reverse_distance = 0;
1790
1791                                 delta = 0.01 * (last_scrub_x - current_x);
1792                                 _session->request_transport_speed_nonzero (_session->transport_speed() - delta);
1793                         }
1794
1795                 } else {
1796                         /* pointer moved to the right */
1797
1798                         if (scrubbing_direction < 0) {
1799                                 /* we reversed direction to go forward */
1800
1801                                 scrub_reversals++;
1802                                 scrub_reverse_distance += (int) (current_x - last_scrub_x);
1803
1804                         } else {
1805                                 /* still moving to the right */
1806
1807                                 scrub_reversals = 0;
1808                                 scrub_reverse_distance = 0;
1809
1810                                 delta = 0.01 * (current_x - last_scrub_x);
1811                                 _session->request_transport_speed_nonzero (_session->transport_speed() + delta);
1812                         }
1813                 }
1814
1815                 /* if there have been more than 2 opposite motion moves detected, or one that moves
1816                    back more than 10 pixels, reverse direction
1817                 */
1818
1819                 if (scrub_reversals >= 2 || scrub_reverse_distance > 10) {
1820
1821                         if (scrubbing_direction > 0) {
1822                                 /* was forwards, go backwards */
1823                                 _session->request_transport_speed (-0.1);
1824                                 scrubbing_direction = -1;
1825                         } else {
1826                                 /* was backwards, go forwards */
1827                                 _session->request_transport_speed (0.1);
1828                                 scrubbing_direction = 1;
1829                         }
1830
1831                         scrub_reverse_distance = 0;
1832                         scrub_reversals = 0;
1833                 }
1834         }
1835
1836         last_scrub_x = current_x;
1837 }
1838
1839 bool
1840 Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from_autoscroll)
1841 {
1842         _last_motion_y = event->motion.y;
1843
1844         if (event->motion.is_hint) {
1845                 gint x, y;
1846
1847                 /* We call this so that MOTION_NOTIFY events continue to be
1848                    delivered to the canvas. We need to do this because we set
1849                    Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces
1850                    the density of the events, at the expense of a round-trip
1851                    to the server. Given that this will mostly occur on cases
1852                    where DISPLAY = :0.0, and given the cost of what the motion
1853                    event might do, its a good tradeoff.
1854                 */
1855
1856                 _track_canvas->get_pointer (x, y);
1857         }
1858
1859         if (current_stepping_trackview) {
1860                 /* don't keep the persistent stepped trackview if the mouse moves */
1861                 current_stepping_trackview = 0;
1862                 step_timeout.disconnect ();
1863         }
1864         
1865         if (_session && _session->actively_recording()) {
1866                 /* Sorry. no dragging stuff around while we record */
1867                 return true;
1868         }
1869         
1870         update_join_object_range_location (event->motion.y);
1871         
1872         if (_drags->active ()) {
1873                 return _drags->motion_handler (event, from_autoscroll);
1874         }
1875
1876         return false;
1877 }
1878
1879 bool
1880 Editor::can_remove_control_point (ArdourCanvas::Item* item)
1881 {
1882         ControlPoint* control_point;
1883
1884         if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
1885                 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
1886                 abort(); /*NOTREACHED*/
1887         }
1888
1889         AutomationLine& line = control_point->line ();
1890         if (dynamic_cast<AudioRegionGainLine*> (&line)) {
1891                 /* we shouldn't remove the first or last gain point in region gain lines */
1892                 if (line.is_last_point(*control_point) || line.is_first_point(*control_point)) {
1893                         return false;
1894                 }
1895         }
1896
1897         return true;
1898 }
1899
1900 void
1901 Editor::remove_control_point (ArdourCanvas::Item* item)
1902 {
1903         if (!can_remove_control_point (item)) {
1904                 return;
1905         }
1906
1907         ControlPoint* control_point;
1908
1909         if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
1910                 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
1911                 abort(); /*NOTREACHED*/
1912         }
1913
1914         control_point->line().remove_point (*control_point);
1915 }
1916
1917 void
1918 Editor::edit_control_point (ArdourCanvas::Item* item)
1919 {
1920         ControlPoint* p = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
1921
1922         if (p == 0) {
1923                 fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
1924                 abort(); /*NOTREACHED*/
1925         }
1926
1927         ControlPointDialog d (p);
1928         ensure_float (d);
1929
1930         if (d.run () != RESPONSE_ACCEPT) {
1931                 return;
1932         }
1933
1934         p->line().modify_point_y (*p, d.get_y_fraction ());
1935 }
1936
1937 void
1938 Editor::edit_notes (MidiRegionView* mrv)
1939 {
1940         MidiRegionView::Selection const & s = mrv->selection();
1941
1942         if (s.empty ()) {
1943                 return;
1944         }
1945
1946         EditNoteDialog* d = new EditNoteDialog (mrv, s);
1947         d->show_all ();
1948         ensure_float (*d);
1949
1950         d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d));
1951 }
1952
1953 void
1954 Editor::note_edit_done (int r, EditNoteDialog* d)
1955 {
1956         d->done (r);
1957         delete d;
1958 }
1959
1960 void
1961 Editor::visible_order_range (int* low, int* high) const
1962 {
1963         *low = TimeAxisView::max_order ();
1964         *high = 0;
1965
1966         for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
1967
1968                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
1969
1970                 if (!rtv->hidden()) {
1971
1972                         if (*high < rtv->order()) {
1973                                 *high = rtv->order ();
1974                         }
1975
1976                         if (*low > rtv->order()) {
1977                                 *low = rtv->order ();
1978                         }
1979                 }
1980         }
1981 }
1982
1983 void
1984 Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
1985 {
1986         /* Either add to or set the set the region selection, unless
1987            this is an alignment click (control used)
1988         */
1989
1990         if (Keyboard::modifier_state_contains (event->state, Keyboard::PrimaryModifier)) {
1991                 TimeAxisView* tv = &rv.get_time_axis_view();
1992                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1993                 double speed = 1.0;
1994                 if (rtv && rtv->is_track()) {
1995                         speed = rtv->track()->speed();
1996                 }
1997
1998                 framepos_t where = get_preferred_edit_position();
1999
2000                 if (where >= 0) {
2001
2002                         if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
2003
2004                                 align_region (rv.region(), SyncPoint, (framepos_t) (where * speed));
2005
2006                         } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
2007
2008                                 align_region (rv.region(), End, (framepos_t) (where * speed));
2009
2010                         } else {
2011
2012                                 align_region (rv.region(), Start, (framepos_t) (where * speed));
2013                         }
2014                 }
2015         }
2016 }
2017
2018 void
2019 Editor::collect_new_region_view (RegionView* rv)
2020 {
2021         latest_regionviews.push_back (rv);
2022 }
2023
2024 void
2025 Editor::collect_and_select_new_region_view (RegionView* rv)
2026 {
2027         selection->add(rv);
2028         latest_regionviews.push_back (rv);
2029 }
2030
2031 void
2032 Editor::cancel_selection ()
2033 {
2034         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2035                 (*i)->hide_selection ();
2036         }
2037
2038         selection->clear ();
2039         clicked_selection = 0;
2040 }
2041
2042 void
2043 Editor::cancel_time_selection ()
2044 {
2045         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
2046                 (*i)->hide_selection ();
2047         }
2048         selection->time.clear ();
2049         clicked_selection = 0;
2050 }       
2051
2052 void
2053 Editor::point_trim (GdkEvent* event, framepos_t new_bound)
2054 {
2055         RegionView* rv = clicked_regionview;
2056
2057         /* Choose action dependant on which button was pressed */
2058         switch (event->button.button) {
2059         case 1:
2060                 begin_reversible_command (_("start point trim"));
2061
2062                 if (selection->selected (rv)) {
2063                         for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin();
2064                              i != selection->regions.by_layer().end(); ++i)
2065                         {
2066                                 if (!(*i)->region()->locked()) {
2067                                         (*i)->region()->clear_changes ();
2068                                         (*i)->region()->trim_front (new_bound);
2069                                         _session->add_command(new StatefulDiffCommand ((*i)->region()));
2070                                 }
2071                         }
2072
2073                 } else {
2074                         if (!rv->region()->locked()) {
2075                                 rv->region()->clear_changes ();
2076                                 rv->region()->trim_front (new_bound);
2077                                 _session->add_command(new StatefulDiffCommand (rv->region()));
2078                         }
2079                 }
2080
2081                 commit_reversible_command();
2082
2083                 break;
2084         case 2:
2085                 begin_reversible_command (_("End point trim"));
2086
2087                 if (selection->selected (rv)) {
2088
2089                         for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i)
2090                         {
2091                                 if (!(*i)->region()->locked()) {
2092                                         (*i)->region()->clear_changes();
2093                                         (*i)->region()->trim_end (new_bound);
2094                                         _session->add_command(new StatefulDiffCommand ((*i)->region()));
2095                                 }
2096                         }
2097
2098                 } else {
2099
2100                         if (!rv->region()->locked()) {
2101                                 rv->region()->clear_changes ();
2102                                 rv->region()->trim_end (new_bound);
2103                                 _session->add_command (new StatefulDiffCommand (rv->region()));
2104                         }
2105                 }
2106
2107                 commit_reversible_command();
2108
2109                 break;
2110         default:
2111                 break;
2112         }
2113 }
2114
2115 void
2116 Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* /*event*/)
2117 {
2118         Marker* marker;
2119         bool is_start;
2120
2121         if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
2122                 fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg;
2123                 abort(); /*NOTREACHED*/
2124         }
2125
2126         Location* location = find_location_from_marker (marker, is_start);
2127         location->set_hidden (true, this);
2128 }
2129
2130 gint
2131 Editor::mouse_rename_region (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/)
2132 {
2133         using namespace Gtkmm2ext;
2134
2135         ArdourPrompter prompter (false);
2136
2137         prompter.set_prompt (_("Name for region:"));
2138         prompter.set_initial_text (clicked_regionview->region()->name());
2139         prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
2140         prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
2141         prompter.show_all ();
2142         switch (prompter.run ()) {
2143         case Gtk::RESPONSE_ACCEPT:
2144                 string str;
2145                 prompter.get_result(str);
2146                 if (str.length()) {
2147                         clicked_regionview->region()->set_name (str);
2148                 }
2149                 break;
2150         }
2151         return true;
2152 }
2153
2154
2155 void
2156 Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos)
2157 {
2158         /* no brushing without a useful snap setting */
2159
2160         switch (_snap_mode) {
2161         case SnapMagnetic:
2162                 return; /* can't work because it allows region to be placed anywhere */
2163         default:
2164                 break; /* OK */
2165         }
2166
2167         switch (_snap_type) {
2168         case SnapToMark:
2169                 return;
2170
2171         default:
2172                 break;
2173         }
2174
2175         /* don't brush a copy over the original */
2176
2177         if (pos == rv->region()->position()) {
2178                 return;
2179         }
2180
2181         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view());
2182
2183         if (rtv == 0 || !rtv->is_track()) {
2184                 return;
2185         }
2186
2187         boost::shared_ptr<Playlist> playlist = rtv->playlist();
2188         double speed = rtv->track()->speed();
2189
2190         playlist->clear_changes ();
2191         boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region(), true));
2192         playlist->add_region (new_region, (framepos_t) (pos * speed));
2193         _session->add_command (new StatefulDiffCommand (playlist));
2194
2195         // playlist is frozen, so we have to update manually XXX this is disgusting
2196
2197         playlist->RegionAdded (new_region); /* EMIT SIGNAL */
2198 }
2199
2200 gint
2201 Editor::track_height_step_timeout ()
2202 {
2203         if (get_microseconds() - last_track_height_step_timestamp < 250000) {
2204                 current_stepping_trackview = 0;
2205                 return false;
2206         }
2207         return true;
2208 }
2209
2210 void
2211 Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region_view)
2212 {
2213         assert (region_view);
2214
2215         if (!region_view->region()->playlist()) {
2216                 return;
2217         }
2218
2219         switch (Config->get_edit_mode()) {
2220                 case Splice:
2221                         _drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer()));
2222                         break;
2223                 case Ripple:
2224                         _drags->add (new RegionRippleDrag (this, item, region_view, selection->regions.by_layer()));
2225                         break;
2226                 default:
2227                         _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false));
2228                         break;
2229
2230         }
2231 }
2232
2233 void
2234 Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region_view)
2235 {
2236         assert (region_view);
2237
2238         if (!region_view->region()->playlist()) {
2239                 return;
2240         }
2241
2242         _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, true));
2243 }
2244
2245 void
2246 Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region_view)
2247 {
2248         assert (region_view);
2249
2250         if (!region_view->region()->playlist()) {
2251                 return;
2252         }
2253
2254         if (Config->get_edit_mode() == Splice || Config->get_edit_mode() == Ripple) {
2255                 return;
2256         }
2257
2258         _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), true, false));
2259
2260         begin_reversible_command (Operations::drag_region_brush);
2261 }
2262
2263 /** Start a grab where a time range is selected, track(s) are selected, and the
2264  *  user clicks and drags a region with a modifier in order to create a new region containing
2265  *  the section of the clicked region that lies within the time range.
2266  */
2267 void
2268 Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event)
2269 {
2270         if (clicked_regionview == 0) {
2271                 return;
2272         }
2273
2274         /* lets try to create new Region for the selection */
2275
2276         vector<boost::shared_ptr<Region> > new_regions;
2277         create_region_from_selection (new_regions);
2278
2279         if (new_regions.empty()) {
2280                 return;
2281         }
2282
2283         /* XXX fix me one day to use all new regions */
2284
2285         boost::shared_ptr<Region> region (new_regions.front());
2286
2287         /* add it to the current stream/playlist.
2288
2289            tricky: the streamview for the track will add a new regionview. we will
2290            catch the signal it sends when it creates the regionview to
2291            set the regionview we want to then drag.
2292         */
2293
2294         latest_regionviews.clear();
2295         sigc::connection c = clicked_routeview->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
2296
2297         /* A selection grab currently creates two undo/redo operations, one for
2298            creating the new region and another for moving it.
2299         */
2300
2301         begin_reversible_command (Operations::selection_grab);
2302
2303         boost::shared_ptr<Playlist> playlist = clicked_axisview->playlist();
2304
2305         playlist->clear_changes ();
2306         clicked_routeview->playlist()->add_region (region, selection->time[clicked_selection].start);
2307         _session->add_command(new StatefulDiffCommand (playlist));
2308
2309         c.disconnect ();
2310
2311         if (latest_regionviews.empty()) {
2312                 /* something went wrong */
2313                 return;
2314         }
2315
2316         /* we need to deselect all other regionviews, and select this one
2317            i'm ignoring undo stuff, because the region creation will take care of it
2318         */
2319
2320         selection->set (latest_regionviews);
2321
2322         commit_reversible_command ();
2323
2324         _drags->set (new RegionMoveDrag (this, latest_regionviews.front()->get_canvas_group(), latest_regionviews.front(), latest_regionviews, false, false), event);
2325 }
2326
2327 void
2328 Editor::escape ()
2329 {
2330         if (_drags->active ()) {
2331                 _drags->abort ();
2332         } else {
2333                 selection->clear ();
2334         }
2335
2336         reset_focus ();
2337 }
2338
2339 /** Update _join_object_range_state which indicate whether we are over the top
2340  *  or bottom half of a route view, used by the `join object/range' tool
2341  *  mode. Coordinates in canvas space.
2342  */
2343 void
2344 Editor::update_join_object_range_location (double y)
2345 {
2346         if (!get_smart_mode()) {
2347                 _join_object_range_state = JOIN_OBJECT_RANGE_NONE;
2348                 return;
2349         }
2350
2351         JoinObjectRangeState const old = _join_object_range_state;
2352
2353         if (mouse_mode == MouseObject) {
2354                 _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
2355         } else if (mouse_mode == MouseRange) {
2356                 _join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
2357         }
2358
2359         if (entered_regionview) {
2360
2361                 ArdourCanvas::Duple const item_space = entered_regionview->get_canvas_group()->canvas_to_item (ArdourCanvas::Duple (0, y));
2362                 double const c = item_space.y / entered_regionview->height();
2363
2364                 _join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT;
2365
2366                 Editor::EnterContext* ctx = get_enter_context(RegionItem);
2367                 if (_join_object_range_state != old && ctx) {
2368                         ctx->cursor_ctx->change(which_track_cursor());
2369                 }
2370
2371         } else if (entered_track) {
2372
2373                 RouteTimeAxisView* entered_route_view = dynamic_cast<RouteTimeAxisView*> (entered_track);
2374                 
2375                 if (entered_route_view) {
2376
2377                         double cx = 0;
2378                         double cy = y;
2379
2380                         entered_route_view->canvas_display()->canvas_to_item (cx, cy);
2381
2382                         double track_height = entered_route_view->view()->child_height();
2383                         if (ARDOUR_UI::config()->get_show_name_highlight()) {
2384                                 track_height -= TimeAxisViewItem::NAME_HIGHLIGHT_SIZE;
2385                         }
2386                         double const c = cy / track_height;
2387
2388
2389                         if (c <= 0.5) {
2390                                 _join_object_range_state = JOIN_OBJECT_RANGE_RANGE;
2391                         } else {
2392                                 _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
2393                         }
2394
2395                 } else {
2396                         /* Other kinds of tracks use object mode */
2397                         _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
2398                 }
2399
2400                 Editor::EnterContext* ctx = get_enter_context(StreamItem);
2401                 if (_join_object_range_state != old && ctx) {
2402                         ctx->cursor_ctx->change(which_track_cursor());
2403                 }
2404         }
2405 }
2406
2407 Editing::MouseMode
2408 Editor::effective_mouse_mode () const
2409 {
2410         if (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
2411                 return MouseObject;
2412         } else if (_join_object_range_state == JOIN_OBJECT_RANGE_RANGE) {
2413                 return MouseRange;
2414         }
2415
2416         return mouse_mode;
2417 }
2418
2419 void
2420 Editor::remove_midi_note (ArdourCanvas::Item* item, GdkEvent *)
2421 {
2422         NoteBase* e = reinterpret_cast<NoteBase*> (item->get_data ("notebase"));
2423         assert (e);
2424
2425         e->region_view().delete_note (e->note ());
2426 }
2427
2428 /** Obtain the pointer position in canvas coordinates */
2429 void
2430 Editor::get_pointer_position (double& x, double& y) const
2431 {
2432         int px, py;
2433         _track_canvas->get_pointer (px, py);
2434         _track_canvas->window_to_canvas (px, py, x, y);
2435 }