ui/gtk/model.c

changeset 35
3e8b5c9b4033
child 40
caa0df8ed095
equal deleted inserted replaced
34:0ec8a5f17782 35:3e8b5c9b4033
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2014 Olaf Wintermann. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "model.h"
33
34 #define IS_UI_LIST_MODEL(obj) \
35 (G_TYPE_CHECK_INSTANCE_TYPE((obj), list_model_type))
36 #define UI_LIST_MODEL(obj) \
37 (G_TYPE_CHECK_INSTANCE_CAST((obj), list_model_type, UiListModel))
38
39 static void list_model_class_init(GObjectClass *cl, gpointer data);
40 static void list_model_interface_init(GtkTreeModelIface *i, gpointer data);
41 static void list_model_init(UiListModel *instance, GObjectClass *cl);
42
43 static GObjectClass list_model_class;
44 static const GTypeInfo list_model_info = {
45 sizeof(GObjectClass),
46 NULL,
47 NULL,
48 (GClassInitFunc)list_model_class_init,
49 NULL,
50 NULL,
51 sizeof(UiListModel),
52 0,
53 (GInstanceInitFunc)list_model_init
54 };
55 static const GInterfaceInfo list_model_interface_info = {
56 (GInterfaceInitFunc)list_model_interface_init,
57 NULL,
58 NULL
59 };
60 static GType list_model_type;
61
62 void ui_list_init() {
63 list_model_type = g_type_register_static(
64 G_TYPE_OBJECT,
65 "UiListModel",
66 &list_model_info,
67 (GTypeFlags)0);
68 g_type_add_interface_static(
69 list_model_type,
70 GTK_TYPE_TREE_MODEL,
71 &list_model_interface_info);
72 }
73
74 static void list_model_class_init(GObjectClass *cl, gpointer data) {
75 //cl->finalize = ...; // TODO
76 }
77
78 static void list_model_interface_init(GtkTreeModelIface *i, gpointer data) {
79 i->get_flags = ui_list_model_get_flags;
80 i->get_n_columns = ui_list_model_get_n_columns;
81 i->get_column_type = ui_list_model_get_column_type;
82 i->get_iter = ui_list_model_get_iter;
83 i->get_path = ui_list_model_get_path;
84 i->get_value = ui_list_model_get_value;
85 i->iter_next = ui_list_model_iter_next;
86 i->iter_children = ui_list_model_iter_children;
87 i->iter_has_child = ui_list_model_iter_has_child;
88 i->iter_n_children = ui_list_model_iter_n_children;
89 i->iter_nth_child = ui_list_model_iter_nth_child;
90 i->iter_parent = ui_list_model_iter_parent;
91 }
92
93 static void list_model_init(UiListModel *instance, GObjectClass *cl) {
94 instance->columntypes = NULL;
95 instance->list = NULL;
96 instance->numcolumns = 0;
97 instance->stamp = g_random_int();
98 }
99
100 UiListModel* ui_list_model_new(UiListPtr *list, ui_model_getvalue_f getvalue) {
101 UiListModel *model = g_object_new(list_model_type, NULL);
102 model->list = list;
103 model->getvalue = getvalue;
104 model->columntypes = malloc(sizeof(GType));
105 model->numcolumns = 1;
106 model->columntypes[0] = G_TYPE_STRING;
107 return model;
108 }
109
110
111 GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) {
112 return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST);
113 }
114
115 gint ui_list_model_get_n_columns(GtkTreeModel *tree_model) {
116 g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), 0);
117 UiListModel *model = UI_LIST_MODEL(tree_model);
118 return model->numcolumns;
119 }
120
121 GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index) {
122 g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), G_TYPE_INVALID);
123 UiListModel *model = UI_LIST_MODEL(tree_model);
124 g_return_val_if_fail(index < model->numcolumns, G_TYPE_INVALID);
125 return model->columntypes[index];
126 }
127
128 gboolean ui_list_model_get_iter(
129 GtkTreeModel *tree_model,
130 GtkTreeIter *iter,
131 GtkTreePath *path)
132 {
133 g_assert(IS_UI_LIST_MODEL(tree_model));
134 UiListModel *model = UI_LIST_MODEL(tree_model);
135 UiList *list = model->list->list;
136
137 // check the depth of the path
138 // a list must have a depth of 1
139 gint depth = gtk_tree_path_get_depth(path);
140 g_assert(depth == 1);
141
142 // get row
143 gint *indices = gtk_tree_path_get_indices(path);
144 gint row = indices[0];
145
146 // check row
147 if(row == 0) {
148 // we don't need to count if the first element is requested
149 if(list->first(list) == NULL) {
150 return FALSE;
151 }
152 } else if(row >= list->count(list)) {
153 return FALSE;
154 }
155
156 // the UiList has an integrated iterator
157 // we only get a value to adjust it
158 void *val = NULL;
159 if(row == 0) {
160 val = list->first(list);
161 } else {
162 val = list->get(list, row);
163 }
164
165 iter->stamp = model->stamp;
166 iter->user_data = list->iter;
167 iter->user_data2 = (gpointer)(intptr_t)row; // list->index
168 iter->user_data3 = val;
169
170 return val ? TRUE : FALSE;
171 }
172
173 GtkTreePath* ui_list_model_get_path(
174 GtkTreeModel *tree_model,
175 GtkTreeIter *iter)
176 {
177 g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), NULL);
178 g_return_val_if_fail(iter != NULL, NULL);
179 g_return_val_if_fail(iter->user_data != NULL, NULL);
180
181 UiListModel *model = UI_LIST_MODEL(tree_model);
182 UiList *list = model->list->list;
183
184 GtkTreePath *path = gtk_tree_path_new();
185 gtk_tree_path_append_index(path, (int)(intptr_t)iter->user_data2); // list->index
186
187 return path;
188 }
189
190 void ui_list_model_get_value(
191 GtkTreeModel *tree_model,
192 GtkTreeIter *iter,
193 gint column,
194 GValue *value)
195 {
196 g_return_if_fail(IS_UI_LIST_MODEL(tree_model));
197 g_return_if_fail(iter != NULL);
198 g_return_if_fail(iter->user_data != NULL);
199
200 UiListModel *model = UI_LIST_MODEL(tree_model);
201 UiList *list = model->list->list;
202
203 g_return_if_fail(column < model->numcolumns);
204
205 // TODO: return correct value from column
206
207 value->g_type = G_TYPE_STRING;
208 list->iter = iter->user_data;
209 //list->index = (int)(intptr_t)iter->user_data2;
210 //list->current = iter->user_data3;
211 if(model->getvalue) {
212 char *str = model->getvalue(iter->user_data3, column);
213 g_value_set_string(value, str);
214 } else {
215 g_value_set_string(value, iter->user_data3);
216 }
217 }
218
219 gboolean ui_list_model_iter_next(
220 GtkTreeModel *tree_model,
221 GtkTreeIter *iter)
222 {
223 g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE);
224 g_return_val_if_fail(iter != NULL, FALSE);
225 g_return_val_if_fail(iter->user_data != NULL, FALSE);
226
227 UiListModel *model = UI_LIST_MODEL(tree_model);
228 UiList *list = model->list->list;
229 list->iter = iter->user_data;
230 //list->index = (int)(intptr_t)iter->user_data2;
231 void *val = list->next(list);
232 iter->user_data = list->iter;
233 intptr_t index = (intptr_t)iter->user_data2;
234 index++;
235 //iter->user_data2 = (gpointer)(intptr_t)list->index;
236 iter->user_data2 = (gpointer)index;
237 iter->user_data3 = val;
238 return val ? TRUE : FALSE;
239 }
240
241 gboolean ui_list_model_iter_children(
242 GtkTreeModel *tree_model,
243 GtkTreeIter *iter,
244 GtkTreeIter *parent)
245 {
246 g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE);
247
248 UiListModel *model = UI_LIST_MODEL(tree_model);
249 UiList *list = model->list->list;
250
251 if(parent) {
252 return FALSE;
253 }
254
255 /*
256 * a list element has no children
257 * we set the iter to the first element
258 */
259 void *val = list->first(list);
260 iter->stamp = model->stamp;
261 iter->user_data = list->iter;
262 iter->user_data2 = (gpointer)0;
263 iter->user_data3 = val;
264
265 return val ? TRUE : FALSE;
266 }
267
268 gboolean ui_list_model_iter_has_child(
269 GtkTreeModel *tree_model,
270 GtkTreeIter *iter)
271 {
272 return FALSE;
273 }
274
275 gint ui_list_model_iter_n_children(
276 GtkTreeModel *tree_model,
277 GtkTreeIter *iter)
278 {
279 g_assert(IS_UI_LIST_MODEL(tree_model));
280
281 if(!iter) {
282 // return number of rows
283 UiListModel *model = UI_LIST_MODEL(tree_model);
284 UiList *list = model->list->list;
285 return list->count(list);
286 }
287
288 return 0;
289 }
290
291 gboolean ui_list_model_iter_nth_child(
292 GtkTreeModel *tree_model,
293 GtkTreeIter *iter,
294 GtkTreeIter *parent,
295 gint n)
296 {
297 g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE);
298
299 if(parent) {
300 return FALSE;
301 }
302
303 UiListModel *model = UI_LIST_MODEL(tree_model);
304 UiList *list = model->list->list;
305
306 // check n
307 if(n == 0) {
308 // we don't need to count if the first element is requested
309 if(list->first(list) == NULL) {
310 return FALSE;
311 }
312 } else if(n >= list->count(list)) {
313 return FALSE;
314 }
315
316 void *val = list->get(list, n);
317 iter->stamp = model->stamp;
318 iter->user_data = list->iter;
319 iter->user_data2 = (gpointer)(intptr_t)n; // list->index
320 iter->user_data3 = val;
321
322 return val ? TRUE : FALSE;
323 }
324
325 gboolean ui_list_model_iter_parent(
326 GtkTreeModel *tree_model,
327 GtkTreeIter *iter,
328 GtkTreeIter *child)
329 {
330 return FALSE;
331 }

mercurial