+
+void
+TimeAxisView::compute_heights ()
+{
+ 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;
+ extra_height = (2 * border_width)
+ //+ 2 // 2 pixels for the hseparator between TimeAxisView control areas
+ + 6; // resizer button (3 x 2 pixel elements + 2 x 2 pixel gaps)
+
+ 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");
+ }
+
+ 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 ();
+ Gtk::Requisition req(one_row_table.size_request ());
+
+ // height required to show 1 row of buttons
+
+ smaller_height = req.height + extra_height;
+}
+
+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 ()
+{
+ for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); i++) {
+ (*i)->set_colors();
+ }
+
+ for (list<SelectionRect*>::iterator i = used_selection_rects.begin(); i != used_selection_rects.end(); ++i) {
+
+ (*i)->rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectionRect.get();
+ (*i)->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+
+ (*i)->start_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+ (*i)->start_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+
+ (*i)->end_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+ (*i)->end_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+ }
+
+ for (list<SelectionRect*>::iterator i = free_selection_rects.begin(); i != free_selection_rects.end(); ++i) {
+
+ (*i)->rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_SelectionRect.get();
+ (*i)->rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+
+ (*i)->start_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+ (*i)->start_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+
+ (*i)->end_trim->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+ (*i)->end_trim->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_Selection.get();
+ }
+}
+
+/** @return Pair: TimeAxisView, layer index.
+ * TimeAxisView is non-0 if this object covers y, or one of its children does.
+ * If the covering object is a child axis, then the child is returned.
+ * TimeAxisView is 0 otherwise.
+ * Layer index is the layer number if the TimeAxisView is valid and is in stacked
+ * region display mode, otherwise 0.
+ */
+std::pair<TimeAxisView*, layer_t>
+TimeAxisView::covers_y_position (double y)
+{
+ if (hidden()) {
+ return std::make_pair ((TimeAxisView *) 0, 0);
+ }
+
+ if (_y_position <= y && y < (_y_position + height)) {
+
+ /* work out the layer index if appropriate */
+ layer_t l = 0;
+ if (layer_display () == Stacked && view ()) {
+ /* compute layer */
+ l = layer_t ((_y_position + height - y) / (view()->child_height ()));
+ /* clamp to max layers to be on the safe side; sometimes the above calculation
+ returns a too-high value */
+ if (l >= view()->layers ()) {
+ l = view()->layers() - 1;
+ }
+ }
+
+ return std::make_pair (this, l);
+ }
+
+ for (Children::const_iterator i = children.begin(); i != children.end(); ++i) {
+
+ std::pair<TimeAxisView*, int> const r = (*i)->covers_y_position (y);
+ if (r.first) {
+ return r;
+ }
+ }
+
+ return std::make_pair ((TimeAxisView *) 0, 0);
+}
+
+bool
+TimeAxisView::resizer_button_press (GdkEventButton* event)
+{
+ _resize_drag_start = event->y_root;
+ return true;
+}
+
+bool
+TimeAxisView::resizer_button_release (GdkEventButton*)
+{
+ _editor.stop_canvas_autoscroll ();
+ _resize_drag_start = -1;
+ return true;
+}
+
+void
+TimeAxisView::idle_resize (uint32_t h)
+{
+ set_height (h);
+}
+
+bool
+TimeAxisView::resizer_motion (GdkEventMotion* ev)
+{
+ if (_resize_drag_start >= 0) {
+ /* (ab)use the DragManager to do autoscrolling; adjust the event coordinates
+ into the world coordinate space that DragManager::motion_handler is expecting,
+ and then fake a DragManager motion event so that when maybe_autoscroll
+ asks DragManager for the current pointer position it will get the correct
+ answers.
+ */
+ int tx, ty;
+ resizer.translate_coordinates (*control_parent, ev->x, ev->y, tx, ty);
+ ev->y = ty - _editor.get_trackview_group_vertical_offset();
+ _editor.drags()->motion_handler ((GdkEvent *) ev, false);
+ _editor.maybe_autoscroll (false, true);
+
+ /* now do 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;
+ }
+
+ return true;
+}
+
+bool
+TimeAxisView::resizer_expose (GdkEventExpose* event)
+{
+ int w, h, x, y, d;
+ Glib::RefPtr<Gdk::Window> win (resizer.get_window());
+ Glib::RefPtr<Gdk::GC> dark (resizer.get_style()->get_fg_gc (STATE_NORMAL));
+ Glib::RefPtr<Gdk::GC> light (resizer.get_style()->get_bg_gc (STATE_NORMAL));
+
+ win->draw_rectangle (controls_ebox.get_style()->get_bg_gc(STATE_NORMAL),
+ true,
+ event->area.x,
+ event->area.y,
+ event->area.width,
+ event->area.height);
+
+ win->get_geometry (x, y, w, h, d);
+
+ /* handle/line #1 */
+
+ win->draw_line (dark, 0, 0, w - 2, 0);
+ win->draw_point (dark, 0, 1);
+ win->draw_line (light, 1, 1, w - 1, 1);
+ win->draw_point (light, w - 1, 0);
+
+ /* handle/line #2 */
+
+ win->draw_line (dark, 0, 4, w - 2, 4);
+ win->draw_point (dark, 0, 5);
+ win->draw_line (light, 1, 5, w - 1, 5);
+ win->draw_point (light, w - 1, 4);
+
+ /* use vertical resize mouse cursor */
+ win->set_cursor(Gdk::Cursor(Gdk::SB_V_DOUBLE_ARROW));
+
+ return true;
+}
+
+bool
+TimeAxisView::set_visibility (bool yn)
+{
+ if (yn != marked_for_display()) {
+ if (yn) {
+ set_marked_for_display (true);
+ canvas_display()->show();
+ } else {
+ set_marked_for_display (false);
+ hide ();
+ }
+ return true; // things changed
+ }