1/* Constraints/Interactive Constraints
2 * #Keywords: GtkConstraintLayout
3 *
4 * This example shows how constraints can be updated during user interaction.
5 * The vertical edge between the buttons can be dragged with the mouse.
6 */
7
8#include <glib/gi18n.h>
9#include <gtk/gtk.h>
10
11G_DECLARE_FINAL_TYPE (InteractiveGrid, interactive_grid, INTERACTIVE, GRID, GtkWidget)
12
13struct _InteractiveGrid
14{
15 GtkWidget parent_instance;
16
17 GtkWidget *button1, *button2;
18 GtkWidget *button3;
19 GtkConstraintGuide *guide;
20 GtkConstraint *constraint;
21};
22
23G_DEFINE_TYPE (InteractiveGrid, interactive_grid, GTK_TYPE_WIDGET)
24
25static void
26interactive_grid_dispose (GObject *object)
27{
28 InteractiveGrid *self = INTERACTIVE_GRID (ptr: object);
29
30 g_clear_pointer (&self->button1, gtk_widget_unparent);
31 g_clear_pointer (&self->button2, gtk_widget_unparent);
32 g_clear_pointer (&self->button3, gtk_widget_unparent);
33
34 G_OBJECT_CLASS (interactive_grid_parent_class)->dispose (object);
35}
36
37static void
38interactive_grid_class_init (InteractiveGridClass *klass)
39{
40 GObjectClass *object_class = G_OBJECT_CLASS (klass);
41 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
42
43 object_class->dispose = interactive_grid_dispose;
44
45 gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_CONSTRAINT_LAYOUT);
46}
47
48static void
49build_constraints (InteractiveGrid *self,
50 GtkConstraintLayout *manager)
51{
52 self->guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL);
53 gtk_constraint_layout_add_guide (layout: manager, guide: self->guide);
54
55 gtk_constraint_layout_add_constraint (layout: manager,
56 constraint: gtk_constraint_new_constant (target: GTK_CONSTRAINT_TARGET (ptr: self->guide),
57 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_WIDTH,
58 relation: GTK_CONSTRAINT_RELATION_EQ,
59 constant: 0.0,
60 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
61
62 gtk_constraint_layout_add_constraint (layout: manager,
63 constraint: gtk_constraint_new (NULL,
64 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_START,
65 relation: GTK_CONSTRAINT_RELATION_EQ,
66 source: GTK_CONSTRAINT_TARGET (ptr: self->button1),
67 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_START,
68 multiplier: 1.0,
69 constant: -8.0,
70 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
71 gtk_constraint_layout_add_constraint (layout: manager,
72 constraint: gtk_constraint_new (target: GTK_CONSTRAINT_TARGET (ptr: self->button1),
73 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_END,
74 relation: GTK_CONSTRAINT_RELATION_EQ,
75 source: GTK_CONSTRAINT_TARGET (ptr: self->guide),
76 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_START,
77 multiplier: 1.0,
78 constant: 0.0,
79 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
80 gtk_constraint_layout_add_constraint (layout: manager,
81 constraint: gtk_constraint_new (target: GTK_CONSTRAINT_TARGET (ptr: self->button2),
82 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_START,
83 relation: GTK_CONSTRAINT_RELATION_EQ,
84 source: GTK_CONSTRAINT_TARGET (ptr: self->guide),
85 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_END,
86 multiplier: 1.0,
87 constant: 0.0,
88 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
89 gtk_constraint_layout_add_constraint (layout: manager,
90 constraint: gtk_constraint_new (target: GTK_CONSTRAINT_TARGET (ptr: self->button2),
91 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_END,
92 relation: GTK_CONSTRAINT_RELATION_EQ,
93 NULL,
94 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_END,
95 multiplier: 1.0,
96 constant: -8.0,
97 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
98 gtk_constraint_layout_add_constraint (layout: manager,
99 constraint: gtk_constraint_new (NULL,
100 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_START,
101 relation: GTK_CONSTRAINT_RELATION_EQ,
102 source: GTK_CONSTRAINT_TARGET (ptr: self->button3),
103 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_START,
104 multiplier: 1.0,
105 constant: -8.0,
106 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
107
108 gtk_constraint_layout_add_constraint (layout: manager,
109 constraint: gtk_constraint_new (target: GTK_CONSTRAINT_TARGET (ptr: self->button3),
110 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_END,
111 relation: GTK_CONSTRAINT_RELATION_EQ,
112 source: GTK_CONSTRAINT_TARGET (ptr: self->guide),
113 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_START,
114 multiplier: 1.0,
115 constant: 0.0,
116 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
117
118 gtk_constraint_layout_add_constraint (layout: manager,
119 constraint: gtk_constraint_new (NULL,
120 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_TOP,
121 relation: GTK_CONSTRAINT_RELATION_EQ,
122 source: GTK_CONSTRAINT_TARGET (ptr: self->button1),
123 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_TOP,
124 multiplier: 1.0,
125 constant: -8.0,
126 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
127 gtk_constraint_layout_add_constraint (layout: manager,
128 constraint: gtk_constraint_new (target: GTK_CONSTRAINT_TARGET (ptr: self->button2),
129 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_TOP,
130 relation: GTK_CONSTRAINT_RELATION_EQ,
131 source: GTK_CONSTRAINT_TARGET (ptr: self->button1),
132 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
133 multiplier: 1.0,
134 constant: 0.0,
135 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
136 gtk_constraint_layout_add_constraint (layout: manager,
137 constraint: gtk_constraint_new (target: GTK_CONSTRAINT_TARGET (ptr: self->button3),
138 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_TOP,
139 relation: GTK_CONSTRAINT_RELATION_EQ,
140 source: GTK_CONSTRAINT_TARGET (ptr: self->button2),
141 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
142 multiplier: 1.0,
143 constant: 0.0,
144 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
145 gtk_constraint_layout_add_constraint (layout: manager,
146 constraint: gtk_constraint_new (target: GTK_CONSTRAINT_TARGET (ptr: self->button3),
147 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
148 relation: GTK_CONSTRAINT_RELATION_EQ,
149 NULL,
150 source_attribute: GTK_CONSTRAINT_ATTRIBUTE_BOTTOM,
151 multiplier: 1.0,
152 constant: -8.0,
153 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED));
154}
155
156static void
157drag_cb (GtkGestureDrag *drag,
158 double offset_x,
159 double offset_y,
160 InteractiveGrid *self)
161{
162 GtkConstraintLayout *layout = GTK_CONSTRAINT_LAYOUT (ptr: gtk_widget_get_layout_manager (GTK_WIDGET (self)));
163 double x, y;
164
165 if (self->constraint)
166 {
167 gtk_constraint_layout_remove_constraint (layout, constraint: self->constraint);
168 g_clear_object (&self->constraint);
169 }
170
171 gtk_gesture_drag_get_start_point (gesture: drag, x: &x, y: &y);
172 self->constraint = gtk_constraint_new_constant (target: GTK_CONSTRAINT_TARGET (ptr: self->guide),
173 target_attribute: GTK_CONSTRAINT_ATTRIBUTE_LEFT,
174 relation: GTK_CONSTRAINT_RELATION_EQ,
175 constant: x + offset_x,
176 strength: GTK_CONSTRAINT_STRENGTH_REQUIRED);
177 gtk_constraint_layout_add_constraint (layout, g_object_ref (self->constraint));
178 gtk_widget_queue_allocate (GTK_WIDGET (self));
179}
180
181static void
182interactive_grid_init (InteractiveGrid *self)
183{
184 GtkWidget *widget = GTK_WIDGET (self);
185 GtkGesture *drag;
186
187 self->button1 = gtk_button_new_with_label (label: "Child 1");
188 gtk_widget_set_parent (widget: self->button1, parent: widget);
189 gtk_widget_set_name (widget: self->button1, name: "button1");
190
191 self->button2 = gtk_button_new_with_label (label: "Child 2");
192 gtk_widget_set_parent (widget: self->button2, parent: widget);
193 gtk_widget_set_name (widget: self->button2, name: "button2");
194
195 self->button3 = gtk_button_new_with_label (label: "Child 3");
196 gtk_widget_set_parent (widget: self->button3, parent: widget);
197 gtk_widget_set_name (widget: self->button3, name: "button3");
198
199 GtkLayoutManager *manager = gtk_widget_get_layout_manager (GTK_WIDGET (self));
200 build_constraints (self, manager: GTK_CONSTRAINT_LAYOUT (ptr: manager));
201
202 drag = gtk_gesture_drag_new ();
203 g_signal_connect (drag, "drag-update", G_CALLBACK (drag_cb), self);
204 gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (drag));
205}
206
207GtkWidget *
208do_constraints_interactive (GtkWidget *do_widget)
209{
210 static GtkWidget *window;
211
212 if (!window)
213 {
214 GtkWidget *box, *grid;
215
216 window = gtk_window_new ();
217 gtk_window_set_display (GTK_WINDOW (window), display: gtk_widget_get_display (widget: do_widget));
218 gtk_window_set_title (GTK_WINDOW (window), title: "Interactive Constraints");
219 gtk_window_set_default_size (GTK_WINDOW (window), width: 260, height: -1);
220 g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window);
221
222 box = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 12);
223 gtk_window_set_child (GTK_WINDOW (window), child: box);
224
225 grid = g_object_new (object_type: interactive_grid_get_type (), NULL);
226 gtk_widget_set_hexpand (widget: grid, TRUE);
227 gtk_widget_set_vexpand (widget: grid, TRUE);
228 gtk_box_append (GTK_BOX (box), child: grid);
229 }
230
231 if (!gtk_widget_get_visible (widget: window))
232 gtk_widget_show (widget: window);
233 else
234 gtk_window_destroy (GTK_WINDOW (window));
235
236 return window;
237}
238

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