diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_uilist_type.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_uilist_type.c | 95 |
1 files changed, 94 insertions, 1 deletions
diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c index 45c14c0bbe9..82ba4aa6e6f 100644 --- a/source/blender/windowmanager/intern/wm_uilist_type.c +++ b/source/blender/windowmanager/intern/wm_uilist_type.c @@ -21,16 +21,24 @@ */ #include <stdio.h> +#include <string.h> +#include "BLI_listbase.h" #include "BLI_sys_types.h" +#include "DNA_space_types.h" #include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" +#include "UI_interface.h" + #include "BLI_ghash.h" +#include "BLI_listbase.h" +#include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_main.h" #include "BKE_screen.h" #include "WM_api.h" @@ -60,8 +68,62 @@ bool WM_uilisttype_add(uiListType *ult) return 1; } -void WM_uilisttype_freelink(uiListType *ult) +static void wm_uilisttype_unlink_from_region(const uiListType *ult, ARegion *region) { + LISTBASE_FOREACH (uiList *, list, ®ion->ui_lists) { + if (list->type == ult) { + /* Don't delete the list, it's not just runtime data but stored in files. Freeing would make + * that data get lost. */ + list->type = NULL; + } + } +} + +static void wm_uilisttype_unlink_from_area(const uiListType *ult, ScrArea *area) +{ + LISTBASE_FOREACH (SpaceLink *, space_link, &area->spacedata) { + ListBase *regionbase = (space_link == area->spacedata.first) ? &area->regionbase : + &space_link->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { + wm_uilisttype_unlink_from_region(ult, region); + } + } +} + +/** + * For all lists representing \a ult, clear their `uiListType` pointer. Use when a list-type is + * deleted, so that the UI doesn't keep references to it. + * + * This is a common pattern for unregistering (usually .py defined) types at runtime, e.g. see + * #WM_gizmomaptype_group_unlink(). + * Note that unlike in some other cases using this pattern, we don't actually free the lists with + * type \a ult, we just clear the reference to the type. That's because UI-Lists are written to + * files and we don't want them to get lost together with their (user visible) settings. + */ +static void wm_uilisttype_unlink(Main *bmain, const uiListType *ult) +{ + for (wmWindowManager *wm = bmain->wm.first; wm != NULL; wm = wm->id.next) { + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + LISTBASE_FOREACH (ScrArea *, global_area, &win->global_areas.areabase) { + wm_uilisttype_unlink_from_area(ult, global_area); + } + } + } + + for (bScreen *screen = bmain->screens.first; screen != NULL; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + wm_uilisttype_unlink_from_area(ult, area); + } + + LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { + wm_uilisttype_unlink_from_region(ult, region); + } + } +} + +void WM_uilisttype_remove_ptr(Main *bmain, uiListType *ult) +{ + wm_uilisttype_unlink(bmain, ult); bool ok = BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, MEM_freeN); @@ -88,3 +150,34 @@ void WM_uilisttype_free(void) BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN); uilisttypes_hash = NULL; } + +/** + * The "full" list-ID is an internal name used for storing and identifying a list. It is built like + * this: + * "{uiListType.idname}_{list_id}", whereby "list_id" is an optional parameter passed to + * `UILayout.template_list()`. If it is not set, the full list-ID is just "{uiListType.idname}_". + * + * Note that whenever the Python API refers to the list-ID, it's the short, "non-full" one it + * passed to `UILayout.template_list()`. C code can query that through + * #WM_uilisttype_list_id_get(). + */ +void WM_uilisttype_to_full_list_id(const uiListType *ult, + const char *list_id, + char r_full_list_id[/*UI_MAX_NAME_STR*/]) +{ + /* We tag the list id with the list type... */ + BLI_snprintf(r_full_list_id, UI_MAX_NAME_STR, "%s_%s", ult->idname, list_id ? list_id : ""); +} + +/** + * Get the "non-full" list-ID, see #WM_uilisttype_to_full_list_id() for details. + * + * \note Assumes `uiList.list_id` was set using #WM_uilisttype_to_full_list_id()! + */ +const char *WM_uilisttype_list_id_get(const uiListType *ult, uiList *list) +{ + /* Some sanity check for the assumed behavior of #WM_uilisttype_to_full_list_id(). */ + BLI_assert((list->list_id + strlen(ult->idname))[0] == '_'); + /* +1 to skip the '_' */ + return list->list_id + strlen(ult->idname) + 1; +} |