Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_panel.c
| Show First 20 Lines • Show All 210 Lines • ▼ Show 20 Lines | |||||
| } | } | ||||
| /********* Functions for instanced panels. ***********/ | /********* Functions for instanced panels. ***********/ | ||||
| static Panel *UI_panel_add_instanced_ex(ScrArea *area, | static Panel *UI_panel_add_instanced_ex(ScrArea *area, | ||||
| ARegion *region, | ARegion *region, | ||||
| ListBase *panels, | ListBase *panels, | ||||
| PanelType *panel_type, | PanelType *panel_type, | ||||
| int list_index, | |||||
| PointerRNA *custom_data) | PointerRNA *custom_data) | ||||
| { | { | ||||
| Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel"); | Panel *panel = MEM_callocN(sizeof(Panel), "instanced panel"); | ||||
| panel->type = panel_type; | panel->type = panel_type; | ||||
| BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname)); | BLI_strncpy(panel->panelname, panel_type->idname, sizeof(panel->panelname)); | ||||
| panel->runtime.list_index = list_index; | |||||
| panel->runtime.custom_data_ptr = custom_data; | panel->runtime.custom_data_ptr = custom_data; | ||||
| /* Add the panel's children too. Although they aren't instanced panels, we can still use this | /* Add the panel's children too. Although they aren't instanced panels, we can still use this | ||||
| * function to create them, as UI_panel_begin does other things we don't need to do. */ | * function to create them, as UI_panel_begin does other things we don't need to do. */ | ||||
| LISTBASE_FOREACH (LinkData *, child, &panel_type->children) { | LISTBASE_FOREACH (LinkData *, child, &panel_type->children) { | ||||
| PanelType *child_type = child->data; | PanelType *child_type = child->data; | ||||
| UI_panel_add_instanced_ex(area, region, &panel->children, child_type, list_index, custom_data); | UI_panel_add_instanced_ex(area, region, &panel->children, child_type, custom_data); | ||||
| } | } | ||||
| /* Make sure the panel is added to the end of the display-order as well. This is needed for | /* Make sure the panel is added to the end of the display-order as well. This is needed for | ||||
| * loading existing files. | * loading existing files. | ||||
| * | * | ||||
| * Note: We could use special behavior to place it after the panel that starts the list of | * Note: We could use special behavior to place it after the panel that starts the list of | ||||
| * instanced panels, but that would add complexity that isn't needed for now. */ | * instanced panels, but that would add complexity that isn't needed for now. */ | ||||
| int max_sortorder = 0; | int max_sortorder = 0; | ||||
| LISTBASE_FOREACH (Panel *, existing_panel, panels) { | LISTBASE_FOREACH (Panel *, existing_panel, panels) { | ||||
| if (existing_panel->sortorder > max_sortorder) { | if (existing_panel->sortorder > max_sortorder) { | ||||
| max_sortorder = existing_panel->sortorder; | max_sortorder = existing_panel->sortorder; | ||||
| } | } | ||||
| } | } | ||||
| panel->sortorder = max_sortorder + 1; | panel->sortorder = max_sortorder + 1; | ||||
| BLI_addtail(panels, panel); | BLI_addtail(panels, panel); | ||||
| return panel; | return panel; | ||||
| } | } | ||||
| /** | /** | ||||
| * Called in situations where panels need to be added dynamically rather than having only one panel | * Called in situations where panels need to be added dynamically rather than having only one panel | ||||
| * corresponding to each PanelType. | * corresponding to each PanelType. | ||||
| */ | */ | ||||
| Panel *UI_panel_add_instanced(ScrArea *area, | Panel *UI_panel_add_instanced( | ||||
| ARegion *region, | ScrArea *area, ARegion *region, ListBase *panels, char *panel_idname, PointerRNA *custom_data) | ||||
| ListBase *panels, | |||||
| char *panel_idname, | |||||
| int list_index, | |||||
| PointerRNA *custom_data) | |||||
| { | { | ||||
| ARegionType *region_type = region->type; | ARegionType *region_type = region->type; | ||||
| PanelType *panel_type = BLI_findstring( | PanelType *panel_type = BLI_findstring( | ||||
| ®ion_type->paneltypes, panel_idname, offsetof(PanelType, idname)); | ®ion_type->paneltypes, panel_idname, offsetof(PanelType, idname)); | ||||
| if (panel_type == NULL) { | if (panel_type == NULL) { | ||||
| printf("Panel type '%s' not found.\n", panel_idname); | printf("Panel type '%s' not found.\n", panel_idname); | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| return UI_panel_add_instanced_ex(area, region, panels, panel_type, list_index, custom_data); | return UI_panel_add_instanced_ex(area, region, panels, panel_type, custom_data); | ||||
| } | } | ||||
| /** | /** | ||||
| * Find a unique key to append to the idname for the lookup to the panel's #uiBlock. Needed for | * Find a unique key to append to the idname for the lookup to the panel's #uiBlock. Needed for | ||||
| * instanced panels, where there can be multiple with the same type and idname. | * instanced panels, where there can be multiple with the same type and idname. | ||||
| */ | */ | ||||
| void UI_list_panel_unique_str(Panel *panel, char *r_name) | void UI_list_panel_unique_str(Panel *panel, char *r_name) | ||||
HooglyBoogly: I should just delete this function and set the panel name to include the index in… | |||||
| { | { | ||||
| snprintf(r_name, LIST_PANEL_UNIQUE_STR_LEN, "%d", panel->runtime.list_index); | /* The panel sortorder will be unique for a specific panel type because the instanced | ||||
| } | * panel list is regenerated for every change in the data order / length. */ | ||||
| snprintf(r_name, INSTANCED_PANEL_UNIQUE_STR_LEN, "%d", panel->sortorder); | |||||
| /** | |||||
| * Remove the #uiBlock corresponding to a panel. The lookup is needed because panels don't store | |||||
| * a reference to their corresponding #uiBlock. | |||||
| */ | |||||
| static void panel_free_block(const bContext *C, ARegion *region, Panel *panel) | |||||
| { | |||||
| BLI_assert(panel->type); | |||||
| char block_name[BKE_ST_MAXNAME + LIST_PANEL_UNIQUE_STR_LEN]; | |||||
| strncpy(block_name, panel->type->idname, BKE_ST_MAXNAME); | |||||
| char unique_panel_str[LIST_PANEL_UNIQUE_STR_LEN]; | |||||
| UI_list_panel_unique_str(panel, unique_panel_str); | |||||
| strncat(block_name, unique_panel_str, LIST_PANEL_UNIQUE_STR_LEN); | |||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | |||||
| if (STREQ(block->name, block_name)) { | |||||
| BLI_remlink(®ion->uiblocks, block); | |||||
| UI_block_free(C, block); | |||||
| break; /* Only delete one block for this panel. */ | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| * Free a panel and it's children. Custom data is shared by the panel and its children | * Free a panel and it's children. Custom data is shared by the panel and its children | ||||
| * and is freed by #UI_panels_free_instanced. | * and is freed by #UI_panels_free_instanced. | ||||
| * | * | ||||
| * \note The only panels that should need to be deleted at runtime are panels with the | * \note The only panels that should need to be deleted at runtime are panels with the | ||||
| * #PNL_INSTANCED flag set. | * #PNL_INSTANCED flag set. | ||||
| */ | */ | ||||
| static void panel_delete(const bContext *C, ARegion *region, ListBase *panels, Panel *panel) | static void panel_delete(const bContext *C, ARegion *region, ListBase *panels, Panel *panel) | ||||
| { | { | ||||
| /* Recursively delete children. */ | /* Recursively delete children. */ | ||||
| LISTBASE_FOREACH_MUTABLE (Panel *, child, &panel->children) { | LISTBASE_FOREACH_MUTABLE (Panel *, child, &panel->children) { | ||||
| panel_delete(C, region, &panel->children, child); | panel_delete(C, region, &panel->children, child); | ||||
| } | } | ||||
| BLI_freelistN(&panel->children); | BLI_freelistN(&panel->children); | ||||
| panel_free_block(C, region, panel); | |||||
Not Done Inline ActionsWhy isn't this needed anymore? When is the block freed now? Severin: Why isn't this needed anymore? When is the block freed now? | |||||
Done Inline ActionsSorry for putting this in here, it was related at one point developing these changes but not anymore. Originally I thought I had to remove the block immediately when the panel was removed, but we can just leave it and it will be removed later by ED_region_do_draw and the like. Removing it is nice because it reduces reliance on the somewhat hacky UI_list_panel_unique_str and results in fewer unnecessary string lookups. I can commit this separately. HooglyBoogly: Sorry for putting this in here, it was related at one point developing these changes but not… | |||||
| BLI_remlink(panels, panel); | BLI_remlink(panels, panel); | ||||
| if (panel->activedata) { | if (panel->activedata) { | ||||
| MEM_freeN(panel->activedata); | MEM_freeN(panel->activedata); | ||||
| } | } | ||||
| MEM_freeN(panel); | MEM_freeN(panel); | ||||
| } | } | ||||
| /** | /** | ||||
| ▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | static void reorder_instanced_panel_list(bContext *C, ARegion *region, Panel *drag_panel) | ||||
| /* Free panel sort array. */ | /* Free panel sort array. */ | ||||
| int i = 0; | int i = 0; | ||||
| for (sort_index = panel_sort; i < list_panels_len; i++, sort_index++) { | for (sort_index = panel_sort; i < list_panels_len; i++, sort_index++) { | ||||
| MEM_freeN(sort_index->panel); | MEM_freeN(sort_index->panel); | ||||
| } | } | ||||
| MEM_freeN(panel_sort); | MEM_freeN(panel_sort); | ||||
| /* Don't reorder the panel didn't change order after being dropped. */ | |||||
| if (move_to_index == drag_panel->runtime.list_index) { | |||||
| return; | |||||
| } | |||||
| /* Set the bit to tell the interface to instanced the list. */ | /* Set the bit to tell the interface to instanced the list. */ | ||||
| drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED; | drag_panel->flag |= PNL_INSTANCED_LIST_ORDER_CHANGED; | ||||
| /* Finally, move this panel's list item to the new index in its list. */ | /* Finally, move this panel's list item to the new index in its list. */ | ||||
| drag_panel->type->reorder(C, drag_panel, move_to_index); | drag_panel->type->reorder(C, drag_panel, move_to_index); | ||||
| } | } | ||||
| /** | /** | ||||
| ▲ Show 20 Lines • Show All 2,021 Lines • ▼ Show 20 Lines | void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data) | ||||
| /* Free the old custom data, which should be shared among all of the panel's sub-panels. */ | /* Free the old custom data, which should be shared among all of the panel's sub-panels. */ | ||||
| if (panel->runtime.custom_data_ptr != NULL) { | if (panel->runtime.custom_data_ptr != NULL) { | ||||
| MEM_freeN(panel->runtime.custom_data_ptr); | MEM_freeN(panel->runtime.custom_data_ptr); | ||||
| } | } | ||||
| ui_panel_custom_data_set_recursive(panel, custom_data); | ui_panel_custom_data_set_recursive(panel, custom_data); | ||||
| } | } | ||||
| PointerRNA *UI_panel_custom_data_get(const Panel *panel) | |||||
| { | |||||
| return panel->runtime.custom_data_ptr; | |||||
| } | |||||
| PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event) | PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event) | ||||
| { | { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| Panel *panel = NULL; | Panel *panel = NULL; | ||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| panel = block->panel; | panel = block->panel; | ||||
| if (panel == NULL) { | if (panel == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| int mx = event->x; | int mx = event->x; | ||||
| int my = event->y; | int my = event->y; | ||||
| ui_window_to_block(region, block, &mx, &my); | ui_window_to_block(region, block, &mx, &my); | ||||
| int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); | int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); | ||||
| if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { | if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (panel == NULL) { | if (panel == NULL) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| PointerRNA *customdata = panel->runtime.custom_data_ptr; | return UI_panel_custom_data_get(panel); | ||||
| return customdata; | |||||
| } | } | ||||
| /**************** window level modal panel interaction **************/ | /**************** window level modal panel interaction **************/ | ||||
| /* note, this is modal handler and should not swallow events for animation */ | /* note, this is modal handler and should not swallow events for animation */ | ||||
| static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) | static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) | ||||
| { | { | ||||
| Panel *panel = userdata; | Panel *panel = userdata; | ||||
| ▲ Show 20 Lines • Show All 119 Lines • Show Last 20 Lines | |||||
I should just delete this function and set the panel name to include the index in UI_panel_add_instanced_ex