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
14 G_DECLARE_FINAL_TYPE (VflGrid, vfl_grid, VFL, GRID, GtkWidget)
15
16 struct _VflGrid
17 {
18 GtkWidget parent_instance;
19
20 GtkWidget *button1, *button2;
21 GtkWidget *button3;
22 };
23
G_DEFINE_TYPE(VflGrid,vfl_grid,GTK_TYPE_WIDGET)24 G_DEFINE_TYPE (VflGrid, vfl_grid, GTK_TYPE_WIDGET)
25
26 static void
27 vfl_grid_dispose (GObject *object)
28 {
29 VflGrid *self = VFL_GRID (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
38 static void
vfl_grid_class_init(VflGridClass * klass)39 vfl_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 */
83 static void
build_constraints(VflGrid * self,GtkConstraintLayout * manager)84 build_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 (manager, vfl, G_N_ELEMENTS (vfl),
96 8, 8,
97 &error,
98 "button1", self->button1,
99 "button2", self->button2,
100 "button3", self->button3,
101 NULL);
102 if (error != NULL)
103 {
104 g_printerr ("VFL parsing error:\n%s", error->message);
105 g_error_free (error);
106 }
107 }
108
109 static void
vfl_grid_init(VflGrid * self)110 vfl_grid_init (VflGrid *self)
111 {
112 GtkWidget *widget = GTK_WIDGET (self);
113
114 self->button1 = gtk_button_new_with_label ("Child 1");
115 gtk_widget_set_parent (self->button1, widget);
116 gtk_widget_set_name (self->button1, "button1");
117
118 self->button2 = gtk_button_new_with_label ("Child 2");
119 gtk_widget_set_parent (self->button2, widget);
120 gtk_widget_set_name (self->button2, "button2");
121
122 self->button3 = gtk_button_new_with_label ("Child 3");
123 gtk_widget_set_parent (self->button3, widget);
124 gtk_widget_set_name (self->button3, "button3");
125
126 GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
127 build_constraints (self, GTK_CONSTRAINT_LAYOUT (manager));
128 }
129
130 GtkWidget *
do_constraints_vfl(GtkWidget * do_widget)131 do_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), gtk_widget_get_display (do_widget));
141 gtk_window_set_title (GTK_WINDOW (window), "Constraints — VFL");
142 gtk_window_set_default_size (GTK_WINDOW (window), 260, -1);
143 g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
144
145 box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
146 gtk_window_set_child (GTK_WINDOW (window), box);
147
148 grid = g_object_new (vfl_grid_get_type (), NULL);
149 gtk_widget_set_hexpand (grid, TRUE);
150 gtk_widget_set_vexpand (grid, TRUE);
151 gtk_box_append (GTK_BOX (box), grid);
152 }
153
154 if (!gtk_widget_get_visible (window))
155 gtk_widget_show (window);
156 else
157 gtk_window_destroy (GTK_WINDOW (window));
158
159 return window;
160 }
161