]> git.tdb.fi Git - libs/gltk.git/commitdiff
Add autosizing for panels
authorMikko Rasa <tdb@tdb.fi>
Tue, 27 Nov 2012 21:58:07 +0000 (23:58 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 27 Nov 2012 21:58:07 +0000 (23:58 +0200)
It still does a lot of unnecessary layout updates, but seems to work at
least in basic cases.

source/layout.cpp
source/layout.h
source/panel.cpp
source/panel.h

index f89e407cf7f4d3b61d08831c0f71693b68b27760..ccd02830924b0622eb12dcf86ba4a0aa9b5a2b74 100644 (file)
@@ -221,19 +221,27 @@ void Layout::set_expand(Widget &wdg, bool h, bool v)
 
 void Layout::update()
 {
-       solve_constraints(HORIZONTAL);
-       solve_constraints(VERTICAL);
+       solve_constraints(HORIZONTAL, UPDATE);
+       solve_constraints(VERTICAL, UPDATE);
 
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
                (*i)->widget.set_geometry((*i)->geom);
 }
 
-void Layout::solve_constraints(int dir)
+void Layout::autosize()
+{
+       solve_constraints(HORIZONTAL, AUTOSIZE);
+       solve_constraints(VERTICAL, AUTOSIZE);
+
+       container->set_size(autosize_geom.w, autosize_geom.h);
+}
+
+void Layout::solve_constraints(int dir, SolveMode mode)
 {
        Pointers &ptrs = pointers[dir&VERTICAL];
 
        const Geometry &geom = container->get_geometry();
-       if(geom.*(ptrs.dim)<margin.*(ptrs.low_margin)+margin.*(ptrs.high_margin))
+       if(mode==UPDATE && geom.*(ptrs.dim)<margin.*(ptrs.low_margin)+margin.*(ptrs.high_margin))
                return;
 
        /* Set up a linear program to solve the constraints.  The program matrix has
@@ -244,8 +252,17 @@ void Layout::solve_constraints(int dir)
        float weight = slots.size();
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
        {
-               linprog.get_objective_row()[(*i)->index*5] = ((*i)->*(ptrs.packing)).gravity/weight;
-               linprog.get_objective_row()[(*i)->index*5+1] = (((*i)->*(ptrs.packing)).expand ? weight : -1);
+               LinearProgram::Row objective = linprog.get_objective_row();
+               if(mode==AUTOSIZE)
+               {
+                       objective[(*i)->index*5] = -1;
+                       objective[(*i)->index*5+1] = -1;
+               }
+               else
+               {
+                       objective[(*i)->index*5] = ((*i)->*(ptrs.packing)).gravity/weight;
+                       objective[(*i)->index*5+1] = (((*i)->*(ptrs.packing)).expand ? weight : -1);
+               }
 
                {
                        // Prevent the widget from going past the container's low edge.
@@ -255,6 +272,7 @@ void Layout::solve_constraints(int dir)
                        row.back() = margin.*(ptrs.low_margin);
                }
 
+               if(mode==UPDATE)
                {
                        // Prevent the widget from going past the container's high edge.
                        LinearProgram::Row row = linprog.add_row();
@@ -296,10 +314,22 @@ void Layout::solve_constraints(int dir)
        if(!linprog.solve())
                return;
 
-       for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
+       if(mode==AUTOSIZE)
        {
-               (*i)->geom.*(ptrs.pos) = linprog.get_variable((*i)->index*5);
-               (*i)->geom.*(ptrs.dim) = linprog.get_variable((*i)->index*5+1);
+               autosize_geom.*(ptrs.dim) = 0;
+               for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
+               {
+                       int high_edge = linprog.get_variable((*i)->index*5)+linprog.get_variable((*i)->index*5+1);
+                       autosize_geom.*(ptrs.dim) = max(autosize_geom.*(ptrs.dim), high_edge+margin.*(ptrs.high_margin));
+               }
+       }
+       else
+       {
+               for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
+               {
+                       (*i)->geom.*(ptrs.pos) = linprog.get_variable((*i)->index*5);
+                       (*i)->geom.*(ptrs.dim) = linprog.get_variable((*i)->index*5+1);
+               }
        }
 }
 
@@ -336,7 +366,10 @@ void Layout::Slot::autosize_changed()
        if(autosize_geom.w<=geom.w && autosize_geom.h<=geom.h)
                widget.set_geometry(geom);
        else
+       {
+               layout.container->signal_autosize_changed.emit();
                layout.update();
+       }
 }
 
 
index cf63538413e6465c967f93063ee394e8fc09f07d..cbd763e9e5337dc7a6395d7d0b3a860c6d9ad7e1 100644 (file)
@@ -113,6 +113,12 @@ protected:
                void autosize_changed();
        };
 
+       enum SolveMode
+       {
+               UPDATE,
+               AUTOSIZE
+       };
+
        class LinearProgram;
        struct Pointers;
 
@@ -121,6 +127,7 @@ protected:
        Sides margin;
        unsigned row_spacing;
        unsigned col_spacing;
+       Geometry autosize_geom;
 
        static Pointers pointers[2];
 
@@ -146,9 +153,10 @@ public:
        void set_expand(Widget &, bool, bool);
 
        void update();
+       void autosize();
 
 protected:
-       void solve_constraints(int);
+       void solve_constraints(int, SolveMode);
 };
 
 } // namespace GLtk
index 7876120b2ce2e7cea30cecb52fd42aeef2b11185..91e30cdcbafadd63b98714c6cd1a8f3969fb1f07 100644 (file)
@@ -39,6 +39,12 @@ void Panel::set_layout(Layout *l)
        layout = l;
 }
 
+void Panel::autosize()
+{
+       if(layout)
+               layout->autosize();
+}
+
 Panel::Child *Panel::create_child(Widget *wdg)
 {
        return new Child(*this, wdg);
@@ -160,13 +166,19 @@ void Panel::on_geometry_change()
 void Panel::on_child_added(Widget &wdg)
 {
        if(layout)
+       {
                layout->add_widget(wdg);
+               signal_autosize_changed.emit();
+       }
 }
 
 void Panel::on_child_removed(Widget &wdg)
 {
        if(layout)
+       {
                layout->remove_widget(wdg);
+               signal_autosize_changed.emit();
+       }
 }
 
 void Panel::set_pointer_focus(Widget *wdg)
index d3d1f79448d469cd720088dae7612188b20b2c0e..a6a89c5ba18e8dd956fe2580262bf5b4627f8aca 100644 (file)
@@ -61,6 +61,7 @@ public:
        virtual const char *get_class() const { return "panel"; }
 
        void set_layout(Layout *);
+       virtual void autosize();
 
 protected:
        virtual Child *create_child(Widget *);