944 return NULL; |
944 return NULL; |
945 } |
945 } |
946 |
946 |
947 |
947 |
948 |
948 |
|
949 /* -------------------- ItemList Container -------------------- */ |
|
950 |
|
951 static void remove_item(void *data, void *item) { |
|
952 UiGtkItemListContainer *ct = data; |
|
953 UiObject *obj = item; |
|
954 if(ct->remove_items) { |
|
955 BOX_REMOVE(ct->widget, obj->widget); |
|
956 } |
|
957 uic_object_destroy(obj); |
|
958 } |
|
959 |
|
960 static void update_itemlist(UiList *list, int c) { |
|
961 UiGtkItemListContainer *ct = list->obj; |
|
962 |
|
963 CxMap *new_items = cxHashMapCreateSimple(CX_STORE_POINTERS); |
|
964 new_items->collection.advanced_destructor = remove_item; |
|
965 new_items->collection.destructor_data = ct; |
|
966 |
|
967 // only create new widgets for new elements, so at first we have |
|
968 // to find which elements are new |
|
969 // check which elements in the list are already in the container |
|
970 void *elm = list->first(list); |
|
971 int j = 0; |
|
972 while(elm) { |
|
973 CxHashKey key = cx_hash_key(&elm, sizeof(void*)); |
|
974 UiObject *item_obj = cxMapRemoveAndGet(ct->current_items, key); |
|
975 if(item_obj) { |
|
976 g_object_ref(G_OBJECT(item_obj->widget)); |
|
977 BOX_REMOVE(ct->widget, item_obj->widget); |
|
978 cxMapPut(new_items, key, item_obj); |
|
979 } |
|
980 elm = list->next(list); |
|
981 j++; |
|
982 } |
|
983 |
|
984 // ct->current_items only contains elements, that are not in the list |
|
985 cxMapDestroy(ct->current_items); // calls destructor remove_item |
|
986 ct->current_items = new_items; |
|
987 |
|
988 // add all items |
|
989 int index = 0; |
|
990 elm = list->first(list); |
|
991 while(elm) { |
|
992 CxHashKey key = cx_hash_key(&elm, sizeof(void*)); |
|
993 UiObject *item_obj = cxMapGet(ct->current_items, key); |
|
994 if(item_obj) { |
|
995 // re-add previously created widget |
|
996 ui_box_container_add(ct->container, item_obj->widget, FALSE); |
|
997 } else { |
|
998 // create new widget and object for this list element |
|
999 CxMempool *mp = cxBasicMempoolCreate(256); |
|
1000 const CxAllocator *a = mp->allocator; |
|
1001 UiObject *obj = cxCalloc(a, 1, sizeof(UiObject)); |
|
1002 obj->ctx = uic_context(obj, mp); |
|
1003 obj->window = NULL; |
|
1004 obj->widget = ui_subcontainer_create( |
|
1005 ct->subcontainer, |
|
1006 obj, |
|
1007 ct->spacing, |
|
1008 ct->columnspacing, |
|
1009 ct->rowspacing, |
|
1010 ct->margin); |
|
1011 ui_box_container_add(ct->container, obj->widget, FALSE); |
|
1012 if(ct->create_ui) { |
|
1013 ct->create_ui(obj, index, elm, ct->userdata); |
|
1014 } |
|
1015 cxMapPut(new_items, key, obj); |
|
1016 } |
|
1017 elm = list->next(list); |
|
1018 index++; |
|
1019 } |
|
1020 } |
|
1021 |
|
1022 static void destroy_itemlist_container(GtkWidget *w, UiGtkItemListContainer *container) { |
|
1023 container->remove_items = FALSE; |
|
1024 cxMapDestroy(container->current_items); |
|
1025 free(container); |
|
1026 } |
|
1027 |
|
1028 UIWIDGET ui_itemlist_create(UiObject *obj, UiItemListContainerArgs args) { |
|
1029 UiObject *current = uic_current_obj(obj); |
|
1030 UiContainer *ct = current->container; |
|
1031 UI_APPLY_LAYOUT1(current, args); |
|
1032 |
|
1033 GtkWidget *box = args.container == UI_CONTAINER_VBOX ? ui_gtk_vbox_new(args.spacing) : ui_gtk_hbox_new(args.spacing); |
|
1034 ui_set_name_and_style(box, args.name, args.style_class); |
|
1035 GtkWidget *widget = args.margin > 0 ? ui_box_set_margin(box, args.margin) : box; |
|
1036 ct->add(ct, widget, TRUE); |
|
1037 |
|
1038 UiGtkItemListContainer *container = malloc(sizeof(UiGtkItemListContainer)); |
|
1039 container->parent = obj; |
|
1040 container->widget = box; |
|
1041 container->container = ui_box_container(current, box, args.container); |
|
1042 container->create_ui = args.create_ui; |
|
1043 container->userdata = args.userdata; |
|
1044 container->subcontainer = args.subcontainer; |
|
1045 container->current_items = cxHashMapCreateSimple(CX_STORE_POINTERS); |
|
1046 container->current_items->collection.advanced_destructor = remove_item; |
|
1047 container->current_items->collection.destructor_data = container; |
|
1048 container->margin = args.sub_margin; |
|
1049 container->spacing = args.sub_spacing; |
|
1050 container->columnspacing = args.sub_columnspacing; |
|
1051 container->rowspacing = args.sub_rowspacing; |
|
1052 container->remove_items = TRUE; |
|
1053 |
|
1054 UiVar* var = uic_widget_var(obj->ctx, current->ctx, args.value, args.varname, UI_VAR_LIST); |
|
1055 if(var) { |
|
1056 UiList *list = var->value; |
|
1057 list->obj = container; |
|
1058 list->update = update_itemlist; |
|
1059 update_itemlist(list, 0); |
|
1060 } |
|
1061 g_signal_connect( |
|
1062 box, |
|
1063 "destroy", |
|
1064 G_CALLBACK(destroy_itemlist_container), |
|
1065 container); |
|
1066 |
|
1067 return box; |
|
1068 } |
949 |
1069 |
950 |
1070 |
951 |
1071 |
952 /* |
1072 /* |
953 * -------------------- Layout Functions -------------------- |
1073 * -------------------- Layout Functions -------------------- |