1/* gtkconstraint.c: Constraint between two widgets
2 * Copyright 2019 GNOME Foundation
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 * Author: Emmanuele Bassi
18 */
19
20/**
21 * GtkConstraint:
22 *
23 * `GtkConstraint` describes a constraint between attributes of two widgets,
24 * expressed as a linear equation.
25 *
26 * The typical equation for a constraint is:
27 *
28 * ```
29 * target.target_attr = source.source_attr × multiplier + constant
30 * ```
31 *
32 * Each `GtkConstraint` is part of a system that will be solved by a
33 * [class@Gtk.ConstraintLayout] in order to allocate and position each
34 * child widget or guide.
35 *
36 * The source and target, as well as their attributes, of a `GtkConstraint`
37 * instance are immutable after creation.
38 */
39
40#include "config.h"
41
42#include "gtkconstraintprivate.h"
43#include "gtkconstraintsolverprivate.h"
44#include "gtkintl.h"
45#include "gtktypebuiltins.h"
46#include "gtkwidget.h"
47
48enum {
49 PROP_TARGET = 1,
50 PROP_TARGET_ATTRIBUTE,
51 PROP_RELATION,
52 PROP_SOURCE,
53 PROP_SOURCE_ATTRIBUTE,
54 PROP_MULTIPLIER,
55 PROP_CONSTANT,
56 PROP_STRENGTH,
57
58 N_PROPERTIES
59};
60
61static GParamSpec *obj_props[N_PROPERTIES];
62
63G_DEFINE_TYPE (GtkConstraint, gtk_constraint, G_TYPE_OBJECT)
64
65static void
66gtk_constraint_set_property (GObject *gobject,
67 guint prop_id,
68 const GValue *value,
69 GParamSpec *pspec)
70{
71 GtkConstraint *self = GTK_CONSTRAINT (ptr: gobject);
72
73 switch (prop_id)
74 {
75 case PROP_TARGET:
76 self->target = g_value_get_object (value);
77 break;
78
79 case PROP_TARGET_ATTRIBUTE:
80 self->target_attribute = g_value_get_enum (value);
81 break;
82
83 case PROP_RELATION:
84 self->relation = g_value_get_enum (value);
85 break;
86
87 case PROP_SOURCE:
88 self->source = g_value_get_object (value);
89 break;
90
91 case PROP_SOURCE_ATTRIBUTE:
92 self->source_attribute = g_value_get_enum (value);
93 break;
94
95 case PROP_MULTIPLIER:
96 self->multiplier = g_value_get_double (value);
97 break;
98
99 case PROP_CONSTANT:
100 self->constant = g_value_get_double (value);
101 break;
102
103 case PROP_STRENGTH:
104 self->strength = g_value_get_int (value);
105 break;
106
107 default:
108 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
109 break;
110 }
111}
112
113static void
114gtk_constraint_get_property (GObject *gobject,
115 guint prop_id,
116 GValue *value,
117 GParamSpec *pspec)
118{
119 GtkConstraint *self = GTK_CONSTRAINT (ptr: gobject);
120
121 switch (prop_id)
122 {
123 case PROP_TARGET:
124 g_value_set_object (value, v_object: self->target);
125 break;
126
127 case PROP_TARGET_ATTRIBUTE:
128 g_value_set_enum (value, v_enum: self->target_attribute);
129 break;
130
131 case PROP_RELATION:
132 g_value_set_enum (value, v_enum: self->relation);
133 break;
134
135 case PROP_SOURCE:
136 g_value_set_object (value, v_object: self->source);
137 break;
138
139 case PROP_SOURCE_ATTRIBUTE:
140 g_value_set_enum (value, v_enum: self->source_attribute);
141 break;
142
143 case PROP_MULTIPLIER:
144 g_value_set_double (value, v_double: self->multiplier);
145 break;
146
147 case PROP_CONSTANT:
148 g_value_set_double (value, v_double: self->constant);
149 break;
150
151 case PROP_STRENGTH:
152 g_value_set_int (value, v_int: self->strength);
153 break;
154
155 default:
156 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
157 break;
158 }
159}
160
161static void
162gtk_constraint_finalize (GObject *gobject)
163{
164 GtkConstraint *self = GTK_CONSTRAINT (ptr: gobject);
165
166 gtk_constraint_detach (constraint: self);
167
168 G_OBJECT_CLASS (gtk_constraint_parent_class)->finalize (gobject);
169}
170
171static void
172gtk_constraint_class_init (GtkConstraintClass *klass)
173{
174 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
175
176 gobject_class->set_property = gtk_constraint_set_property;
177 gobject_class->get_property = gtk_constraint_get_property;
178 gobject_class->finalize = gtk_constraint_finalize;
179
180 /**
181 * GtkConstraint:target: (attributes org.gtk.Property.get=gtk_constraint_get_target)
182 *
183 * The target of the constraint.
184 *
185 * The constraint will set the [property@Gtk.Constraint:target-attribute]
186 * property of the target using the [property@Gtk.Constraint:source-attribute]
187 * property of the source widget.
188 *
189 *
190 */
191 obj_props[PROP_TARGET] =
192 g_param_spec_object (name: "target",
193 P_("Target"),
194 P_("The target of the constraint"),
195 GTK_TYPE_CONSTRAINT_TARGET,
196 flags: G_PARAM_READWRITE |
197 G_PARAM_STATIC_STRINGS |
198 G_PARAM_CONSTRUCT_ONLY);
199
200 /**
201 * GtkConstraint:target-attribute: (attributes org.gtk.Property.get=gtk_constraint_get_target_attribute)
202 *
203 * The attribute of the [property@Gtk.Constraint:target] set by the constraint.
204 */
205 obj_props[PROP_TARGET_ATTRIBUTE] =
206 g_param_spec_enum (name: "target-attribute",
207 P_("Target Attribute"),
208 P_("The attribute of the target set by the constraint"),
209 enum_type: GTK_TYPE_CONSTRAINT_ATTRIBUTE,
210 default_value: GTK_CONSTRAINT_ATTRIBUTE_NONE,
211 flags: G_PARAM_READWRITE |
212 G_PARAM_STATIC_STRINGS |
213 G_PARAM_CONSTRUCT_ONLY);
214
215 /**
216 * GtkConstraint:relation: (attributes org.gtk.Property.get=gtk_constraint_get_relation)
217 *
218 * The order relation between the terms of the constraint.
219 */
220 obj_props[PROP_RELATION] =
221 g_param_spec_enum (name: "relation",
222 P_("Relation"),
223 P_("The relation between the source and target attributes"),
224 enum_type: GTK_TYPE_CONSTRAINT_RELATION,
225 default_value: GTK_CONSTRAINT_RELATION_EQ,
226 flags: G_PARAM_READWRITE |
227 G_PARAM_STATIC_STRINGS |
228 G_PARAM_CONSTRUCT_ONLY);
229
230 /**
231 * GtkConstraint:source: (attributes org.gtk.Property.get=gtk_constraint_get_source)
232 *
233 * The source of the constraint.
234 *
235 * The constraint will set the [property@Gtk.Constraint:target-attribute]
236 * property of the target using the [property@Gtk.Constraint:source-attribute]
237 * property of the source.
238 */
239 obj_props[PROP_SOURCE] =
240 g_param_spec_object (name: "source",
241 P_("Source"),
242 P_("The source of the constraint"),
243 GTK_TYPE_CONSTRAINT_TARGET,
244 flags: G_PARAM_READWRITE |
245 G_PARAM_STATIC_STRINGS |
246 G_PARAM_CONSTRUCT_ONLY);
247 /**
248 * GtkConstraint:source-attribute: (attributes org.gtk.Property.get=gtk_constraint_get_source_attribute)
249 *
250 * The attribute of the [property@Gtk.Constraint:source] read by the
251 * constraint.
252 */
253 obj_props[PROP_SOURCE_ATTRIBUTE] =
254 g_param_spec_enum (name: "source-attribute",
255 P_("Source Attribute"),
256 P_("The attribute of the source widget set by the constraint"),
257 enum_type: GTK_TYPE_CONSTRAINT_ATTRIBUTE,
258 default_value: GTK_CONSTRAINT_ATTRIBUTE_NONE,
259 flags: G_PARAM_READWRITE |
260 G_PARAM_STATIC_STRINGS |
261 G_PARAM_CONSTRUCT_ONLY);
262
263 /**
264 * GtkConstraint:multiplier: (attributes org.gtk.Property.get=gtk_constraint_get_multiplier)
265 *
266 * The multiplication factor to be applied to
267 * the [property@Gtk.Constraint:source-attribute].
268 */
269 obj_props[PROP_MULTIPLIER] =
270 g_param_spec_double (name: "multiplier",
271 P_("Multiplier"),
272 P_("The multiplication factor to be applied to the source attribute"),
273 minimum: -G_MAXDOUBLE, G_MAXDOUBLE, default_value: 1.0,
274 flags: G_PARAM_READWRITE |
275 G_PARAM_STATIC_STRINGS |
276 G_PARAM_CONSTRUCT_ONLY);
277
278 /**
279 * GtkConstraint:constant: (attributes org.gtk.Property.get=gtk_constraint_get_constant)
280 *
281 * The constant value to be added to the [property@Gtk.Constraint:source-attribute].
282 */
283 obj_props[PROP_CONSTANT] =
284 g_param_spec_double (name: "constant",
285 P_("Constant"),
286 P_("The constant to be added to the source attribute"),
287 minimum: -G_MAXDOUBLE, G_MAXDOUBLE, default_value: 0.0,
288 flags: G_PARAM_READWRITE |
289 G_PARAM_STATIC_STRINGS |
290 G_PARAM_CONSTRUCT_ONLY);
291
292 /**
293 * GtkConstraint:strength: (attributes org.gtk.Property.get=gtk_constraint_get_strength)
294 *
295 * The strength of the constraint.
296 *
297 * The strength can be expressed either using one of the symbolic values
298 * of the [enum@Gtk.ConstraintStrength] enumeration, or any positive integer
299 * value.
300 */
301 obj_props[PROP_STRENGTH] =
302 g_param_spec_int (name: "strength",
303 P_("Strength"),
304 P_("The strength of the constraint"),
305 minimum: 0, maximum: GTK_CONSTRAINT_STRENGTH_REQUIRED,
306 default_value: GTK_CONSTRAINT_STRENGTH_REQUIRED,
307 flags: G_PARAM_READWRITE |
308 G_PARAM_STATIC_STRINGS |
309 G_PARAM_CONSTRUCT_ONLY);
310
311 g_object_class_install_properties (oclass: gobject_class, n_pspecs: N_PROPERTIES, pspecs: obj_props);
312}
313
314static void
315gtk_constraint_init (GtkConstraint *self)
316{
317 self->multiplier = 1.0;
318 self->constant = 0.0;
319
320 self->target_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE;
321 self->source_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE;
322 self->relation = GTK_CONSTRAINT_RELATION_EQ;
323 self->strength = GTK_CONSTRAINT_STRENGTH_REQUIRED;
324}
325
326/**
327 * gtk_constraint_new: (constructor)
328 * @target: (nullable) (type GtkConstraintTarget): the target of the constraint
329 * @target_attribute: the attribute of `target` to be set
330 * @relation: the relation equivalence between `target_attribute` and `source_attribute`
331 * @source: (nullable) (type GtkConstraintTarget): the source of the constraint
332 * @source_attribute: the attribute of `source` to be read
333 * @multiplier: a multiplication factor to be applied to `source_attribute`
334 * @constant: a constant factor to be added to `source_attribute`
335 * @strength: the strength of the constraint
336 *
337 * Creates a new constraint representing a relation between a layout
338 * attribute on a source and a layout attribute on a target.
339 *
340 * Returns: (transfer full): the newly created constraint
341 */
342GtkConstraint *
343gtk_constraint_new (gpointer target,
344 GtkConstraintAttribute target_attribute,
345 GtkConstraintRelation relation,
346 gpointer source,
347 GtkConstraintAttribute source_attribute,
348 double multiplier,
349 double constant,
350 int strength)
351{
352 g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL);
353 g_return_val_if_fail (source == NULL || GTK_IS_CONSTRAINT_TARGET (source), NULL);
354
355 return g_object_new (GTK_TYPE_CONSTRAINT,
356 first_property_name: "target", target,
357 "target-attribute", target_attribute,
358 "relation", relation,
359 "source", source,
360 "source-attribute", source_attribute,
361 "multiplier", multiplier,
362 "constant", constant,
363 "strength", strength,
364 NULL);
365}
366
367/**
368 * gtk_constraint_new_constant: (constructor)
369 * @target: (nullable) (type GtkConstraintTarget): a the target of the constraint
370 * @target_attribute: the attribute of `target` to be set
371 * @relation: the relation equivalence between `target_attribute` and `constant`
372 * @constant: a constant factor to be set on `target_attribute`
373 * @strength: the strength of the constraint
374 *
375 * Creates a new constraint representing a relation between a layout
376 * attribute on a target and a constant value.
377 *
378 * Returns: (transfer full): the newly created constraint
379 */
380GtkConstraint *
381gtk_constraint_new_constant (gpointer target,
382 GtkConstraintAttribute target_attribute,
383 GtkConstraintRelation relation,
384 double constant,
385 int strength)
386{
387 g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL);
388
389 return g_object_new (GTK_TYPE_CONSTRAINT,
390 first_property_name: "target", target,
391 "target-attribute", target_attribute,
392 "relation", relation,
393 "source-attribute", GTK_CONSTRAINT_ATTRIBUTE_NONE,
394 "constant", constant,
395 "strength", strength,
396 NULL);
397}
398
399/**
400 * gtk_constraint_get_target: (attributes org.gtk.Method.get_property=target)
401 * @constraint: a `GtkConstraint`
402 *
403 * Retrieves the [iface@Gtk.ConstraintTarget] used as the target for
404 * the constraint.
405 *
406 * If the targe is set to `NULL` at creation, the constraint will use
407 * the widget using the [class@Gtk.ConstraintLayout] as the target.
408 *
409 * Returns: (transfer none) (nullable): a `GtkConstraintTarget`
410 */
411GtkConstraintTarget *
412gtk_constraint_get_target (GtkConstraint *constraint)
413{
414 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
415
416 return constraint->target;
417}
418
419/**
420 * gtk_constraint_get_target_attribute: (attributes org.gtk.Method.get_property=target-attribute)
421 * @constraint: a `GtkConstraint`
422 *
423 * Retrieves the attribute of the target to be set by the constraint.
424 *
425 * Returns: the target's attribute
426 */
427GtkConstraintAttribute
428gtk_constraint_get_target_attribute (GtkConstraint *constraint)
429{
430 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE);
431
432 return constraint->target_attribute;
433}
434
435/**
436 * gtk_constraint_get_source: (attributes org.gtk.Method.get_property=source)
437 * @constraint: a `GtkConstraint`
438 *
439 * Retrieves the [iface@Gtk.ConstraintTarget] used as the source for the
440 * constraint.
441 *
442 * If the source is set to `NULL` at creation, the constraint will use
443 * the widget using the [class@Gtk.ConstraintLayout] as the source.
444 *
445 * Returns: (transfer none) (nullable): the source of the constraint
446 */
447GtkConstraintTarget *
448gtk_constraint_get_source (GtkConstraint *constraint)
449{
450 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
451
452 return constraint->source;
453}
454
455/**
456 * gtk_constraint_get_source_attribute: (attributes org.gtk.Method.get_property=source-attribute)
457 * @constraint: a `GtkConstraint`
458 *
459 * Retrieves the attribute of the source to be read by the constraint.
460 *
461 * Returns: the source's attribute
462 */
463GtkConstraintAttribute
464gtk_constraint_get_source_attribute (GtkConstraint *constraint)
465{
466 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE);
467
468 return constraint->source_attribute;
469}
470
471/**
472 * gtk_constraint_get_relation: (attributes org.gtk.Method.get_property=relation)
473 * @constraint: a `GtkConstraint`
474 *
475 * The order relation between the terms of the constraint.
476 *
477 * Returns: a relation type
478 */
479GtkConstraintRelation
480gtk_constraint_get_relation (GtkConstraint *constraint)
481{
482 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_RELATION_EQ);
483
484 return constraint->relation;
485}
486
487/**
488 * gtk_constraint_get_multiplier: (attributes org.gtk.Method.get_property=multiplier)
489 * @constraint: a `GtkConstraint`
490 *
491 * Retrieves the multiplication factor applied to the source
492 * attribute's value.
493 *
494 * Returns: a multiplication factor
495 */
496double
497gtk_constraint_get_multiplier (GtkConstraint *constraint)
498{
499 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 1.0);
500
501 return constraint->multiplier;
502}
503
504/**
505 * gtk_constraint_get_constant: (attributes org.gtk.Method.get_property=constant)
506 * @constraint: a `GtkConstraint`
507 *
508 * Retrieves the constant factor added to the source attributes' value.
509 *
510 * Returns: a constant factor
511 */
512double
513gtk_constraint_get_constant (GtkConstraint *constraint)
514{
515 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 0.0);
516
517 return constraint->constant;
518}
519
520/**
521 * gtk_constraint_get_strength: (attributes org.gtk.Method.get_property=strength)
522 * @constraint: a `GtkConstraint`
523 *
524 * Retrieves the strength of the constraint.
525 *
526 * Returns: the strength value
527 */
528int
529gtk_constraint_get_strength (GtkConstraint *constraint)
530{
531 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_STRENGTH_REQUIRED);
532
533 return constraint->strength;
534}
535
536/**
537 * gtk_constraint_is_required:
538 * @constraint: a `GtkConstraint`
539 *
540 * Checks whether the constraint is a required relation for solving the
541 * constraint layout.
542 *
543 * Returns: %TRUE if the constraint is required
544 */
545gboolean
546gtk_constraint_is_required (GtkConstraint *constraint)
547{
548 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
549
550 return constraint->strength == GTK_CONSTRAINT_STRENGTH_REQUIRED;
551}
552
553/**
554 * gtk_constraint_is_attached:
555 * @constraint: a `GtkConstraint`
556 *
557 * Checks whether the constraint is attached to a [class@Gtk.ConstraintLayout],
558 * and it is contributing to the layout.
559 *
560 * Returns: `TRUE` if the constraint is attached
561 */
562gboolean
563gtk_constraint_is_attached (GtkConstraint *constraint)
564{
565 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
566
567 return constraint->constraint_ref != NULL;
568}
569
570/**
571 * gtk_constraint_is_constant:
572 * @constraint: a `GtkConstraint`
573 *
574 * Checks whether the constraint describes a relation between an attribute
575 * on the [property@Gtk.Constraint:target] and a constant value.
576 *
577 * Returns: `TRUE` if the constraint is a constant relation
578 */
579gboolean
580gtk_constraint_is_constant (GtkConstraint *constraint)
581{
582 g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
583
584 return constraint->source == NULL &&
585 constraint->source_attribute == GTK_CONSTRAINT_ATTRIBUTE_NONE;
586}
587
588void
589gtk_constraint_attach (GtkConstraint *constraint,
590 GtkConstraintSolver *solver,
591 GtkConstraintRef *ref)
592{
593 g_return_if_fail (GTK_IS_CONSTRAINT (constraint));
594 g_return_if_fail (GTK_IS_CONSTRAINT_SOLVER (solver));
595 g_return_if_fail (ref != NULL);
596
597 constraint->constraint_ref = ref;
598 constraint->solver = solver;
599}
600
601void
602gtk_constraint_detach (GtkConstraint *constraint)
603{
604 g_return_if_fail (GTK_IS_CONSTRAINT (constraint));
605
606 if (constraint->constraint_ref == NULL)
607 return;
608
609 gtk_constraint_solver_remove_constraint (solver: constraint->solver, reference: constraint->constraint_ref);
610 constraint->constraint_ref = NULL;
611 constraint->solver = NULL;
612}
613
614typedef struct _GtkConstraintTargetInterface GtkConstraintTargetInterface;
615
616struct _GtkConstraintTargetInterface
617{
618 GTypeInterface g_iface;
619};
620
621G_DEFINE_INTERFACE (GtkConstraintTarget, gtk_constraint_target, G_TYPE_OBJECT)
622
623static void
624gtk_constraint_target_default_init (GtkConstraintTargetInterface *iface)
625{
626}
627

source code of gtk/gtk/gtkconstraint.c