1 #ifndef MSP_GLTK_LAYOUT_H_
2 #define MSP_GLTK_LAYOUT_H_
6 #include <sigc++/trackable.h>
7 #include <msp/strings/lexicalcast.h>
9 #include "mspgltk_api.h"
19 Positions Widgets inside a Container.
21 A layout operates on constraints, which are used to form a linear program that
22 is then solved to obtain positions and dimensions that fulfill the constraints.
23 There are three kinds of constraints available: ordering, alignment and
26 Ordering constraints specify that the widgets should be placed next to each
27 other along X or Y axis. These operate on one axis at a time, so a widget
28 could be "right of" another even if they are separated by hundreds of pixels
29 vertically. The widgets will be separated by a spacing value, which is
30 settable on a per-layout basis.
32 Alignment constraints make the corresponding edges of two widgets be on the
33 same line. These are incompatible with ordering constraints, so only one or
34 the other should be used between any pair of widgets for the same axis.
36 Dimension matching constraints force the two widgets to have the same dimension
37 along the relevant axis.
39 In addition to constraints, there are some other properties that can be set on
40 widgets to determine how they are laid out. Gravity affects which edge of the
41 container the widget should be placed at. This is a relatively weak hint and
42 will be overridden by many other things. Margins can also be specified to
43 prevent widgets from getting too close to the container's edges.
45 Usually widgets are made as small as their content allows. Setting the expand
46 flag for a widget causes it to use as much space as possible. If multiple co-
47 dependent widgets have the expand flag set, the results are currently
50 Since specifiyng constraints manually can be quite tedious, an Arrangement
51 interface is provided to automatically arrange widgets. See classes Row,
52 Column and Grid for some commonly used arrangements.
54 class MSPGLTK_API Layout
75 ABOVE = VERTICAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING,
76 BELOW = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING,
77 RIGHT_OF = HORIZONTAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING,
78 LEFT_OF = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING,
79 FAR_ABOVE = VERTICAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING|SLACK,
80 FAR_BELOW = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING|SLACK,
81 FAR_RIGHT_OF = HORIZONTAL|SELF_POS|TARGET_POS|TARGET_DIM|SPACING|SLACK,
82 FAR_LEFT_OF = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|SPACING|SLACK,
83 ALIGN_TOP = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM,
84 ALIGN_VCENTER = VERTICAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM|HALF_DIM,
85 ALIGN_BOTTOM = VERTICAL|SELF_POS|TARGET_POS,
86 ALIGN_RIGHT = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM,
87 ALIGN_HCENTER = HORIZONTAL|SELF_POS|SELF_DIM|TARGET_POS|TARGET_DIM|HALF_DIM,
88 ALIGN_LEFT = HORIZONTAL|SELF_POS|TARGET_POS,
89 COPY_WIDTH = HORIZONTAL|SELF_DIM|TARGET_DIM,
90 COPY_HEIGHT = VERTICAL|SELF_DIM|TARGET_DIM
93 class Loader: public DataFile::ObjectLoader<Layout>
96 typedef std::map<std::string, Widget *> WidgetMap;
99 const WidgetMap &wdg_map;
102 Loader(Layout &, const WidgetMap &);
105 void column_spacing(unsigned);
107 void row_spacing(unsigned);
108 void spacing(unsigned);
109 void widget(const std::string &);
113 class WidgetLoader: public DataFile::Loader
118 const Layout::Loader::WidgetMap &wdg_map;
121 WidgetLoader(Layout &, Widget &, const Layout::Loader::WidgetMap &);
124 void constraint(ConstraintType, const std::string &);
125 void expand(bool, bool);
127 void gravity(int, int);
135 Slot *target = nullptr;
138 Constraint(ConstraintType, Slot &);
147 struct Slot: public sigc::trackable
152 Geometry autosize_geom;
154 std::vector<Constraint> constraints;
158 bool floating = false;
160 Slot(Layout &, Widget &);
162 void autosize_changed();
163 void visibility_changed(bool);
175 Container *container = nullptr;
176 std::vector<std::unique_ptr<Slot>> slots;
177 std::size_t n_active_slots = 0;
178 std::size_t n_slack_vars[2] = { 0, 0 };
180 unsigned row_spacing = 5;
181 unsigned col_spacing = 4;
182 Geometry autosize_geom;
183 std::vector<Arrangement *> arrangement_stack;
185 static Pointers pointers[2];
188 void set_container(Container &);
189 void set_margin(const Sides &);
190 const Sides &get_margin() const { return margin; }
192 /** Sets the default spacing between widgets in both directions. */
193 void set_spacing(unsigned);
195 /** Sets the default vertical spacing between widgets. Affects the ABOVE
196 and BELOW constraints. */
197 void set_row_spacing(unsigned);
199 /** Sets the default horizontal spacing between widgets. Affects the
200 LEFT_OF and RIGHT_OF constraints. */
201 void set_column_spacing(unsigned);
203 unsigned get_row_spacing() const { return row_spacing; }
204 unsigned get_column_spacing() const { return col_spacing; }
206 void push_arrangement(Arrangement &);
207 Arrangement *get_arrangement() const;
208 void pop_arrangement(Arrangement &);
210 void add_widget(Widget &);
211 void remove_widget(Widget &);
213 void update_slot_indices();
214 Slot &get_slot_for_widget(Widget &);
215 static ConstraintType complement(ConstraintType);
216 void create_constraint(Widget &, ConstraintType, Widget &, int);
219 /** Adds a constraint between two widgets. */
220 void add_constraint(Widget &src, ConstraintType type, Widget &tgt);
222 /** Adds a constraint between two widgets, overriding the default spacing.
223 Not all constraint types use a spacing. */
224 void add_constraint(Widget &src, ConstraintType type, Widget &tgt, unsigned);
226 void set_gravity(Widget &, int, int);
227 void set_expand(Widget &, bool, bool);
229 /// Sets a widget as a ghost, taking up space even if it is hidden.
230 void set_ghost(Widget &, bool);
232 void set_floating(Widget &, bool);
235 void autosize(Geometry &);
238 void solve_constraints(int, SolveMode);
241 MSPGLTK_API void operator>>(const LexicalConverter &, Layout::ConstraintType &);