From 26b098c04fbeb7f4d7c320b6c2066d2b448ae136 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 13 Jul 2021 17:42:25 +0200 Subject: UI: Support defining UI lists in C So far all UI lists had to be defined in Python, this makes it possible to define them in C as well. Note that there is a whole bunch of special handling for the Python API that isn't there for C. I think most importantly custom properties support, which currently can't be added for C defined UI lists. The upcoming asset view UI template will use this, which needs to be defined in C. Adds a new file `interface_template_list.cc`, which at this point is mostly a dummy to have a place for the `ED_uilisttypes_ui()` definition. I plan a separate cleanup to move the UI-list template to that file. --- source/blender/editors/include/UI_interface.h | 1 + source/blender/editors/interface/CMakeLists.txt | 1 + .../editors/interface/interface_template_list.cc | 27 ++++++++++ source/blender/editors/space_api/spacetypes.c | 2 + source/blender/makesrna/intern/rna_ui.c | 4 +- source/blender/windowmanager/WM_api.h | 2 +- source/blender/windowmanager/intern/wm_init_exit.c | 3 +- .../blender/windowmanager/intern/wm_uilist_type.c | 60 +++++++++++++++++++++- 8 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 source/blender/editors/interface/interface_template_list.cc diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 747ec776d80..020ca1f8f55 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -2558,6 +2558,7 @@ typedef struct uiDragColorHandle { void ED_operatortypes_ui(void); void ED_keymap_ui(struct wmKeyConfig *keyconf); +void ED_uilisttypes_ui(void); void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop); bool UI_drop_color_poll(struct bContext *C, diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 2cc3830042c..29f868eebb0 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -66,6 +66,7 @@ set(SRC interface_region_tooltip.c interface_regions.c interface_style.c + interface_template_list.cc interface_template_search_menu.c interface_template_search_operator.c interface_templates.c diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc new file mode 100644 index 00000000000..90980b3c963 --- /dev/null +++ b/source/blender/editors/interface/interface_template_list.cc @@ -0,0 +1,27 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edinterface + * + * TODO: The UI list template implementation should be moved here. + */ + +#include "UI_interface.h" + +void ED_uilisttypes_ui(void) +{ +} diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index adb824b8934..b3b3eafb6e7 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -129,6 +129,8 @@ void ED_spacetypes_init(void) ED_screen_user_menu_register(); + ED_uilisttypes_ui(); + /* Gizmo types. */ ED_gizmotypes_button_2d(); ED_gizmotypes_dial_3d(); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 2a076554d03..a88b100435a 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -654,7 +654,7 @@ static void uilist_filter_items(uiList *ui_list, RNA_parameter_list_free(&list); } -static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type) +static void rna_UIList_unregister(Main *bmain, StructRNA *type) { uiListType *ult = RNA_struct_blender_type_get(type); @@ -665,7 +665,7 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type) RNA_struct_free_extension(type, &ult->rna_ext); RNA_struct_free(&BLENDER_RNA, type); - WM_uilisttype_freelink(ult); + WM_uilisttype_remove_ptr(bmain, ult); /* update while blender is running */ WM_main_add_notifier(NC_WINDOW, NULL); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index c529fef73ef..66e91526009 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -618,7 +618,7 @@ void WM_operator_type_modal_from_exec_for_object_edit_coords(struct wmOperatorTy void WM_uilisttype_init(void); struct uiListType *WM_uilisttype_find(const char *idname, bool quiet); bool WM_uilisttype_add(struct uiListType *ult); -void WM_uilisttype_freelink(struct uiListType *ult); +void WM_uilisttype_remove_ptr(struct Main *bmain, struct uiListType *ult); void WM_uilisttype_free(void); void WM_uilisttype_to_full_list_id(const struct uiListType *ult, diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index fa087f5e226..d7ea47fc625 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -553,7 +553,6 @@ void WM_exit_ex(bContext *C, const bool do_python) wm_surfaces_free(); wm_dropbox_free(); WM_menutype_free(); - WM_uilisttype_free(); /* all non-screen and non-space stuff editors did, like editmode */ if (C) { @@ -609,6 +608,8 @@ void WM_exit_ex(bContext *C, const bool do_python) wm_gizmomaptypes_free(); wm_gizmogrouptype_free(); wm_gizmotype_free(); + /* Same for UI-list types. */ + WM_uilisttype_free(); BLF_exit(); diff --git a/source/blender/windowmanager/intern/wm_uilist_type.c b/source/blender/windowmanager/intern/wm_uilist_type.c index 6d298ee63f1..468ea7e4d5b 100644 --- a/source/blender/windowmanager/intern/wm_uilist_type.c +++ b/source/blender/windowmanager/intern/wm_uilist_type.c @@ -23,8 +23,10 @@ #include #include +#include "BLI_listbase.h" #include "BLI_sys_types.h" +#include "DNA_space_types.h" #include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -32,9 +34,11 @@ #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" @@ -64,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); -- cgit v1.2.3