various work on Pane, including cursors, more styling stuff, and making the forall_vf...
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 27 May 2016 16:58:55 +0000 (12:58 -0400)
committerPaul Davis <paul@linuxaudiosystems.com>
Tue, 31 May 2016 19:30:45 +0000 (15:30 -0400)
libs/gtkmm2ext/gtkmm2ext/pane.h
libs/gtkmm2ext/pane.cc

index 452c9f9f0ade48d8fc2414f4adc493d32ef220c9..ecf466833a2becb2c052d929416ccdbb3cc85233 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <stdint.h>
 
+#include <gdkmm/cursor.h>
 #include <gtkmm/container.h>
 #include <gtkmm/eventbox.h>
 
@@ -47,8 +48,9 @@ class LIBGTKMM2EXT_API Pane : public Gtk::Container
        float get_divider (std::vector<float>::size_type divider = 0);
 
        GType child_type_vfunc() const;
+       void set_drag_cursor (Gdk::Cursor);
 
-
+  protected:
        bool horizontal;
 
        void on_add (Gtk::Widget*);
@@ -60,10 +62,15 @@ class LIBGTKMM2EXT_API Pane : public Gtk::Container
        bool handle_press_event (GdkEventButton*, Divider*);
        bool handle_release_event (GdkEventButton*, Divider*);
        bool handle_motion_event (GdkEventMotion*, Divider*);
+       bool handle_enter_event (GdkEventCrossing*, Divider*);
+       bool handle_leave_event (GdkEventCrossing*, Divider*);
 
        void forall_vfunc (gboolean include_internals, GtkCallback callback, gpointer callback_data);
 
   private:
+       Gdk::Cursor drag_cursor;
+       bool did_move;
+
        void reallocate (Gtk::Allocation const &);
 
        typedef std::list<Gtk::Widget*> Children;
@@ -76,11 +83,9 @@ class LIBGTKMM2EXT_API Pane : public Gtk::Container
                bool dragging;
 
                bool on_expose_event (GdkEventExpose* ev);
-               bool on_enter_notify_event (GdkEventCrossing*);
-               bool on_leave_notify_event (GdkEventCrossing*);
        };
 
-       typedef std::vector<Divider*> Dividers;
+       typedef std::list<Divider*> Dividers;
        Dividers dividers;
        int divider_width;
        void add_divider ();
index 2472d0257d9abc48f2057e0482a175bd4b58380c..5945ec40dca030accd0ad2c3c1c5c23355ef6765 100644 (file)
@@ -17,6 +17,7 @@
 
 */
 
+#include <gdkmm/cursor.h>
 #include "gtkmm2ext/pane.h"
 
 #include "i18n.h"
@@ -28,10 +29,25 @@ using namespace std;
 
 Pane::Pane (bool h)
        : horizontal (h)
+       , did_move (false)
        , divider_width (5)
 {
+       using namespace Gdk;
+
        set_name ("Pane");
        set_has_window (false);
+
+       if (horizontal) {
+               drag_cursor = Cursor (SB_H_DOUBLE_ARROW);
+       } else {
+               drag_cursor = Cursor (SB_H_DOUBLE_ARROW);
+       }
+}
+
+void
+Pane::set_drag_cursor (Gdk::Cursor c)
+{
+       drag_cursor = c;
 }
 
 void
@@ -41,11 +57,11 @@ Pane::on_size_request (GtkRequisition* req)
 
        /* iterate over all children, get their size requests */
 
-       /* horizontal pane is as high as its tallest child, but has no width
-        * requirement.
+       /* horizontal pane is as high as its tallest child, including the dividers.
+        * Its width is the sum of the children plus the dividers.
         *
-        * vertical pane is as wide as its widest child, but has no height
-        * requirement.
+        * vertical pane is as wide as its widest child, including the dividers.
+        * Its height is the sum of the children plus the dividers.
         */
 
        if (horizontal) {
@@ -76,6 +92,7 @@ Pane::on_size_request (GtkRequisition* req)
 GType
 Pane::child_type_vfunc() const
 {
+       /* We accept any number of any types of widgets */
        return Gtk::Widget::get_type();
 }
 
@@ -86,6 +103,8 @@ Pane::add_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);
+       d->signal_enter_notify_event().connect (sigc::bind (sigc::mem_fun (*this, &Pane::handle_enter_event), d), false);
+       d->signal_leave_notify_event().connect (sigc::bind (sigc::mem_fun (*this, &Pane::handle_leave_event), d), false);
        d->set_parent (*this);
        d->show ();
        d->fract = 0.5;
@@ -121,7 +140,6 @@ Pane::on_size_allocate (Gtk::Allocation& alloc)
 void
 Pane::reallocate (Gtk::Allocation const & alloc)
 {
-       Children::size_type n = 0;
         int remaining;
         int xpos = alloc.get_x();
         int ypos = alloc.get_y();
@@ -132,6 +150,7 @@ Pane::reallocate (Gtk::Allocation const & alloc)
         }
 
         if (children.size() == 1) {
+               /* only child gets the full allocation */
                children.front()->size_allocate (alloc);
                return;
         }
@@ -146,7 +165,7 @@ Pane::reallocate (Gtk::Allocation const & alloc)
         Children::iterator next;
         Dividers::iterator div;
 
-        for (child = children.begin(), div = dividers.begin(); child != children.end(); ++n) {
+        for (child = children.begin(), div = dividers.begin(); child != children.end(); ) {
 
                Gtk::Allocation child_alloc;
                next = child;
@@ -155,12 +174,12 @@ Pane::reallocate (Gtk::Allocation const & alloc)
                child_alloc.set_x (xpos);
                child_alloc.set_y (ypos);
 
-               if (n >= dividers.size()) {
-                       /* the next child gets all the remaining space */
+               if (next == children.end()) {
+                       /* last child gets all the remaining space */
                        fract = 1.0;
                } else {
-                       /* the next child gets the fraction of the remaining space given by the divider that follows it */
-                       fract = dividers[n]->fract;
+                       /* child gets the fraction of the remaining space given by the divider that follows it */
+                       fract = (*div)->fract;
                }
 
                Gtk::Requisition cr;
@@ -213,14 +232,15 @@ Pane::reallocate (Gtk::Allocation const & alloc)
 bool
 Pane::on_expose_event (GdkEventExpose* ev)
 {
-       Children::size_type n = 0;
+       Children::iterator child;
+       Dividers::iterator div;
 
-       for (Children::iterator child = children.begin(); child != children.end(); ++child, ++n) {
+       for (child = children.begin(), div = dividers.begin(); child != children.end(); ++child, ++div) {
 
                propagate_expose (**child, ev);
 
-               if (n < dividers.size()) {
-                       propagate_expose (*dividers[n], ev);
+               if (div != dividers.end()) {
+                       propagate_expose (**div, ev);
                }
         }
 
@@ -240,7 +260,11 @@ bool
 Pane::handle_release_event (GdkEventButton* ev, Divider* d)
 {
        d->dragging = false;
-       children.front()->queue_resize ();
+
+       if (did_move) {
+               children.front()->queue_resize ();
+               did_move = false;
+       }
 
        return false;
 }
@@ -248,6 +272,8 @@ Pane::handle_release_event (GdkEventButton* ev, Divider* d)
 bool
 Pane::handle_motion_event (GdkEventMotion* ev, Divider* d)
 {
+       did_move = true;
+
        if (!d->dragging) {
                return true;
        }
@@ -305,12 +331,20 @@ Pane::set_divider (Dividers::size_type div, float fract)
 {
        bool redraw = false;
 
-       while (dividers.size() <= div) {
-               add_divider ();
+       Dividers::iterator d = dividers.begin();
+
+       while (div--) {
+               ++d;
+               if (d == dividers.end()) {
+                       /* caller is trying to set divider that does not exist
+                        * yet.
+                        */
+                       return;
+               }
        }
 
-       if (fract != dividers[div]->fract) {
-               dividers[div]->fract = fract;
+       if (fract != (*d)->fract) {
+               (*d)->fract = fract;
                redraw = true;
        }
 
@@ -324,23 +358,41 @@ Pane::set_divider (Dividers::size_type div, float fract)
 float
 Pane::get_divider (Dividers::size_type div)
 {
-       if (div >= dividers.size()) {
-               return -1;
+       Dividers::iterator d = dividers.begin();
+
+       while (div--) {
+               ++d;
+               if (d == dividers.end()) {
+                       /* caller is trying to set divider that does not exist
+                        * yet.
+                        */
+                       return -1.0f;
+               }
        }
 
-       return dividers[div]->fract;
+       return (*d)->fract;
 }
 
 void
 Pane::forall_vfunc (gboolean include_internals, GtkCallback callback, gpointer callback_data)
 {
-       for (Children::iterator w = children.begin(); w != children.end(); ++w) {
+       /* since the callback could modify the child list(s), make sure we keep
+        * the iterators safe;
+        */
+
+       for (Children::iterator w = children.begin(); w != children.end(); ) {
+               Children::iterator next = w;
+               ++next;
                callback ((*w)->gobj(), callback_data);
+               w = next;
        }
 
        if (include_internals) {
-               for (Dividers::iterator d = dividers.begin(); d != dividers.end(); ++d) {
+               for (Dividers::iterator d = dividers.begin(); d != dividers.end(); ) {
+                       Dividers::iterator next = d;
+                       ++next;
                        callback (GTK_WIDGET((*d)->gobj()), callback_data);
+                       d = next;
                }
        }
 }
@@ -372,15 +424,17 @@ Pane::Divider::on_expose_event (GdkEventExpose* ev)
 }
 
 bool
-Pane::Divider::on_enter_notify_event (GdkEventCrossing*)
+Pane::handle_enter_event (GdkEventCrossing*, Divider* d)
 {
-       set_state (Gtk::STATE_SELECTED);
+       d->get_window()->set_cursor (drag_cursor);
+       d->set_state (Gtk::STATE_SELECTED);
        return true;
 }
 
 bool
-Pane::Divider::on_leave_notify_event (GdkEventCrossing*)
+Pane::handle_leave_event (GdkEventCrossing*, Divider* d)
 {
-       set_state (Gtk::STATE_NORMAL);
+       d->get_window()->set_cursor ();
+       d->set_state (Gtk::STATE_NORMAL);
        return true;
 }