UI: Add callback for comparing button identity

The code to compare buttons from the previous to the current frame, to
see if they match (an thus should keep the same state) was quite
generic, and didn't allow much flexibility/customization. For some
cases this isn't enough, and a more specific comparison is needed. Say
if some buttons don't actually store comparable data themselves, only
via the button context. This was the case in D14653.
This commit is contained in:
Julian Eisel 2022-04-26 22:26:15 +02:00
parent 5fe1624b0e
commit 83c8f996f1
4 changed files with 37 additions and 0 deletions

View File

@ -508,6 +508,10 @@ typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
typedef void (*uiButHandleHoldFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but);
typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
/** Function to compare the identity of two buttons over redraws, to check if they represent the
* same data, and thus should be considered the same button over redraws. */
typedef bool (*uiButIdentityCompareFunc)(const uiBut *a, const uiBut *b);
/* Search types. */
typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
struct ARegion *butregion,
@ -1649,6 +1653,18 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
eButLabelAlign label_align,
bool compact);
/**
* Callback to compare the identity of two buttons, used to identify buttons over redraws. If the
* callback returns true, the given buttons are considered to be matching and relevant state is
* preserved (copied from the old to the new button). If it returns false, it's considered
* non-matching and no further checks are done.
*
* If this is set, it is always executed instead of the default comparisons. However it is only
* executed for buttons that have the same type and the same callback. So callbacks can assume the
* button types match.
*/
void UI_but_func_identity_compare_set(uiBut *but, uiButIdentityCompareFunc cmp_fn);
/**
* Public function exported for functions that use #UI_BTYPE_SEARCH_MENU.
*

View File

@ -725,6 +725,19 @@ bool ui_but_rna_equals_ex(const uiBut *but,
/* NOTE: if `but->poin` is allocated memory for every `uiDefBut*`, things fail. */
static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
{
if (but->identity_cmp_func) {
/* If the buttons have own identity comparator callbacks (and they match), use this to
* determine equality. */
if (but->identity_cmp_func && (but->type == oldbut->type) &&
(but->identity_cmp_func == oldbut->identity_cmp_func)) {
/* Test if the comparison is symmetrical (if a == b then b == a), may help catch some issues.
*/
BLI_assert(but->identity_cmp_func(but, oldbut) == but->identity_cmp_func(oldbut, but));
return but->identity_cmp_func(but, oldbut);
}
}
/* various properties are being compared here, hopefully sufficient
* to catch all cases, but it is simple to add more checks later */
if (but->retval != oldbut->retval) {

View File

@ -183,6 +183,9 @@ struct uiBut {
uchar col[4];
/** See \ref UI_but_func_identity_compare_set(). */
uiButIdentityCompareFunc identity_cmp_func;
uiButHandleFunc func;
void *func_arg1;
void *func_arg2;

View File

@ -452,6 +452,11 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout,
return return_info;
}
void UI_but_func_identity_compare_set(uiBut *but, uiButIdentityCompareFunc cmp_fn)
{
but->identity_cmp_func = cmp_fn;
}
/* *** RNA collection search menu *** */
struct CollItemSearch {