1 #ifndef MSP_GLTK_LAYOUT_H_
2 #define MSP_GLTK_LAYOUT_H_
5 #include <sigc++/trackable.h>
6 #include <msp/strings/lexicalcast.h>
8 #include "mspgltk_api.h"
18 Positions Widgets inside a Container.
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
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.
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.
35 Dimension matching constraints force the two widgets to have the same dimension
36 along the relevant axis.
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.
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
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.
53 class MSPGLTK_API Layout
74 ABOVE = VERTICAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING,
75 BELOW = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING,
76 RIGHT_OF = HORIZONTAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING,
77 LEFT_OF = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING,
78 FAR_ABOVE = VERTICAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING|SLACK,
79 FAR_BELOW = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING|SLACK,
80 FAR_RIGHT_OF = HORIZONTAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING|SLACK,
81 FAR_LEFT_OF = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING|SLACK,
82 ALIGN_TOP = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM,
83 ALIGN_VCENTER = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM|HALF_DIM,
84 ALIGN_BOTTOM = VERTICAL|SELF_POS|TARGET_POS,
85 ALIGN_RIGHT = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM,
86 ALIGN_HCENTER = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM|HALF_DIM,
87 ALIGN_LEFT = HORIZONTAL|SELF_POS|TARGET_POS,
88 COPY_WIDTH = HORIZONTAL|SELF_DIM|TARGET_DIM,
89 COPY_HEIGHT = VERTICAL|SELF_DIM|TARGET_DIM
92 class Loader: public DataFile::ObjectLoader<Layout>
95 typedef std::map<std::string, Widget *> WidgetMap;
98 const WidgetMap &wdg_map;
101 Loader(Layout &, const WidgetMap &);
104 void column_spacing(unsigned);
106 void row_spacing(unsigned);
107 void spacing(unsigned);
108 void widget(const std::string &);
112 class WidgetLoader: public DataFile::Loader
117 const Layout::Loader::WidgetMap &wdg_map;
120 WidgetLoader(Layout &, Widget &, const Layout::Loader::WidgetMap &);
123 void constraint(ConstraintType, const std::string &);
124 void expand(bool, bool);
126 void gravity(int, int);
134 Slot *target = nullptr;
137 Constraint(ConstraintType, Slot &);
146 struct Slot: public sigc::trackable
151 Geometry autosize_geom;
153 std::vector<Constraint> constraints;
157 bool floating = false;
159 Slot(Layout &, Widget &);
161 void autosize_changed();
162 void visibility_changed(bool);
174 Container *container = nullptr;
175 std::vector<Slot *> slots;
176 std::size_t n_active_slots = 0;
177 std::size_t n_slack_vars[2] = { 0, 0 };
179 unsigned row_spacing = 5;
180 unsigned col_spacing = 4;
181 Geometry autosize_geom;
182 std::vector<Arrangement *> arrangement_stack;
184 static Pointers pointers[2];
189 void set_container(Container &);
190 void set_margin(const Sides &);
191 const Sides &get_margin() const { return margin; }
193 /** Sets the default spacing between widgets in both directions. */
194 void set_spacing(unsigned);
196 /** Sets the default vertical spacing between widgets. Affects the ABOVE
197 and BELOW constraints. */
198 void set_row_spacing(unsigned);
200 /** Sets the default horizontal spacing between widgets. Affects the
201 LEFT_OF and RIGHT_OF constraints. */
202 void set_column_spacing(unsigned);
204 unsigned get_row_spacing() const { return row_spacing; }
205 unsigned get_column_spacing() const { return col_spacing; }
207 void push_arrangement(Arrangement &);
208 Arrangement *get_arrangement() const;
209 void pop_arrangement(Arrangement &);
211 void add_widget(Widget &);
212 void remove_widget(Widget &);
214 void update_slot_indices();
215 Slot &get_slot_for_widget(Widget &);
216 static ConstraintType complement(ConstraintType);
217 void create_constraint(Widget &, ConstraintType, Widget &, int);
220 /** Adds a constraint between two widgets. */
221 void add_constraint(Widget &src, ConstraintType type, Widget &tgt);
223 /** Adds a constraint between two widgets, overriding the default spacing.
224 Not all constraint types use a spacing. */
225 void add_constraint(Widget &src, ConstraintType type, Widget &tgt, unsigned);
227 void set_gravity(Widget &, int, int);
228 void set_expand(Widget &, bool, bool);
230 /// Sets a widget as a ghost, taking up space even if it is hidden.
231 void set_ghost(Widget &, bool);
233 void set_floating(Widget &, bool);
236 void autosize(Geometry &);
239 void solve_constraints(int, SolveMode);
242 MSPGLTK_API void operator>>(const LexicalConverter &, Layout::ConstraintType &);