1 /*
2 * TilEm II
3 *
4 * Copyright (c) 2011 Benjamin Moody
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <gtk/gtk.h>
28 #include <gobject/gvaluecollector.h>
29
30 #include "fixedtreeview.h"
31
32 /* Style set on tree view; update column sizes */
ftv_style_set(GtkWidget * treeview,G_GNUC_UNUSED GtkStyle * oldstyle,G_GNUC_UNUSED gpointer data)33 static void ftv_style_set(GtkWidget *treeview,
34 G_GNUC_UNUSED GtkStyle *oldstyle,
35 G_GNUC_UNUSED gpointer data)
36 {
37 GtkTreeModel *template;
38 GtkTreeIter iter;
39 GList *cols, *cp;
40 GtkTreeViewColumn *col;
41 int width;
42
43 template = g_object_get_data(G_OBJECT(treeview), "ftv-template");
44 if (!template)
45 return;
46
47 if (!gtk_tree_model_get_iter_first(template, &iter))
48 return;
49
50 cols = gtk_tree_view_get_columns(GTK_TREE_VIEW(treeview));
51 for (cp = cols; cp; cp = cp->next) {
52 col = cp->data;
53 gtk_tree_view_column_cell_set_cell_data(col, template, &iter,
54 FALSE, FALSE);
55 gtk_tree_view_column_cell_get_size(col, NULL, NULL, NULL,
56 &width, NULL);
57 gtk_tree_view_column_set_fixed_width(col, width + 2);
58 }
59 g_list_free(cols);
60 }
61
62 /* Widget destroyed */
ftv_destroy(GtkWidget * treeview,G_GNUC_UNUSED gpointer data)63 static void ftv_destroy(GtkWidget *treeview, G_GNUC_UNUSED gpointer data)
64 {
65 GtkTreeModel *template;
66
67 template = g_object_get_data(G_OBJECT(treeview), "ftv-template");
68 if (template)
69 g_object_unref(template);
70 g_object_set_data(G_OBJECT(treeview), "ftv-template", NULL);
71 }
72
fixed_tree_view_init_with_template(GtkWidget * treeview,GtkTreeModel * template)73 void fixed_tree_view_init_with_template(GtkWidget *treeview,
74 GtkTreeModel *template)
75 {
76 GtkTreeModel *oldtemplate;
77
78 if (template)
79 g_object_ref_sink(template);
80
81 oldtemplate = g_object_get_data(G_OBJECT(treeview), "ftv-template");
82 if (oldtemplate) {
83 g_object_unref(oldtemplate);
84 }
85 else {
86 g_signal_connect(treeview, "style-set",
87 G_CALLBACK(ftv_style_set), NULL);
88 g_signal_connect(treeview, "destroy",
89 G_CALLBACK(ftv_destroy), NULL);
90 }
91 g_object_set_data(G_OBJECT(treeview), "ftv-template", template);
92
93 if (template && GTK_WIDGET_REALIZED(treeview))
94 ftv_style_set(treeview, NULL, NULL);
95 }
96
fixed_tree_view_init(GtkWidget * treeview,int colgroupsize,...)97 void fixed_tree_view_init(GtkWidget *treeview, int colgroupsize, ...)
98 {
99 GtkTreeModel *real_model;
100 int ncols, i, col;
101 GType *types;
102 GtkListStore *store;
103 GtkTreeIter iter;
104 GValue value;
105 gchar *error = NULL;
106 va_list ap;
107
108 g_return_if_fail(GTK_IS_TREE_VIEW(treeview));
109 g_return_if_fail(colgroupsize >= 0);
110
111 real_model = gtk_tree_view_get_model(GTK_TREE_VIEW(treeview));
112 g_return_if_fail(real_model != NULL);
113
114 ncols = gtk_tree_model_get_n_columns(real_model);
115 g_return_if_fail(ncols > 0);
116
117 if (colgroupsize == 0)
118 colgroupsize = ncols;
119
120 g_return_if_fail(ncols % colgroupsize == 0);
121
122 types = g_new(GType, ncols);
123 for (i = 0; i < ncols; i++) {
124 types[i] = gtk_tree_model_get_column_type(real_model, i);
125 if (i > colgroupsize)
126 g_return_if_fail(types[i] == types[i - colgroupsize]);
127 }
128 store = gtk_list_store_newv(ncols, types);
129
130 va_start(ap, colgroupsize);
131 gtk_list_store_append(store, &iter);
132
133 memset(&value, 0, sizeof(value));
134
135 col = va_arg(ap, int);
136 while (col != -1) {
137 if (col < 0 || col >= colgroupsize) {
138 g_critical("missing sentinel");
139 break;
140 }
141
142 g_value_init(&value, types[col]);
143
144 G_VALUE_COLLECT(&value, ap, 0, &error);
145
146 if (error) {
147 g_critical("%s", error);
148 g_free(error);
149 break;
150 }
151
152 for (i = col; i < ncols; i += colgroupsize)
153 gtk_list_store_set_value(store, &iter, i, &value);
154
155 g_value_unset(&value);
156
157 col = va_arg(ap, int);
158 }
159
160 va_end(ap);
161
162 g_free(types);
163
164 fixed_tree_view_init_with_template(treeview, GTK_TREE_MODEL(store));
165 }
166