add a destructor for Gtkmm2ext::Pane that unparents the children.
[ardour.git] / libs / gtkmm2ext / pane.cc
index 5945ec40dca030accd0ad2c3c1c5c23355ef6765..aa8e7d142b74655eaa3f0922eacf17dfdd1fe0a8 100644 (file)
@@ -30,7 +30,7 @@ using namespace std;
 Pane::Pane (bool h)
        : horizontal (h)
        , did_move (false)
-       , divider_width (5)
+       , divider_width (2)
 {
        using namespace Gdk;
 
@@ -40,7 +40,25 @@ Pane::Pane (bool h)
        if (horizontal) {
                drag_cursor = Cursor (SB_H_DOUBLE_ARROW);
        } else {
-               drag_cursor = Cursor (SB_H_DOUBLE_ARROW);
+               drag_cursor = Cursor (SB_V_DOUBLE_ARROW);
+       }
+}
+
+Pane::~Pane ()
+{
+       for (Children::iterator c = children.begin(); c != children.end(); ++c) {
+               c->w->unparent ();
+       }
+}
+
+void
+Pane::set_child_minsize (Gtk::Widget const& w, int32_t minsize)
+{
+       for (Children::iterator c = children.begin(); c != children.end(); ++c) {
+               if (c->w == &w) {
+                       c->minsize = minsize;
+                       break;
+               }
        }
 }
 
@@ -75,7 +93,7 @@ Pane::on_size_request (GtkRequisition* req)
        for (Children::iterator child = children.begin(); child != children.end(); ++child) {
                GtkRequisition r;
 
-               (*child)->size_request (r);
+               child->w->size_request (r);
 
                if (horizontal) {
                        largest.height = max (largest.height, r.height);
@@ -100,6 +118,7 @@ void
 Pane::add_divider ()
 {
        Divider* d = new Divider;
+       d->set_name (X_("Divider"));
        d->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Pane::handle_press_event), d), false);
        d->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &Pane::handle_release_event), d), false);
        d->signal_motion_notify_event().connect (sigc::bind (sigc::mem_fun (*this, &Pane::handle_motion_event), d), false);
@@ -111,13 +130,22 @@ Pane::add_divider ()
        dividers.push_back (d);
 }
 
+void
+Pane::handle_child_visibility ()
+{
+       reallocate (get_allocation());
+}
+
 void
 Pane::on_add (Widget* w)
 {
-       children.push_back (w);
+       children.push_back (Child (w, 0));
 
        w->set_parent (*this);
 
+       w->signal_show().connect (sigc::mem_fun (*this, &Pane::handle_child_visibility));
+       w->signal_hide().connect (sigc::mem_fun (*this, &Pane::handle_child_visibility));
+
        while (dividers.size() < (children.size() - 1)) {
                add_divider ();
        }
@@ -126,8 +154,13 @@ Pane::on_add (Widget* w)
 void
 Pane::on_remove (Widget* w)
 {
-       w->unparent ();
-       children.remove (w);
+       for (Children::iterator c = children.begin(); c != children.end(); ++c) {
+               if (c->w == w) {
+                       w->unparent ();
+                       children.erase (c);
+                       break;
+               }
+       }
 }
 
 void
@@ -151,7 +184,7 @@ Pane::reallocate (Gtk::Allocation const & alloc)
 
         if (children.size() == 1) {
                /* only child gets the full allocation */
-               children.front()->size_allocate (alloc);
+               children.front().w->size_allocate (alloc);
                return;
         }
 
@@ -165,11 +198,30 @@ Pane::reallocate (Gtk::Allocation const & alloc)
         Children::iterator next;
         Dividers::iterator div;
 
-        for (child = children.begin(), div = dividers.begin(); child != children.end(); ) {
+        child = children.begin();
+
+        /* skip initial hidden children */
+
+        while (child != children.end()) {
+               if (child->w->is_visible()) {
+                       break;
+               }
+               ++child;
+        }
+
+        for (div = dividers.begin(); child != children.end(); ) {
 
                Gtk::Allocation child_alloc;
+
                next = child;
-               ++next;
+
+               /* Move on to next *visible* child */
+
+               while (++next != children.end()) {
+                       if (next->w->is_visible()) {
+                               break;
+                       }
+               }
 
                child_alloc.set_x (xpos);
                child_alloc.set_y (ypos);
@@ -183,7 +235,7 @@ Pane::reallocate (Gtk::Allocation const & alloc)
                }
 
                Gtk::Requisition cr;
-               (*child)->size_request (cr);
+               child->w->size_request (cr);
 
                if (horizontal) {
                        child_alloc.set_width ((gint) floor (remaining * fract));
@@ -197,14 +249,23 @@ Pane::reallocate (Gtk::Allocation const & alloc)
                        ypos += child_alloc.get_height ();
                }
 
-               (*child)->size_allocate (child_alloc);
-               ++child;
+               if (child->minsize) {
+                       if (horizontal) {
+                               child_alloc.set_width (max (child_alloc.get_width(), child->minsize));
+                       } else {
+                               child_alloc.set_height (max (child_alloc.get_height(), child->minsize));
+                       }
+               }
+
+               child->w->size_allocate (child_alloc);
 
-               if (child == children.end()) {
+               if (next == children.end()) {
                        /* done, no more children, no need for a divider */
                        break;
                }
 
+               child = next;
+
                /* add a divider between children */
 
                Gtk::Allocation divider_allocation;
@@ -225,6 +286,14 @@ Pane::reallocate (Gtk::Allocation const & alloc)
                }
 
                (*div)->size_allocate (divider_allocation);
+               (*div)->show ();
+               ++div;
+        }
+
+        /* hide all remaining dividers */
+
+        while (div != dividers.end()) {
+               (*div)->hide ();
                ++div;
         }
 }
@@ -237,9 +306,11 @@ Pane::on_expose_event (GdkEventExpose* ev)
 
        for (child = children.begin(), div = dividers.begin(); child != children.end(); ++child, ++div) {
 
-               propagate_expose (**child, ev);
+               if (child->w->is_visible()) {
+                       propagate_expose (*(child->w), ev);
+               }
 
-               if (div != dividers.end()) {
+               if ((div != dividers.end()) && (*div)->is_visible()) {
                        propagate_expose (**div, ev);
                }
         }
@@ -262,7 +333,7 @@ Pane::handle_release_event (GdkEventButton* ev, Divider* d)
        d->dragging = false;
 
        if (did_move) {
-               children.front()->queue_resize ();
+               children.front().w->queue_resize ();
                did_move = false;
        }
 
@@ -329,8 +400,6 @@ Pane::handle_motion_event (GdkEventMotion* ev, Divider* d)
 void
 Pane::set_divider (Dividers::size_type div, float fract)
 {
-       bool redraw = false;
-
        Dividers::iterator d = dividers.begin();
 
        while (div--) {
@@ -343,12 +412,10 @@ Pane::set_divider (Dividers::size_type div, float fract)
                }
        }
 
+       fract = max (0.0f, min (1.0f, fract));
+
        if (fract != (*d)->fract) {
                (*d)->fract = fract;
-               redraw = true;
-       }
-
-       if (redraw) {
                /* our size hasn't changed, but our internal allocations have */
                reallocate (get_allocation());
                queue_draw ();
@@ -380,11 +447,11 @@ Pane::forall_vfunc (gboolean include_internals, GtkCallback callback, gpointer c
         * the iterators safe;
         */
 
-       for (Children::iterator w = children.begin(); w != children.end(); ) {
-               Children::iterator next = w;
+       for (Children::iterator c = children.begin(); c != children.end(); ) {
+               Children::iterator next = c;
                ++next;
-               callback ((*w)->gobj(), callback_data);
-               w = next;
+               callback (c->w->gobj(), callback_data);
+               c = next;
        }
 
        if (include_internals) {
@@ -436,5 +503,6 @@ Pane::handle_leave_event (GdkEventCrossing*, Divider* d)
 {
        d->get_window()->set_cursor ();
        d->set_state (Gtk::STATE_NORMAL);
+       d->queue_draw ();
        return true;
 }