]> git.tdb.fi Git - libs/gltk.git/blobdiff - source/layout.cpp
Properly filter out duplicate constraints
[libs/gltk.git] / source / layout.cpp
index d3d015f7305c7ddb70a024c4884ee88cbf3711f2..1ffbcdaf87e0a7176176e6e75518c62323fda184 100644 (file)
@@ -84,6 +84,7 @@ Layout::Pointers Layout::pointers[2] =
 
 Layout::Layout():
        container(0),
+       n_active_slots(0),
        margin(8),
        row_spacing(5),
        col_spacing(4)
@@ -140,8 +141,8 @@ void Layout::add_widget(Widget &wdg)
        Slot *slot = create_slot(wdg);
        for(list<Constraint>::iterator i=slot->constraints.begin(); i!=slot->constraints.end(); ++i)
                i->target.constraints.push_back(Constraint(complement(i->type), *slot));
-       slot->index = slots.size();
        slots.push_back(slot);
+       update_slot_indices();
        if(container)
                update();
 }
@@ -180,6 +181,18 @@ Layout::Slot *Layout::create_slot(Widget &wdg)
        return new Slot(*this, wdg);
 }
 
+void Layout::update_slot_indices()
+{
+       n_active_slots = 0;
+       for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
+       {
+               if((*i)->widget.is_visible())
+                       (*i)->index = n_active_slots++;
+               else
+                       (*i)->index = -1;
+       }
+}
+
 Layout::Slot &Layout::get_slot_for_widget(Widget &wdg)
 {
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
@@ -282,10 +295,13 @@ void Layout::solve_constraints(int dir, SolveMode mode)
        five columns for each widget, and one constant column.  The first and second
        columns of a widget are its position and dimension, respectively.  The
        remaining three are slack columns; see below for their purposes. */
-       LinearProgram linprog(slots.size()*5+1);
+       LinearProgram linprog(n_active_slots*5+1);
        float weight = slots.size();
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
        {
+               if((*i)->index<0)
+                       continue;
+
                LinearProgram::Row objective = linprog.get_objective_row();
                if(mode==AUTOSIZE)
                {
@@ -327,29 +343,29 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                }
 
                {
-                       /* Only allow the widget's dimension to increase.  The geometry has
-                       previously been set to the smallest allowable size. */
+                       /* Don't allow the widget's dimension to get below that determined
+                       by autosizing. */
                        LinearProgram::Row row = linprog.add_row();
                        row[(*i)->index*5+1] = 1;
                        row[(*i)->index*5+4] = -1;
                        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. */
+               /* Add rows for user-defined constraints.  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)
+                       if(j->target.index>(*i)->index && (j->type&1)==dir)
                        {
                                LinearProgram::Row row = linprog.add_row();
+                               float polarity = ((j->type&SELF_DIM) ? -1 : 1);
                                if(j->type&SELF_POS)
-                                       row[(*i)->index*5] = 1;
+                                       row[(*i)->index*5] = polarity;
                                if(j->type&SELF_DIM)
-                                       row[(*i)->index*5+1] = 1;
+                                       row[(*i)->index*5+1] = polarity;
                                if(j->type&TARGET_POS)
-                                       row[j->target.index*5] = -1;
+                                       row[j->target.index*5] = -polarity;
                                if(j->type&TARGET_DIM)
-                                       row[j->target.index*5+1] = -1;
+                                       row[j->target.index*5+1] = -polarity;
                                if(j->type&SPACING)
                                        row.back() = (j->spacing>=0 ? j->spacing : this->*(ptrs.spacing));
                        }
@@ -362,18 +378,20 @@ void Layout::solve_constraints(int dir, SolveMode mode)
        {
                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));
-               }
+                       if((*i)->index>=0)
+                       {
+                               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);
-               }
+                       if((*i)->index>=0)
+                       {
+                               (*i)->geom.*(ptrs.pos) = linprog.get_variable((*i)->index*5);
+                               (*i)->geom.*(ptrs.dim) = linprog.get_variable((*i)->index*5+1);
+                       }
        }
 }
 
@@ -398,6 +416,7 @@ Layout::Slot::Slot(Layout &l, Widget &w):
 {
        vert_pack.gravity = 1;
        widget.signal_autosize_changed.connect(sigc::mem_fun(this, &Slot::autosize_changed));
+       widget.signal_visibility_changed.connect(sigc::mem_fun(this, &Slot::visibility_changed));
        widget.autosize();
        autosize_geom = widget.get_geometry();
 }
@@ -407,6 +426,9 @@ void Layout::Slot::autosize_changed()
        widget.autosize();
        autosize_geom = widget.get_geometry();
 
+       if(!widget.is_visible())
+               return;
+
        // 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);
@@ -417,6 +439,16 @@ void Layout::Slot::autosize_changed()
        }
 }
 
+void Layout::Slot::visibility_changed(bool v)
+{
+       layout.update_slot_indices();
+       if(v)
+       {
+               layout.container->signal_autosize_changed.emit();
+               layout.update();
+       }
+}
+
 
 Layout::LinearProgram::LinearProgram(unsigned s):
        n_columns(s),
@@ -497,11 +529,12 @@ void Layout::LinearProgram::prepare_columns()
        /* See if any variables are already basic.  A basic variable must only have
        a nonzero coefficient on one row, and its product with the constant column
        must not be negative.  Only one variable can be basic for any given row. */
-       vector<float> basic_coeff(n_rows, 0.0f);
+       vector<float> obj_coeff(n_rows, 0.0f);
+       vector<float> row_coeff(n_rows, 1.0f);
        const vector<float> &constants = columns.back().values;
        for(vector<Column>::iterator i=columns.begin(); i!=columns.end(); ++i)
        {
-               if(i->values.size()>=2 && i->values.back()!=0.0f && (constants.size()<i->values.size() || i->values.back()*constants[i->values.size()-1]>=0.0f) && basic_coeff[i->values.size()-1]==0.0f)
+               if(i->values.size()>=2 && i->values.back()!=0.0f && (constants.size()<i->values.size() || i->values.back()*constants[i->values.size()-1]>=0.0f) && obj_coeff[i->values.size()-1]==0.0f)
                {
                        bool basic = true;
                        for(unsigned j=1; (basic && j+1<i->values.size()); ++j)
@@ -509,7 +542,8 @@ void Layout::LinearProgram::prepare_columns()
                        if(basic)
                        {
                                i->basic = i->values.size()-1;
-                               basic_coeff[i->basic] = -i->values.front()/i->values.back();
+                               row_coeff[i->basic] = 1.0f/i->values.back();
+                               obj_coeff[i->basic] = -i->values.front();
                                i->values.clear();
                        }
                }
@@ -520,7 +554,10 @@ void Layout::LinearProgram::prepare_columns()
                if(!i->values.empty())
                {
                        for(unsigned j=0; j<i->values.size(); ++j)
-                               i->values.front() += basic_coeff[j]*i->values[j];
+                       {
+                               i->values[j] *= row_coeff[j];
+                               i->values.front() += obj_coeff[j]*i->values[j];
+                       }
                }
 }