diff options
author | Matthias Clasen <mclasen@redhat.com> | 2019-06-25 19:38:32 -0400 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2019-06-30 23:42:44 +0100 |
commit | 38d353dc1a0cb725681bb2c6d108c5ca77db23d7 (patch) | |
tree | f4689b2a5b8f48eccafff3f6dcbf8ac00c971a83 | |
parent | 7ae04ba36b3031a8795e2778e171c886f6b922ce (diff) | |
download | gtk+-38d353dc1a0cb725681bb2c6d108c5ca77db23d7.tar.gz |
Add GtkConstraintGuide
This is meant to be a flexible space.
-rw-r--r-- | demos/gtk-demo/constraints.c | 21 | ||||
-rw-r--r-- | gtk/gtkconstraint.c | 2 | ||||
-rw-r--r-- | gtk/gtkconstraintlayout.c | 585 | ||||
-rw-r--r-- | gtk/gtkconstraintlayout.h | 35 |
4 files changed, 577 insertions, 66 deletions
diff --git a/demos/gtk-demo/constraints.c b/demos/gtk-demo/constraints.c index cc6cac145e..ba13f9b00f 100644 --- a/demos/gtk-demo/constraints.c +++ b/demos/gtk-demo/constraints.c @@ -74,6 +74,16 @@ static void build_constraints (SimpleGrid *self, GtkConstraintLayout *manager) { + GtkConstraintGuide *guide; + + guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, + "min-width", 10, + "min-height", 10, + "nat-width", 100, + "nat-height", 10, + NULL); + gtk_constraint_layout_add_guide (manager, guide); + gtk_constraint_layout_add_constraint (manager, gtk_constraint_new (NULL, GTK_CONSTRAINT_ATTRIBUTE_START, @@ -96,10 +106,19 @@ build_constraints (SimpleGrid *self, gtk_constraint_new (self->button1, GTK_CONSTRAINT_ATTRIBUTE_END, GTK_CONSTRAINT_RELATION_EQ, + guide, + GTK_CONSTRAINT_ATTRIBUTE_START, + 1.0, + 0.0, + GTK_CONSTRAINT_STRENGTH_REQUIRED)); + gtk_constraint_layout_add_constraint (manager, + gtk_constraint_new (guide, + GTK_CONSTRAINT_ATTRIBUTE_END, + GTK_CONSTRAINT_RELATION_EQ, self->button2, GTK_CONSTRAINT_ATTRIBUTE_START, 1.0, - -12.0, + 0.0, GTK_CONSTRAINT_STRENGTH_REQUIRED)); gtk_constraint_layout_add_constraint (manager, gtk_constraint_new (self->button2, diff --git a/gtk/gtkconstraint.c b/gtk/gtkconstraint.c index 6c20c48b94..2ac4d5b05d 100644 --- a/gtk/gtkconstraint.c +++ b/gtk/gtkconstraint.c @@ -572,7 +572,7 @@ gtk_constraint_is_constant (GtkConstraint *constraint) { g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE); - return constraint->source_widget == NULL && + return constraint->source == NULL && constraint->source_attribute == GTK_CONSTRAINT_ATTRIBUTE_NONE; } diff --git a/gtk/gtkconstraintlayout.c b/gtk/gtkconstraintlayout.c index b5375c596a..405d080164 100644 --- a/gtk/gtkconstraintlayout.c +++ b/gtk/gtkconstraintlayout.c @@ -72,16 +72,38 @@ #include "gtksizerequest.h" #include "gtkwidgetprivate.h" -struct _GtkConstraintLayoutChild +typedef struct { - GtkLayoutChild parent_instance; - /* HashTable<static string, Variable>; a hash table of variables, * one for each attribute; we use these to query and suggest the * values for the solver. The string is static and does not need * to be freed. */ GHashTable *bound_attributes; +} ConstraintSolverChildData; + +struct _GtkConstraintLayoutChild +{ + GtkLayoutChild parent_instance; + + ConstraintSolverChildData data; +}; + +struct _GtkConstraintGuide +{ + GObject parent_instance; + + int min_width; + int min_height; + int nat_width; + int nat_height; + + GtkConstraintLayout *layout; + + ConstraintSolverChildData data; + + GtkConstraintRef *width_constraint[2]; + GtkConstraintRef *height_constraint[2]; }; struct _GtkConstraintLayout @@ -105,6 +127,9 @@ struct _GtkConstraintLayout * parent widget, using the public API objects. */ GHashTable *constraints; + + /* HashSet<GtkConstraintGuide> */ + GHashTable *guides; }; G_DEFINE_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK_TYPE_LAYOUT_CHILD) @@ -154,44 +179,20 @@ get_attribute_name (GtkConstraintAttribute attr) } static GtkConstraintVariable * -get_child_attribute (GtkConstraintLayoutChild *self, - GtkConstraintSolver *solver, - GtkWidget *widget, - GtkConstraintAttribute attr) +get_attribute (ConstraintSolverChildData *self, + GtkConstraintSolver *solver, + const char *prefix, + GtkConstraintAttribute attr) { - GtkTextDirection text_dir; const char *attr_name; GtkConstraintVariable *res; - g_assert (attr != GTK_CONSTRAINT_ATTRIBUTE_NONE); - - /* Resolve the start/end attributes depending on the layout's text direction */ - if (attr == GTK_CONSTRAINT_ATTRIBUTE_START) - { - text_dir = gtk_widget_get_direction (widget); - if (text_dir == GTK_TEXT_DIR_RTL) - attr = GTK_CONSTRAINT_ATTRIBUTE_RIGHT; - else - attr = GTK_CONSTRAINT_ATTRIBUTE_LEFT; - } - else if (attr == GTK_CONSTRAINT_ATTRIBUTE_END) - { - text_dir = gtk_widget_get_direction (widget); - if (text_dir == GTK_TEXT_DIR_RTL) - attr = GTK_CONSTRAINT_ATTRIBUTE_LEFT; - else - attr = GTK_CONSTRAINT_ATTRIBUTE_RIGHT; - } - attr_name = get_attribute_name (attr); res = g_hash_table_lookup (self->bound_attributes, attr_name); if (res != NULL) return res; - res = gtk_constraint_solver_create_variable (solver, - gtk_widget_get_name (widget), - attr_name, - 0.0); + res = gtk_constraint_solver_create_variable (solver, prefix, attr_name, 0.0); g_hash_table_insert (self->bound_attributes, (gpointer) attr_name, res); /* Some attributes are really constraints computed from other @@ -207,8 +208,8 @@ get_child_attribute (GtkConstraintLayoutChild *self, GtkConstraintVariable *left, *width; GtkConstraintExpression *expr; - left = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_LEFT); - width = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_WIDTH); + left = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_LEFT); + width = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_WIDTH); gtk_constraint_expression_builder_init (&builder, solver); gtk_constraint_expression_builder_term (&builder, left); @@ -229,8 +230,8 @@ get_child_attribute (GtkConstraintLayoutChild *self, GtkConstraintVariable *top, *height; GtkConstraintExpression *expr; - top = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_TOP); - height = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT); + top = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_TOP); + height = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT); gtk_constraint_expression_builder_init (&builder, solver); gtk_constraint_expression_builder_term (&builder, top); @@ -251,8 +252,8 @@ get_child_attribute (GtkConstraintLayoutChild *self, GtkConstraintVariable *left, *width; GtkConstraintExpression *expr; - left = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_LEFT); - width = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_WIDTH); + left = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_LEFT); + width = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_WIDTH); gtk_constraint_expression_builder_init (&builder, solver); gtk_constraint_expression_builder_term (&builder, width); @@ -275,8 +276,8 @@ get_child_attribute (GtkConstraintLayoutChild *self, GtkConstraintVariable *top, *height; GtkConstraintExpression *expr; - top = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_TOP); - height = get_child_attribute (self, solver, widget, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT); + top = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_TOP); + height = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT); gtk_constraint_expression_builder_init (&builder, solver); gtk_constraint_expression_builder_term (&builder, height); @@ -325,12 +326,81 @@ get_child_attribute (GtkConstraintLayoutChild *self, return res; } +static GtkConstraintAttribute +resolve_direction (GtkConstraintAttribute attr, + GtkWidget *widget) +{ + GtkTextDirection text_dir; + + /* Resolve the start/end attributes depending on the layout's text direction */ + + if (widget) + text_dir = gtk_widget_get_direction (widget); + else + text_dir = GTK_TEXT_DIR_LTR; + + if (attr == GTK_CONSTRAINT_ATTRIBUTE_START) + { + if (text_dir == GTK_TEXT_DIR_RTL) + attr = GTK_CONSTRAINT_ATTRIBUTE_RIGHT; + else + attr = GTK_CONSTRAINT_ATTRIBUTE_LEFT; + } + else if (attr == GTK_CONSTRAINT_ATTRIBUTE_END) + { + if (text_dir == GTK_TEXT_DIR_RTL) + attr = GTK_CONSTRAINT_ATTRIBUTE_LEFT; + else + attr = GTK_CONSTRAINT_ATTRIBUTE_RIGHT; + } + + return attr; +} + +static GtkConstraintVariable * +get_child_attribute (GtkConstraintLayoutChild *self, + GtkConstraintSolver *solver, + GtkWidget *widget, + GtkConstraintAttribute attr) +{ + const char *prefix = gtk_widget_get_name (widget); + + attr = resolve_direction (attr, widget); + + return get_attribute (&self->data, solver, prefix, attr); +} + +static GtkConstraintVariable * +get_guide_attribute (GtkConstraintLayout *layout, + GtkConstraintGuide *guide, + GtkConstraintSolver *solver, + GtkConstraintAttribute attr) +{ + GtkLayoutManager *manager = GTK_LAYOUT_MANAGER (layout); + GtkWidget *widget = gtk_layout_manager_get_widget (manager); + + attr = resolve_direction (attr, widget); + + return get_attribute (&guide->data, solver, "guide", attr); +} + +static void +clear_constraint_solver_data (GtkConstraintSolver *solver, + ConstraintSolverChildData *data) +{ + g_clear_pointer (&data->bound_attributes, g_hash_table_unref); +} + static void gtk_constraint_layout_child_finalize (GObject *gobject) { GtkConstraintLayoutChild *self = GTK_CONSTRAINT_LAYOUT_CHILD (gobject); + GtkLayoutManager *manager; + GtkConstraintSolver *solver; - g_clear_pointer (&self->bound_attributes, g_hash_table_unref); + manager = gtk_layout_child_get_layout_manager (GTK_LAYOUT_CHILD (self)); + solver = gtk_constraint_layout_get_solver (GTK_CONSTRAINT_LAYOUT (manager)); + clear_constraint_solver_data (solver, &self->data); G_OBJECT_CLASS (gtk_constraint_layout_child_parent_class)->finalize (gobject); } @@ -346,7 +416,7 @@ gtk_constraint_layout_child_class_init (GtkConstraintLayoutChildClass *klass) static void gtk_constraint_layout_child_init (GtkConstraintLayoutChild *self) { - self->bound_attributes = + self->data.bound_attributes = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) gtk_constraint_variable_unref); @@ -361,6 +431,7 @@ gtk_constraint_layout_finalize (GObject *gobject) g_clear_pointer (&self->bound_attributes, g_hash_table_unref); g_clear_pointer (&self->constraints, g_hash_table_unref); + g_clear_pointer (&self->guides, g_hash_table_unref); G_OBJECT_CLASS (gtk_constraint_layout_parent_class)->finalize (gobject); } @@ -553,7 +624,7 @@ layout_add_constraint (GtkConstraintLayout *self, GtkConstraintExpression *expr; GtkConstraintSolver *solver; GtkConstraintAttribute attr; - GtkWidget *target_widget, *source_widget; + GtkConstraintTarget *target, *source; GtkWidget *layout_widget; if (gtk_constraint_is_attached (constraint)) @@ -572,25 +643,33 @@ layout_add_constraint (GtkConstraintLayout *self, return; attr = gtk_constraint_get_target_attribute (constraint); - target_widget = gtk_constraint_get_target_widget (constraint); - if (target_widget == NULL || target_widget == layout_widget) + target = gtk_constraint_get_target (constraint); + if (target == NULL || target == GTK_CONSTRAINT_TARGET (layout_widget)) { /* A NULL target widget is assumed to be referring to the layout itself */ target_attr = get_layout_attribute (self, layout_widget, attr); } - else if (gtk_widget_get_parent (target_widget) == layout_widget) + else if (GTK_IS_WIDGET (target) && + gtk_widget_get_parent (GTK_WIDGET (target)) == layout_widget) { GtkLayoutChild *child_info; - child_info = gtk_layout_manager_get_layout_child (GTK_LAYOUT_MANAGER (self), target_widget); + child_info = gtk_layout_manager_get_layout_child (GTK_LAYOUT_MANAGER (self), GTK_WIDGET (target)); target_attr = get_child_attribute (GTK_CONSTRAINT_LAYOUT_CHILD (child_info), solver, - target_widget, + GTK_WIDGET (target), attr); } + else if (GTK_IS_CONSTRAINT_GUIDE (target)) + { + GtkConstraintGuide *guide; + + guide = (GtkConstraintGuide*)g_hash_table_lookup (self->guides, target); + target_attr = get_guide_attribute (self, guide, solver, attr); + } else { - g_critical ("Unknown target widget '%s'", gtk_widget_get_name (target_widget)); + g_critical ("Unknown target widget '%p'", target); target_attr = NULL; } @@ -598,7 +677,7 @@ layout_add_constraint (GtkConstraintLayout *self, return; attr = gtk_constraint_get_source_attribute (constraint); - source_widget = gtk_constraint_get_source_widget (constraint); + source = gtk_constraint_get_source (constraint); /* The constraint is a constant */ if (attr == GTK_CONSTRAINT_ATTRIBUTE_NONE) @@ -607,23 +686,31 @@ layout_add_constraint (GtkConstraintLayout *self, } else { - if (source_widget == NULL || source_widget == layout_widget) + if (source == NULL || source == GTK_CONSTRAINT_TARGET (layout_widget)) { source_attr = get_layout_attribute (self, layout_widget, attr); } - else if (gtk_widget_get_parent (source_widget) == layout_widget) + else if (GTK_IS_WIDGET (source) && + gtk_widget_get_parent (GTK_WIDGET (source)) == layout_widget) { GtkLayoutChild *child_info; - child_info = gtk_layout_manager_get_layout_child (GTK_LAYOUT_MANAGER (self), source_widget); + child_info = gtk_layout_manager_get_layout_child (GTK_LAYOUT_MANAGER (self), GTK_WIDGET (source)); source_attr = get_child_attribute (GTK_CONSTRAINT_LAYOUT_CHILD (child_info), solver, - source_widget, + GTK_WIDGET (source), attr); } + else if (GTK_IS_CONSTRAINT_GUIDE (source)) + { + GtkConstraintGuide *guide; + + guide = (GtkConstraintGuide*)g_hash_table_lookup (self->guides, source); + source_attr = get_guide_attribute (self, guide, solver, attr); + } else { - g_critical ("Unknown source widget '%s'", gtk_widget_get_name (source_widget)); + g_critical ("Unknown source widget '%p'", source); source_attr = NULL; return; } @@ -871,7 +958,6 @@ gtk_constraint_layout_allocate (GtkLayoutManager *manager, gtk_widget_get_preferred_size (child, &min_req, &nat_req); - width_var = get_child_attribute (child_info, solver, child, GTK_CONSTRAINT_ATTRIBUTE_WIDTH); @@ -972,6 +1058,11 @@ gtk_constraint_layout_allocate (GtkLayoutManager *manager, gtk_constraint_solver_remove_constraint (solver, stay_l); } +static void update_min_width (GtkConstraintGuide *guide); +static void update_nat_width (GtkConstraintGuide *guide); +static void update_min_height (GtkConstraintGuide *guide); +static void update_nat_height (GtkConstraintGuide *guide); + static void gtk_constraint_layout_root (GtkLayoutManager *manager) { @@ -991,9 +1082,18 @@ gtk_constraint_layout_root (GtkLayoutManager *manager) while (g_hash_table_iter_next (&iter, &key, NULL)) { GtkConstraint *constraint = key; - layout_add_constraint (self, constraint); } + + g_hash_table_iter_init (&iter, self->guides); + while (g_hash_table_iter_next (&iter, &key, NULL)) + { + GtkConstraintGuide *guide = key; + update_min_width (guide); + update_nat_width (guide); + update_min_height (guide); + update_nat_height (guide); + } } static void @@ -1011,7 +1111,6 @@ gtk_constraint_layout_unroot (GtkLayoutManager *manager) while (g_hash_table_iter_next (&iter, &key, NULL)) { GtkConstraint *constraint = key; - gtk_constraint_detach (constraint); } @@ -1047,6 +1146,11 @@ gtk_constraint_layout_init (GtkConstraintLayout *self) g_hash_table_new_full (NULL, NULL, (GDestroyNotify) g_object_unref, NULL); + + self->guides = + g_hash_table_new_full (NULL, NULL, + (GDestroyNotify) g_object_unref, + NULL); } /** @@ -1116,3 +1220,368 @@ gtk_constraint_layout_remove_constraint (GtkConstraintLayout *manager, gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (manager)); } + +static void +gtk_constraint_guide_constraint_target_iface_init (GtkConstraintTargetInterface *iface) +{ +} + +struct _GtkConstraintGuideClass { + GObjectClass parent_class; +}; + +enum { + PROP_MIN_WIDTH = 1, + PROP_MIN_HEIGHT, + PROP_NAT_WIDTH, + PROP_NAT_HEIGHT, + LAST_PROP +}; + +static GParamSpec *guide_props[LAST_PROP]; + +G_DEFINE_TYPE_WITH_CODE (GtkConstraintGuide, gtk_constraint_guide, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (GTK_TYPE_CONSTRAINT_TARGET, + gtk_constraint_guide_constraint_target_iface_init)) + +static void +gtk_constraint_guide_init (GtkConstraintGuide *guide) +{ + guide->data.bound_attributes = + g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, + (GDestroyNotify) gtk_constraint_variable_unref); +} + +static void +update_min_width (GtkConstraintGuide *guide) +{ + GtkConstraintSolver *solver; + GtkConstraintVariable *var; + + if (!guide->layout) + return; + + solver = guide->layout->solver; + + if (!solver) + return; + + if (guide->width_constraint[0] != NULL) + gtk_constraint_solver_remove_constraint (solver, guide->width_constraint[0]); + + var = get_guide_attribute (guide->layout, guide, solver, GTK_CONSTRAINT_ATTRIBUTE_WIDTH); + guide->width_constraint[0] = + gtk_constraint_solver_add_constraint (solver, + var, + GTK_CONSTRAINT_RELATION_GE, + gtk_constraint_expression_new (guide->min_width), + GTK_CONSTRAINT_WEIGHT_REQUIRED); +} + +static void +update_min_height (GtkConstraintGuide *guide) +{ + GtkConstraintSolver *solver; + GtkConstraintVariable *var; + + if (!guide->layout) + return; + + solver = guide->layout->solver; + + if (!solver) + return; + + if (guide->height_constraint[0] != NULL) + gtk_constraint_solver_remove_constraint (solver, guide->height_constraint[0]); + + var = get_guide_attribute (guide->layout, guide, solver, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT); + guide->height_constraint[0] = + gtk_constraint_solver_add_constraint (solver, + var, + GTK_CONSTRAINT_RELATION_GE, + gtk_constraint_expression_new (guide->min_height), + GTK_CONSTRAINT_WEIGHT_REQUIRED); +} + +static void +update_nat_width (GtkConstraintGuide *guide) +{ + GtkConstraintSolver *solver; + GtkConstraintVariable *var; + + if (!guide->layout) + return; + + solver = guide->layout->solver; + + if (!solver) + return; + + if (guide->width_constraint[1] != NULL) + gtk_constraint_solver_remove_constraint (solver, guide->width_constraint[1]); + + var = get_guide_attribute (guide->layout, guide, solver, GTK_CONSTRAINT_ATTRIBUTE_WIDTH); + guide->width_constraint[1] = + gtk_constraint_solver_add_constraint (solver, + var, + GTK_CONSTRAINT_RELATION_EQ, + gtk_constraint_expression_new (guide->nat_width), + GTK_CONSTRAINT_WEIGHT_MEDIUM); +} + +static void +update_nat_height (GtkConstraintGuide *guide) +{ + GtkConstraintSolver *solver; + GtkConstraintVariable *var; + + if (!guide->layout) + return; + + solver = guide->layout->solver; + + if (!solver) + return; + + if (guide->height_constraint[1] != NULL) + gtk_constraint_solver_remove_constraint (solver, guide->height_constraint[1]); + + var = get_guide_attribute (guide->layout, guide, solver, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT); + guide->height_constraint[1] = + gtk_constraint_solver_add_constraint (solver, + var, + GTK_CONSTRAINT_RELATION_EQ, + gtk_constraint_expression_new (guide->nat_height), + GTK_CONSTRAINT_WEIGHT_MEDIUM); +} + +static void +set_min_width (GtkConstraintGuide *guide, + int min_width) +{ + if (guide->min_width == min_width) + return; + + guide->min_width = min_width; + g_object_notify_by_pspec (G_OBJECT (guide), + guide_props[PROP_MIN_WIDTH]); + + update_min_width (guide); +} + +static void +set_min_height (GtkConstraintGuide *guide, + int min_height) +{ + if (guide->min_height == min_height) + return; + + guide->min_height = min_height; + g_object_notify_by_pspec (G_OBJECT (guide), + guide_props[PROP_MIN_HEIGHT]); + + update_min_height (guide); +} + +static void +set_nat_width (GtkConstraintGuide *guide, + int nat_width) +{ + if (guide->nat_width == nat_width) + return; + + guide->nat_width = nat_width; + g_object_notify_by_pspec (G_OBJECT (guide), + guide_props[PROP_NAT_WIDTH]); + + update_nat_width (guide); +} +static void +set_nat_height (GtkConstraintGuide *guide, + int nat_height) +{ + if (guide->nat_height == nat_height) + return; + + guide->nat_height = nat_height; + g_object_notify_by_pspec (G_OBJECT (guide), + guide_props[PROP_NAT_HEIGHT]); + + update_nat_height (guide); +} + +static void +gtk_constraint_guide_set_property (GObject *gobject, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (gobject); + + switch (prop_id) + { + case PROP_MIN_WIDTH: + set_min_width (self, g_value_get_int (value)); + break; + + case PROP_MIN_HEIGHT: + set_min_height (self, g_value_get_int (value)); + break; + + case PROP_NAT_WIDTH: + set_nat_width (self, g_value_get_int (value)); + break; + + case PROP_NAT_HEIGHT: + set_nat_height (self, g_value_get_int (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +gtk_constraint_guide_get_property (GObject *gobject, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (gobject); + + switch (prop_id) + { + case PROP_MIN_WIDTH: + g_value_set_int (value, self->min_width); + break; + + case PROP_MIN_HEIGHT: + g_value_set_int (value, self->min_height); + break; + + case PROP_NAT_WIDTH: + g_value_set_int (value, self->nat_width); + break; + + case PROP_NAT_HEIGHT: + g_value_set_int (value, self->nat_height); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); + break; + } +} + +static void +gtk_constraint_guide_finalize (GObject *object) +{ + GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (object); + GtkConstraintSolver *solver; + + if (self->layout) + { + solver = gtk_constraint_layout_get_solver (self->layout); + clear_constraint_solver_data (solver, &self->data); + } + + G_OBJECT_CLASS (gtk_constraint_guide_parent_class)->finalize (object); +} + +static void +gtk_constraint_guide_class_init (GtkConstraintGuideClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gtk_constraint_guide_finalize; + object_class->set_property = gtk_constraint_guide_set_property; + object_class->get_property = gtk_constraint_guide_get_property; + + guide_props[PROP_MIN_WIDTH] = + g_param_spec_int ("min-width", + "Minimum width", + "Minimum width", + 0, G_MAXINT, 0, + G_PARAM_READWRITE| + G_PARAM_EXPLICIT_NOTIFY); + guide_props[PROP_MIN_HEIGHT] = + g_param_spec_int ("min-height", + "Minimum height", + "Minimum height", + 0, G_MAXINT, 0, + G_PARAM_READWRITE| + G_PARAM_EXPLICIT_NOTIFY); + guide_props[PROP_NAT_WIDTH] = + g_param_spec_int ("nat-width", + "Natural width", + "Natural width", + 0, G_MAXINT, 0, + G_PARAM_READWRITE| + G_PARAM_EXPLICIT_NOTIFY); + guide_props[PROP_NAT_HEIGHT] = + g_param_spec_int ("nat-height", + "Natural height", + "Natural height", + 0, G_MAXINT, 0, + G_PARAM_READWRITE| + G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, LAST_PROP, guide_props); +} + +/** + * gtk_constraint_layout_add_guide: + * @layout: a #GtkConstraintLayout + * @guide: (transfer full): a #GtkConstraintGuide object + * + * Adds a guide to @layout. A guide can be used as + * the source or target of constraints, like a widget, + * but it is not visible. + * + * The @manager acquires the ownership of @guide after calling + * this function. + */ +void +gtk_constraint_layout_add_guide (GtkConstraintLayout *layout, + GtkConstraintGuide *guide) +{ + g_return_if_fail (GTK_IS_CONSTRAINT_LAYOUT (layout)); + g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide)); + g_return_if_fail (guide->layout == NULL); + + guide->layout = layout; + + g_hash_table_add (layout->guides, guide); + + gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout)); +} + +/** + * gtk_constraint_layout_remove_guide: + * @layout: a #GtkConstraintManager + * @guide: a #GtkConstraintGuide object + * + * Removes @guide from the layout manager, + * so that it no longer influences the layout. + */ +void +gtk_constraint_layout_remove_guide (GtkConstraintLayout *layout, + GtkConstraintGuide *guide) +{ + GtkConstraintSolver *solver; + + g_return_if_fail (GTK_IS_CONSTRAINT_LAYOUT (layout)); + g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide)); + g_return_if_fail (guide->layout == layout); + + solver = gtk_constraint_layout_get_solver (guide->layout); + clear_constraint_solver_data (solver, &guide->data); + guide->layout = NULL; + + g_hash_table_remove (layout->guides, guide); + + gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout)); +} diff --git a/gtk/gtkconstraintlayout.h b/gtk/gtkconstraintlayout.h index b5eba7b125..758fcefb20 100644 --- a/gtk/gtkconstraintlayout.h +++ b/gtk/gtkconstraintlayout.h @@ -25,6 +25,30 @@ G_BEGIN_DECLS #define GTK_TYPE_CONSTRAINT_LAYOUT (gtk_constraint_layout_get_type ()) #define GTK_TYPE_CONSTRAINT_LAYOUT_CHILD (gtk_constraint_layout_child_get_type ()) +#define GTK_TYPE_CONSTRAINT_GUIDE (gtk_constraint_guide_get_type ()) + +/** + * GtkConstraintLayoutChild: + * + * A #GtkLayoutChild in a #GtkConstraintLayout. + */ +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK, CONSTRAINT_LAYOUT_CHILD, GtkLayoutChild) + +/** + * GtkConstraintGuide: + * + * An object that can be added to a #GtkConstraintLayout and be + * used in constraints like a widget, without being drawn. Guides + * have a minimal and natural size. Depending on the constraints + * that are applied, they can act like a guideline that widgets + * can be aligned to, or like 'flexible space'. + */ +GDK_AVAILABLE_IN_ALL +G_DECLARE_FINAL_TYPE (GtkConstraintGuide, gtk_constraint_guide, GTK, CONSTRAINT_GUIDE, GObject) + +GDK_AVAILABLE_IN_ALL +GtkConstraintGuide * gtk_constraint_guide_new (void); /** * GtkConstraintLayout: @@ -45,12 +69,11 @@ GDK_AVAILABLE_IN_ALL void gtk_constraint_layout_remove_constraint (GtkConstraintLayout *manager, GtkConstraint *constraint); -/** - * GtkConstraintLayoutChild: - * - * A #GtkLayoutChild in a #GtkConstraintLayout. - */ GDK_AVAILABLE_IN_ALL -G_DECLARE_FINAL_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK, CONSTRAINT_LAYOUT_CHILD, GtkLayoutChild) +void gtk_constraint_layout_add_guide (GtkConstraintLayout *manager, + GtkConstraintGuide *guide); +GDK_AVAILABLE_IN_ALL +void gtk_constraint_layout_remove_guide (GtkConstraintLayout *manager, + GtkConstraintGuide *guide); G_END_DECLS |