Commit: 2dafd1bfb8294acd996607f2b31961f66b5a3587
Author: Campbell Barton
Date:   Sat Feb 8 09:03:25 2014 +1100
https://developer.blender.org/rB2dafd1bfb8294acd996607f2b31961f66b5a3587

UI: butstore API to generalize button storage for modal handlers

===================================================================

M       source/blender/editors/include/UI_interface.h
M       source/blender/editors/interface/interface.c
M       source/blender/editors/interface/interface_intern.h
M       source/blender/editors/interface/interface_utils.c

===================================================================

diff --git a/source/blender/editors/include/UI_interface.h 
b/source/blender/editors/include/UI_interface.h
index 65811b7..5925796 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -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
 
diff --git a/source/blender/editors/interface/interface.c 
b/source/blender/editors/interface/interface.c
index db2b804..40e3b15 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -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);
        }
diff --git a/source/blender/editors/interface/interface_intern.h 
b/source/blender/editors/interface/interface_intern.h
index 4a0864e..f3d7203 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -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);
diff --git a/source/blender/editors/interface/interface_utils.c 
b/source/blender/editors/interface/interface_utils.c
index 2b9d7a7..ed4852b 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -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;
+                               }
+                       }
+               }
+       }
+}
+
+/** \} */

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to