]> git.tdb.fi Git - libs/gltk.git/blobdiff - source/layout.cpp
Fix a crash if the linear program contains an empty column
[libs/gltk.git] / source / layout.cpp
index b4c3a0eccd38883ac83beb7b863a62b6d3a52b6b..74b33f0bce1933de385720eed1eabe6e821956b2 100644 (file)
@@ -44,7 +44,7 @@ public:
 
        Row add_row();
        Row operator[](unsigned);
-       Row get_object_row();
+       Row get_objective_row();
        bool solve();
        float get_variable(unsigned);
 private:
@@ -217,18 +217,11 @@ void Layout::set_expand(Widget &wdg, bool h, bool v)
 
 void Layout::update()
 {
-       for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
-       {
-               (*i)->widget.autosize();
-               (*i)->geom = (*i)->widget.get_geometry();
-       }
-
        solve_constraints(HORIZONTAL);
        solve_constraints(VERTICAL);
 
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
                (*i)->widget.set_geometry((*i)->geom);
-
 }
 
 void Layout::solve_constraints(int dir)
@@ -243,8 +236,8 @@ void Layout::solve_constraints(int dir)
        float weight = slots.size();
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
        {
-               linprog.get_object_row()[(*i)->index*5] = ((*i)->*(ptrs.packing)).gravity/weight;
-               linprog.get_object_row()[(*i)->index*5+1] = (((*i)->*(ptrs.packing)).expand ? weight : -1);
+               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);
 
                {
                        // Prevent the widget from going past the container's low edge.
@@ -269,14 +262,13 @@ void Layout::solve_constraints(int dir)
                        LinearProgram::Row row = linprog.add_row();
                        row[(*i)->index*5+1] = 1;
                        row[(*i)->index*5+4] = -1;
-                       row.back() = (*i)->geom.*(ptrs.dim);
+                       row.back() = (*i)->autosize_geom.*(ptrs.dim);
                }
 
                /* Add rows for user-defined constraints.  Below/above and left/right of
                constraints are always added in pairs, so it's only necessary to create a
                row for one half. */
                for(list<Constraint>::iterator j=(*i)->constraints.begin(); j!=(*i)->constraints.end(); ++j)
-               {
                        if((j->type&1)==dir && j->type!=BELOW && j->type!=LEFT_OF)
                        {
                                LinearProgram::Row row = linprog.add_row();
@@ -291,7 +283,6 @@ void Layout::solve_constraints(int dir)
                                if(j->type&SPACING)
                                        row.back() = this->*(ptrs.spacing);
                        }
-               }
        }
 
        if(!linprog.solve())
@@ -324,11 +315,20 @@ Layout::Slot::Slot(Layout &l, Widget &w):
 {
        vert_pack.gravity = 1;
        widget.signal_autosize_changed.connect(sigc::mem_fun(this, &Slot::autosize_changed));
+       widget.autosize();
+       autosize_geom = widget.get_geometry();
 }
 
 void Layout::Slot::autosize_changed()
 {
-       layout.update();
+       widget.autosize();
+       autosize_geom = widget.get_geometry();
+
+       // If the widget fits in the area it had, just leave it there.
+       if(autosize_geom.w<=geom.w && autosize_geom.h<=geom.h)
+               widget.set_geometry(geom);
+       else
+               layout.update();
 }
 
 
@@ -353,7 +353,7 @@ Layout::LinearProgram::Row Layout::LinearProgram::operator[](unsigned r)
        return Row(*this, r);
 }
 
-Layout::LinearProgram::Row Layout::LinearProgram::get_object_row()
+Layout::LinearProgram::Row Layout::LinearProgram::get_objective_row()
 {
        return Row(*this, 0);
 }
@@ -383,10 +383,14 @@ bool Layout::LinearProgram::solve()
        pricing out the constraint rows. */
        for(vector<Column>::iterator i=columns.begin(); i!=columns.end(); ++i)
        {
-               float objective = i->values.front();
-               i->values.front() = 0.0f;
-               for(vector<float>::iterator j=i->values.begin(); j!=i->values.end(); ++j)
-                       i->values.front() += *j;
+               float objective = 0.0f;
+               if(!i->values.empty())
+               {
+                       objective = i->values.front();
+                       i->values.front() = 0.0f;
+                       for(vector<float>::iterator j=i->values.begin(); j!=i->values.end(); ++j)
+                               i->values.front() += *j;
+               }
                i->values.resize(n_rows+1, 0.0f);
                i->values.back() = objective;
        }
@@ -438,7 +442,7 @@ unsigned Layout::LinearProgram::find_minimal_ratio(unsigned c)
        /* Pick the row with the minimum ratio between the constant column and the
        pivot column.  This ensures that when the pivot column is made basic, values
        in the constant column stay positive.
-       
+
        The use of n_rows instead of the true size of the column is intentional,
        since the relocated objective row must be ignored in phase 1. */
        float best = numeric_limits<float>::infinity();
@@ -453,7 +457,7 @@ unsigned Layout::LinearProgram::find_minimal_ratio(unsigned c)
                                row = i;
                        }
                }
-       
+
        return row;
 }
 
@@ -472,14 +476,11 @@ void Layout::LinearProgram::make_basic_column(unsigned c, unsigned r)
                        }
 
                        float scale = columns[i].values[r]/columns[c].values[r];
-                       
+
+                       columns[i].values[r] = scale;
                        for(unsigned j=0; j<columns[i].values.size(); ++j)
-                       {
-                               if(j==r)
-                                       columns[i].values[j] = scale;
-                               else
+                               if(j!=r)
                                        columns[i].values[j] -= scale*columns[c].values[j];
-                       }
                }
 
        columns[c].basic = r;