1#include <gtk/gtk.h>
2
3#define TEST_TYPE_OBJECT (test_object_get_type ())
4G_DECLARE_FINAL_TYPE (TestObject, test_object, TEST, OBJECT, GObject)
5
6struct _TestObject {
7 GObject parent_instance;
8 char *string;
9 guint number;
10 gboolean allow_children;
11};
12
13enum {
14 PROP_STRING = 1,
15 PROP_NUMBER,
16 PROP_ALLOW_CHILDREN,
17 PROP_NUM_PROPERTIES
18};
19
20G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT);
21
22static void
23test_object_init (TestObject *obj)
24{
25}
26
27static void
28test_object_finalize (GObject *object)
29{
30 TestObject *obj = TEST_OBJECT (ptr: object);
31
32 g_free (mem: obj->string);
33
34 G_OBJECT_CLASS (test_object_parent_class)->finalize (object);
35}
36
37static void
38test_object_set_property (GObject *object,
39 guint property_id,
40 const GValue *value,
41 GParamSpec *pspec)
42{
43 TestObject *obj = TEST_OBJECT (ptr: object);
44
45 switch (property_id)
46 {
47 case PROP_STRING:
48 g_free (mem: obj->string);
49 obj->string = g_value_dup_string (value);
50 break;
51
52 case PROP_NUMBER:
53 obj->number = g_value_get_uint (value);
54 break;
55
56 case PROP_ALLOW_CHILDREN:
57 obj->allow_children = g_value_get_boolean (value);
58 break;
59
60 default:
61 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
62 break;
63 }
64}
65
66static void
67test_object_get_property (GObject *object,
68 guint property_id,
69 GValue *value,
70 GParamSpec *pspec)
71{
72 TestObject *obj = TEST_OBJECT (ptr: object);
73
74 switch (property_id)
75 {
76 case PROP_STRING:
77 g_value_set_string (value, v_string: obj->string);
78 break;
79
80 case PROP_NUMBER:
81 g_value_set_uint (value, v_uint: obj->number);
82 break;
83
84 case PROP_ALLOW_CHILDREN:
85 g_value_set_boolean (value, v_boolean: obj->allow_children);
86 break;
87
88 default:
89 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
90 break;
91 }
92}
93
94static void
95test_object_class_init (TestObjectClass *class)
96{
97 GObjectClass *object_class = G_OBJECT_CLASS (class);
98
99 object_class->finalize = test_object_finalize;
100 object_class->set_property = test_object_set_property;
101 object_class->get_property = test_object_get_property;
102
103 g_object_class_install_property (oclass: object_class, property_id: PROP_STRING,
104 pspec: g_param_spec_string (name: "string", nick: "String", blurb: "String",
105 NULL,
106 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
107
108 g_object_class_install_property (oclass: object_class, property_id: PROP_NUMBER,
109 pspec: g_param_spec_uint (name: "number", nick: "Number", blurb: "Number",
110 minimum: 0, G_MAXUINT, default_value: 0,
111 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
112
113 g_object_class_install_property (oclass: object_class, property_id: PROP_ALLOW_CHILDREN,
114 pspec: g_param_spec_boolean (name: "allow-children", nick: "Allow children", blurb: "Allow children",
115 FALSE,
116 flags: G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
117}
118
119static TestObject *
120test_object_new (const char *string,
121 guint number,
122 gboolean allow_children)
123{
124 return g_object_new (TEST_TYPE_OBJECT,
125 first_property_name: "string", string,
126 "number", number,
127 "allow-children", allow_children,
128 NULL);
129}
130
131static const char *
132test_object_get_string (TestObject *obj)
133{
134 return obj->string;
135}
136
137static guint
138test_object_get_number (TestObject *obj)
139{
140 return obj->number;
141}
142
143static gboolean
144test_object_get_allow_children (TestObject *obj)
145{
146 return obj->allow_children;
147}
148
149/* * * */
150
151static GListModel *
152create_model (guint base,
153 guint n,
154 guint increment,
155 gboolean allow_children)
156{
157 GListStore *store;
158 guint i;
159
160 store = g_list_store_new (TEST_TYPE_OBJECT);
161 for (i = 0; i < n; i++)
162 {
163 char *string;
164 guint number;
165 TestObject *obj;
166
167 number = base + i * increment;
168 string = g_strdup_printf (format: "%u", number);
169 obj = test_object_new (string, number, allow_children);
170 g_list_store_append (store, item: obj);
171 g_object_unref (object: obj);
172 g_free (mem: string);
173 }
174
175 return G_LIST_MODEL (ptr: store);
176}
177
178static GListModel *
179create_child_model (gpointer item,
180 gpointer user_data)
181{
182 guint size = GPOINTER_TO_UINT (user_data);
183 guint base = test_object_get_number (obj: TEST_OBJECT (ptr: item));
184
185 if (test_object_get_allow_children (obj: TEST_OBJECT (ptr: item)))
186 return create_model (base, n: size, increment: 1, FALSE);
187 else
188 return NULL;
189}
190
191static GListModel *
192create_tree_model (guint n, guint m)
193{
194 return G_LIST_MODEL (ptr: gtk_tree_list_model_new (root: create_model (base: 0, n, increment: m, TRUE),
195 FALSE,
196 FALSE,
197 create_func: create_child_model,
198 GUINT_TO_POINTER (m), NULL));
199}
200
201static void
202setup_item (GtkSignalListItemFactory *factory,
203 GtkListItem *item)
204{
205 GtkWidget *entry;
206
207 entry = gtk_editable_label_new (str: "");
208 gtk_editable_set_width_chars (GTK_EDITABLE (entry), n_chars: 3);
209 gtk_list_item_set_child (self: item, child: entry);
210}
211
212static void
213text_changed (GObject *object,
214 GParamSpec *pspec,
215 gpointer data)
216{
217 const char *text;
218
219 text = gtk_editable_get_text (GTK_EDITABLE (object));
220g_print (format: "text changed to '%s'\n", text);
221 g_object_set (object: data, first_property_name: "string", text, NULL);
222}
223
224static void
225bind_item (GtkSignalListItemFactory *factory,
226 GtkListItem *item)
227{
228 TestObject *obj;
229 GtkWidget *entry;
230
231 obj = gtk_list_item_get_item (self: item);
232 entry = gtk_list_item_get_child (self: item);
233 gtk_editable_set_text (GTK_EDITABLE (entry), text: test_object_get_string (obj));
234 g_signal_connect (entry, "notify::text", G_CALLBACK (text_changed), obj);
235}
236
237static void
238unbind_item (GtkSignalListItemFactory *factory,
239 GtkListItem *item)
240{
241 TestObject *obj;
242 GtkWidget *entry;
243
244 obj = gtk_list_item_get_item (self: item);
245 entry = gtk_list_item_get_child (self: item);
246 g_signal_handlers_disconnect_by_func (entry, text_changed, obj);
247}
248
249static void
250setup_tree_item (GtkSignalListItemFactory *factory,
251 GtkListItem *item)
252{
253 GtkWidget *expander;
254 GtkWidget *entry;
255
256 entry = gtk_editable_label_new (str: "");
257 gtk_editable_set_width_chars (GTK_EDITABLE (entry), n_chars: 3);
258 expander = gtk_tree_expander_new ();
259 gtk_tree_expander_set_child (self: GTK_TREE_EXPANDER (ptr: expander), child: entry);
260 gtk_list_item_set_child (self: item, child: expander);
261}
262
263static void
264bind_tree_item (GtkSignalListItemFactory *factory,
265 GtkListItem *item)
266{
267 GtkTreeListRow *row;
268 GtkTreeExpander *expander;
269 TestObject *obj;
270 GtkWidget *entry;
271
272 row = gtk_list_item_get_item (self: item);
273 expander = GTK_TREE_EXPANDER (ptr: gtk_list_item_get_child (self: item));
274 gtk_tree_expander_set_list_row (self: expander, list_row: row);
275 obj = gtk_tree_list_row_get_item (self: row);
276 entry = gtk_tree_expander_get_child (self: expander);
277 gtk_editable_set_text (GTK_EDITABLE (entry), text: test_object_get_string (obj));
278
279 g_signal_connect (entry, "notify::text", G_CALLBACK (text_changed), obj);
280}
281
282static void
283unbind_tree_item (GtkSignalListItemFactory *factory,
284 GtkListItem *item)
285{
286 GtkTreeListRow *row;
287 GtkTreeExpander *expander;
288 TestObject *obj;
289 GtkWidget *entry;
290
291 row = gtk_list_item_get_item (self: item);
292 expander = GTK_TREE_EXPANDER (ptr: gtk_list_item_get_child (self: item));
293 obj = gtk_tree_list_row_get_item (self: row);
294 entry = gtk_tree_expander_get_child (self: expander);
295 g_signal_handlers_disconnect_by_func (entry, text_changed, obj);
296}
297
298int
299main (int argc, char *argv[])
300{
301 GtkWidget *window;
302 GtkWidget *box;
303 GtkWidget *label;
304 GtkWidget *box2;
305 GtkWidget *stack;
306 GtkWidget *switcher;
307 GtkWidget *sw;
308 GtkWidget *grid;
309 GtkWidget *list;
310 GtkWidget *cv;
311 GListModel *model;
312 GtkListItemFactory *factory;
313
314 gtk_init ();
315
316 window = gtk_window_new ();
317 gtk_window_set_default_size (GTK_WINDOW (window), width: 600, height: 400);
318
319 box2 = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 10);
320 gtk_window_set_child (GTK_WINDOW (window), child: box2);
321
322 switcher = gtk_stack_switcher_new ();
323 gtk_widget_set_halign (GTK_WIDGET (switcher), align: GTK_ALIGN_CENTER);
324 gtk_widget_set_margin_top (GTK_WIDGET (switcher), margin: 10);
325 gtk_widget_set_margin_bottom (GTK_WIDGET (switcher), margin: 10);
326 gtk_box_append (GTK_BOX (box2), child: switcher);
327
328 box = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 10);
329 gtk_box_set_homogeneous (GTK_BOX (box), TRUE);
330 gtk_box_append (GTK_BOX (box2), child: box);
331
332 label = gtk_editable_label_new (str: "Drag me");
333 gtk_box_append (GTK_BOX (box), child: label);
334
335 stack = gtk_stack_new ();
336 gtk_widget_set_vexpand (widget: stack, TRUE);
337 gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), GTK_STACK (stack));
338 gtk_box_append (GTK_BOX (box), child: stack);
339
340 /* grid */
341 sw = gtk_scrolled_window_new ();
342 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
343 gtk_stack_add_titled (GTK_STACK (stack), child: sw, name: "grid", title: "GtkGridView");
344
345 model = create_model (base: 0, n: 400, increment: 1, FALSE);
346 factory = gtk_signal_list_item_factory_new ();
347 g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
348 g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
349 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_item), NULL);
350
351 grid = gtk_grid_view_new (model: GTK_SELECTION_MODEL (ptr: gtk_single_selection_new (model)), factory);
352 gtk_grid_view_set_min_columns (GTK_GRID_VIEW (grid), min_columns: 20);
353 gtk_grid_view_set_max_columns (GTK_GRID_VIEW (grid), max_columns: 20);
354
355 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: grid);
356
357 /* list */
358 sw = gtk_scrolled_window_new ();
359 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
360 gtk_stack_add_titled (GTK_STACK (stack), child: sw, name: "list", title: "GtkListView");
361
362 list = gtk_list_view_new (model: GTK_SELECTION_MODEL (ptr: gtk_single_selection_new (model: create_model (base: 0, n: 400, increment: 1, FALSE))), NULL);
363 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: list);
364
365 factory = gtk_signal_list_item_factory_new ();
366 g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
367 g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
368 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_item), NULL);
369
370 gtk_list_view_set_factory (GTK_LIST_VIEW (list), factory);
371 g_object_unref (object: factory);
372
373 /* columnview */
374 sw = gtk_scrolled_window_new ();
375 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
376 gtk_stack_add_titled (GTK_STACK (stack), child: sw, name: "column", title: "GtkColumnView");
377
378 cv = gtk_column_view_new (model: GTK_SELECTION_MODEL (ptr: gtk_single_selection_new (model: create_model (base: 0, n: 400, increment: 1, FALSE))));
379
380 for (guint i = 0; i < 20; i++)
381 {
382 GtkColumnViewColumn *column;
383 char *title;
384
385 factory = gtk_signal_list_item_factory_new ();
386 g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
387 g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
388 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_item), NULL);
389
390 title = g_strdup_printf (format: "Column %u", i);
391 column = gtk_column_view_column_new (title, factory);
392 gtk_column_view_append_column (GTK_COLUMN_VIEW (cv), column);
393 g_object_unref (object: column);
394 g_free (mem: title);
395 }
396
397 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: cv);
398
399 /* tree */
400 sw = gtk_scrolled_window_new ();
401 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
402 gtk_stack_add_titled (GTK_STACK (stack), child: sw, name: "tree", title: "Tree");
403
404 list = gtk_list_view_new (model: GTK_SELECTION_MODEL (ptr: gtk_single_selection_new (model: create_tree_model (n: 20, m: 20))), NULL);
405 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: list);
406
407 factory = gtk_signal_list_item_factory_new ();
408 g_signal_connect (factory, "setup", G_CALLBACK (setup_tree_item), NULL);
409 g_signal_connect (factory, "bind", G_CALLBACK (bind_tree_item), NULL);
410 g_signal_connect (factory, "unbind", G_CALLBACK (unbind_tree_item), NULL);
411
412 gtk_list_view_set_factory (GTK_LIST_VIEW (list), factory);
413 g_object_unref (object: factory);
414
415 gtk_window_present (GTK_WINDOW (window));
416
417 while (g_list_model_get_n_items (list: gtk_window_get_toplevels ()) > 0)
418 g_main_context_iteration (NULL, TRUE);
419
420 gtk_window_destroy (GTK_WINDOW (window));
421
422 return 0;
423}
424

source code of gtk/tests/testlistdnd.c