Compare commits
35 Commits
foreach-ap
...
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 | ||
|
19e7d412e3 | ||
|
80c27061c6 | ||
|
bd5c558646 | ||
|
ad40630008 | ||
|
f07ba4ac5b | ||
|
391add73ec | ||
|
a21562f270 | ||
|
124607d1e8 | ||
|
9756cb9482 | ||
|
92f93a603b | ||
|
e7cd3d4633 | ||
|
5780ec4bf1 | ||
|
ec14c1f605 | ||
|
c09fada79e |
280
demos/gtk-demo/constraints.c
Normal file
280
demos/gtk-demo/constraints.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/* Constraints/Simple
|
||||
*
|
||||
* GtkConstraintLayout provides a layout manager that uses relations
|
||||
* between widgets (also known as "constraints") to compute the position
|
||||
* and size of each child.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE (SimpleGrid, simple_grid, SIMPLE, GRID, GtkWidget)
|
||||
|
||||
struct _SimpleGrid
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *button1, *button2;
|
||||
GtkWidget *button3;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (SimpleGrid, simple_grid, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
simple_grid_destroy (GtkWidget *widget)
|
||||
{
|
||||
SimpleGrid *self = SIMPLE_GRID (widget);
|
||||
|
||||
g_clear_pointer (&self->button1, gtk_widget_destroy);
|
||||
g_clear_pointer (&self->button2, gtk_widget_destroy);
|
||||
g_clear_pointer (&self->button3, gtk_widget_destroy);
|
||||
|
||||
GTK_WIDGET_CLASS (simple_grid_parent_class)->destroy (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
simple_grid_class_init (SimpleGridClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
widget_class->destroy = simple_grid_destroy;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
|
||||
}
|
||||
|
||||
/* Layout:
|
||||
*
|
||||
* +-----------------------------+
|
||||
* | +-----------+ +-----------+ |
|
||||
* | | Child 1 | | Child 2 | |
|
||||
* | +-----------+ +-----------+ |
|
||||
* | +-------------------------+ |
|
||||
* | | Child 3 | |
|
||||
* | +-------------------------+ |
|
||||
* +-----------------------------+
|
||||
*
|
||||
* Constraints:
|
||||
*
|
||||
* super.start = child1.start - 8
|
||||
* child1.width = child2.width
|
||||
* child1.end = child2.start - 12
|
||||
* child2.end = super.end - 8
|
||||
* super.start = child3.start - 8
|
||||
* child3.end = super.end - 8
|
||||
* super.top = child1.top - 8
|
||||
* super.top = child2.top - 8
|
||||
* child1.bottom = child3.top - 12
|
||||
* child2.bottom = child3.top - 12
|
||||
* child3.height = child1.height
|
||||
* child3.height = child2.height
|
||||
* child3.bottom = super.bottom - 8
|
||||
*
|
||||
*/
|
||||
static void
|
||||
build_constraints (SimpleGrid *self,
|
||||
GtkConstraintLayout *manager)
|
||||
{
|
||||
GtkConstraintGuide *guide;
|
||||
|
||||
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,
|
||||
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_RELATION_LE,
|
||||
200.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button1,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button1,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button2,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
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,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button2,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button3,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button3,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button1,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button2,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button1,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button3,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
1.0,
|
||||
-12.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button2,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button3,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
1.0,
|
||||
-12.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button3,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button1,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button3,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
self->button2,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (self->button3,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
}
|
||||
|
||||
static void
|
||||
simple_grid_init (SimpleGrid *self)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
|
||||
self->button1 = gtk_button_new_with_label ("Child 1");
|
||||
gtk_widget_set_parent (self->button1, widget);
|
||||
gtk_widget_set_name (self->button1, "button1");
|
||||
|
||||
self->button2 = gtk_button_new_with_label ("Child 2");
|
||||
gtk_widget_set_parent (self->button2, widget);
|
||||
gtk_widget_set_name (self->button2, "button2");
|
||||
|
||||
self->button3 = gtk_button_new_with_label ("Child 3");
|
||||
gtk_widget_set_parent (self->button3, widget);
|
||||
gtk_widget_set_name (self->button3, "button3");
|
||||
|
||||
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
|
||||
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_constraints (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *header, *box, *grid, *button;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
grid = g_object_new (simple_grid_get_type (), NULL);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
gtk_widget_set_vexpand (grid, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), grid);
|
||||
|
||||
button = gtk_button_new_with_label ("Close");
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
G_CALLBACK (gtk_widget_destroy), window);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
245
demos/gtk-demo/constraints2.c
Normal file
245
demos/gtk-demo/constraints2.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/* Constraints/Interactive
|
||||
*
|
||||
* Demonstrate how constraints can be updates during
|
||||
* user interaction.
|
||||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
G_DECLARE_FINAL_TYPE (InteractiveGrid, interactive_grid, INTERACTIVE, GRID, GtkWidget)
|
||||
|
||||
struct _InteractiveGrid
|
||||
{
|
||||
GtkWidget parent_instance;
|
||||
|
||||
GtkWidget *button1, *button2;
|
||||
GtkWidget *button3;
|
||||
GtkConstraintGuide *guide;
|
||||
GtkConstraint *constraint;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (InteractiveGrid, interactive_grid, GTK_TYPE_WIDGET)
|
||||
|
||||
static void
|
||||
interactive_grid_destroy (GtkWidget *widget)
|
||||
{
|
||||
InteractiveGrid *self = INTERACTIVE_GRID (widget);
|
||||
|
||||
g_clear_pointer (&self->button1, gtk_widget_destroy);
|
||||
g_clear_pointer (&self->button2, gtk_widget_destroy);
|
||||
g_clear_pointer (&self->button3, gtk_widget_destroy);
|
||||
|
||||
GTK_WIDGET_CLASS (interactive_grid_parent_class)->destroy (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
interactive_grid_class_init (InteractiveGridClass *klass)
|
||||
{
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
widget_class->destroy = interactive_grid_destroy;
|
||||
|
||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
build_constraints (InteractiveGrid *self,
|
||||
GtkConstraintLayout *manager)
|
||||
{
|
||||
self->guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
|
||||
gtk_constraint_layout_add_guide (manager, self->guide);
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button3),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button1),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
GTK_CONSTRAINT_TARGET (self->button2),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
0.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
gtk_constraint_layout_add_constraint (manager,
|
||||
gtk_constraint_new (GTK_CONSTRAINT_TARGET (self->button3),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
NULL,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
1.0,
|
||||
-8.0,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED));
|
||||
}
|
||||
|
||||
static void
|
||||
drag_cb (GtkGestureDrag *drag,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
InteractiveGrid *self)
|
||||
{
|
||||
GtkConstraintLayout *layout = GTK_CONSTRAINT_LAYOUT (gtk_widget_get_layout_manager (GTK_WIDGET (self)));
|
||||
double x, y;
|
||||
|
||||
if (self->constraint)
|
||||
{
|
||||
gtk_constraint_layout_remove_constraint (layout, self->constraint);
|
||||
g_clear_object (&self->constraint);
|
||||
}
|
||||
|
||||
gtk_gesture_drag_get_start_point (drag, &x, &y);
|
||||
self->constraint = gtk_constraint_new_constant (GTK_CONSTRAINT_TARGET (self->guide),
|
||||
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
x + offset_x,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED);
|
||||
gtk_constraint_layout_add_constraint (layout, g_object_ref (self->constraint));
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
interactive_grid_init (InteractiveGrid *self)
|
||||
{
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
GtkGesture *drag;
|
||||
|
||||
self->button1 = gtk_button_new_with_label ("Child 1");
|
||||
gtk_widget_set_parent (self->button1, widget);
|
||||
gtk_widget_set_name (self->button1, "button1");
|
||||
|
||||
self->button2 = gtk_button_new_with_label ("Child 2");
|
||||
gtk_widget_set_parent (self->button2, widget);
|
||||
gtk_widget_set_name (self->button2, "button2");
|
||||
|
||||
self->button3 = gtk_button_new_with_label ("Child 3");
|
||||
gtk_widget_set_parent (self->button3, widget);
|
||||
gtk_widget_set_name (self->button3, "button3");
|
||||
|
||||
GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
|
||||
build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
|
||||
|
||||
drag = gtk_gesture_drag_new ();
|
||||
g_signal_connect (drag, "drag-update", G_CALLBACK (drag_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drag));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_constraints2 (GtkWidget *do_widget)
|
||||
{
|
||||
static GtkWidget *window;
|
||||
|
||||
if (!window)
|
||||
{
|
||||
GtkWidget *header, *box, *grid, *button;
|
||||
|
||||
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
gtk_window_set_display (GTK_WINDOW (window), gtk_widget_get_display (do_widget));
|
||||
|
||||
header = gtk_header_bar_new ();
|
||||
gtk_header_bar_set_title (GTK_HEADER_BAR (header), "Constraints");
|
||||
gtk_header_bar_set_show_title_buttons (GTK_HEADER_BAR (header), FALSE);
|
||||
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||
g_signal_connect (window, "destroy",
|
||||
G_CALLBACK (gtk_widget_destroyed), &window);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
|
||||
gtk_container_add (GTK_CONTAINER (window), box);
|
||||
|
||||
grid = g_object_new (interactive_grid_get_type (), NULL);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
gtk_widget_set_vexpand (grid, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (box), grid);
|
||||
|
||||
button = gtk_button_new_with_label ("Close");
|
||||
gtk_container_add (GTK_CONTAINER (box), button);
|
||||
gtk_widget_set_hexpand (grid, TRUE);
|
||||
g_signal_connect_swapped (button, "clicked",
|
||||
G_CALLBACK (gtk_widget_destroy), window);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_widget_destroy (window);
|
||||
|
||||
return window;
|
||||
}
|
@@ -150,6 +150,8 @@
|
||||
<file>clipboard.c</file>
|
||||
<file>colorsel.c</file>
|
||||
<file>combobox.c</file>
|
||||
<file>constraints.c</file>
|
||||
<file>constraints2.c</file>
|
||||
<file>css_accordion.c</file>
|
||||
<file>css_basics.c</file>
|
||||
<file>css_blendmodes.c</file>
|
||||
|
@@ -8,6 +8,8 @@ demos = files([
|
||||
'clipboard.c',
|
||||
'colorsel.c',
|
||||
'combobox.c',
|
||||
'constraints.c',
|
||||
'constraints2.c',
|
||||
'css_accordion.c',
|
||||
'css_basics.c',
|
||||
'css_blendmodes.c',
|
||||
|
@@ -82,6 +82,8 @@
|
||||
#include <gtk/gtkcolorutils.h>
|
||||
#include <gtk/gtkcombobox.h>
|
||||
#include <gtk/gtkcomboboxtext.h>
|
||||
#include <gtk/gtkconstraintlayout.h>
|
||||
#include <gtk/gtkconstraint.h>
|
||||
#include <gtk/gtkcontainer.h>
|
||||
#include <gtk/gtkcssprovider.h>
|
||||
#include <gtk/gtkcustomlayout.h>
|
||||
|
617
gtk/gtkconstraint.c
Normal file
617
gtk/gtkconstraint.c
Normal file
@@ -0,0 +1,617 @@
|
||||
/* gtkconstraint.c: Constraint between two widgets
|
||||
* Copyright 2019 GNOME Foundation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:gtkconstraint
|
||||
* @Title: GtkConstraint
|
||||
* @Short_description: The description of a constraint
|
||||
*
|
||||
* #GtkConstraint describes a constraint between an attribute on a widget
|
||||
* and another attribute on another widget, expressed as a linear equation
|
||||
* like:
|
||||
*
|
||||
* |[
|
||||
* target.attr1 = source.attr2 × multiplier + constant
|
||||
* ]|
|
||||
*
|
||||
* Each #GtkConstraint is part of a system that will be solved by a
|
||||
* #GtkConstraintLayout in order to allocate and position each child widget.
|
||||
*
|
||||
* The source and target widgets, as well as their attributes, of a
|
||||
* #GtkConstraint instance are immutable after creation.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkconstraintprivate.h"
|
||||
#include "gtkconstraintsolverprivate.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkwidget.h"
|
||||
|
||||
enum {
|
||||
PROP_TARGET = 1,
|
||||
PROP_TARGET_ATTRIBUTE,
|
||||
PROP_RELATION,
|
||||
PROP_SOURCE,
|
||||
PROP_SOURCE_ATTRIBUTE,
|
||||
PROP_MULTIPLIER,
|
||||
PROP_CONSTANT,
|
||||
PROP_STRENGTH,
|
||||
|
||||
N_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *obj_props[N_PROPERTIES];
|
||||
|
||||
G_DEFINE_TYPE (GtkConstraint, gtk_constraint, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gtk_constraint_set_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkConstraint *self = GTK_CONSTRAINT (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TARGET:
|
||||
self->target = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_TARGET_ATTRIBUTE:
|
||||
self->target_attribute = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_RELATION:
|
||||
self->relation = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_SOURCE:
|
||||
self->source = g_value_get_object (value);
|
||||
break;
|
||||
|
||||
case PROP_SOURCE_ATTRIBUTE:
|
||||
self->source_attribute = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_MULTIPLIER:
|
||||
self->multiplier = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_CONSTANT:
|
||||
self->constant = g_value_get_double (value);
|
||||
break;
|
||||
|
||||
case PROP_STRENGTH:
|
||||
self->strength = g_value_get_int (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_constraint_get_property (GObject *gobject,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkConstraint *self = GTK_CONSTRAINT (gobject);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TARGET:
|
||||
g_value_set_object (value, self->target);
|
||||
break;
|
||||
|
||||
case PROP_TARGET_ATTRIBUTE:
|
||||
g_value_set_enum (value, self->target_attribute);
|
||||
break;
|
||||
|
||||
case PROP_RELATION:
|
||||
g_value_set_enum (value, self->relation);
|
||||
break;
|
||||
|
||||
case PROP_SOURCE:
|
||||
g_value_set_object (value, self->source);
|
||||
break;
|
||||
|
||||
case PROP_SOURCE_ATTRIBUTE:
|
||||
g_value_set_enum (value, self->source_attribute);
|
||||
break;
|
||||
|
||||
case PROP_MULTIPLIER:
|
||||
g_value_set_double (value, self->multiplier);
|
||||
break;
|
||||
|
||||
case PROP_CONSTANT:
|
||||
g_value_set_double (value, self->constant);
|
||||
break;
|
||||
|
||||
case PROP_STRENGTH:
|
||||
g_value_set_int (value, self->strength);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_constraint_finalize (GObject *gobject)
|
||||
{
|
||||
GtkConstraint *self = GTK_CONSTRAINT (gobject);
|
||||
|
||||
gtk_constraint_detach (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_constraint_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_constraint_class_init (GtkConstraintClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->set_property = gtk_constraint_set_property;
|
||||
gobject_class->get_property = gtk_constraint_get_property;
|
||||
gobject_class->finalize = gtk_constraint_finalize;
|
||||
|
||||
/**
|
||||
* GtkConstraint:target:
|
||||
*
|
||||
* The target of the constraint.
|
||||
*
|
||||
* The constraint will set the #GtkConstraint:target-attribute of the
|
||||
* target using the #GtkConstraint:source-attribute of the source
|
||||
* widget.
|
||||
*/
|
||||
obj_props[PROP_TARGET] =
|
||||
g_param_spec_object ("target",
|
||||
P_("Target"),
|
||||
P_("The target of the constraint"),
|
||||
GTK_TYPE_CONSTRAINT_TARGET,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkConstraint:target-attribute:
|
||||
*
|
||||
* The attribute of the #GtkConstraint:target set by the constraint.
|
||||
*/
|
||||
obj_props[PROP_TARGET_ATTRIBUTE] =
|
||||
g_param_spec_enum ("target-attribute",
|
||||
P_("Target Attribute"),
|
||||
P_("The attribute of the target set by the constraint"),
|
||||
GTK_TYPE_CONSTRAINT_ATTRIBUTE,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_NONE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkConstraint:relation:
|
||||
*
|
||||
* The relation order between the terms of the constraint.
|
||||
*/
|
||||
obj_props[PROP_RELATION] =
|
||||
g_param_spec_enum ("relation",
|
||||
P_("Relation"),
|
||||
P_("The relation between the source and target attributes"),
|
||||
GTK_TYPE_CONSTRAINT_RELATION,
|
||||
GTK_CONSTRAINT_RELATION_EQ,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkConstraint:source:
|
||||
*
|
||||
* The source of the constraint.
|
||||
*
|
||||
* The constraint will set the #GtkConstraint:target-attribute of the
|
||||
* target using the #GtkConstraint:source-attribute of the source.
|
||||
*/
|
||||
obj_props[PROP_SOURCE] =
|
||||
g_param_spec_object ("source",
|
||||
P_("Source"),
|
||||
P_("The source of the constraint"),
|
||||
GTK_TYPE_CONSTRAINT_TARGET,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkConstraint:source-attribute:
|
||||
*
|
||||
* The attribute of the #GtkConstraint:source read by the constraint.
|
||||
*/
|
||||
obj_props[PROP_SOURCE_ATTRIBUTE] =
|
||||
g_param_spec_enum ("source-attribute",
|
||||
P_("Source Attribute"),
|
||||
P_("The attribute of the source widget set by the constraint"),
|
||||
GTK_TYPE_CONSTRAINT_ATTRIBUTE,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_NONE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkConstraint:multiplier:
|
||||
*
|
||||
* The multiplication factor to be applied to the
|
||||
* #GtkConstraint:source-attribue.
|
||||
*/
|
||||
obj_props[PROP_MULTIPLIER] =
|
||||
g_param_spec_double ("multiplier",
|
||||
P_("Multiplier"),
|
||||
P_("The multiplication factor to be applied to the source attribute"),
|
||||
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkConstraint:constant:
|
||||
*
|
||||
* The constant value to be added to the #GtkConstraint:source-attribute.
|
||||
*/
|
||||
obj_props[PROP_CONSTANT] =
|
||||
g_param_spec_double ("constant",
|
||||
P_("Constant"),
|
||||
P_("The constant to be added to the source attribute"),
|
||||
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* GtkConstraint:strength:
|
||||
*
|
||||
* The strength of the constraint.
|
||||
*
|
||||
* The strength can be expressed either using one of the symbolic values
|
||||
* of the #GtkConstraintStrength enumeration, or any positive integer
|
||||
* value.
|
||||
*/
|
||||
obj_props[PROP_STRENGTH] =
|
||||
g_param_spec_int ("strength",
|
||||
P_("Strength"),
|
||||
P_("The strength of the constraint"),
|
||||
GTK_CONSTRAINT_STRENGTH_WEAK, G_MAXINT,
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS |
|
||||
G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_props);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_constraint_init (GtkConstraint *self)
|
||||
{
|
||||
self->multiplier = 1.0;
|
||||
self->constant = 0.0;
|
||||
|
||||
self->target_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE;
|
||||
self->source_attribute = GTK_CONSTRAINT_ATTRIBUTE_NONE;
|
||||
self->relation = GTK_CONSTRAINT_RELATION_EQ;
|
||||
self->strength = GTK_CONSTRAINT_STRENGTH_REQUIRED;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_new:
|
||||
* @target: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget
|
||||
* @target_attribute: the attribute of @target to be set
|
||||
* @relation: the relation equivalence between @target_attribute and @source_attribute
|
||||
* @source: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget
|
||||
* @source_attribute: the attribute of @source to be read
|
||||
* @multiplier: a multiplication factor to be applied to @source_attribute
|
||||
* @constant: a constant factor to be added to @source_attribute
|
||||
* @strength: the strength of the constraint
|
||||
*
|
||||
* Creates a new #GtkConstraint representing a relation between a layout
|
||||
* attribute on a source and a layout attribute on a target.
|
||||
*
|
||||
* Returns: the newly created #GtkConstraint
|
||||
*/
|
||||
GtkConstraint *
|
||||
gtk_constraint_new (gpointer target,
|
||||
GtkConstraintAttribute target_attribute,
|
||||
GtkConstraintRelation relation,
|
||||
gpointer source,
|
||||
GtkConstraintAttribute source_attribute,
|
||||
double multiplier,
|
||||
double constant,
|
||||
int strength)
|
||||
{
|
||||
g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL);
|
||||
g_return_val_if_fail (source == NULL || GTK_IS_CONSTRAINT_TARGET (source), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_CONSTRAINT,
|
||||
"target", target,
|
||||
"target-attribute", target_attribute,
|
||||
"relation", relation,
|
||||
"source", source,
|
||||
"source-attribute", source_attribute,
|
||||
"multiplier", multiplier,
|
||||
"constant", constant,
|
||||
"strength", strength,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_new_constant:
|
||||
* @target: (nullable) (type GtkConstraintTarget): a #GtkConstraintTarget
|
||||
* @target_attribute: the attribute of @target to be set
|
||||
* @relation: the relation equivalence between @target_attribute and @constant
|
||||
* @constant: a constant factor to be set on @target_attribute
|
||||
* @strength: the strength of the constraint
|
||||
*
|
||||
* Creates a new #GtkConstraint representing a relation between a layout
|
||||
* attribute on a target and a constant value.
|
||||
*
|
||||
* Returns: the newly created #GtkConstraint
|
||||
*/
|
||||
GtkConstraint *
|
||||
gtk_constraint_new_constant (gpointer target,
|
||||
GtkConstraintAttribute target_attribute,
|
||||
GtkConstraintRelation relation,
|
||||
double constant,
|
||||
int strength)
|
||||
{
|
||||
g_return_val_if_fail (target == NULL || GTK_IS_CONSTRAINT_TARGET (target), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_CONSTRAINT,
|
||||
"target", target,
|
||||
"target-attribute", target_attribute,
|
||||
"relation", relation,
|
||||
"source-attribute", GTK_CONSTRAINT_ATTRIBUTE_NONE,
|
||||
"constant", constant,
|
||||
"strength", strength,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_get_target_widget:
|
||||
* @constraint: a #GtkConstraint
|
||||
*
|
||||
* Retrieves the target widget for the @constraint.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GtkWidget
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_constraint_get_target_widget (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
|
||||
|
||||
if (GTK_IS_WIDGET (constraint->target))
|
||||
return GTK_WIDGET (constraint->target);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GtkConstraintTarget *
|
||||
gtk_constraint_get_target (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
|
||||
|
||||
return constraint->target;
|
||||
}
|
||||
|
||||
GtkConstraintAttribute
|
||||
gtk_constraint_get_target_attribute (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE);
|
||||
|
||||
return constraint->target_attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_get_source_widget:
|
||||
* @constraint: a #GtkConstraint
|
||||
*
|
||||
* Retrieves the source widget for the @constraint.
|
||||
*
|
||||
* Returns: (transfer none) (nullable): a #GtkWidget
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_constraint_get_source_widget (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
|
||||
|
||||
if (GTK_IS_WIDGET (constraint->source))
|
||||
return GTK_WIDGET (constraint->source);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GtkConstraintTarget *
|
||||
gtk_constraint_get_source (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), NULL);
|
||||
|
||||
return constraint->source;
|
||||
}
|
||||
|
||||
GtkConstraintAttribute
|
||||
gtk_constraint_get_source_attribute (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_ATTRIBUTE_NONE);
|
||||
|
||||
return constraint->source_attribute;
|
||||
}
|
||||
|
||||
GtkConstraintRelation
|
||||
gtk_constraint_get_relation (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_RELATION_EQ);
|
||||
|
||||
return constraint->relation;
|
||||
}
|
||||
|
||||
double
|
||||
gtk_constraint_get_multiplier (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 1.0);
|
||||
|
||||
return constraint->multiplier;
|
||||
}
|
||||
|
||||
double
|
||||
gtk_constraint_get_constant (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), 0.0);
|
||||
|
||||
return constraint->constant;
|
||||
}
|
||||
|
||||
int
|
||||
gtk_constraint_get_strength (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), GTK_CONSTRAINT_STRENGTH_REQUIRED);
|
||||
|
||||
return constraint->strength;
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_constraint_get_weight:
|
||||
* @constraint: a #GtkConstraint
|
||||
*
|
||||
* Computes the weight of the @constraint to be used with
|
||||
* #GtkConstraintSolver.
|
||||
*
|
||||
* Returns: the weight of the constraint
|
||||
*/
|
||||
double
|
||||
gtk_constraint_get_weight (GtkConstraint *constraint)
|
||||
{
|
||||
if (constraint->strength > 0)
|
||||
return constraint->strength;
|
||||
|
||||
switch (constraint->strength)
|
||||
{
|
||||
case GTK_CONSTRAINT_STRENGTH_REQUIRED:
|
||||
return GTK_CONSTRAINT_WEIGHT_REQUIRED;
|
||||
|
||||
case GTK_CONSTRAINT_STRENGTH_STRONG:
|
||||
return GTK_CONSTRAINT_WEIGHT_STRONG;
|
||||
|
||||
case GTK_CONSTRAINT_STRENGTH_MEDIUM:
|
||||
return GTK_CONSTRAINT_WEIGHT_MEDIUM;
|
||||
|
||||
case GTK_CONSTRAINT_STRENGTH_WEAK:
|
||||
return GTK_CONSTRAINT_WEIGHT_WEAK;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_is_required:
|
||||
* @constraint: a #GtkConstraint
|
||||
*
|
||||
* Checks whether the @constraint is a required relation for solving the
|
||||
* constraint layout.
|
||||
*
|
||||
* Returns: %TRUE if the constraint is required
|
||||
*/
|
||||
gboolean
|
||||
gtk_constraint_is_required (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
|
||||
|
||||
return constraint->strength == GTK_CONSTRAINT_STRENGTH_REQUIRED;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_is_attached:
|
||||
* @constraint: a #GtkConstraint
|
||||
*
|
||||
* Checks whether the @constraint is attached to a #GtkConstraintLayout,
|
||||
* and it is contributing to the layout.
|
||||
*
|
||||
* Returns: %TRUE if the constraint is attached
|
||||
*/
|
||||
gboolean
|
||||
gtk_constraint_is_attached (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
|
||||
|
||||
return constraint->constraint_ref != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_constraint_is_constant:
|
||||
* @constraint: a #GtkConstraint
|
||||
*
|
||||
* Checks whether the @constraint describes a relation between an attribute
|
||||
* on the #GtkConstraint:target-widget and a constant value.
|
||||
*
|
||||
* Returns: %TRUE if the constraint is a constant relation
|
||||
*/
|
||||
gboolean
|
||||
gtk_constraint_is_constant (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_CONSTRAINT (constraint), FALSE);
|
||||
|
||||
return constraint->source == NULL &&
|
||||
constraint->source_attribute == GTK_CONSTRAINT_ATTRIBUTE_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_constraint_attach (GtkConstraint *constraint,
|
||||
GtkConstraintSolver *solver,
|
||||
GtkConstraintRef *ref)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT (constraint));
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT_SOLVER (solver));
|
||||
g_return_if_fail (ref != NULL);
|
||||
|
||||
constraint->constraint_ref = ref;
|
||||
constraint->solver = solver;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_constraint_detach (GtkConstraint *constraint)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_CONSTRAINT (constraint));
|
||||
|
||||
if (constraint->constraint_ref == NULL)
|
||||
return;
|
||||
|
||||
gtk_constraint_solver_remove_constraint (constraint->solver, constraint->constraint_ref);
|
||||
constraint->constraint_ref = NULL;
|
||||
constraint->solver = NULL;
|
||||
}
|
||||
|
||||
typedef struct _GtkConstraintTargetInterface GtkConstraintTargetInterface;
|
||||
|
||||
struct _GtkConstraintTargetInterface
|
||||
{
|
||||
GTypeInterface g_iface;
|
||||
};
|
||||
|
||||
G_DEFINE_INTERFACE (GtkConstraintTarget, gtk_constraint_target, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gtk_constraint_target_default_init (GtkConstraintTargetInterface *iface)
|
||||
{
|
||||
}
|
104
gtk/gtkconstraint.h
Normal file
104
gtk/gtkconstraint.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/* gtkconstraint.h: Constraint between two widgets
|
||||
* Copyright 2019 GNOME Foundation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtkenums.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GtkConstraintTarget GtkConstraintTarget;
|
||||
|
||||
#define GTK_TYPE_CONSTRAINT_TARGET (gtk_constraint_target_get_type ())
|
||||
|
||||
/**
|
||||
* GtkConstraintTarget:
|
||||
*
|
||||
* The GtkConstraintTarget interface is implemented by objects that
|
||||
* can be used as source or target in #GtkConstraints. Besides
|
||||
* #GtkWidget, it is also implemented by #GtkConstraintGuide.
|
||||
*/
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_INTERFACE (GtkConstraintTarget, gtk_constraint_target, GTK, CONSTRAINT_TARGET, GObject)
|
||||
|
||||
#define GTK_TYPE_CONSTRAINT (gtk_constraint_get_type ())
|
||||
|
||||
/**
|
||||
* GtkConstraint:
|
||||
*
|
||||
* An object describing the relation between two widget attributes.
|
||||
*
|
||||
* All relations are in the form:
|
||||
*
|
||||
* |[<!-- language=plain -->
|
||||
* target.attr_name = source.attr_name × multiplier + constant
|
||||
* ]|
|
||||
*
|
||||
* A #GtkConstraint is immutable once it's created.
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkConstraint, gtk_constraint, GTK, CONSTRAINT, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkConstraint * gtk_constraint_new (gpointer target,
|
||||
GtkConstraintAttribute target_attribute,
|
||||
GtkConstraintRelation relation,
|
||||
gpointer source,
|
||||
GtkConstraintAttribute source_attribute,
|
||||
double multiplier,
|
||||
double constant,
|
||||
int strength);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkConstraint * gtk_constraint_new_constant (gpointer target,
|
||||
GtkConstraintAttribute target_attribute,
|
||||
GtkConstraintRelation relation,
|
||||
double constant,
|
||||
int strength);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_constraint_get_target_widget (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkConstraintTarget * gtk_constraint_get_target (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkConstraintAttribute gtk_constraint_get_target_attribute (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_constraint_get_source_widget (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkConstraintTarget * gtk_constraint_get_source (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkConstraintAttribute gtk_constraint_get_source_attribute (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkConstraintRelation gtk_constraint_get_relation (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
double gtk_constraint_get_multiplier (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
double gtk_constraint_get_constant (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gtk_constraint_get_strength (GtkConstraint *constraint);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_constraint_is_required (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_constraint_is_attached (GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_constraint_is_constant (GtkConstraint *constraint);
|
||||
|
||||
G_END_DECLS
|
1839
gtk/gtkconstraintexpression.c
Normal file
1839
gtk/gtkconstraintexpression.c
Normal file
File diff suppressed because it is too large
Load Diff
276
gtk/gtkconstraintexpressionprivate.h
Normal file
276
gtk/gtkconstraintexpressionprivate.h
Normal file
@@ -0,0 +1,276 @@
|
||||
/* gtkconstraintequationprivate.h: Constraint expressions and variables
|
||||
* Copyright 2019 GNOME Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* 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: Emmanuele Bassi
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gtkconstrainttypesprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_variable_new (const char *name);
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_variable_new_dummy (const char *name);
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_variable_new_objective (const char *name);
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_variable_new_slack (const char *name);
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_variable_ref (GtkConstraintVariable *variable);
|
||||
|
||||
void
|
||||
gtk_constraint_variable_unref (GtkConstraintVariable *variable);
|
||||
|
||||
void
|
||||
gtk_constraint_variable_set_value (GtkConstraintVariable *variable,
|
||||
double value);
|
||||
|
||||
double
|
||||
gtk_constraint_variable_get_value (const GtkConstraintVariable *variable);
|
||||
|
||||
void
|
||||
gtk_constraint_variable_set_prefix (GtkConstraintVariable *variable,
|
||||
const char *prefix);
|
||||
|
||||
char *
|
||||
gtk_constraint_variable_to_string (const GtkConstraintVariable *variable);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_variable_is_external (const GtkConstraintVariable *variable);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_variable_is_pivotable (const GtkConstraintVariable *variable);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_variable_is_restricted (const GtkConstraintVariable *variable);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_variable_is_dummy (const GtkConstraintVariable *variable);
|
||||
|
||||
typedef struct {
|
||||
GtkConstraintVariable *first;
|
||||
GtkConstraintVariable *second;
|
||||
} GtkConstraintVariablePair;
|
||||
|
||||
GtkConstraintVariablePair *
|
||||
gtk_constraint_variable_pair_new (GtkConstraintVariable *first,
|
||||
GtkConstraintVariable *second);
|
||||
|
||||
void
|
||||
gtk_constraint_variable_pair_free (GtkConstraintVariablePair *pair);
|
||||
|
||||
typedef struct _GtkConstraintVariableSet GtkConstraintVariableSet;
|
||||
|
||||
GtkConstraintVariableSet *
|
||||
gtk_constraint_variable_set_new (void);
|
||||
|
||||
void
|
||||
gtk_constraint_variable_set_free (GtkConstraintVariableSet *set);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_variable_set_add (GtkConstraintVariableSet *set,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_variable_set_remove (GtkConstraintVariableSet *set,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
int
|
||||
gtk_constraint_variable_set_size (GtkConstraintVariableSet *set);
|
||||
|
||||
typedef struct {
|
||||
/*< private >*/
|
||||
gpointer dummy1;
|
||||
gpointer dummy2;
|
||||
gint64 dummy3;
|
||||
} GtkConstraintVariableSetIter;
|
||||
|
||||
void
|
||||
gtk_constraint_variable_set_iter_init (GtkConstraintVariableSetIter *iter,
|
||||
GtkConstraintVariableSet *set);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_variable_set_iter_next (GtkConstraintVariableSetIter *iter,
|
||||
GtkConstraintVariable **variable_p);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_new (double constant);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_new_from_variable (GtkConstraintVariable *variable);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_ref (GtkConstraintExpression *expression);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_unref (GtkConstraintExpression *expression);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_clone (GtkConstraintExpression *expression);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_set_constant (GtkConstraintExpression *expression,
|
||||
double constant);
|
||||
double
|
||||
gtk_constraint_expression_get_constant (const GtkConstraintExpression *expression);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_expression_is_constant (const GtkConstraintExpression *expression);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_add_expression (GtkConstraintExpression *a_expr,
|
||||
GtkConstraintExpression *b_expr,
|
||||
double n,
|
||||
GtkConstraintVariable *subject,
|
||||
GtkConstraintSolver *solver);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_add_variable (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *variable,
|
||||
double coefficient,
|
||||
GtkConstraintVariable *subject,
|
||||
GtkConstraintSolver *solver);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_remove_variable (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_set_variable (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *variable,
|
||||
double coefficient);
|
||||
|
||||
double
|
||||
gtk_constraint_expression_get_coefficient (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
char *
|
||||
gtk_constraint_expression_to_string (const GtkConstraintExpression *expression);
|
||||
|
||||
double
|
||||
gtk_constraint_expression_new_subject (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *subject);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_change_subject (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *old_subject,
|
||||
GtkConstraintVariable *new_subject);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_substitute_out (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *out_var,
|
||||
GtkConstraintExpression *expr,
|
||||
GtkConstraintVariable *subject,
|
||||
GtkConstraintSolver *solver);
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_expression_get_pivotable_variable (GtkConstraintExpression *expression);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_plus_constant (GtkConstraintExpression *expression,
|
||||
double constant);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_minus_constant (GtkConstraintExpression *expression,
|
||||
double constant);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_plus_variable (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_minus_variable (GtkConstraintExpression *expression,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_multiply_by (GtkConstraintExpression *expression,
|
||||
double factor);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_divide_by (GtkConstraintExpression *expression,
|
||||
double factor);
|
||||
|
||||
struct _GtkConstraintExpressionBuilder
|
||||
{
|
||||
/*< private >*/
|
||||
gpointer dummy1;
|
||||
gpointer dummy2;
|
||||
int dummy3;
|
||||
};
|
||||
|
||||
void
|
||||
gtk_constraint_expression_builder_init (GtkConstraintExpressionBuilder *builder,
|
||||
GtkConstraintSolver *solver);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_builder_term (GtkConstraintExpressionBuilder *builder,
|
||||
GtkConstraintVariable *term);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_builder_plus (GtkConstraintExpressionBuilder *builder);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_builder_minus (GtkConstraintExpressionBuilder *builder);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_builder_divide_by (GtkConstraintExpressionBuilder *builder);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_builder_multiply_by (GtkConstraintExpressionBuilder *builder);
|
||||
|
||||
void
|
||||
gtk_constraint_expression_builder_constant (GtkConstraintExpressionBuilder *builder,
|
||||
double value);
|
||||
|
||||
GtkConstraintExpression *
|
||||
gtk_constraint_expression_builder_finish (GtkConstraintExpressionBuilder *builder) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
/*< private >
|
||||
* GtkConstraintExpressionIter:
|
||||
*
|
||||
* An iterator object for terms inside a #GtkConstraintExpression.
|
||||
*/
|
||||
typedef struct {
|
||||
/*< private >*/
|
||||
gpointer dummy1;
|
||||
gpointer dummy2;
|
||||
gint64 dummy3;
|
||||
} GtkConstraintExpressionIter;
|
||||
|
||||
void
|
||||
gtk_constraint_expression_iter_init (GtkConstraintExpressionIter *iter,
|
||||
GtkConstraintExpression *equation);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_expression_iter_next (GtkConstraintExpressionIter *iter,
|
||||
GtkConstraintVariable **variable,
|
||||
double *coefficient);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_expression_iter_prev (GtkConstraintExpressionIter *iter,
|
||||
GtkConstraintVariable **variable,
|
||||
double *coefficient);
|
||||
|
||||
G_END_DECLS
|
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
|
1210
gtk/gtkconstraintlayout.c
Normal file
1210
gtk/gtkconstraintlayout.c
Normal file
File diff suppressed because it is too large
Load Diff
64
gtk/gtkconstraintlayout.h
Normal file
64
gtk/gtkconstraintlayout.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* gtkconstraintlayout.h: Layout manager using constraints
|
||||
* Copyright 2019 GNOME Foundation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#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 ())
|
||||
|
||||
/**
|
||||
* GtkConstraintLayoutChild:
|
||||
*
|
||||
* A #GtkLayoutChild in a #GtkConstraintLayout.
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkConstraintLayoutChild, gtk_constraint_layout_child, GTK, CONSTRAINT_LAYOUT_CHILD, GtkLayoutChild)
|
||||
|
||||
/**
|
||||
* GtkConstraintLayout:
|
||||
*
|
||||
* A layout manager using #GtkConstraint to describe
|
||||
* relations between widgets.
|
||||
*/
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkConstraintLayout, gtk_constraint_layout, GTK, CONSTRAINT_LAYOUT, GtkLayoutManager)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkLayoutManager * gtk_constraint_layout_new (void);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_layout_add_constraint (GtkConstraintLayout *manager,
|
||||
GtkConstraint *constraint);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_constraint_layout_remove_constraint (GtkConstraintLayout *manager,
|
||||
GtkConstraint *constraint);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
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
|
62
gtk/gtkconstraintprivate.h
Normal file
62
gtk/gtkconstraintprivate.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* gtkconstraintprivate.h: Constraint between two widgets
|
||||
* Copyright 2019 GNOME Foundation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Emmanuele Bassi
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gtkconstraint.h"
|
||||
#include "gtkconstrainttypesprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct _GtkConstraint
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GtkConstraintAttribute target_attribute;
|
||||
GtkConstraintAttribute source_attribute;
|
||||
|
||||
GtkConstraintTarget *target;
|
||||
GtkConstraintTarget *source;
|
||||
|
||||
GtkConstraintRelation relation;
|
||||
|
||||
double multiplier;
|
||||
double constant;
|
||||
|
||||
int strength;
|
||||
|
||||
/* A reference to the real constraint inside the
|
||||
* GtkConstraintSolver, so we can remove it when
|
||||
* finalizing the GtkConstraint instance
|
||||
*/
|
||||
GtkConstraintRef *constraint_ref;
|
||||
|
||||
GtkConstraintSolver *solver;
|
||||
|
||||
guint active : 1;
|
||||
};
|
||||
|
||||
double gtk_constraint_get_weight (GtkConstraint *constraint);
|
||||
|
||||
void gtk_constraint_attach (GtkConstraint *constraint,
|
||||
GtkConstraintSolver *solver,
|
||||
GtkConstraintRef *ref);
|
||||
void gtk_constraint_detach (GtkConstraint *constraint);
|
||||
|
||||
G_END_DECLS
|
2208
gtk/gtkconstraintsolver.c
Normal file
2208
gtk/gtkconstraintsolver.c
Normal file
File diff suppressed because it is too large
Load Diff
165
gtk/gtkconstraintsolverprivate.h
Normal file
165
gtk/gtkconstraintsolverprivate.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/* gtkconstraintsolverprivate.h: Constraint solver based on the Cassowary method
|
||||
* Copyright 2019 GNOME Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* 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: Emmanuele Bassi
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gtkconstrainttypesprivate.h"
|
||||
|
||||
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
|
||||
* sake, so we don't have to necessarily reason in terms of numeric values.
|
||||
*
|
||||
* The public API has a similar approach, where the symbolic constants are negative
|
||||
* values, and positive values are explicit weights. We map those values into
|
||||
* numeric values that the GtkConstraintSolver can plug into the linear equations
|
||||
* tableau.
|
||||
*/
|
||||
#define GTK_CONSTRAINT_WEIGHT_REQUIRED (make_weight (1000, 1000, 1000, 1))
|
||||
#define GTK_CONSTRAINT_WEIGHT_STRONG (make_weight ( 1, 0, 0, 1))
|
||||
#define GTK_CONSTRAINT_WEIGHT_MEDIUM (make_weight ( 0, 1, 0, 1))
|
||||
#define GTK_CONSTRAINT_WEIGHT_WEAK (make_weight ( 0, 0, 1, 1))
|
||||
|
||||
G_GNUC_PURE
|
||||
static inline double
|
||||
make_weight (double a,
|
||||
double b,
|
||||
double c,
|
||||
double w)
|
||||
{
|
||||
double res = 0;
|
||||
|
||||
res += CLAMP (a * w, 0, 1000) * 1000000;
|
||||
res += CLAMP (b * w, 0, 1000) * 1000;
|
||||
res += CLAMP (c * w, 0, 1000);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
GtkConstraintSolver *
|
||||
gtk_constraint_solver_new (void);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_freeze (GtkConstraintSolver *solver);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_thaw (GtkConstraintSolver *solver);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_resolve (GtkConstraintSolver *solver);
|
||||
|
||||
GtkConstraintVariable *
|
||||
gtk_constraint_solver_create_variable (GtkConstraintSolver *solver,
|
||||
const char *prefix,
|
||||
const char *name,
|
||||
double value);
|
||||
|
||||
GtkConstraintRef *
|
||||
gtk_constraint_solver_add_constraint (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable,
|
||||
GtkConstraintRelation relation,
|
||||
GtkConstraintExpression *expression,
|
||||
double strength);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_remove_constraint (GtkConstraintSolver *solver,
|
||||
GtkConstraintRef *reference);
|
||||
|
||||
GtkConstraintRef *
|
||||
gtk_constraint_solver_add_stay_variable (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable,
|
||||
double strength);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_remove_stay_variable (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_solver_has_stay_variable (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
GtkConstraintRef *
|
||||
gtk_constraint_solver_add_edit_variable (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable,
|
||||
double strength);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_remove_edit_variable (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
gboolean
|
||||
gtk_constraint_solver_has_edit_variable (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_suggest_value (GtkConstraintSolver *solver,
|
||||
GtkConstraintVariable *variable,
|
||||
double value);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_begin_edit (GtkConstraintSolver *solver);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_end_edit (GtkConstraintSolver *solver);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_note_added_variable (GtkConstraintSolver *self,
|
||||
GtkConstraintVariable *variable,
|
||||
GtkConstraintVariable *subject);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_note_removed_variable (GtkConstraintSolver *self,
|
||||
GtkConstraintVariable *variable,
|
||||
GtkConstraintVariable *subject);
|
||||
|
||||
void
|
||||
gtk_constraint_solver_clear (GtkConstraintSolver *solver);
|
||||
|
||||
char *
|
||||
gtk_constraint_solver_to_string (GtkConstraintSolver *solver);
|
||||
|
||||
G_END_DECLS
|
50
gtk/gtkconstrainttypesprivate.h
Normal file
50
gtk/gtkconstrainttypesprivate.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* gtkconstrainttypesprivate.h: Private types for the constraint solver
|
||||
* Copyright 2019 GNOME Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*
|
||||
* 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: Emmanuele Bassi
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtkenums.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _GtkConstraintVariable GtkConstraintVariable;
|
||||
typedef struct _GtkConstraintExpression GtkConstraintExpression;
|
||||
typedef struct _GtkConstraintExpressionBuilder GtkConstraintExpressionBuilder;
|
||||
|
||||
/*< private >
|
||||
* GtkConstraintRef:
|
||||
*
|
||||
* A reference to a constraint stored inside the solver; while #GtkConstraint
|
||||
* represent the public API, a #GtkConstraintRef represents data stored inside
|
||||
* the solver. A #GtkConstraintRef is completely opaque, and should only be
|
||||
* used to remove a constraint from the solver.
|
||||
*/
|
||||
typedef struct _GtkConstraintRef GtkConstraintRef;
|
||||
|
||||
/*< private >
|
||||
* GtkConstraintSolver:
|
||||
*
|
||||
* A simplex solver using the Cassowary constraint solving algorithm.
|
||||
*/
|
||||
typedef struct _GtkConstraintSolver GtkConstraintSolver;
|
||||
|
||||
G_END_DECLS
|
@@ -1053,4 +1053,78 @@ typedef enum {
|
||||
GTK_PICK_NON_TARGETABLE = 1 << 1
|
||||
} GtkPickFlags;
|
||||
|
||||
/**
|
||||
* GtkConstraintRelation:
|
||||
* @GTK_CONSTRAINT_RELATION_EQ: Equal
|
||||
* @GTK_CONSTRAINT_RELATION_LE: Less than, or equal
|
||||
* @GTK_CONSTRAINT_RELATION_GE: Greater than, or equal
|
||||
*
|
||||
* The relation between two terms of a constraint.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_CONSTRAINT_RELATION_LE = -1,
|
||||
GTK_CONSTRAINT_RELATION_EQ = 0,
|
||||
GTK_CONSTRAINT_RELATION_GE = 1
|
||||
} GtkConstraintRelation;
|
||||
|
||||
/**
|
||||
* GtkConstraintStrength:
|
||||
* @GTK_CONSTRAINT_STRENGTH_REQUIRED: The constraint is required towards solving the layout
|
||||
* @GTK_CONSTRAINT_STRENGTH_STRONG: A strong constraint
|
||||
* @GTK_CONSTRAINT_STRENGTH_MEDIUM: A medium constraint
|
||||
* @GTK_CONSTRAINT_STRENGTH_WEAK: A weak constraint
|
||||
*
|
||||
* The strength of a constraint, expressed as a symbolic constant.
|
||||
*
|
||||
* The strength of a #GtkConstraint can be expressed with any positive
|
||||
* integer; the values of this enumeration can be used for readability.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_CONSTRAINT_STRENGTH_REQUIRED = 0,
|
||||
GTK_CONSTRAINT_STRENGTH_STRONG = -1,
|
||||
GTK_CONSTRAINT_STRENGTH_MEDIUM = -2,
|
||||
GTK_CONSTRAINT_STRENGTH_WEAK = -3
|
||||
} GtkConstraintStrength;
|
||||
|
||||
/**
|
||||
* GtkConstraintAttribute:
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_NONE: No attribute, used for constant
|
||||
* relations
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_LEFT: The left edge of a widget, regardless of
|
||||
* text direction
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_RIGHT: The right edge of a widget, regardless
|
||||
* of text direction
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_TOP: The top edge of a widget
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_BOTTOM: The bottom edge of a widget
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_START: The leading edge of a widget, depending
|
||||
* on text direction; equivalent to %GTK_CONSTRAINT_ATTRIBUTE_LEFT for LTR
|
||||
* languages, and %GTK_CONSTRAINT_ATTRIBUTE_RIGHT for RTL ones
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_END: The trailing edge of a widget, depending
|
||||
* on text direction; equivalent to %GTK_CONSTRAINT_ATTRIBUTE_RIGHT for LTR
|
||||
* languages, and %GTK_CONSTRAINT_ATTRIBUTE_LEFT for RTL ones
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_WIDTH: The width of a widget
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_HEIGHT: The height of a widget
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_CENTER_X: The center of a widget, on the
|
||||
* horizontal axis
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y: The center of a widget, on the
|
||||
* vertical axis
|
||||
* @GTK_CONSTRAINT_ATTRIBUTE_BASELINE: The baseline of a widget
|
||||
*
|
||||
* The widget attributes that can be used when creating a #GtkConstraint.
|
||||
*/
|
||||
typedef enum {
|
||||
GTK_CONSTRAINT_ATTRIBUTE_NONE,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_LEFT,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_RIGHT,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_TOP,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_START,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_END,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_HEIGHT,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_CENTER_X,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_CENTER_Y,
|
||||
GTK_CONSTRAINT_ATTRIBUTE_BASELINE
|
||||
} GtkConstraintAttribute;
|
||||
|
||||
#endif /* __GTK_ENUMS_H__ */
|
||||
|
@@ -91,6 +91,7 @@
|
||||
|
||||
typedef struct {
|
||||
GtkWidget *widget;
|
||||
GtkRoot *root;
|
||||
|
||||
/* HashTable<Widget, LayoutChild> */
|
||||
GHashTable *layout_children;
|
||||
@@ -98,6 +99,16 @@ typedef struct {
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GtkLayoutManager, gtk_layout_manager, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
gtk_layout_manager_real_root (GtkLayoutManager *manager)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_layout_manager_real_unroot (GtkLayoutManager *manager)
|
||||
{
|
||||
}
|
||||
|
||||
static GtkSizeRequestMode
|
||||
gtk_layout_manager_real_get_request_mode (GtkLayoutManager *manager,
|
||||
GtkWidget *widget)
|
||||
@@ -188,13 +199,30 @@ gtk_layout_manager_real_create_layout_child (GtkLayoutManager *manager,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_layout_manager_finalize (GObject *gobject)
|
||||
{
|
||||
GtkLayoutManager *self = GTK_LAYOUT_MANAGER (gobject);
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->layout_children, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (gtk_layout_manager_parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_layout_manager_class_init (GtkLayoutManagerClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = gtk_layout_manager_finalize;
|
||||
|
||||
klass->get_request_mode = gtk_layout_manager_real_get_request_mode;
|
||||
klass->measure = gtk_layout_manager_real_measure;
|
||||
klass->allocate = gtk_layout_manager_real_allocate;
|
||||
klass->create_layout_child = gtk_layout_manager_real_create_layout_child;
|
||||
klass->root = gtk_layout_manager_real_root;
|
||||
klass->unroot = gtk_layout_manager_real_unroot;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -226,6 +254,38 @@ gtk_layout_manager_set_widget (GtkLayoutManager *layout_manager,
|
||||
}
|
||||
|
||||
priv->widget = widget;
|
||||
|
||||
if (widget != NULL)
|
||||
gtk_layout_manager_set_root (layout_manager, gtk_widget_get_root (widget));
|
||||
}
|
||||
|
||||
/*< private >
|
||||
* gtk_layout_manager_set_root:
|
||||
* @layout_manager: a #GtkLayoutManager
|
||||
* @root: (nullable): a #GtkWidget implementing #GtkRoot
|
||||
*
|
||||
* Sets a back pointer from @root to @layout_manager.
|
||||
*
|
||||
* This function is called by #GtkWidget when getting rooted and unrooted,
|
||||
* and will call #GtkLayoutManagerClass.root() or #GtkLayoutManagerClass.unroot()
|
||||
* depending on whether @root is a #GtkWidget or %NULL.
|
||||
*/
|
||||
void
|
||||
gtk_layout_manager_set_root (GtkLayoutManager *layout_manager,
|
||||
GtkRoot *root)
|
||||
{
|
||||
GtkLayoutManagerPrivate *priv = gtk_layout_manager_get_instance_private (layout_manager);
|
||||
GtkRoot *old_root = priv->root;
|
||||
|
||||
priv->root = root;
|
||||
|
||||
if (old_root != root)
|
||||
{
|
||||
if (priv->root != NULL)
|
||||
GTK_LAYOUT_MANAGER_GET_CLASS (layout_manager)->root (layout_manager);
|
||||
else
|
||||
GTK_LAYOUT_MANAGER_GET_CLASS (layout_manager)->unroot (layout_manager);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -42,6 +42,10 @@ G_DECLARE_DERIVABLE_TYPE (GtkLayoutManager, gtk_layout_manager, GTK, LAYOUT_MANA
|
||||
* @layout_child_type: the type of #GtkLayoutChild used by this layout manager
|
||||
* @create_layout_child: a virtual function, used to create a #GtkLayoutChild
|
||||
* meta object for the layout properties
|
||||
* @root: a virtual function, called when the widget using the layout
|
||||
* manager is attached to a #GtkRoot
|
||||
* @unroot: a virtual function, called when the widget using the layout
|
||||
* manager is detached from a #GtkRoot
|
||||
*
|
||||
* The `GtkLayoutManagerClass` structure contains only private data, and
|
||||
* should only be accessed through the provided API, or when subclassing
|
||||
@@ -77,6 +81,9 @@ struct _GtkLayoutManagerClass
|
||||
GtkWidget *widget,
|
||||
GtkWidget *for_child);
|
||||
|
||||
void (* root) (GtkLayoutManager *manager);
|
||||
void (* unroot) (GtkLayoutManager *manager);
|
||||
|
||||
/*< private >*/
|
||||
gpointer _padding[16];
|
||||
};
|
||||
|
@@ -10,4 +10,7 @@ void gtk_layout_manager_set_widget (GtkLayoutManager *manager,
|
||||
void gtk_layout_manager_remove_layout_child (GtkLayoutManager *manager,
|
||||
GtkWidget *widget);
|
||||
|
||||
void gtk_layout_manager_set_root (GtkLayoutManager *manager,
|
||||
GtkRoot *root);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -50,10 +50,18 @@ gtk_root_default_get_display (GtkRoot *self)
|
||||
return gdk_display_get_default ();
|
||||
}
|
||||
|
||||
|
||||
static GtkConstraintSolver *
|
||||
gtk_root_default_get_constraint_solver (GtkRoot *self)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_root_default_init (GtkRootInterface *iface)
|
||||
{
|
||||
iface->get_display = gtk_root_default_get_display;
|
||||
iface->get_constraint_solver = gtk_root_default_get_constraint_solver;
|
||||
|
||||
g_object_interface_install_property (iface,
|
||||
g_param_spec_object ("focus-widget",
|
||||
@@ -82,6 +90,17 @@ gtk_root_get_display (GtkRoot *self)
|
||||
return iface->get_display (self);
|
||||
}
|
||||
|
||||
GtkConstraintSolver *
|
||||
gtk_root_get_constraint_solver (GtkRoot *self)
|
||||
{
|
||||
GtkRootInterface *iface;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_ROOT (self), NULL);
|
||||
|
||||
iface = GTK_ROOT_GET_IFACE (self);
|
||||
return iface->get_constraint_solver (self);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_root_set_focus:
|
||||
* @self: a #GtkRoot
|
||||
|
@@ -34,20 +34,6 @@ G_BEGIN_DECLS
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_INTERFACE (GtkRoot, gtk_root, GTK, ROOT, GtkWidget)
|
||||
|
||||
/**
|
||||
* GtkRootIface:
|
||||
*
|
||||
* The list of functions that must be implemented for the #GtkRoot interface.
|
||||
*/
|
||||
struct _GtkRootInterface
|
||||
{
|
||||
/*< private >*/
|
||||
GTypeInterface g_iface;
|
||||
|
||||
/*< public >*/
|
||||
GdkDisplay * (* get_display) (GtkRoot *self);
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GdkDisplay * gtk_root_get_display (GtkRoot *self);
|
||||
|
||||
|
@@ -3,8 +3,28 @@
|
||||
|
||||
#include "gtkroot.h"
|
||||
|
||||
#include "gtkconstraintsolverprivate.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* GtkRootIface:
|
||||
*
|
||||
* The list of functions that must be implemented for the #GtkRoot interface.
|
||||
*/
|
||||
struct _GtkRootInterface
|
||||
{
|
||||
/*< private >*/
|
||||
GTypeInterface g_iface;
|
||||
|
||||
/*< public >*/
|
||||
GdkDisplay * (* get_display) (GtkRoot *self);
|
||||
|
||||
GtkConstraintSolver * (* get_constraint_solver) (GtkRoot *self);
|
||||
};
|
||||
|
||||
GtkConstraintSolver * gtk_root_get_constraint_solver (GtkRoot *self);
|
||||
|
||||
enum {
|
||||
GTK_ROOT_PROP_FOCUS_WIDGET,
|
||||
GTK_ROOT_NUM_PROPERTIES
|
||||
|
@@ -73,6 +73,7 @@
|
||||
#include "gtkwindowgroup.h"
|
||||
#include "gtkwindowprivate.h"
|
||||
#include "gtknativeprivate.h"
|
||||
#include "gtkconstraint.h"
|
||||
|
||||
#include "a11y/gtkwidgetaccessible.h"
|
||||
#include "inspector/window.h"
|
||||
@@ -770,6 +771,13 @@ gtk_widget_get_type (void)
|
||||
NULL /* interface data */
|
||||
};
|
||||
|
||||
const GInterfaceInfo constraint_target_info =
|
||||
{
|
||||
(GInterfaceInitFunc) NULL,
|
||||
(GInterfaceFinalizeFunc) NULL,
|
||||
NULL /* interface data */
|
||||
};
|
||||
|
||||
widget_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, g_intern_static_string ("GtkWidget"),
|
||||
&widget_info, G_TYPE_FLAG_ABSTRACT);
|
||||
|
||||
@@ -782,6 +790,8 @@ gtk_widget_get_type (void)
|
||||
&accessibility_info) ;
|
||||
g_type_add_interface_static (widget_type, GTK_TYPE_BUILDABLE,
|
||||
&buildable_info) ;
|
||||
g_type_add_interface_static (widget_type, GTK_TYPE_CONSTRAINT_TARGET,
|
||||
&constraint_target_info) ;
|
||||
}
|
||||
|
||||
return widget_type;
|
||||
@@ -2893,6 +2903,9 @@ gtk_widget_root (GtkWidget *widget)
|
||||
|
||||
_gtk_widget_update_parent_muxer (widget);
|
||||
|
||||
if (priv->layout_manager)
|
||||
gtk_layout_manager_set_root (priv->layout_manager, priv->root);
|
||||
|
||||
GTK_WIDGET_GET_CLASS (widget)->root (widget);
|
||||
|
||||
if (!GTK_IS_ROOT (widget))
|
||||
@@ -2920,6 +2933,9 @@ gtk_widget_unroot (GtkWidget *widget)
|
||||
if (priv->context)
|
||||
gtk_style_context_set_display (priv->context, gdk_display_get_default ());
|
||||
|
||||
if (priv->layout_manager)
|
||||
gtk_layout_manager_set_root (priv->layout_manager, NULL);
|
||||
|
||||
if (g_object_get_qdata (G_OBJECT (widget), quark_pango_context))
|
||||
g_object_set_qdata (G_OBJECT (widget), quark_pango_context, NULL);
|
||||
|
||||
|
@@ -281,6 +281,8 @@ typedef struct
|
||||
GskRenderer *renderer;
|
||||
|
||||
GList *foci;
|
||||
|
||||
GtkConstraintSolver *constraint_solver;
|
||||
} GtkWindowPrivate;
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
@@ -1883,6 +1885,9 @@ gtk_window_init (GtkWindow *window)
|
||||
g_signal_connect_swapped (priv->key_controller, "key-released",
|
||||
G_CALLBACK (gtk_window_key_released), window);
|
||||
gtk_widget_add_controller (widget, priv->key_controller);
|
||||
|
||||
/* Shared constraint solver */
|
||||
priv->constraint_solver = gtk_constraint_solver_new ();
|
||||
}
|
||||
|
||||
static GtkGesture *
|
||||
@@ -2353,6 +2358,15 @@ gtk_window_native_get_renderer (GtkNative *native)
|
||||
return priv->renderer;
|
||||
}
|
||||
|
||||
static GtkConstraintSolver *
|
||||
gtk_window_root_get_constraint_solver (GtkRoot *root)
|
||||
{
|
||||
GtkWindow *self = GTK_WINDOW (root);
|
||||
GtkWindowPrivate *priv = gtk_window_get_instance_private (self);
|
||||
|
||||
return priv->constraint_solver;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_window_native_get_surface_transform (GtkNative *native,
|
||||
int *x,
|
||||
@@ -2381,6 +2395,7 @@ static void
|
||||
gtk_window_root_interface_init (GtkRootInterface *iface)
|
||||
{
|
||||
iface->get_display = gtk_window_root_get_display;
|
||||
iface->get_constraint_solver = gtk_window_root_get_constraint_solver;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -4723,6 +4738,7 @@ gtk_window_finalize (GObject *object)
|
||||
priv->mnemonics_display_timeout_id = 0;
|
||||
}
|
||||
|
||||
g_clear_object (&priv->constraint_solver);
|
||||
g_clear_object (&priv->renderer);
|
||||
|
||||
G_OBJECT_CLASS (gtk_window_parent_class)->finalize (object);
|
||||
|
@@ -37,6 +37,8 @@ gtk_private_sources = files([
|
||||
'gtkcolorpickershell.c',
|
||||
'gtkcolorscale.c',
|
||||
'gtkcolorswatch.c',
|
||||
'gtkconstraintexpression.c',
|
||||
'gtkconstraintsolver.c',
|
||||
'gtkcssanimatedstyle.c',
|
||||
'gtkcssanimation.c',
|
||||
'gtkcssarrayvalue.c',
|
||||
@@ -200,6 +202,9 @@ gtk_public_sources = files([
|
||||
'gtkcombobox.c',
|
||||
'gtkcomboboxtext.c',
|
||||
'gtkcomposetable.c',
|
||||
'gtkconstraintguide.c',
|
||||
'gtkconstraintlayout.c',
|
||||
'gtkconstraint.c',
|
||||
'gtkcontainer.c',
|
||||
'gtkcssprovider.c',
|
||||
'gtkdialog.c',
|
||||
@@ -459,6 +464,8 @@ gtk_public_headers = files([
|
||||
'gtkcolorutils.h',
|
||||
'gtkcombobox.h',
|
||||
'gtkcomboboxtext.h',
|
||||
'gtkconstraintlayout.h',
|
||||
'gtkconstraint.h',
|
||||
'gtkcontainer.h',
|
||||
'gtkcssprovider.h',
|
||||
'gtkcustomlayout.h',
|
||||
|
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
|
||||
|
||||
|
368
testsuite/gtk/constraint-solver.c
Normal file
368
testsuite/gtk/constraint-solver.c
Normal file
@@ -0,0 +1,368 @@
|
||||
#include <locale.h>
|
||||
|
||||
#include "../../gtk/gtkconstrainttypesprivate.h"
|
||||
#include "../../gtk/gtkconstraintsolverprivate.h"
|
||||
#include "../../gtk/gtkconstraintexpressionprivate.h"
|
||||
|
||||
static void
|
||||
constraint_solver_simple (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 167.0);
|
||||
GtkConstraintVariable *y = gtk_constraint_solver_create_variable (solver, NULL, "y", 2.0);
|
||||
|
||||
GtkConstraintExpression *e = gtk_constraint_expression_new_from_variable (y);
|
||||
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
x, GTK_CONSTRAINT_RELATION_EQ, e,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
double x_value = gtk_constraint_variable_get_value (x);
|
||||
double y_value = gtk_constraint_variable_get_value (y);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (x_value, y_value, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (x_value, 0.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (y_value, 0.0, 0.001);
|
||||
|
||||
gtk_constraint_variable_unref (y);
|
||||
gtk_constraint_variable_unref (x);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_stay (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 5.0);
|
||||
GtkConstraintVariable *y = gtk_constraint_solver_create_variable (solver, NULL, "y", 10.0);
|
||||
|
||||
gtk_constraint_solver_add_stay_variable (solver, x, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
gtk_constraint_solver_add_stay_variable (solver, y, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
|
||||
double x_value = gtk_constraint_variable_get_value (x);
|
||||
double y_value = gtk_constraint_variable_get_value (y);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (x_value, 5.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (y_value, 10.0, 0.001);
|
||||
|
||||
gtk_constraint_variable_unref (x);
|
||||
gtk_constraint_variable_unref (y);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_variable_geq_constant (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 10.0);
|
||||
GtkConstraintExpression *e = gtk_constraint_expression_new (100.0);
|
||||
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
x, GTK_CONSTRAINT_RELATION_GE, e,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
double x_value = gtk_constraint_variable_get_value (x);
|
||||
|
||||
g_assert_cmpfloat (x_value, >=, 100.0);
|
||||
|
||||
gtk_constraint_variable_unref (x);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_variable_leq_constant (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 100.0);
|
||||
GtkConstraintExpression *e = gtk_constraint_expression_new (10.0);
|
||||
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
x, GTK_CONSTRAINT_RELATION_LE, e,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
double x_value = gtk_constraint_variable_get_value (x);
|
||||
|
||||
g_assert_cmpfloat (x_value, <=, 10.0);
|
||||
|
||||
gtk_constraint_variable_unref (x);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_variable_eq_constant (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 10.0);
|
||||
GtkConstraintExpression *e = gtk_constraint_expression_new (100.0);
|
||||
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
x, GTK_CONSTRAINT_RELATION_EQ, e,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
double x_value = gtk_constraint_variable_get_value (x);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (x_value, 100.0, 0.001);
|
||||
|
||||
gtk_constraint_variable_unref (x);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_eq_with_stay (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 10.0);
|
||||
GtkConstraintVariable *width = gtk_constraint_solver_create_variable (solver, NULL, "width", 10.0);
|
||||
GtkConstraintVariable *right_min = gtk_constraint_solver_create_variable (solver, NULL, "rightMin", 100.0);
|
||||
|
||||
GtkConstraintExpressionBuilder builder;
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, x);
|
||||
gtk_constraint_expression_builder_plus (&builder);
|
||||
gtk_constraint_expression_builder_term (&builder, width);
|
||||
GtkConstraintExpression *right = gtk_constraint_expression_builder_finish (&builder);
|
||||
|
||||
gtk_constraint_solver_add_stay_variable (solver, width, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
gtk_constraint_solver_add_stay_variable (solver, right_min, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
right_min, GTK_CONSTRAINT_RELATION_EQ, right,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
double x_value = gtk_constraint_variable_get_value (x);
|
||||
double width_value = gtk_constraint_variable_get_value (width);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (x_value, 90.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (width_value, 10.0, 0.001);
|
||||
|
||||
gtk_constraint_variable_unref (right_min);
|
||||
gtk_constraint_variable_unref (width);
|
||||
gtk_constraint_variable_unref (x);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_cassowary (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *x = gtk_constraint_solver_create_variable (solver, NULL, "x", 0.0);
|
||||
GtkConstraintVariable *y = gtk_constraint_solver_create_variable (solver, NULL, "y", 0.0);
|
||||
|
||||
GtkConstraintExpression *e;
|
||||
|
||||
e = gtk_constraint_expression_new_from_variable (y);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
x, GTK_CONSTRAINT_RELATION_LE, e,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
e = gtk_constraint_expression_plus_constant (gtk_constraint_expression_new_from_variable (x), 3.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
y, GTK_CONSTRAINT_RELATION_EQ, e,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
e = gtk_constraint_expression_new (10.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
x, GTK_CONSTRAINT_RELATION_EQ, e,
|
||||
GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
|
||||
e = gtk_constraint_expression_new (10.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
y, GTK_CONSTRAINT_RELATION_EQ, e,
|
||||
GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
|
||||
double x_val = gtk_constraint_variable_get_value (x);
|
||||
double y_val = gtk_constraint_variable_get_value (y);
|
||||
|
||||
g_test_message ("x = %g, y = %g", x_val, y_val);
|
||||
|
||||
/* The system is unstable and has two possible solutions we need to test */
|
||||
g_assert_true ((G_APPROX_VALUE (x_val, 10.0, 1e-8) &&
|
||||
G_APPROX_VALUE (y_val, 13.0, 1e-8)) ||
|
||||
(G_APPROX_VALUE (x_val, 7.0, 1e-8) &&
|
||||
G_APPROX_VALUE (y_val, 10.0, 1e-8)));
|
||||
|
||||
gtk_constraint_variable_unref (x);
|
||||
gtk_constraint_variable_unref (y);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_edit_var_required (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *a = gtk_constraint_solver_create_variable (solver, NULL, "a", 0.0);
|
||||
gtk_constraint_solver_add_stay_variable (solver, a, GTK_CONSTRAINT_WEIGHT_STRONG);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 0.0, 0.001);
|
||||
|
||||
gtk_constraint_solver_add_edit_variable (solver, a, GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_begin_edit (solver);
|
||||
gtk_constraint_solver_suggest_value (solver, a, 2.0);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 2.0, 0.001);
|
||||
|
||||
gtk_constraint_solver_suggest_value (solver, a, 10.0);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 10.0, 0.001);
|
||||
|
||||
gtk_constraint_solver_end_edit (solver);
|
||||
|
||||
gtk_constraint_variable_unref (a);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_edit_var_suggest (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *a = gtk_constraint_solver_create_variable (solver, NULL, "a", 0.0);
|
||||
GtkConstraintVariable *b = gtk_constraint_solver_create_variable (solver, NULL, "b", 0.0);
|
||||
|
||||
gtk_constraint_solver_add_stay_variable (solver, a, GTK_CONSTRAINT_WEIGHT_STRONG);
|
||||
|
||||
GtkConstraintExpression *e = gtk_constraint_expression_new_from_variable (b);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
a, GTK_CONSTRAINT_RELATION_EQ, e,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (a), 0.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (b), 0.0, 0.001);
|
||||
|
||||
gtk_constraint_solver_add_edit_variable (solver, a, GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
gtk_constraint_solver_begin_edit (solver);
|
||||
|
||||
gtk_constraint_solver_suggest_value (solver, a, 2.0);
|
||||
gtk_constraint_solver_resolve (solver);
|
||||
|
||||
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_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_variable_unref (a);
|
||||
gtk_constraint_variable_unref (b);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
static void
|
||||
constraint_solver_paper (void)
|
||||
{
|
||||
GtkConstraintSolver *solver = gtk_constraint_solver_new ();
|
||||
|
||||
GtkConstraintVariable *left = gtk_constraint_solver_create_variable (solver, NULL, "left", 0.0);
|
||||
GtkConstraintVariable *middle = gtk_constraint_solver_create_variable (solver, NULL, "middle", 0.0);
|
||||
GtkConstraintVariable *right = gtk_constraint_solver_create_variable (solver, NULL, "right", 0.0);
|
||||
|
||||
GtkConstraintExpressionBuilder builder;
|
||||
GtkConstraintExpression *expr;
|
||||
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, left);
|
||||
gtk_constraint_expression_builder_plus (&builder);
|
||||
gtk_constraint_expression_builder_term (&builder, right);
|
||||
gtk_constraint_expression_builder_divide_by (&builder);
|
||||
gtk_constraint_expression_builder_constant (&builder, 2.0);
|
||||
expr = gtk_constraint_expression_builder_finish (&builder);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
middle, GTK_CONSTRAINT_RELATION_EQ, expr,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
gtk_constraint_expression_builder_init (&builder, solver);
|
||||
gtk_constraint_expression_builder_term (&builder, left);
|
||||
gtk_constraint_expression_builder_plus (&builder);
|
||||
gtk_constraint_expression_builder_constant (&builder, 10.0);
|
||||
expr = gtk_constraint_expression_builder_finish (&builder);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
right, GTK_CONSTRAINT_RELATION_EQ, expr,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
expr = gtk_constraint_expression_new (100.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
right, GTK_CONSTRAINT_RELATION_LE, expr,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
expr = gtk_constraint_expression_new (0.0);
|
||||
gtk_constraint_solver_add_constraint (solver,
|
||||
left, GTK_CONSTRAINT_RELATION_GE, expr,
|
||||
GTK_CONSTRAINT_WEIGHT_REQUIRED);
|
||||
|
||||
g_test_message ("Check constraints hold");
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (middle),
|
||||
(gtk_constraint_variable_get_value (left) + gtk_constraint_variable_get_value (right)) / 2.0,
|
||||
0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (right),
|
||||
gtk_constraint_variable_get_value (left) + 10.0,
|
||||
0.001);
|
||||
g_assert_cmpfloat (gtk_constraint_variable_get_value (right), <=, 100.0);
|
||||
g_assert_cmpfloat (gtk_constraint_variable_get_value (left), >=, 0.0);
|
||||
|
||||
gtk_constraint_variable_set_value (middle, 45.0);
|
||||
gtk_constraint_solver_add_stay_variable (solver, middle, GTK_CONSTRAINT_WEIGHT_WEAK);
|
||||
|
||||
g_test_message ("Check constraints hold after setting middle");
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (middle),
|
||||
(gtk_constraint_variable_get_value (left) + gtk_constraint_variable_get_value (right)) / 2.0,
|
||||
0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (right),
|
||||
gtk_constraint_variable_get_value (left) + 10.0,
|
||||
0.001);
|
||||
g_assert_cmpfloat (gtk_constraint_variable_get_value (right), <=, 100.0);
|
||||
g_assert_cmpfloat (gtk_constraint_variable_get_value (left), >=, 0.0);
|
||||
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (left), 40.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (middle), 45.0, 0.001);
|
||||
g_assert_cmpfloat_with_epsilon (gtk_constraint_variable_get_value (right), 50.0, 0.001);
|
||||
|
||||
gtk_constraint_variable_unref (left);
|
||||
gtk_constraint_variable_unref (middle);
|
||||
gtk_constraint_variable_unref (right);
|
||||
|
||||
g_object_unref (solver);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
setlocale (LC_ALL, "C");
|
||||
|
||||
g_test_add_func ("/constraint-solver/paper", constraint_solver_paper);
|
||||
g_test_add_func ("/constraint-solver/simple", constraint_solver_simple);
|
||||
g_test_add_func ("/constraint-solver/constant/eq", constraint_solver_variable_eq_constant);
|
||||
g_test_add_func ("/constraint-solver/constant/ge", constraint_solver_variable_geq_constant);
|
||||
g_test_add_func ("/constraint-solver/constant/le", constraint_solver_variable_leq_constant);
|
||||
g_test_add_func ("/constraint-solver/stay/simple", constraint_solver_stay);
|
||||
g_test_add_func ("/constraint-solver/stay/eq", constraint_solver_eq_with_stay);
|
||||
g_test_add_func ("/constraint-solver/cassowary", constraint_solver_cassowary);
|
||||
g_test_add_func ("/constraint-solver/edit/required", constraint_solver_edit_var_required);
|
||||
g_test_add_func ("/constraint-solver/edit/suggest", constraint_solver_edit_var_suggest);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
@@ -17,6 +17,11 @@ tests = [
|
||||
['builderparser'],
|
||||
['cellarea'],
|
||||
['check-icon-names'],
|
||||
['constraint-solver', [
|
||||
'../../gtk/gtkconstraintsolver.c',
|
||||
'../../gtk/gtkconstraintexpression.c',
|
||||
], ['-DGTK_COMPILATION', '-UG_ENABLE_DEBUG']
|
||||
],
|
||||
['cssprovider'],
|
||||
['rbtree-crash', ['../../gtk/gtkrbtree.c'], ['-DGTK_COMPILATION', '-UG_ENABLE_DEBUG']],
|
||||
['defaultvalue'],
|
||||
|
Reference in New Issue
Block a user