| 37 |
37 |
| 38 #include <cx/array_list.h> |
38 #include <cx/array_list.h> |
| 39 #include <cx/linked_list.h> |
39 #include <cx/linked_list.h> |
| 40 |
40 |
| 41 #include "list.h" |
41 #include "list.h" |
| |
42 #include "button.h" |
| 42 #include "icon.h" |
43 #include "icon.h" |
| 43 #include "menu.h" |
44 #include "menu.h" |
| 44 #include "dnd.h" |
45 #include "dnd.h" |
| 45 |
46 |
| 46 |
47 |
| 47 void* ui_strmodel_getvalue(void *elm, int column) { |
48 static void* getvalue_wrapper(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) { |
| 48 return column == 0 ? elm : NULL; |
49 ui_getvaluefunc getvalue = (ui_getvaluefunc)userdata; |
| 49 } |
50 return getvalue(elm, col); |
| 50 |
51 } |
| 51 static void* model_getvalue(UiModel *model, UiList *list, void *elm, int row, int col, UiBool *freeResult) { |
52 |
| 52 if(model->getvalue2) { |
53 static void* str_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) { |
| 53 return model->getvalue2(list, elm, row, col, model->getvalue2data, freeResult); |
54 return elm; |
| 54 } else if(model->getvalue) { |
55 } |
| 55 return model->getvalue(elm, col); |
56 |
| 56 } |
57 static void* null_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) { |
| 57 return NULL; |
58 return NULL; |
| 58 } |
59 } |
| 59 |
60 |
| 60 /* |
61 /* |
| 61 static GtkTargetEntry targetentries[] = |
62 static GtkTargetEntry targetentries[] = |
| 70 listview->elements = calloc(nelm, sizeof(char*)); |
71 listview->elements = calloc(nelm, sizeof(char*)); |
| 71 listview->nelm = nelm; |
72 listview->nelm = nelm; |
| 72 for(int i=0;i<nelm;i++) { |
73 for(int i=0;i<nelm;i++) { |
| 73 listview->elements[i] = strdup(elm[i]); |
74 listview->elements[i] = strdup(elm[i]); |
| 74 } |
75 } |
| |
76 } |
| |
77 |
| |
78 static UiListView* create_listview(UiObject *obj, UiListArgs *args) { |
| |
79 UiListView *tableview = malloc(sizeof(UiListView)); |
| |
80 memset(tableview, 0, sizeof(UiListView)); |
| |
81 tableview->obj = obj; |
| |
82 tableview->model = args->model; |
| |
83 tableview->onactivate = args->onactivate; |
| |
84 tableview->onactivatedata = args->onactivatedata; |
| |
85 tableview->onselection = args->onselection; |
| |
86 tableview->onselectiondata = args->onselectiondata; |
| |
87 tableview->ondragstart = args->ondragstart; |
| |
88 tableview->ondragstartdata = args->ondragstartdata; |
| |
89 tableview->ondragcomplete = args->ondragcomplete; |
| |
90 tableview->ondragcompletedata = args->ondragcompletedata; |
| |
91 tableview->ondrop = args->ondrop; |
| |
92 tableview->ondropdata = args->ondropdata; |
| |
93 tableview->selection.count = 0; |
| |
94 tableview->selection.rows = NULL; |
| |
95 |
| |
96 if(args->getvalue2) { |
| |
97 tableview->getvalue = args->getvalue2; |
| |
98 tableview->getvaluedata = args->getvalue2data; |
| |
99 } else if(args->getvalue) { |
| |
100 tableview->getvalue = getvalue_wrapper; |
| |
101 tableview->getvaluedata = (void*)args->getvalue; |
| |
102 } else { |
| |
103 tableview->getvalue = null_getvalue; |
| |
104 } |
| |
105 |
| |
106 return tableview; |
| 75 } |
107 } |
| 76 |
108 |
| 77 #if GTK_CHECK_VERSION(4, 10, 0) |
109 #if GTK_CHECK_VERSION(4, 10, 0) |
| 78 |
110 |
| 79 |
111 |
| 129 gtk_label_set_xalign(GTK_LABEL(label), 0); |
161 gtk_label_set_xalign(GTK_LABEL(label), 0); |
| 130 gtk_list_item_set_child(item, label); |
162 gtk_list_item_set_child(item, label); |
| 131 } |
163 } |
| 132 } |
164 } |
| 133 |
165 |
| 134 static void column_factory_bind( GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { |
166 static void column_factory_bind(GtkListItemFactory *factory, GtkListItem *item, gpointer userdata) { |
| 135 UiColData *col = userdata; |
167 UiColData *col = userdata; |
| 136 UiList *list = col->listview->var ? col->listview->var->value : NULL; |
168 UiList *list = col->listview->var ? col->listview->var->value : NULL; |
| |
169 UiListView *listview = col->listview; |
| 137 |
170 |
| 138 ObjWrapper *obj = gtk_list_item_get_item(item); |
171 ObjWrapper *obj = gtk_list_item_get_item(item); |
| 139 UiModel *model = col->listview->model; |
172 UiModel *model = col->listview->model; |
| 140 UiModelType type = model->types[col->model_column]; |
173 UiModelType type = model->types[col->model_column]; |
| 141 |
174 |
| 142 UiBool freevalue = FALSE; |
175 UiBool freevalue = FALSE; |
| 143 void *data = model_getvalue(model, list, obj->data, obj->i, col->data_column, &freevalue); |
176 void *data = listview->getvalue(list, obj->data, obj->i, col->data_column, listview->getvaluedata, &freevalue); |
| 144 GtkWidget *child = gtk_list_item_get_child(item); |
177 GtkWidget *child = gtk_list_item_get_child(item); |
| 145 |
178 |
| 146 switch(type) { |
179 switch(type) { |
| 147 case UI_STRING_FREE: { |
180 case UI_STRING_FREE: { |
| 148 freevalue = TRUE; |
181 freevalue = TRUE; |
| 197 GtkSelectionModel *selection_model; |
230 GtkSelectionModel *selection_model; |
| 198 if(multiselection) { |
231 if(multiselection) { |
| 199 selection_model = GTK_SELECTION_MODEL(gtk_multi_selection_new(G_LIST_MODEL(liststore))); |
232 selection_model = GTK_SELECTION_MODEL(gtk_multi_selection_new(G_LIST_MODEL(liststore))); |
| 200 } else { |
233 } else { |
| 201 selection_model = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(liststore))); |
234 selection_model = GTK_SELECTION_MODEL(gtk_single_selection_new(G_LIST_MODEL(liststore))); |
| |
235 gtk_single_selection_set_can_unselect(GTK_SINGLE_SELECTION(selection_model), TRUE); |
| |
236 gtk_single_selection_set_autoselect(GTK_SINGLE_SELECTION(selection_model), FALSE); |
| 202 } |
237 } |
| 203 g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), listview); |
238 g_signal_connect(selection_model, "selection-changed", G_CALLBACK(ui_listview_selection_changed), listview); |
| 204 return selection_model; |
239 return selection_model; |
| 205 } |
|
| 206 |
|
| 207 static UiListView* create_listview(UiObject *obj, UiListArgs *args) { |
|
| 208 UiListView *tableview = malloc(sizeof(UiListView)); |
|
| 209 memset(tableview, 0, sizeof(UiListView)); |
|
| 210 tableview->obj = obj; |
|
| 211 tableview->model = args->model; |
|
| 212 tableview->onactivate = args->onactivate; |
|
| 213 tableview->onactivatedata = args->onactivatedata; |
|
| 214 tableview->onselection = args->onselection; |
|
| 215 tableview->onselectiondata = args->onselectiondata; |
|
| 216 tableview->ondragstart = args->ondragstart; |
|
| 217 tableview->ondragstartdata = args->ondragstartdata; |
|
| 218 tableview->ondragcomplete = args->ondragcomplete; |
|
| 219 tableview->ondragcompletedata = args->ondragcompletedata; |
|
| 220 tableview->ondrop = args->ondrop; |
|
| 221 tableview->ondropdata = args->ondropdata; |
|
| 222 tableview->selection.count = 0; |
|
| 223 tableview->selection.rows = NULL; |
|
| 224 return tableview; |
|
| 225 } |
240 } |
| 226 |
241 |
| 227 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) { |
242 UIWIDGET ui_listview_create(UiObject *obj, UiListArgs *args) { |
| 228 UiObject* current = uic_current_obj(obj); |
243 UiObject* current = uic_current_obj(obj); |
| 229 |
244 |
| 230 // to simplify things and share code with ui_table_create, we also |
245 // to simplify things and share code with ui_table_create, we also |
| 231 // use a UiModel for the listview |
246 // use a UiModel for the listview |
| 232 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
247 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
| 233 if(args->getvalue2) { |
|
| 234 model->getvalue2 = args->getvalue2; |
|
| 235 model->getvalue2data = args->getvalue2data; |
|
| 236 } else if(args->getvalue) { |
|
| 237 model->getvalue = args->getvalue; |
|
| 238 } else { |
|
| 239 model->getvalue = ui_strmodel_getvalue; |
|
| 240 } |
|
| 241 args->model = model; |
248 args->model = model; |
| 242 |
249 |
| 243 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
250 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
| 244 UiListView *listview = create_listview(obj, args); |
251 UiListView *listview = create_listview(obj, args); |
| |
252 if(!args->getvalue && !args->getvalue2) { |
| |
253 listview->getvalue = str_getvalue; |
| |
254 } |
| 245 |
255 |
| 246 listview->columns = malloc(sizeof(UiColData)); |
256 listview->columns = malloc(sizeof(UiColData)); |
| 247 listview->columns->listview = listview; |
257 listview->columns->listview = listview; |
| 248 listview->columns->data_column = 0; |
258 listview->columns->data_column = 0; |
| 249 listview->columns->model_column = 0; |
259 listview->columns->model_column = 0; |
| 250 |
260 |
| 251 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
261 GtkListItemFactory *factory = gtk_signal_list_item_factory_new(); |
| 252 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns); |
262 g_signal_connect(factory, "setup", G_CALLBACK(column_factory_setup), listview->columns); |
| 253 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns); |
263 g_signal_connect(factory, "bind", G_CALLBACK(column_factory_bind), listview->columns); |
| 254 |
264 |
| 255 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection); |
265 GtkSelectionModel *selection_model = create_selection_model(listview, ls, args->multiselection); |
| 318 UiObject* current = uic_current_obj(obj); |
328 UiObject* current = uic_current_obj(obj); |
| 319 |
329 |
| 320 // to simplify things and share code with ui_tableview_create, we also |
330 // to simplify things and share code with ui_tableview_create, we also |
| 321 // use a UiModel for the listview |
331 // use a UiModel for the listview |
| 322 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
332 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
| 323 if(args->getvalue2) { |
|
| 324 model->getvalue2 = args->getvalue2; |
|
| 325 model->getvalue2data = args->getvalue2data; |
|
| 326 } else if(args->getvalue) { |
|
| 327 model->getvalue = args->getvalue; |
|
| 328 } else { |
|
| 329 model->getvalue = ui_strmodel_getvalue; |
|
| 330 } |
|
| 331 args->model = model; |
333 args->model = model; |
| 332 |
334 |
| 333 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
335 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
| 334 UiListView *listview = create_listview(obj, args); |
336 UiListView *listview = create_listview(obj, args); |
| |
337 |
| |
338 if(!args->getvalue && !args->getvalue2) { |
| |
339 listview->getvalue = str_getvalue; |
| |
340 } |
| 335 |
341 |
| 336 listview->columns = malloc(sizeof(UiColData)); |
342 listview->columns = malloc(sizeof(UiColData)); |
| 337 listview->columns->listview = listview; |
343 listview->columns->listview = listview; |
| 338 listview->columns->data_column = 0; |
344 listview->columns->data_column = 0; |
| 339 listview->columns->model_column = 0; |
345 listview->columns->model_column = 0; |
| 624 ui_update_liststore(view->liststore, list); |
630 ui_update_liststore(view->liststore, list); |
| 625 } else { |
631 } else { |
| 626 void *value = list->get(list, i); |
632 void *value = list->get(list, i); |
| 627 if(value) { |
633 if(value) { |
| 628 ObjWrapper *obj = obj_wrapper_new(value, i); |
634 ObjWrapper *obj = obj_wrapper_new(value, i); |
| |
635 UiListSelection sel = list->getselection(list); |
| 629 // TODO: if index i is selected, the selection is lost |
636 // TODO: if index i is selected, the selection is lost |
| 630 // is it possible to update the item without removing it? |
637 // is it possible to update the item without removing it? |
| |
638 // workaround: save selection and reapply it |
| 631 int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore)); |
639 int count = g_list_model_get_n_items(G_LIST_MODEL(view->liststore)); |
| 632 if(count <= i) { |
640 if(count <= i) { |
| 633 g_list_store_splice(view->liststore, i, 0, (void **)&obj, 1); |
641 g_list_store_splice(view->liststore, i, 0, (void **)&obj, 1); |
| 634 } else { |
642 } else { |
| 635 g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1); |
643 g_list_store_splice(view->liststore, i, 1, (void **)&obj, 1); |
| 636 } |
644 } |
| |
645 if(sel.count > 0) { |
| |
646 list->setselection(list, sel); |
| |
647 } |
| |
648 ui_listselection_free(sel); |
| 637 } |
649 } |
| 638 } |
650 } |
| 639 } |
651 } |
| 640 |
652 |
| 641 UiListSelection ui_listview_getselection2(UiList *list) { |
653 UiListSelection ui_listview_getselection2(UiList *list) { |
| 693 ui_setop_enable(FALSE); |
705 ui_setop_enable(FALSE); |
| 694 } |
706 } |
| 695 |
707 |
| 696 #else |
708 #else |
| 697 |
709 |
| 698 static void update_list_row(GtkListStore *store, GtkTreeIter *iter, UiModel *model, UiList *list, void *elm, int row) { |
710 static void update_list_row(UiListView *listview, GtkListStore *store, GtkTreeIter *iter, UiList *list, void *elm, int row) { |
| |
711 UiModel *model = listview->model; |
| 699 // set column values |
712 // set column values |
| 700 int c = 0; |
713 int c = 0; |
| 701 for(int i=0;i<model->columns;i++,c++) { |
714 for(int i=0;i<model->columns;i++,c++) { |
| 702 UiBool freevalue = FALSE; |
715 UiBool freevalue = FALSE; |
| 703 void *data = model_getvalue(model, list, elm, row, c, &freevalue); |
716 void *data = listview->getvalue(list, elm, row, c, listview->getvaluedata, &freevalue); |
| 704 |
717 |
| 705 GValue value = G_VALUE_INIT; |
718 GValue value = G_VALUE_INIT; |
| 706 switch(model->types[i]) { |
719 switch(model->types[i]) { |
| 707 case UI_STRING_FREE: { |
720 case UI_STRING_FREE: { |
| 708 freevalue = TRUE; |
721 freevalue = TRUE; |
| 839 #else |
853 #else |
| 840 // TODO: implement for gtk2 |
854 // TODO: implement for gtk2 |
| 841 #endif |
855 #endif |
| 842 |
856 |
| 843 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
857 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
| 844 if(args->getvalue2) { |
858 |
| 845 model->getvalue2 = args->getvalue2; |
859 UiListView *listview = create_listview(obj, args); |
| 846 model->getvalue2data = args->getvalue2data; |
860 if(!args->getvalue && !args->getvalue2) { |
| 847 } else if(args->getvalue) { |
861 listview->getvalue = str_getvalue; |
| 848 model->getvalue = args->getvalue; |
862 } |
| 849 } else { |
|
| 850 model->getvalue = ui_strmodel_getvalue; |
|
| 851 } |
|
| 852 |
|
| 853 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST); |
|
| 854 |
|
| 855 UiList *list = var ? var->value : NULL; |
|
| 856 GtkListStore *listmodel = create_list_store(list, model); |
|
| 857 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
|
| 858 g_object_unref(listmodel); |
|
| 859 |
|
| 860 UiListView *listview = malloc(sizeof(UiListView)); |
|
| 861 memset(listview, 0, sizeof(UiListView)); |
|
| 862 listview->obj = obj; |
|
| 863 listview->widget = view; |
|
| 864 listview->var = var; |
|
| 865 listview->model = model; |
863 listview->model = model; |
| 866 listview->selection.count = 0; |
|
| 867 listview->selection.rows = NULL; |
|
| 868 g_signal_connect( |
864 g_signal_connect( |
| 869 view, |
865 view, |
| 870 "destroy", |
866 "destroy", |
| 871 G_CALLBACK(ui_listview_destroy), |
867 G_CALLBACK(ui_listview_destroy), |
| 872 listview); |
868 listview); |
| |
869 |
| |
870 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST); |
| |
871 |
| |
872 // init listview |
| |
873 listview->widget = view; |
| |
874 listview->var = var; |
| |
875 |
| |
876 UiList *list = var ? var->value : NULL; |
| |
877 GtkListStore *listmodel = create_list_store(listview, list); |
| |
878 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
| |
879 g_object_unref(listmodel); |
| 873 |
880 |
| 874 // bind var |
881 // bind var |
| 875 list->update = ui_listview_update; |
882 list->update = ui_listview_update; |
| 876 list->getselection = ui_listview_getselection; |
883 list->getselection = ui_listview_getselection; |
| 877 list->setselection = ui_listview_setselection; |
884 list->setselection = ui_listview_setselection; |
| 919 GTK_POLICY_AUTOMATIC, |
926 GTK_POLICY_AUTOMATIC, |
| 920 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS |
927 GTK_POLICY_AUTOMATIC); // GTK_POLICY_ALWAYS |
| 921 SCROLLEDWINDOW_SET_CHILD(scroll_area, view); |
928 SCROLLEDWINDOW_SET_CHILD(scroll_area, view); |
| 922 |
929 |
| 923 UI_APPLY_LAYOUT2(current, args); |
930 UI_APPLY_LAYOUT2(current, args); |
| 924 current->container->add(current->container, scroll_area, FALSE); |
931 current->container->add(current->container, scroll_area); |
| 925 |
932 |
| 926 // ct->current should point to view, not scroll_area, to make it possible |
933 // ct->current should point to view, not scroll_area, to make it possible |
| 927 // to add a context menu |
934 // to add a context menu |
| 928 current->container->current = view; |
935 current->container->current = view; |
| 929 |
936 |
| 1004 |
1011 |
| 1005 #endif |
1012 #endif |
| 1006 |
1013 |
| 1007 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST); |
1014 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST); |
| 1008 |
1015 |
| 1009 UiList *list = var ? var->value : NULL; |
|
| 1010 GtkListStore *listmodel = create_list_store(list, model); |
|
| 1011 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
|
| 1012 g_object_unref(listmodel); |
|
| 1013 |
|
| 1014 //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL); |
1016 //g_signal_connect(view, "drag-begin", G_CALLBACK(drag_begin), NULL); |
| 1015 //g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL); |
1017 //g_signal_connect(view, "drag-end", G_CALLBACK(drag_end), NULL); |
| 1016 |
1018 |
| 1017 // add TreeView as observer to the UiList to update the TreeView if the |
1019 // add TreeView as observer to the UiList to update the TreeView if the |
| 1018 // data changes |
1020 // data changes |
| 1019 UiListView *tableview = malloc(sizeof(UiListView)); |
1021 UiListView *tableview = create_listview(obj, args); |
| 1020 memset(tableview, 0, sizeof(UiListView)); |
|
| 1021 tableview->obj = obj; |
|
| 1022 tableview->widget = view; |
|
| 1023 tableview->var = var; |
|
| 1024 tableview->model = model; |
|
| 1025 tableview->ondragstart = args->ondragstart; |
|
| 1026 tableview->ondragstartdata = args->ondragstartdata; |
|
| 1027 tableview->ondragcomplete = args->ondragcomplete; |
|
| 1028 tableview->ondragcompletedata = args->ondragcompletedata; |
|
| 1029 tableview->ondrop = args->ondrop; |
|
| 1030 tableview->ondropdata = args->ondropdata; |
|
| 1031 tableview->selection.count = 0; |
|
| 1032 tableview->selection.rows = NULL; |
|
| 1033 g_signal_connect( |
1022 g_signal_connect( |
| 1034 view, |
1023 view, |
| 1035 "destroy", |
1024 "destroy", |
| 1036 G_CALLBACK(ui_listview_destroy), |
1025 G_CALLBACK(ui_listview_destroy), |
| 1037 tableview); |
1026 tableview); |
| |
1027 |
| |
1028 UiList *list = var ? var->value : NULL; |
| |
1029 GtkListStore *listmodel = create_list_store(tableview, list); |
| |
1030 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(listmodel)); |
| |
1031 g_object_unref(listmodel); |
| 1038 |
1032 |
| 1039 // bind var |
1033 // bind var |
| 1040 list->update = ui_listview_update; |
1034 list->update = ui_listview_update; |
| 1041 list->getselection = ui_listview_getselection; |
1035 list->getselection = ui_listview_getselection; |
| 1042 list->setselection = ui_listview_setselection; |
1036 list->setselection = ui_listview_setselection; |
| 1110 |
1104 |
| 1111 |
1105 |
| 1112 void ui_listview_update(UiList *list, int i) { |
1106 void ui_listview_update(UiList *list, int i) { |
| 1113 UiListView *view = list->obj; |
1107 UiListView *view = list->obj; |
| 1114 if(i < 0) { |
1108 if(i < 0) { |
| 1115 GtkListStore *store = create_list_store(list, view->model); |
1109 GtkListStore *store = create_list_store(view, list); |
| 1116 gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store)); |
1110 gtk_tree_view_set_model(GTK_TREE_VIEW(view->widget), GTK_TREE_MODEL(store)); |
| 1117 g_object_unref(G_OBJECT(store)); |
1111 g_object_unref(G_OBJECT(store)); |
| 1118 } else { |
1112 } else { |
| 1119 void *elm = list->get(list, i); |
1113 void *elm = list->get(list, i); |
| 1120 GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget)); |
1114 GtkTreeModel *store = gtk_tree_view_get_model(GTK_TREE_VIEW(view->widget)); |
| 1121 GtkTreeIter iter; |
1115 GtkTreeIter iter; |
| 1122 if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) { |
1116 if(gtk_tree_model_iter_nth_child(store, &iter, NULL, i)) { |
| 1123 update_list_row(GTK_LIST_STORE(store), &iter, view->model, list, elm, i); |
1117 update_list_row(view, GTK_LIST_STORE(store), &iter, list, elm, i); |
| 1124 } |
1118 } |
| 1125 } |
1119 } |
| 1126 } |
1120 } |
| 1127 |
1121 |
| 1128 UiListSelection ui_listview_getselection(UiList *list) { |
1122 UiListSelection ui_listview_getselection(UiList *list) { |
| 1148 /* --------------------------- ComboBox --------------------------- */ |
1142 /* --------------------------- ComboBox --------------------------- */ |
| 1149 |
1143 |
| 1150 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) { |
1144 UIWIDGET ui_combobox_create(UiObject *obj, UiListArgs *args) { |
| 1151 UiObject* current = uic_current_obj(obj); |
1145 UiObject* current = uic_current_obj(obj); |
| 1152 |
1146 |
| 1153 UiModel *model = ui_model(obj->ctx, UI_STRING, "", -1); |
1147 GtkWidget *combobox = gtk_combo_box_new(); |
| 1154 if(args->getvalue2) { |
1148 |
| 1155 model->getvalue2 = args->getvalue2; |
|
| 1156 model->getvalue2data = args->getvalue2data; |
|
| 1157 } else if(args->getvalue) { |
|
| 1158 model->getvalue = args->getvalue; |
|
| 1159 } else { |
|
| 1160 model->getvalue = ui_strmodel_getvalue; |
|
| 1161 } |
|
| 1162 |
|
| 1163 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST); |
|
| 1164 |
|
| 1165 GtkWidget *combobox = ui_create_combobox(obj, model, var, args->static_elements, args->static_nelm, args->onactivate, args->onactivatedata); |
|
| 1166 ui_set_name_and_style(combobox, args->name, args->style_class); |
1149 ui_set_name_and_style(combobox, args->name, args->style_class); |
| 1167 ui_set_widget_groups(obj->ctx, combobox, args->groups); |
1150 ui_set_widget_groups(obj->ctx, combobox, args->groups); |
| 1168 UI_APPLY_LAYOUT2(current, args); |
1151 UI_APPLY_LAYOUT2(current, args); |
| 1169 current->container->add(current->container, combobox, FALSE); |
1152 current->container->add(current->container, combobox); |
| 1170 current->container->current = combobox; |
1153 current->container->current = combobox; |
| 1171 return combobox; |
1154 |
| 1172 } |
1155 UiListView *listview = create_listview(obj, args); |
| 1173 |
1156 listview->widget = combobox; |
| 1174 GtkWidget* ui_create_combobox(UiObject *obj, UiModel *model, UiVar *var, char **elm, size_t nelm, ui_callback f, void *udata) { |
1157 listview->model = ui_model(obj->ctx, UI_STRING, "", -1); |
| 1175 GtkWidget *combobox = gtk_combo_box_new(); |
1158 g_signal_connect( |
| 1176 |
1159 combobox, |
| 1177 UiListView *uicbox = malloc(sizeof(UiListView)); |
1160 "destroy", |
| 1178 memset(uicbox, 0, sizeof(UiListView)); |
1161 G_CALLBACK(ui_listview_destroy), |
| 1179 uicbox->obj = obj; |
1162 listview); |
| 1180 uicbox->widget = combobox; |
1163 |
| 1181 |
1164 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args->list, args->varname, UI_VAR_LIST); |
| 1182 UiList *list = var ? var->value : NULL; |
1165 UiList *list = var ? var->value : NULL; |
| 1183 GtkListStore *listmodel = create_list_store(list, model); |
1166 GtkListStore *listmodel = create_list_store(listview, list); |
| 1184 |
1167 if(var) { |
| 1185 if(!list && elm && nelm > 0) { |
1168 listview->var = var; |
| 1186 listview_copy_static_elements(uicbox, elm, nelm); |
1169 list->update = ui_combobox_modelupdate; |
| 1187 for(int i=0;i<nelm;i++) { |
1170 list->getselection = ui_combobox_getselection; |
| |
1171 list->setselection = ui_combobox_setselection; |
| |
1172 list->obj = listview; |
| |
1173 list->update(list, -1); |
| |
1174 } else if(args->static_nelm > 0) { |
| |
1175 listview_copy_static_elements(listview, args->static_elements, args->static_nelm); |
| |
1176 for(int i=0;i<args->static_nelm;i++) { |
| 1188 GtkTreeIter iter; |
1177 GtkTreeIter iter; |
| 1189 GValue value = G_VALUE_INIT; |
1178 GValue value = G_VALUE_INIT; |
| 1190 gtk_list_store_insert(listmodel, &iter, -1); |
1179 gtk_list_store_insert(listmodel, &iter, -1); |
| 1191 g_value_init(&value, G_TYPE_STRING); |
1180 g_value_init(&value, G_TYPE_STRING); |
| 1192 g_value_set_string(&value, uicbox->elements[i]); |
1181 g_value_set_string(&value, listview->elements[i]); |
| 1193 gtk_list_store_set_value(listmodel, &iter, 0, &value); |
1182 gtk_list_store_set_value(listmodel, &iter, 0, &value); |
| 1194 } |
1183 } |
| 1195 } |
1184 } |
| 1196 |
1185 |
| 1197 if(listmodel) { |
1186 if(listmodel) { |
| 1198 gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(listmodel)); |
1187 gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(listmodel)); |
| 1199 g_object_unref(listmodel); |
1188 g_object_unref(listmodel); |
| 1200 } |
|
| 1201 |
|
| 1202 uicbox->var = var; |
|
| 1203 uicbox->model = model; |
|
| 1204 |
|
| 1205 g_signal_connect( |
|
| 1206 combobox, |
|
| 1207 "destroy", |
|
| 1208 G_CALLBACK(ui_combobox_destroy), |
|
| 1209 uicbox); |
|
| 1210 |
|
| 1211 // bind var |
|
| 1212 if(list) { |
|
| 1213 list->update = ui_combobox_modelupdate; |
|
| 1214 list->getselection = ui_combobox_getselection; |
|
| 1215 list->setselection = ui_combobox_setselection; |
|
| 1216 list->obj = uicbox; |
|
| 1217 } |
1189 } |
| 1218 |
1190 |
| 1219 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
1191 GtkCellRenderer *renderer = gtk_cell_renderer_text_new(); |
| 1220 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); |
1192 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); |
| 1221 gtk_cell_layout_set_attributes( |
1193 gtk_cell_layout_set_attributes( |
| 1799 uisublist.separator = sublist->separator; |
1758 uisublist.separator = sublist->separator; |
| 1800 uisublist.widgets = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
1759 uisublist.widgets = cxLinkedListCreateSimple(CX_STORE_POINTERS); |
| 1801 uisublist.listbox = uilistbox; |
1760 uisublist.listbox = uilistbox; |
| 1802 uisublist.userdata = sublist->userdata; |
1761 uisublist.userdata = sublist->userdata; |
| 1803 uisublist.index = cxListSize(sublists); |
1762 uisublist.index = cxListSize(sublists); |
| 1804 |
1763 uisublist.startpos = 0; |
| |
1764 cxListAdd(sublists, &uisublist); |
| |
1765 |
| 1805 // bind UiList |
1766 // bind UiList |
| 1806 UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(sublists)-1); |
1767 UiListBoxSubList *sublist_ptr = cxListAt(uilistbox->sublists, cxListSize(sublists)-1); |
| 1807 UiList *list = uisublist.var->value; |
1768 if(uisublist.var && uisublist.var->value) { |
| 1808 if(list) { |
1769 UiList *list = uisublist.var->value; |
| 1809 list->obj = sublist_ptr; |
1770 list->obj = sublist_ptr; |
| 1810 list->update = ui_listbox_list_update; |
1771 list->update = ui_listbox_list_update; |
| 1811 } |
1772 } |
| 1812 |
|
| 1813 cxListAdd(sublists, &uisublist); |
|
| 1814 } |
1773 } |
| 1815 |
1774 |
| 1816 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) { |
1775 UIEXPORT UIWIDGET ui_sourcelist_create(UiObject *obj, UiSourceListArgs *args) { |
| 1817 UiObject* current = uic_current_obj(obj); |
1776 UiObject* current = uic_current_obj(obj); |
| 1818 |
1777 |
| 1950 if(i.index > to) { |
1914 if(i.index > to) { |
| 1951 break; |
1915 break; |
| 1952 } |
1916 } |
| 1953 |
1917 |
| 1954 // reload sublist |
1918 // reload sublist |
| |
1919 sublist->startpos = pos; |
| 1955 ui_listbox_update_sublist(listbox, sublist, pos); |
1920 ui_listbox_update_sublist(listbox, sublist, pos); |
| 1956 pos += sublist->numitems; |
1921 pos += sublist->numitems; |
| |
1922 } |
| |
1923 } |
| |
1924 |
| |
1925 static void listbox_button_clicked(GtkWidget *widget, UiEventDataExt *data) { |
| |
1926 UiListBoxSubList *sublist = data->customdata0; |
| |
1927 |
| |
1928 UiSubListEventData eventdata; |
| |
1929 eventdata.list = sublist->var->value; |
| |
1930 eventdata.sublist_index = sublist->index; |
| |
1931 eventdata.row_index = data->value0; |
| |
1932 eventdata.sublist_userdata = sublist->userdata; |
| |
1933 eventdata.row_data = eventdata.list->get(eventdata.list, eventdata.row_index); |
| |
1934 eventdata.event_data = data->customdata2; |
| |
1935 |
| |
1936 UiEvent event; |
| |
1937 event.obj = data->obj; |
| |
1938 event.window = event.obj->window; |
| |
1939 event.document = event.obj->ctx->document; |
| |
1940 event.eventdata = &eventdata; |
| |
1941 event.eventdatatype = UI_EVENT_DATA_SUBLIST; |
| |
1942 event.intval = data->value0; |
| |
1943 event.set = ui_get_setop(); |
| |
1944 |
| |
1945 if(data->callback2) { |
| |
1946 data->callback2(&event, data->userdata2); |
| 1957 } |
1947 } |
| 1958 } |
1948 } |
| 1959 |
1949 |
| 1960 static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *sublist, UiSubListItem *item, int index) { |
1950 static GtkWidget* create_listbox_row(UiListBox *listbox, UiListBoxSubList *sublist, UiSubListItem *item, int index) { |
| 1961 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); |
1951 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); |
| 1989 G_CALLBACK(ui_destroy_userdata), |
1981 G_CALLBACK(ui_destroy_userdata), |
| 1990 event); |
1982 event); |
| 1991 |
1983 |
| 1992 g_object_set_data(G_OBJECT(row), "ui-listbox-row-eventdata", event); |
1984 g_object_set_data(G_OBJECT(row), "ui-listbox-row-eventdata", event); |
| 1993 |
1985 |
| |
1986 // badge |
| |
1987 if(item->badge) { |
| |
1988 GtkWidget *badge = gtk_label_new(item->badge); |
| |
1989 WIDGET_ADD_CSS_CLASS(badge, "ui-badge"); |
| |
1990 #if GTK_CHECK_VERSION(4, 0, 0) |
| |
1991 gtk_widget_set_valign(badge, GTK_ALIGN_CENTER); |
| |
1992 BOX_ADD(hbox, badge); |
| |
1993 #else |
| |
1994 GtkWidget *align = gtk_alignment_new(0.5, 0.5, 0, 0); |
| |
1995 gtk_container_add(GTK_CONTAINER(align), badge); |
| |
1996 BOX_ADD(hbox, align); |
| |
1997 #endif |
| |
1998 } |
| |
1999 // button |
| |
2000 if(item->button_icon || item->button_label) { |
| |
2001 GtkWidget *button = gtk_button_new(); |
| |
2002 gtk_button_set_label(GTK_BUTTON(button), item->button_label); |
| |
2003 ui_button_set_icon_name(button, item->button_icon); |
| |
2004 WIDGET_ADD_CSS_CLASS(button, "flat"); |
| |
2005 BOX_ADD(hbox, button); |
| |
2006 g_signal_connect( |
| |
2007 button, |
| |
2008 "clicked", |
| |
2009 G_CALLBACK(listbox_button_clicked), |
| |
2010 event |
| |
2011 ); |
| |
2012 } |
| |
2013 |
| 1994 return row; |
2014 return row; |
| 1995 } |
2015 } |
| 1996 |
2016 |
| 1997 void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index) { |
2017 void ui_listbox_update_sublist(UiListBox *listbox, UiListBoxSubList *sublist, size_t listbox_insert_index) { |
| 1998 // clear sublist |
2018 // clear sublist |
| 2003 cxListClear(sublist->widgets); |
2023 cxListClear(sublist->widgets); |
| 2004 |
2024 |
| 2005 sublist->numitems = 0; |
2025 sublist->numitems = 0; |
| 2006 |
2026 |
| 2007 // create items for each UiList element |
2027 // create items for each UiList element |
| |
2028 if(!sublist->var) { |
| |
2029 return; |
| |
2030 } |
| 2008 UiList *list = sublist->var->value; |
2031 UiList *list = sublist->var->value; |
| 2009 if(!list) { |
2032 if(!list) { |
| 2010 return; |
2033 return; |
| 2011 } |
2034 } |
| 2012 |
2035 |
| 2013 size_t index = 0; |
2036 size_t index = 0; |
| 2014 void *elm = list->first(list); |
2037 void *elm = list->first(list); |
| |
2038 |
| |
2039 if(!elm && sublist->header) { |
| |
2040 // empty row for header |
| |
2041 GtkWidget *row = gtk_list_box_row_new(); |
| |
2042 cxListAdd(sublist->widgets, row); |
| |
2043 g_object_set_data(G_OBJECT(row), "ui_listbox", listbox); |
| |
2044 g_object_set_data(G_OBJECT(row), "ui_listbox_sublist", sublist); |
| |
2045 intptr_t rowindex = listbox_insert_index + index; |
| |
2046 g_object_set_data(G_OBJECT(row), "ui_listbox_row_index", (gpointer)rowindex); |
| |
2047 gtk_list_box_insert(listbox->listbox, row, listbox_insert_index + index); |
| |
2048 sublist->numitems = 1; |
| |
2049 return; |
| |
2050 } |
| |
2051 |
| 2015 while(elm) { |
2052 while(elm) { |
| 2016 UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL }; |
2053 UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL }; |
| 2017 if(listbox->getvalue) { |
2054 if(listbox->getvalue) { |
| 2018 listbox->getvalue(list, sublist->userdata, elm, index, &item, listbox->getvaluedata); |
2055 listbox->getvalue(list, sublist->userdata, elm, index, &item, listbox->getvaluedata); |
| 2019 } else { |
2056 } else { |