Fri, 10 Nov 2017 17:17:14 +0100
refactors value binding system
35 | 1 | /* |
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. | |
3 | * | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
4 | * Copyright 2017 Olaf Wintermann. All rights reserved. |
35 | 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; | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
95 | instance->var = NULL; |
35 | 96 | instance->numcolumns = 0; |
97 | instance->stamp = g_random_int(); | |
98 | } | |
99 | ||
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
100 | static GType ui_gtk_type(UiModelType type) { |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
101 | switch(type) { |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
102 | case UI_STRING: return G_TYPE_STRING; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
103 | case UI_INTEGER: return G_TYPE_INT; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
104 | } |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
105 | return G_TYPE_INVALID; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
106 | } |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
107 | |
129
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
108 | static void ui_model_set_value(GType type, void *data, GValue *value) { |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
109 | switch(type) { |
129
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
110 | case G_TYPE_STRING: { |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
111 | value->g_type = G_TYPE_STRING; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
112 | g_value_set_string(value, data); |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
113 | return; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
114 | } |
129
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
115 | case G_TYPE_INT: { |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
116 | value->g_type = G_TYPE_INT; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
117 | int *i = data; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
118 | g_value_set_int(value, *i); |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
119 | return; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
120 | } |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
121 | } |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
122 | value->g_type = G_TYPE_INVALID; |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
123 | } |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
124 | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
125 | UiListModel* ui_list_model_new(UiVar *var, UiModelInfo *info) { |
35 | 126 | UiListModel *model = g_object_new(list_model_type, NULL); |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
127 | model->info = info; |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
128 | model->var = var; |
129
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
129 | model->columntypes = calloc(sizeof(GType), 2 * info->columns); |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
130 | int ncol = 0; |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
131 | for(int i=0;i<info->columns;i++) { |
129
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
132 | UiModelType type = info->types[i]; |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
133 | if(type == UI_ICON_TEXT) { |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
134 | model->columntypes[ncol] = G_TYPE_STRING; |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
135 | ncol++; |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
136 | model->columntypes[ncol] = G_TYPE_STRING; |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
137 | } else { |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
138 | model->columntypes[ncol] = ui_gtk_type(info->types[i]); |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
139 | } |
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
140 | ncol++; |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
141 | } |
129
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
142 | model->numcolumns = ncol; |
35 | 143 | return model; |
144 | } | |
145 | ||
146 | ||
147 | GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) { | |
148 | return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST); | |
149 | } | |
150 | ||
151 | gint ui_list_model_get_n_columns(GtkTreeModel *tree_model) { | |
152 | g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), 0); | |
153 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
154 | return model->numcolumns; | |
155 | } | |
156 | ||
157 | GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index) { | |
158 | g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), G_TYPE_INVALID); | |
159 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
160 | g_return_val_if_fail(index < model->numcolumns, G_TYPE_INVALID); | |
161 | return model->columntypes[index]; | |
162 | } | |
163 | ||
164 | gboolean ui_list_model_get_iter( | |
165 | GtkTreeModel *tree_model, | |
166 | GtkTreeIter *iter, | |
167 | GtkTreePath *path) | |
168 | { | |
169 | g_assert(IS_UI_LIST_MODEL(tree_model)); | |
170 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
171 | UiList *list = model->var->value; |
35 | 172 | |
173 | // check the depth of the path | |
174 | // a list must have a depth of 1 | |
175 | gint depth = gtk_tree_path_get_depth(path); | |
176 | g_assert(depth == 1); | |
177 | ||
178 | // get row | |
179 | gint *indices = gtk_tree_path_get_indices(path); | |
180 | gint row = indices[0]; | |
181 | ||
182 | // check row | |
183 | if(row == 0) { | |
184 | // we don't need to count if the first element is requested | |
185 | if(list->first(list) == NULL) { | |
186 | return FALSE; | |
187 | } | |
188 | } else if(row >= list->count(list)) { | |
189 | return FALSE; | |
190 | } | |
191 | ||
192 | // the UiList has an integrated iterator | |
193 | // we only get a value to adjust it | |
194 | void *val = NULL; | |
195 | if(row == 0) { | |
196 | val = list->first(list); | |
197 | } else { | |
198 | val = list->get(list, row); | |
199 | } | |
200 | ||
201 | iter->stamp = model->stamp; | |
202 | iter->user_data = list->iter; | |
203 | iter->user_data2 = (gpointer)(intptr_t)row; // list->index | |
204 | iter->user_data3 = val; | |
205 | ||
206 | return val ? TRUE : FALSE; | |
207 | } | |
208 | ||
209 | GtkTreePath* ui_list_model_get_path( | |
210 | GtkTreeModel *tree_model, | |
211 | GtkTreeIter *iter) | |
212 | { | |
213 | g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), NULL); | |
214 | g_return_val_if_fail(iter != NULL, NULL); | |
215 | g_return_val_if_fail(iter->user_data != NULL, NULL); | |
216 | ||
217 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
218 | ||
219 | GtkTreePath *path = gtk_tree_path_new(); | |
220 | gtk_tree_path_append_index(path, (int)(intptr_t)iter->user_data2); // list->index | |
221 | ||
222 | return path; | |
223 | } | |
224 | ||
225 | void ui_list_model_get_value( | |
226 | GtkTreeModel *tree_model, | |
227 | GtkTreeIter *iter, | |
228 | gint column, | |
229 | GValue *value) | |
230 | { | |
231 | g_return_if_fail(IS_UI_LIST_MODEL(tree_model)); | |
232 | g_return_if_fail(iter != NULL); | |
233 | g_return_if_fail(iter->user_data != NULL); | |
234 | ||
235 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
236 | UiList *list = model->var->value; |
35 | 237 | |
238 | g_return_if_fail(column < model->numcolumns); | |
239 | ||
240 | // TODO: return correct value from column | |
241 | ||
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
242 | //value->g_type = G_TYPE_STRING; |
35 | 243 | list->iter = iter->user_data; |
244 | //list->index = (int)(intptr_t)iter->user_data2; | |
245 | //list->current = iter->user_data3; | |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
246 | if(model->info->getvalue) { |
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
247 | void *data = model->info->getvalue(iter->user_data3, column); |
129
5babf09f5f19
fixes stultus commit
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
128
diff
changeset
|
248 | ui_model_set_value(model->columntypes[column], data, value); |
35 | 249 | } else { |
40
caa0df8ed095
added table view (GTK)
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
35
diff
changeset
|
250 | value->g_type = G_TYPE_INVALID; |
35 | 251 | } |
252 | } | |
253 | ||
254 | gboolean ui_list_model_iter_next( | |
255 | GtkTreeModel *tree_model, | |
256 | GtkTreeIter *iter) | |
257 | { | |
258 | g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); | |
259 | g_return_val_if_fail(iter != NULL, FALSE); | |
260 | g_return_val_if_fail(iter->user_data != NULL, FALSE); | |
261 | ||
262 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
263 | UiList *list = model->var->value; |
35 | 264 | list->iter = iter->user_data; |
265 | //list->index = (int)(intptr_t)iter->user_data2; | |
266 | void *val = list->next(list); | |
267 | iter->user_data = list->iter; | |
268 | intptr_t index = (intptr_t)iter->user_data2; | |
269 | index++; | |
270 | //iter->user_data2 = (gpointer)(intptr_t)list->index; | |
271 | iter->user_data2 = (gpointer)index; | |
272 | iter->user_data3 = val; | |
273 | return val ? TRUE : FALSE; | |
274 | } | |
275 | ||
276 | gboolean ui_list_model_iter_children( | |
277 | GtkTreeModel *tree_model, | |
278 | GtkTreeIter *iter, | |
279 | GtkTreeIter *parent) | |
280 | { | |
281 | g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); | |
282 | ||
283 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
284 | UiList *list = model->var->value; |
35 | 285 | |
286 | if(parent) { | |
287 | return FALSE; | |
288 | } | |
289 | ||
290 | /* | |
291 | * a list element has no children | |
292 | * we set the iter to the first element | |
293 | */ | |
294 | void *val = list->first(list); | |
295 | iter->stamp = model->stamp; | |
296 | iter->user_data = list->iter; | |
297 | iter->user_data2 = (gpointer)0; | |
298 | iter->user_data3 = val; | |
299 | ||
300 | return val ? TRUE : FALSE; | |
301 | } | |
302 | ||
303 | gboolean ui_list_model_iter_has_child( | |
304 | GtkTreeModel *tree_model, | |
305 | GtkTreeIter *iter) | |
306 | { | |
307 | return FALSE; | |
308 | } | |
309 | ||
310 | gint ui_list_model_iter_n_children( | |
311 | GtkTreeModel *tree_model, | |
312 | GtkTreeIter *iter) | |
313 | { | |
314 | g_assert(IS_UI_LIST_MODEL(tree_model)); | |
315 | ||
316 | if(!iter) { | |
317 | // return number of rows | |
318 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
319 | UiList *list = model->var->value; |
35 | 320 | return list->count(list); |
321 | } | |
322 | ||
323 | return 0; | |
324 | } | |
325 | ||
326 | gboolean ui_list_model_iter_nth_child( | |
327 | GtkTreeModel *tree_model, | |
328 | GtkTreeIter *iter, | |
329 | GtkTreeIter *parent, | |
330 | gint n) | |
331 | { | |
332 | g_return_val_if_fail(IS_UI_LIST_MODEL(tree_model), FALSE); | |
333 | ||
334 | if(parent) { | |
335 | return FALSE; | |
336 | } | |
337 | ||
338 | UiListModel *model = UI_LIST_MODEL(tree_model); | |
140
c03c338a7dcf
refactors value binding system
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
129
diff
changeset
|
339 | UiList *list = model->var->value; |
35 | 340 | |
341 | // check n | |
342 | if(n == 0) { | |
343 | // we don't need to count if the first element is requested | |
344 | if(list->first(list) == NULL) { | |
345 | return FALSE; | |
346 | } | |
347 | } else if(n >= list->count(list)) { | |
348 | return FALSE; | |
349 | } | |
350 | ||
351 | void *val = list->get(list, n); | |
352 | iter->stamp = model->stamp; | |
353 | iter->user_data = list->iter; | |
354 | iter->user_data2 = (gpointer)(intptr_t)n; // list->index | |
355 | iter->user_data3 = val; | |
356 | ||
357 | return val ? TRUE : FALSE; | |
358 | } | |
359 | ||
360 | gboolean ui_list_model_iter_parent( | |
361 | GtkTreeModel *tree_model, | |
362 | GtkTreeIter *iter, | |
363 | GtkTreeIter *child) | |
364 | { | |
365 | return FALSE; | |
366 | } |