1#include <locale.h>
2
3#include <gtk/gtk.h>
4#include "../../gtk/gtkconstrainttypesprivate.h"
5#include "../../gtk/gtkconstraintsolverprivate.h"
6#include "../../gtk/gtkconstraintexpressionprivate.h"
7
8static void
9constraint_solver_simple (void)
10{
11 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
12
13 GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, name: "x", value: 167.0);
14 GtkConstraintVariable *y = gtk_constraint_solver_create_variable (solver, NULL, name: "y", value: 2.0);
15
16 GtkConstraintExpression *e = gtk_constraint_expression_new_from_variable (variable: y);
17
18 gtk_constraint_solver_add_constraint (solver,
19 variable: x, relation: GTK_CONSTRAINT_RELATION_EQ, expression: e,
20 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
21
22 double x_value = gtk_constraint_variable_get_value (variable: x);
23 double y_value = gtk_constraint_variable_get_value (variable: y);
24
25 g_assert_cmpfloat_with_epsilon (x_value, y_value, 0.001);
26 g_assert_cmpfloat_with_epsilon (x_value, 0.0, 0.001);
27 g_assert_cmpfloat_with_epsilon (y_value, 0.0, 0.001);
28
29 gtk_constraint_variable_unref (variable: y);
30 gtk_constraint_variable_unref (variable: x);
31
32 g_object_unref (object: solver);
33}
34
35static void
36constraint_solver_stay (void)
37{
38 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
39
40 GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, name: "x", value: 5.0);
41 GtkConstraintVariable *y = gtk_constraint_solver_create_variable (solver, NULL, name: "y", value: 10.0);
42
43 gtk_constraint_solver_add_stay_variable (solver, variable: x, strength: GTK_CONSTRAINT_STRENGTH_WEAK);
44 gtk_constraint_solver_add_stay_variable (solver, variable: y, strength: GTK_CONSTRAINT_STRENGTH_WEAK);
45
46 double x_value = gtk_constraint_variable_get_value (variable: x);
47 double y_value = gtk_constraint_variable_get_value (variable: y);
48
49 g_assert_cmpfloat_with_epsilon (x_value, 5.0, 0.001);
50 g_assert_cmpfloat_with_epsilon (y_value, 10.0, 0.001);
51
52 gtk_constraint_variable_unref (variable: x);
53 gtk_constraint_variable_unref (variable: y);
54
55 g_object_unref (object: solver);
56}
57
58static void
59constraint_solver_variable_geq_constant (void)
60{
61 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
62
63 GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, name: "x", value: 10.0);
64 GtkConstraintExpression *e = gtk_constraint_expression_new (constant: 100.0);
65
66 gtk_constraint_solver_add_constraint (solver,
67 variable: x, relation: GTK_CONSTRAINT_RELATION_GE, expression: e,
68 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
69
70 double x_value = gtk_constraint_variable_get_value (variable: x);
71
72 g_assert_cmpfloat (x_value, >=, 100.0);
73
74 gtk_constraint_variable_unref (variable: x);
75
76 g_object_unref (object: solver);
77}
78
79static void
80constraint_solver_variable_leq_constant (void)
81{
82 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
83
84 GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, name: "x", value: 100.0);
85 GtkConstraintExpression *e = gtk_constraint_expression_new (constant: 10.0);
86
87 gtk_constraint_solver_add_constraint (solver,
88 variable: x, relation: GTK_CONSTRAINT_RELATION_LE, expression: e,
89 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
90
91 double x_value = gtk_constraint_variable_get_value (variable: x);
92
93 g_assert_cmpfloat (x_value, <=, 10.0);
94
95 gtk_constraint_variable_unref (variable: x);
96
97 g_object_unref (object: solver);
98}
99
100static void
101constraint_solver_variable_eq_constant (void)
102{
103 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
104
105 GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, name: "x", value: 10.0);
106 GtkConstraintExpression *e = gtk_constraint_expression_new (constant: 100.0);
107
108 gtk_constraint_solver_add_constraint (solver,
109 variable: x, relation: GTK_CONSTRAINT_RELATION_EQ, expression: e,
110 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
111
112 double x_value = gtk_constraint_variable_get_value (variable: x);
113
114 g_assert_cmpfloat_with_epsilon (x_value, 100.0, 0.001);
115
116 gtk_constraint_variable_unref (variable: x);
117
118 g_object_unref (object: solver);
119}
120
121static void
122constraint_solver_eq_with_stay (void)
123{
124 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
125
126 GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, name: "x", value: 10.0);
127 GtkConstraintVariable *width = gtk_constraint_solver_create_variable (solver, NULL, name: "width", value: 10.0);
128 GtkConstraintVariable *right_min = gtk_constraint_solver_create_variable (solver, NULL, name: "rightMin", value: 100.0);
129
130 GtkConstraintExpressionBuilder builder;
131 gtk_constraint_expression_builder_init (builder: &builder, solver);
132 gtk_constraint_expression_builder_term (builder: &builder, term: x);
133 gtk_constraint_expression_builder_plus (builder: &builder);
134 gtk_constraint_expression_builder_term (builder: &builder, term: width);
135 GtkConstraintExpression *right = gtk_constraint_expression_builder_finish (builder: &builder);
136
137 gtk_constraint_solver_add_stay_variable (solver, variable: width, strength: GTK_CONSTRAINT_STRENGTH_WEAK);
138 gtk_constraint_solver_add_stay_variable (solver, variable: right_min, strength: GTK_CONSTRAINT_STRENGTH_WEAK);
139 gtk_constraint_solver_add_constraint (solver,
140 variable: right_min, relation: GTK_CONSTRAINT_RELATION_EQ, expression: right,
141 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
142
143 double x_value = gtk_constraint_variable_get_value (variable: x);
144 double width_value = gtk_constraint_variable_get_value (variable: width);
145
146 g_assert_cmpfloat_with_epsilon (x_value, 90.0, 0.001);
147 g_assert_cmpfloat_with_epsilon (width_value, 10.0, 0.001);
148
149 gtk_constraint_variable_unref (variable: right_min);
150 gtk_constraint_variable_unref (variable: width);
151 gtk_constraint_variable_unref (variable: x);
152
153 g_object_unref (object: solver);
154}
155
156static void
157constraint_solver_cassowary (void)
158{
159 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
160
161 GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, name: "x", value: 0.0);
162 GtkConstraintVariable *y = gtk_constraint_solver_create_variable (solver, NULL, name: "y", value: 0.0);
163
164 GtkConstraintExpression *e;
165
166 e = gtk_constraint_expression_new_from_variable (variable: y);
167 gtk_constraint_solver_add_constraint (solver,
168 variable: x, relation: GTK_CONSTRAINT_RELATION_LE, expression: e,
169 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
170
171 e = gtk_constraint_expression_plus_constant (expression: gtk_constraint_expression_new_from_variable (variable: x), constant: 3.0);
172 gtk_constraint_solver_add_constraint (solver,
173 variable: y, relation: GTK_CONSTRAINT_RELATION_EQ, expression: e,
174 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
175
176 e = gtk_constraint_expression_new (constant: 10.0);
177 gtk_constraint_solver_add_constraint (solver,
178 variable: x, relation: GTK_CONSTRAINT_RELATION_EQ, expression: e,
179 strength: GTK_CONSTRAINT_STRENGTH_WEAK);
180
181 e = gtk_constraint_expression_new (constant: 10.0);
182 gtk_constraint_solver_add_constraint (solver,
183 variable: y, relation: GTK_CONSTRAINT_RELATION_EQ, expression: e,
184 strength: GTK_CONSTRAINT_STRENGTH_WEAK);
185
186 double x_val = gtk_constraint_variable_get_value (variable: x);
187 double y_val = gtk_constraint_variable_get_value (variable: y);
188
189 g_test_message (format: "x = %g, y = %g", x_val, y_val);
190
191 /* The system is unstable and has two possible solutions we need to test */
192 g_assert_true ((G_APPROX_VALUE (x_val, 10.0, 1e-8) &&
193 G_APPROX_VALUE (y_val, 13.0, 1e-8)) ||
194 (G_APPROX_VALUE (x_val, 7.0, 1e-8) &&
195 G_APPROX_VALUE (y_val, 10.0, 1e-8)));
196
197 gtk_constraint_variable_unref (variable: x);
198 gtk_constraint_variable_unref (variable: y);
199
200 g_object_unref (object: solver);
201}
202
203static void
204constraint_solver_edit_var_required (void)
205{
206 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
207
208 GtkConstraintVariable *a = gtk_constraint_solver_create_variable (solver, NULL, name: "a", value: 0.0);
209 gtk_constraint_solver_add_stay_variable (solver, variable: a, strength: GTK_CONSTRAINT_STRENGTH_STRONG);
210
211 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 0.0, 0.001);
212
213 gtk_constraint_solver_add_edit_variable (solver, variable: a, strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
214 gtk_constraint_solver_begin_edit (solver);
215 gtk_constraint_solver_suggest_value (solver, variable: a, value: 2.0);
216 gtk_constraint_solver_resolve (solver);
217
218 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 2.0, 0.001);
219
220 gtk_constraint_solver_suggest_value (solver, variable: a, value: 10.0);
221 gtk_constraint_solver_resolve (solver);
222
223 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 10.0, 0.001);
224
225 gtk_constraint_solver_end_edit (solver);
226
227 gtk_constraint_variable_unref (variable: a);
228
229 g_object_unref (object: solver);
230}
231
232static void
233constraint_solver_edit_var_suggest (void)
234{
235 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
236
237 GtkConstraintVariable *a = gtk_constraint_solver_create_variable (solver, NULL, name: "a", value: 0.0);
238 GtkConstraintVariable *b = gtk_constraint_solver_create_variable (solver, NULL, name: "b", value: 0.0);
239
240 gtk_constraint_solver_add_stay_variable (solver, variable: a, strength: GTK_CONSTRAINT_STRENGTH_STRONG);
241
242 GtkConstraintExpression *e = gtk_constraint_expression_new_from_variable (variable: b);
243 gtk_constraint_solver_add_constraint (solver,
244 variable: a, relation: GTK_CONSTRAINT_RELATION_EQ, expression: e,
245 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
246
247 gtk_constraint_solver_resolve (solver);
248
249 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 0.0, 0.001);
250 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 0.0, 0.001);
251
252 gtk_constraint_solver_add_edit_variable (solver, variable: a, strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
253 gtk_constraint_solver_begin_edit (solver);
254
255 gtk_constraint_solver_suggest_value (solver, variable: a, value: 2.0);
256 gtk_constraint_solver_resolve (solver);
257
258 g_test_message (format: "Check values after first edit");
259
260 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 2.0, 0.001);
261 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 2.0, 0.001);
262
263 gtk_constraint_solver_suggest_value (solver, variable: a, value: 10.0);
264 gtk_constraint_solver_resolve (solver);
265
266 g_test_message (format: "Check values after second edit");
267
268 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 10.0, 0.001);
269 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 10.0, 0.001);
270
271 gtk_constraint_solver_suggest_value (solver, variable: a, value: 12.0);
272 gtk_constraint_solver_resolve (solver);
273
274 g_test_message (format: "Check values after third edit");
275
276 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 12.0, 0.001);
277 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 12.0, 0.001);
278
279 gtk_constraint_variable_unref (variable: a);
280 gtk_constraint_variable_unref (variable: b);
281
282 g_object_unref (object: solver);
283}
284
285static void
286constraint_solver_paper (void)
287{
288 GtkConstraintSolver *solver = gtk_constraint_solver_new ();
289
290 GtkConstraintVariable *left = gtk_constraint_solver_create_variable (solver, NULL, name: "left", value: 0.0);
291 GtkConstraintVariable *middle = gtk_constraint_solver_create_variable (solver, NULL, name: "middle", value: 0.0);
292 GtkConstraintVariable *right = gtk_constraint_solver_create_variable (solver, NULL, name: "right", value: 0.0);
293
294 GtkConstraintExpressionBuilder builder;
295 GtkConstraintExpression *expr;
296
297 gtk_constraint_expression_builder_init (builder: &builder, solver);
298 gtk_constraint_expression_builder_term (builder: &builder, term: left);
299 gtk_constraint_expression_builder_plus (builder: &builder);
300 gtk_constraint_expression_builder_term (builder: &builder, term: right);
301 gtk_constraint_expression_builder_divide_by (builder: &builder);
302 gtk_constraint_expression_builder_constant (builder: &builder, value: 2.0);
303 expr = gtk_constraint_expression_builder_finish (builder: &builder);
304 gtk_constraint_solver_add_constraint (solver,
305 variable: middle, relation: GTK_CONSTRAINT_RELATION_EQ, expression: expr,
306 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
307
308 gtk_constraint_expression_builder_init (builder: &builder, solver);
309 gtk_constraint_expression_builder_term (builder: &builder, term: left);
310 gtk_constraint_expression_builder_plus (builder: &builder);
311 gtk_constraint_expression_builder_constant (builder: &builder, value: 10.0);
312 expr = gtk_constraint_expression_builder_finish (builder: &builder);
313 gtk_constraint_solver_add_constraint (solver,
314 variable: right, relation: GTK_CONSTRAINT_RELATION_EQ, expression: expr,
315 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
316
317 expr = gtk_constraint_expression_new (constant: 100.0);
318 gtk_constraint_solver_add_constraint (solver,
319 variable: right, relation: GTK_CONSTRAINT_RELATION_LE, expression: expr,
320 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
321
322 expr = gtk_constraint_expression_new (constant: 0.0);
323 gtk_constraint_solver_add_constraint (solver,
324 variable: left, relation: GTK_CONSTRAINT_RELATION_GE, expression: expr,
325 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
326
327 g_test_message (format: "Check constraints hold");
328
329 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (middle),
330 (gtk_constraint_variable_get_value (left) + gtk_constraint_variable_get_value (right)) / 2.0,
331 0.001);
332 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (right),
333 gtk_constraint_variable_get_value (left) + 10.0,
334 0.001);
335 g_assert_cmpfloat (gtk_constraint_variable_get_value (right), <=, 100.0);
336 g_assert_cmpfloat (gtk_constraint_variable_get_value (left), >=, 0.0);
337
338 gtk_constraint_variable_set_value (variable: middle, value: 45.0);
339 gtk_constraint_solver_add_stay_variable (solver, variable: middle, strength: GTK_CONSTRAINT_STRENGTH_WEAK);
340
341 g_test_message (format: "Check constraints hold after setting middle");
342
343 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (middle),
344 (gtk_constraint_variable_get_value (left) + gtk_constraint_variable_get_value (right)) / 2.0,
345 0.001);
346 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (right),
347 gtk_constraint_variable_get_value (left) + 10.0,
348 0.001);
349 g_assert_cmpfloat (gtk_constraint_variable_get_value (right), <=, 100.0);
350 g_assert_cmpfloat (gtk_constraint_variable_get_value (left), >=, 0.0);
351
352 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (left), 40.0, 0.001);
353 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (middle), 45.0, 0.001);
354 g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (right), 50.0, 0.001);
355
356 gtk_constraint_variable_unref (variable: left);
357 gtk_constraint_variable_unref (variable: middle);
358 gtk_constraint_variable_unref (variable: right);
359
360 g_object_unref (object: solver);
361}
362
363int
364main (int argc, char *argv[])
365{
366 (g_test_init) (argc: &argc, argv: &argv, NULL);
367 setlocale (LC_ALL, locale: "C");
368
369 g_test_add_func (testpath: "/constraint-solver/paper", test_func: constraint_solver_paper);
370 g_test_add_func (testpath: "/constraint-solver/simple", test_func: constraint_solver_simple);
371 g_test_add_func (testpath: "/constraint-solver/constant/eq", test_func: constraint_solver_variable_eq_constant);
372 g_test_add_func (testpath: "/constraint-solver/constant/ge", test_func: constraint_solver_variable_geq_constant);
373 g_test_add_func (testpath: "/constraint-solver/constant/le", test_func: constraint_solver_variable_leq_constant);
374 g_test_add_func (testpath: "/constraint-solver/stay/simple", test_func: constraint_solver_stay);
375 g_test_add_func (testpath: "/constraint-solver/stay/eq", test_func: constraint_solver_eq_with_stay);
376 g_test_add_func (testpath: "/constraint-solver/cassowary", test_func: constraint_solver_cassowary);
377 g_test_add_func (testpath: "/constraint-solver/edit/required", test_func: constraint_solver_edit_var_required);
378 g_test_add_func (testpath: "/constraint-solver/edit/suggest", test_func: constraint_solver_edit_var_suggest);
379
380 return g_test_run ();
381}
382

source code of gtk/testsuite/gtk/constraint-solver.c