some fixes/improvements for track selection; add upload target to manual makefile...
[ardour.git] / gtk2_ardour / editor_mouse.cc
index 3fbd0a19bd383f36412d1e3f02fe5741ee632a88..10f4c0eb032f354f3b9e3c7732984ace8dbe68a6 100644 (file)
@@ -290,8 +290,6 @@ void
 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
        bool commit = false;
-       bool c1; 
-       bool c2;
 
        /* in object/audition/timefx mode, any button press sets
           the selection if the object can be selected. this is a
@@ -303,11 +301,23 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
 
        if (((mouse_mode != MouseObject) &&
             (mouse_mode != MouseAudition || item_type != RegionItem) &&
-            (mouse_mode != MouseTimeFX || item_type != RegionItem)) ||
+            (mouse_mode != MouseTimeFX || item_type != RegionItem) &&
+            (mouse_mode != MouseRange)) ||
+
            (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE || event->button.button > 3)) {
                
                return;
        }
+
+       if (event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) {
+
+               if ((event->button.state & Keyboard::RelevantModifierKeyMask) && event->button.button != 1) {
+                       
+                       /* no selection action on modified button-2 or button-3 events */
+                       
+                       return;
+               }
+       }
            
        Selection::Operation op = Keyboard::selection_type (event->button.state);
        bool press = (event->type == GDK_BUTTON_PRESS);
@@ -316,58 +326,52 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
 
        switch (item_type) {
        case RegionItem:
-               c1 = set_selected_track_from_click (op, true);
-               c2 = set_selected_regionview_from_click (press, op, true);
-               commit = (c1 || c2);
+               if (mouse_mode != MouseRange) {
+                       commit = set_selected_regionview_from_click (press, op, true);
+               }
                break;
                
        case RegionViewNameHighlight:
        case RegionViewName:
-               c1 = set_selected_track_from_click (op, true);
-               c2 = set_selected_regionview_from_click (press, op, true);
-               commit = (c1 || c2);
+               if (mouse_mode != MouseRange) {
+                       commit = set_selected_regionview_from_click (press, op, true);
+               }
+               break;
+
+       case FadeInHandleItem:
+       case FadeInItem:
+       case FadeOutHandleItem:
+       case FadeOutItem:
+               if (mouse_mode != MouseRange) {
+                       commit = set_selected_regionview_from_click (press, op, true);
+               }
                break;
                
        case GainAutomationControlPointItem:
        case PanAutomationControlPointItem:
        case RedirectAutomationControlPointItem:
-               c1 = set_selected_track_from_click (op, true);
-               c2 = set_selected_control_point_from_click (op, false);
-               commit = (c1 || c2);
+               if (mouse_mode != MouseRange) {
+                       commit = set_selected_control_point_from_click (op, false);
+               }
                break;
                
        case StreamItem:
-               commit = set_selected_track_from_click (op, true);
+               /* for context click or range selection, select track */
+               if (event->button.button == 3) {
+                       commit = set_selected_track_from_click (press, op, true);
+               } else if (event->type == GDK_BUTTON_PRESS && mouse_mode == MouseRange) {
+                       commit = set_selected_track_from_click (press, op, false);
+               }
                break;
                    
        case AutomationTrackItem:
-               commit = set_selected_track_from_click (op, true);
+               commit = set_selected_track_from_click (press, op, 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 */
-
-       if (mouse_mode == MouseRange && 
-           event->type == GDK_BUTTON_PRESS && 
-           event->button.button <= 3) {
-               
-               switch (item_type) {
-               case StreamItem:
-               case RegionItem:
-               case AutomationTrackItem:
-                       commit = set_selected_track_from_click (op, true);
-                       break;
-
-               default:
-                       break;
-               }
-       }
-#endif
        if (commit) {
                commit_reversible_command ();
        }
@@ -496,10 +500,9 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        break;
                        
                case MouseObject:
-                       if (Keyboard::modifier_state_contains (event->button.state, 
-                                                              Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt))
-                               && event->type == GDK_BUTTON_PRESS) {
-
+                       if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt)) &&
+                           event->type == GDK_BUTTON_PRESS) {
+                               
                                start_rubberband_select (item, event);
 
                        } else if (event->type == GDK_BUTTON_PRESS) {
@@ -1761,7 +1764,7 @@ Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        nframes_t pos;
        nframes_t fade_length;
 
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -1771,16 +1774,26 @@ Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
                snap_to (pos);
        }
-       
+
        if (pos < (arv->region()->position() + 64)) {
                fade_length = 64; // this should be a minimum defined somewhere
        } else if (pos > arv->region()->last_frame()) {
                fade_length = arv->region()->length();
        } else {
                fade_length = pos - arv->region()->position();
-       }
+       }               
+       /* mapover the region selection */
+
+       for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+
+               AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+               
+               if (!tmp) {
+                       continue;
+               }
        
-       arv->reset_fade_in_shape_width (fade_length);
+               tmp->reset_fade_in_shape_width (fade_length);
+       }
 
        show_verbose_duration_cursor (arv->region()->position(),  arv->region()->position() + fade_length, 10);
 
@@ -1790,43 +1803,46 @@ Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 void
 Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
 {
-       if (drag_info.first_move) return;
-
        AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
        nframes_t pos;
        nframes_t fade_length;
 
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.first_move) return;
+
+       if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-       }
-       else {
+       } else {
                pos = 0;
        }
 
-       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
-               snap_to (pos);
-       }
-
        if (pos < (arv->region()->position() + 64)) {
                fade_length = 64; // this should be a minimum defined somewhere
-       }
-       else if (pos > arv->region()->last_frame()) {
+       } else if (pos > arv->region()->last_frame()) {
                fade_length = arv->region()->length();
-       }
-       else {
+       } else {
                fade_length = pos - arv->region()->position();
        }
-
+               
        begin_reversible_command (_("change fade in length"));
-       AutomationList& alist = arv->audio_region()->fade_in();
-        XMLNode &before = alist.get_state();
 
-       arv->audio_region()->set_fade_in_length (fade_length);
+       for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+
+               AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+               
+               if (!tmp) {
+                       continue;
+               }
+       
+               AutomationList& alist = tmp->audio_region()->fade_in();
+               XMLNode &before = alist.get_state();
+
+               tmp->audio_region()->set_fade_in_length (fade_length);
+               
+               XMLNode &after = alist.get_state();
+               session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+       }
 
-        XMLNode &after = alist.get_state();
-        session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
        commit_reversible_command ();
-       fade_in_drag_motion_callback (item, event);
 }
 
 void
@@ -1865,7 +1881,7 @@ Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event
        if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
                snap_to (pos);
        }
-
+       
        if (pos > (arv->region()->last_frame() - 64)) {
                fade_length = 64; // this should really be a minimum fade defined somewhere
        }
@@ -1875,8 +1891,19 @@ Editor::fade_out_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event
        else {
                fade_length = arv->region()->last_frame() - pos;
        }
+               
+       /* mapover the region selection */
+
+       for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+
+               AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+               
+               if (!tmp) {
+                       continue;
+               }
        
-       arv->reset_fade_out_shape_width (fade_length);
+               tmp->reset_fade_out_shape_width (fade_length);
+       }
 
        show_verbose_duration_cursor (arv->region()->last_frame() - fade_length, arv->region()->last_frame(), 10);
 
@@ -1914,16 +1941,25 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve
        }
 
        begin_reversible_command (_("change fade out length"));
-       AutomationList& alist = arv->audio_region()->fade_out();
-        XMLNode &before = alist.get_state();
 
-       arv->audio_region()->set_fade_out_length (fade_length);
+       for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
 
-        XMLNode &after = alist.get_state();
-        session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
-       commit_reversible_command ();
+               AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+               
+               if (!tmp) {
+                       continue;
+               }
+       
+               AutomationList& alist = tmp->audio_region()->fade_out();
+               XMLNode &before = alist.get_state();
+               
+               tmp->audio_region()->set_fade_out_length (fade_length);
+
+               XMLNode &after = alist.get_state();
+               session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
+       }
 
-       fade_out_drag_motion_callback (item, event);
+       commit_reversible_command ();
 }
 
 void
@@ -1942,8 +1978,10 @@ Editor::start_cursor_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        Cursor* cursor = (Cursor *) drag_info.data;
 
-       if (session && cursor == playhead_cursor) {
-               if (drag_info.was_rolling) {
+       if (cursor == playhead_cursor) {
+               _dragging_playhead = true;
+               
+               if (session && drag_info.was_rolling) {
                        session->request_stop ();
                } 
        }
@@ -1978,6 +2016,8 @@ Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        
        if (cursor == edit_cursor) {
                edit_cursor_clock.set (cursor->current_frame);
+       } else {
+               UpdateAllTransportClocks (cursor->current_frame);
        }
 
        show_verbose_time_cursor (cursor->current_frame, 10);
@@ -1992,6 +2032,8 @@ Editor::cursor_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
        if (drag_info.first_move) return;
        
        cursor_drag_motion_callback (item, event);
+
+       _dragging_playhead = false;
        
        if (item == &playhead_cursor->canvas_item) {
                if (session) {
@@ -2724,6 +2766,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
        drag_info.want_move_threshold = true;
        drag_info.motion_callback = &Editor::region_drag_motion_callback;
        drag_info.finished_callback = &Editor::region_drag_finished_callback;
+       show_verbose_time_cursor (drag_info.last_frame_position, 10);
 }
 
 void
@@ -2772,8 +2815,6 @@ 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
@@ -2786,17 +2827,17 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                
                vector<RegionView*> new_regionviews;
                
-               set<Playlist*> affected_playlists;
-               pair<set<Playlist*>::iterator,bool> insert_result;
+               set<boost::shared_ptr<Playlist> > affected_playlists;
+               pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
                
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
                        RegionView* rv;
                        
                        rv = (*i);
                        
-                       Playlist* to_playlist = rv->region()->playlist();
+                       boost::shared_ptr<Playlist> to_playlist = rv->region()->playlist();
                        RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view());
-                       
+
                        insert_result = affected_playlists.insert (to_playlist);
                        if (insert_result.second) {
                                session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
@@ -2830,6 +2871,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                                new_regionviews.push_back (latest_regionview);
                        }
                }
+
+               
                
                if (new_regionviews.empty()) {
                        return;
@@ -3120,7 +3163,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                         MOTION                                                               
        ************************************************************/
 
-       pair<set<Playlist*>::iterator,bool> insert_result;
+       pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
        const list<RegionView*>& layered_regions = selection->regions.by_layer();
 
        for (list<RegionView*>::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) {
@@ -3214,7 +3257,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
                        /* hide any dependent views */
 
-//                     rv->get_time_axis_view().hide_dependent_views (*rv);
+                       rv->get_time_axis_view().hide_dependent_views (*rv);
                                
                        /* this is subtle. raising the regionview itself won't help,
                           because raise_to_top() just puts the item on the top of
@@ -3232,7 +3275,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
                        AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&rv->get_time_axis_view());
                        if (atv && atv->is_audio_track()) {
-                               AudioPlaylist* pl = dynamic_cast<AudioPlaylist*>(atv->get_diskstream()->playlist());
+                               boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>(atv->get_diskstream()->playlist());
                                if (pl) {
                                        /* only freeze and capture state once */
 
@@ -3243,6 +3286,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                                        }
                                }
                        }
+                       rv->region()->set_opaque(false);
                }
 
                if (drag_info.brushing) {
@@ -3269,7 +3313,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 {
        nframes_t where;
        RegionView* rv = reinterpret_cast<RegionView *> (drag_info.data);
-       pair<set<Playlist*>::iterator,bool> insert_result;
+       pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
        bool nocommit = true;
        double speed;
        RouteTimeAxisView* atv;
@@ -3341,8 +3385,8 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
                for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
 
-                       Playlist* from_playlist;
-                       Playlist* to_playlist;
+                       boost::shared_ptr<Playlist> from_playlist;
+                       boost::shared_ptr<Playlist> to_playlist;
                                
                        double ix1, ix2, iy1, iy2;
            
@@ -3350,6 +3394,8 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                        (*i)->get_canvas_group()->i2w (ix1, iy1);
                        TimeAxisView* tvp2 = trackview_by_y_position (iy1);
                        AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
+
+                       (*i)->region()->set_opaque (true);
            
                        from_playlist = (*i)->region()->playlist();
                        to_playlist = atv2->playlist();
@@ -3376,8 +3422,8 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
                for (list<RegionView*>::const_iterator i = new_selection.begin(); i != new_selection.end();i++ ) {
 
-                       Playlist* from_playlist;
-                       Playlist* to_playlist;
+                       boost::shared_ptr<Playlist> from_playlist;
+                       boost::shared_ptr<Playlist> to_playlist;
                                
                        double ix1, ix2, iy1, iy2;
            
@@ -3443,13 +3489,14 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                        /* no need to add an undo here, we did that when we added this playlist to motion_frozen playlists */
                        
                        rv->region()->set_position (where, (void *) this);
+                       rv->region()->set_opaque (true);
                }
        }
 
   out:
-       for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
+       for (set<boost::shared_ptr<Playlist> >::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
                (*p)->thaw ();
-               session->add_command (new MementoCommand<Playlist>(*(*p), 0, & (*p)->get_state()));
+               session->add_command (new MementoCommand<Playlist>(*((*p).get()), 0, & (*p)->get_state()));
        }
 
        motion_frozen_playlists.clear ();
@@ -3495,6 +3542,8 @@ Editor::show_verbose_time_cursor (nframes_t frame, double offset, double xpos, d
        char buf[128];
        SMPTE::Time smpte;
        BBT_Time bbt;
+       int hours, mins;
+       nframes_t frame_rate;
        float secs;
 
        if (session == 0) {
@@ -3513,10 +3562,14 @@ Editor::show_verbose_time_cursor (nframes_t frame, double offset, double xpos, d
                break;
 
        case AudioClock::MinSec:
-               /* XXX fix this to compute min/sec properly */
-               session->smpte_time (frame, smpte);
-               secs = smpte.seconds + ((float) smpte.frames / Config->get_smpte_frames_per_second());
-               snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
+               /* 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 ":%.4f", hours, mins, secs);
                break;
 
        default:
@@ -3540,6 +3593,8 @@ Editor::show_verbose_duration_cursor (nframes_t start, nframes_t end, double off
        SMPTE::Time smpte;
        BBT_Time sbbt;
        BBT_Time ebbt;
+       int hours, mins;
+       nframes_t distance, frame_rate;
        float secs;
        Meter meter_at_start(session->tempo_map().meter_at(start));
 
@@ -3580,10 +3635,15 @@ Editor::show_verbose_duration_cursor (nframes_t start, nframes_t end, double off
                break;
 
        case AudioClock::MinSec:
-               /* XXX fix this to compute min/sec properly */
-               session->smpte_duration (end - start, smpte);
-               secs = smpte.seconds + ((float) smpte.frames / Config->get_smpte_frames_per_second());
-               snprintf (buf, sizeof (buf), "%02" PRId32 ":%02" PRId32 ":%.4f", smpte.hours, smpte.minutes, secs);
+               /* 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 ":%.4f", hours, mins, secs);
                break;
 
        default:
@@ -3642,7 +3702,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        begin_reversible_command (_("selection grab"));
 
-       Playlist* playlist = clicked_trackview->playlist();
+       boost::shared_ptr<Playlist> playlist = clicked_trackview->playlist();
 
         XMLNode *before = &(playlist->get_state());
        clicked_trackview->playlist()->add_region (region, selection->time[clicked_selection].start);
@@ -3966,7 +4026,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        double speed = 1.0;
        TimeAxisView* tvp = clicked_trackview;
        RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
-       pair<set<Playlist*>::iterator,bool> insert_result;
+       pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
 
        if (tv && tv->is_audio_track()) {
                speed = tv->get_diskstream()->speed();
@@ -4005,13 +4065,14 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                begin_reversible_command (trim_type);
 
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
+                       (*i)->region()->set_opaque(false);
                        (*i)->region()->freeze ();
                
                        AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
                        if (arv)
                                arv->temporarily_hide_envelope ();
 
-                       Playlist * pl = (*i)->region()->playlist();
+                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
                        insert_result = motion_frozen_playlists.insert (pl);
                        if (insert_result.second) {
                                 session->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
@@ -4199,12 +4260,13 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event)
                             i != selection->regions.by_layer().end(); ++i)
                        {
                                thaw_region_after_trim (**i);
+                               (*i)->region()->set_opaque(true);
                        }
                }
                
-               for (set<Playlist*>::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
+               for (set<boost::shared_ptr<Playlist> >::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) {
                        //(*p)->thaw ();
-                        session->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
+                        session->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
                 }
                
                motion_frozen_playlists.clear ();
@@ -4238,22 +4300,22 @@ Editor::point_trim (GdkEvent* event)
                             i != selection->regions.by_layer().end(); ++i)
                        {
                                if (!(*i)->region()->locked()) {
-                                        Playlist *pl = (*i)->region()->playlist();
+                                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
                                         XMLNode &before = pl->get_state();
                                        (*i)->region()->trim_front (new_bound, this);   
                                         XMLNode &after = pl->get_state();
-                                        session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
+                                        session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
                                }
                        }
 
                } else {
 
                        if (!rv->region()->locked()) {
-                                Playlist *pl = rv->region()->playlist();
+                               boost::shared_ptr<Playlist> pl = rv->region()->playlist();
                                XMLNode &before = pl->get_state();
                                rv->region()->trim_front (new_bound, this);     
                                 XMLNode &after = pl->get_state();
-                               session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
+                               session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
                        }
                }
 
@@ -4269,22 +4331,22 @@ Editor::point_trim (GdkEvent* event)
                        for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i)
                        {
                                if (!(*i)->region()->locked()) {
-                                        Playlist *pl = (*i)->region()->playlist();
+                                       boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
                                        XMLNode &before = pl->get_state();
                                        (*i)->region()->trim_end (new_bound, this);
                                        XMLNode &after = pl->get_state();
-                                       session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
+                                       session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
                                }
                        }
 
                } else {
 
                        if (!rv->region()->locked()) {
-                                Playlist *pl = rv->region()->playlist();
+                               boost::shared_ptr<Playlist> pl = rv->region()->playlist();
                                XMLNode &before = pl->get_state();
                                rv->region()->trim_end (new_bound, this);
                                 XMLNode &after = pl->get_state();
-                               session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
+                               session->add_command (new MementoCommand<Playlist>(*pl.get(), &before, &after));
                        }
                }
 
@@ -4440,6 +4502,7 @@ void
 Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
 {
        Location * newloc = 0;
+       string rangename;
        
        if (!drag_info.first_move) {
                drag_range_markerbar_op (item, event);
@@ -4449,7 +4512,8 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
                    {
                        begin_reversible_command (_("new range marker"));
                         XMLNode &before = session->locations()->get_state();
-                       newloc = new Location(temp_location->start(), temp_location->end(), "unnamed", Location::IsRangeMarker);
+                       session->locations()->next_available_name(rangename,"unnamed");
+                       newloc = new Location(temp_location->start(), temp_location->end(), rangename, Location::IsRangeMarker);
                        session->locations()->add (newloc, true);
                         XMLNode &after = session->locations()->get_state();
                        session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
@@ -4588,7 +4652,7 @@ Editor::reposition_zoom_rect (nframes_t start, nframes_t end)
 {
        double x1 = frame_to_pixel (start);
        double x2 = frame_to_pixel (end);
-       double y2 = canvas_height - 2;
+       double y2 = full_canvas_height - 1.0;
 
        zoom_rect->property_x1() = x1;
        zoom_rect->property_y1() = 1.0;
@@ -4622,16 +4686,15 @@ Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
                return;
        }
 
-//     if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
-//             snap_to (drag_info.current_pointer_frame);
-               
-//             if (drag_info.first_move) {
-//                     snap_to (drag_info.grab_frame);
-//             }
-//     }
-               
+       if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
+               if (drag_info.first_move) {
+                       snap_to (drag_info.grab_frame);
+               } 
+               snap_to (drag_info.current_pointer_frame);
+       }
 
        /* base start and end on initial click position */
+
        if (drag_info.current_pointer_frame < drag_info.grab_frame) {
                start = drag_info.current_pointer_frame;
                end = drag_info.grab_frame;
@@ -4643,8 +4706,7 @@ Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
        if (drag_info.current_pointer_y < drag_info.grab_y) {
                y1 = drag_info.current_pointer_y;
                y2 = drag_info.grab_y;
-       }
-       else {
+       } else {
                y2 = drag_info.current_pointer_y;
                y1 = drag_info.grab_y;
        }
@@ -4691,7 +4753,7 @@ Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
                Selection::Operation op = Keyboard::selection_type (event->button.state);
                bool commit;
 
-               begin_reversible_command (_("select regions"));
+               begin_reversible_command (_("rubberband selection"));
 
                if (drag_info.grab_frame < drag_info.last_pointer_frame) {
                        commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, op);
@@ -4704,6 +4766,7 @@ Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
                }
                
        } else {
+               selection->clear_tracks();
                selection->clear_regions();
                selection->clear_points ();
                selection->clear_lines ();
@@ -4829,13 +4892,13 @@ Editor::mouse_brush_insert_region (RegionView* rv, nframes_t pos)
                return;
        }
 
-       Playlist* playlist = atv->playlist();
+       boost::shared_ptr<Playlist> playlist = atv->playlist();
        double speed = atv->get_diskstream()->speed();
        
         XMLNode &before = playlist->get_state();
        playlist->add_region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (arv->audio_region())), (nframes_t) (pos * speed));
         XMLNode &after = playlist->get_state();
-       session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
+       session->add_command(new MementoCommand<Playlist>(*playlist.get(), &before, &after));
        
        // playlist is frozen, so we have to update manually