]> git.tdb.fi Git - libs/gltk.git/blobdiff - source/layout.cpp
Add lexical conversion for the centering constraints
[libs/gltk.git] / source / layout.cpp
index b8d8fb7d23ad6b196d68550c71f7de6db6f29205..1cf35c722a3a95476532ec1d35898aa7a0e5b903 100644 (file)
@@ -211,22 +211,31 @@ void Layout::remove_widget(Widget &wdg)
 void Layout::update_slot_indices()
 {
        n_active_slots = 0;
+       unsigned n_floating = 0;
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
        {
                if((*i)->widget.is_visible() || (*i)->ghost)
+               {
                        (*i)->index = n_active_slots++;
+                       if((*i)->floating)
+                               ++n_floating;
+               }
                else
                        (*i)->index = -1;
        }
 
-       n_slack_vars[0] = 0;
-       n_slack_vars[1] = 0;
+       n_slack_vars[0] = n_floating*2;
+       n_slack_vars[1] = n_floating*2;
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
                if((*i)->index>=0)
                {
-                       for(unsigned j=0; j<2; ++j)
-                               if(((*i)->*(pointers[j].packing)).gravity==0)
-                                       n_slack_vars[j] += 2;
+                       if(!(*i)->floating)
+                       {
+                               for(unsigned j=0; j<2; ++j)
+                                       if(((*i)->*(pointers[j].packing)).gravity==0)
+                                               n_slack_vars[j] += 2;
+                       }
+
                        for(list<Constraint>::iterator j=(*i)->constraints.begin(); j!=(*i)->constraints.end(); ++j)
                                if(j->target.index>(*i)->index && (j->type&SLACK))
                                        ++n_slack_vars[j->type&1];
@@ -250,7 +259,7 @@ Layout::ConstraintType Layout::complement(ConstraintType type)
 void Layout::create_constraint(Widget &src, ConstraintType type, Widget &tgt, int sp)
 {
        if(&src==&tgt)
-               throw invalid_argument("&src==&tgt");
+               throw invalid_argument("Layout::create_constraint");
 
        Slot &src_slot = get_slot_for_widget(src);
        Slot &tgt_slot = get_slot_for_widget(tgt);
@@ -312,6 +321,16 @@ void Layout::set_ghost(Widget &wdg, bool g)
        }
 }
 
+void Layout::set_floating(Widget &wdg, bool f)
+{
+       Slot &slot = get_slot_for_widget(wdg);
+
+       slot.floating = f;
+
+       update_slot_indices();
+       update();
+}
+
 void Layout::update()
 {
        solve_constraints(HORIZONTAL, UPDATE);
@@ -343,7 +362,7 @@ void Layout::solve_constraints(int dir, SolveMode mode)
        columns of a widget are its position and dimension, respectively.  The
        remaining three are slack columns; see below for their purposes. */
        LinearProgram linprog(n_active_slots*5+n_slack_vars[dir]+1);
-       float weight = slots.size();
+       float weight = slots.size()+1;
        unsigned k = n_active_slots*5;
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
        {
@@ -358,7 +377,8 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                }
                else
                {
-                       objective[(*i)->index*5] = ((*i)->*(ptrs.packing)).gravity/weight;
+                       if(!(*i)->floating)
+                               objective[(*i)->index*5] = ((*i)->*(ptrs.packing)).gravity/weight;
                        objective[(*i)->index*5+1] = (((*i)->*(ptrs.packing)).expand ? weight : -1);
                }
 
@@ -380,18 +400,24 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                        row.back() = geom.*(ptrs.dim)-margin.*(ptrs.high_margin);
                }
 
-               if(((*i)->*(ptrs.packing)).gravity==0)
+               if((*i)->floating || ((*i)->*(ptrs.packing)).gravity==0)
                {
-                       /* Try to keep the widget as close to the center of the container
-                       as possible.  Since linear programs can't express absolute values
-                       directly, use two opposing slack variables that are optimized for
-                       a low value. */
+                       /* Try to keep the widget as close to a target position as possible.
+                       Since linear programs can't express absolute values directly, use two
+                       opposing slack variables that are optimized for a low value. */
+                       float a = ((*i)->*(ptrs.packing)).gravity*0.5+0.5;
                        LinearProgram::Row row = linprog.add_row();
                        row[(*i)->index*5] = 1;
-                       row[(*i)->index*5+1] = 0.5;
+                       row[(*i)->index*5+1] = a;
                        row[k] = 1;
                        row[k+1] = -1;
-                       row.back() = geom.*(ptrs.dim)/2;
+                       if((*i)->floating)
+                       {
+                               const Geometry &cgeom = (*i)->widget.get_geometry();
+                               row.back() = cgeom.*(ptrs.pos)+cgeom.*(ptrs.dim)*a;
+                       }
+                       else
+                               row.back() = geom.*(ptrs.dim)/2;
                        objective[k] = -1;
                        objective[k+1] = -1;
                        k += 2;
@@ -413,14 +439,15 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                        {
                                LinearProgram::Row row = linprog.add_row();
                                float polarity = ((j->type&SELF_DIM) ? -1 : 1);
+                               float dim_weight = ((j->type&HALF_DIM) ? 0.5f : 1);
                                if(j->type&SELF_POS)
                                        row[(*i)->index*5] = polarity;
                                if(j->type&SELF_DIM)
-                                       row[(*i)->index*5+1] = polarity;
+                                       row[(*i)->index*5+1] = polarity*dim_weight;
                                if(j->type&TARGET_POS)
                                        row[j->target.index*5] = -polarity;
                                if(j->type&TARGET_DIM)
-                                       row[j->target.index*5+1] = -polarity;
+                                       row[j->target.index*5+1] = -polarity*dim_weight;
                                if(j->type&SPACING)
                                        row.back() = (j->spacing>=0 ? j->spacing : this->*(ptrs.spacing));
                                if(j->type&SLACK)
@@ -470,13 +497,13 @@ Layout::Slot::Slot(Layout &l, Widget &w):
        layout(l),
        index(0),
        widget(w),
-       ghost(false)
+       ghost(false),
+       floating(false)
 {
        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();
+       widget.autosize(autosize_geom);
 }
 
 void Layout::Slot::autosize_changed()
@@ -600,10 +627,14 @@ void operator>>(const LexicalConverter &conv, Layout::ConstraintType &ctype)
                ctype = Layout::FAR_LEFT_OF;
        else if(str=="ALIGN_TOP")
                ctype = Layout::ALIGN_TOP;
+       else if(str=="ALIGN_VCENTER")
+               ctype = Layout::ALIGN_VCENTER;
        else if(str=="ALIGN_BOTTOM")
                ctype = Layout::ALIGN_BOTTOM;
        else if(str=="ALIGN_RIGHT")
                ctype = Layout::ALIGN_RIGHT;
+       else if(str=="ALIGN_HCENTER")
+               ctype = Layout::ALIGN_HCENTER;
        else if(str=="ALIGN_LEFT")
                ctype = Layout::ALIGN_LEFT;
        else if(str=="COPY_WIDTH")