clean up a-pong
[ardour.git] / gtk2_ardour / time_axis_view.cc
index 059776bd92606326561f855021d0f67c6661fee8..bdddaa0c5ae5a2c5cec1bc4aaa1326ed259267e9 100644 (file)
@@ -27,6 +27,7 @@
 #include "pbd/error.h"
 #include "pbd/convert.h"
 #include "pbd/stacktrace.h"
+#include "pbd/unwind.h"
 
 #include <gtkmm2ext/doi.h>
 #include <gtkmm2ext/utils.h>
 #include "canvas/canvas.h"
 #include "canvas/rectangle.h"
 #include "canvas/debug.h"
+#include "canvas/utils.h"
+#include "canvas/colors.h"
+
+#include "ardour/profile.h"
 
-#include "ardour_ui.h"
 #include "ardour_dialog.h"
-#include "global_signals.h"
+#include "floating_text_entry.h"
 #include "gui_thread.h"
 #include "public_editor.h"
 #include "time_axis_view.h"
 #include "streamview.h"
 #include "editor_drag.h"
 #include "editor.h"
+#include "tooltips.h"
+#include "ui_config.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace Gtk;
 using namespace Gdk;
 using namespace ARDOUR;
+using namespace ARDOUR_UI_UTILS;
 using namespace PBD;
 using namespace Editing;
 using namespace ArdourCanvas;
 using Gtkmm2ext::Keyboard;
 
+#define TOP_LEVEL_WIDGET controls_ebox
+
 const double trim_handle_size = 6.0; /* pixels */
 uint32_t TimeAxisView::button_height = 0;
 uint32_t TimeAxisView::extra_height = 0;
 int const TimeAxisView::_max_order = 512;
+unsigned int TimeAxisView::name_width_px = 100;
 PBD::Signal1<void,TimeAxisView*> TimeAxisView::CatchDeletion;
+Glib::RefPtr<Gtk::SizeGroup> TimeAxisView::controls_meters_size_group = Glib::RefPtr<Gtk::SizeGroup>();
+Glib::RefPtr<Gtk::SizeGroup> TimeAxisView::midi_scroomer_size_group = Glib::RefPtr<Gtk::SizeGroup>();
+
+void
+TimeAxisView::setup_sizes()
+{
+       name_width_px = ceilf (100.f * UIConfiguration::instance().get_ui_scale());
+}
 
 TimeAxisView::TimeAxisView (ARDOUR::Session* sess, PublicEditor& ed, TimeAxisView* rent, Canvas& /*canvas*/)
-       : AxisView (sess)
-       , controls_table (2, 8)
+       : controls_table (5, 4)
+       , controls_button_size_group (Gtk::SizeGroup::create (Gtk::SIZE_GROUP_BOTH))
        , _name_editing (false)
        , height (0)
        , display_menu (0)
        , parent (rent)
        , selection_group (0)
        , _ghost_group (0)
-       , _hidden (false)
+       , _hidden (true)
        , in_destructor (false)
        , _size_menu (0)
        , _canvas_display (0)
        , _y_position (0)
        , _editor (ed)
-       , name_entry (0)
        , control_parent (0)
        , _order (0)
        , _effective_height (0)
        , _resize_drag_start (-1)
+       , _did_resize (false)
        , _preresize_cursor (0)
        , _have_preresize_cursor (false)
        , _ebox_release_can_act (true)
 {
+       if (!controls_meters_size_group) {
+               controls_meters_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
+       }
+       if (!midi_scroomer_size_group) {
+               midi_scroomer_size_group = SizeGroup::create (SIZE_GROUP_HORIZONTAL);
+       }
        if (extra_height == 0) {
                compute_heights ();
        }
 
-       _canvas_display = new Group (ed.get_trackview_group (), ArdourCanvas::Duple (0.0, 0.0));
+       _canvas_display = new ArdourCanvas::Container (ed.get_trackview_group ());
        CANVAS_DEBUG_NAME (_canvas_display, "main for TAV");
        _canvas_display->hide(); // reveal as needed
 
-       selection_group = new Group (_canvas_display);
+       _canvas_separator = new ArdourCanvas::Line(_canvas_display);
+       CANVAS_DEBUG_NAME (_canvas_separator, "separator for TAV");
+       _canvas_separator->set (ArdourCanvas::Duple(0.0, 0.0), ArdourCanvas::Duple(ArdourCanvas::COORD_MAX, 0.0));
+       _canvas_separator->set_outline_color(ArdourCanvas::rgba_to_color (0, 0, 0, 1.0));
+       _canvas_separator->set_outline_width(1.0);
+       _canvas_separator->hide();
+
+       selection_group = new ArdourCanvas::Container (_canvas_display);
        CANVAS_DEBUG_NAME (selection_group, "selection for TAV");
        selection_group->set_data (X_("timeselection"), (void *) 1);
        selection_group->hide();
 
-       _ghost_group = new Group (_canvas_display);
+       _ghost_group = new ArdourCanvas::Container (_canvas_display);
        CANVAS_DEBUG_NAME (_ghost_group, "ghost for TAV");
        _ghost_group->lower_to_bottom();
        _ghost_group->show();
 
-       name_label.set_name ("TrackLabel");
+       name_label.set_name (X_("TrackNameEditor"));
        name_label.set_alignment (0.0, 0.5);
-       ARDOUR_UI::instance()->set_tip (name_label, _("Track/Bus name (double click to edit)"));
+       name_label.set_width_chars (12);
+       set_tooltip (name_label, _("Track/Bus name (double click to edit)"));
 
-       Gtk::Entry* an_entry = new Gtk::Entry;
-       Gtk::Requisition req;
-       an_entry->size_request (req);
-       name_label.set_size_request (-1, req.height);
-       delete an_entry;
+       {
+               std::auto_ptr<Gtk::Entry> an_entry (new Gtkmm2ext::FocusEntry);
+               an_entry->set_name (X_("TrackNameEditor"));
+               Gtk::Requisition req;
+               an_entry->size_request (req);
+
+               name_label.set_size_request (-1, req.height);
+               name_label.set_ellipsize (Pango::ELLIPSIZE_MIDDLE);
+       }
+
+       // set min. track-header width if fader is not visible
+       name_label.set_size_request(name_width_px, -1);
 
-       name_hbox.pack_start (name_label, true, true);
-       name_hbox.show ();
        name_label.show ();
-       
-       controls_table.set_size_request (200);
+
        controls_table.set_row_spacings (2);
        controls_table.set_col_spacings (2);
        controls_table.set_border_width (2);
-       controls_table.set_homogeneous (true);
 
-       controls_table.attach (name_hbox, 0, 5, 0, 1,  Gtk::FILL|Gtk::EXPAND,  Gtk::FILL|Gtk::EXPAND, 3, 0);
+       if (ARDOUR::Profile->get_mixbus() ) {
+               controls_table.attach (name_label, 4, 5, 0, 1,  Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK, 0, 0);
+       } else {
+               controls_table.attach (name_label, 1, 2, 0, 1,  Gtk::FILL|Gtk::EXPAND, Gtk::SHRINK, 0, 0);
+       }
+
        controls_table.show_all ();
        controls_table.set_no_show_all ();
 
-       HSeparator* separator = manage (new HSeparator());
-       separator->set_name("TrackSeparator");
-       separator->set_size_request(-1, 1);
-       separator->show();
-
        controls_vbox.pack_start (controls_table, false, false);
        controls_vbox.show ();
 
-       controls_hbox.pack_start (controls_vbox, true, true);
-       controls_hbox.show ();
+       top_hbox.pack_start (controls_vbox, true, true);
+       top_hbox.show ();
 
-       //controls_ebox.set_name ("TimeAxisViewControlsBaseUnselected");
-       controls_ebox.add (controls_hbox);
+       controls_ebox.add (time_axis_hbox);
        controls_ebox.add_events (Gdk::BUTTON_PRESS_MASK|
                                  Gdk::BUTTON_RELEASE_MASK|
                                  Gdk::POINTER_MOTION_MASK|
@@ -164,17 +198,33 @@ TimeAxisView::TimeAxisView (ARDOUR::Session* sess, PublicEditor& ed, TimeAxisVie
        controls_ebox.signal_leave_notify_event().connect (sigc::mem_fun (*this, &TimeAxisView::controls_ebox_leave));
        controls_ebox.show ();
 
-       time_axis_vbox.pack_start (controls_ebox, true, true, 0);
-       time_axis_vbox.pack_end (*separator, false, false);
-       time_axis_vbox.show();
+       time_axis_frame.set_shadow_type (Gtk::SHADOW_NONE);
+       time_axis_frame.add(top_hbox);
+       time_axis_frame.show();
+
+       HSeparator* separator = manage (new HSeparator());
+       separator->set_name("TrackSeparator");
+       separator->set_size_request(-1, 1);
+       separator->show();
 
-       ColorsChanged.connect (sigc::mem_fun (*this, &TimeAxisView::color_handler));
+       scroomer_placeholder.set_size_request (-1, -1);
+       scroomer_placeholder.show();
+       midi_scroomer_size_group->add_widget (scroomer_placeholder);
+
+       time_axis_vbox.pack_start (*separator, false, false);
+       time_axis_vbox.pack_start (time_axis_frame, true, true);
+       time_axis_vbox.show();
+       time_axis_hbox.pack_start (time_axis_vbox, true, true);
+       time_axis_hbox.show();
+       top_hbox.pack_start (scroomer_placeholder, false, false); // OR pack_end to move after meters ?
 
-       GhostRegion::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&TimeAxisView::erase_ghost, this, _1), gui_context());
+       UIConfiguration::instance().ColorsChanged.connect (sigc::mem_fun (*this, &TimeAxisView::color_handler));
 }
 
 TimeAxisView::~TimeAxisView()
 {
+       CatchDeletion (this);
+
        in_destructor = true;
 
        for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
@@ -182,16 +232,16 @@ TimeAxisView::~TimeAxisView()
        }
 
        for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
-               delete (*i)->rect;
-               delete (*i)->start_trim;
-               delete (*i)->end_trim;
+               delete (*i)->rect; (*i)->rect=0;
+               delete (*i)->start_trim; (*i)->start_trim = 0;
+               delete (*i)->end_trim; (*i)->end_trim = 0;
 
        }
 
        for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
-               delete (*i)->rect;
-               delete (*i)->start_trim;
-               delete (*i)->end_trim;
+               delete (*i)->rect; (*i)->rect = 0;
+               delete (*i)->start_trim; (*i)->start_trim = 0;
+               delete (*i)->end_trim; (*i)->end_trim = 0;
        }
 
        delete selection_group;
@@ -214,9 +264,10 @@ TimeAxisView::hide ()
        }
 
        _canvas_display->hide ();
+       _canvas_separator->hide ();
 
        if (control_parent) {
-               control_parent->remove (time_axis_vbox);
+               control_parent->remove (TOP_LEVEL_WIDGET);
                control_parent = 0;
        }
 
@@ -242,17 +293,18 @@ TimeAxisView::hide ()
 * @param y y position.
 * @param nth index for this TimeAxisView, increased if this view has children.
 * @param parent parent component.
+*
 * @return height of this TimeAxisView.
 */
 guint32
 TimeAxisView::show_at (double y, int& nth, VBox *parent)
 {
        if (control_parent) {
-               control_parent->reorder_child (time_axis_vbox, nth);
+               control_parent->reorder_child (TOP_LEVEL_WIDGET, nth);
        } else {
                control_parent = parent;
-               parent->pack_start (time_axis_vbox, false, false);
-               parent->reorder_child (time_axis_vbox, nth);
+               parent->pack_start (TOP_LEVEL_WIDGET, false, false);
+               parent->reorder_child (TOP_LEVEL_WIDGET, nth);
        }
 
        _order = nth;
@@ -260,7 +312,6 @@ TimeAxisView::show_at (double y, int& nth, VBox *parent)
        if (_y_position != y) {
                _canvas_display->set_y_position (y);
                _y_position = y;
-
        }
 
        _canvas_display->raise_to_top ();
@@ -281,12 +332,48 @@ TimeAxisView::show_at (double y, int& nth, VBox *parent)
                }
        }
 
+       /* put separator at the bottom of this time axis view */
+
+       _canvas_separator->set (ArdourCanvas::Duple(0, height), ArdourCanvas::Duple(ArdourCanvas::COORD_MAX, height));
+       _canvas_separator->lower_to_bottom ();
+       _canvas_separator->show ();
+
        return _effective_height;
 }
 
 bool
 TimeAxisView::controls_ebox_scroll (GdkEventScroll* ev)
 {
+       switch (ev->direction) {
+       case GDK_SCROLL_UP:
+               if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
+                       /* See Editor::_stepping_axis_view for notes on this hack */
+                       Editor& e = dynamic_cast<Editor&> (_editor);
+                       if (!e.stepping_axis_view ()) {
+                               e.set_stepping_axis_view (this);
+                       }
+                       e.stepping_axis_view()->step_height (false);
+                       return true;
+               }
+               break;
+
+       case GDK_SCROLL_DOWN:
+               if (Keyboard::modifier_state_equals (ev->state, Keyboard::ScrollZoomVerticalModifier)) {
+                       /* See Editor::_stepping_axis_view for notes on this hack */
+                       Editor& e = dynamic_cast<Editor&> (_editor);
+                       if (!e.stepping_axis_view ()) {
+                               e.set_stepping_axis_view (this);
+                       }
+                       e.stepping_axis_view()->step_height (true);
+                       return true;
+               }
+               break;
+
+       default:
+               /* no handling for left/right, yet */
+               break;
+       }
+
        /* Just forward to the normal canvas scroll method. The coordinate
           systems are different but since the canvas is always larger than the
           track headers, and aligned with the trackview area, this will work.
@@ -294,7 +381,7 @@ TimeAxisView::controls_ebox_scroll (GdkEventScroll* ev)
           In the not too distant future this layout is going away anyway and
           headers will be on the canvas.
        */
-       return _editor.canvas_scroll_event (ev);
+       return _editor.canvas_scroll_event (ev, false);
 }
 
 bool
@@ -317,7 +404,7 @@ TimeAxisView::controls_ebox_button_press (GdkEventButton* event)
        }
 
        _ebox_release_can_act = true;
-                       
+
        if (maybe_set_cursor (event->y) > 0) {
                _resize_drag_start = event->y_root;
        }
@@ -326,9 +413,9 @@ TimeAxisView::controls_ebox_button_press (GdkEventButton* event)
 }
 
 void
-TimeAxisView::idle_resize (uint32_t h)
+TimeAxisView::idle_resize (int32_t h)
 {
-       set_height (h);
+       set_height (std::max(0, h));
 }
 
 
@@ -341,15 +428,16 @@ TimeAxisView::controls_ebox_motion (GdkEventMotion* ev)
                 * are pretending that the drag is taking place over the canvas
                 * (which perhaps in the glorious future, when track headers
                 * and the canvas are unified, will actually be true.)
-               */
+                */
 
                _editor.maybe_autoscroll (false, true, true);
 
                /* now schedule the actual TAV resize */
-                int32_t const delta = (int32_t) floor (ev->y_root - _resize_drag_start);
-                _editor.add_to_idle_resize (this, delta);
-                _resize_drag_start = ev->y_root;
-        } else {
+               int32_t const delta = (int32_t) floor (ev->y_root - _resize_drag_start);
+               _editor.add_to_idle_resize (this, delta);
+               _resize_drag_start = ev->y_root;
+               _did_resize = true;
+       } else {
                /* not dragging but ... */
                maybe_set_cursor (ev->y);
        }
@@ -407,6 +495,11 @@ TimeAxisView::controls_ebox_button_release (GdkEventButton* ev)
                }
                _editor.stop_canvas_autoscroll ();
                _resize_drag_start = -1;
+               if (_did_resize) {
+                       _did_resize = false;
+                       // don't change selection
+                       return true;
+               }
        }
 
        if (!_ebox_release_can_act) {
@@ -415,7 +508,9 @@ TimeAxisView::controls_ebox_button_release (GdkEventButton* ev)
 
        switch (ev->button) {
        case 1:
-               selection_click (ev);
+               if (selectable()) {
+                       selection_click (ev);
+               }
                break;
 
        case 3:
@@ -474,13 +569,21 @@ TimeAxisView::set_height_enum (Height h, bool apply_to_selection)
 }
 
 void
-TimeAxisView::set_height (uint32_t h)
+TimeAxisView::set_height (uint32_t h, TrackHeightMode m)
 {
+       uint32_t lanes = 0;
+       if (m == TotalHeight) {
+               for (Children::iterator i = children.begin(); i != children.end(); ++i) {
+                       if ( !(*i)->hidden()) ++lanes;
+               }
+       }
+       h /= (lanes + 1);
+
        if (h < preset_height (HeightSmall)) {
                h = preset_height (HeightSmall);
        }
 
-       time_axis_vbox.property_height_request () = h;
+       TOP_LEVEL_WIDGET.property_height_request () = h;
        height = h;
 
        char buf[32];
@@ -496,194 +599,117 @@ TimeAxisView::set_height (uint32_t h)
                show_selection (_editor.get_selection().time);
        }
 
-       _editor.override_visible_track_count ();
-}
-
-bool
-TimeAxisView::name_entry_key_press (GdkEventKey* ev)
-{
-       /* steal escape, tabs from GTK */
-
-       switch (ev->keyval) {
-       case GDK_Escape:
-       case GDK_ISO_Left_Tab:
-       case GDK_Tab:
-               return true;
-       }
-       return false;
-}
-
-bool
-TimeAxisView::name_entry_key_release (GdkEventKey* ev)
-{
-       TrackViewList::iterator i;
-
-       switch (ev->keyval) {
-       case GDK_Escape:
-               end_name_edit (RESPONSE_CANCEL);
-               return true;
-
-       /* Shift+Tab Keys Pressed. Note that for Shift+Tab, GDK actually
-        * generates a different ev->keyval, rather than setting
-        * ev->state.
-        */
-       case GDK_ISO_Left_Tab:
-               end_name_edit (RESPONSE_APPLY);
-               return true;
-
-       case GDK_Tab:
-               end_name_edit (RESPONSE_ACCEPT);
-               return true;
-       default:
-               break;
+       if (m != OnlySelf) {
+               for (Children::iterator i = children.begin(); i != children.end(); ++i) {
+                       (*i)->set_height(h, OnlySelf);
+               }
        }
 
-       return false;
-}
-
-bool
-TimeAxisView::name_entry_focus_out (GdkEventFocus*)
-{
-       end_name_edit (RESPONSE_OK);
-       return false;
+       _editor.override_visible_track_count ();
 }
 
 void
 TimeAxisView::begin_name_edit ()
 {
-       if (name_entry) {
+       if (!can_edit_name()) {
                return;
        }
 
-       if (can_edit_name()) {
+       Gtk::Window* toplevel = (Gtk::Window*) control_parent->get_toplevel();
+       FloatingTextEntry* fte = new FloatingTextEntry (toplevel, name_label.get_text ());
 
-               name_entry = manage (new Gtkmm2ext::FocusEntry);
-               
-               name_entry->set_name ("EditorTrackNameDisplay");
-               name_entry->signal_key_press_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_press), false);
-               name_entry->signal_key_release_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_key_release), false);
-               name_entry->signal_focus_out_event().connect (sigc::mem_fun (*this, &TimeAxisView::name_entry_focus_out));
-               name_entry->set_text (name_label.get_text());
-               name_entry->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &TimeAxisView::end_name_edit), RESPONSE_OK));
+       fte->set_name ("TrackNameEditor");
+       fte->use_text.connect (sigc::mem_fun (*this, &TimeAxisView::end_name_edit));
 
-               if (name_label.is_ancestor (name_hbox)) {
-                       name_hbox.remove (name_label);
-               }
-               
-               name_hbox.pack_start (*name_entry);
-               name_entry->show ();
+       /* We want to new toplevel window to overlay the name label, so
+        * translate the coordinates of the upper left corner of the name label
+        * into the coordinate space of the top level window.
+        */
 
-               name_entry->select_region (0, -1);
-               name_entry->set_state (STATE_SELECTED);
-               name_entry->grab_focus ();
-               name_entry->start_editing (0);
-       }
+       int x, y;
+        int wx, wy;
+
+        name_label.translate_coordinates (*toplevel, 0, 0, x, y);
+        toplevel->get_window()->get_origin (wx, wy);
+
+        fte->move (wx + x, wy + y);
+       fte->present ();
 }
 
 void
-TimeAxisView::end_name_edit (int response)
+TimeAxisView::end_name_edit (std::string str, int next_dir)
 {
-       if (!name_entry) {
-               return;
-       }
-       
-       bool edit_next = false;
-       bool edit_prev = false;
-
-       switch (response) {
-       case RESPONSE_CANCEL:
-               break;
-       case RESPONSE_OK:
-               name_entry_changed ();
-               break;
-       case RESPONSE_ACCEPT:
-               name_entry_changed ();
-               edit_next = true;
-       case RESPONSE_APPLY:
-               name_entry_changed ();
-               edit_prev = true;
+       if (!name_entry_changed (str)) {
+               next_dir = 0;
        }
 
-       /* this will delete the name_entry. but it will also drop focus, which
-        * will cause another callback to this function, so set name_entry = 0
-        * first to ensure we don't double-remove etc. etc.
-        */
-
-       Gtk::Entry* tmp = name_entry;
-       name_entry = 0;
-       name_hbox.remove (*tmp);
-
-       /* put the name label back */
-
-       name_hbox.pack_start (name_label);
-       name_label.show ();
-
-       if (edit_next) {
+       if (next_dir > 0) {
 
                TrackViewList const & allviews = _editor.get_track_views ();
                TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
-               
+
                if (i != allviews.end()) {
-                       
+
                        do {
                                if (++i == allviews.end()) {
                                        return;
                                }
-                               
+
                                RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
-                       
-                               if (rtav && rtav->route()->record_enabled()) {
+
+                               if (rtav && (!rtav->is_track() || rtav->track()->rec_enable_control()->get_value())) {
                                        continue;
                                }
-                               
+
                                if (!(*i)->hidden()) {
                                        break;
                                }
-                               
+
                        } while (true);
                }
 
                if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
-                       _editor.ensure_time_axis_view_is_visible (**i);
+                       _editor.ensure_time_axis_view_is_visible (**i, false);
                        (*i)->begin_name_edit ();
-               } 
+               }
 
-       } else if (edit_prev) {
+       } else if (next_dir < 0) {
 
                TrackViewList const & allviews = _editor.get_track_views ();
                TrackViewList::const_iterator i = find (allviews.begin(), allviews.end(), this);
-               
+
                if (i != allviews.begin()) {
                        do {
                                if (i == allviews.begin()) {
                                        return;
                                }
-                               
+
                                --i;
-                               
+
                                RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*>(*i);
-                               
-                               if (rtav && rtav->route()->record_enabled()) {
+
+                               if (rtav && (!rtav->is_track() || rtav->track()->rec_enable_control()->get_value())) {
                                        continue;
                                }
-                               
+
                                if (!(*i)->hidden()) {
                                        break;
                                }
-                               
+
                        } while (true);
                }
-               
+
                if ((i != allviews.end()) && (*i != this) && !(*i)->hidden()) {
-                       _editor.ensure_time_axis_view_is_visible (**i);
+                       _editor.ensure_time_axis_view_is_visible (**i, false);
                        (*i)->begin_name_edit ();
-               } 
+               }
        }
 }
 
-void
-TimeAxisView::name_entry_changed ()
+bool
+TimeAxisView::name_entry_changed (string const&)
 {
+       return true;
 }
 
 bool
@@ -695,6 +721,10 @@ TimeAxisView::can_edit_name () const
 void
 TimeAxisView::conditionally_add_to_selection ()
 {
+       if (!selectable()) {
+               return;
+       }
+
        Selection& s (_editor.get_selection ());
 
        if (!s.selected (this)) {
@@ -708,26 +738,34 @@ TimeAxisView::popup_display_menu (guint32 when)
        conditionally_add_to_selection ();
 
        build_display_menu ();
-       display_menu->popup (1, when);
+
+       if (!display_menu->items().empty()) {
+               display_menu->popup (1, when);
+       }
 }
 
 void
 TimeAxisView::set_selected (bool yn)
 {
-       if (yn == _selected) {
+       if (yn == selected()) {
                return;
        }
 
        Selectable::set_selected (yn);
 
        if (_selected) {
+               time_axis_frame.set_shadow_type (Gtk::SHADOW_IN);
+               time_axis_frame.set_name ("MixerStripSelectedFrame");
                controls_ebox.set_name (controls_base_selected_name);
-               time_axis_vbox.set_name (controls_base_selected_name);
                controls_vbox.set_name (controls_base_selected_name);
+               time_axis_vbox.set_name (controls_base_selected_name);
        } else {
+               time_axis_frame.set_shadow_type (Gtk::SHADOW_NONE);
+               time_axis_frame.set_name (controls_base_unselected_name);
                controls_ebox.set_name (controls_base_unselected_name);
-               time_axis_vbox.set_name (controls_base_unselected_name);
                controls_vbox.set_name (controls_base_unselected_name);
+               time_axis_vbox.set_name (controls_base_unselected_name);
+
                hide_selection ();
 
                /* children will be set for the yn=true case. but when deselecting
@@ -739,6 +777,9 @@ TimeAxisView::set_selected (bool yn)
                        (*i)->set_selected (false);
                }
        }
+
+       time_axis_frame.show();
+
 }
 
 void
@@ -784,7 +825,8 @@ TimeAxisView::show_selection (TimeSelection& ts)
        double x1;
        double x2;
        double y2;
-       SelectionRect *rect;
+       SelectionRect *rect;    time_axis_frame.show();
+
 
        for (Children::iterator i = children.begin(); i != children.end(); ++i) {
                (*i)->show_selection (ts);
@@ -816,14 +858,14 @@ TimeAxisView::show_selection (TimeSelection& ts)
 
                x1 = _editor.sample_to_pixel (start);
                x2 = _editor.sample_to_pixel (start + cnt - 1);
-               y2 = current_height();
+               y2 = current_height() - 1;
 
-               rect->rect->set (ArdourCanvas::Rect (x1, 1, x2, y2));
+               rect->rect->set (ArdourCanvas::Rect (x1, 0, x2, y2));
 
                // trim boxes are at the top for selections
 
                if (x2 > x1) {
-                       rect->start_trim->set (ArdourCanvas::Rect (x1, 1, x1 + trim_handle_size, y2));
+                       rect->start_trim->set (ArdourCanvas::Rect (x1, 0, x1 + trim_handle_size, y2));
                        rect->end_trim->set (ArdourCanvas::Rect (x2 - trim_handle_size, 1, x2, y2));
 
                        rect->start_trim->show();
@@ -890,6 +932,8 @@ TimeAxisView::order_selection_trims (ArdourCanvas::Item *item, bool put_start_on
        }
 }
 
+// retuned rect is pushed back into the used_selection_rects list
+// in TimeAxisView::show_selection() which is the only caller.
 SelectionRect *
 TimeAxisView::get_selection_rect (uint32_t id)
 {
@@ -899,7 +943,9 @@ TimeAxisView::get_selection_rect (uint32_t id)
 
        for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
                if ((*i)->id == id) {
-                       return (*i);
+                       SelectionRect* ret = (*i);
+                       used_selection_rects.erase (i);
+                       return ret;
                }
        }
 
@@ -922,15 +968,15 @@ TimeAxisView::get_selection_rect (uint32_t id)
                rect->rect = new ArdourCanvas::Rectangle (selection_group);
                CANVAS_DEBUG_NAME (rect->rect, "selection rect");
                rect->rect->set_outline (false);
-               rect->rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectionRect());
+               rect->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
 
                rect->start_trim = new ArdourCanvas::Rectangle (selection_group);
-               CANVAS_DEBUG_NAME (rect->rect, "selection rect start trim");
+               CANVAS_DEBUG_NAME (rect->start_trim, "selection rect start trim");
                rect->start_trim->set_outline (false);
                rect->start_trim->set_fill (false);
 
                rect->end_trim = new ArdourCanvas::Rectangle (selection_group);
-               CANVAS_DEBUG_NAME (rect->rect, "selection rect end trim");
+               CANVAS_DEBUG_NAME (rect->end_trim, "selection rect end trim");
                rect->end_trim->set_outline (false);
                rect->end_trim->set_fill (false);
 
@@ -979,7 +1025,7 @@ TimeAxisView::remove_child (boost::shared_ptr<TimeAxisView> child)
  *  @param result Filled in with selectable things.
  */
 void
-TimeAxisView::get_selectables (framepos_t /*start*/, framepos_t /*end*/, double /*top*/, double /*bot*/, list<Selectable*>& /*result*/)
+TimeAxisView::get_selectables (framepos_t /*start*/, framepos_t /*end*/, double /*top*/, double /*bot*/, list<Selectable*>& /*result*/, bool /*within*/)
 {
        return;
 }
@@ -1054,38 +1100,27 @@ TimeAxisView::reset_height ()
 void
 TimeAxisView::compute_heights ()
 {
+       // TODO this function should be re-evaluated when font-scaling changes (!)
        Gtk::Window window (Gtk::WINDOW_TOPLEVEL);
-       Gtk::Table two_row_table (2, 8);
-       Gtk::Table one_row_table (1, 8);
-       Button* buttons[5];
+       Gtk::Table one_row_table (1, 1);
+       ArdourButton* test_button = manage (new ArdourButton);
        const int border_width = 2;
-
-       const int separator_height = 2;
-       extra_height = (2 * border_width) + separator_height;
+       const int frame_height = 2;
+       extra_height = (2 * border_width) + frame_height;
 
        window.add (one_row_table);
+       test_button->set_name ("mute button");
+       test_button->set_text (S_("Mute|M"));
+       test_button->set_tweaks (ArdourButton::TrackHeader);
 
        one_row_table.set_border_width (border_width);
-       one_row_table.set_row_spacings (0);
-       one_row_table.set_col_spacings (0);
-       one_row_table.set_homogeneous (true);
-
-       two_row_table.set_border_width (border_width);
-       two_row_table.set_row_spacings (0);
-       two_row_table.set_col_spacings (0);
-       two_row_table.set_homogeneous (true);
-
-       for (int i = 0; i < 5; ++i) {
-               buttons[i] = manage (new Button (X_("f")));
-               buttons[i]->set_name ("TrackMuteButton");
-       }
-
-       one_row_table.attach (*buttons[0], 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
+       one_row_table.set_row_spacings (2);
+       one_row_table.set_col_spacings (2);
 
+       one_row_table.attach (*test_button, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK, 0, 0);
        one_row_table.show_all ();
-       Gtk::Requisition req(one_row_table.size_request ());
 
-       // height required to show 1 row of buttons
+       Gtk::Requisition req(one_row_table.size_request ());
        button_height = req.height;
 }
 
@@ -1098,26 +1133,26 @@ TimeAxisView::color_handler ()
 
        for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
 
-               (*i)->rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectionRect());
-               (*i)->rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_Selection());
+               (*i)->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
+               (*i)->rect->set_outline_color (UIConfiguration::instance().color ("selection"));
+
+               (*i)->start_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
+               (*i)->start_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
 
-               (*i)->start_trim->set_fill_color (ARDOUR_UI::config()->get_canvasvar_Selection());
-               (*i)->start_trim->set_outline_color (ARDOUR_UI::config()->get_canvasvar_Selection());
-               
-               (*i)->end_trim->set_fill_color (ARDOUR_UI::config()->get_canvasvar_Selection());
-               (*i)->end_trim->set_outline_color (ARDOUR_UI::config()->get_canvasvar_Selection());
+               (*i)->end_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
+               (*i)->end_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
        }
-       
+
        for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
-               
-               (*i)->rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_SelectionRect());
-               (*i)->rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_Selection());
-               
-               (*i)->start_trim->set_fill_color (ARDOUR_UI::config()->get_canvasvar_Selection());
-               (*i)->start_trim->set_outline_color (ARDOUR_UI::config()->get_canvasvar_Selection());
-               
-               (*i)->end_trim->set_fill_color (ARDOUR_UI::config()->get_canvasvar_Selection());
-               (*i)->end_trim->set_outline_color (ARDOUR_UI::config()->get_canvasvar_Selection());
+
+               (*i)->rect->set_fill_color (UIConfiguration::instance().color_mod ("selection rect", "selection rect"));
+               (*i)->rect->set_outline_color (UIConfiguration::instance().color ("selection"));
+
+               (*i)->start_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
+               (*i)->start_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
+
+               (*i)->end_trim->set_fill_color (UIConfiguration::instance().color ("selection"));
+               (*i)->end_trim->set_outline_color (UIConfiguration::instance().color ("selection"));
        }
 }
 
@@ -1191,7 +1226,7 @@ TimeAxisView::covered_by_y_range (double y0, double y1) const
        /* if either the top or bottom of the axisview is in the vertical
         * range, we cover it.
         */
-       
+
        if ((y0 < _y_position && y1 < _y_position) ||
            (y0 >= _y_position + height && y1 >= _y_position + height)) {
                return false;
@@ -1222,7 +1257,7 @@ TimeAxisView::preset_height (Height h)
                return button_height + extra_height;
        }
 
-       /* NOTREACHED */
+       abort(); /* NOTREACHED */
        return 0;
 }
 
@@ -1269,7 +1304,7 @@ TimeAxisView::reset_visual_state ()
        /* this method is not required to trigger a global redraw */
 
        string str = gui_property ("height");
-       
+
        if (!str.empty()) {
                set_height (atoi (str));
        } else {