Merging from trunk
[ardour.git] / gtk2_ardour / time_axis_view.cc
index bee45147afca285828df78985ebfb14da59c66f4..b5ab5baa1098a6868cacc0ffda3ef24dc2558400 100644 (file)
 #include <string>
 #include <list>
 
+#include <libgnomecanvasmm.h>
+#include <libgnomecanvasmm/canvas.h>
+#include <libgnomecanvasmm/item.h>
+
 #include <pbd/error.h>
 
 #include <gtkmm2ext/utils.h>
 #include "ardour_ui.h"
 #include "public_editor.h"
 #include "time_axis_view.h"
-#include "canvas-simplerect.h"
+#include "simplerect.h"
 #include "selection.h"
 #include "keyboard.h"
 #include "rgb_macros.h"
+#include "utils.h"
 
 #include "i18n.h"
 
 using namespace Gtk;
-/*can't use sigc namespace while we have the compose() in libs/pbd3/pbd */
-//using namespace sigc; 
+using namespace Gdk;
+using namespace sigc; 
 using namespace ARDOUR;
+using namespace PBD;
 using namespace Editing;
+using namespace ArdourCanvas;
 
 const double trim_handle_size = 6.0; /* pixels */
 
-TimeAxisView::TimeAxisView(ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView* rent, Gtk::Widget *canvas) 
-       : AxisView(sess), 
-         editor(ed),
-         controls_table (2, 9)
-{
-       canvas_display = gnome_canvas_item_new (gnome_canvas_root(GNOME_CANVAS(canvas->gobj())),
-                                             gnome_canvas_group_get_type(),
-                                             "x", 0.0,
-                                             "y", 0.0,
-                                             NULL);
-
-       selection_group = gnome_canvas_item_new (GNOME_CANVAS_GROUP(canvas_display), 
-                                              gnome_canvas_group_get_type (), 
-                                              NULL);
-       gnome_canvas_item_hide (selection_group);
+uint32_t TimeAxisView::hLargest = 0;
+uint32_t TimeAxisView::hLarge = 0;
+uint32_t TimeAxisView::hLarger = 0;
+uint32_t TimeAxisView::hNormal = 0;
+uint32_t TimeAxisView::hSmaller = 0;
+uint32_t TimeAxisView::hSmall = 0;
+bool TimeAxisView::need_size_info = true;
+
+TimeAxisView::TimeAxisView (ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView* rent, Canvas& canvas) 
+       : AxisView (sess), 
+         editor (ed),
+         controls_table (2, 8)
+{
+       if (need_size_info) {
+               compute_controls_size_info ();
+               need_size_info = false;
+       }
+
+       canvas_display = new Group (*canvas.root(), 0.0, 0.0);
+       
+       selection_group = new Group (*canvas_display);
+       selection_group->hide();
        
        control_parent = 0;
        display_menu = 0;
@@ -79,6 +93,8 @@ TimeAxisView::TimeAxisView(ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView
        effective_height = 0;
        parent = rent;
        _has_state = false;
+       last_name_entry_key_press_event = 0;
+       name_packing = NamePackingBits (0);
 
        /*
          Create the standard LHS Controls
@@ -89,47 +105,41 @@ TimeAxisView::TimeAxisView(ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView
        name_entry.set_name ("EditorTrackNameDisplay");
        name_entry.signal_button_release_event().connect (mem_fun (*this, &TimeAxisView::name_entry_button_release));
        name_entry.signal_button_press_event().connect (mem_fun (*this, &TimeAxisView::name_entry_button_press));
-       
-       name_entry.signal_focus_in_event().connect (sigc::ptr_fun (ARDOUR_UI::generic_focus_in_event));
-       name_entry.signal_focus_out_event().connect (sigc::ptr_fun (ARDOUR_UI::generic_focus_out_event));
-
+       name_entry.signal_key_release_event().connect (mem_fun (*this, &TimeAxisView::name_entry_key_release));
+       name_entry.signal_activate().connect (mem_fun(*this, &TimeAxisView::name_entry_activated));
+       name_entry.signal_focus_in_event().connect (mem_fun (*this, &TimeAxisView::name_entry_focus_in));
+       name_entry.signal_focus_out_event().connect (mem_fun (*this, &TimeAxisView::name_entry_focus_out));
        Gtkmm2ext::set_size_request_to_display_given_text (name_entry, N_("gTortnam"), 10, 10); // just represents a short name
 
        name_label.set_name ("TrackLabel");
        name_label.set_alignment (0.0, 0.5);
 
-       // name_hbox.set_border_width (2);
-       // name_hbox.set_spacing (5);
-
        /* typically, either name_label OR name_entry are visible,
           but not both. its up to derived classes to show/hide them as they
           wish.
        */
 
-       name_hbox.pack_start (name_label, true, true);
-       name_hbox.pack_start (name_entry, true, true);
        name_hbox.show ();
 
        controls_table.set_border_width (2);
        controls_table.set_row_spacings (0);
        controls_table.set_col_spacings (0);
        controls_table.set_homogeneous (true);
-       controls_table.show ();
-
-       controls_table.attach (name_hbox, 0, 5, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
 
-       controls_table.show ();
+       controls_table.attach (name_hbox, 0, 4, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND);
+       controls_table.show_all ();
 
        controls_vbox.pack_start (controls_table, false, false);
        controls_vbox.show ();
 
        controls_ebox.set_name ("TimeAxisViewControlsBaseUnselected");
        controls_ebox.add (controls_vbox);
-       controls_ebox.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
-       controls_ebox.set_flags (Gtk::CAN_FOCUS);
+       controls_ebox.add_events (BUTTON_PRESS_MASK|BUTTON_RELEASE_MASK|SCROLL_MASK);
+       controls_ebox.set_flags (CAN_FOCUS);
 
        controls_ebox.signal_button_release_event().connect (mem_fun (*this, &TimeAxisView::controls_ebox_button_release));
-       
+       controls_ebox.signal_scroll_event().connect (mem_fun (*this, &TimeAxisView::controls_ebox_scroll), true);
+
        controls_lhs_pad.set_name ("TimeAxisViewControlsPadding");
        controls_hbox.pack_start (controls_lhs_pad,false,false);
        controls_hbox.pack_start (controls_ebox,true,true);
@@ -138,6 +148,8 @@ TimeAxisView::TimeAxisView(ARDOUR::Session& sess, PublicEditor& ed, TimeAxisView
        controls_frame.add (controls_hbox);
        controls_frame.set_name ("TimeAxisViewControlsBaseUnselected");
        controls_frame.set_shadow_type (Gtk::SHADOW_OUT);
+
+       ColorChanged.connect (mem_fun (*this, &TimeAxisView::color_handler));
 }
 
 TimeAxisView::~TimeAxisView()
@@ -147,24 +159,25 @@ TimeAxisView::~TimeAxisView()
        }
 
        for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
-               gtk_object_destroy (GTK_OBJECT((*i)->rect));
-               gtk_object_destroy (GTK_OBJECT((*i)->start_trim));
-               gtk_object_destroy (GTK_OBJECT((*i)->end_trim));
+               delete (*i)->rect;
+               delete (*i)->start_trim;
+               delete (*i)->end_trim;
+
        }
 
        for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
-               gtk_object_destroy (GTK_OBJECT((*i)->rect));
-               gtk_object_destroy (GTK_OBJECT((*i)->start_trim));
-               gtk_object_destroy (GTK_OBJECT((*i)->end_trim));
+               delete (*i)->rect;
+               delete (*i)->start_trim;
+               delete (*i)->end_trim;
        }
 
        if (selection_group) {
-               gtk_object_destroy (GTK_OBJECT (selection_group));
+               delete selection_group;
                selection_group = 0;
        }
 
        if (canvas_display) {
-               gtk_object_destroy (GTK_OBJECT (canvas_display));       
+               delete canvas_display;
                canvas_display = 0;
        }
 
@@ -172,11 +185,6 @@ TimeAxisView::~TimeAxisView()
                delete display_menu;
                display_menu = 0;
        }
-
-       if (size_menu) {
-               delete size_menu;
-               size_menu = 0;
-       }
 }
 
 guint32
@@ -184,7 +192,7 @@ TimeAxisView::show_at (double y, int& nth, VBox *parent)
 {
        gdouble ix1, ix2, iy1, iy2;
        effective_height = 0;
-
+       
        if (control_parent) {
                control_parent->reorder_child (controls_frame, nth);
        } else {
@@ -192,22 +200,23 @@ TimeAxisView::show_at (double y, int& nth, VBox *parent)
                parent->pack_start (controls_frame, false, false);
                parent->reorder_child (controls_frame, nth);
        }
-
        controls_frame.show ();
        controls_ebox.show ();
-
+       
        /* the coordinates used here are in the system of the
           item's parent ...
        */
 
-       gnome_canvas_item_get_bounds (canvas_display, &ix1, &iy1, &ix2, &iy2);
-       gnome_canvas_item_i2w (canvas_display->parent, &ix1, &iy1);
+       canvas_display->get_bounds (ix1, iy1, ix2, iy2);
+       Group* pg = canvas_display->property_parent();
+       pg->i2w (ix1, iy1);
+
        if (iy1 < 0) {
                iy1 = 0;
        }
-       gnome_canvas_item_move (canvas_display, 0.0, y - iy1);
-       gnome_canvas_item_show (canvas_display); /* XXX not necessary */
 
+       canvas_display->move (0.0, y - iy1);
+       canvas_display->show();/* XXX not necessary */
        y_position = y;
        order = nth;
        _hidden = false;
@@ -219,10 +228,10 @@ TimeAxisView::show_at (double y, int& nth, VBox *parent)
        for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
                
                if ((*i)->marked_for_display()) {
-                       gnome_canvas_item_show ((*i)->canvas_display);
+                       (*i)->canvas_display->show();
                }
                
-               if (GTK_OBJECT_FLAGS(GTK_OBJECT((*i)->canvas_display)) & GNOME_CANVAS_ITEM_VISIBLE) {
+               if (canvas_item_visible ((*i)->canvas_display)) {
                        ++nth;
                        effective_height += (*i)->show_at (y + effective_height, nth, parent);
                }
@@ -231,7 +240,33 @@ TimeAxisView::show_at (double y, int& nth, VBox *parent)
        return effective_height;
 }
 
-gint
+bool
+TimeAxisView::controls_ebox_scroll (GdkEventScroll* ev)
+{
+       switch (ev->direction) {
+       case GDK_SCROLL_UP:
+               if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) {
+                       step_height (true);
+                       return true;
+               }
+               break;
+               
+       case GDK_SCROLL_DOWN:
+               if (Keyboard::modifier_state_equals (ev->state, Keyboard::Shift)) {
+                       step_height (false);
+                       return true;
+               }
+               break;
+
+       default:
+               /* no handling for left/right, yet */
+               break;
+       }
+
+       return false;
+}
+
+bool
 TimeAxisView::controls_ebox_button_release (GdkEventButton* ev)
 {
        switch (ev->button) {
@@ -242,27 +277,9 @@ TimeAxisView::controls_ebox_button_release (GdkEventButton* ev)
        case 3:
                popup_display_menu (ev->time);
                break;
-
-       case 4:
-               if (Keyboard::no_modifier_keys_pressed (ev)) {
-                       editor.scroll_tracks_up_line ();
-               } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
-                       step_height (true);
-               }
-               break;
-
-       case 5:
-               if (Keyboard::no_modifier_keys_pressed (ev)) {
-                       editor.scroll_tracks_down_line ();
-               } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::Control)) {
-                       step_height (false);
-               }
-               break;
-               
-
        }
 
-       return TRUE;
+       return true;
 }
 
 void
@@ -289,7 +306,7 @@ TimeAxisView::hide ()
                return;
        }
 
-       gnome_canvas_item_hide (canvas_display);
+       canvas_display->hide();
        controls_frame.hide ();
 
        if (control_parent) {
@@ -312,68 +329,153 @@ TimeAxisView::hide ()
 void
 TimeAxisView::step_height (bool bigger)
 {
-       switch (height) {
-       case Largest:
-               if (!bigger) set_height (Large);
-               break;
-       case Large:
-               if (bigger) set_height (Largest);
-               else set_height (Larger);
-               break;
-       case Larger:
-               if (bigger) set_height (Large);
-               else set_height (Normal);
-               break;
-       case Normal:
-               if (bigger) set_height (Larger);
-               else set_height (Smaller);
-               break;
-       case Smaller:
-               if (bigger) set_height (Normal);
-               else set_height (Small);
-               break;
-       case Small:
-               if (bigger) set_height (Smaller);
-               break;
-       }
+  
+       if (height == hLargest) {
+               if (!bigger) set_height (Large);
+               return;
+       }
+       if (height == hLarge) {
+               if (bigger) set_height (Largest);
+                else set_height (Larger);
+               return;
+       }
+       if (height == hLarger) {
+                if (bigger) set_height (Large);
+                else set_height (Normal);
+               return;
+       }
+       if (height == hNormal) {
+                if (bigger) set_height (Larger);
+                else set_height (Smaller);
+               return;
+       }
+       if (height == hSmaller) {
+                if (bigger) set_height (Normal);
+                else set_height (Small);
+               return;
+       }
+       if (height == hSmall) {
+                if (bigger) set_height (Smaller);
+               return;
+       }
 }
 
-
 void
 TimeAxisView::set_height (TrackHeight h)
 {
-       height = (guint32) h;
+       height_style = h;
+       set_height_pixels (height_to_pixels (h));
+}
+
+void
+TimeAxisView::set_height_pixels (uint32_t h)
+{
+       height = h;
        controls_frame.set_size_request (-1, height);
 
-       if (GTK_OBJECT_FLAGS(GTK_OBJECT(selection_group)) & GNOME_CANVAS_ITEM_VISIBLE) {
+       if (canvas_item_visible (selection_group)) {
                /* resize the selection rect */
                show_selection (editor.get_selection().time);
        }
+}
+
+bool
+TimeAxisView::name_entry_key_release (GdkEventKey* ev)
+{
+       switch (ev->keyval) {
+       case GDK_Tab:
+       case GDK_Up:
+       case GDK_Down:
+               name_entry_changed ();
+               return true;
+
+       default:
+               break;
+       }
+
+#ifdef TIMEOUT_NAME_EDIT       
+       /* adapt the timeout to reflect the user's typing speed */
+
+       guint32 name_entry_timeout;
+
+       if (last_name_entry_key_press_event) {
+               /* timeout is 1/2 second or 5 times their current inter-char typing speed */
+               name_entry_timeout = std::max (500U, (5 * (ev->time - last_name_entry_key_press_event)));
+       } else {
+               /* start with a 1 second timeout */
+               name_entry_timeout = 1000;
+       }
+
+       last_name_entry_key_press_event = ev->time;
+
+       /* wait 1 seconds and if no more keys are pressed, act as if they pressed enter */
 
-//     for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
-//             (*i)->set_height (h);
-//     }
+       name_entry_key_timeout.disconnect();
+       name_entry_key_timeout = Glib::signal_timeout().connect (mem_fun (*this, &TimeAxisView::name_entry_key_timed_out), name_entry_timeout);
+#endif
 
+       return false;
 }
 
+bool
+TimeAxisView::name_entry_focus_in (GdkEventFocus* ev)
+{
+       name_entry.select_region (0, -1);
+       name_entry.set_name ("EditorActiveTrackNameDisplay");
+       return false;
+}
 
-gint
+bool
+TimeAxisView::name_entry_focus_out (GdkEventFocus* ev)
+{
+       /* clean up */
+
+       last_name_entry_key_press_event = 0;
+       name_entry_key_timeout.disconnect ();
+       name_entry.set_name ("EditorTrackNameDisplay");
+       
+       /* do the real stuff */
+
+       name_entry_changed ();
+
+       return false;
+}
+
+bool
+TimeAxisView::name_entry_key_timed_out ()
+{
+       name_entry_activated();
+       return false;
+}
+
+void
+TimeAxisView::name_entry_activated ()
+{
+       controls_ebox.grab_focus();
+}
+
+void
+TimeAxisView::name_entry_changed ()
+{
+}
+
+bool
 TimeAxisView::name_entry_button_press (GdkEventButton *ev)
 {
        if (ev->button == 3) {
-               return do_not_propagate (ev);
+               return true;
        }
-       return FALSE;
+       return false;
 }
 
-gint
+bool
 TimeAxisView::name_entry_button_release (GdkEventButton *ev)
 {
        if (ev->button == 3) {
                popup_display_menu (ev->time);
-               return stop_signal (name_entry, "button_release_event");
+               return true;
        }
-       return FALSE;
+       return false;
 }
 
 void
@@ -448,7 +550,7 @@ TimeAxisView::build_size_menu ()
        items.push_back (MenuElem (_("Large"), bind (mem_fun (*this, &TimeAxisView::set_height), Large)));
        items.push_back (MenuElem (_("Larger"), bind (mem_fun (*this, &TimeAxisView::set_height), Larger)));
        items.push_back (MenuElem (_("Normal"), bind (mem_fun (*this, &TimeAxisView::set_height), Normal)));
-       items.push_back (MenuElem (_("Smaller"), bind (mem_fun (*this, &TimeAxisView::set_height), Smaller)));
+       items.push_back (MenuElem (_("Smaller"), bind (mem_fun (*this, &TimeAxisView::set_height),Smaller)));
        items.push_back (MenuElem (_("Small"), bind (mem_fun (*this, &TimeAxisView::set_height), Small)));
 }
 
@@ -499,19 +601,19 @@ TimeAxisView::show_selection (TimeSelection& ts)
                (*i)->show_selection (ts);
        }
 
-       if (GTK_OBJECT_FLAGS(GTK_OBJECT(selection_group)) & GNOME_CANVAS_ITEM_VISIBLE) {
+       if (canvas_item_visible (selection_group)) {
                while (!used_selection_rects.empty()) {
                        free_selection_rects.push_front (used_selection_rects.front());
                        used_selection_rects.pop_front();
-                       gnome_canvas_item_hide (free_selection_rects.front()->rect);
-                       gnome_canvas_item_hide (free_selection_rects.front()->start_trim);
-                       gnome_canvas_item_hide (free_selection_rects.front()->end_trim);
+                       free_selection_rects.front()->rect->hide();
+                       free_selection_rects.front()->start_trim->hide();
+                       free_selection_rects.front()->end_trim->hide();
                }
-               gnome_canvas_item_hide (selection_group);
+               selection_group->hide();
        }
 
-       gnome_canvas_item_show (selection_group);
-       gnome_canvas_item_raise_to_top (selection_group);
+       selection_group->show();
+       selection_group->raise_to_top();
        
        for (list<AudioRange>::iterator i = ts.begin(); i != ts.end(); ++i) {
                jack_nframes_t start, end, cnt;
@@ -522,40 +624,36 @@ TimeAxisView::show_selection (TimeSelection& ts)
 
                rect = get_selection_rect ((*i).id);
                
-               x1 = start / editor.get_current_zoom();
-               x2 = (start + cnt - 1) / editor.get_current_zoom();
+               x1 = editor.frame_to_unit (start);
+               x2 = editor.frame_to_unit (start + cnt - 1);
                y2 = height;
 
-               gtk_object_set (GTK_OBJECT(rect->rect), 
-                               "x1", x1,
-                               "y1", 1.0,
-                               "x2", x2,
-                               "y2", y2,
-                               NULL);
+               rect->rect->property_x1() = x1;
+               rect->rect->property_y1() = 1.0;
+               rect->rect->property_x2() = x2;
+               rect->rect->property_y2() = y2;
                
                // trim boxes are at the top for selections
                
                if (x2 > x1) {
-                       gtk_object_set (GTK_OBJECT(rect->start_trim), 
-                                       "x1", x1,
-                                       "y1", 1.0,
-                                       "x2", x1 + trim_handle_size,
-                                       "y2", 1.0 + trim_handle_size,
-                                       NULL);
-                       gtk_object_set (GTK_OBJECT(rect->end_trim), 
-                                       "x1", x2 - trim_handle_size,
-                                       "y1", 1.0,
-                                       "x2", x2,
-                                       "y2", 1.0 + trim_handle_size,
-                                       NULL);
-                       gnome_canvas_item_show (rect->start_trim);
-                       gnome_canvas_item_show (rect->end_trim);
+                       rect->start_trim->property_x1() = x1;
+                       rect->start_trim->property_y1() = 1.0;
+                       rect->start_trim->property_x2() = x1 + trim_handle_size;
+                       rect->start_trim->property_y2() = 1.0 + trim_handle_size;
+
+                       rect->end_trim->property_x1() = x2 - trim_handle_size;
+                       rect->end_trim->property_y1() = 1.0;
+                       rect->end_trim->property_x2() = x2;
+                       rect->end_trim->property_y2() = 1.0 + trim_handle_size;
+
+                       rect->start_trim->show();
+                       rect->end_trim->show();
                } else {
-                       gnome_canvas_item_hide (rect->start_trim);
-                       gnome_canvas_item_hide (rect->end_trim);
+                       rect->start_trim->hide();
+                       rect->end_trim->hide();
                }
 
-               gnome_canvas_item_show (rect->rect);
+               rect->rect->show ();
                used_selection_rects.push_back (rect);
        }
 }
@@ -563,6 +661,8 @@ TimeAxisView::show_selection (TimeSelection& ts)
 void
 TimeAxisView::reshow_selection (TimeSelection& ts)
 {
+       cerr << name() << ": reshow selection" << endl;
+
        show_selection (ts);
 
        for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
@@ -573,15 +673,15 @@ TimeAxisView::reshow_selection (TimeSelection& ts)
 void
 TimeAxisView::hide_selection ()
 {
-       if (GTK_OBJECT_FLAGS(GTK_OBJECT(selection_group)) & GNOME_CANVAS_ITEM_VISIBLE) {
+       if (canvas_item_visible (selection_group)) {
                while (!used_selection_rects.empty()) {
                        free_selection_rects.push_front (used_selection_rects.front());
                        used_selection_rects.pop_front();
-                       gnome_canvas_item_hide (free_selection_rects.front()->rect);
-                       gnome_canvas_item_hide (free_selection_rects.front()->start_trim);
-                       gnome_canvas_item_hide (free_selection_rects.front()->end_trim);
+                       free_selection_rects.front()->rect->hide();
+                       free_selection_rects.front()->start_trim->hide();
+                       free_selection_rects.front()->end_trim->hide();
                }
-               gnome_canvas_item_hide (selection_group);
+               selection_group->hide();
        }
        
        for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
@@ -590,7 +690,7 @@ TimeAxisView::hide_selection ()
 }
 
 void
-TimeAxisView::order_selection_trims (GnomeCanvasItem *item, bool put_start_on_top)
+TimeAxisView::order_selection_trims (ArdourCanvas::Item *item, bool put_start_on_top)
 {
        /* find the selection rect this is for. we have the item corresponding to one
           of the trim handles.
@@ -598,15 +698,15 @@ TimeAxisView::order_selection_trims (GnomeCanvasItem *item, bool put_start_on_to
 
        for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
                if ((*i)->start_trim == item || (*i)->end_trim == item) {
-
+                       
                        /* make one trim handle be "above" the other so that if they overlap,
                           the top one is the one last used.
                        */
-
-                       gnome_canvas_item_raise_to_top ((*i)->rect);
-                       gnome_canvas_item_raise_to_top (put_start_on_top ? (*i)->start_trim : (*i)->end_trim);
-                       gnome_canvas_item_raise_to_top (put_start_on_top ? (*i)->end_trim : (*i)->start_trim);
-
+                       
+                       (*i)->rect->raise_to_top ();
+                       (put_start_on_top ? (*i)->start_trim : (*i)->end_trim)->raise_to_top ();
+                       (put_start_on_top ? (*i)->end_trim : (*i)->start_trim)->raise_to_top ();
+                       
                        break;
                }
        }
@@ -640,47 +740,31 @@ TimeAxisView::get_selection_rect (uint32_t id)
 
                rect = new SelectionRect;
 
-               rect->rect = gnome_canvas_item_new (GNOME_CANVAS_GROUP(selection_group),
-                                                 gnome_canvas_simplerect_get_type(),
-                                                 "x1", 0.0,
-                                                 "y1", 0.0,
-                                                 "x2", 0.0,
-                                                 "y2", 0.0,
-                                                 "fill_color_rgba", color_map[cSelectionRectFill],
-                                                 "outline_color_rgba" , color_map[cSelectionRectOutline],
-                                                 NULL);
-               
+               rect->rect = new SimpleRect (*selection_group);
+               rect->rect->property_x1() = 0.0;
+               rect->rect->property_y1() = 0.0;
+               rect->rect->property_x2() = 0.0;
+               rect->rect->property_y2() = 0.0;
+               rect->rect->property_fill_color_rgba() = color_map[cSelectionRectFill];
+               rect->rect->property_outline_color_rgba() = color_map[cSelectionRectOutline];
                
-               rect->start_trim = gnome_canvas_item_new (GNOME_CANVAS_GROUP(selection_group),
-                                                           gnome_canvas_simplerect_get_type(),
-                                                           "x1", (gdouble) 0.0,
-                                                           "x2", (gdouble) 0.0,
-                                                           "fill_color_rgba" , color_map[cSelectionStartFill],
-                                                           "outline_color_rgba" , color_map[cSelectionStartOutline],
-                                                           NULL);
+               rect->start_trim = new SimpleRect (*selection_group);
+               rect->start_trim->property_x1() = 0.0;
+               rect->start_trim->property_x2() = 0.0;
+               rect->start_trim->property_fill_color_rgba() = color_map[cSelectionStartFill];
+               rect->start_trim->property_outline_color_rgba() = color_map[cSelectionStartOutline];
                
-               rect->end_trim = gnome_canvas_item_new (GNOME_CANVAS_GROUP(selection_group),
-                                                         gnome_canvas_simplerect_get_type(),
-                                                         "x1", 0.0,
-                                                         "x2", 0.0,
-                                                         "fill_color_rgba" , color_map[cSelectionEndFill],
-                                                         "outline_color_rgba" , color_map[cSelectionEndOutline],
-                                                         NULL);
+               rect->end_trim = new SimpleRect (*selection_group);
+               rect->end_trim->property_x1() = 0.0;
+               rect->end_trim->property_x2() = 0.0;
+               rect->end_trim->property_fill_color_rgba() = color_map[cSelectionEndFill];
+               rect->end_trim->property_outline_color_rgba() = color_map[cSelectionEndOutline];
+
                free_selection_rects.push_front (rect);
 
-               gtk_signal_connect (GTK_OBJECT(rect->rect), "event",
-                                   (GtkSignalFunc) PublicEditor::canvas_selection_rect_event,
-                                   &editor);
-               gtk_signal_connect (GTK_OBJECT(rect->start_trim), "event",
-                                   (GtkSignalFunc) PublicEditor::canvas_selection_start_trim_event,
-                                   &editor);
-               gtk_signal_connect (GTK_OBJECT(rect->end_trim), "event",
-                                   (GtkSignalFunc) PublicEditor::canvas_selection_end_trim_event,
-                                   &editor);
-
-               gtk_object_set_data(GTK_OBJECT(rect->rect), "rect", rect);
-               gtk_object_set_data(GTK_OBJECT(rect->start_trim), "rect", rect);
-               gtk_object_set_data(GTK_OBJECT(rect->end_trim), "rect", rect);
+               rect->rect->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_selection_rect_event), rect->rect, rect));
+               rect->start_trim->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_selection_start_trim_event), rect->rect, rect));
+               rect->end_trim->signal_event().connect (bind (mem_fun (editor, &PublicEditor::canvas_selection_end_trim_event), rect->rect, rect));
        } 
 
        rect = free_selection_rects.front();
@@ -783,7 +867,7 @@ TimeAxisView::set_state (const XMLNode& node)
                } else if (prop->value() == "small") {
                        set_height (Small);
                } else {
-                       error << compose(_("unknown track height name \"%1\" in XML GUI information"), prop->value()) << endmsg;
+                       error << string_compose(_("unknown track height name \"%1\" in XML GUI information"), prop->value()) << endmsg;
                        set_height (Normal);
                }
 
@@ -795,10 +879,159 @@ TimeAxisView::set_state (const XMLNode& node)
 void
 TimeAxisView::reset_height()
 {
-       set_height ((TrackHeight) height);
+       set_height_pixels (height);
 
        for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
                (*i)->set_height ((TrackHeight)(*i)->height);
        }
 }
        
+uint32_t
+TimeAxisView::height_to_pixels (TrackHeight h)
+{
+       switch (h) {
+       case Largest:
+               return hLargest;
+       case Large:
+               return hLarge;
+       case Larger:
+               return hLarger;
+       case Normal:
+               return hNormal;
+       case Smaller:
+               return hSmaller;
+       case Small:
+               return hSmall;
+       }
+       
+       // what is wrong with gcc ?
+       
+       return hNormal;
+}
+                       
+void
+TimeAxisView::compute_controls_size_info ()
+{
+       Gtk::Window window (Gtk::WINDOW_TOPLEVEL);
+       Gtk::Table two_row_table (2, 8);
+       Gtk::Table one_row_table (1, 8);
+       Button* buttons[5];
+       const int border_width = 2;
+       const int extra_height = (2 * border_width) + 2; // 2 pixels for the controls frame
+
+       window.add (one_row_table);
+
+       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");
+       }
+
+       Gtk::Requisition req;
+
+       one_row_table.attach (*buttons[0], 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
+       
+       one_row_table.show_all ();
+       one_row_table.size_request (req);
+
+
+       // height required to show 1 row of buttons
+
+       hSmaller = req.height + extra_height;
+
+       window.remove ();
+       window.add (two_row_table);
+
+       two_row_table.attach (*buttons[1], 5, 6, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
+       two_row_table.attach (*buttons[2], 6, 7, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
+       two_row_table.attach (*buttons[3], 7, 8, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
+       two_row_table.attach (*buttons[4], 8, 9, 0, 1, Gtk::FILL|Gtk::EXPAND, Gtk::FILL|Gtk::EXPAND, 0, 0);
+
+       two_row_table.show_all ();
+       two_row_table.size_request (req);
+
+       // height required to show all normal buttons 
+
+       hNormal = req.height + extra_height;
+
+       // these heights are all just larger than normal. no more 
+       // elements are visible (yet).
+
+       hLarger = hNormal + 50;
+       hLarge = hNormal + 150;
+       hLargest = hNormal + 250;
+
+       // height required to show track name
+
+       hSmall = 27;
+}
+
+void
+TimeAxisView::show_name_label ()
+{
+       if (!(name_packing & NameLabelPacked)) {
+               name_hbox.pack_start (name_label, true, true);
+               name_packing = NamePackingBits (name_packing | NameLabelPacked);
+               name_hbox.show ();
+               name_label.show ();
+       }
+}
+
+void
+TimeAxisView::show_name_entry ()
+{
+       if (!(name_packing & NameEntryPacked)) {
+               name_hbox.pack_start (name_entry, true, true);
+               name_packing = NamePackingBits (name_packing | NameEntryPacked);
+               name_hbox.show ();
+               name_entry.show ();
+       }
+}
+
+void
+TimeAxisView::hide_name_label ()
+{
+       if (name_packing & NameLabelPacked) {
+               name_hbox.remove (name_label);
+               name_packing = NamePackingBits (name_packing & ~NameLabelPacked);
+       }
+}
+
+void
+TimeAxisView::hide_name_entry ()
+{
+       if (name_packing & NameEntryPacked) {
+               name_hbox.remove (name_entry);
+               name_packing = NamePackingBits (name_packing & ~NameEntryPacked);
+       }
+}
+
+void
+TimeAxisView::color_handler (ColorID id, uint32_t val)
+{
+       switch (id) {
+       case cSelectionRectFill:
+               break;
+       case cSelectionRectOutline:
+               break;
+       case cSelectionStartFill:
+               break;
+       case cSelectionStartOutline:
+               break;
+       case cSelectionEndFill:
+               break;
+       case cSelectionEndOutline:
+               break;
+       default:
+               break;
+       }
+}