1/* Tree View/Tree Store
2 *
3 * The GtkTreeStore is used to store data in tree form, to be
4 * used later on by a GtkTreeView to display it. This demo builds
5 * a simple GtkTreeStore and displays it. If you're new to the
6 * GtkTreeView widgets and associates, look into the GtkListStore
7 * example first.
8 *
9 */
10
11#include <gtk/gtk.h>
12
13/* TreeItem structure */
14typedef struct _TreeItem TreeItem;
15struct _TreeItem
16{
17 const char *label;
18 gboolean alex;
19 gboolean havoc;
20 gboolean tim;
21 gboolean owen;
22 gboolean dave;
23 gboolean world_holiday; /* shared by the European hackers */
24 TreeItem *children;
25};
26
27/* columns */
28enum
29{
30 HOLIDAY_NAME_COLUMN = 0,
31 ALEX_COLUMN,
32 HAVOC_COLUMN,
33 TIM_COLUMN,
34 OWEN_COLUMN,
35 DAVE_COLUMN,
36
37 VISIBLE_COLUMN,
38 WORLD_COLUMN,
39 NUM_COLUMNS
40};
41
42/* tree data */
43static TreeItem january[] =
44{
45 {"New Years Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
46 {"Presidential Inauguration", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
47 {"Martin Luther King Jr. day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
48 { NULL }
49};
50
51static TreeItem february[] =
52{
53 { "Presidents' Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
54 { "Groundhog Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
55 { "Valentine's Day", FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, NULL },
56 { NULL }
57};
58
59static TreeItem march[] =
60{
61 { "National Tree Planting Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
62 { "St Patrick's Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
63 { NULL }
64};
65static TreeItem april[] =
66{
67 { "April Fools' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
68 { "Army Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
69 { "Earth Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
70 { "Administrative Professionals' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
71 { NULL }
72};
73
74static TreeItem may[] =
75{
76 { "Nurses' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
77 { "National Day of Prayer", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
78 { "Mothers' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
79 { "Armed Forces Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
80 { "Memorial Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
81 { NULL }
82};
83
84static TreeItem june[] =
85{
86 { "June Fathers' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
87 { "Juneteenth (Liberation Day)", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
88 { "Flag Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
89 { NULL }
90};
91
92static TreeItem july[] =
93{
94 { "Parents' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
95 { "Independence Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
96 { NULL }
97};
98
99static TreeItem august[] =
100{
101 { "Air Force Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
102 { "Coast Guard Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
103 { "Friendship Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
104 { NULL }
105};
106
107static TreeItem september[] =
108{
109 { "Grandparents' Day", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
110 { "Citizenship Day or Constitution Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
111 { "Labor Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
112 { NULL }
113};
114
115static TreeItem october[] =
116{
117 { "National Children's Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
118 { "Bosses' Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
119 { "Sweetest Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
120 { "Mother-in-Law's Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
121 { "Navy Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
122 { "Columbus Day", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
123 { "Halloween", FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, NULL },
124 { NULL }
125};
126
127static TreeItem november[] =
128{
129 { "Marine Corps Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
130 { "Veterans' Day", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
131 { "Thanksgiving", FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, NULL },
132 { NULL }
133};
134
135static TreeItem december[] =
136{
137 { "Pearl Harbor Remembrance Day", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
138 { "Christmas", TRUE, TRUE, TRUE, TRUE, FALSE, TRUE, NULL },
139 { "Kwanzaa", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, NULL },
140 { NULL }
141};
142
143
144static TreeItem toplevel[] =
145{
146 {"January", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, january},
147 {"February", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, february},
148 {"March", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, march},
149 {"April", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, april},
150 {"May", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, may},
151 {"June", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, june},
152 {"July", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, july},
153 {"August", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, august},
154 {"September", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, september},
155 {"October", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, october},
156 {"November", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, november},
157 {"December", FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, december},
158 {NULL}
159};
160
161
162static GtkTreeModel *
163create_model (void)
164{
165 GtkTreeStore *model;
166 GtkTreeIter iter;
167 TreeItem *month = toplevel;
168
169 /* create tree store */
170 model = gtk_tree_store_new (n_columns: NUM_COLUMNS,
171 G_TYPE_STRING,
172 G_TYPE_BOOLEAN,
173 G_TYPE_BOOLEAN,
174 G_TYPE_BOOLEAN,
175 G_TYPE_BOOLEAN,
176 G_TYPE_BOOLEAN,
177 G_TYPE_BOOLEAN,
178 G_TYPE_BOOLEAN);
179
180 /* add data to the tree store */
181 while (month->label)
182 {
183 TreeItem *holiday = month->children;
184
185 gtk_tree_store_append (tree_store: model, iter: &iter, NULL);
186 gtk_tree_store_set (tree_store: model, iter: &iter,
187 HOLIDAY_NAME_COLUMN, month->label,
188 ALEX_COLUMN, FALSE,
189 HAVOC_COLUMN, FALSE,
190 TIM_COLUMN, FALSE,
191 OWEN_COLUMN, FALSE,
192 DAVE_COLUMN, FALSE,
193 VISIBLE_COLUMN, FALSE,
194 WORLD_COLUMN, FALSE,
195 -1);
196
197 /* add children */
198 while (holiday->label)
199 {
200 GtkTreeIter child_iter;
201
202 gtk_tree_store_append (tree_store: model, iter: &child_iter, parent: &iter);
203 gtk_tree_store_set (tree_store: model, iter: &child_iter,
204 HOLIDAY_NAME_COLUMN, holiday->label,
205 ALEX_COLUMN, holiday->alex,
206 HAVOC_COLUMN, holiday->havoc,
207 TIM_COLUMN, holiday->tim,
208 OWEN_COLUMN, holiday->owen,
209 DAVE_COLUMN, holiday->dave,
210 VISIBLE_COLUMN, TRUE,
211 WORLD_COLUMN, holiday->world_holiday,
212 -1);
213
214 holiday++;
215 }
216
217 month++;
218 }
219
220 return GTK_TREE_MODEL (model);
221}
222
223static void
224item_toggled (GtkCellRendererToggle *cell,
225 char *path_str,
226 gpointer data)
227{
228 GtkTreeModel *model = (GtkTreeModel *)data;
229 GtkTreePath *path = gtk_tree_path_new_from_string (path: path_str);
230 GtkTreeIter iter;
231 gboolean toggle_item;
232
233 int *column;
234
235 column = g_object_get_data (G_OBJECT (cell), key: "column");
236
237 /* get toggled iter */
238 gtk_tree_model_get_iter (tree_model: model, iter: &iter, path);
239 gtk_tree_model_get (tree_model: model, iter: &iter, column, &toggle_item, -1);
240
241 /* do something with the value */
242 toggle_item ^= 1;
243
244 /* set new value */
245 gtk_tree_store_set (GTK_TREE_STORE (model), iter: &iter, column,
246 toggle_item, -1);
247
248 /* clean up */
249 gtk_tree_path_free (path);
250}
251
252static void
253add_columns (GtkTreeView *treeview)
254{
255 int col_offset;
256 GtkCellRenderer *renderer;
257 GtkTreeViewColumn *column;
258 GtkTreeModel *model = gtk_tree_view_get_model (tree_view: treeview);
259
260 /* column for holiday names */
261 renderer = gtk_cell_renderer_text_new ();
262 g_object_set (object: renderer, first_property_name: "xalign", 0.0, NULL);
263
264 col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
265 position: -1, title: "Holiday",
266 cell: renderer, "text",
267 HOLIDAY_NAME_COLUMN,
268 NULL);
269 column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), n: col_offset - 1);
270 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
271
272 /* alex column */
273 renderer = gtk_cell_renderer_toggle_new ();
274 g_object_set (object: renderer, first_property_name: "xalign", 0.0, NULL);
275 g_object_set_data (G_OBJECT (renderer), key: "column", data: (int *)ALEX_COLUMN);
276
277 g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
278
279 col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
280 position: -1, title: "Alex",
281 cell: renderer,
282 "active",
283 ALEX_COLUMN,
284 "visible",
285 VISIBLE_COLUMN,
286 "activatable",
287 WORLD_COLUMN, NULL);
288
289 column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), n: col_offset - 1);
290 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
291 type: GTK_TREE_VIEW_COLUMN_FIXED);
292 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
293
294 /* havoc column */
295 renderer = gtk_cell_renderer_toggle_new ();
296 g_object_set (object: renderer, first_property_name: "xalign", 0.0, NULL);
297 g_object_set_data (G_OBJECT (renderer), key: "column", data: (int *)HAVOC_COLUMN);
298
299 g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
300
301 col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
302 position: -1, title: "Havoc",
303 cell: renderer,
304 "active",
305 HAVOC_COLUMN,
306 "visible",
307 VISIBLE_COLUMN,
308 NULL);
309
310 column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), n: col_offset - 1);
311 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
312 type: GTK_TREE_VIEW_COLUMN_FIXED);
313 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
314
315 /* tim column */
316 renderer = gtk_cell_renderer_toggle_new ();
317 g_object_set (object: renderer, first_property_name: "xalign", 0.0, NULL);
318 g_object_set_data (G_OBJECT (renderer), key: "column", data: (int *)TIM_COLUMN);
319
320 g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
321
322 col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
323 position: -1, title: "Tim",
324 cell: renderer,
325 "active",
326 TIM_COLUMN,
327 "visible",
328 VISIBLE_COLUMN,
329 "activatable",
330 WORLD_COLUMN, NULL);
331
332 column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), n: col_offset - 1);
333 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
334 type: GTK_TREE_VIEW_COLUMN_FIXED);
335 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
336
337 /* owen column */
338 renderer = gtk_cell_renderer_toggle_new ();
339 g_object_set (object: renderer, first_property_name: "xalign", 0.0, NULL);
340 g_object_set_data (G_OBJECT (renderer), key: "column", data: (int *)OWEN_COLUMN);
341
342 g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
343
344 col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
345 position: -1, title: "Owen",
346 cell: renderer,
347 "active",
348 OWEN_COLUMN,
349 "visible",
350 VISIBLE_COLUMN,
351 NULL);
352
353 column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), n: col_offset - 1);
354 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
355 type: GTK_TREE_VIEW_COLUMN_FIXED);
356 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
357
358 /* dave column */
359 renderer = gtk_cell_renderer_toggle_new ();
360 g_object_set (object: renderer, first_property_name: "xalign", 0.0, NULL);
361 g_object_set_data (G_OBJECT (renderer), key: "column", data: (int *)DAVE_COLUMN);
362
363 g_signal_connect (renderer, "toggled", G_CALLBACK (item_toggled), model);
364
365 col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
366 position: -1, title: "Dave",
367 cell: renderer,
368 "active",
369 DAVE_COLUMN,
370 "visible",
371 VISIBLE_COLUMN,
372 NULL);
373
374 column = gtk_tree_view_get_column (GTK_TREE_VIEW (treeview), n: col_offset - 1);
375 gtk_tree_view_column_set_sizing (GTK_TREE_VIEW_COLUMN (column),
376 type: GTK_TREE_VIEW_COLUMN_FIXED);
377 gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE);
378}
379
380GtkWidget *
381do_tree_store (GtkWidget *do_widget)
382{
383 static GtkWidget *window = NULL;
384
385 if (!window)
386 {
387 GtkWidget *vbox;
388 GtkWidget *sw;
389 GtkWidget *treeview;
390 GtkTreeModel *model;
391
392 /* create window, etc */
393 window = gtk_window_new ();
394 gtk_window_set_display (GTK_WINDOW (window),
395 display: gtk_widget_get_display (widget: do_widget));
396 gtk_window_set_title (GTK_WINDOW (window), title: "Tree Store");
397 g_object_add_weak_pointer (G_OBJECT (window), weak_pointer_location: (gpointer *)&window);
398
399 vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 8);
400 gtk_widget_set_margin_start (widget: vbox, margin: 8);
401 gtk_widget_set_margin_end (widget: vbox, margin: 8);
402 gtk_widget_set_margin_top (widget: vbox, margin: 8);
403 gtk_widget_set_margin_bottom (widget: vbox, margin: 8);
404 gtk_window_set_child (GTK_WINDOW (window), child: vbox);
405
406 gtk_box_append (GTK_BOX (vbox),
407 child: gtk_label_new (str: "Jonathan's Holiday Card Planning Sheet"));
408
409 sw = gtk_scrolled_window_new ();
410 gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (sw), TRUE);
411 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
412 hscrollbar_policy: GTK_POLICY_AUTOMATIC,
413 vscrollbar_policy: GTK_POLICY_AUTOMATIC);
414 gtk_box_append (GTK_BOX (vbox), child: sw);
415
416 /* create model */
417 model = create_model ();
418
419 /* create tree view */
420 treeview = gtk_tree_view_new_with_model (model);
421 gtk_widget_set_vexpand (widget: treeview, TRUE);
422 g_object_unref (object: model);
423 gtk_tree_selection_set_mode (selection: gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
424 type: GTK_SELECTION_MULTIPLE);
425
426 add_columns (GTK_TREE_VIEW (treeview));
427
428 gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), child: treeview);
429
430 /* expand all rows after the treeview widget has been realized */
431 g_signal_connect (treeview, "realize",
432 G_CALLBACK (gtk_tree_view_expand_all), NULL);
433 gtk_window_set_default_size (GTK_WINDOW (window), width: 650, height: 400);
434 }
435
436 if (!gtk_widget_get_visible (widget: window))
437 gtk_widget_show (widget: window);
438 else
439 gtk_window_destroy (GTK_WINDOW (window));
440
441 return window;
442}
443

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