Make MIDI tools actually do something. Sorta. Sometimes.
[ardour.git] / gtk2_ardour / editor_mouse.cc
index 39680980d6e8f19fa6ba80ee668405c2b7e15bf3..4ba1213d6279783a776f6a5426188b75ffb9f295 100644 (file)
 #include "time_axis_view.h"
 #include "audio_time_axis.h"
 #include "audio_region_view.h"
+#include "midi_region_view.h"
 #include "marker.h"
 #include "streamview.h"
 #include "region_gain_line.h"
 #include "automation_time_axis.h"
+#include "control_point.h"
 #include "prompter.h"
 #include "utils.h"
 #include "selection.h"
 #include "rgb_macros.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/playlist.h>
 #include <ardour/audioplaylist.h>
 #include <ardour/audioregion.h>
+#include <ardour/midi_region.h>
 #include <ardour/dB.h>
 #include <ardour/utils.h>
 #include <ardour/region_factory.h>
@@ -156,6 +160,12 @@ Editor::mouse_mode_toggled (MouseMode m)
                        set_mouse_mode (m);
                }
                break;
+       
+       case MouseNote:
+               if (mouse_note_button.get_active()) {
+                       set_mouse_mode (m);
+               }
+               break;
 
        default:
                break;
@@ -203,7 +213,7 @@ Editor::set_mouse_mode (MouseMode m, bool force)
                }
        }
 
-       /* XXX the hack of unsetting all other buttongs should go 
+       /* XXX the hack of unsetting all other buttons should go 
           away once GTK2 allows us to use regular radio buttons drawn like
           normal buttons, rather than my silly GroupedButton hack.
        */
@@ -240,8 +250,18 @@ Editor::set_mouse_mode (MouseMode m, bool force)
                mouse_audition_button.set_active (true);
                current_canvas_cursor = speaker_cursor;
                break;
+       
+       case MouseNote:
+               mouse_note_button.set_active (true);
+               current_canvas_cursor = note_cursor;
+               break;
        }
 
+       if (mouse_mode == MouseNote)
+               midi_toolbar_frame.show();
+       else
+               midi_toolbar_frame.hide();
+
        ignore_mouse_mode_toggle = false;
 
        if (is_drawable()) {
@@ -282,9 +302,92 @@ Editor::step_mouse_mode (bool next)
                if (next) set_mouse_mode (MouseObject);
                else set_mouse_mode (MouseTimeFX);
                break;
+       
+       case MouseNote:
+               if (next) set_mouse_mode (MouseObject);
+               else set_mouse_mode (MouseAudition);
+               break;
        }
 }
 
+void
+Editor::midi_edit_mode_toggled (MidiEditMode m)
+{
+       if (ignore_midi_edit_mode_toggle) {
+               return;
+       }
+
+       switch (m) {
+       case MidiEditSelect:
+               if (midi_tool_select_button.get_active()) {
+                       set_midi_edit_mode (m);
+               }
+               break;
+       
+       case MidiEditPencil:
+               if (midi_tool_pencil_button.get_active()) {
+                       set_midi_edit_mode (m);
+               }
+               break;
+       
+       case MidiEditErase:
+               if (midi_tool_erase_button.get_active()) {
+                       set_midi_edit_mode (m);
+               }
+               break;
+
+       default:
+               break;
+       }
+}      
+
+
+void
+Editor::set_midi_edit_mode (MidiEditMode m, bool force)
+{
+       if (drag_info.item) {
+               return;
+       }
+
+       if (!force && m == midi_edit_mode) {
+               return;
+       }
+       
+       midi_edit_mode = m;
+
+       instant_save ();
+       
+       ignore_midi_edit_mode_toggle = true;
+
+       switch (midi_edit_mode) {
+       case MidiEditSelect:
+               midi_tool_select_button.set_active (true);
+               //current_canvas_cursor = selector_cursor;
+               break;
+       
+       case MidiEditPencil:
+               midi_tool_pencil_button.set_active (true);
+               //current_canvas_cursor = selector_cursor;
+               break;
+       
+       case MidiEditErase:
+               midi_tool_erase_button.set_active (true);
+               //current_canvas_cursor = selector_cursor;
+               break;
+       }
+
+       if (mouse_mode == MouseNote)
+               midi_toolbar_frame.show();
+       else
+               midi_toolbar_frame.hide();
+
+       ignore_midi_edit_mode_toggle = false;
+
+       /*if (is_drawable()) {
+               track_canvas.get_window()->set_cursor(*current_canvas_cursor);
+       }*/
+}
+
 void
 Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
 {
@@ -327,22 +430,8 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
        
        switch (item_type) {
        case RegionItem:
-               if (mouse_mode != MouseRange) {
-                       commit = set_selected_regionview_from_click (press, op, true);
-               } else if (event->type == GDK_BUTTON_PRESS) {
-                       commit = set_selected_track_from_click (press, op, false);
-               }
-               break;
-               
        case RegionViewNameHighlight:
        case RegionViewName:
-               if (mouse_mode != MouseRange) {
-                       commit = set_selected_regionview_from_click (press, op, true);
-               } else if (event->type == GDK_BUTTON_PRESS) {
-                       commit = set_selected_track_from_click (press, op, false);
-               }
-               break;
-
        case FadeInHandleItem:
        case FadeInItem:
        case FadeOutHandleItem:
@@ -353,12 +442,15 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it
                        commit = set_selected_track_from_click (press, op, false);
                }
                break;
-               
-       case GainAutomationControlPointItem:
-       case PanAutomationControlPointItem:
-       case RedirectAutomationControlPointItem:
+
+       case CrossfadeViewItem:
+               commit = set_selected_track_from_click (press, op, false);
+               break;
+                       
+       case ControlPointItem:
+               commit = set_selected_track_from_click (press, op, true);
                if (mouse_mode != MouseRange) {
-                       commit = set_selected_control_point_from_click (op, false);
+                       commit |= set_selected_control_point_from_click (op, false);
                }
                break;
                
@@ -542,16 +634,12 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                                return true;
                                        break;
 
-                               case GainAutomationControlPointItem:
-                               case PanAutomationControlPointItem:
-                               case RedirectAutomationControlPointItem:
+                               case ControlPointItem:
                                        start_control_point_grab (item, event);
                                        return true;
                                        break;
                                        
-                               case GainAutomationLineItem:
-                               case PanAutomationLineItem:
-                               case RedirectAutomationLineItem:
+                               case AutomationLineItem:
                                        start_line_grab_from_line (item, event);
                                        return true;
                                        break;
@@ -561,7 +649,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                        start_rubberband_select (item, event);
                                        break;
                                        
-                               /* <CMT Additions> */
+#ifdef WITH_CMT
                                case ImageFrameHandleStartItem:
                                        imageframe_start_handle_op(item, event) ;
                                        return(true) ;
@@ -578,16 +666,13 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                        markerview_item_end_handle_op(item, event) ;
                                        return(true) ;
                                        break ;
-                               /* </CMT Additions> */
-                               
-                               /* <CMT Additions> */
                                case MarkerViewItem:
                                        start_markerview_grab(item, event) ;
                                        break ;
                                case ImageFrameItem:
                                        start_imageframe_grab(item, event) ;
                                        break ;
-                               /* </CMT Additions> */
+#endif
 
                                case MarkerBarItem:
                                        
@@ -606,17 +691,11 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                // start_line_grab_from_regionview (item, event);
                                break;
 
-                       case GainControlPointItem:
-                               start_control_point_grab (item, event);
-                               return true;
-                               
                        case GainLineItem:
                                start_line_grab_from_line (item, event);
                                return true;
 
-                       case GainAutomationControlPointItem:
-                       case PanAutomationControlPointItem:
-                       case RedirectAutomationControlPointItem:
+                       case ControlPointItem:
                                start_control_point_grab (item, event);
                                return true;
                                break;
@@ -628,15 +707,11 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                        break;
 
                        switch (item_type) {
-                       case GainAutomationControlPointItem:
-                       case PanAutomationControlPointItem:
-                       case RedirectAutomationControlPointItem:
+                       case ControlPointItem:
                                start_control_point_grab (item, event);
                                break;
 
-                       case GainAutomationLineItem:
-                       case PanAutomationLineItem:
-                       case RedirectAutomationLineItem:
+                       case AutomationLineItem:
                                start_line_grab_from_line (item, event);
                                break;
 
@@ -688,9 +763,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp
                                        }
                                        
                                        break;
-                               case GainAutomationControlPointItem:
-                               case PanAutomationControlPointItem:
-                               case RedirectAutomationControlPointItem:
+                               case ControlPointItem:
                                        start_control_point_grab (item, event);
                                        return true;
                                        break;
@@ -821,21 +894,13 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                break;
 
                        case StreamItem:
-                               popup_track_context_menu (1, event->button.time, item_type, false, where);
-                               break;
-                               
                        case RegionItem:
                        case RegionViewNameHighlight:
                        case RegionViewName:
-                               popup_track_context_menu (1, event->button.time, item_type, false, where);
-                               break;
-                               
                        case SelectionItem:
-                               popup_track_context_menu (1, event->button.time, item_type, true, where);
-                               break;
-
                        case AutomationTrackItem:
-                               popup_track_context_menu (1, event->button.time, item_type, false, where);
+                       case CrossfadeViewItem:
+                               popup_track_context_menu (1, event->button.time, where);
                                break;
 
                        case MarkerBarItem: 
@@ -858,11 +923,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                tm_marker_context_menu (&event->button, item);
                                break;
 
-                       case CrossfadeViewItem:
-                               popup_track_context_menu (1, event->button.time, item_type, false, where);
-                               break;
-
-                       /* <CMT Additions> */
+#ifdef WITH_CMT
                        case ImageFrameItem:
                                popup_imageframe_edit_menu(1, event->button.time, item, true) ;
                                break ;
@@ -875,8 +936,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        case MarkerTimeAxisItem:
                                popup_marker_time_axis_edit_menu(1, event->button.time, item, false) ;
                                break ;
-                       /* <CMT Additions> */
-
+#endif
                                
                        default:
                                break;
@@ -909,18 +969,14 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                        }
                        break;
                        
-               case GainControlPointItem:
+               case ControlPointItem:
                        if (mouse_mode == MouseGain) {
                                remove_gain_control_point (item, event);
+                       } else {
+                               remove_control_point (item, event);
                        }
                        break;
 
-               case GainAutomationControlPointItem:
-               case PanAutomationControlPointItem:
-               case RedirectAutomationControlPointItem:
-                       remove_control_point (item, event);
-                       break;
-
                default:
                        break;
                }
@@ -936,9 +992,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                case PlayheadCursorItem:
                case MarkerItem:
                case GainLineItem:
-               case GainAutomationLineItem:
-               case PanAutomationLineItem:
-               case RedirectAutomationLineItem:
+               case AutomationLineItem:
                case StartSelectionTrimItem:
                case EndSelectionTrimItem:
                        return true;
@@ -970,7 +1024,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                case MouseObject:
                        switch (item_type) {
                        case AutomationTrackItem:
-                               dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->add_automation_event 
+                               dynamic_cast<AutomationTimeAxisView*>(clicked_axisview)->add_automation_event 
                                        (item,
                                         event,
                                         where,
@@ -985,8 +1039,10 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
 
                case MouseGain:
                        // Gain only makes sense for audio regions
-                       if ( ! dynamic_cast<AudioRegionView*>(clicked_regionview))
+
+                       if (!dynamic_cast<AudioRegionView*>(clicked_regionview)) {
                                break;
+                       }
 
                        switch (item_type) {
                        case RegionItem:
@@ -995,7 +1051,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
                                break;
                                
                        case AutomationTrackItem:
-                               dynamic_cast<AutomationTimeAxisView*>(clicked_trackview)->
+                               dynamic_cast<AutomationTimeAxisView*>(clicked_axisview)->
                                        add_automation_event (item, event, where, event->button.y);
                                return true;
                                break;
@@ -1026,25 +1082,6 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
        case 2:
                switch (mouse_mode) {
                        
-               case MouseObject:
-                       switch (item_type) {
-                       case RegionItem:
-                               if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) {
-                                       raise_region ();
-                               } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) {
-                                       lower_region ();
-                               } else {
-                                       // Button2 click is unused
-                               }
-                               return true;
-                               
-                               break;
-                               
-                       default:
-                               break;
-                       }
-                       break;
-                       
                case MouseRange:
                        
                        // x_style_paste (where, 1.0);
@@ -1074,32 +1111,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
        double fraction;
        
        switch (item_type) {
-       case GainControlPointItem:
-               if (mouse_mode == MouseGain) {
-                       cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
-                       cp->set_visible (true);
-
-                       double at_x, at_y;
-                       at_x = cp->get_x();
-                       at_y = cp->get_y ();
-                       cp->item->i2w (at_x, at_y);
-                       at_x += 20.0;
-                       at_y += 20.0;
-
-                       fraction = 1.0 - (cp->get_y() / cp->line.height());
-
-                       set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
-                       show_verbose_canvas_cursor ();
-
-                       if (is_drawable()) {
-                               track_canvas.get_window()->set_cursor (*fader_cursor);
-                       }
-               }
-               break;
-
-       case GainAutomationControlPointItem:
-       case PanAutomationControlPointItem:
-       case RedirectAutomationControlPointItem:
+       case ControlPointItem:
                if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
                        cp = static_cast<ControlPoint*>(item->get_data ("control_point"));
                        cp->set_visible (true);
@@ -1107,13 +1119,13 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                        double at_x, at_y;
                        at_x = cp->get_x();
                        at_y = cp->get_y ();
-                       cp->item->i2w (at_x, at_y);
+                       cp->item()->i2w (at_x, at_y);
                        at_x += 20.0;
                        at_y += 20.0;
 
-                       fraction = 1.0 - (cp->get_y() / cp->line.height());
+                       fraction = 1.0 - (cp->get_y() / cp->line().height());
 
-                       set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y);
+                       set_verbose_canvas_cursor (cp->line().get_verbose_cursor_string (fraction), at_x, at_y);
                        show_verbose_canvas_cursor ();
 
                        if (is_drawable()) {
@@ -1126,21 +1138,19 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                if (mouse_mode == MouseGain) {
                        ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
                        if (line)
-                               line->property_fill_color_rgba() = color_map[cEnteredGainLine];
+                               line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredGainLine.get();
                        if (is_drawable()) {
                                track_canvas.get_window()->set_cursor (*fader_cursor);
                        }
                }
                break;
                        
-       case GainAutomationLineItem:
-       case RedirectAutomationLineItem:
-       case PanAutomationLineItem:
+       case AutomationLineItem:
                if (mouse_mode == MouseGain || mouse_mode == MouseObject) {
                        {
                                ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
                                if (line)
-                                       line->property_fill_color_rgba() = color_map[cEnteredAutomationLine];
+                                       line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredAutomationLine.get();
                        }
                        if (is_drawable()) {
                                track_canvas.get_window()->set_cursor (*fader_cursor);
@@ -1156,12 +1166,13 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
 
        case StartSelectionTrimItem:
        case EndSelectionTrimItem:
-       /* <CMT Additions> */
+
+#ifdef WITH_CMT
        case ImageFrameHandleStartItem:
        case ImageFrameHandleEndItem:
        case MarkerViewHandleStartItem:
        case MarkerViewHandleEndItem:
-       /* </CMT Additions> */
+#endif
 
                if (is_drawable()) {
                        track_canvas.get_window()->set_cursor (*trimmer_cursor);
@@ -1226,7 +1237,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
                if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) {
                        break;
                }
-               marker->set_color_rgba (color_map[cEnteredMarker]);
+               marker->set_color_rgba (ARDOUR_UI::config()->canvasvar_EnteredMarker.get());
                // fall through
        case MeterMarkerItem:
        case TempoMarkerItem:
@@ -1254,13 +1265,8 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
 
        switch (item_type) {
        case GainLineItem:
-       case GainAutomationLineItem:
-       case RedirectAutomationLineItem:
-       case PanAutomationLineItem:
-       case GainControlPointItem:
-       case GainAutomationControlPointItem:
-       case PanAutomationControlPointItem:
-       case RedirectAutomationControlPointItem:
+       case AutomationLineItem:
+       case ControlPointItem:
                /* these do not affect the current entered track state */
                clear_entered_track = false;
                break;
@@ -1288,13 +1294,10 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
        bool is_start;
 
        switch (item_type) {
-       case GainControlPointItem:
-       case GainAutomationControlPointItem:
-       case PanAutomationControlPointItem:
-       case RedirectAutomationControlPointItem:
+       case ControlPointItem:
                cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point"));
-               if (cp->line.npoints() > 1) {
-                       if (!cp->selected) {
+               if (cp->line().the_list()->interpolation() != AutomationList::Discrete) {
+                       if (cp->line().npoints() > 1 && !cp->selected()) {
                                cp->set_visible (false);
                        }
                }
@@ -1311,21 +1314,21 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_
        case EndSelectionTrimItem:
        case EditCursorItem:
        case PlayheadCursorItem:
-       /* <CMT Additions> */
+
+#ifdef WITH_CMT
        case ImageFrameHandleStartItem:
        case ImageFrameHandleEndItem:
        case MarkerViewHandleStartItem:
        case MarkerViewHandleEndItem:
-       /* </CMT Additions> */
+#endif
+
                if (is_drawable()) {
                        track_canvas.get_window()->set_cursor (*current_canvas_cursor);
                }
                break;
 
        case GainLineItem:
-       case GainAutomationLineItem:
-       case RedirectAutomationLineItem:
-       case PanAutomationLineItem:
+       case AutomationLineItem:
                al = reinterpret_cast<AutomationLine*> (item->get_data ("line"));
                {
                        ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item);
@@ -1445,9 +1448,9 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
                */
                if (!drag_info.move_threshold_passed) {
 
-                       bool x_threshold_passed =  (abs ((int) (drag_info.current_pointer_x - drag_info.grab_x)) > 4);
-                       bool y_threshold_passed =  (abs ((int) (drag_info.current_pointer_y - drag_info.grab_y)) > 4);
-
+                       bool x_threshold_passed =  (abs ((nframes64_t) (drag_info.current_pointer_x - drag_info.grab_x)) > 4LL);
+                       bool y_threshold_passed =  (abs ((nframes64_t) (drag_info.current_pointer_y - drag_info.grab_y)) > 4LL);
+                       
                        drag_info.move_threshold_passed = (x_threshold_passed || y_threshold_passed);
                        
                        // and change the initial grab loc/frame if this drag info wants us to
@@ -1466,10 +1469,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
        case PlayheadCursorItem:
        case EditCursorItem:
        case MarkerItem:
-       case GainControlPointItem:
-       case RedirectAutomationControlPointItem:
-       case GainAutomationControlPointItem:
-       case PanAutomationControlPointItem:
+       case ControlPointItem:
        case TempoMarkerItem:
        case MeterMarkerItem:
        case RegionViewNameHighlight:
@@ -1477,17 +1477,17 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
        case EndSelectionTrimItem:
        case SelectionItem:
        case GainLineItem:
-       case RedirectAutomationLineItem:
-       case GainAutomationLineItem:
-       case PanAutomationLineItem:
+       case AutomationLineItem:
        case FadeInHandleItem:
        case FadeOutHandleItem:
-       /* <CMT Additions> */
+
+#ifdef WITH_CMT
        case ImageFrameHandleStartItem:
        case ImageFrameHandleEndItem:
        case MarkerViewHandleStartItem:
        case MarkerViewHandleEndItem:
-       /* </CMT Additions> */
+#endif
+
          if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
                                 (event->motion.state & Gdk::BUTTON2_MASK))) {
                  if (!from_autoscroll) {
@@ -1559,7 +1559,7 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
                drag_info.y_constrained = false;
        }
 
-       drag_info.grab_frame = event_frame(event, &drag_info.grab_x, &drag_info.grab_y);
+       drag_info.grab_frame = event_frame (event, &drag_info.grab_x, &drag_info.grab_y);
        drag_info.last_pointer_frame = drag_info.grab_frame;
        drag_info.current_pointer_frame = drag_info.grab_frame;
        drag_info.current_pointer_x = drag_info.grab_x;
@@ -1693,7 +1693,7 @@ Editor::start_fade_in_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
 
-       drag_info.pointer_frame_offset = drag_info.grab_frame - ((nframes_t) arv->audio_region()->fade_in().back()->when + arv->region()->position());  
+       drag_info.pointer_frame_offset = drag_info.grab_frame - ((nframes_t) arv->audio_region()->fade_in()->back()->when + arv->region()->position()); 
 }
 
 void
@@ -1703,7 +1703,7 @@ Editor::fade_in_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        nframes_t pos;
        nframes_t fade_length;
 
-       if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -1748,7 +1748,7 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even
 
        if (drag_info.first_move) return;
 
-       if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        } else {
                pos = 0;
@@ -1772,13 +1772,13 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even
                        continue;
                }
        
-               AutomationList& alist = tmp->audio_region()->fade_in();
-               XMLNode &before = alist.get_state();
+               boost::shared_ptr<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.get(), &before, &after));
        }
 
        commit_reversible_command ();
@@ -1800,7 +1800,7 @@ Editor::start_fade_out_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        AudioRegionView* arv = static_cast<AudioRegionView*>(drag_info.data);
 
-       drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region()->length() - (nframes_t) arv->audio_region()->fade_out().back()->when + arv->region()->position());       
+       drag_info.pointer_frame_offset = drag_info.grab_frame - (arv->region()->length() - (nframes_t) arv->audio_region()->fade_out()->back()->when + arv->region()->position());      
 }
 
 void
@@ -1810,10 +1810,9 @@ Editor::fade_out_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 (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;
        }
 
@@ -1858,7 +1857,7 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve
        nframes_t pos;
        nframes_t fade_length;
 
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pos = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -1889,13 +1888,13 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve
                        continue;
                }
        
-               AutomationList& alist = tmp->audio_region()->fade_out();
-               XMLNode &before = alist.get_state();
+               boost::shared_ptr<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));
+               XMLNode &after = alist->get_state();
+               session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
        }
 
        commit_reversible_command ();
@@ -1940,7 +1939,7 @@ Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        Cursor* cursor = (Cursor *) drag_info.data;
        nframes_t adjusted_frame;
        
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -2056,10 +2055,9 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
 
        nframes_t newframe;
-       if (drag_info.pointer_frame_offset <= (long) drag_info.current_pointer_frame) {
+       if (drag_info.pointer_frame_offset <= drag_info.current_pointer_frame) {
                newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-       }
-       else {
+       } else {
                newframe = 0;
        }
 
@@ -2215,7 +2213,7 @@ Editor::start_meter_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
        // The actual copying is not done before we reach the finish callback.
        char name[64];
        snprintf (name, sizeof(name), "%g/%g", meter_marker->meter().beats_per_bar(), meter_marker->meter().note_divisor ());
-       MeterMarker* new_marker = new MeterMarker(*this, *meter_group, color_map[cMeterMarker], name, 
+       MeterMarker* new_marker = new MeterMarker(*this, *meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name, 
                                                  *new MeterSection(meter_marker->meter()));
 
        drag_info.item = &new_marker->the_item();
@@ -2237,7 +2235,7 @@ Editor::meter_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* e
        MeterMarker* marker = (MeterMarker *) drag_info.data;
        nframes_t adjusted_frame;
 
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -2346,7 +2344,7 @@ Editor::start_tempo_marker_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
        // The actual copying is not done before we reach the finish callback.
        char name[64];
        snprintf (name, sizeof (name), "%.2f", tempo_marker->tempo().beats_per_minute());
-       TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, color_map[cTempoMarker], name, 
+       TempoMarker* new_marker = new TempoMarker(*this, *tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name, 
                                                  *new TempoSection(tempo_marker->tempo()));
 
        drag_info.item = &new_marker->the_item();
@@ -2368,7 +2366,7 @@ Editor::tempo_marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* e
        TempoMarker* marker = (TempoMarker *) drag_info.data;
        nframes_t adjusted_frame;
        
-       if ((long)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                adjusted_frame = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
        }
        else {
@@ -2436,16 +2434,16 @@ Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event)
        }
 
        // 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)) {   
+       if (control_point->line().is_last_point(*control_point) ||
+               control_point->line().is_first_point(*control_point)) { 
                return;
        }
 
-       control_point->line.remove_point (*control_point);
+       control_point->line().remove_point (*control_point);
 }
 
 void
-Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
+Editor::remove_control_point (ArdourCanvas::Item* item, GdkEvent* event)
 {
        ControlPoint* control_point;
 
@@ -2454,14 +2452,14 @@ Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event)
                /*NOTREACHED*/
        }
 
-       control_point->line.remove_point (*control_point);
+       control_point->line().remove_point (*control_point);
 }
 
 void
 Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
 {
        ControlPoint* control_point;
-       
+
        if ((control_point = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"))) == 0) {
                fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg;
                /*NOTREACHED*/
@@ -2474,10 +2472,10 @@ Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        start_grab (event, fader_cursor);
 
-       control_point->line.start_drag (control_point, drag_info.grab_frame, 0);
+       control_point->line().start_drag (control_point, drag_info.grab_frame, 0);
 
-       float fraction = 1.0 - (control_point->get_y() / control_point->line.height());
-       set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction), 
+       double fraction = 1.0 - ((control_point->get_y() - control_point->line().y_position()) / (double)control_point->line().height());
+       set_verbose_canvas_cursor (control_point->line().get_verbose_cursor_string (fraction), 
                                   drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20);
 
        show_verbose_canvas_cursor ();
@@ -2501,11 +2499,11 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
                cy = drag_info.grab_y;
        }
 
-       cp->line.parent_group().w2i (cx, cy);
+       cp->line().parent_group().w2i (cx, cy);
 
        cx = max (0.0, cx);
        cy = max (0.0, cy);
-       cy = min ((double) cp->line.height(), cy);
+       cy = min ((double) (cp->line().y_position() + cp->line().height()), cy);
 
        //translate cx to frames
        nframes_t cx_frames = unit_to_frame (cx);
@@ -2514,8 +2512,8 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
                snap_to (cx_frames);
        }
 
-       float fraction = 1.0 - (cy / cp->line.height());
-       
+       const double fraction = 1.0 - ((cy - cp->line().y_position()) / (double)cp->line().height());
+
        bool push;
 
        if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) {
@@ -2524,9 +2522,9 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent*
                push = false;
        }
 
-       cp->line.point_drag (*cp, cx_frames , fraction, push);
+       cp->line().point_drag (*cp, cx_frames , fraction, push);
        
-       set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction));
+       set_verbose_canvas_cursor_text (cp->line().get_verbose_cursor_string (fraction));
 
        drag_info.first_move = false;
 }
@@ -2547,7 +2545,7 @@ Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent
        } else {
                control_point_drag_motion_callback (item, event);
        }
-       cp->line.end_drag (cp);
+       cp->line().end_drag (cp);
 }
 
 void
@@ -2605,7 +2603,7 @@ Editor::start_line_grab (AutomationLine* line, GdkEvent* event)
 
        start_grab (event, fader_cursor);
 
-       double fraction = 1.0 - (cy / line->height());
+       const double fraction = 1.0 - ((cy - line->y_position()) / (double)line->height());
 
        line->start_drag (0, drag_info.grab_frame, fraction);
        
@@ -2623,8 +2621,7 @@ Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
        line->parent_group().w2i (cx, cy);
        
-       double fraction;
-       fraction = 1.0 - (cy / line->height());
+       const double fraction = 1.0 - ((cy - line->y_position()) / (double)line->height());
 
        bool push;
 
@@ -2663,10 +2660,10 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event)
        start_grab (event);
 
        double speed = 1.0;
-       TimeAxisView* tvp = clicked_trackview;
+       TimeAxisView* tvp = clicked_axisview;
        RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
 
-       if (tv && tv->is_audio_track()) {
+       if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
        
@@ -2695,11 +2692,11 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event)
        start_grab(event);
 
        TimeAxisView* tv = &clicked_regionview->get_time_axis_view();
-       RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(tv);
+       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(tv);
        double speed = 1.0;
 
-       if (atv && atv->is_audio_track()) {
-               speed = atv->get_diskstream()->speed();
+       if (rtv && rtv->is_track()) {
+               speed = rtv->get_diskstream()->speed();
        }
        
        drag_info.last_trackview = &clicked_regionview->get_time_axis_view();
@@ -2728,10 +2725,10 @@ Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event)
        start_grab (event);
 
        double speed = 1.0;
-       TimeAxisView* tvp = clicked_trackview;
+       TimeAxisView* tvp = clicked_axisview;
        RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
 
-       if (tv && tv->is_audio_track()) {
+       if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
        
@@ -2763,23 +2760,26 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                drag_info.want_move_threshold = false; // don't copy again
 
                /* duplicate the region(s) */
-               
+
                vector<RegionView*> new_regionviews;
                
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
                        RegionView* rv;
                        RegionView* nrv;
-                       AudioRegionView* arv;
 
                        rv = (*i);
 
-                       
-                       if ((arv = dynamic_cast<AudioRegionView*>(rv)) == 0) {
-                               /* XXX handle MIDI here */
+                       AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
+                       MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
+
+                       if (arv) {
+                               nrv = new AudioRegionView (*arv);
+                       } else if (mrv) {
+                               nrv = new MidiRegionView (*mrv);
+                       } else {
                                continue;
                        }
 
-                       nrv = new AudioRegionView (*arv);
                        nrv->get_canvas_group()->show ();
 
                        new_regionviews.push_back (nrv);
@@ -2796,22 +2796,22 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                /* 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);
-       AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
+       RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
 
        /* The region motion is only processed if the pointer is over
           an audio track.
        */
        
-       if (!tv || !tv->is_audio_track()) {
+       if (!tv || !tv->is_track()) {
                /* To make sure we hide the verbose canvas cursor when the mouse is 
-                  not held over and audiotrack. 
+                  not held over a track. 
                */
                hide_verbose_canvas_cursor ();
                return;
@@ -2839,30 +2839,30 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
                        TimeAxisView *tracklist_timeview;
                        tracklist_timeview = (*i);
-                       AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tracklist_timeview);
-                       list<TimeAxisView*> children_list;
+                       RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tracklist_timeview);
+                       TimeAxisView::Children children_list;
              
                        /* zeroes are audio tracks. ones are other types. */
              
-                       if (!atv2->hidden()) {
+                       if (!rtv2->hidden()) {
                                
-                               if (visible_y_high < atv2->order) {
-                                       visible_y_high = atv2->order;
+                               if (visible_y_high < rtv2->order) {
+                                       visible_y_high = rtv2->order;
                                }
-                               if (visible_y_low > atv2->order) {
-                                       visible_y_low = atv2->order;
+                               if (visible_y_low > rtv2->order) {
+                                       visible_y_low = rtv2->order;
                                }
                
-                               if (!atv2->is_audio_track()) {                            
-                                       tracks = tracks |= (0x01 << atv2->order);
+                               if (!rtv2->is_track()) {                                  
+                                       tracks = tracks |= (0x01 << rtv2->order);
                                }
        
-                               height_list[atv2->order] = (*i)->height;
+                               height_list[rtv2->order] = (*i)->height;
                                children = 1;
-                               if ((children_list = atv2->get_child_list()).size() > 0) {
-                                       for (list<TimeAxisView*>::iterator j = children_list.begin(); j != children_list.end(); ++j) { 
-                                               tracks = tracks |= (0x01 << (atv2->order + children));
-                                               height_list[atv2->order + children] =  (*j)->height;                
+                               if ((children_list = rtv2->get_child_list()).size() > 0) {
+                                       for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) { 
+                                               tracks = tracks |= (0x01 << (rtv2->order + children));
+                                               height_list[rtv2->order + children] =  (*j)->height;                
                                                numtracks++;
                                                children++;     
                                        }
@@ -2897,27 +2897,27 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                        rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
                        rv2->get_canvas_group()->i2w (ix1, iy1);
                        TimeAxisView* tvp2 = trackview_by_y_position (iy1);
-                       RouteTimeAxisView* atv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
+                       RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
 
-                       if (atv2->order != original_pointer_order) {    
+                       if (rtv2->order != original_pointer_order) {    
                                /* this isn't the pointer track */      
 
                                if (canvas_pointer_y_span > 0) {
 
                                        /* moving up the canvas */
-                                       if ((atv2->order - canvas_pointer_y_span) >= visible_y_low) {
+                                       if ((rtv2->order - canvas_pointer_y_span) >= visible_y_low) {
        
                                                int32_t visible_tracks = 0;
                                                while (visible_tracks < canvas_pointer_y_span ) {
                                                        visible_tracks++;
                  
-                                                       while (height_list[atv2->order - (visible_tracks - n)] == 0) {
+                                                       while (height_list[rtv2->order - (visible_tracks - n)] == 0) {
                                                                /* we're passing through a hidden track */
                                                                n--;
                                                        }                 
                                                }
                 
-                                               if (tracks[atv2->order - (canvas_pointer_y_span - n)] != 0x00) {                  
+                                               if (tracks[rtv2->order - (canvas_pointer_y_span - n)] != 0x00) {                  
                                                        clamp_y_axis = true;
                                                }
                    
@@ -2929,7 +2929,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
                                        /*moving down the canvas*/
 
-                                       if ((atv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
+                                       if ((rtv2->order - (canvas_pointer_y_span - n)) <= visible_y_high) { // we will overflow
                    
                    
                                                int32_t visible_tracks = 0;
@@ -2937,11 +2937,11 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                                                while (visible_tracks > canvas_pointer_y_span ) {
                                                        visible_tracks--;
                      
-                                                       while (height_list[atv2->order - (visible_tracks - n)] == 0) {             
+                                                       while (height_list[rtv2->order - (visible_tracks - n)] == 0) {             
                                                                n++;
                                                        }                
                                                }
-                                               if (  tracks[atv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
+                                               if (  tracks[rtv2->order - ( canvas_pointer_y_span - n)] != 0x00) {
                                                        clamp_y_axis = true;
                            
                                                }
@@ -2954,9 +2954,9 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                        } else {
                      
                                /* this is the pointer's track */
-                               if ((atv2->order - pointer_y_span) > visible_y_high) { // we will overflow 
+                               if ((rtv2->order - pointer_y_span) > visible_y_high) { // we will overflow 
                                        clamp_y_axis = true;
-                               } else if ((atv2->order - pointer_y_span) < visible_y_low) { // we will underflow
+                               } else if ((rtv2->order - pointer_y_span) < visible_y_low) { // we will underflow
                                        clamp_y_axis = true;
                                }
                        }             
@@ -2984,14 +2984,14 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
 
        if (drag_info.move_threshold_passed) {
 
-               if ((int32_t)drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+               if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
 
                        nframes_t sync_frame;
                        nframes_t sync_offset;
                        int32_t sync_dir;
            
                        pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-           
+
                        sync_offset = rv->region()->sync_offset (sync_dir);
                        sync_frame = rv->region()->adjust_to_sync (pending_region_position);
 
@@ -3023,13 +3023,13 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                        /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order
                           to make it appear at the new location.
                        */
-           
+
                        if (pending_region_position > drag_info.last_frame_position) {
                                x_delta = ((double) (pending_region_position - drag_info.last_frame_position) / frames_per_unit);
                        } else {
                                x_delta = -((double) (drag_info.last_frame_position - pending_region_position) / frames_per_unit);
                        }
-           
+
                        drag_info.last_frame_position = pending_region_position;
            
                } else {
@@ -3053,6 +3053,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                return;
        } 
 
+
        if (x_delta < 0) {
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
 
@@ -3106,14 +3107,14 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                        rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
                        rv->get_canvas_group()->i2w (ix1, iy1);
                        TimeAxisView* tvp2 = trackview_by_y_position (iy1);
-                       AudioTimeAxisView* canvas_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
-                       AudioTimeAxisView* temp_atv;
+                       RouteTimeAxisView* canvas_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
+                       RouteTimeAxisView* temp_rtv;
 
                        if ((pointer_y_span != 0) && !clamp_y_axis) {
                                y_delta = 0;
                                int32_t x = 0;
                                for (j = height_list.begin(); j!= height_list.end(); j++) {     
-                                       if (x == canvas_atv->order) {
+                                       if (x == canvas_rtv->order) {
                                                /* we found the track the region is on */
                                                if (x != original_pointer_order) {
                                                        /*this isn't from the same track we're dragging from */
@@ -3151,14 +3152,14 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                                                /* find out where we'll be when we move and set height accordingly */
                  
                                                tvp2 = trackview_by_y_position (iy1 + y_delta);
-                                               temp_atv = dynamic_cast<AudioTimeAxisView*>(tvp2);
-                                               rv->set_height (temp_atv->height);
+                                               temp_rtv = dynamic_cast<RouteTimeAxisView*>(tvp2);
+                                               rv->set_y_position_and_height (0, temp_rtv->height);
        
                                                /*   if you un-comment the following, the region colours will follow the track colours whilst dragging,
                                                     personally, i think this can confuse things, but never mind.
                                                */
                                  
-                                               //const GdkColor& col (temp_atv->view->get_region_color());
+                                               //const GdkColor& col (temp_rtv->view->get_region_color());
                                                //rv->set_color (const_cast<GdkColor&>(col));
                                                break;          
                                        }
@@ -3175,10 +3176,11 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
                                if (-x_delta > ix1) {
                                        x_delta = -ix1;
                                }
-                       } else if ((x_delta > 0) &&(rv->region()->last_frame() > max_frames - x_delta)) {
+                       } else if ((x_delta > 0) && (rv->region()->last_frame() > max_frames - x_delta)) {
                                x_delta = max_frames - rv->region()->last_frame();
                        }
 
+
                        if (drag_info.first_move) {
 
                                /* hide any dependent views */
@@ -3226,9 +3228,10 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
        pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
        bool nocommit = true;
        double speed;
-       RouteTimeAxisView* atv;
+       RouteTimeAxisView* rtv;
        bool regionview_y_movement;
        bool regionview_x_movement;
+       vector<RegionView*> copies;
 
        /* first_move is set to false if the regionview has been moved in the 
           motion handler. 
@@ -3249,15 +3252,22 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
        if (drag_info.brushing) {
                /* all changes were made during motion event handlers */
+               
+               if (drag_info.copy) {
+                       for (list<RegionView*>::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+                               copies.push_back (*i);
+                       }
+               }
+
                goto out;
        }
 
        /* adjust for track speed */
        speed = 1.0;
 
-       atv = dynamic_cast<AudioTimeAxisView*> (drag_info.last_trackview);
-       if (atv && atv->get_diskstream()) {
-               speed = atv->get_diskstream()->speed();
+       rtv = dynamic_cast<RouteTimeAxisView*> (drag_info.last_trackview);
+       if (rtv && rtv->get_diskstream()) {
+               speed = rtv->get_diskstream()->speed();
        }
        
        regionview_x_movement = (drag_info.last_frame_position != (nframes_t) (rv->region()->position()/speed));
@@ -3291,7 +3301,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                vector<RegionView*> new_selection;
 
                for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) {
-           
+                       
                        RegionView* rv = (*i);              
 
                        double ix1, ix2, iy1, iy2;
@@ -3299,14 +3309,20 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                        rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
                        rv->get_canvas_group()->i2w (ix1, iy1);
                        TimeAxisView* tvp2 = trackview_by_y_position (iy1);
-                       AudioTimeAxisView* atv2 = dynamic_cast<AudioTimeAxisView*>(tvp2);
+                       RouteTimeAxisView* rtv2 = dynamic_cast<RouteTimeAxisView*>(tvp2);
 
                        boost::shared_ptr<Playlist> from_playlist = rv->region()->playlist();
-                       boost::shared_ptr<Playlist> to_playlist = atv2->playlist();
-           
+                       boost::shared_ptr<Playlist> to_playlist = rtv2->playlist();
+
                        where = (nframes_t) (unit_to_frame (ix1) * speed);
                        boost::shared_ptr<Region> new_region (RegionFactory::create (rv->region()));
 
+                       /* undo the previous hide_dependent_views so that xfades don't
+                          disappear on copying regions 
+                       */
+
+                       rv->get_time_axis_view().reveal_dependent_views (*rv);
+
                        if (!drag_info.copy) {
                                
                                /* the region that used to be in the old playlist is not
@@ -3321,11 +3337,17 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                                session->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));    
                                from_playlist->remove_region ((rv->region()));
                                session->add_command (new MementoCommand<Playlist>(*from_playlist, 0, &from_playlist->get_state()));    
+
+                       } else {
+
+                               /* the regionview we dragged around is a temporary copy, queue it for deletion */
+                               
+                               copies.push_back (rv);
                        }
 
                        latest_regionview = 0;
                        
-                       sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
+                       sigc::connection c = rtv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));        
                        to_playlist->add_region (new_region, where);
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, 0, &to_playlist->get_state()));        
@@ -3335,11 +3357,6 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                                new_selection.push_back (latest_regionview);
                        }
 
-                       if (drag_info.copy) {
-                               // get rid of the copy
-                               delete rv;
-                       } 
-
                        /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
                           was selected in all of them, then removing it from the playlist will have removed all
                           trace of it from the selection (i.e. there were N regions selected, we removed 1,
@@ -3352,12 +3369,19 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
                           here. if the region selection is not empty, then restart the loop because we know that
                           we must have removed at least the region(view) we've just been working on as well as any
                           that we processed on previous iterations.
+
+                          EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
+                          we can just iterate.
                        */
 
-                       if (selection->regions.empty()) {
-                               break;
-                       } else { 
-                               i = selection->regions.by_layer().begin();
+                       if (drag_info.copy) {
+                               ++i;
+                       } else {
+                               if (selection->regions.empty()) {
+                                       break;
+                               } else { 
+                                       i = selection->regions.by_layer().begin();
+                               }
                        }
                } 
 
@@ -3377,17 +3401,16 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
                        rv = (*i);
 
-                       if (rv->region()->locked()) {
+                       if (!rv->region()->can_move()) {
                                continue;
                        }
-                       
 
                        if (regionview_x_movement) {
                                double ownspeed = 1.0;
-                               atv = dynamic_cast<AudioTimeAxisView*> (&(rv->get_time_axis_view()));
+                               rtv = dynamic_cast<RouteTimeAxisView*> (&(rv->get_time_axis_view()));
 
-                               if (atv && atv->get_diskstream()) {
-                                       ownspeed = atv->get_diskstream()->speed();
+                               if (rtv && rtv->get_diskstream()) {
+                                       ownspeed = rtv->get_diskstream()->speed();
                                }
                                
                                /* base the new region position on the current position of the regionview.*/
@@ -3415,30 +3438,26 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
                                boost::shared_ptr<Region> newregion;
                                boost::shared_ptr<Region> ar;
+                               boost::shared_ptr<Region> mr;
 
                                if ((ar = boost::dynamic_pointer_cast<AudioRegion>(rv->region())) != 0) {
                                        newregion = RegionFactory::create (ar);
-                               } else {
-                                       /* XXX MIDI HERE drobilla */
-                                       continue;
+                               } else if ((mr = boost::dynamic_pointer_cast<MidiRegion>(rv->region())) != 0) {
+                                       newregion = RegionFactory::create (mr);
                                }
 
                                /* add it */
-                               
+
                                latest_regionview = 0;
-                               sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
-                               to_playlist->add_region (newregion, (nframes_t) (where * atv->get_diskstream()->speed()));
+                               sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
+                               to_playlist->add_region (newregion, (nframes_t) (where * rtv->get_diskstream()->speed()));
                                c.disconnect ();
                                
                                if (latest_regionview) {
-                                       atv->reveal_dependent_views (*latest_regionview);
+                                       rtv->reveal_dependent_views (*latest_regionview);
                                        selection->add (latest_regionview);
                                }
                                
-                               /* if the original region was locked, we don't care for the new one */
-                               
-                               newregion->set_locked (false);                  
-
                        } else {
 
                                /* just change the model */
@@ -3451,10 +3470,8 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
 
                        session->add_command (new MementoCommand<Playlist>(*to_playlist, 0, &to_playlist->get_state()));
 
-                       /* get rid of the copy */
-
                        if (drag_info.copy) {
-                               delete rv;
+                               copies.push_back (rv);
                        }
                }
        }
@@ -3464,6 +3481,10 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event
        if (!nocommit) {
                commit_reversible_command ();
        }
+
+       for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
+               delete *x;
+       }
 }
 
 void
@@ -3475,10 +3496,10 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event)
        
        if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) {
                TimeAxisView* tv = &rv.get_time_axis_view();
-               AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(tv);
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(tv);
                double speed = 1.0;
-               if (atv && atv->is_audio_track()) {
-                       speed = atv->get_diskstream()->speed();
+               if (rtv && rtv->is_track()) {
+                       speed = rtv->get_diskstream()->speed();
                }
 
                if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) {
@@ -3510,7 +3531,7 @@ Editor::show_verbose_time_cursor (nframes_t frame, double offset, double xpos, d
                return;
        }
 
-       switch (ARDOUR_UI::instance()->secondary_clock.mode ()) {
+       switch (Profile->get_small_screen() ? ARDOUR_UI::instance()->primary_clock.mode () : ARDOUR_UI::instance()->secondary_clock.mode ()) {
        case AudioClock::BBT:
                session->bbt_time (frame, bbt);
                snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks);
@@ -3654,7 +3675,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
        */
        
        latest_regionview = 0;
-       sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
+       sigc::connection c = clicked_routeview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
        
        /* A selection grab currently creates two undo/redo operations, one for 
           creating the new region and another for moving it.
@@ -3662,11 +3683,11 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        begin_reversible_command (_("selection grab"));
 
-       boost::shared_ptr<Playlist> playlist = clicked_trackview->playlist();
+       boost::shared_ptr<Playlist> playlist = clicked_axisview->playlist();
 
-        XMLNode *before = &(playlist->get_state());
-       clicked_trackview->playlist()->add_region (region, selection->time[clicked_selection].start);
-        XMLNode *after = &(playlist->get_state());
+       XMLNode *before = &(playlist->get_state());
+       clicked_routeview->playlist()->add_region (region, selection->time[clicked_selection].start);
+       XMLNode *after = &(playlist->get_state());
        session->add_command(new MementoCommand<Playlist>(*playlist, before, after));
 
        commit_reversible_command ();
@@ -3689,7 +3710,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event)
 
        start_grab (event);
        
-       drag_info.last_trackview = clicked_trackview;
+       drag_info.last_trackview = clicked_axisview;
        drag_info.last_frame_position = latest_regionview->region()->position();
        drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position;
        
@@ -3735,8 +3756,8 @@ Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, Selection
                break;
 
        case SelectionStartTrim:
-               if (clicked_trackview) {
-                       clicked_trackview->order_selection_trims (item, true);
+               if (clicked_axisview) {
+                       clicked_axisview->order_selection_trims (item, true);
                } 
                start_grab (event, trimmer_cursor);
                start = selection->time[clicked_selection].start;
@@ -3744,8 +3765,8 @@ Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, Selection
                break;
                
        case SelectionEndTrim:
-               if (clicked_trackview) {
-                       clicked_trackview->order_selection_trims (item, false);
+               if (clicked_axisview) {
+                       clicked_axisview->order_selection_trims (item, false);
                }
                start_grab (event, trimmer_cursor);
                end = selection->time[clicked_selection].end;
@@ -3774,10 +3795,9 @@ Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
        nframes_t length;
        nframes_t pending_position;
 
-       if ((int32_t) drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
+       if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) {
                pending_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset;
-       }
-       else {
+       } else {
                pending_position = 0;
        }
        
@@ -3820,7 +3840,7 @@ Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event)
                                drag_info.copy = false;
                        } else {
                                /* new selection-> */
-                               clicked_selection = selection->set (clicked_trackview, start, end);
+                               clicked_selection = selection->set (clicked_axisview, start, end);
                        }
                } 
                break;
@@ -3924,10 +3944,10 @@ void
 Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event)
 {
        double speed = 1.0;
-       TimeAxisView* tvp = clicked_trackview;
-       AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
+       TimeAxisView* tvp = clicked_axisview;
+       RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
 
-       if (tv && tv->is_audio_track()) {
+       if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
        
@@ -3982,11 +4002,11 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
        */ 
 
        double speed = 1.0;
-       TimeAxisView* tvp = clicked_trackview;
+       TimeAxisView* tvp = clicked_axisview;
        RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
        pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
 
-       if (tv && tv->is_audio_track()) {
+       if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
        
@@ -4110,10 +4130,10 @@ Editor::single_contents_trim (RegionView& rv, nframes_t frame_delta, bool left_d
        nframes_t new_bound;
 
        double speed = 1.0;
-       TimeAxisView* tvp = clicked_trackview;
+       TimeAxisView* tvp = clicked_axisview;
        RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
 
-       if (tv && tv->is_audio_track()) {
+       if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
        
@@ -4150,10 +4170,10 @@ Editor::single_start_trim (RegionView& rv, nframes_t frame_delta, bool left_dire
        nframes_t new_bound;
 
        double speed = 1.0;
-       TimeAxisView* tvp = clicked_trackview;
-       AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
+       TimeAxisView* tvp = clicked_axisview;
+       RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
 
-       if (tv && tv->is_audio_track()) {
+       if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
        
@@ -4184,10 +4204,10 @@ Editor::single_end_trim (RegionView& rv, nframes_t frame_delta, bool left_direct
        nframes_t new_bound;
 
        double speed = 1.0;
-       TimeAxisView* tvp = clicked_trackview;
-       AudioTimeAxisView* tv = dynamic_cast<AudioTimeAxisView*>(tvp);
+       TimeAxisView* tvp = clicked_axisview;
+       RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
 
-       if (tv && tv->is_audio_track()) {
+       if (tv && tv->is_track()) {
                speed = tv->get_diskstream()->speed();
        }
        
@@ -4510,7 +4530,7 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event)
                        switch (mouse_mode) {
                        case MouseObject:
                                /* find the two markers on either side and then make the selection from it */
-                               select_all_within (start, end, 0.0f, FLT_MAX, Selection::Set);
+                               select_all_within (start, end, 0.0f, FLT_MAX, track_views, Selection::Set);
                                break;
 
                        case MouseRange:
@@ -4713,9 +4733,9 @@ Editor::end_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event)
                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);
+                       commit = select_all_within (drag_info.grab_frame, drag_info.last_pointer_frame, y1, y2, track_views, op);
                } else {
-                       commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, op);
+                       commit = select_all_within (drag_info.last_pointer_frame, drag_info.grab_frame, y1, y2, track_views, op);
                }               
 
                if (commit) {
@@ -4750,7 +4770,7 @@ Editor::mouse_rename_region (ArdourCanvas::Item* item, GdkEvent* event)
         string str;
                prompter.get_result(str);
                if (str.length()) {
-               clicked_regionview->region()->set_name (str);
+                       clicked_regionview->region()->set_name (str);
                }
                break;
        }
@@ -4843,14 +4863,14 @@ Editor::mouse_brush_insert_region (RegionView* rv, nframes_t pos)
                return;
        }
 
-       RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&arv->get_time_axis_view());
+       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&arv->get_time_axis_view());
 
-       if (atv == 0 || !atv->is_audio_track()) {
+       if (rtv == 0 || !rtv->is_track()) {
                return;
        }
 
-       boost::shared_ptr<Playlist> playlist = atv->playlist();
-       double speed = atv->get_diskstream()->speed();
+       boost::shared_ptr<Playlist> playlist = rtv->playlist();
+       double speed = rtv->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));