It still does a lot of unnecessary layout updates, but seems to work at
least in basic cases.
- 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);
}
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();
{
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
return;
/* Set up a linear program to solve the constraints. The program matrix has
float weight = slots.size();
for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
{
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.
{
// Prevent the widget from going past the container's low edge.
row.back() = margin.*(ptrs.low_margin);
}
row.back() = margin.*(ptrs.low_margin);
}
{
// Prevent the widget from going past the container's high edge.
LinearProgram::Row row = linprog.add_row();
{
// Prevent the widget from going past the container's high edge.
LinearProgram::Row row = linprog.add_row();
if(!linprog.solve())
return;
if(!linprog.solve())
return;
- 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);
+ 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);
+ }
if(autosize_geom.w<=geom.w && autosize_geom.h<=geom.h)
widget.set_geometry(geom);
else
if(autosize_geom.w<=geom.w && autosize_geom.h<=geom.h)
widget.set_geometry(geom);
else
+ {
+ layout.container->signal_autosize_changed.emit();
void autosize_changed();
};
void autosize_changed();
};
+ enum SolveMode
+ {
+ UPDATE,
+ AUTOSIZE
+ };
+
class LinearProgram;
struct Pointers;
class LinearProgram;
struct Pointers;
Sides margin;
unsigned row_spacing;
unsigned col_spacing;
Sides margin;
unsigned row_spacing;
unsigned col_spacing;
+ Geometry autosize_geom;
static Pointers pointers[2];
static Pointers pointers[2];
void set_expand(Widget &, bool, bool);
void update();
void set_expand(Widget &, bool, bool);
void update();
- void solve_constraints(int);
+ void solve_constraints(int, SolveMode);
+void Panel::autosize()
+{
+ if(layout)
+ layout->autosize();
+}
+
Panel::Child *Panel::create_child(Widget *wdg)
{
return new Child(*this, wdg);
Panel::Child *Panel::create_child(Widget *wdg)
{
return new Child(*this, wdg);
void Panel::on_child_added(Widget &wdg)
{
if(layout)
void Panel::on_child_added(Widget &wdg)
{
if(layout)
+ signal_autosize_changed.emit();
+ }
}
void Panel::on_child_removed(Widget &wdg)
{
if(layout)
}
void Panel::on_child_removed(Widget &wdg)
{
if(layout)
layout->remove_widget(wdg);
layout->remove_widget(wdg);
+ signal_autosize_changed.emit();
+ }
}
void Panel::set_pointer_focus(Widget *wdg)
}
void Panel::set_pointer_focus(Widget *wdg)
virtual const char *get_class() const { return "panel"; }
void set_layout(Layout *);
virtual const char *get_class() const { return "panel"; }
void set_layout(Layout *);
+ virtual void autosize();
protected:
virtual Child *create_child(Widget *);
protected:
virtual Child *create_child(Widget *);