/* gtkconstraint.c: Constraint between two widgets * Copyright 2019 GNOME Foundation * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Author: Emmanuele Bassi */ /** * SECTION:gtkconstraint * @Title: GtkConstraint * @Short_description: The description of a constraint * * `GtkConstraint` describes a constraint between an attribute on a widget * and another attribute on another widget, expressed as a linear equation. * * For instance: * * ``` * target.attr1 = source.attr2 × multiplier + constant * ``` * * Each `GtkConstraint` is part of a system that will be solved by a * [class@Gtk.ConstraintLayout] in order to allocate and position each * child widget or guide. * * The source and target, as well as their attributes, of a `GtkConstraint` * instance are immutable after creation. */ #include "config.h" #include "gtkconstraintprivate.h" #include "gtkconstraintsolverprivate.h" #include "gtkintl.h" #include "gtktypebuiltins.h" #include "gtkwidget.h" enum { PROP_TARGET = 1, PROP_TARGET_ATTRIBUTE, PROP_RELATION, PROP_SOURCE, PROP_SOURCE_ATTRIBUTE, PROP_MULTIPLIER, PROP_CONSTANT, PROP_STRENGTH, N_PROPERTIES }; static GParamSpec *obj_props[N_PROPERTIES]; G_DEFINE_TYPE (GtkConstraint, gtk_constraint, G_TYPE_OBJECT) static void gtk_constraint_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { GtkConstraint *self = GTK_CONSTRAINT (gobject); switch (prop_id) { case PROP_TARGET: self->target = g_value_get_object (value); break; case PROP_TARGET_ATTRIBUTE: self->target_attribute = g_value_get_enum (value); break; case PROP_RELATION: self->relation = g_value_get_enum (value); break; case PROP_SOURCE: self->source = g_value_get_object (value); break; case PROP_SOURCE_ATTRIBUTE: self->source_attribute = g_value_get_enum (value); break; case PROP_MULTIPLIER: self->multiplier = g_value_get_double (value); break; case PROP_CONSTANT: self->constant = g_value_get_double (value); break; case PROP_STRENGTH: self->strength = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void gtk_constraint_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { GtkConstraint *self = GTK_CONSTRAINT (gobject); switch (prop_id) { case PROP_TARGET: g_value_set_object (value, self->target); break; case PROP_TARGET_ATTRIBUTE: g_value_set_enum (value, self->target_attribute); break; case PROP_RELATION: g_value_set_enum (value, self->relation); break; case PROP_SOURCE: g_value_set_object (value, self->source); break; case PROP_SOURCE_ATTRIBUTE: g_value_set_enum (value, self->source_attribute); break; case PROP_MULTIPLIER: g_value_set_double (value, self->multiplier); break; case PROP_CONSTANT: g_value_set_double (value, self->constant); break; case PROP_STRENGTH: g_value_set_int (value, self->strength); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); break; } } static void gtk_constraint_finalize (GObject *gobject) { GtkConstraint *self = GTK_CONSTRAINT (gobject); gtk_constraint_detach (self); G_OBJECT_CLASS (gtk_constraint_parent_class)->finalize (gobject); } static void gtk_constraint_class_init (GtkConstraintClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->set_property = gtk_constraint_set_property; gobject_class->get_property = gtk_constraint_get_property; gobject_class->finalize = gtk_constraint_finalize; /** * GtkConstraint:target: * * The target of the constraint. * * The constraint will set the #GtkConstraint:target-attribute of the * target using the #GtkConstraint:source-attribute of the source * widget. */ obj_props[PROP_TARGET] = g_param_spec_object ("target", P_("Target"), P_("The target of the constraint"), GTK_TYPE_CONSTRAINT_TARGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); /** * GtkConstraint:target-attribute: * * The attribute of the #GtkConstraint:target set by the constraint. */ obj_props[PROP_TARGET_ATTRIBUTE] = g_param_spec_enum ("target-attribute", P_("Target Attribute"), P_("The attribute of the target set by the constraint"), GTK_TYPE_CONSTRAINT_ATTRIBUTE, GTK_CONSTRAINT_ATTRIBUTE_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); /** * GtkConstraint:relation: * * The order relation between the terms of the constraint. */ obj_props[PROP_RELATION] = g_param_spec_enum ("relation", P_("Relation"), P_("The relation between the source and target attributes"), GTK_TYPE_CONSTRAINT_RELATION, GTK_CONSTRAINT_RELATION_EQ, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); /** * GtkConstraint:source: * * The source of the constraint. * * The constraint will set the #GtkConstraint:target-attribute of the * target using the #GtkConstraint:source-attribute of the source. */ obj_props[PROP_SOURCE] = g_param_spec_object ("source", P_("Source"), P_("The source of the constraint"), GTK_TYPE_CONSTRAINT_TARGET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); /** * GtkConstraint:source-attribute: * * The attribute of the #GtkConstraint:source read by the constraint. */ obj_props[PROP_SOURCE_ATTRIBUTE] = g_param_spec_enum ("source-attribute", P_("Source Attribute"), P_("The attribute of the source widget set by the constraint"), GTK_TYPE_CONSTRAINT_ATTRIBUTE, GTK_CONSTRAINT_ATTRIBUTE_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); /** * GtkConstraint:multiplier: * * The multiplication factor to be applied to the * #GtkConstraint:source-attribute. */ obj_props[PROP_MULTIPLIER] = g_param_spec_double ("multiplier", P_("Multiplier"), P_("The multiplication factor to be applied to the source attribute"), -G_MAXDOUBLE, G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); /** * GtkConstraint:constant: * * The constant value to be added to the #GtkConstraint:source-attribute. */ obj_props[PROP_CONSTANT] = g_param_spec_double ("constant", P_("Constant"), P_("The constant to be added to the source attribute"), -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); /** * GtkConstraint:strength: * * The strength of the constraint. * * The strength can be expressed either using one of the symbolic values * of the #GtkConstraintStrength enumeration, or any positive integer * value. */ obj_props[PROP_STRENGTH] = g_param_spec_int ("strength", P_("Strength"), P_("The strength of the constraint"), 0, GTK_CONSTRAINT_STRENGTH_REQUIRED, GTK_CONSTRAINT_STRENGTH_REQUIRED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY); g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_props); } static void gtk_constraint_init (GtkConstraint *self) { self->multiplier = 1.0; self->constant = 0.0; self->target_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE; self->source_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE; self->relation = GTK_CONSTRAINT_RELATION_EQ; self->strength = GTK_CONSTRAINT_STRENGTH_REQUIRED; } /** * gtk_constraint_new: * @target: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget * @target_attribute: the attribute of @target to be set * @relation: the relation equivalence between @target_attribute and @source_attribute * @source: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget * @source_attribute: the attribute of @source to be read * @multiplier: a multiplication factor to be applied to @source_attribute * @constant: a constant factor to be added to @source_attribute * @strength: the strength of the constraint * * Creates a new #GtkConstraint representing a relation between a layout * attribute on a source and a layout attribute on a target. * * Returns: the newly created #GtkConstraint */ GtkConstraint * gtk_constraint_new (gpointer target, GtkConstraintAttribute target_attribute, GtkConstraintRelation relation, gpointer source, GtkConstraintAttribute source_attribute, double multiplier, double constant, int strength) { g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL); g_return_val_if_fail (source == NULL || GTK_IS_CONSTRAINT_TARGET (source), NULL); return g_object_new (GTK_TYPE_CONSTRAINT, "target", target, "target-attribute", target_attribute, "relation", relation, "source", source, "source-attribute", source_attribute, "multiplier", multiplier, "constant", constant, "strength", strength, NULL); } /** * gtk_constraint_new_constant: * @target: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget * @target_attribute: the attribute of @target to be set * @relation: the relation equivalence between @target_attribute and @constant * @constant: a constant factor to be set on @target_attribute * @strength: the strength of the constraint * * Creates a new #GtkConstraint representing a relation between a layout * attribute on a target and a constant value. * * Returns: the newly created #GtkConstraint */ GtkConstraint * gtk_constraint_new_constant (gpointer target, GtkConstraintAttribute target_attribute, GtkConstraintRelation relation, double constant, int strength) { g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL); return g_object_new (GTK_TYPE_CONSTRAINT, "target", target, "target-attribute", target_attribute, "relation", relation, "source-attribute", GTK_CONSTRAINT_ATTRIBUTE_NONE, "constant", constant, "strength", strength, NULL); } /** * gtk_constraint_get_target: * @constraint: a #GtkConstraint * * Retrieves the #GtkConstraintTarget used as the target for @constraint. * * If the #GtkConstraint:target property is set to %NULL, the @constraint * will use the #GtkConstraintLayout's widget. * * Returns: (transfer none) (nullable): a #GtkConstraintTarget */ GtkConstraintTarget * gtk_constraint_get_target (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL); return constraint->target; } /** * gtk_constraint_get_target_attribute: * @constraint: a #GtkConstraint * * Retrieves the attribute of the target to be set by the @constraint. * * Returns: the target's attribute */ GtkConstraintAttribute gtk_constraint_get_target_attribute (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE); return constraint->target_attribute; } /** * gtk_constraint_get_source: * @constraint: a #GtkConstraint * * Retrieves the #GtkConstraintTarget used as the source for @constraint. * * If the #GtkConstraint:source property is set to %NULL, the @constraint * will use the #GtkConstraintLayout's widget. * * Returns: (transfer none) (nullable): a #GtkConstraintTarget */ GtkConstraintTarget * gtk_constraint_get_source (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL); return constraint->source; } /** * gtk_constraint_get_source_attribute: * @constraint: a #GtkConstraint * * Retrieves the attribute of the source to be read by the @constraint. * * Returns: the target's attribute */ GtkConstraintAttribute gtk_constraint_get_source_attribute (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE); return constraint->source_attribute; } /** * gtk_constraint_get_relation: * @constraint: a #GtkConstraint * * The order relation between the terms of the @constraint. * * Returns: a #GtkConstraintRelation value */ GtkConstraintRelation gtk_constraint_get_relation (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_RELATION_EQ); return constraint->relation; } /** * gtk_constraint_get_multiplier: * @constraint: a #GtkConstraint * * Retrieves the multiplication factor applied to the source * attribute's value. * * Returns: a multiplication factor */ double gtk_constraint_get_multiplier (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 1.0); return constraint->multiplier; } /** * gtk_constraint_get_constant: * @constraint: a #GtkConstraint * * Retrieves the constant factor added to the source attributes' value. * * Returns: a constant factor */ double gtk_constraint_get_constant (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 0.0); return constraint->constant; } /** * gtk_constraint_get_strength: * @constraint: a #GtkConstraint * * Retrieves the strength of the constraint. * * Returns: the strength of the constraint */ int gtk_constraint_get_strength (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_STRENGTH_REQUIRED); return constraint->strength; } /** * gtk_constraint_is_required: * @constraint: a #GtkConstraint * * Checks whether the @constraint is a required relation for solving the * constraint layout. * * Returns: %TRUE if the constraint is required */ gboolean gtk_constraint_is_required (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE); return constraint->strength == GTK_CONSTRAINT_STRENGTH_REQUIRED; } /** * gtk_constraint_is_attached: * @constraint: a #GtkConstraint * * Checks whether the @constraint is attached to a #GtkConstraintLayout, * and it is contributing to the layout. * * Returns: %TRUE if the constraint is attached */ gboolean gtk_constraint_is_attached (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE); return constraint->constraint_ref != NULL; } /** * gtk_constraint_is_constant: * @constraint: a #GtkConstraint * * Checks whether the @constraint describes a relation between an attribute * on the #GtkConstraint:target and a constant value. * * Returns: %TRUE if the constraint is a constant relation */ gboolean gtk_constraint_is_constant (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE); return constraint->source == NULL && constraint->source_attribute == GTK_CONSTRAINT_ATTRIBUTE_NONE; } void gtk_constraint_attach (GtkConstraint *constraint, GtkConstraintSolver *solver, GtkConstraintRef *ref) { g_return_if_fail (GTK_IS_CONSTRAINT (constraint)); g_return_if_fail (GTK_IS_CONSTRAINT_SOLVER (solver)); g_return_if_fail (ref != NULL); constraint->constraint_ref = ref; constraint->solver = solver; } void gtk_constraint_detach (GtkConstraint *constraint) { g_return_if_fail (GTK_IS_CONSTRAINT (constraint)); if (constraint->constraint_ref == NULL) return; gtk_constraint_solver_remove_constraint (constraint->solver, constraint->constraint_ref); constraint->constraint_ref = NULL; constraint->solver = NULL; } typedef struct _GtkConstraintTargetInterface GtkConstraintTargetInterface; struct _GtkConstraintTargetInterface { GTypeInterface g_iface; }; G_DEFINE_INTERFACE (GtkConstraintTarget, gtk_constraint_target, G_TYPE_OBJECT) static void gtk_constraint_target_default_init (GtkConstraintTargetInterface *iface) { }