34 #include "../common/context.h" |
34 #include "../common/context.h" |
35 #include "../common/object.h" |
35 #include "../common/object.h" |
36 #include "container.h" |
36 #include "container.h" |
37 |
37 |
38 #include "tree.h" |
38 #include "tree.h" |
|
39 #include "image.h" |
39 |
40 |
40 |
41 |
41 void* ui_strmodel_getvalue(void *elm, int column) { |
42 void* ui_strmodel_getvalue(void *elm, int column) { |
42 return column == 0 ? elm : NULL; |
43 return column == 0 ? elm : NULL; |
43 } |
44 } |
44 |
45 |
45 |
46 static GtkListStore* create_list_store(UiList *list, UiModel *model) { |
46 |
47 int columns = model->columns; |
47 |
48 GType types[2*columns]; |
48 UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { |
49 int c = 0; |
|
50 for(int i=0;i<columns;i++,c++) { |
|
51 switch(model->types[i]) { |
|
52 case UI_STRING: |
|
53 case UI_STRING_FREE: types[c] = G_TYPE_STRING; break; |
|
54 case UI_INTEGER: types[c] = G_TYPE_INT; break; |
|
55 case UI_ICON: types[c] = G_TYPE_OBJECT; break; |
|
56 case UI_ICON_TEXT: |
|
57 case UI_ICON_TEXT_FREE: { |
|
58 types[c] = G_TYPE_OBJECT; |
|
59 types[++c] = G_TYPE_STRING; |
|
60 } |
|
61 } |
|
62 } |
|
63 |
|
64 GtkListStore *store = gtk_list_store_newv(c, types); |
|
65 |
|
66 if(list) { |
|
67 void *elm = list->first(list); |
|
68 while(elm) { |
|
69 // insert new row |
|
70 GtkTreeIter iter; |
|
71 gtk_list_store_insert (store, &iter, -1); |
|
72 |
|
73 // set column values |
|
74 int c = 0; |
|
75 for(int i=0;i<columns;i++,c++) { |
|
76 void *data = model->getvalue(elm, c); |
|
77 |
|
78 GValue value = G_VALUE_INIT; |
|
79 switch(model->types[i]) { |
|
80 case UI_STRING: |
|
81 case UI_STRING_FREE: { |
|
82 g_value_init(&value, G_TYPE_STRING); |
|
83 g_value_set_string(&value, data); |
|
84 if(model->types[i] == UI_STRING_FREE) { |
|
85 free(data); |
|
86 } |
|
87 break; |
|
88 } |
|
89 case UI_INTEGER: { |
|
90 g_value_init(&value, G_TYPE_INT); |
|
91 int *intptr = data; |
|
92 g_value_set_int(&value, *intptr); |
|
93 break; |
|
94 } |
|
95 case UI_ICON: { |
|
96 g_value_init(&value, G_TYPE_OBJECT); |
|
97 UiIcon *icon = data; |
|
98 if(!icon->pixbuf && icon->info) { |
|
99 GError *error = NULL; |
|
100 GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); |
|
101 icon->pixbuf = pixbuf; |
|
102 } |
|
103 |
|
104 if(icon->pixbuf) { |
|
105 g_value_set_object(&value, icon->pixbuf); |
|
106 } |
|
107 |
|
108 |
|
109 break; |
|
110 } |
|
111 case UI_ICON_TEXT: |
|
112 case UI_ICON_TEXT_FREE: { |
|
113 GValue pixbufvalue = G_VALUE_INIT; |
|
114 UiIcon *icon = data; |
|
115 if(!icon->pixbuf && icon->info) { |
|
116 GError *error = NULL; |
|
117 GdkPixbuf *pixbuf = gtk_icon_info_load_icon(icon->info, &error); |
|
118 icon->pixbuf = pixbuf; |
|
119 } |
|
120 g_value_init(&pixbufvalue, G_TYPE_OBJECT); |
|
121 g_value_set_object(&pixbufvalue, icon->pixbuf); |
|
122 gtk_list_store_set_value(store, &iter, c, &pixbufvalue); |
|
123 c++; |
|
124 |
|
125 char *str = model->getvalue(elm, c); |
|
126 g_value_init(&value, G_TYPE_STRING); |
|
127 g_value_set_string(&value, str); |
|
128 if(model->types[i] == UI_ICON_TEXT_FREE) { |
|
129 free(str); |
|
130 } |
|
131 break; |
|
132 } |
|
133 } |
|
134 |
|
135 gtk_list_store_set_value(store, &iter, c, &value); |
|
136 } |
|
137 |
|
138 // next row |
|
139 elm = list->next(list); |
|
140 } |
|
141 } |
|
142 |
|
143 return store; |
|
144 } |
|
145 |
|
146 |
|
147 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs args) { |
|
148 UiObject* current = uic_current_obj(obj); |
|
149 |
49 // create treeview |
150 // create treeview |
50 GtkWidget *view = gtk_tree_view_new(); |
151 GtkWidget *view = gtk_tree_view_new(); |
51 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
152 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
52 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL); |
153 GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 0, NULL); |
53 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); |
154 gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); |
62 #else |
163 #else |
63 // TODO: implement for gtk2 |
164 // TODO: implement for gtk2 |
64 #endif |
165 #endif |
65 |
166 |
66 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
167 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
67 model->getvalue = getvalue; |
168 model->getvalue = args.getvalue; |
68 UiList *list = var->value; |
169 |
69 UiListModel *listmodel = ui_list_model_new(obj, var, model); |
170 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); |
|
171 |
|
172 UiList *list = var ? var->value : NULL; |
|
173 GtkListStore *listmodel = create_list_store(list, model); |
70 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
174 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
71 |
175 |
72 UiListView *listview = malloc(sizeof(UiListView)); |
176 UiListView *listview = malloc(sizeof(UiListView)); |
73 listview->obj = obj; |
177 listview->obj = obj; |
74 listview->widget = view; |
178 listview->widget = view; |
105 GTK_SCROLLED_WINDOW(scroll_area), |
209 GTK_SCROLLED_WINDOW(scroll_area), |
106 GTK_POLICY_AUTOMATIC, |
210 GTK_POLICY_AUTOMATIC, |
107 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS |
211 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS |
108 gtk_container_add(GTK_CONTAINER(scroll_area), view); |
212 gtk_container_add(GTK_CONTAINER(scroll_area), view); |
109 |
213 |
110 UiContainer *ct = uic_get_current_container(obj); |
214 UI_APPLY_LAYOUT1(current, args); |
111 ct->add(ct, scroll_area, TRUE); |
215 current->container->add(current->container, scroll_area, FALSE); |
112 |
216 |
113 // ct->current should point to view, not scroll_area, to make it possible |
217 // ct->current should point to view, not scroll_area, to make it possible |
114 // to add a context menu |
218 // to add a context menu |
115 ct->current = view; |
219 current->container->current = view; |
116 |
220 |
117 return scroll_area; |
221 return scroll_area; |
118 } |
|
119 |
|
120 UIWIDGET ui_listview_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { |
|
121 UiVar *var = malloc(sizeof(UiVar)); |
|
122 var->value = list; |
|
123 var->type = UI_VAR_SPECIAL; |
|
124 return ui_listview_var(obj, var, getvalue, f, udata); |
|
125 } |
|
126 |
|
127 UIWIDGET ui_listview_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { |
|
128 UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); |
|
129 if(var) { |
|
130 return ui_listview_var(obj, var, getvalue, f, udata); |
|
131 } else { |
|
132 // TODO: error |
|
133 } |
|
134 return NULL; |
|
135 } |
222 } |
136 |
223 |
137 static void drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer udata) { |
224 static void drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer udata) { |
138 printf("drag begin\n"); |
225 printf("drag begin\n"); |
139 |
226 |
154 { "STRING", 0, 0 }, |
241 { "STRING", 0, 0 }, |
155 { "text/plain", 0, 1 }, |
242 { "text/plain", 0, 1 }, |
156 { "text/uri-list", 0, 2 }, |
243 { "text/uri-list", 0, 2 }, |
157 }; |
244 }; |
158 |
245 |
159 UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) { |
246 UIWIDGET ui_table_create(UiObject *obj, UiListArgs args) { |
|
247 UiObject* current = uic_current_obj(obj); |
|
248 |
160 // create treeview |
249 // create treeview |
161 GtkWidget *view = gtk_tree_view_new(); |
250 GtkWidget *view = gtk_tree_view_new(); |
162 |
251 |
|
252 UiModel *model = args.model; |
|
253 int columns = model ? model->columns : 0; |
|
254 |
163 int addi = 0; |
255 int addi = 0; |
164 for(int i=0;i<model->columns;i++) { |
256 for(int i=0;i<columns;i++) { |
165 GtkTreeViewColumn *column = NULL; |
257 GtkTreeViewColumn *column = NULL; |
166 if(model->types[i] == UI_ICON_TEXT) { |
258 if(model->types[i] == UI_ICON_TEXT) { |
167 column = gtk_tree_view_column_new(); |
259 column = gtk_tree_view_column_new(); |
168 gtk_tree_view_column_set_title(column, model->titles[i]); |
260 gtk_tree_view_column_set_title(column, model->titles[i]); |
169 |
261 |
176 |
268 |
177 gtk_tree_view_column_add_attribute(column, iconrenderer, "pixbuf", i); |
269 gtk_tree_view_column_add_attribute(column, iconrenderer, "pixbuf", i); |
178 gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1); |
270 gtk_tree_view_column_add_attribute(column, textrenderer, "text", i+1); |
179 |
271 |
180 addi++; |
272 addi++; |
|
273 } else if (model->types[i] == UI_ICON) { |
|
274 GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new(); |
|
275 column = gtk_tree_view_column_new_with_attributes( |
|
276 model->titles[i], |
|
277 iconrenderer, |
|
278 "pixbuf", |
|
279 i + addi, |
|
280 NULL); |
181 } else { |
281 } else { |
182 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
282 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
183 column = gtk_tree_view_column_new_with_attributes( |
283 column = gtk_tree_view_column_new_with_attributes( |
184 model->titles[i], |
284 model->titles[i], |
185 renderer, |
285 renderer, |
196 //gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(view), TRUE); |
296 //gtk_tree_view_set_activate_on_single_click(GTK_TREE_VIEW(view), TRUE); |
197 #else |
297 #else |
198 |
298 |
199 #endif |
299 #endif |
200 |
300 |
201 UiList *list = var->value; |
301 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); |
202 UiListModel *listmodel = ui_list_model_new(obj, var, model); |
302 |
|
303 UiList *list = var ? var->value : NULL; |
|
304 GtkListStore *listmodel = create_list_store(list, model); |
203 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
305 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
204 |
306 |
205 //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL); |
307 //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL); |
206 //g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL); |
308 //g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL); |
207 |
309 |
223 list->obj = tableview; |
325 list->obj = tableview; |
224 |
326 |
225 // add callback |
327 // add callback |
226 UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); |
328 UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); |
227 event->obj = obj; |
329 event->obj = obj; |
228 event->activate = cb.activate; |
330 event->activate = args.onactivate; |
229 event->selection = cb.selection; |
331 event->selection = args.onselection; |
230 event->userdata = cb.userdata; |
332 event->activatedata = args.onactivatedata; |
231 if(cb.activate) { |
333 event->selectiondata = args.onselectiondata; |
|
334 if(args.onactivate) { |
232 g_signal_connect( |
335 g_signal_connect( |
233 view, |
336 view, |
234 "row-activated", |
337 "row-activated", |
235 G_CALLBACK(ui_listview_activate_event), |
338 G_CALLBACK(ui_listview_activate_event), |
236 event); |
339 event); |
237 } |
340 } |
238 if(cb.selection) { |
341 if(args.onselection) { |
239 GtkTreeSelection *selection = gtk_tree_view_get_selection( |
342 GtkTreeSelection *selection = gtk_tree_view_get_selection( |
240 GTK_TREE_VIEW(view)); |
343 GTK_TREE_VIEW(view)); |
241 g_signal_connect( |
344 g_signal_connect( |
242 selection, |
345 selection, |
243 "changed", |
346 "changed", |
256 GTK_SCROLLED_WINDOW(scroll_area), |
359 GTK_SCROLLED_WINDOW(scroll_area), |
257 GTK_POLICY_AUTOMATIC, |
360 GTK_POLICY_AUTOMATIC, |
258 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS |
361 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS |
259 gtk_container_add(GTK_CONTAINER(scroll_area), view); |
362 gtk_container_add(GTK_CONTAINER(scroll_area), view); |
260 |
363 |
261 UiContainer *ct = uic_get_current_container(obj); |
364 UI_APPLY_LAYOUT1(current, args); |
262 ct->add(ct, scroll_area, TRUE); |
365 current->container->add(current->container, scroll_area, FALSE); |
263 |
366 |
264 // ct->current should point to view, not scroll_area, to make it possible |
367 // ct->current should point to view, not scroll_area, to make it possible |
265 // to add a context menu |
368 // to add a context menu |
266 ct->current = view; |
369 current->container->current = view; |
267 |
370 |
268 return scroll_area; |
371 return scroll_area; |
269 } |
372 } |
270 |
373 |
271 UIWIDGET ui_table_deprecated(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) { |
|
272 UiVar *var = malloc(sizeof(UiVar)); |
|
273 var->value = list; |
|
274 var->type = UI_VAR_SPECIAL; |
|
275 return ui_table_var(obj, var, model, cb); |
|
276 } |
|
277 |
|
278 UIWIDGET ui_table_nv(UiObject *obj, char *varname, UiModel *model, UiListCallbacks cb) { |
|
279 UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); |
|
280 if(var) { |
|
281 return ui_table_var(obj, var, model, cb); |
|
282 } else { |
|
283 // TODO: error |
|
284 } |
|
285 return NULL; |
|
286 } |
|
287 |
374 |
288 GtkWidget* ui_get_tree_widget(UIWIDGET widget) { |
375 GtkWidget* ui_get_tree_widget(UIWIDGET widget) { |
289 GList *c = gtk_container_get_children(GTK_CONTAINER(widget)); |
376 GList *c = gtk_container_get_children(GTK_CONTAINER(widget)); |
290 if(c) { |
377 if(c) { |
291 return c->data; |
378 return c->data; |
368 } |
455 } |
369 */ |
456 */ |
370 |
457 |
371 void ui_listview_update(UiList *list, int i) { |
458 void ui_listview_update(UiList *list, int i) { |
372 UiListView *view = list->obj; |
459 UiListView *view = list->obj; |
373 UiListModel *model = ui_list_model_new(view->obj, view->var, view->model); |
460 GtkListStore *store = create_list_store(list, view->model); |
374 gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(model)); |
461 gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store)); |
375 g_object_unref(G_OBJECT(model)); |
462 g_object_unref(G_OBJECT(store)); |
376 // TODO: free old model |
463 // TODO: free old model |
377 } |
464 } |
378 |
465 |
379 void ui_listview_destroy(GtkWidget *w, UiListView *v) { |
466 void ui_listview_destroy(GtkWidget *w, UiListView *v) { |
380 gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); |
467 gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); |
466 } |
553 } |
467 |
554 |
468 |
555 |
469 /* --------------------------- ComboBox --------------------------- */ |
556 /* --------------------------- ComboBox --------------------------- */ |
470 |
557 |
471 UIWIDGET ui_combobox_deprecated(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f, void *udata) { |
558 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs args) { |
472 UiVar *var = malloc(sizeof(UiVar)); |
559 UiObject* current = uic_current_obj(obj); |
473 var->value = list; |
560 |
474 var->type = UI_VAR_SPECIAL; |
|
475 return ui_combobox_var(obj, var, getvalue, f, udata); |
|
476 } |
|
477 |
|
478 UIWIDGET ui_combobox_nv(UiObject *obj, char *varname, ui_getvaluefunc getvalue, ui_callback f, void *udata) { |
|
479 UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_LIST); |
|
480 if(var) { |
|
481 return ui_combobox_var(obj, var, getvalue, f, udata); |
|
482 } else { |
|
483 // TODO: error |
|
484 } |
|
485 return NULL; |
|
486 } |
|
487 |
|
488 UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f, void *udata) { |
|
489 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
561 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
490 model->getvalue = getvalue; |
562 model->getvalue = args.getvalue; |
491 UiListModel *listmodel = ui_list_model_new(obj, var, model); |
563 |
492 |
564 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.list, args.varname, UI_VAR_LIST); |
493 GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata); |
565 |
494 UiContainer *ct = uic_get_current_container(obj); |
566 GtkWidget *combobox = ui_create_combobox(obj, model, var, args.onactivate, args.onactivatedata); |
495 ct->add(ct, combobox, FALSE); |
567 UI_APPLY_LAYOUT1(current, args); |
|
568 current->container->add(current->container, combobox, FALSE); |
|
569 current->container->current = combobox; |
496 return combobox; |
570 return combobox; |
497 } |
571 } |
498 |
572 |
499 GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f, void *udata) { |
573 GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, ui_callback f, void *udata) { |
500 GtkWidget *combobox = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); |
574 GtkWidget *combobox = gtk_combo_box_new(); |
501 |
575 |
502 UiListView *uicbox = malloc(sizeof(UiListView)); |
576 UiListView *uicbox = malloc(sizeof(UiListView)); |
503 uicbox->obj = obj; |
577 uicbox->obj = obj; |
504 uicbox->widget = combobox; |
578 uicbox->widget = combobox; |
505 uicbox->var = model->var; |
579 |
506 uicbox->model = model->model; |
580 UiList *list = var ? var->value : NULL; |
|
581 GtkListStore *listmodel = create_list_store(list, model); |
|
582 |
|
583 if(listmodel) { |
|
584 gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(listmodel)); |
|
585 } |
|
586 |
|
587 uicbox->var = var; |
|
588 uicbox->model = model; |
507 |
589 |
508 g_signal_connect( |
590 g_signal_connect( |
509 combobox, |
591 combobox, |
510 "destroy", |
592 "destroy", |
511 G_CALLBACK(ui_combobox_destroy), |
593 G_CALLBACK(ui_combobox_destroy), |
512 uicbox); |
594 uicbox); |
513 |
595 |
514 // bind var |
596 // bind var |
515 UiList *list = model->var->value; |
597 if(list) { |
516 list->update = ui_combobox_modelupdate; |
598 list->update = ui_combobox_modelupdate; |
517 list->obj = uicbox; |
599 list->obj = uicbox; |
|
600 } |
518 |
601 |
519 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
602 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
520 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); |
603 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); |
521 gtk_cell_layout_set_attributes( |
604 gtk_cell_layout_set_attributes( |
522 GTK_CELL_LAYOUT(combobox), |
605 GTK_CELL_LAYOUT(combobox), |