Compare commits
21 Commits
repeat-edi
...
constraint
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
615f1aed65 | ||
|
|
19fdb764a6 | ||
|
|
ee04ad7e96 | ||
|
|
d4f6ad74dd | ||
|
|
4025b9ed00 | ||
|
|
f4fe1f4bcf | ||
|
|
75e3017f51 | ||
|
|
f2a604ba9f | ||
|
|
a691df2a5f | ||
|
|
376b5b326e | ||
|
|
38156f4454 | ||
|
|
b462988e3c | ||
|
|
cf702b81a8 | ||
|
|
04d7e894e2 | ||
|
|
4efcad59df | ||
|
|
8bacf47c41 | ||
|
|
8f5515d498 | ||
|
|
3a8c1abbc1 | ||
|
|
02f4e1a5ae | ||
|
|
7afac64225 | ||
|
|
cb11ba4ca0 |
@@ -76,12 +76,10 @@ build_constraints (SimpleGrid *self,
|
||||
{
|
||||
GtkConstraintGuide *guide;
|
||||
|
||||
guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE,
|
||||
"min-width", 10,
|
||||
"min-height", 10,
|
||||
"nat-width", 100,
|
||||
"nat-height", 10,
|
||||
NULL);
|
||||
guide = gtk_constraint_guide_new ();
|
||||
gtk_constraint_guide_set_min_size (guide, 10, 10);
|
||||
gtk_constraint_guide_set_nat_size (guide, 100, 10);
|
||||
gtk_constraint_guide_set_max_size (guide, 200, 20);
|
||||
gtk_constraint_layout_add_guide (manager, guide);
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
|
||||
498
gtk/gtkconstraintguide.c
Normal file
498
gtk/gtkconstraintguide.c
Normal file
@@ -0,0 +1,498 @@
|
||||
/* gtkconstraintguide.c: Flexible space for constraints
|
||||
* Copyright 2019 Red Hat, Inc.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkconstraintguide.h"
|
||||
|
||||
#include "gtkconstraintguideprivate.h"
|
||||
#include "gtkconstraintlayoutprivate.h"
|
||||
#include "gtkconstraintexpressionprivate.h"
|
||||
#include "gtkconstraintsolverprivate.h"
|
||||
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
GUIDE_MIN_WIDTH,
|
||||
GUIDE_MIN_HEIGHT,
|
||||
GUIDE_NAT_WIDTH,
|
||||
GUIDE_NAT_HEIGHT,
|
||||
GUIDE_MAX_WIDTH,
|
||||
GUIDE_MAX_HEIGHT,
|
||||
LAST_GUIDE_VALUE
|
||||
} GuideValue;
|
||||
|
||||
struct _GtkConstraintGuide
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
int values[LAST_GUIDE_VALUE];
|
||||
|
||||
GtkConstraintLayout *layout;
|
||||
|
||||
/* 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;
|
||||
|
||||
GtkConstraintRef *constraints[LAST_GUIDE_VALUE];
|
||||
};
|
||||
|
||||
|
||||
struct _GtkConstraintGuideClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
GUIDE_PROP_MIN_WIDTH = 1,
|
||||
GUIDE_PROP_MIN_HEIGHT,
|
||||
GUIDE_PROP_NAT_WIDTH,
|
||||
GUIDE_PROP_NAT_HEIGHT,
|
||||
GUIDE_PROP_MAX_WIDTH,
|
||||
GUIDE_PROP_MAX_HEIGHT,
|
||||
LAST_GUIDE_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *guide_props[LAST_GUIDE_PROP];
|
||||
|
||||
static void
|
||||
gtk_constraint_guide_constraint_target_iface_init (GtkConstraintTargetInterface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
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->bound_attributes =
|
||||
g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) gtk_constraint_variable_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_constraint_guide_update_constraint (GtkConstraintGuide *guide,
|
||||
GuideValue index)
|
||||
{
|
||||
GtkConstraintSolver *solver;
|
||||
GtkConstraintVariable *var;
|
||||
int attr[LAST_GUIDE_VALUE] = {
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
};
|
||||
int relation[LAST_GUIDE_VALUE] = {
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_RELATION_LE,
|
||||
GTK_CONSTRAINT_RELATION_LE,
|
||||
};
|
||||
double weight[LAST_GUIDE_VALUE] = {
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED,
|
||||
GTK_CONSTRAINT_WEIGHT_MEDIUM,
|
||||
GTK_CONSTRAINT_WEIGHT_MEDIUM,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED,
|
||||
};
|
||||
|
||||
if (!guide->layout)
|
||||
return;
|
||||
|
||||
solver = gtk_constraint_layout_get_solver (guide->layout);
|
||||
if (!solver)
|
||||
return;
|
||||
|
||||
if (guide->constraints[index] != NULL)
|
||||
gtk_constraint_solver_remove_constraint (solver, guide->constraints[index]);
|
||||
|
||||
var = gtk_constraint_layout_get_attribute (guide->layout, attr[index], "guide", NULL, guide->bound_attributes);
|
||||
guide->constraints[index] =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
var,
|
||||
relation[index],
|
||||
gtk_constraint_expression_new (guide->values[index]),
|
||||
weight[index]);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_constraint_guide_update (GtkConstraintGuide *guide)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LAST_GUIDE_VALUE; i++)
|
||||
gtk_constraint_guide_update_constraint (guide, i);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_constraint_guide_detach (GtkConstraintGuide *guide)
|
||||
{
|
||||
GtkConstraintSolver *solver;
|
||||
int i;
|
||||
|
||||
if (!guide->layout)
|
||||
return;
|
||||
|
||||
solver = gtk_constraint_layout_get_solver (guide->layout);
|
||||
if (!solver)
|
||||
return;
|
||||
|
||||
for (i = 0; i < LAST_GUIDE_VALUE; i++)
|
||||
{
|
||||
gtk_constraint_solver_remove_constraint (solver, guide->constraints[i]);
|
||||
guide->constraints[i] = NULL;
|
||||
}
|
||||
|
||||
g_hash_table_remove_all (guide->bound_attributes);
|
||||
}
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_guide_get_attribute (GtkConstraintGuide *guide,
|
||||
GtkConstraintAttribute attr)
|
||||
{
|
||||
GtkLayoutManager *manager = GTK_LAYOUT_MANAGER (guide->layout);
|
||||
GtkWidget *widget = gtk_layout_manager_get_widget (manager);
|
||||
|
||||
return gtk_constraint_layout_get_attribute (guide->layout, attr, "guide", widget, guide->bound_attributes);
|
||||
}
|
||||
|
||||
GtkConstraintLayout *
|
||||
gtk_constraint_guide_get_layout (GtkConstraintGuide *guide)
|
||||
{
|
||||
return guide->layout;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_constraint_guide_set_layout (GtkConstraintGuide *guide,
|
||||
GtkConstraintLayout *layout)
|
||||
{
|
||||
guide->layout = layout;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_constraint_guide_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkConstraintGuide *self = GTK_CONSTRAINT_GUIDE (gobject);
|
||||
int val;
|
||||
GuideValue index;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case GUIDE_PROP_MIN_WIDTH:
|
||||
case GUIDE_PROP_MIN_HEIGHT:
|
||||
case GUIDE_PROP_NAT_WIDTH:
|
||||
case GUIDE_PROP_NAT_HEIGHT:
|
||||
case GUIDE_PROP_MAX_WIDTH:
|
||||
case GUIDE_PROP_MAX_HEIGHT:
|
||||
val = g_value_get_int (value);
|
||||
index = prop_id - 1;
|
||||
if (self->values[index] != val)
|
||||
{
|
||||
self->values[index] = val;
|
||||
g_object_notify_by_pspec (gobject, pspec);
|
||||
gtk_constraint_guide_update_constraint (self, index);
|
||||
}
|
||||
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 GUIDE_PROP_MIN_WIDTH:
|
||||
case GUIDE_PROP_MIN_HEIGHT:
|
||||
case GUIDE_PROP_NAT_WIDTH:
|
||||
case GUIDE_PROP_NAT_HEIGHT:
|
||||
case GUIDE_PROP_MAX_WIDTH:
|
||||
case GUIDE_PROP_MAX_HEIGHT:
|
||||
g_value_set_int (value, self->values[prop_id - 1]);
|
||||
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);
|
||||
|
||||
g_clear_pointer (&self->bound_attributes, g_hash_table_unref);
|
||||
|
||||
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[GUIDE_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[GUIDE_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[GUIDE_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[GUIDE_PROP_NAT_HEIGHT] =
|
||||
g_param_spec_int ("nat-height",
|
||||
"Natural height",
|
||||
"Natural height",
|
||||
0, G_MAXINT, 0,
|
||||
G_PARAM_READWRITE|
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
guide_props[GUIDE_PROP_MAX_WIDTH] =
|
||||
g_param_spec_int ("max-width",
|
||||
"Maximum width",
|
||||
"Maximum width",
|
||||
0, G_MAXINT, G_MAXINT,
|
||||
G_PARAM_READWRITE|
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
guide_props[GUIDE_PROP_MAX_HEIGHT] =
|
||||
g_param_spec_int ("max-height",
|
||||
"Maximum height",
|
||||
"Maximum height",
|
||||
0, G_MAXINT, G_MAXINT,
|
||||
G_PARAM_READWRITE|
|
||||
G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_GUIDE_PROP, guide_props);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_guide_new:
|
||||
*
|
||||
* Creates a new #GtkConstraintGuide object.
|
||||
*
|
||||
* Return: a new #GtkConstraintGuide object.
|
||||
*/
|
||||
GtkConstraintGuide *
|
||||
gtk_constraint_guide_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_guide_set_min_size:
|
||||
* @guide: a #GtkConstraintGuide object
|
||||
* @width: the new minimum width, or -1 to not change it
|
||||
* @height: the new minimum height, or -1 to not change it
|
||||
*
|
||||
* Sets the minimum size of @guide.
|
||||
*
|
||||
* If @guide is attached to a #GtkConstraintLayout,
|
||||
* the constraints will be updated to reflect the new size.
|
||||
*/
|
||||
void
|
||||
gtk_constraint_guide_set_min_size (GtkConstraintGuide *guide,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
|
||||
g_return_if_fail (width >= -1);
|
||||
g_return_if_fail (height >= -1);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (guide));
|
||||
|
||||
if (width != -1)
|
||||
g_object_set (guide, "min-width", width, NULL);
|
||||
|
||||
if (height != -1)
|
||||
g_object_set (guide, "min-height", height, NULL);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (guide));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_guide_get_min_size:
|
||||
* @guide: a #GtkContraintGuide object
|
||||
* @width: (allow-none): return location for the minimum width,
|
||||
* or %NULL
|
||||
* @height: (allow-none): return location for the minimum height,
|
||||
* or %NULL
|
||||
*
|
||||
* Gets the minimum size of @guide.
|
||||
*/
|
||||
void
|
||||
gtk_constraint_guide_get_min_size (GtkConstraintGuide *guide,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
|
||||
|
||||
if (width)
|
||||
*width = guide->values[GUIDE_MIN_WIDTH];
|
||||
if (height)
|
||||
*height = guide->values[GUIDE_MIN_HEIGHT];
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_guide_set_nat_size:
|
||||
* @guide: a #GtkConstraintGuide object
|
||||
* @width: the new natural width, or -1 to not change it
|
||||
* @height: the new natural height, or -1 to not change it
|
||||
*
|
||||
* Sets the natural size of @guide.
|
||||
*
|
||||
* If @guide is attached to a #GtkConstraintLayout,
|
||||
* the constraints will be updated to reflect the new size.
|
||||
*/
|
||||
void
|
||||
gtk_constraint_guide_set_nat_size (GtkConstraintGuide *guide,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
|
||||
g_return_if_fail (width >= -1);
|
||||
g_return_if_fail (height >= -1);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (guide));
|
||||
|
||||
if (width != -1)
|
||||
g_object_set (guide, "nat-width", width, NULL);
|
||||
|
||||
if (height != -1)
|
||||
g_object_set (guide, "nat-height", height, NULL);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (guide));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_guide_get_nat_size:
|
||||
* @guide: a #GtkContraintGuide object
|
||||
* @width: (allow-none): return location for the natural width,
|
||||
* or %NULL
|
||||
* @height: (allow-none): return location for the natural height,
|
||||
* or %NULL
|
||||
*
|
||||
* Gets the natural size of @guide.
|
||||
*/
|
||||
void
|
||||
gtk_constraint_guide_get_nat_size (GtkConstraintGuide *guide,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
|
||||
|
||||
if (width)
|
||||
*width = guide->values[GUIDE_NAT_WIDTH];
|
||||
if (height)
|
||||
*height = guide->values[GUIDE_NAT_HEIGHT];
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_guide_set_max_size:
|
||||
* @guide: a #GtkConstraintGuide object
|
||||
* @width: the new maximum width, or -1 to not change it
|
||||
* @height: the new maximum height, or -1 to not change it
|
||||
*
|
||||
* Sets the maximum size of @guide.
|
||||
*
|
||||
* If @guide is attached to a #GtkConstraintLayout,
|
||||
* the constraints will be updated to reflect the new size.
|
||||
*/
|
||||
void
|
||||
gtk_constraint_guide_set_max_size (GtkConstraintGuide *guide,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
|
||||
g_return_if_fail (width >= -1);
|
||||
g_return_if_fail (height >= -1);
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (guide));
|
||||
|
||||
if (width != -1)
|
||||
g_object_set (guide, "max-width", width, NULL);
|
||||
|
||||
if (height != -1)
|
||||
g_object_set (guide, "max-height", height, NULL);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (guide));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_guide_get_max_size:
|
||||
* @guide: a #GtkContraintGuide object
|
||||
* @width: (allow-none): return location for the maximum width,
|
||||
* or %NULL
|
||||
* @height: (allow-none): return location for the maximum height,
|
||||
* or %NULL
|
||||
*
|
||||
* Gets the maximum size of @guide.
|
||||
*/
|
||||
void
|
||||
gtk_constraint_guide_get_max_size (GtkConstraintGuide *guide,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT_GUIDE (guide));
|
||||
|
||||
if (width)
|
||||
*width = guide->values[GUIDE_MAX_WIDTH];
|
||||
if (height)
|
||||
*height = guide->values[GUIDE_MAX_HEIGHT];
|
||||
}
|
||||
71
gtk/gtkconstraintguide.h
Normal file
71
gtk/gtkconstraintguide.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* gtkconstraintguide.h: Flexible space for constraints
|
||||
* Copyright 2019 Red Hat, Inc.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtkenums.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define GTK_TYPE_CONSTRAINT_GUIDE (gtk_constraint_guide_get_type ())
|
||||
|
||||
/**
|
||||
* GtkConstraintGuide:
|
||||
*
|
||||
* An object that can be added to a #GtkConstraintLayout and be
|
||||
* used in constraints like a widget, without being drawn.
|
||||
*
|
||||
* Guides have a minimum, maximum 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);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_guide_set_min_size (GtkConstraintGuide *guide,
|
||||
int width,
|
||||
int height);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_guide_get_min_size (GtkConstraintGuide *guide,
|
||||
int *width,
|
||||
int *height);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_guide_set_nat_size (GtkConstraintGuide *guide,
|
||||
int width,
|
||||
int height);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_guide_get_nat_size (GtkConstraintGuide *guide,
|
||||
int *width,
|
||||
int *height);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_guide_set_max_size (GtkConstraintGuide *guide,
|
||||
int width,
|
||||
int height);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_guide_get_max_size (GtkConstraintGuide *guide,
|
||||
int *width,
|
||||
int *height);
|
||||
|
||||
G_END_DECLS
|
||||
38
gtk/gtkconstraintguideprivate.h
Normal file
38
gtk/gtkconstraintguideprivate.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* gtkconstraintguideprivate.h: Constraint between two widgets
|
||||
* Copyright 2019 Red Hat, Inc.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Matthias Clasen
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gtkconstraintguide.h"
|
||||
#include "gtkconstraintlayout.h"
|
||||
#include "gtkconstrainttypesprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
void gtk_constraint_guide_update (GtkConstraintGuide *guide);
|
||||
void gtk_constraint_guide_detach (GtkConstraintGuide *guide);
|
||||
|
||||
GtkConstraintVariable *gtk_constraint_guide_get_attribute (GtkConstraintGuide *guide,
|
||||
GtkConstraintAttribute attr);
|
||||
|
||||
GtkConstraintLayout *gtk_constraint_guide_get_layout (GtkConstraintGuide *guide);
|
||||
void gtk_constraint_guide_set_layout (GtkConstraintGuide *guide,
|
||||
GtkConstraintLayout *layout);
|
||||
|
||||
G_END_DECLS
|
||||
@@ -60,11 +60,13 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkconstraintlayout.h"
|
||||
#include "gtkconstraintlayoutprivate.h"
|
||||
|
||||
#include "gtkconstraintprivate.h"
|
||||
#include "gtkconstraintexpressionprivate.h"
|
||||
#include "gtkconstraintsolverprivate.h"
|
||||
#include "gtklayoutchild.h"
|
||||
#include "gtkconstraintguideprivate.h"
|
||||
|
||||
#include "gtkdebug.h"
|
||||
#include "gtkintl.h"
|
||||
@@ -72,38 +74,16 @@
|
||||
#include "gtksizerequest.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
typedef struct
|
||||
struct _GtkConstraintLayoutChild
|
||||
{
|
||||
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
|
||||
@@ -134,7 +114,7 @@ struct _GtkConstraintLayout
|
||||
|
||||
G_DEFINE_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK_TYPE_LAYOUT_CHILD)
|
||||
|
||||
static inline GtkConstraintSolver *
|
||||
GtkConstraintSolver *
|
||||
gtk_constraint_layout_get_solver (GtkConstraintLayout *self)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
@@ -178,22 +158,57 @@ get_attribute_name (GtkConstraintAttribute attr)
|
||||
return attribute_names[attr];
|
||||
}
|
||||
|
||||
static GtkConstraintVariable *
|
||||
get_attribute (ConstraintSolverChildData *self,
|
||||
GtkConstraintSolver *solver,
|
||||
const char *prefix,
|
||||
GtkConstraintAttribute attr)
|
||||
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;
|
||||
}
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_layout_get_attribute (GtkConstraintLayout *layout,
|
||||
GtkConstraintAttribute attr,
|
||||
const char *prefix,
|
||||
GtkWidget *widget,
|
||||
GHashTable *bound_attributes)
|
||||
{
|
||||
const char *attr_name;
|
||||
GtkConstraintVariable *res;
|
||||
GtkConstraintSolver *solver = layout->solver;
|
||||
|
||||
attr = resolve_direction (attr, widget);
|
||||
|
||||
attr_name = get_attribute_name (attr);
|
||||
res = g_hash_table_lookup (self->bound_attributes, attr_name);
|
||||
res = g_hash_table_lookup (bound_attributes, attr_name);
|
||||
if (res != NULL)
|
||||
return res;
|
||||
|
||||
res = gtk_constraint_solver_create_variable (solver, prefix, attr_name, 0.0);
|
||||
g_hash_table_insert (self->bound_attributes, (gpointer) attr_name, res);
|
||||
g_hash_table_insert (bound_attributes, (gpointer) attr_name, res);
|
||||
|
||||
/* Some attributes are really constraints computed from other
|
||||
* attributes, to avoid creating additional constraints from
|
||||
@@ -208,8 +223,8 @@ get_attribute (ConstraintSolverChildData *self,
|
||||
GtkConstraintVariable *left, *width;
|
||||
GtkConstraintExpression *expr;
|
||||
|
||||
left = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_LEFT);
|
||||
width = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
left = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_LEFT, prefix, widget, bound_attributes);
|
||||
width = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_WIDTH, prefix, widget, bound_attributes);
|
||||
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, left);
|
||||
@@ -230,8 +245,8 @@ get_attribute (ConstraintSolverChildData *self,
|
||||
GtkConstraintVariable *top, *height;
|
||||
GtkConstraintExpression *expr;
|
||||
|
||||
top = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_TOP);
|
||||
height = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
top = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_TOP, prefix, widget, bound_attributes);
|
||||
height = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT, prefix, widget, bound_attributes);
|
||||
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, top);
|
||||
@@ -252,8 +267,8 @@ get_attribute (ConstraintSolverChildData *self,
|
||||
GtkConstraintVariable *left, *width;
|
||||
GtkConstraintExpression *expr;
|
||||
|
||||
left = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_LEFT);
|
||||
width = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
left = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_LEFT, prefix, widget, bound_attributes);
|
||||
width = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_WIDTH, prefix, widget, bound_attributes);
|
||||
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, width);
|
||||
@@ -276,8 +291,8 @@ get_attribute (ConstraintSolverChildData *self,
|
||||
GtkConstraintVariable *top, *height;
|
||||
GtkConstraintExpression *expr;
|
||||
|
||||
top = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_TOP);
|
||||
height = get_attribute (self, solver, prefix, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
top = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_TOP, prefix, widget, bound_attributes);
|
||||
height = gtk_constraint_layout_get_attribute (layout, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT, prefix, widget, bound_attributes);
|
||||
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, height);
|
||||
@@ -326,81 +341,25 @@ get_attribute (ConstraintSolverChildData *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,
|
||||
get_child_attribute (GtkConstraintLayout *layout,
|
||||
GtkWidget *widget,
|
||||
GtkConstraintAttribute attr)
|
||||
{
|
||||
GtkLayoutManager *manager = GTK_LAYOUT_MANAGER (layout);
|
||||
GtkWidget *widget = gtk_layout_manager_get_widget (manager);
|
||||
GtkConstraintLayoutChild *child_info;
|
||||
const char *prefix = gtk_widget_get_name (widget);
|
||||
|
||||
attr = resolve_direction (attr, widget);
|
||||
child_info = GTK_CONSTRAINT_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (GTK_LAYOUT_MANAGER (layout), 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);
|
||||
return gtk_constraint_layout_get_attribute (layout, attr, prefix, widget, child_info->bound_attributes);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_constraint_layout_child_finalize (GObject *gobject)
|
||||
{
|
||||
GtkConstraintLayoutChild *self = GTK_CONSTRAINT_LAYOUT_CHILD (gobject);
|
||||
GtkLayoutManager *manager;
|
||||
GtkConstraintSolver *solver;
|
||||
|
||||
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_clear_pointer (&self->bound_attributes, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_constraint_layout_child_parent_class)->finalize (gobject);
|
||||
}
|
||||
@@ -416,7 +375,7 @@ gtk_constraint_layout_child_class_init (GtkConstraintLayoutChildClass *klass)
|
||||
static void
|
||||
gtk_constraint_layout_child_init (GtkConstraintLayoutChild *self)
|
||||
{
|
||||
self->data.bound_attributes =
|
||||
self->bound_attributes =
|
||||
g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL,
|
||||
(GDestroyNotify) gtk_constraint_variable_unref);
|
||||
@@ -652,20 +611,14 @@ layout_add_constraint (GtkConstraintLayout *self,
|
||||
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), GTK_WIDGET (target));
|
||||
target_attr = get_child_attribute (GTK_CONSTRAINT_LAYOUT_CHILD (child_info),
|
||||
solver,
|
||||
GTK_WIDGET (target),
|
||||
attr);
|
||||
target_attr = get_child_attribute (self, 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);
|
||||
target_attr = gtk_constraint_guide_get_attribute (guide, attr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -693,20 +646,14 @@ layout_add_constraint (GtkConstraintLayout *self,
|
||||
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), GTK_WIDGET (source));
|
||||
source_attr = get_child_attribute (GTK_CONSTRAINT_LAYOUT_CHILD (child_info),
|
||||
solver,
|
||||
GTK_WIDGET (source),
|
||||
attr);
|
||||
source_attr = get_child_attribute (self, 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);
|
||||
source_attr = gtk_constraint_guide_get_attribute (guide, attr);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -770,7 +717,6 @@ gtk_constraint_layout_measure (GtkLayoutManager *manager,
|
||||
child != NULL;
|
||||
child = _gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
GtkConstraintLayoutChild *child_info;
|
||||
GtkConstraintVariable *width_var, *height_var;
|
||||
GtkConstraintRef *constraint;
|
||||
int min_size = 0, nat_size = 0;
|
||||
@@ -778,49 +724,55 @@ gtk_constraint_layout_measure (GtkLayoutManager *manager,
|
||||
if (!gtk_widget_should_layout (child))
|
||||
continue;
|
||||
|
||||
child_info = GTK_CONSTRAINT_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (manager, child));
|
||||
|
||||
gtk_widget_measure (child, orientation, -1,
|
||||
&min_size, &nat_size,
|
||||
NULL, NULL);
|
||||
|
||||
width_var = get_child_attribute (child_info, solver, child,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
switch (orientation)
|
||||
{
|
||||
case GTK_ORIENTATION_HORIZONTAL:
|
||||
width_var = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
width_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_new (min_size),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
width_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_new (min_size),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
width_var,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
gtk_constraint_expression_new (nat_size),
|
||||
GTK_CONSTRAINT_WEIGHT_MEDIUM);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
width_var,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
gtk_constraint_expression_new (nat_size),
|
||||
GTK_CONSTRAINT_WEIGHT_MEDIUM);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
break;
|
||||
|
||||
height_var = get_child_attribute (child_info, solver, child,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
case GTK_ORIENTATION_VERTICAL:
|
||||
height_var = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
height_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_new (min_size),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
height_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_new (min_size),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
height_var,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
gtk_constraint_expression_new (nat_size),
|
||||
GTK_CONSTRAINT_WEIGHT_MEDIUM);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
height_var,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
gtk_constraint_expression_new (nat_size),
|
||||
GTK_CONSTRAINT_WEIGHT_MEDIUM);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (orientation)
|
||||
@@ -852,16 +804,9 @@ gtk_constraint_layout_measure (GtkLayoutManager *manager,
|
||||
gtk_constraint_solver_begin_edit (solver);
|
||||
gtk_constraint_solver_suggest_value (solver, opposite_size, for_size);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
value = gtk_constraint_variable_get_value (size);
|
||||
|
||||
gtk_constraint_solver_remove_edit_variable (solver, opposite_size);
|
||||
gtk_constraint_solver_end_edit (solver);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = gtk_constraint_variable_get_value (size);
|
||||
}
|
||||
|
||||
GTK_NOTE (LAYOUT,
|
||||
g_print ("layout %p preferred %s size: %.3f (for opposite size: %d)\n",
|
||||
@@ -870,6 +815,8 @@ gtk_constraint_layout_measure (GtkLayoutManager *manager,
|
||||
gtk_constraint_variable_get_value (size),
|
||||
for_size));
|
||||
|
||||
value = gtk_constraint_variable_get_value (size);
|
||||
|
||||
for (guint i = 0; i < size_constraints->len; i++)
|
||||
{
|
||||
GtkConstraintRef *ref = g_ptr_array_index (size_constraints, i);
|
||||
@@ -946,7 +893,6 @@ gtk_constraint_layout_allocate (GtkLayoutManager *manager,
|
||||
child != NULL;
|
||||
child = _gtk_widget_get_next_sibling (child))
|
||||
{
|
||||
GtkConstraintLayoutChild *child_info;
|
||||
GtkConstraintVariable *width_var, *height_var;
|
||||
GtkRequisition min_req, nat_req;
|
||||
GtkConstraintRef *constraint;
|
||||
@@ -954,12 +900,9 @@ gtk_constraint_layout_allocate (GtkLayoutManager *manager,
|
||||
if (!gtk_widget_should_layout (child))
|
||||
continue;
|
||||
|
||||
child_info = GTK_CONSTRAINT_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (manager, child));
|
||||
|
||||
gtk_widget_get_preferred_size (child, &min_req, &nat_req);
|
||||
|
||||
width_var = get_child_attribute (child_info, solver, child,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
width_var = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
@@ -977,8 +920,7 @@ gtk_constraint_layout_allocate (GtkLayoutManager *manager,
|
||||
GTK_CONSTRAINT_WEIGHT_MEDIUM);
|
||||
g_ptr_array_add (size_constraints, constraint);
|
||||
|
||||
height_var = get_child_attribute (child_info, solver, child,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
height_var = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
|
||||
constraint =
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
@@ -1003,21 +945,18 @@ gtk_constraint_layout_allocate (GtkLayoutManager *manager,
|
||||
{
|
||||
GtkConstraintVariable *var_top, *var_left, *var_width, *var_height;
|
||||
GtkConstraintVariable *var_baseline;
|
||||
GtkConstraintLayoutChild *child_info;
|
||||
GtkAllocation child_alloc;
|
||||
int child_baseline = -1;
|
||||
|
||||
if (!gtk_widget_should_layout (child))
|
||||
continue;
|
||||
|
||||
child_info = GTK_CONSTRAINT_LAYOUT_CHILD (gtk_layout_manager_get_layout_child (manager, child));
|
||||
|
||||
/* Retrieve all the values associated with the child */
|
||||
var_top = get_child_attribute (child_info, solver, child, GTK_CONSTRAINT_ATTRIBUTE_TOP);
|
||||
var_left = get_child_attribute (child_info, solver, child, GTK_CONSTRAINT_ATTRIBUTE_LEFT);
|
||||
var_width = get_child_attribute (child_info, solver, child, GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
var_height = get_child_attribute (child_info, solver, child, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
var_baseline = get_child_attribute (child_info, solver, child, GTK_CONSTRAINT_ATTRIBUTE_BASELINE);
|
||||
var_top = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_TOP);
|
||||
var_left = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_LEFT);
|
||||
var_width = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_WIDTH);
|
||||
var_height = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_HEIGHT);
|
||||
var_baseline = get_child_attribute (self, child, GTK_CONSTRAINT_ATTRIBUTE_BASELINE);
|
||||
|
||||
GTK_NOTE (LAYOUT,
|
||||
g_print ("Allocating child '%s'[%p] with { .x: %g, .y: %g, .w: %g, .h: %g, .b: %g }\n",
|
||||
@@ -1058,11 +997,6 @@ 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)
|
||||
{
|
||||
@@ -1089,10 +1023,7 @@ gtk_constraint_layout_root (GtkLayoutManager *manager)
|
||||
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);
|
||||
gtk_constraint_guide_update (guide);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1114,6 +1045,13 @@ gtk_constraint_layout_unroot (GtkLayoutManager *manager)
|
||||
gtk_constraint_detach (constraint);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, self->guides);
|
||||
while (g_hash_table_iter_next (&iter, &key, NULL))
|
||||
{
|
||||
GtkConstraintGuide *guide = key;
|
||||
gtk_constraint_guide_detach (guide);
|
||||
}
|
||||
|
||||
self->solver = NULL;
|
||||
}
|
||||
|
||||
@@ -1221,317 +1159,6 @@ 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
|
||||
@@ -1550,10 +1177,9 @@ gtk_constraint_layout_add_guide (GtkConstraintLayout *layout,
|
||||
{
|
||||
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_return_if_fail (gtk_constraint_guide_get_layout (guide) == NULL);
|
||||
|
||||
gtk_constraint_guide_set_layout (guide, layout);
|
||||
g_hash_table_add (layout->guides, guide);
|
||||
|
||||
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout));
|
||||
@@ -1571,16 +1197,13 @@ 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);
|
||||
g_return_if_fail (gtk_constraint_guide_get_layout (guide) == layout);
|
||||
|
||||
solver = gtk_constraint_layout_get_solver (guide->layout);
|
||||
clear_constraint_solver_data (solver, &guide->data);
|
||||
guide->layout = NULL;
|
||||
gtk_constraint_guide_detach (guide);
|
||||
|
||||
gtk_constraint_guide_set_layout (guide, NULL);
|
||||
g_hash_table_remove (layout->guides, guide);
|
||||
|
||||
gtk_layout_manager_layout_changed (GTK_LAYOUT_MANAGER (layout));
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
#include <gtk/gtklayoutmanager.h>
|
||||
#include <gtk/gtkconstraint.h>
|
||||
#include <gtk/gtkconstraintguide.h>
|
||||
|
||||
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:
|
||||
@@ -35,21 +35,6 @@ G_BEGIN_DECLS
|
||||
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:
|
||||
*
|
||||
|
||||
@@ -1972,7 +1972,6 @@ gtk_constraint_solver_suggest_value (GtkConstraintSolver *self,
|
||||
double value)
|
||||
{
|
||||
EditInfo *ei = g_hash_table_lookup (self->edit_var_map, variable);
|
||||
double delta;
|
||||
if (ei == NULL)
|
||||
{
|
||||
g_critical ("Suggesting value '%g' but variable %p is not editable",
|
||||
@@ -1988,10 +1987,9 @@ gtk_constraint_solver_suggest_value (GtkConstraintSolver *self,
|
||||
return;
|
||||
}
|
||||
|
||||
delta = value - ei->prev_constant;
|
||||
ei->prev_constant = value;
|
||||
ei->prev_constant = value - ei->prev_constant;
|
||||
|
||||
gtk_constraint_solver_delta_edit_constant (self, delta, ei->eplus, ei->eminus);
|
||||
gtk_constraint_solver_delta_edit_constant (self, ei->prev_constant, ei->eplus, ei->eminus);
|
||||
}
|
||||
|
||||
/*< private >
|
||||
|
||||
@@ -25,10 +25,30 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#ifdef GTK_TEST_EXTERNAL
|
||||
|
||||
#define GTK_TYPE_CONSTRAINT_SOLVER (g_type_from_name ("GtkConstraintSolver"))
|
||||
#define GTK_CONSTRAINT_SOLVER(solver) (G_TYPE_CHECK_INSTANCE_CAST ((solver), GTK_TYPE_CONSTRAINT_SOLVER, GtkConstraintSolver))
|
||||
#define GTK_CONSTRAINT_SOLVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_CONSTRAINT_SOLVER, GtkConstraintSolverClass))
|
||||
#define GTK_IS_CONSTRAINT_SOLVER(solver) (G_TYPE_CHECK_INSTANCE_TYPE ((solver), GTK_TYPE_CONSTRAINT_SOLVER))
|
||||
#define GTK_IS_CONSTRAINT_SOLVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_CONSTRAINT_SOLVER))
|
||||
#define GTK_CONSTRAINT_SOLVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_CONSTRAINT_SOLVER, GtkConstraintSolverClass))
|
||||
|
||||
typedef struct _GtkConstraintSolver GtkConstraintSolver;
|
||||
typedef struct _GtkConstraintSolverClass GtkConstraintSolverClass;
|
||||
|
||||
struct _GtkConstraintSolverClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
#define GTK_TYPE_CONSTRAINT_SOLVER (gtk_constraint_solver_get_type())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (GtkConstraintSolver, gtk_constraint_solver, GTK, CONSTRAINT_SOLVER, GObject)
|
||||
|
||||
#endif
|
||||
|
||||
/* Symbolic weight thresholds
|
||||
*
|
||||
* Constraint weights live on a continuum, but we use thresholds for simplicity's
|
||||
|
||||
@@ -202,6 +202,7 @@ gtk_public_sources = files([
|
||||
'gtkcombobox.c',
|
||||
'gtkcomboboxtext.c',
|
||||
'gtkcomposetable.c',
|
||||
'gtkconstraintguide.c',
|
||||
'gtkconstraintlayout.c',
|
||||
'gtkconstraint.c',
|
||||
'gtkcontainer.c',
|
||||
|
||||
381
tests/constrainttree.c
Normal file
381
tests/constrainttree.c
Normal file
@@ -0,0 +1,381 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "../../gtk/gtkconstrainttypesprivate.h"
|
||||
#include "../../gtk/gtkconstraintsolverprivate.h"
|
||||
#include "../../gtk/gtkconstraintexpressionprivate.h"
|
||||
|
||||
typedef struct _Node Node;
|
||||
|
||||
static GtkConstraintSolver *solver;
|
||||
static Node *tree;
|
||||
static Node *drag_node;
|
||||
static double drag_start_x;
|
||||
static double drag_start_y;
|
||||
static GtkConstraintVariable *width_var;
|
||||
static GtkConstraintVariable *height_var;
|
||||
|
||||
struct _Node {
|
||||
double x;
|
||||
double y;
|
||||
Node *parent;
|
||||
Node *left;
|
||||
Node *right;
|
||||
|
||||
GtkConstraintVariable *x_var;
|
||||
GtkConstraintVariable *y_var;
|
||||
};
|
||||
|
||||
static Node *
|
||||
make_tree (Node *parent,
|
||||
int depth,
|
||||
int x,
|
||||
int y,
|
||||
int dx,
|
||||
int dy)
|
||||
{
|
||||
Node *node;
|
||||
|
||||
node = g_new0 (Node, 1);
|
||||
node->parent = parent;
|
||||
|
||||
if (depth > 0)
|
||||
{
|
||||
node->left = make_tree (node, depth - 1, x - dx, y + dy, dx / 2, dy);
|
||||
node->right = make_tree (node, depth - 1, x + dx, y + dy, dx / 2, dy);
|
||||
}
|
||||
|
||||
node->x = x;
|
||||
node->y = y;
|
||||
|
||||
node->x_var = gtk_constraint_solver_create_variable (solver, NULL, "x", x);
|
||||
node->y_var = gtk_constraint_solver_create_variable (solver, NULL, "y", y);
|
||||
|
||||
/* weak stay for the current position */
|
||||
gtk_constraint_solver_add_stay_variable (solver, node->x_var, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
gtk_constraint_solver_add_stay_variable (solver, node->y_var, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
|
||||
/* require to stay in area */
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->x_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_new (0.0),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->x_var,
|
||||
GTK_CONSTRAINT_RELATION_LE,
|
||||
gtk_constraint_expression_new (1600.0),
|
||||
//gtk_constraint_expression_new_from_variable (width_var),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->y_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_new (0.0),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->y_var,
|
||||
GTK_CONSTRAINT_RELATION_LE,
|
||||
gtk_constraint_expression_new (600.0),
|
||||
//gtk_constraint_expression_new_from_variable (height_var),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
if (node->left)
|
||||
{
|
||||
GtkConstraintExpressionBuilder builder;
|
||||
|
||||
/* left.y = right.y */
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->left->y_var,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
gtk_constraint_expression_new_from_variable (node->right->y_var),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
/* left.y >= parent.y + 10 */
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, node->y_var);
|
||||
gtk_constraint_expression_builder_plus (&builder);
|
||||
gtk_constraint_expression_builder_constant (&builder, 10.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->left->y_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_builder_finish (&builder),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
/* right.y >= parent.y + 10 */
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, node->y_var);
|
||||
gtk_constraint_expression_builder_plus (&builder);
|
||||
gtk_constraint_expression_builder_constant (&builder, 10.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->right->y_var,
|
||||
GTK_CONSTRAINT_RELATION_GE,
|
||||
gtk_constraint_expression_builder_finish (&builder),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
/* parent.x = (left.x + right.x) / 2 */
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, node->left->x_var);
|
||||
gtk_constraint_expression_builder_plus (&builder);
|
||||
gtk_constraint_expression_builder_term (&builder, node->right->x_var);
|
||||
gtk_constraint_expression_builder_divide_by (&builder);
|
||||
gtk_constraint_expression_builder_constant (&builder, 2.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
node->x_var,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
gtk_constraint_expression_builder_finish (&builder),
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_node (Node *node, cairo_t *cr)
|
||||
{
|
||||
if (node->left)
|
||||
draw_node (node->left, cr);
|
||||
if (node->right)
|
||||
draw_node (node->right, cr);
|
||||
|
||||
if (node->parent)
|
||||
{
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_move_to (cr, node->parent->x, node->parent->y);
|
||||
cairo_line_to (cr, node->x, node->y);
|
||||
cairo_stroke (cr);
|
||||
}
|
||||
|
||||
if (node == drag_node)
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
else
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
|
||||
cairo_move_to (cr, node->x, node->y);
|
||||
cairo_arc (cr, node->x, node->y, 5, 0, 2*M_PI);
|
||||
cairo_close_path (cr);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_func (GtkDrawingArea *da,
|
||||
cairo_t *cr,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
cairo_set_line_width (cr, 1);
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
cairo_paint (cr);
|
||||
|
||||
draw_node (tree, cr);
|
||||
}
|
||||
|
||||
static Node *
|
||||
find_node (Node *node,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
Node *ret;
|
||||
|
||||
double dx = x - node->x;
|
||||
double dy = y - node->y;
|
||||
|
||||
if (dx*dx + dy*dy < 10*10)
|
||||
return node;
|
||||
|
||||
if (node->left)
|
||||
{
|
||||
ret = find_node (node->left, x, y);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (node->right)
|
||||
{
|
||||
ret = find_node (node->right, x, y);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
drag_begin (GtkGestureDrag *drag,
|
||||
double start_x,
|
||||
double start_y,
|
||||
gpointer data)
|
||||
{
|
||||
drag_node = find_node (tree, start_x, start_y);
|
||||
if (!drag_node)
|
||||
return;
|
||||
|
||||
drag_start_x = start_x;
|
||||
drag_start_y = start_y;
|
||||
gtk_widget_queue_draw (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (drag)));
|
||||
}
|
||||
|
||||
static void
|
||||
update_tree (Node *node)
|
||||
{
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
node->x = gtk_constraint_variable_get_value (node->x_var);
|
||||
node->y = gtk_constraint_variable_get_value (node->y_var);
|
||||
|
||||
update_tree (node->left);
|
||||
update_tree (node->right);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_update (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
gpointer data)
|
||||
{
|
||||
if (!drag_node)
|
||||
return;
|
||||
|
||||
gtk_constraint_solver_add_edit_variable (solver,
|
||||
drag_node->x_var,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_add_edit_variable (solver,
|
||||
drag_node->y_var,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_begin_edit (solver);
|
||||
gtk_constraint_solver_suggest_value (solver,
|
||||
drag_node->x_var,
|
||||
drag_start_x + offset_x);
|
||||
gtk_constraint_solver_suggest_value (solver,
|
||||
drag_node->y_var,
|
||||
drag_start_y + offset_y);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
update_tree (tree);
|
||||
|
||||
gtk_constraint_solver_remove_edit_variable (solver, drag_node->x_var);
|
||||
gtk_constraint_solver_remove_edit_variable (solver, drag_node->y_var);
|
||||
gtk_constraint_solver_end_edit (solver);
|
||||
gtk_widget_queue_draw (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (drag)));
|
||||
}
|
||||
|
||||
static void
|
||||
drag_end (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
gpointer data)
|
||||
{
|
||||
if (!drag_node)
|
||||
return;
|
||||
|
||||
|
||||
drag_node = NULL;
|
||||
|
||||
gtk_widget_queue_draw (gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (drag)));
|
||||
}
|
||||
|
||||
static void
|
||||
size_change (GtkWidget *da,
|
||||
int width,
|
||||
int height,
|
||||
int baseline,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_constraint_variable_set_value (width_var, width);
|
||||
gtk_constraint_variable_set_value (height_var, height);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_tree (Node *node,
|
||||
int x,
|
||||
int y,
|
||||
int dx,
|
||||
int dy)
|
||||
{
|
||||
node->x = x;
|
||||
node->y = y;
|
||||
|
||||
gtk_constraint_solver_remove_stay_variable (solver, node->x_var);
|
||||
gtk_constraint_solver_remove_stay_variable (solver, node->y_var);
|
||||
gtk_constraint_variable_set_value (node->x_var, x);
|
||||
gtk_constraint_variable_set_value (node->y_var, y);
|
||||
gtk_constraint_solver_add_stay_variable (solver, node->x_var, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
gtk_constraint_solver_add_stay_variable (solver, node->y_var, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
|
||||
if (node->left)
|
||||
reset_tree (node->left, x - dx, y + dy, dx / 2, dy);
|
||||
if (node->right)
|
||||
reset_tree (node->right, x + dx, y + dy, dx / 2, dy);
|
||||
}
|
||||
|
||||
static void
|
||||
reset (GtkButton *button,
|
||||
GtkWidget *da)
|
||||
{
|
||||
int width, height;
|
||||
|
||||
width = gtk_widget_get_allocated_width (da);
|
||||
height = gtk_widget_get_allocated_height (da);
|
||||
|
||||
gtk_constraint_solver_freeze (solver);
|
||||
reset_tree (tree, width / 2, 20, width / 4 - 40, (height - 40) / 7);
|
||||
gtk_constraint_solver_thaw (solver);
|
||||
|
||||
gtk_widget_queue_draw (da);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *header;
|
||||
GtkWidget *button;
|
||||
GtkWidget *da;
|
||||
GtkGesture *drag;
|
||||
int width = 1600;
|
||||
int height = 600;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
da = gtk_drawing_area_new ();
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), TRUE);
|
||||
button = gtk_button_new_with_label ("Reset");
|
||||
g_signal_connect (button, "clicked", G_CALLBACK (reset), da);
|
||||
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), button);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
|
||||
gtk_drawing_area_set_content_width (GTK_DRAWING_AREA (da), width);
|
||||
gtk_drawing_area_set_content_height (GTK_DRAWING_AREA (da), height);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (window), da);
|
||||
|
||||
drag = gtk_gesture_drag_new ();
|
||||
g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), NULL);
|
||||
g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), NULL);
|
||||
g_signal_connect (drag, "drag-end", G_CALLBACK (drag_end), NULL);
|
||||
gtk_widget_add_controller (da, GTK_EVENT_CONTROLLER (drag));
|
||||
|
||||
solver = g_object_new (g_type_from_name ("GtkConstraintSolver"), NULL);
|
||||
gtk_constraint_solver_freeze (solver);
|
||||
|
||||
width_var = gtk_constraint_solver_create_variable (solver, NULL, "width", width);
|
||||
height_var = gtk_constraint_solver_create_variable (solver, NULL, "height", height);
|
||||
gtk_constraint_solver_add_stay_variable (solver, width_var, GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_add_stay_variable (solver, height_var, GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
g_signal_connect (da, "size-allocate", G_CALLBACK (size_change), NULL);
|
||||
|
||||
tree = make_tree (NULL, 7, width / 2, 20, width / 4 - 40, (height - 40) / 7);
|
||||
|
||||
gtk_constraint_solver_thaw (solver);
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
gtk_main ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
gtk_tests = [
|
||||
# testname, optional extra sources
|
||||
['constrainttree', [
|
||||
'../gtk/gtkconstraintsolver.c',
|
||||
'../gtk/gtkconstraintexpression.c',
|
||||
], ['-DGTK_COMPILATION', '-UG_ENABLE_DEBUG', '-DGTK_TEST_EXTERNAL']
|
||||
],
|
||||
['rendernode'],
|
||||
['rendernode-create-tests'],
|
||||
['overlayscroll'],
|
||||
@@ -142,9 +147,12 @@ test_args = ['-DGTK_SRCDIR="@0@"'.format(meson.current_source_dir())]
|
||||
foreach t: gtk_tests
|
||||
test_name = t.get(0)
|
||||
test_srcs = ['@0@.c'.format(test_name), t.get(1, [])]
|
||||
test_extra_cargs = t.get(2, [])
|
||||
test_extra_ldflags = t.get(3, [])
|
||||
executable(test_name, test_srcs,
|
||||
include_directories: [confinc, gdkinc],
|
||||
c_args: test_args,
|
||||
c_args: test_args + test_extra_cargs,
|
||||
link_args : test_extra_ldflags,
|
||||
dependencies: [libgtk_dep, libm])
|
||||
endforeach
|
||||
|
||||
|
||||
@@ -254,27 +254,15 @@ constraint_solver_edit_var_suggest (void)
|
||||
gtk_constraint_solver_suggest_value (solver, a, 2.0);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
g_test_message ("Check values after first edit");
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 2.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 2.0, 0.001);
|
||||
|
||||
gtk_constraint_solver_suggest_value (solver, a, 10.0);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
g_test_message ("Check values after second edit");
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 10.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 10.0, 0.001);
|
||||
|
||||
gtk_constraint_solver_suggest_value (solver, a, 12.0);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
g_test_message ("Check values after third edit");
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 12.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 12.0, 0.001);
|
||||
|
||||
gtk_constraint_variable_unref (a);
|
||||
gtk_constraint_variable_unref (b);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user