]> git.tdb.fi Git - libs/gltk.git/commitdiff
Add some classes for automatically creating basic layouts
authorMikko Rasa <tdb@tdb.fi>
Fri, 4 Mar 2011 20:25:55 +0000 (20:25 +0000)
committerMikko Rasa <tdb@tdb.fi>
Fri, 4 Mar 2011 20:25:55 +0000 (20:25 +0000)
Some enhancements to the base Layout class

source/column.cpp [new file with mode: 0644]
source/column.h [new file with mode: 0644]
source/grid.cpp [new file with mode: 0644]
source/grid.h [new file with mode: 0644]
source/layout.cpp
source/layout.h
source/mixedrows.cpp [new file with mode: 0644]
source/mixedrows.h [new file with mode: 0644]
source/row.cpp [new file with mode: 0644]
source/row.h [new file with mode: 0644]

diff --git a/source/column.cpp b/source/column.cpp
new file mode 100644 (file)
index 0000000..5b86660
--- /dev/null
@@ -0,0 +1,29 @@
+#include "column.h"
+
+namespace Msp {
+namespace GLtk {
+
+Column::Column(bool u):
+       uniform(u)
+{ }
+
+Layout::Slot *Column::create_slot(Widget &w)
+{
+       Slot *slot = new Slot(*this, w);
+
+       if(!slots.empty())
+       {
+               Slot &prev = *slots.back();
+               slot->constraints.push_back(Constraint(BELOW, prev));
+               slot->constraints.push_back(Constraint(ALIGN_LEFT, prev));
+               slot->constraints.push_back(Constraint(ALIGN_RIGHT, prev));
+               if(uniform)
+                       slot->constraints.push_back(Constraint(COPY_HEIGHT, prev));
+               slot->horiz_pack.expand = true;
+       }
+
+       return slot;
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/column.h b/source/column.h
new file mode 100644 (file)
index 0000000..92919be
--- /dev/null
@@ -0,0 +1,34 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GLTK_COLUMN_H_
+#define MSP_GLTK_COLUMN_H_
+
+#include "layout.h"
+
+namespace Msp {
+namespace GLtk {
+
+/**
+Arranges widgets in a single column.
+*/
+class Column: public Layout
+{
+private:
+       bool uniform;
+
+public:
+       Column(bool = false);
+
+private:
+       virtual Slot *create_slot(Widget &);
+};
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif
diff --git a/source/grid.cpp b/source/grid.cpp
new file mode 100644 (file)
index 0000000..4bf0167
--- /dev/null
@@ -0,0 +1,82 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "grid.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GLtk {
+
+Grid::Grid(bool u):
+       uniform(u),
+       cur_column(0),
+       first(true),
+       skipped(false)
+{ }
+
+void Grid::start_row()
+{
+       cur_column = 0;
+       first = true;
+}
+
+void Grid::skip_cell()
+{
+       ++cur_column;
+       skipped = true;
+       if(cur_column>=columns.size())
+               columns.push_back(0);
+}
+
+Layout::Slot *Grid::create_slot(Widget &wdg)
+{
+       Slot *slot = new Slot(*this, wdg);
+
+       slot->vert_pack.gravity = 1;
+
+       if(!slots.empty())
+       {
+               Slot &prev = *slots.back();
+               if(first)
+                       slot->constraints.push_back(Constraint(BELOW, prev));
+               else
+               {
+                       slot->constraints.push_back(Constraint(ALIGN_TOP, prev));
+                       slot->constraints.push_back(Constraint(ALIGN_BOTTOM, prev));
+                       if(!skipped)
+                               slot->constraints.push_back(Constraint(RIGHT_OF, prev));
+               }
+
+               if(uniform)
+               {
+                       slot->constraints.push_back(Constraint(COPY_WIDTH, prev));
+                       slot->constraints.push_back(Constraint(COPY_HEIGHT, prev));
+               }
+
+               if(cur_column<columns.size() && columns[cur_column])
+               {
+                       Slot &col = *columns[cur_column];
+                       slot->constraints.push_back(Constraint(ALIGN_LEFT, col));
+                       slot->constraints.push_back(Constraint(ALIGN_RIGHT, col));
+               }
+       }
+
+       if(cur_column>=columns.size())
+               columns.push_back(slot);
+       else if(!columns[cur_column])
+               columns[cur_column] = slot;
+
+       first = false;
+       skipped = false;
+       ++cur_column;
+
+       return slot;
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/grid.h b/source/grid.h
new file mode 100644 (file)
index 0000000..789672a
--- /dev/null
@@ -0,0 +1,48 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GLTK_GRID_H_
+#define MSP_GLTK_GRID_H_
+
+#include "layout.h"
+
+namespace Msp {
+namespace GLtk {
+
+/**
+Arranges widgets in a grid.
+
+This layout class places widgets in a grid, lining up their edges in rows and
+columns.  Widgets are placed on rows left-to-right and rows are placed top-to-
+bottom.
+
+The start of each row must be indicated manually.  Individual cells can be
+skipped to leave them empty.
+*/
+class Grid: public Layout
+{
+private:
+       bool uniform;
+       std::vector<Slot *> columns;
+       unsigned cur_column;
+       bool first;
+       bool skipped;
+
+public:
+       Grid(bool = false);
+
+       void start_row();
+       void skip_cell();
+
+private:
+       Slot *create_slot(Widget &);
+};
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif
index 35019482bcfbc1efe288be7cf6136723ce3f39a3..468d45ff213267a88c55dba98a2777e20dadb3b8 100644 (file)
@@ -1,3 +1,10 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
 #include <limits>
 #include "container.h"
 #include "layout.h"
@@ -179,6 +186,9 @@ Layout::ConstraintType Layout::complement(ConstraintType type)
 
 void Layout::add_constraint(Widget &src, ConstraintType type, Widget &tgt)
 {
+       if(&src==&tgt)
+               throw InvalidParameterValue("Can't add a self-referencing constraint");
+
        Slot &src_slot = get_slot_for_widget(src);
        Slot &tgt_slot = get_slot_for_widget(tgt);
 
@@ -233,10 +243,11 @@ void Layout::solve_constraints(int dir)
        Pointers &ptrs = pointers[dir&VERTICAL];
 
        LinearProgram linprog(slots.size()*5+1);
+       float weight = slots.size();
        for(list<Slot *>::iterator i=slots.begin(); i!=slots.end(); ++i)
        {
-               linprog.get_object_row()[(*i)->index*5] = 0.1*((*i)->*(ptrs.packing)).gravity;
-               linprog.get_object_row()[(*i)->index*5+1] = (((*i)->*(ptrs.packing)).expand ? 5 : -1);
+               linprog.get_object_row()[(*i)->index*5] = ((*i)->*(ptrs.packing)).gravity/weight;
+               linprog.get_object_row()[(*i)->index*5+1] = (((*i)->*(ptrs.packing)).expand ? weight : -1);
 
                {
                        LinearProgram::Row row = linprog.add_row();
index 540c5ee4d90bacfe9b233e824ad181b81a21aeeb..7e8cdea123fc1a25f845bfb5ecf3e272df9d9b57 100644 (file)
@@ -1,3 +1,10 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
 #ifndef MSP_GLTK_LAYOUT_H_
 #define MSP_GLTK_LAYOUT_H_
 
@@ -12,6 +19,42 @@ namespace GLtk {
 class Container;
 class Widget;
 
+/**
+Positions Widgets inside a Container.
+
+A layout operates on constraints, which are used to form a linear program that
+is then solved to obtain positions and dimensions that fulfill the constraints.
+There are three kinds of constraints available: ordering, alignment and
+dimension matching.
+
+Ordering constraints specify that the widgets should be placed next to other
+along X or Y axis.  These operate on one axis at a time, so a widget could be
+"right of" another even if they are separated by hundreds of pixels vertically.
+The widgets will be separated by a spacing value, which is settable on a per-
+layout basis.
+
+Alignment constraints make the corresponding edges of two widgets be on the
+same line.  These are incompatible with ordering constraints, so only one or
+the other should be used between any pair of widgets for the same axis.
+
+Dimension matching constraints force the two widgets to have the same dimension
+along the relevant axis.
+
+In addition to constraints, there are some other properties that can be set on
+widgets to determine how they are laid out.  Gravity affects which edge of the
+container the widget should be placed at.  This is a relatively weak hint and
+will be overridden by many other things.  Margins can also be specified to
+prevent widgets from getting too close to the container's edges.
+
+Usually widgets are made as small as their content allows.  Setting the expand
+flag for a widget causes it to use as much space as possible.  If multiple co-
+dependent widgets have the expand flag set, the results are currently
+undefined.
+
+Since specifiyng constraints manually can be quite tedious, there are some
+derived Layout classes that implement common positioning patterns.  See
+MixedRows and Grid.
+*/
 class Layout
 {
 private:
diff --git a/source/mixedrows.cpp b/source/mixedrows.cpp
new file mode 100644 (file)
index 0000000..275629d
--- /dev/null
@@ -0,0 +1,77 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#include "mixedrows.h"
+
+namespace Msp {
+namespace GLtk {
+
+MixedRows::MixedRows(bool u):
+       uniform_rows(u),
+       uniform_cols(false),
+       hgravity(-1),
+       hsplit(false),
+       vgravity(1),
+       vsplit(false),
+       first(true)
+{ }
+
+void MixedRows::start_row(bool u)
+{
+       uniform_cols = u;
+       first = true;
+       hgravity = -1;
+       hsplit = false;
+}
+
+void MixedRows::split_rows()
+{
+       vgravity = -1;
+       vsplit = true;
+}
+
+void MixedRows::split_columns()
+{
+       hgravity = 1;
+       hsplit = true;
+}
+
+Layout::Slot *MixedRows::create_slot(Widget &wdg)
+{
+       Slot *slot = new Slot(*this, wdg);
+
+       slot->horiz_pack.gravity = hgravity;
+       slot->vert_pack.gravity = vgravity;
+
+       if(!first)
+       {
+               Slot *prev = slots.back();
+               if(!hsplit)
+                       slot->constraints.push_back(Constraint(RIGHT_OF, *prev));
+               slot->constraints.push_back(Constraint(ALIGN_TOP, *prev));
+               slot->constraints.push_back(Constraint(ALIGN_BOTTOM, *prev));
+               if(uniform_cols)
+                       slot->constraints.push_back(Constraint(COPY_WIDTH, *prev));
+       }
+       else if(!slots.empty())
+       {
+               Slot *prev = slots.back();
+               if(!vsplit)
+                       slot->constraints.push_back(Constraint(BELOW, *prev));
+               if(uniform_rows)
+                       slot->constraints.push_back(Constraint(COPY_HEIGHT, *prev));
+       }
+
+       first = false;
+       hsplit = false;
+       vsplit = false;
+
+       return slot;
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/mixedrows.h b/source/mixedrows.h
new file mode 100644 (file)
index 0000000..721b877
--- /dev/null
@@ -0,0 +1,56 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GLTK_MIXEDROWS_H_
+#define MSP_GLTK_MIXEDROWS_H_
+
+#include "layout.h"
+
+namespace Msp {
+namespace GLtk {
+
+/**
+Places widgets on multiple heterogeneous rows.
+
+This layout class creates rows of widgets, with no horizontal constraints
+between rows.  Widgets are placed on rows left-to-right and rows are placed
+top-to-bottom.
+
+The start of each new row must be indicated manually.  The widgets on a row
+can be specified to have a uniform width, and similarly all rows can be set to
+have a uniform height.
+
+By default widgets have a top-left gravity.  It's possible to specify a "split"
+to align remaining widgets on a row to the right, or remaining rows to the
+bottom.  This does not change the placement order of widgets.
+*/
+class MixedRows: public Layout
+{
+private:
+       bool uniform_rows;
+       bool uniform_cols;
+       int hgravity;
+       bool hsplit;
+       int vgravity;
+       bool vsplit;
+       bool first;
+
+public:
+       MixedRows(bool = false);
+
+       void start_row(bool = false);
+       void split_rows();
+       void split_columns();
+
+private:
+       virtual Slot *create_slot(Widget &);
+};
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif
diff --git a/source/row.cpp b/source/row.cpp
new file mode 100644 (file)
index 0000000..30e1811
--- /dev/null
@@ -0,0 +1,29 @@
+#include "row.h"
+
+namespace Msp {
+namespace GLtk {
+
+Row::Row(bool u):
+       uniform(u)
+{ }
+
+Layout::Slot *Row::create_slot(Widget &w)
+{
+       Slot *slot = new Slot(*this, w);
+
+       if(!slots.empty())
+       {
+               Slot &prev = *slots.back();
+               slot->constraints.push_back(Constraint(RIGHT_OF, prev));
+               slot->constraints.push_back(Constraint(ALIGN_TOP, prev));
+               slot->constraints.push_back(Constraint(ALIGN_BOTTOM, prev));
+               if(uniform)
+                       slot->constraints.push_back(Constraint(COPY_WIDTH, prev));
+               slot->vert_pack.expand = true;
+       }
+
+       return slot;
+}
+
+} // namespace GLtk
+} // namespace Msp
diff --git a/source/row.h b/source/row.h
new file mode 100644 (file)
index 0000000..f8ebe6c
--- /dev/null
@@ -0,0 +1,34 @@
+/* $Id$
+
+This file is part of libmspgltk
+Copyright © 2011  Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+
+#ifndef MSP_GLTK_ROW_H_
+#define MSP_GLTK_ROW_H_
+
+#include "layout.h"
+
+namespace Msp {
+namespace GLtk {
+
+/**
+Arranges widgets in a single row.
+*/
+class Row: public Layout
+{
+private:
+       bool uniform;
+
+public:
+       Row(bool = false);
+
+private:
+       virtual Slot *create_slot(Widget &);
+};
+
+} // namespace GLtk
+} // namespace Msp
+
+#endif