UI: UI list refactor & preparations for asset view template

This is more of a first-pass refactor for the UI list template. More
improvements could be done, but that's better done separately. Main
purpose of this is to make the UI list code more manageable and ready
for the asset view template.

No functional changes for users.

* Split the huge template function into more manageable functions, with
  clear names and a few structs with high coherency.
* Move runtime data management to the template code, with a free
  callback called from BKE. This is UI data and should be managed at
  that level.
* Replace boolean arguments with bit-flags (easily extendable and more
  readable from the caller).
* Allow passing custom-data to the UI list for callbacks to access.
* Make list grip button for resizing optional.
* Put logic for generating the internal UI list identifier (stored in
  .blends) into function. This is a quite important bit and a later
  commit adds a related function. Good to have a clear API for this.
* Improve naming, comments, etc.

As part of further cleanups I'd like to move this to an own file.
This commit is contained in:
Julian Eisel 2021-07-14 16:01:53 +02:00 committed by Sybren A. Stüvel
parent 6e01b52100
commit 788d380460
Notes: blender-bot 2023-02-14 10:29:32 +01:00
Referenced by commit 9d9c879f4b, Cleanup: Move UI list template code to own file (C++)
8 changed files with 654 additions and 327 deletions

View File

@ -682,19 +682,13 @@ void BKE_area_region_free(SpaceType *st, ARegion *region)
BKE_area_region_panels_free(&region->panels);
LISTBASE_FOREACH (uiList *, uilst, &region->ui_lists) {
if (uilst->dyn_data) {
uiListDyn *dyn_data = uilst->dyn_data;
if (dyn_data->items_filter_flags) {
MEM_freeN(dyn_data->items_filter_flags);
}
if (dyn_data->items_filter_neworder) {
MEM_freeN(dyn_data->items_filter_neworder);
}
MEM_freeN(dyn_data);
if (uilst->dyn_data && uilst->dyn_data->free_runtime_data_fn) {
uilst->dyn_data->free_runtime_data_fn(uilst);
}
if (uilst->properties) {
IDP_FreeProperty(uilst->properties);
}
MEM_SAFE_FREE(uilst->dyn_data);
}
if (region->gizmo_map != NULL) {

View File

@ -25,6 +25,7 @@
#include "BLI_compiler_attrs.h"
#include "BLI_sys_types.h" /* size_t */
#include "BLI_utildefines.h"
#include "UI_interface_icons.h"
#ifdef __cplusplus
@ -2194,6 +2195,17 @@ void uiTemplateCacheFile(uiLayout *layout,
/* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */
#define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list"
enum uiTemplateListFlags {
UI_TEMPLATE_LIST_FLAG_NONE = 0,
UI_TEMPLATE_LIST_SORT_REVERSE = (1 << 0),
UI_TEMPLATE_LIST_SORT_LOCK = (1 << 1),
/* Don't allow resizing the list, i.e. don't add the grip button. */
UI_TEMPLATE_LIST_NO_GRIP = (1 << 2),
UI_TEMPLATE_LIST_FLAGS_LAST
};
ENUM_OPERATORS(enum uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST);
void uiTemplateList(uiLayout *layout,
struct bContext *C,
const char *listtype_name,
@ -2207,8 +2219,23 @@ void uiTemplateList(uiLayout *layout,
int maxrows,
int layout_type,
int columns,
bool sort_reverse,
bool sort_lock);
enum uiTemplateListFlags flags);
struct uiList *uiTemplateList_ex(uiLayout *layout,
struct bContext *C,
const char *listtype_name,
const char *list_id,
struct PointerRNA *dataptr,
const char *propname,
struct PointerRNA *active_dataptr,
const char *active_propname,
const char *item_dyntip_propname,
int rows,
int maxrows,
int layout_type,
int columns,
enum uiTemplateListFlags flags,
void *customdata);
void uiTemplateNodeLink(uiLayout *layout,
struct bContext *C,
struct bNodeTree *ntree,

File diff suppressed because it is too large Load Diff

View File

@ -1953,8 +1953,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
0,
0,
0,
false,
false);
UI_TEMPLATE_LIST_FLAG_NONE);
RNA_property_collection_lookup_int(
ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr);
}
@ -1972,8 +1971,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi
0,
0,
0,
false,
false);
UI_TEMPLATE_LIST_FLAG_NONE);
RNA_property_collection_lookup_int(
ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr);
}

View File

@ -43,6 +43,7 @@ struct SpaceLink;
struct SpaceType;
struct uiBlock;
struct uiLayout;
struct uiList;
struct wmDrawBuffer;
struct wmTimer;
struct wmTooltipState;
@ -246,11 +247,16 @@ typedef struct PanelCategoryStack {
char idname[64];
} PanelCategoryStack;
typedef void (*uiListFreeRuntimeDataFunc)(struct uiList *ui_list);
/* uiList dynamic data... */
/* These two Lines with # tell makesdna this struct can be excluded. */
#
#
typedef struct uiListDyn {
/** Callback to free UI data when freeing UI-Lists in BKE. */
uiListFreeRuntimeDataFunc free_runtime_data_fn;
/** Number of rows needed to draw all elements. */
int height;
/** Actual visual height of the list (in rows). */
@ -258,6 +264,9 @@ typedef struct uiListDyn {
/** Minimal visual height of the list (in rows). */
int visual_height_min;
/** Number of columns drawn for grid layouts. */
int columns;
/** Number of items in collection. */
int items_len;
/** Number of items actually visible after filtering. */
@ -270,6 +279,9 @@ typedef struct uiListDyn {
int resize;
int resize_prev;
/* Allocated custom data. Free'ed together with the uiList (and when re-assigning). */
void *customdata;
/* Filtering data. */
/** Items_len length. */
int *items_filter_flags;

View File

@ -525,6 +525,46 @@ static void rna_uiTemplateAnyID(uiLayout *layout,
uiTemplateAnyID(layout, ptr, propname, proptypename, name);
}
void rna_uiTemplateList(uiLayout *layout,
struct bContext *C,
const char *listtype_name,
const char *list_id,
struct PointerRNA *dataptr,
const char *propname,
struct PointerRNA *active_dataptr,
const char *active_propname,
const char *item_dyntip_propname,
const int rows,
const int maxrows,
const int layout_type,
const int columns,
const bool sort_reverse,
const bool sort_lock)
{
int flags = UI_TEMPLATE_LIST_FLAG_NONE;
if (sort_reverse) {
flags |= UI_TEMPLATE_LIST_SORT_REVERSE;
}
if (sort_lock) {
flags |= UI_TEMPLATE_LIST_SORT_LOCK;
}
uiTemplateList(layout,
C,
listtype_name,
list_id,
dataptr,
propname,
active_dataptr,
active_propname,
item_dyntip_propname,
rows,
maxrows,
layout_type,
columns,
flags);
}
static void rna_uiTemplateCacheFile(uiLayout *layout,
bContext *C,
PointerRNA *ptr,
@ -1508,7 +1548,7 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_pointer(func, "clip_user", "MovieClipUser", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
func = RNA_def_function(srna, "template_list", "uiTemplateList");
func = RNA_def_function(srna, "template_list", "rna_uiTemplateList");
RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups.");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_string(func, "listtype_name", NULL, 0, "", "Identifier of the list type to use");

View File

@ -621,6 +621,10 @@ bool WM_uilisttype_add(struct uiListType *ult);
void WM_uilisttype_freelink(struct uiListType *ult);
void WM_uilisttype_free(void);
void WM_uilisttype_to_full_list_id(const struct uiListType *ult,
const char *list_id,
char *r_ui_list_id);
/* wm_menu_type.c */
void WM_menutype_init(void);
struct MenuType *WM_menutype_find(const char *idname, bool quiet);

View File

@ -28,7 +28,10 @@
#include "MEM_guardedalloc.h"
#include "UI_interface.h"
#include "BLI_ghash.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "BKE_screen.h"
@ -88,3 +91,21 @@ 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}", wherby "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 : "");
}