X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Flayout.cpp;h=e9f9b40d0e9e0cced67238e62f2b0d8b480754d2;hb=a6733b168083926ccc11eb3896642348b13817a2;hp=d5437f0b0a29ed04c1ce000534174fd0d9b9fa12;hpb=8fc5cb226f0c2b36298f51b3d2501b04ebb11b8a;p=libs%2Fgltk.git diff --git a/source/layout.cpp b/source/layout.cpp index d5437f0..e9f9b40 100644 --- a/source/layout.cpp +++ b/source/layout.cpp @@ -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::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::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::iterator i=slots.begin(); i!=slots.end(); ++i) @@ -203,7 +216,7 @@ Layout::ConstraintType Layout::complement(ConstraintType type) return type; } -void Layout::add_constraint(Widget &src, ConstraintType type, Widget &tgt) +void Layout::create_constraint(Widget &src, ConstraintType type, Widget &tgt, int sp) { if(&src==&tgt) throw invalid_argument("&src==&tgt"); @@ -216,11 +229,23 @@ void Layout::add_constraint(Widget &src, ConstraintType type, Widget &tgt) return; src_slot.constraints.push_back(Constraint(type, tgt_slot)); + src_slot.constraints.back().spacing = sp; tgt_slot.constraints.push_back(Constraint(complement(type), src_slot)); + tgt_slot.constraints.back().spacing = sp; update(); } +void Layout::add_constraint(Widget &src, ConstraintType type, Widget &tgt) +{ + create_constraint(src, type, tgt, -1); +} + +void Layout::add_constraint(Widget &src, ConstraintType type, Widget &tgt, unsigned spacing) +{ + create_constraint(src, type, tgt, spacing); +} + void Layout::set_gravity(Widget &wdg, int h, int v) { Slot &slot = get_slot_for_widget(wdg); @@ -270,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::iterator i=slots.begin(); i!=slots.end(); ++i) { + if((*i)->index<0) + continue; + LinearProgram::Row objective = linprog.get_objective_row(); if(mode==AUTOSIZE) { @@ -304,6 +332,16 @@ void Layout::solve_constraints(int dir, SolveMode mode) row.back() = geom.*(ptrs.dim)-margin.*(ptrs.high_margin); } + if(((*i)->*(ptrs.packing)).gravity==0) + { + /* This forces the widget's distance from the left and right edge of + the container to be equal. It's a bit of a hack, but more time and + thought is needed for a better solution. */ + LinearProgram::Row row = linprog.add_row(); + row[(*i)->index*5+2] = 1; + row[(*i)->index*5+3] = -1; + } + { /* Only allow the widget's dimension to increase. The geometry has previously been set to the smallest allowable size. */ @@ -317,7 +355,7 @@ void Layout::solve_constraints(int dir, SolveMode mode) 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) + if(j->target.index>=0 && (j->type&1)==dir && j->type!=BELOW && j->type!=LEFT_OF) { LinearProgram::Row row = linprog.add_row(); if(j->type&SELF_POS) @@ -329,7 +367,7 @@ void Layout::solve_constraints(int dir, SolveMode mode) if(j->type&TARGET_DIM) row[j->target.index*5+1] = -1; if(j->type&SPACING) - row.back() = this->*(ptrs.spacing); + row.back() = (j->spacing>=0 ? j->spacing : this->*(ptrs.spacing)); } } @@ -340,25 +378,28 @@ void Layout::solve_constraints(int dir, SolveMode mode) { autosize_geom.*(ptrs.dim) = 0; for(list::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::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); + } } } Layout::Constraint::Constraint(ConstraintType t, Slot &s): type(t), - target(s) + target(s), + spacing(-1) { } @@ -375,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(); } @@ -384,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); @@ -394,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), @@ -474,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 basic_coeff(n_rows, 0.0f); + vector obj_coeff(n_rows, 0.0f); + vector row_coeff(n_rows, 1.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) + if(i->values.size()>=2 && i->values.back()!=0.0f && (constants.size()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+1values.size()); ++j) @@ -486,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(); } } @@ -497,7 +554,10 @@ void Layout::LinearProgram::prepare_columns() if(!i->values.empty()) { for(unsigned j=0; jvalues.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]; + } } }