1/* Constraints/VFL
2 *
3 * GtkConstraintLayout allows defining constraints using a
4 * compact syntax called Visual Format Language, or VFL.
5 *
6 * A typical example of a VFL specification looks like this:
7 *
8 * H:|-[button1(==button2)]-12-[button2]-|
9 */
10
11#include <glib/gi18n.h>
12#include <gtk/gtk.h>
13
14G_DECLARE_FINAL_TYPE (VflGrid, vfl_grid, VFL, GRID, GtkWidget)
15
16struct _VflGrid
17{
18 GtkWidget parent_instance;
19
20 GtkWidget *button1, *button2;
21 GtkWidget *button3;
22};
23
24G_DEFINE_TYPE (VflGrid, vfl_grid, GTK_TYPE_WIDGET)
25
26static void
27vfl_grid_dispose (GObject *object)
28{
29 VflGrid *self = VFL_GRID (ptr: object);
30
31 g_clear_pointer (&self->button1, gtk_widget_unparent);
32 g_clear_pointer (&self->button2, gtk_widget_unparent);
33 g_clear_pointer (&self->button3, gtk_widget_unparent);
34
35 G_OBJECT_CLASS (vfl_grid_parent_class)->dispose (object);
36}
37
38static void
39vfl_grid_class_init (VflGridClass *klass)
40{
41 GObjectClass *object_class = G_OBJECT_CLASS (klass);
42 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
43
44 object_class->dispose = vfl_grid_dispose;
45
46 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
47}
48
49/* Layout:
50 *
51 * +-----------------------------+
52 * | +-----------+ +-----------+ |
53 * | | Child 1 | | Child 2 | |
54 * | +-----------+ +-----------+ |
55 * | +-------------------------+ |
56 * | | Child 3 | |
57 * | +-------------------------+ |
58 * +-----------------------------+
59 *
60 * Constraints:
61 *
62 * super.start = child1.start - 8
63 * child1.width = child2.width
64 * child1.end = child2.start - 12
65 * child2.end = super.end - 8
66 * super.start = child3.start - 8
67 * child3.end = super.end - 8
68 * super.top = child1.top - 8
69 * super.top = child2.top - 8
70 * child1.bottom = child3.top - 12
71 * child2.bottom = child3.top - 12
72 * child3.height = child1.height
73 * child3.height = child2.height
74 * child3.bottom = super.bottom - 8
75 *
76 * Visual format:
77 *
78 * H:|-8-[view1(==view2)-12-[view2]-8-|
79 * H:|-8-[view3]-8-|
80 * V:|-8-[view1]-12-[view3(==view1)]-8-|
81 * V:|-8-[view2]-12-[view3(==view2)]-8-|
82 */
83static void
84build_constraints (VflGrid *self,
85 GtkConstraintLayout *manager)
86{
87 const char * const vfl[] = {
88 "H:|-[button1(==button2)]-12-[button2]-|",
89 "H:|-[button3]-|",
90 "V:|-[button1]-12-[button3(==button1)]-|",
91 "V:|-[button2]-12-[button3(==button2)]-|",
92 };
93 GError *error = NULL;
94
95 gtk_constraint_layout_add_constraints_from_description (layout: manager, lines: vfl, G_N_ELEMENTS (vfl),
96 hspacing: 8, vspacing: 8,
97 error: &error,
98 first_view: "button1", self->button1,
99 "button2", self->button2,
100 "button3", self->button3,
101 NULL);
102 if (error != NULL)
103 {
104 g_printerr (format: "VFL parsing error:\n%s", error->message);
105 g_error_free (error);
106 }
107}
108
109static void
110vfl_grid_init (VflGrid *self)
111{
112 GtkWidget *widget = GTK_WIDGET (self);
113
114 self->button1 = gtk_button_new_with_label (label: "Child 1");
115 gtk_widget_set_parent (widget: self->button1, parent: widget);
116 gtk_widget_set_name (widget: self->button1, name: "button1");
117
118 self->button2 = gtk_button_new_with_label (label: "Child 2");
119 gtk_widget_set_parent (widget: self->button2, parent: widget);
120 gtk_widget_set_name (widget: self->button2, name: "button2");
121
122 self->button3 = gtk_button_new_with_label (label: "Child 3");
123 gtk_widget_set_parent (widget: self->button3, parent: widget);
124 gtk_widget_set_name (widget: self->button3, name: "button3");
125
126 GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
127 build_constraints (self, manager: GTK_CONSTRAINT_LAYOUT (ptr: manager));
128}
129
130GtkWidget *
131do_constraints_vfl (GtkWidget *do_widget)
132{
133 static GtkWidget *window;
134
135 if (!window)
136 {
137 GtkWidget *box, *grid;
138
139 window = gtk_window_new ();
140 gtk_window_set_display (GTK_WINDOW (window), display: gtk_widget_get_display (widget: do_widget));
141 gtk_window_set_title (GTK_WINDOW (window), title: "Constraints — VFL");
142 gtk_window_set_default_size (GTK_WINDOW (window), width: 260, height: -1);
143 g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window);
144
145 box = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 12);
146 gtk_window_set_child (GTK_WINDOW (window), child: box);
147
148 grid = g_object_new (object_type: vfl_grid_get_type (), NULL);
149 gtk_widget_set_hexpand (widget: grid, TRUE);
150 gtk_widget_set_vexpand (widget: grid, TRUE);
151 gtk_box_append (GTK_BOX (box), child: grid);
152 }
153
154 if (!gtk_widget_get_visible (widget: window))
155 gtk_widget_show (widget: window);
156 else
157 gtk_window_destroy (GTK_WINDOW (window));
158
159 return window;
160}
161

source code of gtk/demos/gtk-demo/constraints_vfl.c