From e291dcf478052c771d85089409f9bc22a4c8ab93 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 27 Nov 2012 23:58:07 +0200 Subject: [PATCH] Add autosizing for panels It still does a lot of unnecessary layout updates, but seems to work at least in basic cases. --- source/layout.cpp | 51 ++++++++++++++++++++++++++++++++++++++--------- source/layout.h | 10 +++++++++- source/panel.cpp | 12 +++++++++++ source/panel.h | 1 + 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/source/layout.cpp b/source/layout.cpp index f89e407..ccd0283 100644 --- a/source/layout.cpp +++ b/source/layout.cpp @@ -221,19 +221,27 @@ void Layout::set_expand(Widget &wdg, bool h, bool v) void Layout::update() { - solve_constraints(HORIZONTAL); - solve_constraints(VERTICAL); + solve_constraints(HORIZONTAL, UPDATE); + solve_constraints(VERTICAL, UPDATE); for(list::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(); - if(geom.*(ptrs.dim)::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. @@ -255,6 +272,7 @@ void Layout::solve_constraints(int dir) row.back() = margin.*(ptrs.low_margin); } + if(mode==UPDATE) { // Prevent the widget from going past the container's high edge. LinearProgram::Row row = linprog.add_row(); @@ -296,10 +314,22 @@ void Layout::solve_constraints(int dir) if(!linprog.solve()) return; - for(list::iterator i=slots.begin(); i!=slots.end(); ++i) + if(mode==AUTOSIZE) { - (*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::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::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); + } } } @@ -336,7 +366,10 @@ void Layout::Slot::autosize_changed() if(autosize_geom.w<=geom.w && autosize_geom.h<=geom.h) widget.set_geometry(geom); else + { + layout.container->signal_autosize_changed.emit(); layout.update(); + } } diff --git a/source/layout.h b/source/layout.h index cf63538..cbd763e 100644 --- a/source/layout.h +++ b/source/layout.h @@ -113,6 +113,12 @@ protected: void autosize_changed(); }; + enum SolveMode + { + UPDATE, + AUTOSIZE + }; + class LinearProgram; struct Pointers; @@ -121,6 +127,7 @@ protected: Sides margin; unsigned row_spacing; unsigned col_spacing; + Geometry autosize_geom; static Pointers pointers[2]; @@ -146,9 +153,10 @@ public: void set_expand(Widget &, bool, bool); void update(); + void autosize(); protected: - void solve_constraints(int); + void solve_constraints(int, SolveMode); }; } // namespace GLtk diff --git a/source/panel.cpp b/source/panel.cpp index 7876120..91e30cd 100644 --- a/source/panel.cpp +++ b/source/panel.cpp @@ -39,6 +39,12 @@ void Panel::set_layout(Layout *l) layout = l; } +void Panel::autosize() +{ + if(layout) + layout->autosize(); +} + Panel::Child *Panel::create_child(Widget *wdg) { return new Child(*this, wdg); @@ -160,13 +166,19 @@ void Panel::on_geometry_change() void Panel::on_child_added(Widget &wdg) { if(layout) + { layout->add_widget(wdg); + signal_autosize_changed.emit(); + } } void Panel::on_child_removed(Widget &wdg) { if(layout) + { layout->remove_widget(wdg); + signal_autosize_changed.emit(); + } } void Panel::set_pointer_focus(Widget *wdg) diff --git a/source/panel.h b/source/panel.h index d3d1f79..a6a89c5 100644 --- a/source/panel.h +++ b/source/panel.h @@ -61,6 +61,7 @@ public: virtual const char *get_class() const { return "panel"; } void set_layout(Layout *); + virtual void autosize(); protected: virtual Child *create_child(Widget *); -- 2.43.0