]> git.tdb.fi Git - libs/gltk.git/blobdiff - source/layout.cpp
Replace the derived layout classes with a more flexible design
[libs/gltk.git] / source / layout.cpp
index e9f9b40d0e9e0cced67238e62f2b0d8b480754d2..c41dcb87b68172236b1bb67155b48990ca79609e 100644 (file)
@@ -1,5 +1,6 @@
 #include <algorithm>
 #include <limits>
+#include "arrangement.h"
 #include "container.h"
 #include "layout.h"
 #include "widget.h"
@@ -88,7 +89,10 @@ Layout::Layout():
        margin(8),
        row_spacing(5),
        col_spacing(4)
-{ }
+{
+       n_slack_constraints[0] = 0;
+       n_slack_constraints[1] = 0;
+}
 
 Layout::~Layout()
 {
@@ -133,16 +137,45 @@ void Layout::set_column_spacing(unsigned s)
                update();
 }
 
+void Layout::push_arrangement(Arrangement &arr)
+{
+       arrangement_stack.push_back(&arr);
+}
+
+Arrangement *Layout::get_arrangement() const
+{
+       if(arrangement_stack.empty())
+               return 0;
+       else
+               return arrangement_stack.back();
+}
+
+void Layout::pop_arrangement(Arrangement &arr)
+{
+       list<Arrangement *>::iterator begin = find(arrangement_stack.begin(), arrangement_stack.end(), &arr);
+       if(begin==arrangement_stack.end())
+               return;
+
+       while(1)
+       {
+               Arrangement *top = arrangement_stack.back();
+               arrangement_stack.pop_back();
+               if(!arrangement_stack.empty())
+                       arrangement_stack.back()->arrange(*top);
+               if(top==&arr)
+                       break;
+       }
+}
+
 void Layout::add_widget(Widget &wdg)
 {
        if(!container)
                throw logic_error("!container");
 
-       Slot *slot = create_slot(wdg);
-       for(list<Constraint>::iterator i=slot->constraints.begin(); i!=slot->constraints.end(); ++i)
-               i->target.constraints.push_back(Constraint(complement(i->type), *slot));
-       slots.push_back(slot);
+       slots.push_back(new Slot(*this, wdg));
        update_slot_indices();
+       if(!arrangement_stack.empty())
+               arrangement_stack.back()->arrange(wdg);
        if(container)
                update();
 }
@@ -167,20 +200,12 @@ void Layout::remove_widget(Widget &wdg)
                        delete *i;
                        slots.erase(i);
 
-                       unsigned n = 0;
-                       for(i=slots.begin(); i!=slots.end(); ++i, ++n)
-                               (*i)->index = n;
-
+                       update_slot_indices();
                        update();
                        return;
                }
 }
 
-Layout::Slot *Layout::create_slot(Widget &wdg)
-{
-       return new Slot(*this, wdg);
-}
-
 void Layout::update_slot_indices()
 {
        n_active_slots = 0;
@@ -191,6 +216,16 @@ void Layout::update_slot_indices()
                else
                        (*i)->index = -1;
        }
+
+       n_slack_constraints[0] = 0;
+       n_slack_constraints[1] = 0;
+       for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
+               if((*i)->index>=0)
+               {
+                       for(list<Constraint>::iterator j=(*i)->constraints.begin(); j!=(*i)->constraints.end(); ++j)
+                               if(j->target.index>(*i)->index && (j->type&SLACK))
+                                       ++n_slack_constraints[j->type&1];
+               }
 }
 
 Layout::Slot &Layout::get_slot_for_widget(Widget &wdg)
@@ -204,16 +239,7 @@ Layout::Slot &Layout::get_slot_for_widget(Widget &wdg)
 
 Layout::ConstraintType Layout::complement(ConstraintType type)
 {
-       if(type==RIGHT_OF)
-               return LEFT_OF;
-       else if(type==LEFT_OF)
-               return RIGHT_OF;
-       else if(type==ABOVE)
-               return BELOW;
-       else if(type==BELOW)
-               return ABOVE;
-       else
-               return type;
+       return static_cast<ConstraintType>((type&~(SELF_MASK|TARGET_MASK)) | ((type&SELF_MASK)<<2) | ((type&TARGET_MASK)>>2));
 }
 
 void Layout::create_constraint(Widget &src, ConstraintType type, Widget &tgt, int sp)
@@ -233,6 +259,7 @@ void Layout::create_constraint(Widget &src, ConstraintType type, Widget &tgt, in
        tgt_slot.constraints.push_back(Constraint(complement(type), src_slot));
        tgt_slot.constraints.back().spacing = sp;
 
+       update_slot_indices();
        update();
 }
 
@@ -295,7 +322,7 @@ 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(n_active_slots*5+1);
+       LinearProgram linprog(n_active_slots*5+n_slack_constraints[dir]+1);
        float weight = slots.size();
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
        {
@@ -343,31 +370,34 @@ void Layout::solve_constraints(int dir, SolveMode mode)
                }
 
                {
-                       /* Only allow the widget's dimension to increase.  The geometry has
-                       previously been set to the smallest allowable size. */
+                       /* Don't allow the widget's dimension to get below that determined
+                       by autosizing. */
                        LinearProgram::Row row = linprog.add_row();
                        row[(*i)->index*5+1] = 1;
                        row[(*i)->index*5+4] = -1;
                        row.back() = (*i)->autosize_geom.*(ptrs.dim);
                }
 
-               /* Add rows for user-defined constraints.  Below/above and left/right of
-               constraints are always added in pairs, so it's only necessary to create a
-               row for one half. */
+               /* Add rows for user-defined constraints.  Constraints are always added
+               in pairs, so it's only necessary to create a row for one half. */
+               unsigned k = n_active_slots*5;
                for(list<Constraint>::iterator j=(*i)->constraints.begin(); j!=(*i)->constraints.end(); ++j)
-                       if(j->target.index>=0 && (j->type&1)==dir && j->type!=BELOW && j->type!=LEFT_OF)
+                       if(j->target.index>(*i)->index && (j->type&1)==dir)
                        {
                                LinearProgram::Row row = linprog.add_row();
+                               float polarity = ((j->type&SELF_DIM) ? -1 : 1);
                                if(j->type&SELF_POS)
-                                       row[(*i)->index*5] = 1;
+                                       row[(*i)->index*5] = polarity;
                                if(j->type&SELF_DIM)
-                                       row[(*i)->index*5+1] = 1;
+                                       row[(*i)->index*5+1] = polarity;
                                if(j->type&TARGET_POS)
-                                       row[j->target.index*5] = -1;
+                                       row[j->target.index*5] = -polarity;
                                if(j->type&TARGET_DIM)
-                                       row[j->target.index*5+1] = -1;
+                                       row[j->target.index*5+1] = -polarity;
                                if(j->type&SPACING)
                                        row.back() = (j->spacing>=0 ? j->spacing : this->*(ptrs.spacing));
+                               if(j->type&SLACK)
+                                       row[k++] = -1;
                        }
        }