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 "guide-editor.h" |
23 | |
24 | struct _GuideEditor |
25 | { |
26 | GtkWidget parent_instance; |
27 | |
28 | GtkWidget *grid; |
29 | GtkWidget *name; |
30 | GtkWidget *min_width; |
31 | GtkWidget *min_height; |
32 | GtkWidget *nat_width; |
33 | GtkWidget *nat_height; |
34 | GtkWidget *max_width; |
35 | GtkWidget *max_height; |
36 | GtkWidget *strength; |
37 | GtkWidget *button; |
38 | |
39 | GtkConstraintGuide *guide; |
40 | |
41 | gboolean constructed; |
42 | }; |
43 | |
44 | enum { |
45 | PROP_GUIDE = 1, |
46 | LAST_PROP |
47 | }; |
48 | |
49 | static GParamSpec *pspecs[LAST_PROP]; |
50 | |
51 | enum { |
52 | DONE, |
53 | LAST_SIGNAL |
54 | }; |
55 | |
56 | static guint signals[LAST_SIGNAL]; |
57 | |
58 | G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET); |
59 | |
60 | static void |
61 | guide_strength_combo (GtkWidget *combo) |
62 | { |
63 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "weak" , text: "Weak" ); |
64 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "medium" , text: "Medium" ); |
65 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "strong" , text: "Strong" ); |
66 | gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), id: "required" , text: "Required" ); |
67 | } |
68 | |
69 | static GtkConstraintStrength |
70 | get_strength (const char *id) |
71 | { |
72 | GtkConstraintStrength strength; |
73 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_STRENGTH); |
74 | GEnumValue *value = g_enum_get_value_by_nick (enum_class: class, nick: id); |
75 | strength = value->value; |
76 | g_type_class_unref (g_class: class); |
77 | |
78 | return strength; |
79 | } |
80 | |
81 | static const char * |
82 | get_strength_nick (GtkConstraintStrength strength) |
83 | { |
84 | GEnumClass *class = g_type_class_ref (type: GTK_TYPE_CONSTRAINT_STRENGTH); |
85 | GEnumValue *value = g_enum_get_value (enum_class: class, value: strength); |
86 | const char *nick = value->value_nick; |
87 | g_type_class_unref (g_class: class); |
88 | |
89 | return nick; |
90 | } |
91 | |
92 | void |
93 | guide_editor_serialize_guide (GString *str, |
94 | int indent, |
95 | GtkConstraintGuide *guide) |
96 | { |
97 | int min_width, min_height; |
98 | int nat_width, nat_height; |
99 | int max_width, max_height; |
100 | const char *name; |
101 | const char *strength; |
102 | |
103 | gtk_constraint_guide_get_min_size (guide, width: &min_width, height: &min_height); |
104 | gtk_constraint_guide_get_nat_size (guide, width: &nat_width, height: &nat_height); |
105 | gtk_constraint_guide_get_max_size (guide, width: &max_width, height: &max_height); |
106 | name = gtk_constraint_guide_get_name (guide); |
107 | strength = get_strength_nick (strength: gtk_constraint_guide_get_strength (guide)); |
108 | |
109 | g_string_append_printf (string: str, format: "%*s<guide min-width=\"%d\" min-height=\"%d\"\n" , indent, "" , min_width, min_height); |
110 | g_string_append_printf (string: str, format: "%*s nat-width=\"%d\" nat-height=\"%d\"\n" , indent, "" , nat_width, nat_height); |
111 | g_string_append_printf (string: str, format: "%*s max-width=\"%d\" max-height=\"%d\"\n" , indent, "" , max_width, max_height); |
112 | g_string_append_printf (string: str, format: "%*s name=\"%s\" strength=\"%s\" />\n" , indent, "" , name, strength); |
113 | } |
114 | |
115 | static void |
116 | create_guide (GtkButton *button, |
117 | GuideEditor *editor) |
118 | { |
119 | const char *id; |
120 | int strength; |
121 | const char *name; |
122 | int w, h; |
123 | GtkConstraintGuide *guide; |
124 | |
125 | if (editor->guide) |
126 | guide = g_object_ref (editor->guide); |
127 | else |
128 | guide = gtk_constraint_guide_new (); |
129 | |
130 | name = gtk_editable_get_text (GTK_EDITABLE (editor->name)); |
131 | gtk_constraint_guide_set_name (guide, name); |
132 | |
133 | w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width)); |
134 | h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height)); |
135 | gtk_constraint_guide_set_min_size (guide, width: w, height: h); |
136 | |
137 | w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_width)); |
138 | h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_height)); |
139 | gtk_constraint_guide_set_nat_size (guide, width: w, height: h); |
140 | |
141 | w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_width)); |
142 | h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height)); |
143 | gtk_constraint_guide_set_max_size (guide, width: w, height: h); |
144 | |
145 | id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength)); |
146 | strength = get_strength (id); |
147 | gtk_constraint_guide_set_strength (guide, strength); |
148 | |
149 | g_signal_emit (instance: editor, signal_id: signals[DONE], detail: 0, guide); |
150 | g_object_unref (object: guide); |
151 | } |
152 | |
153 | static void |
154 | guide_editor_init (GuideEditor *editor) |
155 | { |
156 | gtk_widget_init_template (GTK_WIDGET (editor)); |
157 | } |
158 | |
159 | static int guide_counter; |
160 | |
161 | static int |
162 | min_input (GtkSpinButton *spin_button, |
163 | double *new_val) |
164 | { |
165 | if (strcmp (s1: gtk_editable_get_text (GTK_EDITABLE (spin_button)), s2: "" ) == 0) |
166 | { |
167 | *new_val = 0.0; |
168 | return TRUE; |
169 | } |
170 | |
171 | return FALSE; |
172 | } |
173 | |
174 | static int |
175 | max_input (GtkSpinButton *spin_button, |
176 | double *new_val) |
177 | { |
178 | if (strcmp (s1: gtk_editable_get_text (GTK_EDITABLE (spin_button)), s2: "" ) == 0) |
179 | { |
180 | *new_val = G_MAXINT; |
181 | return TRUE; |
182 | } |
183 | |
184 | return FALSE; |
185 | } |
186 | |
187 | static void |
188 | guide_editor_constructed (GObject *object) |
189 | { |
190 | GuideEditor *editor = GUIDE_EDITOR (ptr: object); |
191 | |
192 | guide_strength_combo (combo: editor->strength); |
193 | |
194 | g_signal_connect (editor->min_width, "input" , G_CALLBACK (min_input), NULL); |
195 | |
196 | g_signal_connect (editor->min_height, "input" , G_CALLBACK (min_input), NULL); |
197 | |
198 | g_signal_connect (editor->max_width, "input" , G_CALLBACK (max_input), NULL); |
199 | |
200 | g_signal_connect (editor->max_height, "input" , G_CALLBACK (max_input), NULL); |
201 | |
202 | if (editor->guide) |
203 | { |
204 | GtkConstraintStrength strength; |
205 | const char *nick; |
206 | int w, h; |
207 | |
208 | nick = gtk_constraint_guide_get_name (guide: editor->guide); |
209 | if (nick) |
210 | gtk_editable_set_text (GTK_EDITABLE (editor->name), text: nick); |
211 | |
212 | gtk_constraint_guide_get_min_size (guide: editor->guide, width: &w, height: &h); |
213 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), value: w); |
214 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), value: h); |
215 | |
216 | gtk_constraint_guide_get_nat_size (guide: editor->guide, width: &w, height: &h); |
217 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), value: w); |
218 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), value: h); |
219 | |
220 | gtk_constraint_guide_get_max_size (guide: editor->guide, width: &w, height: &h); |
221 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), value: w); |
222 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), value: h); |
223 | |
224 | strength = gtk_constraint_guide_get_strength (guide: editor->guide); |
225 | nick = get_strength_nick (strength); |
226 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), active_id: nick); |
227 | |
228 | gtk_button_set_label (GTK_BUTTON (editor->button), label: "Apply" ); |
229 | } |
230 | else |
231 | { |
232 | char *name; |
233 | |
234 | guide_counter++; |
235 | name = g_strdup_printf (format: "Guide %d" , guide_counter); |
236 | gtk_editable_set_text (GTK_EDITABLE (editor->name), text: name); |
237 | g_free (mem: name); |
238 | |
239 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), value: 0.0); |
240 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), value: 0.0); |
241 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), value: 0.0); |
242 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), value: 0.0); |
243 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT); |
244 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT); |
245 | |
246 | gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), active_id: "medium" ); |
247 | |
248 | gtk_button_set_label (GTK_BUTTON (editor->button), label: "Create" ); |
249 | } |
250 | |
251 | editor->constructed = TRUE; |
252 | } |
253 | |
254 | static void |
255 | guide_editor_set_property (GObject *object, |
256 | guint property_id, |
257 | const GValue *value, |
258 | GParamSpec *pspec) |
259 | { |
260 | GuideEditor *self = GUIDE_EDITOR (ptr: object); |
261 | |
262 | switch (property_id) |
263 | { |
264 | case PROP_GUIDE: |
265 | self->guide = g_value_dup_object (value); |
266 | break; |
267 | |
268 | default: |
269 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
270 | } |
271 | } |
272 | |
273 | static void |
274 | guide_editor_get_property (GObject *object, |
275 | guint property_id, |
276 | GValue *value, |
277 | GParamSpec *pspec) |
278 | { |
279 | GuideEditor *self = GUIDE_EDITOR (ptr: object); |
280 | |
281 | switch (property_id) |
282 | { |
283 | case PROP_GUIDE: |
284 | g_value_set_object (value, v_object: self->guide); |
285 | break; |
286 | |
287 | default: |
288 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); |
289 | } |
290 | } |
291 | |
292 | static void |
293 | guide_editor_dispose (GObject *object) |
294 | { |
295 | GuideEditor *self = (GuideEditor *)object; |
296 | |
297 | g_clear_pointer (&self->grid, gtk_widget_unparent); |
298 | g_clear_object (&self->guide); |
299 | |
300 | G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object); |
301 | } |
302 | |
303 | static void |
304 | guide_editor_class_init (GuideEditorClass *class) |
305 | { |
306 | GObjectClass *object_class = G_OBJECT_CLASS (class); |
307 | GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); |
308 | |
309 | object_class->constructed = guide_editor_constructed; |
310 | object_class->dispose = guide_editor_dispose; |
311 | object_class->set_property = guide_editor_set_property; |
312 | object_class->get_property = guide_editor_get_property; |
313 | |
314 | pspecs[PROP_GUIDE] = |
315 | g_param_spec_object (name: "guide" , nick: "guide" , blurb: "guide" , |
316 | GTK_TYPE_CONSTRAINT_GUIDE, |
317 | flags: G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); |
318 | |
319 | g_object_class_install_properties (oclass: object_class, n_pspecs: LAST_PROP, pspecs); |
320 | |
321 | signals[DONE] = |
322 | g_signal_new (signal_name: "done" , |
323 | G_TYPE_FROM_CLASS (object_class), |
324 | signal_flags: G_SIGNAL_RUN_LAST, |
325 | class_offset: 0, |
326 | NULL, NULL, |
327 | NULL, |
328 | G_TYPE_NONE, n_params: 1, GTK_TYPE_CONSTRAINT_GUIDE); |
329 | |
330 | gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); |
331 | |
332 | gtk_widget_class_set_template_from_resource (widget_class, |
333 | resource_name: "/org/gtk/gtk4/constraint-editor/guide-editor.ui" ); |
334 | |
335 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, grid); |
336 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, name); |
337 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_width); |
338 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_height); |
339 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_width); |
340 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_height); |
341 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_width); |
342 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_height); |
343 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, strength); |
344 | gtk_widget_class_bind_template_child (widget_class, GuideEditor, button); |
345 | |
346 | gtk_widget_class_bind_template_callback (widget_class, create_guide); |
347 | } |
348 | |
349 | GuideEditor * |
350 | guide_editor_new (GtkConstraintGuide *guide) |
351 | { |
352 | return g_object_new (GUIDE_EDITOR_TYPE, |
353 | first_property_name: "guide" , guide, |
354 | NULL); |
355 | } |
356 | |