From aa8e0ced0130bf62d0fa24d93b4cb509ec47acb9 Mon Sep 17 00:00:00 2001 From: Leonard Ritter Date: Sun, 21 Sep 2014 17:56:42 +0200 Subject: [PATCH] merged data and handles; handles can either be set or allocated. --- example.cpp | 89 ++++++++++++++++----------------------- oui.h | 118 +++++++++++++++++++++++++--------------------------- 2 files changed, 93 insertions(+), 114 deletions(-) diff --git a/example.cpp b/example.cpp index 1fa06d0..80c4664 100644 --- a/example.cpp +++ b/example.cpp @@ -40,6 +40,8 @@ typedef enum { ST_PANEL = 7, // text ST_TEXT = 8, + // + ST_IGNORE = 9, } SubType; typedef struct { @@ -93,7 +95,7 @@ int cornerFlags(int item) { int parent = uiParent(item); int numkids = uiGetChildCount(parent); if (numkids < 2) return BND_CORNER_NONE; - const UIData *head = (const UIData *)uiGetData(parent); + const UIData *head = (const UIData *)uiGetHandle(parent); if (head) { int numid = uiGetChildId(item); switch(head->subtype) { @@ -124,7 +126,7 @@ void testrect(NVGcontext *vg, UIrect rect) { } void drawUI(NVGcontext *vg, int item, int x, int y) { - const UIData *head = (const UIData *)uiGetData(item); + const UIData *head = (const UIData *)uiGetHandle(item); UIrect rect = uiGetRect(item); rect.x += x; rect.y += y; @@ -202,7 +204,7 @@ void drawUI(NVGcontext *vg, int item, int x, int y) { int label(int iconid, const char *label) { int item = uiItem(); uiSetSize(item, 0, BND_WIDGET_HEIGHT); - UIButtonData *data = (UIButtonData *)uiAllocData(item, sizeof(UIButtonData)); + UIButtonData *data = (UIButtonData *)uiAllocHandle(item, sizeof(UIButtonData)); data->head.subtype = ST_LABEL; data->iconid = iconid; data->label = label; @@ -210,23 +212,19 @@ int label(int iconid, const char *label) { } void demohandler(int item, UIevent event) { - const UIButtonData *data = (const UIButtonData *)uiGetData(item); - printf("clicked: %lld %s\n", uiGetHandle(item), data->label); + const UIButtonData *data = (const UIButtonData *)uiGetHandle(item); + printf("clicked: %p %s\n", uiGetHandle(item), data->label); } -int button(UIhandle handle, int iconid, const char *label, - UIhandler handler) { +int button(int iconid, const char *label, UIhandler handler) { // create new ui item int item = uiItem(); - // set persistent handle for item that is used - // to track activity over time - uiSetHandle(item, handle); // set size of wiget; horizontal size is dynamic, vertical is fixed uiSetSize(item, 0, BND_WIDGET_HEIGHT); // attach event handler e.g. demohandler above uiSetHandler(item, handler, UI_BUTTON0_HOT_UP); // store some custom data with the button that we use for styling - UIButtonData *data = (UIButtonData *)uiAllocData(item, sizeof(UIButtonData)); + UIButtonData *data = (UIButtonData *)uiAllocHandle(item, sizeof(UIButtonData)); data->head.subtype = ST_BUTTON; data->iconid = iconid; data->label = label; @@ -234,22 +232,19 @@ int button(UIhandle handle, int iconid, const char *label, } void checkhandler(int item, UIevent event) { - const UICheckData *data = (const UICheckData *)uiGetData(item); + const UICheckData *data = (const UICheckData *)uiGetHandle(item); *data->option = !(*data->option); } -int check(UIhandle handle, const char *label, int *option) { +int check(const char *label, int *option) { // create new ui item int item = uiItem(); - // set persistent handle for item that is used - // to track activity over time - uiSetHandle(item, handle); // set size of wiget; horizontal size is dynamic, vertical is fixed uiSetSize(item, 0, BND_WIDGET_HEIGHT); // attach event handler e.g. demohandler above uiSetHandler(item, checkhandler, UI_BUTTON0_DOWN); // store some custom data with the button that we use for styling - UICheckData *data = (UICheckData *)uiAllocData(item, sizeof(UICheckData)); + UICheckData *data = (UICheckData *)uiAllocHandle(item, sizeof(UICheckData)); data->head.subtype = ST_CHECK; data->label = label; data->option = option; @@ -264,7 +259,7 @@ static float sliderstart = 0.0; // event handler for slider (same handler for all sliders) void sliderhandler(int item, UIevent event) { // retrieve the custom data we saved with the slider - UISliderData *data = (UISliderData *)uiGetData(item); + UISliderData *data = (UISliderData *)uiGetHandle(item); switch(event) { default: break; case UI_BUTTON0_DOWN: { @@ -288,12 +283,9 @@ void sliderhandler(int item, UIevent event) { } } -int slider(UIhandle handle, const char *label, float *progress) { +int slider(const char *label, float *progress) { // create new ui item int item = uiItem(); - // set persistent handle for item that is used - // to track activity over time - uiSetHandle(item, handle); // set size of wiget; horizontal size is dynamic, vertical is fixed uiSetSize(item, 0, BND_WIDGET_HEIGHT); // attach our slider event handler and capture two classes of events @@ -301,7 +293,7 @@ int slider(UIhandle handle, const char *label, float *progress) { UI_BUTTON0_DOWN | UI_BUTTON0_CAPTURE); // store some custom data with the button that we use for styling // and logic, e.g. the pointer to the data we want to alter. - UISliderData *data = (UISliderData *)uiAllocData(item, sizeof(UISliderData)); + UISliderData *data = (UISliderData *)uiAllocHandle(item, sizeof(UISliderData)); data->head.subtype = ST_SLIDER; data->label = label; data->progress = progress; @@ -309,7 +301,7 @@ int slider(UIhandle handle, const char *label, float *progress) { } void textboxhandler(int item, UIevent event) { - UITextData *data = (UITextData *)uiGetData(item); + UITextData *data = (UITextData *)uiGetHandle(item); switch(event) { default: break; case UI_BUTTON0_DOWN: { @@ -344,15 +336,14 @@ void textboxhandler(int item, UIevent event) { } } -int textbox(UIhandle handle, char *text, int maxsize) { +int textbox(char *text, int maxsize) { int item = uiItem(); - uiSetHandle(item, handle); uiSetSize(item, 0, BND_WIDGET_HEIGHT); uiSetHandler(item, textboxhandler, UI_BUTTON0_DOWN | UI_KEY_DOWN | UI_CHAR | UI_ADJUST_HEIGHT); // store some custom data with the button that we use for styling // and logic, e.g. the pointer to the data we want to alter. - UITextData *data = (UITextData *)uiAllocData(item, sizeof(UITextData)); + UITextData *data = (UITextData *)uiAllocHandle(item, sizeof(UITextData)); data->head.subtype = ST_TEXT; data->text = text; data->maxsize = maxsize; @@ -361,15 +352,14 @@ int textbox(UIhandle handle, char *text, int maxsize) { // simple logic for a radio button void radiohandler(int item, UIevent event) { - UIRadioData *data = (UIRadioData *)uiGetData(item); + UIRadioData *data = (UIRadioData *)uiGetHandle(item); *data->value = uiGetChildId(item); } -int radio(UIhandle handle, int iconid, const char *label, int *value) { +int radio(int iconid, const char *label, int *value) { int item = uiItem(); - uiSetHandle(item, handle); uiSetSize(item, label?0:BND_TOOL_WIDTH, BND_WIDGET_HEIGHT); - UIRadioData *data = (UIRadioData *)uiAllocData(item, sizeof(UIRadioData)); + UIRadioData *data = (UIRadioData *)uiAllocHandle(item, sizeof(UIRadioData)); data->head.subtype = ST_RADIO; data->iconid = iconid; data->label = label; @@ -380,7 +370,7 @@ int radio(UIhandle handle, int iconid, const char *label, int *value) { int panel() { int item = uiItem(); - UIData *data = (UIData *)uiAllocData(item, sizeof(UIData)); + UIData *data = (UIData *)uiAllocHandle(item, sizeof(UIData)); data->subtype = ST_PANEL; return item; } @@ -416,8 +406,6 @@ int vgroup_append(int parent, int item) { int vgroup() { int item = uiItem(); - UIData *data = (UIData *)uiAllocData(item, sizeof(UIData)); - data->subtype = ST_COLUMN; return item; } @@ -434,8 +422,6 @@ int hgroup_append(int parent, int item) { int hgroup() { int item = uiItem(); - UIData *data = (UIData *)uiAllocData(item, sizeof(UIData)); - data->subtype = ST_ROW; return item; } @@ -700,7 +686,6 @@ void draw(NVGcontext *vg, float w, float h) { uiSetLayout(0,UI_LEFT|UI_TOP); uiSetMargins(0,600,10,0,0); uiSetSize(0,250,400); - uiSetSelfHandle(root); uiSetHandler(root, roothandler, UI_SCROLL|UI_BUTTON0_DOWN); int col = column(); @@ -709,15 +694,15 @@ void draw(NVGcontext *vg, float w, float h) { uiSetLayout(col, UI_TOP|UI_HFILL); - column_append(col, button(1, BND_ICONID(6,3), "Item 1", demohandler)); - column_append(col, button(2, BND_ICONID(6,3), "Item 2", demohandler)); + column_append(col, button(BND_ICONID(6,3), "Item 1", demohandler)); + column_append(col, button(BND_ICONID(6,3), "Item 2", demohandler)); { int h = column_append(col, hgroup()); - hgroup_append(h, radio(3, BND_ICONID(6,3), "Item 3.0", &enum1)); - hgroup_append(h, radio(4, BND_ICONID(0,10), NULL, &enum1)); - hgroup_append(h, radio(5, BND_ICONID(1,10), NULL, &enum1)); - hgroup_append(h, radio(6, BND_ICONID(6,3), "Item 3.3", &enum1)); + hgroup_append(h, radio(BND_ICONID(6,3), "Item 3.0", &enum1)); + hgroup_append(h, radio(BND_ICONID(0,10), NULL, &enum1)); + hgroup_append(h, radio(BND_ICONID(1,10), NULL, &enum1)); + hgroup_append(h, radio(BND_ICONID(6,3), "Item 3.3", &enum1)); } { @@ -725,24 +710,24 @@ void draw(NVGcontext *vg, float w, float h) { int coll = row_append(rows, vgroup()); vgroup_append(coll, label(-1, "Items 4.0:")); coll = vgroup_append(coll, vgroup()); - vgroup_append(coll, button(7, BND_ICONID(6,3), "Item 4.0.0", demohandler)); - vgroup_append(coll, button(8, BND_ICONID(6,3), "Item 4.0.1", demohandler)); + vgroup_append(coll, button(BND_ICONID(6,3), "Item 4.0.0", demohandler)); + vgroup_append(coll, button(BND_ICONID(6,3), "Item 4.0.1", demohandler)); int colr = row_append(rows, vgroup()); uiSetFrozen(colr, option1); vgroup_append(colr, label(-1, "Items 4.1:")); colr = vgroup_append(colr, vgroup()); - vgroup_append(colr, slider(9, "Item 4.1.0", &progress1)); - vgroup_append(colr, slider(10, "Item 4.1.1", &progress2)); + vgroup_append(colr, slider("Item 4.1.0", &progress1)); + vgroup_append(colr, slider("Item 4.1.1", &progress2)); } - column_append(col, button(11, BND_ICONID(6,3), "Item 5", NULL)); + column_append(col, button(BND_ICONID(6,3), "Item 5", NULL)); static char textbuffer[1024] = "This textbox adjusts its height to its content when the text is overflowing the widgets width."; - column_append(col, textbox((UIhandle)textbuffer, textbuffer, 1024)); + column_append(col, textbox(textbuffer, 1024)); - column_append(col, check(12, "Frozen", &option1)); - column_append(col, check(13, "Item 7", &option2)); - column_append(col, check(14, "Item 8", &option3)); + column_append(col, check("Frozen", &option1)); + column_append(col, check("Item 7", &option2)); + column_append(col, check("Item 8", &option3)); uiLayout(); drawUI(vg, 0, 0, 0); diff --git a/oui.h b/oui.h index 537bb86..83f8bfe 100644 --- a/oui.h +++ b/oui.h @@ -215,9 +215,6 @@ typedef unsigned int UIuint; // opaque UI context typedef struct UIcontext UIcontext; -// application defined context handle -typedef unsigned long long UIhandle; - // item states as returned by uiGetState() typedef enum UIitemState { @@ -423,6 +420,12 @@ OUI_EXPORT void uiUpdateHotItem(); // this is an O(N) operation for N = number of declared items. OUI_EXPORT void uiProcess(int timestamp); +// reset the currently stored hot/active etc. handles; this should be called when +// a redeclaration of the UI changes the handle addresses, to avoid state +// related glitches because item identities have changed. If you're using +// uiAllocHandle() you should definitely make use of this. +OUI_EXPORT void uiClearHandleState(); + // UI Declaration // -------------- @@ -439,19 +442,15 @@ OUI_EXPORT int uiItem(); OUI_EXPORT void uiSetFrozen(int item, int enable); // set the application-dependent handle of an item. -// handle is an application defined 64-bit handle. If handle is 0, the item +// handle is an application defined 64-bit handle. If handle is NULL, the item // will not be interactive. -OUI_EXPORT void uiSetHandle(int item, UIhandle handle); - -// assigns the items own address as handle; this may cause glitches -// when the order of items changes while theitem is captured -OUI_EXPORT void uiSetSelfHandle(int item); +OUI_EXPORT void uiSetHandle(int item, void *handle); -// allocate space for application-dependent context data and return the pointer -// if successful. If no data has been allocated, a new pointer is returned. -// Otherwise, an assertion is thrown. -// The memory of the pointer is managed by the UI context. -OUI_EXPORT void *uiAllocData(int item, int size); +// allocate space for application-dependent context data and assign it +// as the handle to the item. +// The memory of the pointer is managed by the UI context and released +// upon the next call to uiClear() +OUI_EXPORT void *uiAllocHandle(int item, int size); // set the handler callback for an interactive item. // flags is a combination of UI_EVENT_* and designates for which events the @@ -529,12 +528,13 @@ OUI_EXPORT int uiGetItemCount(); // The returned value is one of UI_COLD, UI_HOT, UI_ACTIVE, UI_FROZEN. OUI_EXPORT UIitemState uiGetState(int item); -// return the application-dependent handle of the item as passed to uiSetHandle(). -OUI_EXPORT UIhandle uiGetHandle(int item); +// return the application-dependent handle of the item as passed to uiSetHandle() +// or uiAllocHandle(). +OUI_EXPORT void *uiGetHandle(int item); // return the item with the given application-dependent handle as assigned by // uiSetHandle() or -1 if unsuccessful. -OUI_EXPORT int uiGetItem(UIhandle handle); +OUI_EXPORT int uiGetItem(void *handle); // return the item that is currently under the cursor or -1 for none OUI_EXPORT int uiGetHotItem(); @@ -542,11 +542,6 @@ OUI_EXPORT int uiGetHotItem(); // return the item that is currently focused or -1 for none OUI_EXPORT int uiGetFocusedItem(); -// return the application-dependent context data for an item as passed to -// uiAllocData(). The memory of the pointer is managed by the UI context -// and should not be altered. -OUI_EXPORT const void *uiGetData(int item); - // return the handler callback for an item as passed to uiSetHandler() OUI_EXPORT UIhandler uiGetHandler(int item); // return the handler flags for an item as passed to uiSetHandler() @@ -667,8 +662,11 @@ OUI_EXPORT int uiGetAbove(int item); enum { UI_ITEM_LAYOUT_MASK = 0x000F, UI_ITEM_EVENT_MASK = 0xFFF0, + // item is frozen UI_ITEM_FROZEN = 0x10000, - UI_ITEM_VISITED_BITOFS = 17, // 0x20000, 0x40000, 0x80000, 0x100000 + // item handle is pointer to data + UI_ITEM_DATA = 0x20000, + UI_ITEM_VISITED_BITOFS = 18, // 0x4 0000, 0x8 0000, 0x10 0000, 0x20 0000 UI_ITEM_VISITED_MASK = (UI_ITEM_VISITED_XY_FLAG(0) | UI_ITEM_VISITED_XY_FLAG(1) | UI_ITEM_VISITED_WH_FLAG(0) @@ -677,12 +675,13 @@ enum { typedef struct UIitem { // declaration independent unique handle (for persistence) - UIhandle handle; + void *handle; // handler UIhandler handler; - - // container structure + unsigned int flags; + + // container structure // number of kids int numkids; @@ -713,17 +712,12 @@ typedef struct UIitem { UIvec2 computed_size; // relative rect UIrect rect; - - // attributes - - // index of data or -1 for none - int data; } UIitem; // 40 bytes typedef struct UIitem2 { // declaration independent unique handle (for persistence) - UIhandle handle; + void *handle; // handler UIhandler handler; @@ -777,9 +771,10 @@ struct UIcontext { // accumulated scroll wheel offsets UIvec2 scroll; - UIhandle hot_handle; - UIhandle active_handle; - UIhandle focus_handle; + void *hot_handle; + void *active_handle; + void *focus_handle; + void *last_click_handle; UIrect hot_rect; UIrect active_rect; UIstate state; @@ -789,7 +784,6 @@ struct UIcontext { int event_item; int last_timestamp; int last_click_timestamp; - UIhandle last_click_handle; int clicks; int count; @@ -832,9 +826,10 @@ void uiDestroyContext(UIcontext *ctx) { free(ctx); } -UI_INLINE unsigned int uiHashHandle(UIhandle handle) { - handle = (handle+(handle>>32)) & 0xffffffff; - unsigned int x = (unsigned int)handle; +UI_INLINE unsigned int uiHashHandle(void *handle) { + unsigned long long uval = (unsigned long long)handle; + uval = (uval+(uval>>32)) & 0xffffffff; + unsigned int x = (unsigned int)uval; x += (x>>6)+(x>>19); x += x<<16; x ^= x<<3; @@ -867,13 +862,13 @@ UI_INLINE UIhandleEntry *uiHashLookupHandle(unsigned int key) { } } -int uiGetItem(UIhandle handle) { +int uiGetItem(void *handle) { unsigned int key = uiHashHandle(handle); UIhandleEntry *e = uiHashLookupHandle(key); return e?(e->item):-1; } -static void uiHashInsertHandle(UIhandle handle, int item) { +static void uiHashInsertHandle(void *handle, int item) { unsigned int key = uiHashHandle(handle); UIhandleEntry *e = uiHashLookupHandle(key); if (e) { // update @@ -1053,6 +1048,14 @@ void uiClear() { memset(ui_context->handles, 0, sizeof(ui_context->handles)); } +void uiClearHandleState() { + assert(ui_context); + ui_context->hot_handle = NULL; + ui_context->active_handle = NULL; + ui_context->focus_handle = NULL; + ui_context->last_click_handle = NULL; +} + int uiItem() { assert(ui_context); assert(ui_context->count < UI_MAX_ITEMS); @@ -1064,7 +1067,6 @@ int uiItem() { item->lastkid = -1; item->nextitem = -1; item->previtem = -1; - item->data = -1; for (int i = 0; i < 4; ++i) item->relto[i] = -1; return idx; @@ -1400,36 +1402,28 @@ int uiParent(int item) { return uiItemPtr(item)->parent; } -const void *uiGetData(int item) { - UIitem *pitem = uiItemPtr(item); - if (pitem->data < 0) return NULL; - return ui_context->data + pitem->data; -} - -void *uiAllocData(int item, int size) { +void *uiAllocHandle(int item, int size) { assert((size > 0) && (size < UI_MAX_DATASIZE)); UIitem *pitem = uiItemPtr(item); - assert(pitem->data < 0); + assert(pitem->handle == NULL); assert((ui_context->datasize+size) <= UI_MAX_BUFFERSIZE); - pitem->data = ui_context->datasize; + pitem->handle = ui_context->data + ui_context->datasize; + pitem->flags |= UI_ITEM_DATA; ui_context->datasize += size; - return ui_context->data + pitem->data; + uiHashInsertHandle(pitem->handle, item); + return pitem->handle; } -void uiSetHandle(int item, UIhandle handle) { - uiItemPtr(item)->handle = handle; +void uiSetHandle(int item, void *handle) { + UIitem *pitem = uiItemPtr(item); + assert(pitem->handle == NULL); + pitem->handle = handle; if (handle) { uiHashInsertHandle(handle, item); } } -void uiSetSelfHandle(int item) { - UIitem *pitem = uiItemPtr(item); - pitem->handle = (UIhandle)pitem; - uiHashInsertHandle((UIhandle)pitem, item); -} - -UIhandle uiGetHandle(int item) { +void *uiGetHandle(int item) { return uiItemPtr(item)->handle; } @@ -1599,7 +1593,7 @@ void uiProcess(int timestamp) { } if (active_item >= 0) { - UIhandle active_handle = uiGetHandle(active_item); + void *active_handle = uiGetHandle(active_item); if ( ((timestamp - ui_context->last_click_timestamp) > UI_CLICK_THRESHOLD) || (ui_context->last_click_handle != active_handle)) {