1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include "model.h"
33 #include "image.h"
34 #include "toolkit.h"
35
36 #define IS_UI_LIST_MODEL(obj) \
37 (
G_TYPE_CHECK_INSTANCE_TYPE((obj), list_model_type))
38 #define UI_LIST_MODEL(obj) \
39 (
G_TYPE_CHECK_INSTANCE_CAST((obj), list_model_type, UiListModel))
40
41 static void list_model_class_init(GObjectClass *cl, gpointer data);
42 static void list_model_interface_init(GtkTreeModelIface *i, gpointer data);
43 static void list_model_init(UiListModel *instance, GObjectClass *cl);
44
45 static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data);
46 static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data);
47
48 static GObjectClass list_model_class;
49 static const GTypeInfo list_model_info = {
50 sizeof(GObjectClass),
51 NULL,
52 NULL,
53 (GClassInitFunc)list_model_class_init,
54 NULL,
55 NULL,
56 sizeof(UiListModel),
57 0,
58 (GInstanceInitFunc)list_model_init
59 };
60 static const GInterfaceInfo list_model_interface_info = {
61 (GInterfaceInitFunc)list_model_interface_init,
62 NULL,
63 NULL
64 };
65 static GType list_model_type;
66
67 static const GInterfaceInfo list_model_dnd_dest_interface_info = {
68 (GInterfaceInitFunc)list_model_dnd_dest_interface_init,
69 NULL,
70 NULL
71 };
72 static const GInterfaceInfo list_model_dnd_src_interface_info = {
73 (GInterfaceInitFunc)list_model_dnd_src_interface_init,
74 NULL,
75 NULL
76 };
77
78 void ui_list_init() {
79 list_model_type = g_type_register_static(
80 G_TYPE_OBJECT,
81 "UiListModel",
82 &list_model_info,
83 (GTypeFlags)
0);
84 g_type_add_interface_static(
85 list_model_type,
86 GTK_TYPE_TREE_MODEL,
87 &list_model_interface_info);
88 g_type_add_interface_static(
89 list_model_type,
90 GTK_TYPE_TREE_DRAG_DEST,
91 &list_model_dnd_dest_interface_info);
92 g_type_add_interface_static(
93 list_model_type,
94 GTK_TYPE_TREE_DRAG_SOURCE,
95 &list_model_dnd_src_interface_info);
96 }
97
98 static void list_model_class_init(GObjectClass *cl, gpointer data) {
99 cl->dispose = ui_list_model_dispose;
100 cl->finalize = ui_list_model_finalize;
101
102 }
103
104 static void list_model_interface_init(GtkTreeModelIface *i, gpointer data) {
105 i->get_flags = ui_list_model_get_flags;
106 i->get_n_columns = ui_list_model_get_n_columns;
107 i->get_column_type = ui_list_model_get_column_type;
108 i->get_iter = ui_list_model_get_iter;
109 i->get_path = ui_list_model_get_path;
110 i->get_value = ui_list_model_get_value;
111 i->iter_next = ui_list_model_iter_next;
112 i->iter_children = ui_list_model_iter_children;
113 i->iter_has_child = ui_list_model_iter_has_child;
114 i->iter_n_children = ui_list_model_iter_n_children;
115 i->iter_nth_child = ui_list_model_iter_nth_child;
116 i->iter_parent = ui_list_model_iter_parent;
117 }
118
119 static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data) {
120 i->drag_data_received = ui_list_model_drag_data_received;
121 i->row_drop_possible = ui_list_model_row_drop_possible;
122 }
123
124 static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data) {
125 i->drag_data_delete = ui_list_model_drag_data_delete;
126 i->drag_data_get = ui_list_model_drag_data_get;
127 i->row_draggable = ui_list_model_row_draggable;
128 }
129
130 static void list_model_init(UiListModel *instance, GObjectClass *cl) {
131 instance->columntypes =
NULL;
132 instance->var =
NULL;
133 instance->numcolumns =
0;
134 instance->stamp = g_random_int();
135 }
136
137 static GType ui_gtk_type(UiModelType type) {
138 switch(type) {
139 default:
break;
140 case UI_STRING:
return G_TYPE_STRING;
141 case UI_INTEGER:
return G_TYPE_INT;
142 }
143 return G_TYPE_INVALID;
144 }
145
146 static void ui_model_set_value(GType type,
void *data, GValue *value) {
147 switch(type) {
148 default:
break;
149 case G_TYPE_OBJECT: {
150 value->g_type =
G_TYPE_OBJECT;
151 g_value_set_object(value, data);
152 return;
153 }
154 case G_TYPE_STRING: {
155 value->g_type =
G_TYPE_STRING;
156 g_value_set_string(value, data);
157 return;
158 }
159 case G_TYPE_INT: {
160 value->g_type =
G_TYPE_INT;
161 int *i = data;
162 g_value_set_int(value, *i);
163 return;
164 }
165 }
166 value->g_type =
G_TYPE_INVALID;
167 }
168
169 UiListModel* ui_list_model_new(UiObject *obj, UiVar *var, UiModel *info) {
170 UiListModel *model = g_object_new(list_model_type,
NULL);
171 model->obj = obj;
172 model->model = info;
173 model->var = var;
174 model->columntypes = calloc(
sizeof(GType),
2 * info->columns);
175 int ncol =
0;
176 for(
int i=
0;i<info->columns;i++) {
177 UiModelType type = info->types[i];
178 if(type ==
UI_ICON_TEXT) {
179 model->columntypes[ncol] =
G_TYPE_OBJECT;
180 ncol++;
181 model->columntypes[ncol] =
G_TYPE_STRING;
182 }
else {
183 model->columntypes[ncol] = ui_gtk_type(info->types[i]);
184 }
185 ncol++;
186 }
187 model->numcolumns = ncol;
188 return model;
189 }
190
191 void ui_list_model_dispose(GObject *obj) {
192
193 }
194
195 void ui_list_model_finalize(GObject *obj) {
196
197 }
198
199
200 GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) {
201 return (
GTK_TREE_MODEL_LIST_ONLY |
GTK_TREE_MODEL_ITERS_PERSIST);
202 }
203
204 gint ui_list_model_get_n_columns(GtkTreeModel *tree_model) {
205 g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
0);
206 UiListModel *model =
UI_LIST_MODEL(tree_model);
207 return model->numcolumns;
208 }
209
210 GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index) {
211 g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
G_TYPE_INVALID);
212 UiListModel *model =
UI_LIST_MODEL(tree_model);
213 g_return_val_if_fail(index < model->numcolumns,
G_TYPE_INVALID);
214 return model->columntypes[index];
215 }
216
217 gboolean ui_list_model_get_iter(
218 GtkTreeModel *tree_model,
219 GtkTreeIter *iter,
220 GtkTreePath *path)
221 {
222 g_assert(
IS_UI_LIST_MODEL(tree_model));
223 UiListModel *model =
UI_LIST_MODEL(tree_model);
224 UiList *list = model->var->value;
225
226
227
228 gint depth = gtk_tree_path_get_depth(path);
229 g_assert(depth ==
1);
230
231
232 gint *indices = gtk_tree_path_get_indices(path);
233 gint row = indices[
0];
234
235
236 if(row ==
0) {
237
238 if(list->first(list) ==
NULL) {
239 return FALSE;
240 }
241 }
else if(row >= list->count(list)) {
242 return FALSE;
243 }
244
245
246
247 void *val =
NULL;
248 if(row ==
0) {
249 val = list->first(list);
250 }
else {
251 val = list->get(list, row);
252 }
253
254 iter->stamp = model->stamp;
255 iter->user_data = list->iter;
256 iter->user_data2 = (gpointer)(
intptr_t)row;
257 iter->user_data3 = val;
258
259 return val ?
TRUE :
FALSE;
260 }
261
262 GtkTreePath* ui_list_model_get_path(
263 GtkTreeModel *tree_model,
264 GtkTreeIter *iter)
265 {
266 g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
NULL);
267 g_return_val_if_fail(iter !=
NULL,
NULL);
268 g_return_val_if_fail(iter->user_data !=
NULL,
NULL);
269
270 UiListModel *model =
UI_LIST_MODEL(tree_model);
271
272 GtkTreePath *path = gtk_tree_path_new();
273 gtk_tree_path_append_index(path, (
int)(
intptr_t)iter->user_data2);
274
275 return path;
276 }
277
278 void ui_list_model_get_value(
279 GtkTreeModel *tree_model,
280 GtkTreeIter *iter,
281 gint column,
282 GValue *value)
283 {
284 g_return_if_fail(
IS_UI_LIST_MODEL(tree_model));
285 g_return_if_fail(iter !=
NULL);
286 g_return_if_fail(iter->user_data !=
NULL);
287
288 UiListModel *model =
UI_LIST_MODEL(tree_model);
289 UiList *list = model->var->value;
290
291 g_return_if_fail(column < model->numcolumns);
292
293
294
295
296 list->iter = iter->user_data;
297
298
299 if(model->model->getvalue) {
300 void *data = model->model->getvalue(iter->user_data3, column);
301 if(model->columntypes[column] ==
G_TYPE_OBJECT) {
302 UiImage *img = data;
303 ui_model_set_value(model->columntypes[column], img->pixbuf, value);
304 }
else {
305 ui_model_set_value(model->columntypes[column], data, value);
306 }
307 }
else {
308 value->g_type =
G_TYPE_INVALID;
309 }
310 }
311
312 gboolean ui_list_model_iter_next(
313 GtkTreeModel *tree_model,
314 GtkTreeIter *iter)
315 {
316 g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
FALSE);
317 g_return_val_if_fail(iter !=
NULL,
FALSE);
318
319
320 if(!iter->user_data) {
321 return FALSE;
322 }
323
324 UiListModel *model =
UI_LIST_MODEL(tree_model);
325 UiList *list = model->var->value;
326 list->iter = iter->user_data;
327
328 void *val = list->next(list);
329 iter->user_data = list->iter;
330 intptr_t index = (
intptr_t)iter->user_data2;
331 index++;
332
333 iter->user_data2 = (gpointer)index;
334 iter->user_data3 = val;
335 return val ?
TRUE :
FALSE;
336 }
337
338 gboolean ui_list_model_iter_children(
339 GtkTreeModel *tree_model,
340 GtkTreeIter *iter,
341 GtkTreeIter *parent)
342 {
343 g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
FALSE);
344
345 UiListModel *model =
UI_LIST_MODEL(tree_model);
346 UiList *list = model->var->value;
347
348 if(parent) {
349 return FALSE;
350 }
351
352
353
354
355
356 void *val = list->first(list);
357 iter->stamp = model->stamp;
358 iter->user_data = list->iter;
359 iter->user_data2 = (gpointer)
0;
360 iter->user_data3 = val;
361
362 return val ?
TRUE :
FALSE;
363 }
364
365 gboolean ui_list_model_iter_has_child(
366 GtkTreeModel *tree_model,
367 GtkTreeIter *iter)
368 {
369 return FALSE;
370 }
371
372 gint ui_list_model_iter_n_children(
373 GtkTreeModel *tree_model,
374 GtkTreeIter *iter)
375 {
376 g_assert(
IS_UI_LIST_MODEL(tree_model));
377
378 if(!iter) {
379
380 UiListModel *model =
UI_LIST_MODEL(tree_model);
381 UiList *list = model->var->value;
382 return list->count(list);
383 }
384
385 return 0;
386 }
387
388 gboolean ui_list_model_iter_nth_child(
389 GtkTreeModel *tree_model,
390 GtkTreeIter *iter,
391 GtkTreeIter *parent,
392 gint n)
393 {
394 g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
FALSE);
395
396 if(parent) {
397 return FALSE;
398 }
399
400 UiListModel *model =
UI_LIST_MODEL(tree_model);
401 UiList *list = model->var->value;
402
403
404 if(n ==
0) {
405
406 if(list->first(list) ==
NULL) {
407 return FALSE;
408 }
409 }
else if(n >= list->count(list)) {
410 return FALSE;
411 }
412
413 void *val = list->get(list, n);
414 iter->stamp = model->stamp;
415 iter->user_data = list->iter;
416 iter->user_data2 = (gpointer)(
intptr_t)n;
417 iter->user_data3 = val;
418
419 return val ?
TRUE :
FALSE;
420 }
421
422 gboolean ui_list_model_iter_parent(
423 GtkTreeModel *tree_model,
424 GtkTreeIter *iter,
425 GtkTreeIter *child)
426 {
427 return FALSE;
428 }
429
430
431
432 gboolean ui_list_model_drag_data_received(
433 GtkTreeDragDest *drag_dest,
434 GtkTreePath *dest_path,
435 GtkSelectionData *selection_data)
436 {
437
438 UiListModel *model =
UI_LIST_MODEL(drag_dest);
439 if(model->model->drop) {
440 gint *indices = gtk_tree_path_get_indices(dest_path);
441 gint row = indices[
0];
442 UiEvent e;
443 e.obj = model->obj;
444 e.window = e.obj->window;
445 e.document = e.obj->ctx->document;
446 e.eventdata =
NULL;
447 e.intval =
0;
448 UiSelection s;
449 s.data = selection_data;
450 model->model->drop(&e, &s, model->var->value, row);
451 }
452 return TRUE;
453 }
454
455 gboolean ui_list_model_row_drop_possible(
456 GtkTreeDragDest *drag_dest,
457 GtkTreePath *dest_path,
458 GtkSelectionData *selection_data)
459 {
460
461 UiListModel *model =
UI_LIST_MODEL(drag_dest);
462 if(model->model->candrop) {
463 gint *indices = gtk_tree_path_get_indices(dest_path);
464 gint row = indices[
0];
465 UiEvent e;
466 e.obj = model->obj;
467 e.window = e.obj->window;
468 e.document = e.obj->ctx->document;
469 e.eventdata =
NULL;
470 e.intval =
0;
471 UiSelection s;
472 s.data = selection_data;
473 return model->model->candrop(&e, &s, model->var->value, row);
474 }
475 return TRUE;
476 }
477
478 gboolean ui_list_model_row_draggable(
479 GtkTreeDragSource *drag_source,
480 GtkTreePath *path)
481 {
482
483 UiListModel *model =
UI_LIST_MODEL(drag_source);
484 if(model->model->candrag) {
485 gint *indices = gtk_tree_path_get_indices(path);
486 gint row = indices[
0];
487 UiEvent e;
488 e.obj = model->obj;
489 e.window = e.obj->window;
490 e.document = e.obj->ctx->document;
491 e.eventdata =
NULL;
492 e.intval =
0;
493 return model->model->candrag(&e, model->var->value, row);
494 }
495 return TRUE;
496 }
497
498 gboolean ui_list_model_drag_data_get(
499 GtkTreeDragSource *drag_source,
500 GtkTreePath *path,
501 GtkSelectionData *selection_data)
502 {
503
504 UiListModel *model =
UI_LIST_MODEL(drag_source);
505 if(model->model->data_get) {
506 gint *indices = gtk_tree_path_get_indices(path);
507 gint row = indices[
0];
508 UiEvent e;
509 e.obj = model->obj;
510 e.window = e.obj->window;
511 e.document = e.obj->ctx->document;
512 e.eventdata =
NULL;
513 e.intval =
0;
514 UiSelection s;
515 s.data = selection_data;
516 model->model->data_get(&e, &s, model->var->value, row);
517 }
518 return TRUE;
519 }
520
521 gboolean ui_list_model_drag_data_delete(
522 GtkTreeDragSource *drag_source,
523 GtkTreePath *path)
524 {
525
526 UiListModel *model =
UI_LIST_MODEL(drag_source);
527 if(model->model->data_get) {
528 gint *indices = gtk_tree_path_get_indices(path);
529 gint row = indices[
0];
530 UiEvent e;
531 e.obj = model->obj;
532 e.window = e.obj->window;
533 e.document = e.obj->ctx->document;
534 e.eventdata =
NULL;
535 e.intval =
0;
536 model->model->data_delete(&e, model->var->value, row);
537 }
538 return TRUE;
539 }
540