]> git.tdb.fi Git - libs/gltk.git/blobdiff - source/layout.cpp
Don't let input events that are passed to widgets go to other consumers
[libs/gltk.git] / source / layout.cpp
index f89e407cf7f4d3b61d08831c0f71693b68b27760..d3d015f7305c7ddb70a024c4884ee88cbf3711f2 100644 (file)
@@ -110,6 +110,28 @@ void Layout::set_margin(const Sides &m)
                update();
 }
 
+void Layout::set_spacing(unsigned s)
+{
+       row_spacing = s;
+       col_spacing = s;
+       if(container)
+               update();
+}
+
+void Layout::set_row_spacing(unsigned s)
+{
+       row_spacing = s;
+       if(container)
+               update();
+}
+
+void Layout::set_column_spacing(unsigned s)
+{
+       col_spacing = s;
+       if(container)
+               update();
+}
+
 void Layout::add_widget(Widget &wdg)
 {
        if(!container)
@@ -181,7 +203,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");
@@ -194,11 +216,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);
@@ -221,19 +255,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<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();
-       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
@@ -244,8 +286,17 @@ void Layout::solve_constraints(int dir)
        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.
@@ -255,6 +306,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();
@@ -264,6 +316,16 @@ void Layout::solve_constraints(int dir)
                        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. */
@@ -289,24 +351,37 @@ void Layout::solve_constraints(int dir)
                                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));
                        }
        }
 
        if(!linprog.solve())
                return;
 
-       for(list<Slot *>::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<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);
+               }
        }
 }
 
 
 Layout::Constraint::Constraint(ConstraintType t, Slot &s):
        type(t),
-       target(s)
+       target(s),
+       spacing(-1)
 { }
 
 
@@ -336,7 +411,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();
+       }
 }