From ec0611d6132de7f894bd6b43a3a5a4344cf7497c Mon Sep 17 00:00:00 2001 From: Leonard Ritter Date: Fri, 11 Jul 2014 01:23:14 +0200 Subject: [PATCH] more work on oui.h: simplifications, better support for radio buttons --- example.cpp | 95 ++++++++++++++++++++++++++++-------------------- oui.h | 103 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 147 insertions(+), 51 deletions(-) diff --git a/example.cpp b/example.cpp index 4a22146..9290b2b 100644 --- a/example.cpp +++ b/example.cpp @@ -66,7 +66,7 @@ int cornerFlags(int item) { } void drawUI(NVGcontext *vg, int item, int x, int y) { - UIData *data = (UIData *)uiGetData(item); + const UIData *data = (const UIData *)uiGetData(item); UIrect rect = uiGetRect(item); rect.x += x; rect.y += y; @@ -86,8 +86,9 @@ void drawUI(NVGcontext *vg, int item, int x, int y) { data->iconid,data->label); } break; case ST_RADIO:{ + BNDwidgetState state = (BNDwidgetState)uiGetState(item); bndRadioButton(vg,rect.x,rect.y,rect.w,rect.h, - cornerFlags(item),(BNDwidgetState)uiGetState(item), + cornerFlags(item),state, data->iconid,data->label); } break; } @@ -102,6 +103,42 @@ void drawUI(NVGcontext *vg, int item, int x, int y) { } } +int label(int parent, int iconid, const char *label) { + UIData data = { sizeof(UIData), ST_DEFAULT, iconid, label }; + return uiItem(parent, 0, UI_LABEL, 0, BND_WIDGET_HEIGHT, &data); +} + +int button(int parent, UIhandle handle, int iconid, const char *label, + UIhandler handler) { + UIData data = { sizeof(UIData), ST_DEFAULT, iconid, label }; + int item = uiItem(parent, handle, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); + uiSetHandler(item, handler); + return item; +} + +static UIhandle radio_handle = 0; + +void radiohandler(int item) { + radio_handle = uiGetHandle(item); + uiSetActive(item, 1); +} + +int radio(int parent, UIhandle handle, int iconid, const char *label) { + UIData data = { sizeof(UIData), ST_RADIO, iconid, label }; + int w = (label)?0:BND_TOOL_WIDTH; + int item = uiItem(parent, handle, UI_BUTTON, w, BND_WIDGET_HEIGHT, &data); + uiSetHandler(item, radiohandler); + uiSetEarlyHandler(item, true); + if (radio_handle == handle) + uiSetActive(item, 1); + return item; +} + +void demohandler(int item) { + const UIData *data = (const UIData *)uiGetData(item); + printf("clicked: %lld %s\n", uiGetHandle(item), data->label); +} + void draw(NVGcontext *vg, float w, float h) { bndBackground(vg, 0, 0, w, h); @@ -288,60 +325,40 @@ void draw(NVGcontext *vg, float w, float h) { bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT, BND_DEFAULT,BND_ICONID(5,11),NULL); + // some OUI stuff + uiClear(); uiSetRect(0,600,10,250,400); - + int col = uiColumn(0,1); - UIData data = { sizeof(UIData), ST_DEFAULT, BND_ICONID(6,3), "Item 1" }; - uiItem(col, 1, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); - data.label = "Item 2"; - uiItem(col, 2, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); + button(col, 1, BND_ICONID(6,3), "Item 1", demohandler); + button(col, 2, BND_ICONID(6,3), "Item 2", demohandler); { int row = uiRow(col,-1); - data.subtype = ST_RADIO; - data.label = "Item 3.0"; - uiItem(row, 3, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); - data.label = NULL; - data.iconid = BND_ICONID(0,10); - uiItem(row, 4, UI_BUTTON, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data); - data.label = NULL; - data.iconid = BND_ICONID(1,10); - uiItem(row, 5, UI_BUTTON, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data); - data.iconid = BND_ICONID(6,3); - data.label = "Item 3.3"; - uiItem(row, 6, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); - data.subtype = ST_DEFAULT; + radio(row, 3, BND_ICONID(6,3), "Item 3.0"); + radio(row, 4, BND_ICONID(0,10), NULL); + radio(row, 5, BND_ICONID(1,10), NULL); + radio(row, 6, BND_ICONID(6,3), "Item 3.3"); } { int row = uiRow(col,8); int coll = uiColumn(row,-2); - data.label = "Items 4.0:"; - data.iconid = -1; - uiItem(coll, 0, UI_LABEL, 0, BND_WIDGET_HEIGHT, &data); + label(coll, -1, "Items 4.0:"); coll = uiColumn(coll,-2); - data.label = "Item 4.0.0"; - data.iconid = BND_ICONID(6,3); - uiItem(coll, 7, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); - data.label = "Item 4.0.1"; - uiItem(coll, 8, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); + button(coll, 7, BND_ICONID(6,3), "Item 4.0.0", demohandler); + button(coll, 8, BND_ICONID(6,3), "Item 4.0.1", demohandler); int colr = uiColumn(row,-2); - data.label = "Items 4.1:"; - data.iconid = -1; - uiItem(colr, 0, UI_LABEL, 0, BND_WIDGET_HEIGHT, &data); + label(colr, -1, "Items 4.1:"); colr = uiColumn(colr,-2); - data.label = "Item 4.1.0"; - data.iconid = BND_ICONID(6,3); - uiItem(colr, 9, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); - data.label = "Item 4.1.1"; - uiItem(colr,10, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); + button(colr, 9, BND_ICONID(6,3), "Item 4.1.0", demohandler); + button(colr,10, BND_ICONID(6,3), "Item 4.1.1", demohandler); } - data.label = "Item 5"; - uiItem(col,11, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); + button(col, 11, BND_ICONID(6,3), "Item 5", NULL); - uiLayout(); + uiProcess(); drawUI(vg, 0, 0, 0); diff --git a/oui.h b/oui.h index d42f72f..29ad836 100644 --- a/oui.h +++ b/oui.h @@ -163,9 +163,9 @@ int uiRow(int parent, int spacing); // layout all added items and update the internal state according to the // current cursor position and button states. -// It is safe to immediately draw the items after a call to uiLayout(). +// It is safe to immediately draw the items after a call to uiProcess(). // this is an O(N) operation for N = number of declared items. -void uiLayout(); +void uiProcess(); // returns the number of child items a container item contains. If the item // is not a container or does not contain any items, 0 is returned. @@ -208,17 +208,17 @@ int uiGetSpacing(int item); int uiGetKind(int item); // returns the items layout rectangle relative to its parent. If uiGetRect() -// is called before uiLayout(), the values of the returned rectangle are +// is called before uiProcess(), the values of the returned rectangle are // undefined. UIrect uiGetRect(int item); // returns the items layout rectangle in absolute coordinates. If -// uiGetAbsoluteRect() is called before uiLayout(), the values of the returned +// uiGetAbsoluteRect() is called before uiProcess(), the values of the returned // rectangle are undefined. UIrect uiGetScreenRect(int item); // explicitly assign a layout rectangle to an item; If uiSetRect() is called -// after uiLayout(), behavior is undefined. +// after uiProcess(), behavior is undefined. // This function is primarily used to position the root element. void uiSetRect(int item, int x, int y, int w, int h); @@ -227,7 +227,7 @@ void uiSetRect(int item, int x, int y, int w, int h); const void *uiGetData(int item); // return the application-dependent handle of the item as passed to uiItem(). -int uiGetHandle(int item); +UIhandle uiGetHandle(int item); // return the current state of the item. // The returned value is one of UI_COLD, UI_HOT, UI_ACTIVE. @@ -237,6 +237,27 @@ int uiGetState(int item); // callback is dependent on the item kind. void uiSetHandler(int item, UIhandler handler); +// return the handler callback for an item as passed to uiSetHandler() +UIhandler uiGetHandler(int item); + +// set the state of a toggleable item to active. If set, uiGetState() will +// always return UI_ACTIVE. +// enabled is 1 for active, 0 for default behavior +void uiSetActive(int item, int enabled); + +// returns the active state of a toggleable item; +// the function returns 1 if the item is always active, 0 for default behavior. +int uiGetActive(int item); + +// set an interactive item to activate on button-down. The default behavior +// is to call the handler callback when the button is released; if set, +// the handler will already be called if the button is pressed. +void uiSetEarlyHandler(int item, int enabled); + +// returns the setting passed to uiSetEarlyHandler(); +// the function returns 1 if the setting is active, 0 for default behavior. +int uiGetEarlyHandler(int item); + #endif // _UI_H_ #define UI_IMPLEMENTATION @@ -246,7 +267,19 @@ void uiSetHandler(int item, UIhandler handler); #define UI_MAX_KIND 16 +typedef enum UIflags { + // if true, item is always active + UI_FLAG_ALWAYS_ACTIVE = (1<<0), + // if true, activate on mousedown, not mouseup + UI_FLAG_EARLY_HANDLER = (1<<1), +} UIflags; + typedef struct UIitem { + // declaration independent unique handle (for persistence) + UIhandle handle; + // handler + UIhandler handler; + // container structure // number of kids @@ -267,8 +300,6 @@ typedef struct UIitem { // attributes - // declaration independent unique handle (for persistence) - UIhandle handle; // layout rectangle UIrect rect; // absolute position @@ -279,8 +310,8 @@ typedef struct UIitem { int data; // layouting containers: spacing between items int spacing; - // handler - UIhandler handler; + // a combination of UIflags + int flags; } UIitem; struct UIcontext { @@ -289,6 +320,7 @@ struct UIcontext { UIhandle hot; UIhandle active; + int handle_item; int count; UIitem items[UI_MAX_ITEMS]; @@ -463,13 +495,40 @@ int uiGetKind(int item) { return uiItemPtr(item)->kind; } +static void uiSetFlag(int item, int flag, int enabled) { + if (enabled) + uiItemPtr(item)->flags |= flag; + else + uiItemPtr(item)->flags &= ~flag; +} + +static int uiGetFlag(int item, int flag) { + return (uiItemPtr(item)->flags & flag)?1:0; +} + +void uiSetActive(int item, int enabled) { + uiSetFlag(item, UI_FLAG_ALWAYS_ACTIVE, enabled); +} + +int uiGetActive(int item) { + return uiGetFlag(item, UI_FLAG_ALWAYS_ACTIVE); +} + +void uiSetEarlyHandler(int item, int enabled) { + uiSetFlag(item, UI_FLAG_EARLY_HANDLER, enabled); +} + +int uiGetEarlyHandler(int item) { + return uiGetFlag(item, UI_FLAG_EARLY_HANDLER); +} + const void *uiGetData(int item) { UIitem *pitem = uiItemPtr(item); if (pitem->data < 0) return NULL; return ui_context->data + pitem->data; } -int uiGetHandle(int item) { +UIhandle uiGetHandle(int item) { return uiItemPtr(item)->handle; } @@ -477,6 +536,10 @@ void uiSetHandler(int item, UIhandler handler) { uiItemPtr(item)->handler = handler; } +UIhandler uiGetHandler(int item) { + return uiItemPtr(item)->handler; +} + int uiGetChildId(int item) { return uiItemPtr(item)->kidid; } @@ -602,8 +665,15 @@ void uiUpdateItemState(int item, int x, int y) { && (cyrect.h)) { ui_context->hot = pitem->handle; + // button down, no widget activated if (!ui_context->active && uiGetButton(0)) { ui_context->active = pitem->handle; + if (pitem->flags & UI_FLAG_EARLY_HANDLER) { + ui_context->handle_item = item; + } + } else if ( // button up, this widget is active + (ui_context->active == pitem->handle) && !uiGetButton(0)) { + ui_context->handle_item = item; } } } @@ -616,12 +686,19 @@ void uiUpdateItemState(int item, int x, int y) { } -void uiLayout() { +void uiProcess() { + ui_context->handle_item = -1; uiLayoutItem(0); uiUpdateItemState(0, 0, 0); if (!uiGetButton(0)) { ui_context->active = 0; } + if (ui_context->handle_item >= 0) { + UIhandler handler = uiGetHandler(ui_context->handle_item); + if (handler) { + handler(ui_context->handle_item); + } + } } int uiIsActive(int item) { @@ -635,6 +712,8 @@ int uiIsHot(int item) { } int uiGetState(int item) { + UIitem *pitem = uiItemPtr(item); + if (pitem->flags & UI_FLAG_ALWAYS_ACTIVE) return UI_ACTIVE; return (!uiIsHot(item))?UI_COLD:(uiIsActive(item))?UI_ACTIVE:UI_HOT; }