]> git.tdb.fi Git - libs/gltk.git/blob - source/layout.h
Allow loading generic layout properties from datafiles
[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         class Loader: public DataFile::ObjectLoader<Layout>
90         {
91         public:
92                 typedef std::map<std::string, Widget *> WidgetMap;
93
94         private:
95                 const WidgetMap &wdg_map;
96
97         public:
98                 Loader(Layout &, const WidgetMap &);
99
100         private:
101                 void column_spacing(unsigned);
102                 void margin();
103                 void row_spacing(unsigned);
104                 void spacing(unsigned);
105                 void widget(const std::string &);
106         };
107
108 private:
109         class WidgetLoader: public DataFile::Loader
110         {
111         private:
112                 Layout &layout;
113                 Widget &widget;
114                 const Layout::Loader::WidgetMap &wdg_map;
115
116         public:
117                 WidgetLoader(Layout &, Widget &, const Layout::Loader::WidgetMap &);
118
119         private:
120                 void constraint(ConstraintType, const std::string &);
121                 void expand(bool, bool);
122                 void gravity(int, int);
123         };
124
125         struct Slot;
126
127         struct Constraint
128         {
129                 ConstraintType type;
130                 Slot &target;
131                 int spacing;
132
133                 Constraint(ConstraintType, Slot &);
134         };
135
136         struct Packing
137         {
138                 int gravity;
139                 bool expand;
140
141                 Packing();
142         };
143
144         struct Slot: public sigc::trackable
145         {
146                 Layout &layout;
147                 int index;
148                 Widget &widget;
149                 Geometry autosize_geom;
150                 Geometry geom;
151                 std::list<Constraint> constraints;
152                 Packing horiz_pack;
153                 Packing vert_pack;
154
155                 Slot(Layout &, Widget &);
156
157                 void autosize_changed();
158                 void visibility_changed(bool);
159         };
160
161         enum SolveMode
162         {
163                 UPDATE,
164                 AUTOSIZE
165         };
166
167         class LinearProgram;
168         struct Pointers;
169
170         Container *container;
171         std::list<Slot *> slots;
172         unsigned n_active_slots;
173         unsigned n_slack_constraints[2];
174         Sides margin;
175         unsigned row_spacing;
176         unsigned col_spacing;
177         Geometry autosize_geom;
178         std::list<Arrangement *> arrangement_stack;
179
180         static Pointers pointers[2];
181
182 public:
183         Layout();
184         ~Layout();
185
186         void set_container(Container &);
187         void set_margin(const Sides &);
188
189         /** Sets the default spacing between widgets in bothg directions. */
190         void set_spacing(unsigned);
191
192         /** Sets the default vertical spacing between widgets.  Affects the ABOVE
193         and BELOW constraints. */
194         void set_row_spacing(unsigned);
195
196         /** Sets the default horizontal spacing between widgets.  Affects the
197         LEFT_OF and RIGHT_OF constraints. */
198         void set_column_spacing(unsigned);
199
200         void push_arrangement(Arrangement &);
201         Arrangement *get_arrangement() const;
202         void pop_arrangement(Arrangement &);
203
204         void add_widget(Widget &);
205         void remove_widget(Widget &);
206 private:
207         void update_slot_indices();
208         Slot &get_slot_for_widget(Widget &);
209         static ConstraintType complement(ConstraintType);
210         void create_constraint(Widget &, ConstraintType, Widget &, int);
211
212 public:
213         /** Adds a constraint between two widgets. */
214         void add_constraint(Widget &src, ConstraintType type, Widget &tgt);
215
216         /** Adds a constraint between two widgets, overriding the default spacing.
217         Not all constraint types use a spacing. */
218         void add_constraint(Widget &src, ConstraintType type, Widget &tgt, unsigned);
219
220         void set_gravity(Widget &, int, int);
221         void set_expand(Widget &, bool, bool);
222
223         void update();
224         void autosize();
225
226 private:
227         void solve_constraints(int, SolveMode);
228 };
229
230 void operator>>(const LexicalConverter &, Layout::ConstraintType &);
231
232 } // namespace GLtk
233 } // namespace Msp
234
235 #endif