From c78fb2df9c10781d7784689640778134c0209553 Mon Sep 17 00:00:00 2001 From: Leonard Ritter Date: Fri, 11 Jul 2014 00:13:50 +0200 Subject: [PATCH] documented oui.h --- example.cpp | 45 +++++++---- oui.h | 215 +++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 215 insertions(+), 45 deletions(-) diff --git a/example.cpp b/example.cpp index f543fd9..4a22146 100644 --- a/example.cpp +++ b/example.cpp @@ -21,8 +21,16 @@ //////////////////////////////////////////////////////////////////////////////// +typedef enum { + // default + ST_DEFAULT = 0, + // radio button + ST_RADIO = 1, +} SubType; + typedef struct { int size; + int subtype; int iconid; const char *label; } UIData; @@ -69,17 +77,20 @@ void drawUI(NVGcontext *vg, int item, int x, int y) { bndLabel(vg,rect.x,rect.y,rect.w,rect.h, data->iconid,data->label); } break; - case UI_RADIO: { - assert(data); - bndRadioButton(vg,rect.x,rect.y,rect.w,rect.h, - cornerFlags(item),(BNDwidgetState)uiGetState(item), - data->iconid,data->label); - } break; case UI_BUTTON: { assert(data); - bndToolButton(vg,rect.x,rect.y,rect.w,rect.h, - cornerFlags(item),(BNDwidgetState)uiGetState(item), - data->iconid,data->label); + switch(data->subtype) { + default: { + bndToolButton(vg,rect.x,rect.y,rect.w,rect.h, + cornerFlags(item),(BNDwidgetState)uiGetState(item), + data->iconid,data->label); + } break; + case ST_RADIO:{ + bndRadioButton(vg,rect.x,rect.y,rect.w,rect.h, + cornerFlags(item),(BNDwidgetState)uiGetState(item), + data->iconid,data->label); + } break; + } } break; default: break; } @@ -282,26 +293,28 @@ void draw(NVGcontext *vg, float w, float h) { uiSetRect(0,600,10,250,400); int col = uiColumn(0,1); - UIData data = { sizeof(UIData), BND_ICONID(6,3), "Item 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); - { // nested row + { int row = uiRow(col,-1); + data.subtype = ST_RADIO; data.label = "Item 3.0"; - uiItem(row, 3, UI_RADIO, 0, BND_WIDGET_HEIGHT, &data); + uiItem(row, 3, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); data.label = NULL; data.iconid = BND_ICONID(0,10); - uiItem(row, 4, UI_RADIO, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data); + 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_RADIO, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data); + 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_RADIO, 0, BND_WIDGET_HEIGHT, &data); + uiItem(row, 6, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data); + data.subtype = ST_DEFAULT; } - { // two columns + { int row = uiRow(col,8); int coll = uiColumn(row,-2); data.label = "Items 4.0:"; diff --git a/oui.h b/oui.h index e883efb..d42f72f 100644 --- a/oui.h +++ b/oui.h @@ -35,76 +35,211 @@ user interfaces; the intended use is for bootstrap situations where only basic UI services are needed. */ +// item states as returned by uiGetState() + +// the item is inactive #define UI_COLD 0x0000 +// the item is inactive, but the cursor is hovering over this item #define UI_HOT 0x0001 +// the item is toggled or activated (depends on item kind) #define UI_ACTIVE 0x0002 +// the item is unresponsive +#define UI_FROZEN 0x0003 + +// item kinds -// containers +// this is a reserved kind and only used by the root item 0 #define UI_ROOT 0x0100 +// Column container. Arranges child items vertically and adjusts their width to +// the width of the column. Items of fixed width will only be truncated, but not +// expanded. #define UI_COLUMN 0x0101 +// Row container. Arranges items horizontally and distributes their width to +// match the width of the row. Items of fixed width will only be truncated, but +// not expanded. The remaining space will be equally distributed among all items +// of dynamic width. #define UI_ROW 0x0102 -// controls +// Label control. The control is non-interactive and will not call any handlers. #define UI_LABEL 0x0203 +// Button control. Will call the buttons handler when activated. #define UI_BUTTON 0x0204 -#define UI_RADIO 0x0205 +// maximum number of items that may be added #define UI_MAX_ITEMS 4096 +// maximum size in bytes reserved for storage of application dependent data +// as passed to uiItem(). #define UI_MAX_BUFFERSIZE 1048576 +// maximum size in bytes of a single data buffer passed to uiItem(). #define UI_MAX_DATASIZE 4096 +// maximum depth of nested containers #define UI_MAX_DEPTH 64 +// opaque UI context typedef struct UIcontext UIcontext; + +// application defined context handle typedef unsigned long long UIhandle; +// handler callback +typedef void (*UIhandler)(int item); + +// layout rectangle typedef struct UIrect { int x, y, w, h; } UIrect; +// exemplary buffer of variable size to pass to the data argument of uiItem(); +// see uiItem() for more information. typedef struct UIdata { int size; unsigned char content[1]; } UIdata; +// unless declared otherwise, all operations have the complexity O(1). + +// create a new UI context; call uiMakeCurrent() to make this context the +// current context. UIcontext *uiCreateContext(); + +// select an UI context as the current context; a context must always be +// selected before using any of the other UI functions void uiMakeCurrent(UIcontext *ctx); + +// release the memory of an UI context created with uiCreateContext(); if the +// context is the current context, the current context will be set to NULL void uiDestroyContext(UIcontext *ctx); +// sets a mouse or gamepad button as pressed/released +// button is in the range 0..63 and maps to an application defined input +// source. +// enabled is 1 for pressed, 0 for released void uiSetButton(int button, int enabled); + +// returns the current state of an application dependent input button +// as set by uiSetButton(). +// the function returns 1 if the button has been set to pressed, 0 for released. int uiGetButton(int button); +// sets the current cursor position (usually belonging to a mouse) to the +// screen coordinates at (x,y) void uiSetCursor(int x, int y); + +// returns the current cursor position in screen coordinates as set by +// uiSetCursor() void uiGetCursor(int *x, int *y); +// clear the item buffer; uiClear() should be called before each UI declaration +// to avoid concatenation of the same UI multiple times. +// After the call, all previously declared item IDs are invalid, and all +// application dependent context data has been freed. void uiClear(); +// add a new UI item with size (w,h) and return the new items ID. +// parent is the item ID of the containing item; an item ID of 0 refers to the +// root item. +// handle is an application defined 64-bit handle. If handle is 0, the item +// will not be interactive. +// kind is one of UI_COLUMN, UI_ROW, UI_LABEL, UI_BUTTON and influences the +// items behavior in layouting and input handling. +// If w or h are 0, the dimension is marked as dynamic and will be rescaled +// accordingly by the containing element. +// if data is not NULL, it points to an application defined buffer conforming +// to the declaration of UIdata; The first element must always be a 32-bit +// integer denoting the size of the structure in bytes. The contents of data +// will be copied and can be read back later using uiGetData(). The data +// pointer passed to uiItem() is allowed to become invalid right after the call. int uiItem(int parent, UIhandle handle, int kind, - int w, int h, void *data); + int w, int h, const void *data); + +// add a new UI item of type UI_COLUMN. +// this is a shorthand of the equivalent call +// int id = uiItem(parent,0,UI_COLUMN,0,0,NULL); uiSetSpacing(id, spacing); int uiColumn(int parent, int spacing); + +// this is a shorthand of the equivalent call +// int id = uiItem(parent,0,UI_ROW,0,0,NULL); uiSetSpacing(id, spacing); 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(). +// this is an O(N) operation for N = number of declared items. void uiLayout(); +// 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. +// if item is 0, the child item count of the root item will be returned. +int uiGetChildCount(int item); + +// returns the first child item of a container item. If the item is not +// a container or does not contain any items, -1 is returned. +// if item is 0, the first child item of the root item will be returned. int uiFirstChild(int item); + +// returns the last child item of a container item. If the item is not +// a container or does not contain any items, -1 is returned. +// if item is 0, the last child item of the root item will be returned. int uiLastChild(int item); -int uiNextSibling(int item); + +// returns an items parent container item. +// if item is 0, -1 will be returned. int uiParent(int item); +// returns an items child index relative to its parent. If the item is the +// first item, the return value is 0; If the item is the last item, the return +// value is equivalent to uiGetChildCount(uiParent(item))-1. +// if item is 0, 0 will be returned. +int uiGetChildId(int item); + +// returns an items next sibling in the list of the parent containers children. +// if item is 0 or the item is the last child item, -1 will be returned. +int uiNextSibling(int item); + +// assign a spacing value by which child items of a container items will be +// separated. If item is not a container type, the call has no effect. void uiSetSpacing(int item, int spacing); + +// returns the current spacing value assigned to item by uiSetSpacing() int uiGetSpacing(int item); +// returns the kind of the item as passed to uiItem(). +// The returned value is one of UI_COLUMN, UI_ROW, UI_LABEL, UI_BUTTON. 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 +// undefined. UIrect uiGetRect(int item); + +// returns the items layout rectangle in absolute coordinates. If +// uiGetAbsoluteRect() is called before uiLayout(), 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. +// This function is primarily used to position the root element. void uiSetRect(int item, int x, int y, int w, int h); -void *uiGetData(int item); -int uiGetChildId(int item); -int uiGetChildCount(int item); + +// return the application-dependent context data for an item as passed to +// uiItem(). The memory of the pointer is managed by the UI context. +const void *uiGetData(int item); + +// return the application-dependent handle of the item as passed to uiItem(). int uiGetHandle(int item); + +// return the current state of the item. +// The returned value is one of UI_COLD, UI_HOT, UI_ACTIVE. int uiGetState(int item); +// set the handler callback for an interactive item. The meaning of the +// callback is dependent on the item kind. +void uiSetHandler(int item, UIhandler handler); + #endif // _UI_H_ +#define UI_IMPLEMENTATION #ifdef UI_IMPLEMENTATION #include @@ -112,23 +247,40 @@ int uiGetState(int item); #define UI_MAX_KIND 16 typedef struct UIitem { - UIhandle handle; - int parent; + // container structure + // number of kids int numkids; + // index of first kid + int firstkid; + // index of last kid + int lastkid; + + // child structure + + // parent item + int parent; // index of kid relative to parent int kidid; + // index of next sibling with same parent + int nextitem; + + // attributes + + // declaration independent unique handle (for persistence) + UIhandle handle; + // layout rectangle UIrect rect; + // absolute position int absx,absy; + // widget type int kind; + // index of data or -1 for none int data; + // layouting containers: spacing between items int spacing; - // index of first kid - int firstkid; - // index of last kid - int lastkid; - // index of next sibling with same parent - int nextitem; + // handler + UIhandler handler; } UIitem; struct UIcontext { @@ -154,10 +306,13 @@ UIcontext *uiCreateContext() { void uiMakeCurrent(UIcontext *ctx) { ui_context = ctx; - uiClear(); + if (ui_context) + uiClear(); } void uiDestroyContext(UIcontext *ctx) { + if (ui_context == ctx) + uiMakeCurrent(NULL); free(ctx); } @@ -208,7 +363,7 @@ void uiClear() { item->data = -1; } -int uiAllocItem(int parent, UIhandle handle, int kind, void *data) { +int uiAllocItem(int parent, UIhandle handle, int kind, const void *data) { assert(ui_context && (ui_context->count < UI_MAX_ITEMS)); assert(parent >= 0); int idx = ui_context->count++; @@ -240,7 +395,7 @@ int uiAllocItem(int parent, UIhandle handle, int kind, void *data) { return idx; } -int uiItem(int parent, UIhandle handle, int kind, int w, int h, void *data) { +int uiItem(int parent, UIhandle handle, int kind, int w, int h, const void *data) { int idx = uiAllocItem(parent, handle, kind, data); UIitem *item = uiItemPtr(idx); item->rect.w = w; @@ -308,7 +463,7 @@ int uiGetKind(int item) { return uiItemPtr(item)->kind; } -void *uiGetData(int item) { +const void *uiGetData(int item) { UIitem *pitem = uiItemPtr(item); if (pitem->data < 0) return NULL; return ui_context->data + pitem->data; @@ -318,6 +473,10 @@ int uiGetHandle(int item) { return uiItemPtr(item)->handle; } +void uiSetHandler(int item, UIhandler handler) { + uiItemPtr(item)->handler = handler; +} + int uiGetChildId(int item) { return uiItemPtr(item)->kidid; } @@ -326,19 +485,17 @@ int uiGetChildCount(int item) { return uiItemPtr(item)->numkids; } -void uiLayoutItem(int item, int x, int y); -void uiLayoutChildren(int item, int x, int y) { +void uiLayoutItem(int item); +void uiLayoutChildren(int item) { int kid = uiFirstChild(item); while (kid > 0) { - uiLayoutItem(kid, x, y); + uiLayoutItem(kid); kid = uiNextSibling(kid); } } -void uiLayoutItem(int item, int x, int y) { +void uiLayoutItem(int item) { UIrect rect = uiGetRect(item); - rect.x += x; - rect.y += y; switch(uiGetKind(item)) { case UI_COLUMN: @@ -352,7 +509,7 @@ void uiLayoutItem(int item, int x, int y) { kid = uiNextSibling(kid); } - uiLayoutChildren(item, rect.x, rect.y); + uiLayoutChildren(item); int spacing = uiItemPtr(item)->spacing; int h = -spacing; @@ -415,7 +572,7 @@ void uiLayoutItem(int item, int x, int y) { kid = uiNextSibling(kid); } - uiLayoutChildren(item, rect.x, rect.y); + uiLayoutChildren(item); // adjust row height to tallest child kid = uiFirstChild(item); @@ -460,7 +617,7 @@ void uiUpdateItemState(int item, int x, int y) { } void uiLayout() { - uiLayoutItem(0, 0, 0); + uiLayoutItem(0); uiUpdateItemState(0, 0, 0); if (!uiGetButton(0)) { ui_context->active = 0;