Merged with trunk (painfully)
[ardour.git] / gtk2_ardour / editor_mouse.cc
index 6b38b904e138dea2e8bbabfb449abb4d7bacacdf..cc171617a631737925c8694c07c313e2c6d918a3 100644 (file)
@@ -96,7 +96,6 @@ Editor::event_frame (GdkEvent* event, double* pcx, double* pcy)
                break;
        case GDK_KEY_PRESS:
        case GDK_KEY_RELEASE:
-               cerr << "here\n";
                // track_canvas.w2c(event->key.x, event->key.y, *pcx, *pcy);
                break;
        default:
@@ -168,7 +167,7 @@ Editor::set_mouse_mode (MouseMode m, bool force)
                return;
        }
 
-       if (m == mouse_mode && !force) {
+       if (!force && m == mouse_mode) {
                return;
        }
        
@@ -284,65 +283,68 @@ Editor::step_mouse_mode (bool next)
        }
 }
 
-bool
-Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
+void
+Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
-       jack_nframes_t where = event_frame (event, 0, 0);
-
-       track_canvas.grab_focus();
-
-       if (session && session->actively_recording()) {
-               return true;
-       }
+       bool commit;
+       bool c1; 
+       bool c2;
 
        /* in object/audition/timefx mode, any button press sets
           the selection if the object can be selected. this is a
           bit of hack, because we want to avoid this if the
           mouse operation is a region alignment.
-       */
-
-       if (((mouse_mode == MouseObject) ||
-            (mouse_mode == MouseAudition && item_type == RegionItem) ||
-            (mouse_mode == MouseTimeFX && item_type == RegionItem)) &&
-           event->type == GDK_BUTTON_PRESS && 
-           event->button.button <= 3) {
-
-               AudioRegionView* rv;
-               ControlPoint* cp;
 
-               /* not dbl-click or triple-click */
-
-               switch (item_type) {
-               case RegionItem:
-                       set_selected_regionview_from_click (Keyboard::selection_type (event->button.state), true);
-                       break;
-                       
-               case AudioRegionViewNameHighlight:
-               case AudioRegionViewName:
-                       if ((rv = static_cast<AudioRegionView *> (item->get_data ("regionview"))) != 0) {
-                               set_selected_regionview_from_click (Keyboard::selection_type (event->button.state), true);
-                       }
-                       break;
-                       
-               case GainAutomationControlPointItem:
-               case PanAutomationControlPointItem:
-               case RedirectAutomationControlPointItem:
-                       if ((cp = static_cast<ControlPoint *> (item->get_data ("control_point"))) != 0) {
-                               set_selected_control_point_from_click (Keyboard::selection_type (event->button.state), true);
-                       }
-                       break;
+          note: not dbl-click or triple-click
+       */
 
-               case StreamItem:
-                       break;
+       if (((mouse_mode != MouseObject) &&
+            (mouse_mode != MouseAudition || item_type != RegionItem) &&
+            (mouse_mode != MouseTimeFX || item_type != RegionItem)) ||
+           (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE || event->button.button > 3)) {
+               
+               return;
+       }
+           
+       Selection::Operation op = Keyboard::selection_type (event->button.state);
+       bool press = (event->type == GDK_BUTTON_PRESS);
 
-               case AutomationTrackItem:
-                       break;
+       begin_reversible_command (_("select on click"));
 
-               default:
-                       break;
-               }
+       switch (item_type) {
+       case RegionItem:
+               c1 = set_selected_track_from_click (press, op, true, true);
+               c2 = set_selected_regionview_from_click (press, op, true);
+               commit = (c1 || c2);
+               break;
+               
+       case AudioRegionViewNameHighlight:
+       case AudioRegionViewName:
+               c1 = set_selected_track_from_click (press, op, true, true);
+               c2 = set_selected_regionview_from_click (press, op, true);
+               commit = (c1 || c2);
+               break;
+               
+       case GainAutomationControlPointItem:
+       case PanAutomationControlPointItem:
+       case RedirectAutomationControlPointItem:
+               c1 = set_selected_track_from_click (press, op, true, true);
+               c2 = set_selected_control_point_from_click (press, op, false);
+               commit = (c1 || c2);
+               break;
+               
+       case StreamItem:
+               commit = set_selected_track_from_click (press, op, true, true);
+               break;
+                   
+       case AutomationTrackItem:
+               commit = set_selected_track_from_click (press, op, true, true);
+               break;
+               
+       default:
+               break;
        }
-
+       
 #define SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
 #ifdef  SELECT_TRACK_FROM_CANVAS_IN_RANGE_MODE
        /* in range mode, button 1/2/3 press potentially selects a track */
@@ -351,24 +353,36 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
            event->type == GDK_BUTTON_PRESS && 
            event->button.button <= 3) {
                
-               AudioRegionView* rv;
-
                switch (item_type) {
                case StreamItem:
                case RegionItem:
                case AutomationTrackItem:
-                       set_selected_track_from_click (Keyboard::selection_type (event->button.state), true, true);
+                       commit = set_selected_track_from_click (press, op, true, true);
                        break;
 
-               case AudioRegionViewNameHighlight:
-               case AudioRegionViewName:
-                       rv = reinterpret_cast<AudioRegionView *> (item->get_data ("regionview"));
                default:
                        break;
                }
        }
 #endif
+       if (commit) {
+               commit_reversible_command ();
+       }
+}
+
+bool
+Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
+{
+       jack_nframes_t where = event_frame (event, 0, 0);
 
+       track_canvas.grab_focus();
+
+       if (session && session->actively_recording()) {
+               return true;
+       }
+
+       button_selection (item, event, item_type);
+       
        if (drag_info.item == 0 &&
            (Keyboard::is_delete_event (&event->button) ||
             Keyboard::is_context_menu_event (&event->button) ||
@@ -434,6 +448,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                start_range_markerbar_op (item, event, CreateRangeMarker); 
                                return true;
                                break;
+
                        case TransportMarkerBarItem:
                                start_range_markerbar_op (item, event, CreateTransportMarker); 
                                return true;
@@ -563,6 +578,10 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                        break ;
                                /* </CMT Additions> */
 
+                               case MarkerBarItem:
+                                       
+                                       break;
+
                                default:
                                        break;
                                }
@@ -815,6 +834,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                }
        }
        
+       button_selection (item, event, item_type);
+
        /* edit events get handled here */
        
        if (drag_info.item == 0 && Keyboard::is_edit_event (&event->button)) {
@@ -941,9 +962,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        break;
 
                case MarkerItem:
-
                        remove_marker (*item, event);
-
                        break;
 
                case RegionItem:
@@ -1105,31 +1124,6 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
        return false;
 }
 
-void
-Editor::maybe_autoscroll (GdkEvent* event)
-{
-       jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
-       jack_nframes_t rightmost_frame = leftmost_frame + one_page;
-
-       jack_nframes_t frame = drag_info.current_pointer_frame;
-
-       if (autoscroll_timeout_tag < 0) {
-               if (frame > rightmost_frame) {
-                       if (rightmost_frame < max_frames) {
-                               start_canvas_autoscroll (1);
-                       }
-               } else if (frame < leftmost_frame) {
-                       if (leftmost_frame > 0) {
-                               start_canvas_autoscroll (-1);
-                       }
-               } 
-       } else {
-               if (frame >= leftmost_frame && frame < rightmost_frame) {
-                       stop_canvas_autoscroll ();
-               }
-       }
-}
-
 bool
 Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
@@ -1470,7 +1464,7 @@ Editor::left_automation_track ()
 }
 
 bool
-Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
+Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
 {
        gint x, y;
        
@@ -1496,18 +1490,20 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
                return true;
        }
 
+       drag_info.item_type = item_type;
        drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
                                                       &drag_info.current_pointer_y);
 
-       if (drag_info.item) {
-               /* item != 0 is the best test i can think of for 
-                  dragging.
+       if (!from_autoscroll && drag_info.item) {
+               /* item != 0 is the best test i can think of for dragging.
                */
-               if (!drag_info.move_threshold_passsed) {
-                       drag_info.move_threshold_passsed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
+               if (!drag_info.move_threshold_passed) {
+
+                       drag_info.move_threshold_passed = (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
                        
                        // and change the initial grab loc/frame if this drag info wants us to
-                       if (drag_info.want_move_threshold && drag_info.move_threshold_passsed) {
+
+                       if (drag_info.want_move_threshold && drag_info.move_threshold_passed) {
                                drag_info.grab_frame = drag_info.current_pointer_frame;
                                drag_info.grab_x = drag_info.current_pointer_x;
                                drag_info.grab_y = drag_info.current_pointer_y;
@@ -1545,12 +1541,14 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
        /* </CMT Additions> */
          if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
                                 (event->motion.state & Gdk::BUTTON2_MASK))) {
-                       maybe_autoscroll (event);
-                       (this->*(drag_info.motion_callback)) (item, event);
-                       goto handled;
-               }
-               goto not_handled;
-
+                 if (!from_autoscroll) {
+                         maybe_autoscroll (event);
+                 }
+                 (this->*(drag_info.motion_callback)) (item, event);
+                 goto handled;
+         }
+         goto not_handled;
+         
        default:
                break;
        }
@@ -1562,7 +1560,9 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
        case MouseTimeFX:
                if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
                                       (event->motion.state & GDK_BUTTON2_MASK))) {
-                       maybe_autoscroll (event);
+                       if (!from_autoscroll) {
+                               maybe_autoscroll (event);
+                       }
                        (this->*(drag_info.motion_callback)) (item, event);
                        goto handled;
                }
@@ -1575,6 +1575,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
 
   handled:
        track_canvas_motion (event);
+       // drag_info.last_pointer_frame = drag_info.current_pointer_frame;
        return true;
        
   not_handled:
@@ -1597,9 +1598,16 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
         // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
 
        if (event->button.button == 2) {
-               drag_info.x_constrained = true;
+               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) {
+                       drag_info.y_constrained = true;
+                       drag_info.x_constrained = false;
+               } else {
+                       drag_info.y_constrained = false;
+                       drag_info.x_constrained = true;
+               }
        } else {
                drag_info.x_constrained = false;
+               drag_info.y_constrained = false;
        }
 
        drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
@@ -1610,7 +1618,7 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
        drag_info.cumulative_x_drag = 0;
        drag_info.cumulative_y_drag = 0;
        drag_info.first_move = true;
-       drag_info.move_threshold_passsed = false;
+       drag_info.move_threshold_passed = false;
        drag_info.want_move_threshold = false;
        drag_info.pointer_frame_offset = 0;
        drag_info.brushing = false;
@@ -1638,6 +1646,19 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
        }
 }
 
+void
+Editor::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
+{
+       drag_info.item->ungrab (0);
+       drag_info.item = new_item;
+
+       if (cursor == 0) {
+               cursor = grabber_cursor;
+       }
+
+       drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time);
+}
+
 bool
 Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event)
 {
@@ -2033,6 +2054,7 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        bool is_start;
        bool move_both = false;
 
+
        jack_nframes_t newframe;
        if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
                newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
@@ -2040,14 +2062,16 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        else {
                newframe = 0;
        }
-               
+
        jack_nframes_t next = newframe;
 
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
                snap_to (newframe, 0, true);
        }
        
-       if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) return;
+       if (drag_info.current_pointer_frame == drag_info.last_pointer_frame) { 
+               return;
+       }
 
        /* call this to find out if its the start or end */
        
@@ -2114,7 +2138,6 @@ Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
        bool is_start;
 
 
-
        begin_reversible_command ( _("move marker") );
        session->add_undo( session->locations()->get_memento() );
        
@@ -2454,18 +2477,12 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
        drag_info.cumulative_x_drag = cx - drag_info.grab_x ;
        drag_info.cumulative_y_drag = cy - drag_info.grab_y ;
 
-       bool x_constrained = false;
-
        if (drag_info.x_constrained) {
-               if (fabs(drag_info.cumulative_x_drag) < fabs(drag_info.cumulative_y_drag)) {
-                       cx = drag_info.grab_x;
-                       x_constrained = true;
-
-               } else {
-                       cy = drag_info.grab_y;
-               }
-       
-       } 
+               cx = drag_info.grab_x;
+       }
+       if (drag_info.y_constrained) {
+               cy = drag_info.grab_y;
+       }
 
        cp->line.parent_group().w2i (cx, cy);
 
@@ -2474,9 +2491,9 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
        cy = min ((double) cp->line.height(), cy);
 
        //translate cx to frames
-       jack_nframes_t cx_frames = (jack_nframes_t) floor (cx * frames_per_unit);
+       jack_nframes_t cx_frames = unit_to_frame (cx);
 
-       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !x_constrained) {
+       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && !drag_info.x_constrained) {
                snap_to (cx_frames);
        }
 
@@ -2493,13 +2510,26 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
        cp->line.point_drag (*cp, cx_frames , fraction, push);
        
        set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
+
+       drag_info.first_move = false;
 }
 
 void
 Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
 {
        ControlPoint* cp = reinterpret_cast<ControlPoint *> (drag_info.data);
-       control_point_drag_motion_callback (item, event);
+
+       if (drag_info.first_move) {
+
+               /* just a click */
+               
+               if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
+                       reset_point_selection ();
+               }
+
+       } else {
+               control_point_drag_motion_callback (item, event);
+       }
        cp->line.end_drag (cp);
 }
 
@@ -2640,68 +2670,9 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
                return;
        }
 
-       /* this is committed in the grab finished callback. */
-
-       begin_reversible_command (_("Drag region copy"));
-
-       /* duplicate the region(s) */
-       
-       vector<AudioRegionView*> new_regionviews;
-       
-       set<Playlist*> affected_playlists;
-       pair<set<Playlist*>::iterator,bool> insert_result;
-       
-       for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
-               AudioRegionView* rv;
-               
-               rv = (*i);
-               
-               Playlist* to_playlist = rv->region.playlist();
-               AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
-               
-               insert_result = affected_playlists.insert (to_playlist);
-               if (insert_result.second) {
-                       session->add_undo (to_playlist->get_memento ());
-               }
-               
-               latest_regionview = 0;
-               
-               sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
-               
-               /* create a new region with the same name.
-                */
-               
-               AudioRegion* newregion = new AudioRegion (rv->region);
-               
-               /* if the original region was locked, we don't care */
-               
-               newregion->set_locked (false);
-               
-               to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
-               
-               c.disconnect ();
-               
-               if (latest_regionview) {
-                       new_regionviews.push_back (latest_regionview);
-               }
-       }
-       
-       if (new_regionviews.empty()) {
-               return;
-       }
-       
-       /* reset selection to new regionviews */
-       
-       selection->set (new_regionviews);
-       
-       /* reset drag_info data to reflect the fact that we are dragging the copies */
-       
-       drag_info.data = new_regionviews.front();
-       drag_info.item = new_regionviews.front()->get_canvas_group ();
-       
        drag_info.copy = true;
-       drag_info.motion_callback = &Editor::region_drag_motion_callback;
-       drag_info.finished_callback = &Editor::region_drag_finished_callback;
+       drag_info.item = item;
+       drag_info.data = clicked_regionview;    
 
        start_grab(event);
 
@@ -2718,10 +2689,8 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
        drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
        // we want a move threshold
        drag_info.want_move_threshold = true;
-
-       show_verbose_time_cursor (drag_info.last_frame_position, 10);
-
-       //begin_reversible_command (_("copy region(s)"));
+       drag_info.motion_callback = &Editor::region_drag_motion_callback;
+       drag_info.finished_callback = &Editor::region_drag_finished_callback;
 }
 
 void
@@ -2770,6 +2739,72 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        vector<int32_t>  height_list(512) ;
        vector<int32_t>::iterator j;
 
+       show_verbose_time_cursor (drag_info.last_frame_position, 10);
+
+       if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) {
+
+               drag_info.want_move_threshold = false; // don't copy again
+
+               /* this is committed in the grab finished callback. */
+               
+               begin_reversible_command (_("Drag region copy"));
+               
+               /* duplicate the region(s) */
+               
+               vector<AudioRegionView*> new_regionviews;
+               
+               set<Playlist*> affected_playlists;
+               pair<set<Playlist*>::iterator,bool> insert_result;
+               
+               for (list<AudioRegionView*>::const_iterator i = selection->audio_regions.by_layer().begin(); i != selection->audio_regions.by_layer().end(); ++i) {
+                       AudioRegionView* rv;
+                       
+                       rv = (*i);
+                       
+                       Playlist* to_playlist = rv->region.playlist();
+                       AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(&rv->get_time_axis_view());
+                       
+                       insert_result = affected_playlists.insert (to_playlist);
+                       if (insert_result.second) {
+                               session->add_undo (to_playlist->get_memento ());
+                       }
+                       
+                       latest_regionview = 0;
+                       
+                       sigc::connection c = atv->view->AudioRegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
+                       
+                       /* create a new region with the same name.
+                        */
+                       
+                       AudioRegion* newregion = new AudioRegion (rv->region);
+                       
+                       /* if the original region was locked, we don't care */
+                       
+                       newregion->set_locked (false);
+                       
+                       to_playlist->add_region (*newregion, (jack_nframes_t) (rv->region.position() * atv->get_diskstream()->speed()));
+                       
+                       c.disconnect ();
+                       
+                       if (latest_regionview) {
+                               new_regionviews.push_back (latest_regionview);
+                       }
+               }
+               
+               if (new_regionviews.empty()) {
+                       return;
+               }
+               
+               /* reset selection to new regionviews */
+               
+               selection->set (new_regionviews);
+               
+               /* reset drag_info data to reflect the fact that we are dragging the copies */
+               
+               drag_info.data = new_regionviews.front();
+               swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
+       }
+
        /* Which trackview is this ? */
 
        TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);
@@ -2953,7 +2988,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
           the region would be if we moved it by that much.
        */
 
-       if (drag_info.move_threshold_passsed) {
+       if (drag_info.move_threshold_passed) {
 
                if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
 
@@ -3423,7 +3458,7 @@ void
 Editor::show_verbose_time_cursor (jack_nframes_t frame, double offset, double xpos, double ypos) 
 {
        char buf[128];
-       SMPTE_Time smpte;
+       SMPTE::Time smpte;
        BBT_Time bbt;
        float secs;
 
@@ -3467,7 +3502,7 @@ void
 Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end, double offset, double xpos, double ypos) 
 {
        char buf[128];
-       SMPTE_Time smpte;
+       SMPTE::Time smpte;
        BBT_Time sbbt;
        BBT_Time ebbt;
        float secs;
@@ -3513,7 +3548,7 @@ Editor::show_verbose_duration_cursor (jack_nframes_t start, jack_nframes_t end,
                /* XXX fix this to compute min/sec properly */
                session->smpte_duration (end - start, smpte);
                secs = smpte.seconds + ((float) smpte.frames / session->smpte_frames_per_second);
-               snprintf (buf, sizeof (buf), "%02ld:%02ld:%.4f", smpte.hours, smpte.minutes, secs);
+               snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
                break;
 
        default:
@@ -3608,11 +3643,13 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
 void
 Editor::cancel_selection ()
 {
-       for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+        for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                (*i)->hide_selection ();
        }
+       begin_reversible_command (_("cancel selection"));
        selection->clear ();
        clicked_selection = 0;
+       commit_reversible_command ();
 }      
 
 void
@@ -3633,7 +3670,6 @@ Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, Selection
 
        switch (op) {
        case CreateSelection:
-               
                if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
                        drag_info.copy = true;
                } else {
@@ -3643,14 +3679,18 @@ Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, Selection
                break;
 
        case SelectionStartTrim:
-               clicked_trackview->order_selection_trims (item, true);
+               if (clicked_trackview) {
+                       clicked_trackview->order_selection_trims (item, true);
+               } 
                start_grab (event, trimmer_cursor);
                start = selection->time[clicked_selection].start;
                drag_info.pointer_frame_offset = drag_info.grab_frame - start;  
                break;
                
        case SelectionEndTrim:
-               clicked_trackview->order_selection_trims (item, false);
+               if (clicked_trackview) {
+                       clicked_trackview->order_selection_trims (item, false);
+               }
                start_grab (event, trimmer_cursor);
                end = selection->time[clicked_selection].end;
                drag_info.pointer_frame_offset = drag_info.grab_frame - end;    
@@ -4243,7 +4283,6 @@ Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* event)
 void
 Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, RangeMarkerOp op)
 {
-
        if (session == 0) {
                return;
        }
@@ -4308,7 +4347,7 @@ Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
                }
                
                /* first drag: Either add to the selection
-                  or create a new selection->
+                  or create a new selection.
                */
                
                if (drag_info.first_move) {
@@ -4375,12 +4414,39 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
                        break;
                }
        } else {
-               /* just a click, no pointer movement.*/
+               /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
 
                if (Keyboard::no_modifier_keys_pressed (&event->button)) {
 
-                       // nothing yet
+                       jack_nframes_t start;
+                       jack_nframes_t end;
+
+                       start = session->locations()->first_mark_before (drag_info.grab_frame);
+                       end = session->locations()->first_mark_after (drag_info.grab_frame);
+                       
+                       if (end == max_frames) {
+                               end = session->current_end_frame ();
+                       }
+
+                       if (start == 0) {
+                               start = session->current_start_frame ();
+                       }
 
+                       switch (mouse_mode) {
+                       case MouseObject:
+                               /* find the two markers on either side and then make the selection from it */
+                               cerr << "select between " << start << " .. " << end << endl;
+                               select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
+                               break;
+
+                       case MouseRange:
+                               /* find the two markers on either side of the click and make the range out of it */
+                               selection->set (0, start, end);
+                               break;
+
+                       default:
+                               break;
+                       }
                } 
        }
 
@@ -4603,6 +4669,8 @@ Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
 
        prompter.set_prompt (_("Name for region:"));
        prompter.set_initial_text (clicked_regionview->region.name());
+       prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
+       prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
        prompter.show_all ();
        switch (prompter.run ()) {
        case Gtk::RESPONSE_ACCEPT: