| 121 } |
122 } |
| 122 |
123 |
| 123 return tableview; |
124 return tableview; |
| 124 } |
125 } |
| 125 |
126 |
| 126 static UiListView* create_treeview(UiObject *obj, UiTreeArgs *args) { |
|
| 127 UiListView *treeview = malloc(sizeof(UiListView)); |
|
| 128 memset(treeview, 0, sizeof(UiListView)); |
|
| 129 treeview->obj = obj; |
|
| 130 treeview->model = args->model; |
|
| 131 treeview->multiselection = args->multiselection; |
|
| 132 treeview->onactivate = args->onactivate; |
|
| 133 treeview->onactivatedata = args->onactivatedata; |
|
| 134 treeview->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL; |
|
| 135 treeview->onselection = args->onselection; |
|
| 136 treeview->onselectiondata = args->onselectiondata; |
|
| 137 treeview->onselection_action = args->onselection_action ? strdup(args->onselection_action) : NULL; |
|
| 138 treeview->ondragstart = args->ondragstart; |
|
| 139 treeview->ondragstartdata = args->ondragstartdata; |
|
| 140 treeview->ondragstart_action = args->ondragstart_action ? strdup(args->ondragstart_action) : NULL; |
|
| 141 treeview->ondragcomplete = args->ondragcomplete; |
|
| 142 treeview->ondragcompletedata = args->ondragcompletedata; |
|
| 143 treeview->ondragcomplete_action = args->ondragcomplete_action ? strdup(args->ondragcomplete_action) : NULL; |
|
| 144 treeview->ondrop = args->ondrop; |
|
| 145 treeview->ondropdata = args->ondropdata; |
|
| 146 treeview->ondrop_action = args->ondrop_action ? strdup(args->ondrop_action) : NULL; |
|
| 147 treeview->selection.count = 0; |
|
| 148 treeview->selection.rows = NULL; |
|
| 149 treeview->current_row = -1; |
|
| 150 |
|
| 151 #if GTK_CHECK_VERSION(4, 0, 0) |
|
| 152 treeview->coldata.listview = treeview; |
|
| 153 treeview->coldata.column = 0; |
|
| 154 #endif |
|
| 155 |
|
| 156 if(args->getvalue != NULL) { |
|
| 157 treeview->getvalue = args->getvalue; |
|
| 158 treeview->getvaluedata = args->getvaluedata; |
|
| 159 } else { |
|
| 160 args->getvalue = ui_null_getvalue; |
|
| 161 } |
|
| 162 |
|
| 163 treeview->istreeview = TRUE; |
|
| 164 treeview->getdepth = args->getdepth; |
|
| 165 treeview->getdepthdata = args->getdepthdata; |
|
| 166 |
|
| 167 return treeview; |
|
| 168 } |
|
| 169 |
|
| 170 #if GTK_CHECK_VERSION(4, 10, 0) |
127 #if GTK_CHECK_VERSION(4, 10, 0) |
| 171 |
128 |
| 172 |
129 |
| 173 /* BEGIN GObject wrapper for generic pointers */ |
130 /* BEGIN GObject wrapper for generic pointers */ |
| |
131 |
| |
132 typedef struct _ObjWrapper { |
| |
133 GObject parent_instance; |
| |
134 GListStore *children; |
| |
135 void *data; |
| |
136 int i; |
| |
137 } ObjWrapper; |
| 174 |
138 |
| 175 typedef struct _ObjWrapperClass { |
139 typedef struct _ObjWrapperClass { |
| 176 GObjectClass parent_class; |
140 GObjectClass parent_class; |
| 177 } ObjWrapperClass; |
141 } ObjWrapperClass; |
| 178 |
142 |
| 800 |
765 |
| 801 |
766 |
| 802 |
767 |
| 803 UIWIDGET ui_treeview_create(UiObject *obj, UiTreeArgs *args) { |
768 UIWIDGET ui_treeview_create(UiObject *obj, UiTreeArgs *args) { |
| 804 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
769 GListStore *ls = g_list_store_new(G_TYPE_OBJECT); |
| 805 //g_list_store_append(ls, v1); |
|
| 806 |
770 |
| 807 // create obj to store all relevant data we need for handling events |
771 // create obj to store all relevant data we need for handling events |
| 808 // and list updates |
772 // and list updates |
| 809 UiListView *tableview = create_treeview(obj, args); |
773 UiListView *treeview = ui_create_treeview(obj, args); |
| 810 |
774 |
| 811 GtkSelectionModel *selection_model = create_selection_model(tableview, ls, args->multiselection); |
775 GtkSelectionModel *selection_model = create_selection_model(treeview, ls, args->multiselection); |
| 812 GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model)); |
776 GtkWidget *view = gtk_column_view_new(GTK_SELECTION_MODEL(selection_model)); |
| 813 if(!args->show_header) { |
777 if(!args->show_header) { |
| 814 gtk_widget_set_visible(gtk_widget_get_first_child(view), FALSE); |
778 gtk_widget_set_visible(gtk_widget_get_first_child(view), FALSE); |
| 815 } |
779 } |
| 816 |
780 |
| 817 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); |
781 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); |
| 818 |
782 |
| 819 // init tableview |
783 // init tableview |
| 820 tableview->widget = view; |
784 treeview->widget = view; |
| 821 tableview->var = var; |
785 treeview->var = var; |
| 822 tableview->liststore = ls; |
786 treeview->liststore = ls; |
| 823 tableview->selectionmodel = selection_model; |
787 treeview->selectionmodel = selection_model; |
| 824 g_signal_connect( |
788 g_signal_connect( |
| 825 view, |
789 view, |
| 826 "destroy", |
790 "destroy", |
| 827 G_CALLBACK(ui_listview_destroy), |
791 G_CALLBACK(ui_listview_destroy), |
| 828 tableview); |
792 treeview); |
| 829 |
793 |
| 830 |
794 |
| 831 // create columns from UiModel |
795 // create columns from UiModel |
| 832 UiModel *model = args->model; |
796 UiModel *model = args->model; |
| 833 int columns = 0; |
797 int columns = 0; |
| 834 if(model) { |
798 if(model) { |
| 835 columns = model->columns; |
799 columns = model->columns; |
| 836 ui_model_add_observer(model, ui_listview_update_model, tableview); |
800 ui_model_add_observer(model, ui_listview_update_model, treeview); |
| 837 } |
801 } |
| 838 |
802 |
| 839 tableview->columns = calloc(columns, sizeof(int)); |
803 treeview->columns = calloc(columns, sizeof(int)); |
| 840 tableview->numcolumns = columns; |
804 treeview->numcolumns = columns; |
| 841 |
805 |
| 842 tableview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
806 treeview->bound_rows = cxHashMapCreate(NULL, CX_STORE_POINTERS, 128); |
| 843 tableview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
807 treeview->bound_rows->collection.simple_destructor = (cx_destructor_func)free; |
| 844 |
808 |
| 845 int addi = 0; |
809 int addi = 0; |
| 846 for(int i=0;i<columns;i++) { |
810 for(int i=0;i<columns;i++) { |
| 847 tableview->columns[i] = i+addi; |
811 treeview->columns[i] = i+addi; |
| 848 |
812 |
| 849 if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) { |
813 if(model->types[i] == UI_ICON_TEXT || model->types[i] == UI_ICON_TEXT_FREE) { |
| 850 // icon+text has 2 data columns |
814 // icon+text has 2 data columns |
| 851 addi++; |
815 addi++; |
| 852 } |
816 } |
| 853 |
817 |
| 854 add_column(tableview, i); |
818 add_column(treeview, i); |
| 855 } |
819 } |
| 856 |
820 |
| 857 // bind listview to list |
821 // bind listview to list |
| 858 if(var && var->value) { |
822 if(var && var->value) { |
| 859 UiList *list = var->value; |
823 UiList *list = var->value; |
| 860 |
824 |
| 861 list->obj = tableview; |
825 list->obj = treeview; |
| 862 list->update = ui_listview_update2; |
826 list->update = ui_listview_update2; |
| 863 list->getselection = ui_listview_getselection2; |
827 list->getselection = ui_listview_getselection2; |
| 864 list->setselection = ui_listview_setselection2; |
828 list->setselection = ui_listview_setselection2; |
| 865 |
829 |
| 866 ui_update_liststore(ls, list); |
830 ui_update_tree_liststore(ls, list); |
| 867 } |
831 } |
| 868 |
832 |
| 869 // event handling |
833 // event handling |
| 870 if(args->onactivate || args->onactivate_action) { |
834 if(args->onactivate || args->onactivate_action) { |
| 871 g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), tableview); |
835 g_signal_connect(view, "activate", G_CALLBACK(ui_columnview_activate), treeview); |
| 872 } |
836 } |
| 873 if(args->contextmenu) { |
837 if(args->contextmenu) { |
| 874 UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view); |
838 UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, view); |
| 875 ui_widget_set_contextmenu(view, menu); |
839 ui_widget_set_contextmenu(view, menu); |
| 876 } |
840 } |
| 3066 |
3034 |
| 3067 if(data->callback) { |
3035 if(data->callback) { |
| 3068 data->callback(&event, data->userdata); |
3036 data->callback(&event, data->userdata); |
| 3069 } |
3037 } |
| 3070 } |
3038 } |
| |
3039 |
| |
3040 /* ------------------------------ SourceList2 ------------------------------ */ |
| |
3041 |
| |
3042 static void ui_destroy_sourcelist2(GtkWidget *w, UiListBox2 *v) { |
| |
3043 cxListFree(v->rows); |
| |
3044 free(v->onactivate_action); |
| |
3045 free(v->onbuttonclick_action); |
| |
3046 free(v); |
| |
3047 } |
| |
3048 |
| |
3049 UIWIDGET ui_sourcelist2_create(UiObject *obj, UiSourceList2Args *args) { |
| |
3050 #ifdef UI_GTK3 |
| |
3051 GtkWidget *listbox = g_object_new(ui_sidebar_list_box_get_type(), NULL); |
| |
3052 #else |
| |
3053 GtkWidget *listbox = gtk_list_box_new(); |
| |
3054 #endif |
| |
3055 if(!args->style_class) { |
| |
3056 #if GTK_MAJOR_VERSION >= 4 |
| |
3057 WIDGET_ADD_CSS_CLASS(listbox, "navigation-sidebar"); |
| |
3058 #else |
| |
3059 WIDGET_ADD_CSS_CLASS(listbox, "sidebar"); |
| |
3060 #endif |
| |
3061 } |
| |
3062 GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); |
| |
3063 SCROLLEDWINDOW_SET_CHILD(scroll_area, listbox); |
| |
3064 |
| |
3065 ui_set_name_and_style(listbox, args->name, args->style_class); |
| |
3066 ui_set_widget_states(obj->ctx, listbox, args->states); |
| |
3067 UiContainerPrivate *ct = (UiContainerPrivate*)obj->container_end; |
| |
3068 UiLayout layout = UI_ARGS2LAYOUT(args); |
| |
3069 ct->add(ct, scroll_area, &layout); |
| |
3070 |
| |
3071 UiListBox2 *uilistbox = malloc(sizeof(UiListBox2)); |
| |
3072 uilistbox->obj = obj; |
| |
3073 uilistbox->listbox = GTK_LIST_BOX(listbox); |
| |
3074 uilistbox->rows = cxArrayListCreate(NULL, CX_STORE_POINTERS, 64); |
| |
3075 uilistbox->getvalue = args->getvalue; |
| |
3076 uilistbox->getvaluedata = args->getvaluedata; |
| |
3077 uilistbox->getdepth = args->getdepth; |
| |
3078 uilistbox->getdepthdata = args->getdepthdata; |
| |
3079 uilistbox->onactivate = args->onactivate; |
| |
3080 uilistbox->onactivatedata = args->onactivatedata; |
| |
3081 uilistbox->onactivate_action = args->onactivate_action ? strdup(args->onactivate_action) : NULL; |
| |
3082 uilistbox->onbuttonclick = args->onbuttonclick; |
| |
3083 uilistbox->onbuttonclickdata = args->onbuttonclickdata; |
| |
3084 uilistbox->onbuttonclick_action = args->onbuttonclick_action ? strdup(args->onbuttonclick_action) : NULL; |
| |
3085 |
| |
3086 UiVar* var = uic_widget_var(obj->ctx, obj->ctx, args->list, args->varname, UI_VAR_LIST); |
| |
3087 uilistbox->var = var; |
| |
3088 if(var) { |
| |
3089 UiList *list = var->value; |
| |
3090 list->update = ui_listbox2_update; |
| |
3091 list->getselection = ui_listbox2_getselection; |
| |
3092 list->setselection = ui_listbox2_setselection; |
| |
3093 list->obj = uilistbox; |
| |
3094 ui_listbox2_update(list, -1); |
| |
3095 } |
| |
3096 |
| |
3097 // register uilistbox for both widgets, so it doesn't matter which |
| |
3098 // widget is used later |
| |
3099 g_object_set_data(G_OBJECT(scroll_area), "ui_listbox", uilistbox); |
| |
3100 g_object_set_data(G_OBJECT(listbox), "ui_listbox", uilistbox); |
| |
3101 |
| |
3102 if(args->contextmenu) { |
| |
3103 UIMENU menu = ui_contextmenu_create(args->contextmenu, obj, listbox); |
| |
3104 ui_widget_set_contextmenu(listbox, menu); |
| |
3105 } |
| |
3106 |
| |
3107 // signals |
| |
3108 g_signal_connect( |
| |
3109 listbox, |
| |
3110 "destroy", |
| |
3111 G_CALLBACK(ui_destroy_sourcelist2), |
| |
3112 uilistbox); |
| |
3113 |
| |
3114 if(args->onactivate) { |
| |
3115 g_signal_connect( |
| |
3116 listbox, |
| |
3117 "row-activated", |
| |
3118 G_CALLBACK(ui_listbox2_row_activate), |
| |
3119 NULL); |
| |
3120 } |
| |
3121 |
| |
3122 return scroll_area; |
| |
3123 } |
| |
3124 |
| |
3125 |
| |
3126 static int listbox2_update_item(UiListBox2 *listbox, GtkWidget *row, UiList *list, void *elm, int index) { |
| |
3127 UiSubListItem item = { NULL, NULL, NULL, NULL, NULL, NULL }; |
| |
3128 if(listbox->getvalue) { |
| |
3129 listbox->getvalue(list,elm, index, &item, listbox->getvaluedata); |
| |
3130 } |
| |
3131 |
| |
3132 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); |
| |
3133 |
| |
3134 return 0; |
| |
3135 } |
| |
3136 |
| |
3137 static void listbox2_update_all(UiListBox2 *listbox) { |
| |
3138 gtk_list_box_remove_all(listbox->listbox); |
| |
3139 cxListClear(listbox->rows); |
| |
3140 if(!listbox->var) { |
| |
3141 return; |
| |
3142 } |
| |
3143 UiList *list = listbox->var->value; |
| |
3144 if(!list) { |
| |
3145 return; |
| |
3146 } |
| |
3147 |
| |
3148 |
| |
3149 int index = 0; |
| |
3150 void *elm = list->first(list); |
| |
3151 while(elm) { |
| |
3152 GtkWidget *row = gtk_list_box_row_new(); |
| |
3153 cxListAdd(listbox->rows, row); |
| |
3154 gtk_list_box_append(listbox->listbox, row); |
| |
3155 int node_depth = listbox2_update_item(listbox, row, list, elm, index); |
| |
3156 |
| |
3157 elm = list->next(list); |
| |
3158 index++; |
| |
3159 } |
| |
3160 } |
| |
3161 |
| |
3162 void ui_listbox2_row_activate(GtkListBox *self, GtkListBoxRow *row, gpointer user_data) { |
| |
3163 |
| |
3164 } |
| |
3165 |
| |
3166 |
| |
3167 void ui_listbox2_update(UiList *list, int i) { |
| |
3168 UiListBox2 *listbox = list->obj; |
| |
3169 if(i >= 0) { |
| |
3170 // TODO |
| |
3171 } else { |
| |
3172 listbox2_update_all(listbox); |
| |
3173 } |
| |
3174 } |
| |
3175 |
| |
3176 UiListSelection ui_listbox2_getselection(UiList *list) { |
| |
3177 |
| |
3178 } |
| |
3179 |
| |
3180 void ui_listbox2_setselection(UiList *list, UiListSelection selection) { |
| |
3181 |
| |
3182 } |