UI: butstore API to generalize button storage for modal handlers
This commit is contained in:
parent
b0c314af9f
commit
2dafd1bfb8
@ -942,6 +942,20 @@ void UI_template_fix_linking(void);
|
||||
bool UI_editsource_enable_check(void);
|
||||
void UI_editsource_active_but_test(uiBut *but);
|
||||
|
||||
/* UI_butstore_ helpers */
|
||||
typedef struct uiButStore uiButStore;
|
||||
typedef struct uiButStoreElem uiButStoreElem;
|
||||
|
||||
uiButStore *UI_butstore_create(uiBlock *block);
|
||||
void UI_butstore_clear(uiBlock *block);
|
||||
void UI_butstore_update(uiBlock *block);
|
||||
void UI_butstore_free(uiBlock *block, uiButStore *bs);
|
||||
bool UI_butstore_is_valid(uiButStore *bs);
|
||||
bool UI_butstore_is_registered(uiBlock *block, uiBut *but);
|
||||
void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p);
|
||||
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
|
||||
|
||||
|
||||
/* Float precision helpers */
|
||||
#define UI_PRECISION_FLOAT_MAX 7
|
||||
|
||||
|
@ -525,7 +525,7 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut)
|
||||
return true;
|
||||
}
|
||||
|
||||
static uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new)
|
||||
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new)
|
||||
{
|
||||
uiBut *but_old;
|
||||
for (but_old = block_old->buttons.first; but_old; but_old = but_old->next) {
|
||||
@ -535,6 +535,16 @@ static uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new)
|
||||
}
|
||||
return but_old;
|
||||
}
|
||||
uiBut *ui_but_find_new(uiBlock *block_new, const uiBut *but_old)
|
||||
{
|
||||
uiBut *but_new;
|
||||
for (but_new = block_new->buttons.first; but_new; but_new = but_new->next) {
|
||||
if (ui_but_equals_old(but_new, but_old)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return but_new;
|
||||
}
|
||||
|
||||
/* oldbut is being inserted in new block, so we use the lines from new button, and replace button pointers */
|
||||
static void ui_but_update_linklines(uiBlock *block, uiBut *oldbut, uiBut *newbut)
|
||||
@ -1020,6 +1030,11 @@ void uiEndBlock(const bContext *C, uiBlock *block)
|
||||
uiBut *but;
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
|
||||
|
||||
if (has_old && BLI_listbase_is_empty(&block->oldblock->butstore) == false) {
|
||||
UI_butstore_update(block);
|
||||
}
|
||||
|
||||
/* inherit flags from 'old' buttons that was drawn here previous, based
|
||||
* on matching buttons, we need this to make button event handling non
|
||||
* blocking, while still allowing buttons to be remade each redraw as it
|
||||
@ -2228,6 +2243,8 @@ static void ui_free_but(const bContext *C, uiBut *but)
|
||||
IMB_freeImBuf((struct ImBuf *)but->poin);
|
||||
}
|
||||
|
||||
BLI_assert(UI_butstore_is_registered(but->block, but) == false);
|
||||
|
||||
MEM_freeN(but);
|
||||
}
|
||||
|
||||
@ -2236,6 +2253,8 @@ void uiFreeBlock(const bContext *C, uiBlock *block)
|
||||
{
|
||||
uiBut *but;
|
||||
|
||||
UI_butstore_clear(block);
|
||||
|
||||
while ((but = BLI_pophead(&block->buttons))) {
|
||||
ui_free_but(C, but);
|
||||
}
|
||||
|
@ -280,6 +280,8 @@ struct uiBlock {
|
||||
Panel *panel;
|
||||
uiBlock *oldblock;
|
||||
|
||||
ListBase butstore; /* UI_butstore_* runtime function */
|
||||
|
||||
ListBase layouts;
|
||||
struct uiLayout *curlayout;
|
||||
|
||||
@ -526,6 +528,8 @@ extern int ui_button_open_menu_direction(uiBut *but);
|
||||
extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
|
||||
void ui_button_clipboard_free(void);
|
||||
void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
|
||||
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
|
||||
uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
|
||||
|
||||
/* interface_widgets.c */
|
||||
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
|
||||
|
@ -34,21 +34,26 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
#include "BLF_translation.h"
|
||||
|
||||
#include "BKE_context.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
|
||||
#include "UI_interface.h"
|
||||
#include "UI_resources.h"
|
||||
|
||||
#include "interface_intern.h"
|
||||
|
||||
|
||||
/*************************** RNA Utilities ******************************/
|
||||
|
||||
@ -280,3 +285,160 @@ int uiFloatPrecisionCalc(int prec, double value)
|
||||
|
||||
return prec;
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Modal Button Store API */
|
||||
|
||||
/** \name Button Store
|
||||
*
|
||||
* Store for modal operators & handlers to register button pointers
|
||||
* which are maintained while drawing or NULL when removed.
|
||||
*
|
||||
* This is needed since button pointers are continuously freed and re-allocated.
|
||||
*
|
||||
* \{ */
|
||||
|
||||
typedef struct uiButStore {
|
||||
struct uiButStore *next, *prev;
|
||||
uiBlock *block;
|
||||
ListBase items;
|
||||
} uiButStore;
|
||||
|
||||
typedef struct uiButStoreElem {
|
||||
struct uiButStoreElem *next, *prev;
|
||||
uiBut **but_p;
|
||||
} uiButStoreElem;
|
||||
|
||||
/**
|
||||
* Create a new button sture, the caller must manage and run #UI_butstore_free
|
||||
*/
|
||||
uiButStore *UI_butstore_create(uiBlock *block)
|
||||
{
|
||||
uiButStore *bs_handle = MEM_callocN(sizeof(uiButStore), __func__);
|
||||
|
||||
bs_handle->block = block;
|
||||
BLI_addtail(&block->butstore, bs_handle);
|
||||
|
||||
return bs_handle;
|
||||
}
|
||||
|
||||
void UI_butstore_free(uiBlock *block, uiButStore *bs_handle)
|
||||
{
|
||||
BLI_freelistN(&bs_handle->items);
|
||||
BLI_remlink(&block->butstore, bs_handle);
|
||||
|
||||
MEM_freeN(bs_handle);
|
||||
}
|
||||
|
||||
bool UI_butstore_is_valid(uiButStore *bs)
|
||||
{
|
||||
return (bs->block != NULL);
|
||||
}
|
||||
|
||||
bool UI_butstore_is_registered(uiBlock *block, uiBut *but)
|
||||
{
|
||||
uiButStore *bs_handle;
|
||||
|
||||
for (bs_handle = block->butstore.first; bs_handle; bs_handle = bs_handle->next) {
|
||||
uiButStoreElem *bs_elem;
|
||||
|
||||
for (bs_elem = bs_handle->items.first; bs_elem; bs_elem = bs_elem->next) {
|
||||
if (*bs_elem->but_p == but) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void UI_butstore_register(uiButStore *bs_handle, uiBut **but_p)
|
||||
{
|
||||
uiButStoreElem *bs_elem = MEM_callocN(sizeof(uiButStoreElem), __func__);
|
||||
BLI_assert(*but_p);
|
||||
bs_elem->but_p = but_p;
|
||||
|
||||
BLI_addtail(&bs_handle->items, bs_elem);
|
||||
|
||||
}
|
||||
|
||||
void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p)
|
||||
{
|
||||
uiButStoreElem *bs_elem, *bs_elem_next;
|
||||
|
||||
for (bs_elem = bs_handle->items.first; bs_elem; bs_elem = bs_elem_next) {
|
||||
bs_elem_next = bs_elem->next;
|
||||
if (bs_elem->but_p == but_p) {
|
||||
BLI_remlink(&bs_handle->items, bs_elem);
|
||||
MEM_freeN(bs_elem);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* NULL all pointers, don't free since the owner needs to be able to inspect.
|
||||
*/
|
||||
void UI_butstore_clear(uiBlock *block)
|
||||
{
|
||||
uiButStore *bs_handle;
|
||||
|
||||
for (bs_handle = block->butstore.first; bs_handle; bs_handle = bs_handle->next) {
|
||||
uiButStoreElem *bs_elem;
|
||||
|
||||
bs_handle->block = NULL;
|
||||
|
||||
for (bs_elem = bs_handle->items.first; bs_elem; bs_elem = bs_elem->next) {
|
||||
*bs_elem->but_p = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Map freed buttons from the old block and update pointers.
|
||||
*/
|
||||
void UI_butstore_update(uiBlock *block)
|
||||
{
|
||||
uiButStore *bs_handle;
|
||||
|
||||
/* move this list to the new block */
|
||||
if (block->oldblock) {
|
||||
if (block->oldblock->butstore.first) {
|
||||
block->butstore = block->oldblock->butstore;
|
||||
BLI_listbase_clear(&block->oldblock->butstore);
|
||||
}
|
||||
}
|
||||
|
||||
if (LIKELY(block->butstore.first == NULL))
|
||||
return;
|
||||
|
||||
/* warning, loop-in-loop, in practice we only store <10 buttons at a time,
|
||||
* so this isn't going to be a problem, if that changes old-new mapping can be cached first */
|
||||
for (bs_handle = block->butstore.first; bs_handle; bs_handle = bs_handle->next) {
|
||||
|
||||
BLI_assert((bs_handle->block == NULL) ||
|
||||
(bs_handle->block == block) ||
|
||||
(block->oldblock && block->oldblock == bs_handle->block));
|
||||
|
||||
if (bs_handle->block == block->oldblock) {
|
||||
uiButStoreElem *bs_elem;
|
||||
|
||||
bs_handle->block = block;
|
||||
|
||||
for (bs_elem = bs_handle->items.first; bs_elem; bs_elem = bs_elem->next) {
|
||||
if (*bs_elem->but_p) {
|
||||
uiBut *but_new = ui_but_find_new(block, *bs_elem->but_p);
|
||||
|
||||
/* can be NULL if the buttons removed,
|
||||
* note: we could allow passing in a callback when buttons are removed
|
||||
* so the caller can cleanup */
|
||||
*bs_elem->but_p = but_new;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
Loading…
Reference in New Issue
Block a user