another part of #3512 for the dark theme
[ardour.git] / gtk2_ardour / editor_mouse.cc
index d1d9afc985c74f48ab92a1b2b65f6b8b330b4a86..b47934554c0495406b4cd2ac184e96efd1c4188f 100644 (file)
 
 #include "pbd/error.h"
 #include "pbd/enumwriter.h"
-#include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/tearoff.h>
 #include "pbd/memento_command.h"
 #include "pbd/basename.h"
 #include "pbd/stateful_diff_command.h"
 
+#include "gtkmm2ext/bindings.h"
+#include "gtkmm2ext/utils.h"
+#include "gtkmm2ext/tearoff.h"
+
 #include "ardour_ui.h"
 #include "actions.h"
 #include "canvas-note.h"
 #include "edit_note_dialog.h"
 #include "mouse_cursors.h"
 #include "editor_cursors.h"
+#include "verbose_cursor.h"
 
 #include "ardour/types.h"
 #include "ardour/profile.h"
 #include "ardour/route.h"
 #include "ardour/audio_track.h"
-#include "ardour/audio_diskstream.h"
-#include "ardour/midi_diskstream.h"
 #include "ardour/playlist.h"
 #include "ardour/audioplaylist.h"
 #include "ardour/audioregion.h"
@@ -204,7 +205,7 @@ Editor::which_grabber_cursor ()
                        boost::shared_ptr<Movable> m = _movable.lock();
                        if (m && m->locked()) {
                                c = _cursors->speaker;
-                       } 
+                       }
                        break;
                }
        }
@@ -370,27 +371,24 @@ Editor::mouse_mode_toggled (MouseMode m)
        mouse_mode = m;
 
        instant_save ();
-        
+
        if (!internal_editing()) {
                if (mouse_mode != MouseRange && _join_object_range_state == JOIN_OBJECT_RANGE_NONE) {
-                        
+
                        /* in all modes except range and joined object/range, hide the range selection,
                           show the object (region) selection.
                        */
-                        
-                       for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
-                               (*i)->set_should_show_selection (true);
-                       }
+
                        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                                (*i)->hide_selection ();
                        }
-                        
+
                } else {
-                        
+
                        /*
                          in range or object/range mode, show the range selection.
                        */
-                        
+
                        for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
                                (*i)->show_selection (selection->time);
                        }
@@ -506,8 +504,6 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
        Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
        bool press = (event->type == GDK_BUTTON_PRESS);
 
-       // begin_reversible_command (_("select on click"));
-
        switch (item_type) {
        case RegionItem:
                if (mouse_mode != MouseRange || _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) {
@@ -591,26 +587,42 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                return true;
 
        case TempoMarkerItem:
-               _drags->set (
-                       new TempoMarkerDrag (
-                               this,
-                               item,
-                               Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)
-                               ),
-                       event
-                       );
-               return true;
+       {
+               TempoMarker* m = reinterpret_cast<TempoMarker*> (item->get_data ("marker"));
+               assert (m);
+               if (m->tempo().movable ()) {
+                       _drags->set (
+                               new TempoMarkerDrag (
+                                       this,
+                                       item,
+                                       Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)
+                                       ),
+                               event
+                               );
+                       return true;
+               } else {
+                       return false;
+               }
+       }
 
        case MeterMarkerItem:
-               _drags->set (
-                       new MeterMarkerDrag (
-                               this,
-                               item,
-                               Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)
-                               ),
-                       event
-                       );
-               return true;
+       {
+               MeterMarker* m = reinterpret_cast<MeterMarker*> (item->get_data ("marker"));
+               assert (m);
+               if (m->meter().movable ()) {
+                       _drags->set (
+                               new MeterMarkerDrag (
+                                       this,
+                                       item,
+                                       Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)
+                                       ),
+                               event
+                               );
+                       return true;
+               } else {
+                       return false;
+               }
+       }
 
        case MarkerBarItem:
        case TempoBarItem:
@@ -714,8 +726,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        if (internal_editing()) {
                                /* trim notes if we're in internal edit mode and near the ends of the note */
                                ArdourCanvas::CanvasNote* cn = dynamic_cast<ArdourCanvas::CanvasNote*> (item);
-                               cerr << "NoteItem button press, cursor = " << current_canvas_cursor << endl;
-                               if (cn->mouse_near_ends()) {
+                               if (cn && cn->big_enough_to_trim() && cn->mouse_near_ends()) {
                                        _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor);
                                } else {
                                        _drags->set (new NoteDrag (this, item), event);
@@ -728,7 +739,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                if (dynamic_cast<MidiTimeAxisView*> (clicked_axisview)) {
                                        _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event);
                                        return true;
-                               }
+                               } 
                        } else {
                                _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event);
                                return true;
@@ -736,9 +747,16 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        break;
 
                case RegionViewNameHighlight:
+                       if (!clicked_regionview->region()->locked()) {
+                               RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
+                               _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event);
+                               return true;
+                       }
+                       break;
+
                case LeftFrameHandle:
                case RightFrameHandle:
-                       if (!clicked_regionview->region()->locked()) {
+                       if (!internal_editing() && !clicked_regionview->region()->locked()) {
                                RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
                                _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event);
                                return true;
@@ -766,7 +784,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                return true;
                        }
                        break;
-                       
+
                default:
                        break;
                }
@@ -774,7 +792,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) &&
                    event->type == GDK_BUTTON_PRESS) {
 
-                       _drags->set (new RubberbandSelectDrag (this, item), event);
+                       _drags->set (new EditorRubberbandSelectDrag (this, item), event);
 
                } else if (event->type == GDK_BUTTON_PRESS) {
 
@@ -794,12 +812,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        }
 
                        case FeatureLineItem:
-                       {                       
+                       {
                                if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) {
                                        remove_transient(item);
                                        return true;
                                }
-                               
+
                                _drags->set (new FeatureLineDrag (this, item), event);
                                return true;
                                break;
@@ -817,17 +835,16 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                        /* no region drags in internal edit mode */
                                        break;
                                }
-                               
+
                                /* click on a normal region view */
                                if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
                                        add_region_copy_drag (item, event, clicked_regionview);
-                               } 
-                               else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
+                               } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) {
                                        add_region_brush_drag (item, event, clicked_regionview);
                                } else {
                                        add_region_drag (item, event, clicked_regionview);
                                }
-                               
+
                                if (_join_object_range_state == JOIN_OBJECT_RANGE_OBJECT && !selection->regions.empty()) {
                                        _drags->add (new SelectionDrag (this, clicked_axisview->get_selection_rect (clicked_selection)->rect, SelectionDrag::SelectionMove));
                                }
@@ -838,7 +855,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        case RegionViewNameHighlight:
                        case LeftFrameHandle:
                         case RightFrameHandle:
-                               if (!internal_editing () && !clicked_regionview->region()->locked()) {
+                               if (!clicked_regionview->region()->locked()) {
                                        RegionSelection s = get_equivalent_regions (selection->regions, Properties::edit.property_id);
                                        _drags->set (new TrimDrag (this, item, clicked_regionview, s.by_layer()), event);
                                        return true;
@@ -871,14 +888,24 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                        }
                                        return true;
                                } else {
-                                       _drags->set (new RubberbandSelectDrag (this, item), event);
+                                       _drags->set (new EditorRubberbandSelectDrag (this, item), event);
                                }
                                break;
-                               
+
                        case AutomationTrackItem:
-                               /* rubberband drag to select automation points */
-                               _drags->set (new RubberbandSelectDrag (this, item), event);
+                       {
+                               TimeAxisView* parent = clicked_axisview->get_parent ();
+                               AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (clicked_axisview);
+                               assert (atv);
+                               if (parent && dynamic_cast<MidiTimeAxisView*> (parent) && atv->show_regions ()) {
+                                       /* create a MIDI region so that we have somewhere to put automation */
+                                       _drags->set (new RegionCreateDrag (this, item, parent), event);
+                               } else {
+                                       /* rubberband drag to select automation points */
+                                       _drags->set (new EditorRubberbandSelectDrag (this, item), event);
+                               }
                                break;
+                       }
 
                        case SelectionItem:
                        {
@@ -902,7 +929,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                                        if (t) {
                                                                boost::shared_ptr<Playlist> pl = t->playlist ();
                                                                if (pl) {
-                                                                       
+
                                                                        boost::shared_ptr<Region> r = pl->top_region_at (event_frame (event));
                                                                        if (r) {
                                                                                RegionView* rv = rtv->view()->find_view (r);
@@ -1047,6 +1074,11 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
        case MouseObject:
                switch (item_type) {
                case RegionItem:
+                       if (internal_editing ()) {
+                               /* no region drags in internal edit mode */
+                               return false;
+                       }
+
                        if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) {
                                add_region_copy_drag (item, event, clicked_regionview);
                        } else {
@@ -1066,6 +1098,10 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
                switch (item_type) {
                case RegionViewNameHighlight:
+                        _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event);
+                        return true;
+                        break;
+
                 case LeftFrameHandle:
                 case RightFrameHandle:
                        if (!internal_editing ()) {
@@ -1093,7 +1129,7 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
        case MouseZoom:
                if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
-                       temporal_zoom_session();
+                       temporal_zoom_to_frame (false, event_frame (event));
                } else {
                        temporal_zoom_to_frame (true, event_frame(event));
                }
@@ -1161,6 +1197,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                break;
 
        default:
+                return button_press_dispatch (&event->button);
                break;
 
        }
@@ -1168,6 +1205,26 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
        return false;
 }
 
+bool
+Editor::button_press_dispatch (GdkEventButton* ev)
+{
+        /* this function is intended only for buttons 4 and above.
+         */
+
+        Gtkmm2ext::MouseButton b (ev->state, ev->button);
+        return button_bindings->activate (b, Gtkmm2ext::Bindings::Press);
+}
+
+bool
+Editor::button_release_dispatch (GdkEventButton* ev)
+{
+        /* this function is intended only for buttons 4 and above.
+         */
+
+        Gtkmm2ext::MouseButton b (ev->state, ev->button);
+        return button_bindings->activate (b, Gtkmm2ext::Bindings::Release);
+}
+
 bool
 Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
@@ -1299,6 +1356,10 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                popup_track_context_menu (1, event->button.time, item_type, false);
                                break;
 
+                       case ControlPointItem:
+                               popup_control_point_context_menu (item, event);
+                               break;
+
 #ifdef WITH_CMT
                        case ImageFrameItem:
                                popup_imageframe_edit_menu(1, event->button.time, item, true) ;
@@ -1348,11 +1409,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        break;
 
                case ControlPointItem:
-                       if (eff == MouseGain) {
-                               remove_gain_control_point (item, event);
-                       } else {
-                               remove_control_point (item, event);
-                       }
+                       remove_control_point (item);
                        break;
 
                case NoteItem:
@@ -1417,7 +1474,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        case AutomationTrackItem:
                                atv = dynamic_cast<AutomationTimeAxisView*>(clicked_axisview);
                                if (atv) {
-                                       atv->add_automation_event (item, event, where, event->button.y);
+                                       atv->add_automation_event (event, where, event->button.y);
                                }
                                return true;
                                break;
@@ -1445,7 +1502,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
                        case AutomationTrackItem:
                                dynamic_cast<AutomationTimeAxisView*>(clicked_axisview)->
-                                       add_automation_event (item, event, where, event->button.y);
+                                       add_automation_event (event, where, event->button.y);
                                return true;
                                break;
                        default:
@@ -1454,7 +1511,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        break;
 
                case MouseAudition:
-                        set_canvas_cursor (current_canvas_cursor);
+                       set_canvas_cursor (current_canvas_cursor);
                        if (scrubbing_direction == 0) {
                                /* no drag, just a click */
                                switch (item_type) {
@@ -1475,6 +1532,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
                }
 
+                /* do any (de)selection operations that should occur on button release */
+                button_selection (item, event, item_type);
                return true;
                break;
 
@@ -1519,6 +1578,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
        default:
                break;
        }
+
        return false;
 }
 
@@ -1551,8 +1611,8 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                                set_canvas_cursor (_cursors->fader);
                        }
 
-                       set_verbose_canvas_cursor (cp->line().get_verbose_cursor_string (fraction), at_x, at_y);
-                       show_verbose_canvas_cursor ();
+                       _verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction), at_x, at_y);
+                       _verbose_cursor->show ();
                }
                break;
 
@@ -1581,7 +1641,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                break;
 
        case RegionViewNameHighlight:
-               if (is_drawable() && mouse_mode == MouseObject && !internal_editing() && entered_regionview) {
+               if (is_drawable() && mouse_mode == MouseObject && entered_regionview) {
                        set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview);
                        _over_region_trim_target = true;
                }
@@ -1595,17 +1655,21 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                 break;
 
        case StartSelectionTrimItem:
-       case EndSelectionTrimItem:
-
 #ifdef WITH_CMT
        case ImageFrameHandleStartItem:
-       case ImageFrameHandleEndItem:
        case MarkerViewHandleStartItem:
+#endif
+               if (is_drawable()) {
+                       set_canvas_cursor (_cursors->left_side_trim);
+               }
+               break;
+       case EndSelectionTrimItem:
+#ifdef WITH_CMT
+       case ImageFrameHandleEndItem:
        case MarkerViewHandleEndItem:
 #endif
-
                if (is_drawable()) {
-                       set_canvas_cursor (_cursors->trimmer);
+                       set_canvas_cursor (_cursors->right_side_trim);
                }
                break;
 
@@ -1706,8 +1770,8 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                break;
        case FeatureLineItem:
                {
-                       ArdourCanvas::SimpleLine *line = dynamic_cast<ArdourCanvas::SimpleLine *> (item);
-                       line->property_color_rgba() = 0xFF0000FF;
+                       ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
+                       line->property_fill_color_rgba() = 0xFF0000FF;
                }
                break;
        case SelectionItem:
@@ -1715,7 +1779,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                        set_canvas_cursor ();
                }
                break;
-               
+
        default:
                break;
        }
@@ -1744,7 +1808,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
 }
 
 bool
-Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
+Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type)
 {
        AutomationLine* al;
        ControlPoint* cp;
@@ -1767,7 +1831,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                        set_canvas_cursor (current_canvas_cursor);
                }
 
-               hide_verbose_canvas_cursor ();
+               _verbose_cursor->hide ();
                break;
 
        case RegionViewNameHighlight:
@@ -1785,7 +1849,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
 #endif
 
                _over_region_trim_target = false;
-               
+
                if (is_drawable()) {
                        set_canvas_cursor (current_canvas_cursor);
                }
@@ -1807,7 +1871,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
        case RegionViewName:
                /* see enter_handler() for notes */
                _over_region_trim_target = false;
-               
+
                if (!reinterpret_cast<RegionView *> (item->get_data ("regionview"))->name_active()) {
                        if (is_drawable() && mouse_mode == MouseObject) {
                                set_canvas_cursor (current_canvas_cursor);
@@ -1866,8 +1930,8 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                break;
        case FeatureLineItem:
                {
-                       ArdourCanvas::SimpleLine *line = dynamic_cast<ArdourCanvas::SimpleLine *> (item);
-                       line->property_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();;
+                       ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
+                       line->property_fill_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();;
                }
                break;
 
@@ -1920,7 +1984,7 @@ Editor::scrub (framepos_t frame, double current_x)
                                scrub_reverse_distance = 0;
 
                                delta = 0.01 * (last_scrub_x - current_x);
-                               _session->request_transport_speed (_session->transport_speed() - delta);
+                               _session->request_transport_speed_nonzero (_session->transport_speed() - delta);
                        }
 
                } else {
@@ -1939,7 +2003,7 @@ Editor::scrub (framepos_t frame, double current_x)
                                scrub_reverse_distance = 0;
 
                                delta = 0.01 * (current_x - last_scrub_x);
-                               _session->request_transport_speed (_session->transport_speed() + delta);
+                               _session->request_transport_speed_nonzero (_session->transport_speed() + delta);
                        }
                }
 
@@ -1971,7 +2035,7 @@ bool
 Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from_autoscroll)
 {
        _last_motion_y = event->motion.y;
-       
+
        if (event->motion.is_hint) {
                gint x, y;
 
@@ -2012,7 +2076,7 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from
        if (_drags->active ()) {
                handled = _drags->motion_handler (event, from_autoscroll);
        }
-       
+
        if (!handled) {
                return false;
        }
@@ -2021,8 +2085,8 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from
        return true;
 }
 
-void
-Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* /*event*/)
+bool
+Editor::can_remove_control_point (ArdourCanvas::Item* item)
 {
        ControlPoint* control_point;
 
@@ -2031,18 +2095,24 @@ Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* /*event*/)
                /*NOTREACHED*/
        }
 
-       // We shouldn't remove the first or last gain point
-       if (control_point->line().is_last_point(*control_point) ||
-               control_point->line().is_first_point(*control_point)) {
-               return;
+       AutomationLine& line = control_point->line ();
+       if (dynamic_cast<AudioRegionGainLine*> (&line)) {
+               /* we shouldn't remove the first or last gain point in region gain lines */
+               if (line.is_last_point(*control_point) || line.is_first_point(*control_point)) {
+                       return false;
+               }
        }
 
-       control_point->line().remove_point (*control_point);
+       return true;
 }
 
 void
-Editor::remove_control_point (ArdourCanvas::Item* item, GdkEvent* /*event*/)
+Editor::remove_control_point (ArdourCanvas::Item* item)
 {
+       if (!can_remove_control_point (item)) {
+               return;
+       }
+
        ControlPoint* control_point;
 
        if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
@@ -2086,7 +2156,7 @@ Editor::edit_note (ArdourCanvas::Item* item)
 
        d.run ();
 }
-       
+
 
 void
 Editor::visible_order_range (int* low, int* high) const
@@ -2146,146 +2216,6 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
        }
 }
 
-void
-Editor::show_verbose_time_cursor (framepos_t frame, double offset, double xpos, double ypos)
-{
-       char buf[128];
-       Timecode::Time timecode;
-       Timecode::BBT_Time bbt;
-       int hours, mins;
-       framepos_t frame_rate;
-       float secs;
-
-       if (_session == 0) {
-               return;
-       }
-
-       AudioClock::Mode m;
-
-       if (Profile->get_sae() || Profile->get_small_screen()) {
-               m = ARDOUR_UI::instance()->primary_clock.mode();
-       } else {
-               m = ARDOUR_UI::instance()->secondary_clock.mode();
-       }
-
-       switch (m) {
-       case AudioClock::BBT:
-               _session->bbt_time (frame, bbt);
-               snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
-               break;
-
-       case AudioClock::Timecode:
-               _session->timecode_time (frame, timecode);
-               snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
-               break;
-
-       case AudioClock::MinSec:
-               /* XXX this is copied from show_verbose_duration_cursor() */
-               frame_rate = _session->frame_rate();
-               hours = frame / (frame_rate * 3600);
-               frame = frame % (frame_rate * 3600);
-               mins = frame / (frame_rate * 60);
-               frame = frame % (frame_rate * 60);
-               secs = (float) frame / (float) frame_rate;
-               snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%07.4f", hours, mins, secs);
-               break;
-
-       default:
-               snprintf (buf, sizeof(buf), "%" PRIi64, frame);
-               break;
-       }
-
-       if (xpos >= 0 && ypos >=0) {
-               set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
-       } else {
-               set_verbose_canvas_cursor (buf, _drags->current_pointer_x() + offset - horizontal_position(), _drags->current_pointer_y() + offset - vertical_adjustment.get_value() + canvas_timebars_vsize);
-       }
-       show_verbose_canvas_cursor ();
-}
-
-void
-Editor::show_verbose_duration_cursor (framepos_t start, framepos_t end, double offset, double xpos, double ypos)
-{
-       char buf[128];
-       Timecode::Time timecode;
-       Timecode::BBT_Time sbbt;
-       Timecode::BBT_Time ebbt;
-       int hours, mins;
-       framepos_t distance, frame_rate;
-       float secs;
-       Meter meter_at_start(_session->tempo_map().meter_at(start));
-
-       if (_session == 0) {
-               return;
-       }
-
-       AudioClock::Mode m;
-
-       if (Profile->get_sae() || Profile->get_small_screen()) {
-               m = ARDOUR_UI::instance()->primary_clock.mode ();
-       } else {
-               m = ARDOUR_UI::instance()->secondary_clock.mode ();
-       }
-
-       switch (m) {
-       case AudioClock::BBT:
-               _session->bbt_time (start, sbbt);
-               _session->bbt_time (end, ebbt);
-
-               /* subtract */
-               /* XXX this computation won't work well if the
-               user makes a selection that spans any meter changes.
-               */
-
-               ebbt.bars -= sbbt.bars;
-               if (ebbt.beats >= sbbt.beats) {
-                       ebbt.beats -= sbbt.beats;
-               } else {
-                       ebbt.bars--;
-                       ebbt.beats =  int(meter_at_start.beats_per_bar()) + ebbt.beats - sbbt.beats;
-               }
-               if (ebbt.ticks >= sbbt.ticks) {
-                       ebbt.ticks -= sbbt.ticks;
-               } else {
-                       ebbt.beats--;
-                       ebbt.ticks = int(Timecode::BBT_Time::ticks_per_beat) + ebbt.ticks - sbbt.ticks;
-               }
-
-               snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, ebbt.bars, ebbt.beats, ebbt.ticks);
-               break;
-
-       case AudioClock::Timecode:
-               _session->timecode_duration (end - start, timecode);
-               snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
-               break;
-
-       case AudioClock::MinSec:
-               /* XXX this stuff should be elsewhere.. */
-               distance = end - start;
-               frame_rate = _session->frame_rate();
-               hours = distance / (frame_rate * 3600);
-               distance = distance % (frame_rate * 3600);
-               mins = distance / (frame_rate * 60);
-               distance = distance % (frame_rate * 60);
-               secs = (float) distance / (float) frame_rate;
-               snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%07.4f", hours, mins, secs);
-               break;
-
-       default:
-               snprintf (buf, sizeof(buf), "%" PRIi64, end - start);
-               break;
-       }
-
-       if (xpos >= 0 && ypos >=0) {
-               set_verbose_canvas_cursor (buf, xpos + offset, ypos + offset);
-       }
-       else {
-               set_verbose_canvas_cursor (buf, _drags->current_pointer_x() + offset, _drags->current_pointer_y() + offset);
-       }
-
-       show_verbose_canvas_cursor ();
-}
-
 void
 Editor::collect_new_region_view (RegionView* rv)
 {
@@ -2331,7 +2261,7 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound)
 
                                if (!(*i)->region()->locked()) {
                                        (*i)->region()->clear_changes ();
-                                       (*i)->region()->trim_front (new_bound, this);
+                                       (*i)->region()->trim_front (new_bound);
                                        _session->add_command(new StatefulDiffCommand ((*i)->region()));
                                }
                        }
@@ -2339,7 +2269,7 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound)
                } else {
                        if (!rv->region()->locked()) {
                                rv->region()->clear_changes ();
-                               rv->region()->trim_front (new_bound, this);
+                               rv->region()->trim_front (new_bound);
                                _session->add_command(new StatefulDiffCommand (rv->region()));
                        }
                }
@@ -2356,7 +2286,7 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound)
                        {
                                if (!(*i)->region()->locked()) {
                                        (*i)->region()->clear_changes();
-                                       (*i)->region()->trim_end (new_bound, this);
+                                       (*i)->region()->trim_end (new_bound);
                                        _session->add_command(new StatefulDiffCommand ((*i)->region()));
                                }
                        }
@@ -2365,7 +2295,7 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound)
 
                        if (!rv->region()->locked()) {
                                rv->region()->clear_changes ();
-                               rv->region()->trim_end (new_bound, this);
+                               rv->region()->trim_end (new_bound);
                                _session->add_command (new StatefulDiffCommand (rv->region()));
                        }
                }
@@ -2469,7 +2399,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos)
        double speed = rtv->track()->speed();
 
        playlist->clear_changes ();
-       boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region()));
+       boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region(), true));
        playlist->add_region (new_region, (framepos_t) (pos * speed));
        _session->add_command (new StatefulDiffCommand (playlist));
 
@@ -2489,7 +2419,7 @@ Editor::track_height_step_timeout ()
 }
 
 void
-Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent* event, RegionView* region_view)
+Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region_view)
 {
        assert (region_view);
 
@@ -2511,7 +2441,7 @@ Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent* event, RegionView*
 }
 
 void
-Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent* event, RegionView* region_view)
+Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region_view)
 {
        assert (region_view);
 
@@ -2526,14 +2456,14 @@ Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent* event, RegionV
 }
 
 void
-Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent* event, RegionView* region_view)
+Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region_view)
 {
        assert (region_view);
 
        if (!region_view->region()->playlist()) {
                return;
        }
-        
+
        if (Config->get_edit_mode() == Splice) {
                return;
        }
@@ -2623,17 +2553,30 @@ Editor::set_internal_edit (bool yn)
        _internal_editing = yn;
 
        if (yn) {
-               mouse_select_button.set_image (*(manage (new Image (::get_icon("midi_tool_pencil")))));
-               mouse_select_button.get_image ()->show ();
+               mouse_select_button.set_image (::get_icon("midi_tool_pencil"));
                ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Draw/Edit MIDI Notes"));
                mouse_mode_toggled (mouse_mode);
 
+                pre_internal_mouse_mode = mouse_mode;
+
+                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+                        (*i)->enter_internal_edit_mode ();
+                }
+
        } else {
 
-               mouse_select_button.set_image (*(manage (new Image (::get_icon("tool_range")))));
-               mouse_select_button.get_image ()->show ();
+               mouse_select_button.set_image (::get_icon("tool_range"));
                ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
                mouse_mode_toggled (mouse_mode); // sets cursor
+
+                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+                        (*i)->leave_internal_edit_mode ();
+                }
+
+                if (mouse_mode == MouseRange && pre_internal_mouse_mode != MouseRange) {
+                        /* we were drawing .. flip back to something sensible */
+                        set_mouse_mode (pre_internal_mouse_mode);
+                }
        }
 }
 
@@ -2641,18 +2584,18 @@ Editor::set_internal_edit (bool yn)
  *  used by the `join object/range' tool mode.
  */
 void
-Editor::update_join_object_range_location (double x, double y)
+Editor::update_join_object_range_location (double /*x*/, double y)
 {
        /* XXX: actually, this decides based on whether the mouse is in the top or bottom half of a RouteTimeAxisView;
           entered_{track,regionview} is not always setup (e.g. if the mouse is over a TimeSelection), and to get a Region
           that we're over requires searching the playlist.
        */
-          
+
        if (join_object_range_button.get_active() == false || (mouse_mode != MouseRange && mouse_mode != MouseObject)) {
                _join_object_range_state = JOIN_OBJECT_RANGE_NONE;
                return;
        }
-       
+
        if (mouse_mode == MouseObject) {
                _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT;
        } else if (mouse_mode == MouseRange) {
@@ -2661,7 +2604,7 @@ Editor::update_join_object_range_location (double x, double y)
 
        /* XXX: maybe we should make entered_track work in all cases, rather than resorting to this */
        pair<TimeAxisView*, int> tvp = trackview_by_y_position (y + vertical_adjustment.get_value() - canvas_timebars_vsize);
-       
+
        if (tvp.first) {
 
                RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
@@ -2704,6 +2647,8 @@ Editor::remove_midi_note (ArdourCanvas::Item* item, GdkEvent *)
 void
 Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv)
 {
+       assert (rv);
+
        ArdourCanvas::Group* g = rv->get_canvas_group ();
        ArdourCanvas::Group* p = g->get_parent_group ();
 
@@ -2732,3 +2677,12 @@ Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv)
                }
        }
 }
+
+/** Obtain the pointer position in world coordinates */
+void
+Editor::get_pointer_position (double& x, double& y) const
+{
+       int px, py;
+       track_canvas->get_pointer (px, py);
+       track_canvas->window_to_world (px, py, x, y);
+}