]> git.tdb.fi Git - libs/gltk.git/blob - source/layout.h
2de4013a5d1e8b943cf939abd5b63b114e5fd1e3
[libs/gltk.git] / source / layout.h
1 #ifndef MSP_GLTK_LAYOUT_H_
2 #define MSP_GLTK_LAYOUT_H_
3
4 #include <list>
5 #include <set>
6 #include <sigc++/trackable.h>
7 #include <msp/strings/lexicalcast.h>
8 #include "geometry.h"
9
10 namespace Msp {
11 namespace GLtk {
12
13 class Arrangement;
14 class Container;
15 class Widget;
16
17 /**
18 Positions Widgets inside a Container.
19
20 A layout operates on constraints, which are used to form a linear program that
21 is then solved to obtain positions and dimensions that fulfill the constraints.
22 There are three kinds of constraints available: ordering, alignment and
23 dimension matching.
24
25 Ordering constraints specify that the widgets should be placed next to each
26 other along X or Y axis.  These operate on one axis at a time, so a widget
27 could be "right of" another even if they are separated by hundreds of pixels
28 vertically.  The widgets will be separated by a spacing value, which is
29 settable on a per-layout basis.
30
31 Alignment constraints make the corresponding edges of two widgets be on the
32 same line.  These are incompatible with ordering constraints, so only one or
33 the other should be used between any pair of widgets for the same axis.
34
35 Dimension matching constraints force the two widgets to have the same dimension
36 along the relevant axis.
37
38 In addition to constraints, there are some other properties that can be set on
39 widgets to determine how they are laid out.  Gravity affects which edge of the
40 container the widget should be placed at.  This is a relatively weak hint and
41 will be overridden by many other things.  Margins can also be specified to
42 prevent widgets from getting too close to the container's edges.
43
44 Usually widgets are made as small as their content allows.  Setting the expand
45 flag for a widget causes it to use as much space as possible.  If multiple co-
46 dependent widgets have the expand flag set, the results are currently
47 undefined.
48
49 Since specifiyng constraints manually can be quite tedious, an Arrangement
50 interface is provided to automatically arrange widgets.  See classes Row,
51 Column and Grid for some commonly used arrangements.
52 */
53 class Layout
54 {
55 private:
56         enum
57         {
58                 HORIZONTAL = 0,
59                 VERTICAL = 1,
60                 SELF_POS = 2,
61                 SELF_DIM = 4,
62                 SELF_MASK = 6,
63                 TARGET_POS = 8,
64                 TARGET_DIM = 16,
65                 TARGET_MASK = 24,
66                 SPACING = 32,
67                 SLACK = 64
68         };
69
70 public:
71         enum ConstraintType
72         {
73                 ABOVE = VERTICAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING,
74                 BELOW = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING,
75                 RIGHT_OF = HORIZONTAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING,
76                 LEFT_OF = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING,
77                 FAR_ABOVE = VERTICAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING|SLACK,
78                 FAR_BELOW = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING|SLACK,
79                 FAR_RIGHT_OF = HORIZONTAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING|SLACK,
80                 FAR_LEFT_OF = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING|SLACK,
81                 ALIGN_TOP = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM,
82                 ALIGN_BOTTOM = VERTICAL|SELF_POS|TARGET_POS,
83                 ALIGN_RIGHT = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM,
84                 ALIGN_LEFT = HORIZONTAL|SELF_POS|TARGET_POS,
85                 COPY_WIDTH = HORIZONTAL|SELF_DIM|TARGET_DIM,
86                 COPY_HEIGHT = VERTICAL|SELF_DIM|TARGET_DIM
87         };
88
89 private:
90         struct Slot;
91
92         struct Constraint
93         {
94                 ConstraintType type;
95                 Slot &target;
96                 int spacing;
97
98                 Constraint(ConstraintType, Slot &);
99         };
100
101         struct Packing
102         {
103                 int gravity;
104                 bool expand;
105
106                 Packing();
107         };
108
109         struct Slot: public sigc::trackable
110         {
111                 Layout &layout;
112                 int index;
113                 Widget &widget;
114                 Geometry autosize_geom;
115                 Geometry geom;
116                 std::list<Constraint> constraints;
117                 Packing horiz_pack;
118                 Packing vert_pack;
119
120                 Slot(Layout &, Widget &);
121
122                 void autosize_changed();
123                 void visibility_changed(bool);
124         };
125
126         enum SolveMode
127         {
128                 UPDATE,
129                 AUTOSIZE
130         };
131
132         class LinearProgram;
133         struct Pointers;
134
135         Container *container;
136         std::list<Slot *> slots;
137         unsigned n_active_slots;
138         unsigned n_slack_constraints[2];
139         Sides margin;
140         unsigned row_spacing;
141         unsigned col_spacing;
142         Geometry autosize_geom;
143         std::list<Arrangement *> arrangement_stack;
144
145         static Pointers pointers[2];
146
147 public:
148         Layout();
149         ~Layout();
150
151         void set_container(Container &);
152         void set_margin(const Sides &);
153
154         /** Sets the default spacing between widgets in bothg directions. */
155         void set_spacing(unsigned);
156
157         /** Sets the default vertical spacing between widgets.  Affects the ABOVE
158         and BELOW constraints. */
159         void set_row_spacing(unsigned);
160
161         /** Sets the default horizontal spacing between widgets.  Affects the
162         LEFT_OF and RIGHT_OF constraints. */
163         void set_column_spacing(unsigned);
164
165         void push_arrangement(Arrangement &);
166         Arrangement *get_arrangement() const;
167         void pop_arrangement(Arrangement &);
168
169         void add_widget(Widget &);
170         void remove_widget(Widget &);
171 private:
172         void update_slot_indices();
173         Slot &get_slot_for_widget(Widget &);
174         static ConstraintType complement(ConstraintType);
175         void create_constraint(Widget &, ConstraintType, Widget &, int);
176
177 public:
178         /** Adds a constraint between two widgets. */
179         void add_constraint(Widget &src, ConstraintType type, Widget &tgt);
180
181         /** Adds a constraint between two widgets, overriding the default spacing.
182         Not all constraint types use a spacing. */
183         void add_constraint(Widget &src, ConstraintType type, Widget &tgt, unsigned);
184
185         void set_gravity(Widget &, int, int);
186         void set_expand(Widget &, bool, bool);
187
188         void update();
189         void autosize();
190
191 private:
192         void solve_constraints(int, SolveMode);
193 };
194
195 void operator>>(const LexicalConverter &, Layout::ConstraintType &);
196
197 } // namespace GLtk
198 } // namespace Msp
199
200 #endif