1 | /* |
2 | * Copyright © 2019 Red Hat, Inc. |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 2.1 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU Lesser General Public |
15 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
16 | * |
17 | * Authors: Matthias Clasen |
18 | */ |
19 | |
20 | #include "config.h" |
21 | |
22 | #include "constraint-editor.h" |
23 | |
24 | struct _ConstraintEditor |
25 | { |
26 | GtkWidget parent_instance; |
27 | |
28 | GtkWidget *grid; |
29 | GtkWidget *target; |
30 | GtkWidget *target_attr; |
31 | GtkWidget *relation; |
32 | GtkWidget *source; |
33 | GtkWidget *source_attr; |
34 | GtkWidget *multiplier; |
35 | GtkWidget *constant; |
36 | GtkWidget *strength; |
37 | GtkWidget *preview; |
38 | GtkWidget *button; |
39 | |
40 | GtkConstraint *constraint; |
41 | GListModel *model; |
42 | |
43 | gboolean constructed; |
44 | }; |
45 | |
46 | enum { |
47 | PROP_MODEL = 1, |
48 | PROP_CONSTRAINT, |
49 | LAST_PROP |
50 | }; |
51 | |
52 | static GParamSpec *pspecs[LAST_PROP]; |
53 | |
54 | enum { |
55 | DONE, |
56 | LAST_SIGNAL |
57 | }; |
58 | |
59 | static guint signals[LAST_SIGNAL]; |
60 | |
61 | G_DEFINE_TYPE(ConstraintEditor, constraint_editor, GTK_TYPE_WIDGET); |
62 | |
63 | static const char * |
64 | get_target_name (GtkConstraintTarget *target) |
65 | { |
66 | if (target == NULL) |
67 | return "super" ; |
68 | else if (GTK_IS_WIDGET (target)) |
69 | return gtk_widget_get_name (GTK_WIDGET (target)); |
70 | else if (GTK_IS_CONSTRAINT_GUIDE (ptr: target)) |
71 | return gtk_constraint_guide_get_name (guide: GTK_CONSTRAINT_GUIDE (ptr: target)); |
72 | else |
73 | return "" ; |
74 | } |
75 | |
76 | static void |
77 | constraint_target_combo (GListModel *model, |
78 | GtkWidget *combo, |
79 | gboolean is_source) |
80 | { |
81 | int i; |
82 | |
83 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "super" , text: "Super" ); |
84 | |
85 | if (model) |
86 | { |
87 | for (i = 0; i < g_list_model_get_n_items (list: model); i++) |
88 | { |
89 | GObject *item = g_list_model_get_object (list: model, position: i); |
90 | const char *name; |
91 | |
92 | if (GTK_IS_CONSTRAINT (ptr: item)) |
93 | continue; |
94 | |
95 | name = get_target_name (target: GTK_CONSTRAINT_TARGET (ptr: item)); |
96 | |
97 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: name, text: name); |
98 | g_object_unref (object: item); |
99 | } |
100 | } |
101 | } |
102 | |
103 | static void |
104 | constraint_attribute_combo (GtkWidget *combo, |
105 | gboolean is_source) |
106 | { |
107 | if (is_source) |
108 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "none" , text: "None" ); |
109 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "left" , text: "Left" ); |
110 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "right" , text: "Right" ); |
111 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "top" , text: "Top" ); |
112 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "bottom" , text: "Bottom" ); |
113 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "start" , text: "Start" ); |
114 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "end" , text: "End" ); |
115 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "width" , text: "Width" ); |
116 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "height" , text: "Height" ); |
117 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "center-x" , text: "Center X" ); |
118 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "center-y" , text: "Center Y" ); |
119 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "baseline" , text: "Baseline" ); |
120 | } |
121 | |
122 | static void |
123 | constraint_relation_combo (GtkWidget *combo) |
124 | { |
125 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "le" , text: "≤" ); |
126 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "eq" , text: "=" ); |
127 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "ge" , text: "≥" ); |
128 | } |
129 | |
130 | static void |
131 | constraint_strength_combo (GtkWidget *combo) |
132 | { |
133 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "weak" , text: "Weak" ); |
134 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "medium" , text: "Medium" ); |
135 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "strong" , text: "Strong" ); |
136 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "required" , text: "Required" ); |
137 | } |
138 | |
139 | static gpointer |
140 | get_target (GListModel *model, |
141 | const char *id) |
142 | { |
143 | int i; |
144 | |
145 | if (id == NULL) |
146 | return NULL; |
147 | |
148 | if (strcmp (s1: "super" , s2: id) == 0) |
149 | return NULL; |
150 | |
151 | for (i = 0; i < g_list_model_get_n_items (list: model); i++) |
152 | { |
153 | GObject *item = g_list_model_get_object (list: model, position: i); |
154 | g_object_unref (object: item); |
155 | if (GTK_IS_CONSTRAINT (ptr: item)) |
156 | continue; |
157 | else if (GTK_IS_WIDGET (item)) |
158 | { |
159 | if (strcmp (s1: id, s2: gtk_widget_get_name (GTK_WIDGET (item))) == 0) |
160 | return item; |
161 | } |
162 | else if (GTK_IS_CONSTRAINT_GUIDE (ptr: item)) |
163 | { |
164 | if (strcmp (s1: id, s2: gtk_constraint_guide_get_name (guide: GTK_CONSTRAINT_GUIDE (ptr: item))) == 0) |
165 | return item; |
166 | } |
167 | } |
168 | |
169 | return NULL; |
170 | } |
171 | |
172 | static GtkConstraintAttribute |
173 | get_target_attr (const char *id) |
174 | { |
175 | GtkConstraintAttribute attr; |
176 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_ATTRIBUTE); |
177 | GEnumValue *value = g_enum_get_value_by_nick (enum_class: class, nick: id); |
178 | attr = value->value; |
179 | g_type_class_unref (g_class: class); |
180 | |
181 | return attr; |
182 | } |
183 | |
184 | static const char * |
185 | get_attr_nick (GtkConstraintAttribute attr) |
186 | { |
187 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_ATTRIBUTE); |
188 | GEnumValue *value = g_enum_get_value (enum_class: class, value: attr); |
189 | const char *nick = value->value_nick; |
190 | g_type_class_unref (g_class: class); |
191 | |
192 | return nick; |
193 | } |
194 | |
195 | static GtkConstraintRelation |
196 | get_relation (const char *id) |
197 | { |
198 | GtkConstraintRelation relation; |
199 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_RELATION); |
200 | GEnumValue *value = g_enum_get_value_by_nick (enum_class: class, nick: id); |
201 | relation = value->value; |
202 | g_type_class_unref (g_class: class); |
203 | |
204 | return relation; |
205 | } |
206 | |
207 | static const char * |
208 | get_relation_nick (GtkConstraintRelation relation) |
209 | { |
210 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_RELATION); |
211 | GEnumValue *value = g_enum_get_value (enum_class: class, value: relation); |
212 | const char *nick = value->value_nick; |
213 | g_type_class_unref (g_class: class); |
214 | |
215 | return nick; |
216 | } |
217 | |
218 | static const char * |
219 | get_relation_display_name (GtkConstraintRelation relation) |
220 | { |
221 | switch (relation) |
222 | { |
223 | case GTK_CONSTRAINT_RELATION_LE: |
224 | return "≤" ; |
225 | case GTK_CONSTRAINT_RELATION_EQ: |
226 | return "=" ; |
227 | case GTK_CONSTRAINT_RELATION_GE: |
228 | return "≥" ; |
229 | default: |
230 | return "?" ; |
231 | } |
232 | } |
233 | |
234 | static GtkConstraintStrength |
235 | get_strength (const char *id) |
236 | { |
237 | GtkConstraintStrength strength; |
238 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_STRENGTH); |
239 | GEnumValue *value = g_enum_get_value_by_nick (enum_class: class, nick: id); |
240 | strength = value->value; |
241 | g_type_class_unref (g_class: class); |
242 | |
243 | return strength; |
244 | } |
245 | |
246 | static const char * |
247 | get_strength_nick (GtkConstraintStrength strength) |
248 | { |
249 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_STRENGTH); |
250 | GEnumValue *value = g_enum_get_value (enum_class: class, value: strength); |
251 | const char *nick = value->value_nick; |
252 | g_type_class_unref (g_class: class); |
253 | |
254 | return nick; |
255 | } |
256 | |
257 | void |
258 | constraint_editor_serialize_constraint (GString *str, |
259 | int indent, |
260 | GtkConstraint *constraint) |
261 | { |
262 | const char *target; |
263 | const char *target_attr; |
264 | const char *relation; |
265 | const char *source; |
266 | const char *source_attr; |
267 | double multiplier; |
268 | double constant; |
269 | const char *strength; |
270 | |
271 | target = get_target_name (target: gtk_constraint_get_target (constraint)); |
272 | target_attr = get_attr_nick (attr: gtk_constraint_get_target_attribute (constraint)); |
273 | relation = get_relation_nick (relation: gtk_constraint_get_relation (constraint)); |
274 | source = get_target_name (target: gtk_constraint_get_source (constraint)); |
275 | source_attr = get_attr_nick (attr: gtk_constraint_get_source_attribute (constraint)); |
276 | multiplier = gtk_constraint_get_multiplier (constraint); |
277 | constant = gtk_constraint_get_constant (constraint); |
278 | strength = get_strength_nick (strength: gtk_constraint_get_strength (constraint)); |
279 | |
280 | g_string_append_printf (string: str, format: "%*s<constraint target=\"%s\" target-attribute=\"%s\"\n" , indent, "" , target, target_attr); |
281 | g_string_append_printf (string: str, format: "%*s relation=\"%s\"\n" , indent, "" , relation); |
282 | if (strcmp (s1: source_attr, s2: "none" ) != 0) |
283 | { |
284 | g_string_append_printf (string: str, format: "%*s source=\"%s\" source-attribute=\"%s\"\n" , indent, "" , source, source_attr); |
285 | g_string_append_printf (string: str, format: "%*s multiplier=\"%g\"\n" , indent, "" , multiplier); |
286 | } |
287 | g_string_append_printf (string: str, format: "%*s constant=\"%g\"\n" , indent, "" , constant); |
288 | g_string_append_printf (string: str, format: "%*s strength=\"%s\" />\n" , indent, "" , strength); |
289 | } |
290 | |
291 | static void |
292 | create_constraint (GtkButton *button, |
293 | ConstraintEditor *editor) |
294 | { |
295 | const char *id; |
296 | gpointer target; |
297 | GtkConstraintAttribute target_attr; |
298 | gpointer source; |
299 | GtkConstraintAttribute source_attr; |
300 | GtkConstraintRelation relation; |
301 | double multiplier; |
302 | double constant; |
303 | int strength; |
304 | GtkConstraint *constraint; |
305 | |
306 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)); |
307 | target = get_target (model: editor->model, id); |
308 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr)); |
309 | target_attr = get_target_attr (id); |
310 | |
311 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)); |
312 | source = get_target (model: editor->model, id); |
313 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr)); |
314 | source_attr = get_target_attr (id); |
315 | |
316 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->relation)); |
317 | relation = get_relation (id); |
318 | |
319 | multiplier = g_ascii_strtod (nptr: gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)), NULL); |
320 | |
321 | constant = g_ascii_strtod (nptr: gtk_editable_get_text (GTK_EDITABLE (editor->constant)), NULL); |
322 | |
323 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength)); |
324 | strength = get_strength (id); |
325 | |
326 | constraint = gtk_constraint_new (target, target_attribute: target_attr, |
327 | relation, |
328 | source, source_attribute: source_attr, |
329 | multiplier, |
330 | constant, |
331 | strength); |
332 | g_signal_emit (instance: editor, signal_id: signals[DONE], detail: 0, constraint); |
333 | g_object_unref (object: constraint); |
334 | } |
335 | |
336 | static void |
337 | source_attr_changed (ConstraintEditor *editor) |
338 | { |
339 | const char *id; |
340 | |
341 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr)); |
342 | if (strcmp (s1: id, s2: "none" ) == 0) |
343 | { |
344 | gtk_combo_box_set_active (GTK_COMBO_BOX (editor->source), index_: -1); |
345 | gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), text: "" ); |
346 | gtk_widget_set_sensitive (widget: editor->source, FALSE); |
347 | gtk_widget_set_sensitive (widget: editor->multiplier, FALSE); |
348 | } |
349 | else |
350 | { |
351 | gtk_widget_set_sensitive (widget: editor->source, TRUE); |
352 | gtk_widget_set_sensitive (widget: editor->multiplier, TRUE); |
353 | gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), text: "1" ); |
354 | } |
355 | } |
356 | |
357 | char * |
358 | constraint_editor_constraint_to_string (GtkConstraint *constraint) |
359 | { |
360 | GString *str; |
361 | const char *name; |
362 | const char *attr; |
363 | const char *relation; |
364 | double c, m; |
365 | |
366 | str = g_string_new (init: "" ); |
367 | |
368 | name = get_target_name (target: gtk_constraint_get_target (constraint)); |
369 | attr = get_attr_nick (attr: gtk_constraint_get_target_attribute (constraint)); |
370 | relation = get_relation_display_name (relation: gtk_constraint_get_relation (constraint)); |
371 | |
372 | if (name == NULL) |
373 | name = "[ ]" ; |
374 | |
375 | g_string_append_printf (string: str, format: "%s.%s %s " , name, attr, relation); |
376 | |
377 | c = gtk_constraint_get_constant (constraint); |
378 | |
379 | attr = get_attr_nick (attr: gtk_constraint_get_source_attribute (constraint)); |
380 | if (strcmp (s1: attr, s2: "none" ) != 0) |
381 | { |
382 | name = get_target_name (target: gtk_constraint_get_source (constraint)); |
383 | m = gtk_constraint_get_multiplier (constraint); |
384 | |
385 | if (name == NULL) |
386 | name = "[ ]" ; |
387 | |
388 | g_string_append_printf (string: str, format: "%s.%s" , name, attr); |
389 | |
390 | if (m != 1.0) |
391 | g_string_append_printf (string: str, format: " × %g" , m); |
392 | |
393 | if (c > 0.0) |
394 | g_string_append_printf (string: str, format: " + %g" , c); |
395 | else if (c < 0.0) |
396 | g_string_append_printf (string: str, format: " - %g" , -c); |
397 | } |
398 | else |
399 | g_string_append_printf (string: str, format: "%g" , c); |
400 | |
401 | return g_string_free (string: str, FALSE); |
402 | } |
403 | |
404 | static void |
405 | update_preview (ConstraintEditor *editor) |
406 | { |
407 | GString *str; |
408 | const char *name; |
409 | const char *attr; |
410 | char *relation; |
411 | const char *multiplier; |
412 | const char *constant; |
413 | double c, m; |
414 | |
415 | if (!editor->constructed) |
416 | return; |
417 | |
418 | str = g_string_new (init: "" ); |
419 | |
420 | name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)); |
421 | attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr)); |
422 | relation = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (editor->relation)); |
423 | |
424 | if (name == NULL) |
425 | name = "[ ]" ; |
426 | |
427 | g_string_append_printf (string: str, format: "%s.%s %s " , name, attr, relation); |
428 | g_free (mem: relation); |
429 | |
430 | constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant)); |
431 | c = g_ascii_strtod (nptr: constant, NULL); |
432 | |
433 | attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr)); |
434 | if (strcmp (s1: attr, s2: "none" ) != 0) |
435 | { |
436 | name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)); |
437 | multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)); |
438 | m = g_ascii_strtod (nptr: multiplier, NULL); |
439 | |
440 | if (name == NULL) |
441 | name = "[ ]" ; |
442 | |
443 | g_string_append_printf (string: str, format: "%s.%s" , name, attr); |
444 | |
445 | if (m != 1.0) |
446 | g_string_append_printf (string: str, format: " × %g" , m); |
447 | |
448 | if (c > 0.0) |
449 | g_string_append_printf (string: str, format: " + %g" , c); |
450 | else if (c < 0.0) |
451 | g_string_append_printf (string: str, format: " - %g" , -c); |
452 | } |
453 | else |
454 | g_string_append_printf (string: str, format: "%g" , c); |
455 | |
456 | gtk_label_set_label (GTK_LABEL (editor->preview), str: str->str); |
457 | |
458 | g_string_free (string: str, TRUE); |
459 | } |
460 | |
461 | static void |
462 | update_button (ConstraintEditor *editor) |
463 | { |
464 | const char *target = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)); |
465 | const char *source = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)); |
466 | const char *source_attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr)); |
467 | |
468 | if (target && |
469 | (source || (source_attr && get_target_attr (id: source_attr) == GTK_CONSTRAINT_ATTRIBUTE_NONE))) |
470 | gtk_widget_set_sensitive (widget: editor->button, TRUE); |
471 | else |
472 | gtk_widget_set_sensitive (widget: editor->button, FALSE); |
473 | } |
474 | |
475 | static void |
476 | constraint_editor_init (ConstraintEditor *editor) |
477 | { |
478 | gtk_widget_init_template (GTK_WIDGET (editor)); |
479 | } |
480 | |
481 | static void |
482 | constraint_editor_constructed (GObject *object) |
483 | { |
484 | ConstraintEditor *editor = CONSTRAINT_EDITOR (ptr: object); |
485 | |
486 | constraint_target_combo (model: editor->model, combo: editor->target, FALSE); |
487 | constraint_attribute_combo (combo: editor->target_attr, FALSE); |
488 | constraint_relation_combo (combo: editor->relation); |
489 | constraint_target_combo (model: editor->model, combo: editor->source, TRUE); |
490 | constraint_attribute_combo (combo: editor->source_attr, TRUE); |
491 | |
492 | constraint_strength_combo (combo: editor->strength); |
493 | |
494 | if (editor->constraint) |
495 | { |
496 | GtkConstraintTarget *target; |
497 | GtkConstraintAttribute attr; |
498 | GtkConstraintRelation relation; |
499 | GtkConstraintStrength strength; |
500 | const char *nick; |
501 | char *val; |
502 | double multiplier; |
503 | double constant; |
504 | |
505 | target = gtk_constraint_get_target (constraint: editor->constraint); |
506 | nick = get_target_name (target); |
507 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target), active_id: nick); |
508 | |
509 | attr = gtk_constraint_get_target_attribute (constraint: editor->constraint); |
510 | nick = get_attr_nick (attr); |
511 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), active_id: nick); |
512 | |
513 | target = gtk_constraint_get_source (constraint: editor->constraint); |
514 | nick = get_target_name (target); |
515 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source), active_id: nick); |
516 | |
517 | attr = gtk_constraint_get_source_attribute (constraint: editor->constraint); |
518 | nick = get_attr_nick (attr); |
519 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), active_id: nick); |
520 | |
521 | relation = gtk_constraint_get_relation (constraint: editor->constraint); |
522 | nick = get_relation_nick (relation); |
523 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), active_id: nick); |
524 | |
525 | multiplier = gtk_constraint_get_multiplier (constraint: editor->constraint); |
526 | val = g_strdup_printf (format: "%g" , multiplier); |
527 | gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), text: val); |
528 | g_free (mem: val); |
529 | |
530 | constant = gtk_constraint_get_constant (constraint: editor->constraint); |
531 | val = g_strdup_printf (format: "%g" , constant); |
532 | gtk_editable_set_text (GTK_EDITABLE (editor->constant), text: val); |
533 | g_free (mem: val); |
534 | |
535 | strength = gtk_constraint_get_strength (constraint: editor->constraint); |
536 | nick = get_strength_nick (strength); |
537 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), active_id: nick); |
538 | |
539 | gtk_button_set_label (GTK_BUTTON (editor->button), label: "Apply" ); |
540 | } |
541 | else |
542 | { |
543 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), active_id: "left" ); |
544 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), active_id: "left" ); |
545 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), active_id: "eq" ); |
546 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), active_id: "required" ); |
547 | |
548 | gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), text: "1.0" ); |
549 | gtk_editable_set_text (GTK_EDITABLE (editor->constant), text: "0.0" ); |
550 | |
551 | gtk_button_set_label (GTK_BUTTON (editor->button), label: "Create" ); |
552 | } |
553 | |
554 | editor->constructed = TRUE; |
555 | update_preview (editor); |
556 | update_button (editor); |
557 | } |
558 | |
559 | static void |
560 | constraint_editor_set_property (GObject *object, |
561 | guint property_id, |
562 | const GValue *value, |
563 | GParamSpec *pspec) |
564 | { |
565 | ConstraintEditor *self = CONSTRAINT_EDITOR (ptr: object); |
566 | |
567 | switch (property_id) |
568 | { |
569 | case PROP_MODEL: |
570 | self->model = g_value_dup_object (value); |
571 | break; |
572 | |
573 | case PROP_CONSTRAINT: |
574 | self->constraint = g_value_dup_object (value); |
575 | break; |
576 | |
577 | default: |
578 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
579 | } |
580 | } |
581 | |
582 | static void |
583 | constraint_editor_get_property (GObject *object, |
584 | guint property_id, |
585 | GValue *value, |
586 | GParamSpec *pspec) |
587 | { |
588 | ConstraintEditor *self = CONSTRAINT_EDITOR (ptr: object); |
589 | |
590 | switch (property_id) |
591 | { |
592 | case PROP_MODEL: |
593 | g_value_set_object (value, v_object: self->model); |
594 | break; |
595 | |
596 | case PROP_CONSTRAINT: |
597 | g_value_set_object (value, v_object: self->constraint); |
598 | break; |
599 | |
600 | default: |
601 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
602 | } |
603 | } |
604 | |
605 | static void |
606 | constraint_editor_dispose (GObject *object) |
607 | { |
608 | ConstraintEditor *self = (ConstraintEditor *)object; |
609 | |
610 | g_clear_pointer (&self->grid, gtk_widget_unparent); |
611 | g_clear_object (&self->model); |
612 | g_clear_object (&self->constraint); |
613 | |
614 | G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object); |
615 | } |
616 | |
617 | static void |
618 | constraint_editor_class_init (ConstraintEditorClass *class) |
619 | { |
620 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
621 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
622 | |
623 | object_class->constructed = constraint_editor_constructed; |
624 | object_class->dispose = constraint_editor_dispose; |
625 | object_class->set_property = constraint_editor_set_property; |
626 | object_class->get_property = constraint_editor_get_property; |
627 | |
628 | pspecs[PROP_CONSTRAINT] = |
629 | g_param_spec_object (name: "constraint" , nick: "constraint" , blurb: "constraint" , |
630 | GTK_TYPE_CONSTRAINT, |
631 | flags: G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); |
632 | |
633 | pspecs[PROP_MODEL] = |
634 | g_param_spec_object (name: "model" , nick: "model" , blurb: "model" , |
635 | G_TYPE_LIST_MODEL, |
636 | flags: G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); |
637 | |
638 | g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs); |
639 | |
640 | signals[DONE] = |
641 | g_signal_new (signal_name: "done" , |
642 | G_TYPE_FROM_CLASS (object_class), |
643 | signal_flags: G_SIGNAL_RUN_LAST, |
644 | class_offset: 0, |
645 | NULL, NULL, |
646 | NULL, |
647 | G_TYPE_NONE, n_params: 1, GTK_TYPE_CONSTRAINT); |
648 | |
649 | gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); |
650 | |
651 | gtk_widget_class_set_template_from_resource (widget_class, |
652 | resource_name: "/org/gtk/gtk4/constraint-editor/constraint-editor.ui" ); |
653 | |
654 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, grid); |
655 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target); |
656 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target_attr); |
657 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, relation); |
658 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source); |
659 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source_attr); |
660 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, multiplier); |
661 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, constant); |
662 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, strength); |
663 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, preview); |
664 | gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, button); |
665 | |
666 | gtk_widget_class_bind_template_callback (widget_class, update_preview); |
667 | gtk_widget_class_bind_template_callback (widget_class, update_button); |
668 | gtk_widget_class_bind_template_callback (widget_class, create_constraint); |
669 | gtk_widget_class_bind_template_callback (widget_class, source_attr_changed); |
670 | } |
671 | |
672 | ConstraintEditor * |
673 | constraint_editor_new (GListModel *model, |
674 | GtkConstraint *constraint) |
675 | { |
676 | return g_object_new (CONSTRAINT_EDITOR_TYPE, |
677 | first_property_name: "model" , model, |
678 | "constraint" , constraint, |
679 | NULL); |
680 | } |
681 | |