X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flayout.cpp;h=34afd7284a35878b409dd95f8b4bc34ebd6c4299;hb=2ea95d42a147747c79cade5c9b7f299d47367be7;hp=b4c3a0eccd38883ac83beb7b863a62b6d3a52b6b;hpb=6549eff66171d53be91ea7ba3f23339812ef6cad;p=libs%2Fgltk.git diff --git a/source/layout.cpp b/source/layout.cpp index b4c3a0e..34afd72 100644 --- a/source/layout.cpp +++ b/source/layout.cpp @@ -1,3 +1,4 @@ +#include #include #include "container.h" #include "layout.h" @@ -44,10 +45,13 @@ public: Row add_row(); Row operator[](unsigned); - Row get_object_row(); - bool solve(); + Row get_objective_row(); float get_variable(unsigned); + bool solve(); private: + void prepare_columns(); + void add_artificial_variables(); + void remove_artificial_variables(); unsigned find_minimal_ratio(unsigned); void make_basic_column(unsigned, unsigned); bool pivot(); @@ -217,18 +221,11 @@ void Layout::set_expand(Widget &wdg, bool h, bool v) void Layout::update() { - for(list::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::iterator i=slots.begin(); i!=slots.end(); ++i) (*i)->widget.set_geometry((*i)->geom); - } void Layout::solve_constraints(int dir) @@ -243,8 +240,8 @@ void Layout::solve_constraints(int dir) float weight = slots.size(); for(list::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 +266,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::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 +287,6 @@ void Layout::solve_constraints(int dir) if(j->type&SPACING) row.back() = this->*(ptrs.spacing); } - } } if(!linprog.solve()) @@ -324,11 +319,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 +357,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); } @@ -365,8 +369,10 @@ float Layout::LinearProgram::get_variable(unsigned i) if(i+1>=n_columns) throw out_of_range("LinearProgram::get_variable"); - unsigned r = columns[i].basic; - return columns.back().values[r]; + if(unsigned r = columns[i].basic) + return columns.back().values[r]; + else + return 0; } bool Layout::LinearProgram::solve() @@ -378,30 +384,9 @@ bool Layout::LinearProgram::solve() objective variable is kept implicit, as it would never change during the execution of the algorithm. */ - /* Force all columns fully into existence and relocate objective row to - bottom in preparation of phase 1. A new objective row is calculated by - pricing out the constraint rows. */ - for(vector::iterator i=columns.begin(); i!=columns.end(); ++i) - { - float objective = i->values.front(); - i->values.front() = 0.0f; - for(vector::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; - } + prepare_columns(); - /* Create artificial variables for phase 1. This ensures that each row has - a basic variable associated with it. The original objective row already - contains the implicit objective variable, which is basic. */ - columns.resize(n_columns+n_rows-1); - columns.back() = columns[n_columns-1]; - columns[n_columns-1].values.clear(); - for(unsigned i=1; i basic_coeff(n_rows, 0.0f); + const vector &constants = columns.back().values; + for(vector::iterator i=columns.begin(); i!=columns.end(); ++i) + { + if(i->values.size()>=2 && i->values.back()!=0.0f && (constants.size()values.size() || i->values.back()*constants[i->values.size()-1]>=0.0f) && basic_coeff[i->values.size()-1]==0.0f) + { + bool basic = true; + for(unsigned j=1; (basic && j+1values.size()); ++j) + basic = (i->values[j]==0.0f); + if(basic) + { + i->basic = i->values.size()-1; + basic_coeff[i->basic] = -i->values.front()/i->values.back(); + i->values.clear(); + } + } + } + + // Price out the newly-created basic variables. + for(vector::iterator i=columns.begin(); i!=columns.end(); ++i) + if(!i->values.empty()) + { + for(unsigned j=0; jvalues.size(); ++j) + i->values.front() += basic_coeff[j]*i->values[j]; + } +} + +void Layout::LinearProgram::add_artificial_variables() +{ + vector artificial_rows(n_rows-1); + for(unsigned i=0; i::iterator i=columns.begin(); i!=columns.end(); ++i) + if(i->basic) + artificial_rows[i->basic-1] = 0; + artificial_rows.erase(std::remove(artificial_rows.begin(), artificial_rows.end(), 0), artificial_rows.end()); + + /* Force all non-basic columns fully into existence and relocate objective + row to bottom in preparation of phase 1. A new objective row is calculated + by pricing out the constraint rows. */ + for(vector::iterator i=columns.begin(); i!=columns.end(); ++i) + if(!i->basic) + { + float objective = 0.0f; + if(!i->values.empty()) + { + objective = i->values.front(); + i->values.front() = 0.0f; + for(vector::iterator j=artificial_rows.begin(); j!=artificial_rows.end(); ++j) + if(*jvalues.size()) + i->values.front() += i->values[*j]; + } + i->values.resize(n_rows+1, 0.0f); + i->values.back() = objective; + } + + if(artificial_rows.empty()) + return; + + /* Create artificial variables for phase 1. This ensures that each row has + a basic variable associated with it. The original objective row already + contains the implicit objective variable, which is basic. */ + columns.resize(n_columns+artificial_rows.size()); + columns.back() = columns[n_columns-1]; + columns[n_columns-1].values.clear(); + for(unsigned i=0; ivalues.front() = i->values.back(); i->values.pop_back(); } - - // Solve the phase 2 problem. We already know it to be feasible. - while(pivot()) ; - - solved = true; - - return true; } unsigned Layout::LinearProgram::find_minimal_ratio(unsigned c) @@ -438,7 +519,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::infinity(); @@ -453,7 +534,7 @@ unsigned Layout::LinearProgram::find_minimal_ratio(unsigned c) row = i; } } - + return row; } @@ -472,14 +553,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