- oui: callbacks for appending new items - oui: more API changespull/1/head
@@ -30,6 +30,10 @@ typedef enum { | |||||
ST_RADIO = 2, | ST_RADIO = 2, | ||||
// progress slider | // progress slider | ||||
ST_SLIDER = 3, | ST_SLIDER = 3, | ||||
// column | |||||
ST_COLUMN = 4, | |||||
// row | |||||
ST_ROW = 5, | |||||
} SubType; | } SubType; | ||||
typedef struct { | typedef struct { | ||||
@@ -66,26 +70,39 @@ void init(NVGcontext *vg) { | |||||
// the container the item is in has negative spacing, and the item | // the container the item is in has negative spacing, and the item | ||||
// is first or last element in a sequence of 2 or more elements. | // is first or last element in a sequence of 2 or more elements. | ||||
int cornerFlags(int item) { | int cornerFlags(int item) { | ||||
/* | |||||
int parent = uiParent(item); | int parent = uiParent(item); | ||||
int spacing = uiGetSpacing(parent); | |||||
if (spacing >= 0) return BND_CORNER_NONE; | |||||
int numkids = uiGetChildCount(parent); | int numkids = uiGetChildCount(parent); | ||||
int numid = uiGetChildId(item); | |||||
if (numkids < 2) return BND_CORNER_NONE; | if (numkids < 2) return BND_CORNER_NONE; | ||||
UIuvec2 flags = uiGetLayoutFlags(parent); | |||||
if (flags.x & UI_LAYOUT_PACK) { | |||||
if (!numid) return BND_CORNER_RIGHT; | |||||
else if (numid == numkids-1) return BND_CORNER_LEFT; | |||||
else return BND_CORNER_ALL; | |||||
} else if (flags.y & UI_LAYOUT_PACK) { | |||||
if (!numid) return BND_CORNER_DOWN; | |||||
else if (numid == numkids-1) return BND_CORNER_TOP; | |||||
else return BND_CORNER_ALL; | |||||
}*/ | |||||
const UIData *head = (const UIData *)uiGetData(parent); | |||||
if (head) { | |||||
int numid = uiGetChildId(item); | |||||
switch(head->subtype) { | |||||
case ST_COLUMN: { | |||||
if (!numid) return BND_CORNER_DOWN; | |||||
else if (numid == numkids-1) return BND_CORNER_TOP; | |||||
else return BND_CORNER_ALL; | |||||
} break; | |||||
case ST_ROW: { | |||||
if (!numid) return BND_CORNER_RIGHT; | |||||
else if (numid == numkids-1) return BND_CORNER_LEFT; | |||||
else return BND_CORNER_ALL; | |||||
} break; | |||||
default: break; | |||||
} | |||||
} | |||||
return BND_CORNER_NONE; | return BND_CORNER_NONE; | ||||
} | } | ||||
void testrect(NVGcontext *vg, UIrect rect) { | |||||
#if 0 | |||||
nvgBeginPath(vg); | |||||
nvgRect(vg,rect.x+0.5,rect.y+0.5,rect.w-1,rect.h-1); | |||||
nvgStrokeColor(vg,nvgRGBf(1,0,0)); | |||||
nvgStrokeWidth(vg,1); | |||||
nvgStroke(vg); | |||||
#endif | |||||
} | |||||
void drawUI(NVGcontext *vg, int item, int x, int y) { | void drawUI(NVGcontext *vg, int item, int x, int y) { | ||||
const UIData *head = (const UIData *)uiGetData(item); | const UIData *head = (const UIData *)uiGetData(item); | ||||
UIrect rect = uiGetRect(item); | UIrect rect = uiGetRect(item); | ||||
@@ -93,7 +110,9 @@ void drawUI(NVGcontext *vg, int item, int x, int y) { | |||||
rect.y += y; | rect.y += y; | ||||
if (head) { | if (head) { | ||||
switch(head->subtype) { | switch(head->subtype) { | ||||
default: | |||||
default: { | |||||
testrect(vg,rect); | |||||
} break; | |||||
case ST_LABEL: { | case ST_LABEL: { | ||||
assert(head); | assert(head); | ||||
const UIButtonData *data = (UIButtonData*)head; | const UIButtonData *data = (UIButtonData*)head; | ||||
@@ -126,11 +145,7 @@ void drawUI(NVGcontext *vg, int item, int x, int y) { | |||||
} break; | } break; | ||||
} | } | ||||
} else { | } else { | ||||
nvgBeginPath(vg); | |||||
nvgRect(vg,rect.x+0.5,rect.y+0.5,rect.w-1,rect.h-1); | |||||
nvgStrokeColor(vg,nvgRGBf(1,0,0)); | |||||
nvgStrokeWidth(vg,1); | |||||
nvgStroke(vg); | |||||
testrect(vg,rect); | |||||
} | } | ||||
int kid = uiFirstChild(item); | int kid = uiFirstChild(item); | ||||
@@ -140,58 +155,92 @@ void drawUI(NVGcontext *vg, int item, int x, int y) { | |||||
} | } | ||||
} | } | ||||
int label(int iconid, const char *label) { | |||||
int label(int parent, int iconid, const char *label) { | |||||
int item = uiItem(); | int item = uiItem(); | ||||
uiSetSize(item, 0, BND_WIDGET_HEIGHT); | uiSetSize(item, 0, BND_WIDGET_HEIGHT); | ||||
UIButtonData *data = (UIButtonData *)uiAllocData(item, sizeof(UIButtonData)); | UIButtonData *data = (UIButtonData *)uiAllocData(item, sizeof(UIButtonData)); | ||||
data->head.subtype = ST_LABEL; | data->head.subtype = ST_LABEL; | ||||
data->iconid = iconid; | data->iconid = iconid; | ||||
data->label = label; | data->label = label; | ||||
uiAppend(parent, item); | |||||
return item; | return item; | ||||
} | } | ||||
int button(UIhandle handle, 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); | |||||
} | |||||
int button(int parent, UIhandle handle, int iconid, const char *label, | |||||
UIhandler handler) { | UIhandler handler) { | ||||
int item = uiItem(); | |||||
// create new ui item | |||||
int item = uiItem(); | |||||
// set persistent handle for item that is used | |||||
// to track activity over time | |||||
uiSetHandle(item, handle); | uiSetHandle(item, handle); | ||||
// set size of wiget; horizontal size is dynamic, vertical is fixed | |||||
uiSetSize(item, 0, BND_WIDGET_HEIGHT); | uiSetSize(item, 0, BND_WIDGET_HEIGHT); | ||||
// attach event handler e.g. demohandler above | |||||
uiSetHandler(item, handler, UI_BUTTON0_HOT_UP); | 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 *)uiAllocData(item, sizeof(UIButtonData)); | ||||
data->head.subtype = ST_BUTTON; | data->head.subtype = ST_BUTTON; | ||||
data->iconid = iconid; | data->iconid = iconid; | ||||
data->label = label; | data->label = label; | ||||
uiAppend(parent, item); | |||||
return item; | return item; | ||||
} | } | ||||
// simple logic for a slider | // simple logic for a slider | ||||
// starting offset of the currently active slider | |||||
static float sliderstart = 0.0; | static float sliderstart = 0.0; | ||||
// event handler for slider (same handler for all sliders) | |||||
void sliderhandler(int item, UIevent event) { | void sliderhandler(int item, UIevent event) { | ||||
// retrieve the custom data we saved with the slider | |||||
UISliderData *data = (UISliderData *)uiGetData(item); | UISliderData *data = (UISliderData *)uiGetData(item); | ||||
switch(event) { | switch(event) { | ||||
default: break; | default: break; | ||||
case UI_BUTTON0_DOWN: { | case UI_BUTTON0_DOWN: { | ||||
// button was pressed for the first time; capture initial | |||||
// slider value. | |||||
sliderstart = *data->progress; | sliderstart = *data->progress; | ||||
} break; | } break; | ||||
case UI_BUTTON0_CAPTURE: { | case UI_BUTTON0_CAPTURE: { | ||||
// called for every frame that the button is pressed. | |||||
// get the delta between the click point and the current | |||||
// mouse position | |||||
UIvec2 pos = uiGetCursorStartDelta(); | UIvec2 pos = uiGetCursorStartDelta(); | ||||
// get the items layouted rectangle | |||||
UIrect rc = uiGetRect(item); | UIrect rc = uiGetRect(item); | ||||
// calculate our new offset and clamp | |||||
float value = sliderstart + ((float)pos.x / (float)rc.w); | float value = sliderstart + ((float)pos.x / (float)rc.w); | ||||
value = (value<0)?0:(value>1)?1:value; | value = (value<0)?0:(value>1)?1:value; | ||||
// assign the new value | |||||
*data->progress = value; | *data->progress = value; | ||||
} break; | } break; | ||||
} | } | ||||
} | } | ||||
int slider(UIhandle handle, const char *label, float *progress) { | |||||
int slider(int parent, UIhandle handle, const char *label, float *progress) { | |||||
// create new ui item | |||||
int item = uiItem(); | int item = uiItem(); | ||||
// set persistent handle for item that is used | |||||
// to track activity over time | |||||
uiSetHandle(item, handle); | uiSetHandle(item, handle); | ||||
// set size of wiget; horizontal size is dynamic, vertical is fixed | |||||
uiSetSize(item, 0, BND_WIDGET_HEIGHT); | uiSetSize(item, 0, BND_WIDGET_HEIGHT); | ||||
// attach our slider event handler and capture two classes of events | |||||
uiSetHandler(item, sliderhandler, | uiSetHandler(item, sliderhandler, | ||||
UI_BUTTON0_DOWN | UI_BUTTON0_CAPTURE); | 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 *)uiAllocData(item, sizeof(UISliderData)); | ||||
data->head.subtype = ST_SLIDER; | data->head.subtype = ST_SLIDER; | ||||
data->label = label; | data->label = label; | ||||
data->progress = progress; | data->progress = progress; | ||||
uiAppend(parent, item); | |||||
return item; | return item; | ||||
} | } | ||||
@@ -201,7 +250,7 @@ void radiohandler(int item, UIevent event) { | |||||
*data->value = uiGetChildId(item); | *data->value = uiGetChildId(item); | ||||
} | } | ||||
int radio(UIhandle handle, int iconid, const char *label, int *value) { | |||||
int radio(int parent, UIhandle handle, int iconid, const char *label, int *value) { | |||||
int item = uiItem(); | int item = uiItem(); | ||||
uiSetHandle(item, handle); | uiSetHandle(item, handle); | ||||
uiSetSize(item, label?0:BND_TOOL_WIDTH, BND_WIDGET_HEIGHT); | uiSetSize(item, label?0:BND_TOOL_WIDTH, BND_WIDGET_HEIGHT); | ||||
@@ -211,30 +260,82 @@ int radio(UIhandle handle, int iconid, const char *label, int *value) { | |||||
data->label = label; | data->label = label; | ||||
data->value = value; | data->value = value; | ||||
uiSetHandler(item, radiohandler, UI_BUTTON0_DOWN); | uiSetHandler(item, radiohandler, UI_BUTTON0_DOWN); | ||||
uiAppend(parent, item); | |||||
return item; | return item; | ||||
} | } | ||||
int addVList(int parent, int item) { | |||||
int last = uiLastChild(parent); | |||||
uiSetRelativeTo(item, -1, last, -1, -1); | |||||
void columnhandler(int parent, UIevent event) { | |||||
int item = uiLastChild(parent); | |||||
int last = uiPrevSibling(item); | |||||
// mark the new item as positioned under the previous item | |||||
uiSetRelToTop(item, last); | |||||
// fill parent horizontally, anchor to previous item vertically | |||||
uiSetLayout(item, UI_HFILL|UI_TOP); | uiSetLayout(item, UI_HFILL|UI_TOP); | ||||
uiSetParent(item, parent); | |||||
// if not the first item, add a margin of 1 | |||||
uiSetMargins(item, 0, (last < 0)?0:1, 0, 0); | uiSetMargins(item, 0, (last < 0)?0:1, 0, 0); | ||||
} | |||||
int column(int parent) { | |||||
int item = uiItem(); | |||||
uiSetHandler(item, columnhandler, UI_APPEND); | |||||
uiAppend(parent, item); | |||||
return item; | |||||
} | |||||
void vgrouphandler(int parent, UIevent event) { | |||||
int item = uiLastChild(parent); | |||||
int last = uiPrevSibling(item); | |||||
// mark the new item as positioned under the previous item | |||||
uiSetRelToTop(item, last); | |||||
// fill parent horizontally, anchor to previous item vertically | |||||
uiSetLayout(item, UI_HFILL|UI_TOP); | |||||
// if not the first item, add a margin | |||||
uiSetMargins(item, 0, (last < 0)?0:-2, 0, 0); | |||||
} | |||||
int vgroup(int parent) { | |||||
int item = uiItem(); | |||||
UIData *data = (UIData *)uiAllocData(item, sizeof(UIData)); | |||||
data->subtype = ST_COLUMN; | |||||
uiSetHandler(item, vgrouphandler, UI_APPEND); | |||||
uiAppend(parent, item); | |||||
return item; | return item; | ||||
} | } | ||||
int addHGroup(int parent, int item) { | |||||
int last = uiLastChild(parent); | |||||
uiSetRelativeTo(item, last, -1, -1, -1); | |||||
uiSetLayout(item, UI_LEFT); | |||||
uiSetParent(item, parent); | |||||
void hgrouphandler(int parent, UIevent event) { | |||||
int item = uiLastChild(parent); | |||||
int last = uiPrevSibling(item); | |||||
uiSetRelToLeft(item, last); | |||||
if (last > 0) | |||||
uiSetRelToRight(last, item); | |||||
uiSetLayout(item, UI_LEFT|UI_RIGHT); | |||||
uiSetMargins(item, (last < 0)?0:-1, 0, 0, 0); | uiSetMargins(item, (last < 0)?0:-1, 0, 0, 0); | ||||
} | |||||
int hgroup(int parent) { | |||||
int item = uiItem(); | |||||
UIData *data = (UIData *)uiAllocData(item, sizeof(UIData)); | |||||
data->subtype = ST_ROW; | |||||
uiSetHandler(item, hgrouphandler, UI_APPEND); | |||||
uiAppend(parent, item); | |||||
return item; | return item; | ||||
} | } | ||||
void demohandler(int item, UIevent event) { | |||||
const UIButtonData *data = (const UIButtonData *)uiGetData(item); | |||||
printf("clicked: %lld %s\n", uiGetHandle(item), data->label); | |||||
void rowhandler(int parent, UIevent event) { | |||||
int item = uiLastChild(parent); | |||||
int last = uiPrevSibling(item); | |||||
uiSetRelToLeft(item, last); | |||||
if (last > 0) | |||||
uiSetRelToRight(last, item); | |||||
uiSetLayout(item, UI_LEFT|UI_RIGHT); | |||||
uiSetMargins(item, (last < 0)?0:8, 0, 0, 0); | |||||
} | |||||
int row(int parent) { | |||||
int item = uiItem(); | |||||
uiSetHandler(item, rowhandler, UI_APPEND); | |||||
uiAppend(parent, item); | |||||
return item; | |||||
} | } | ||||
void draw(NVGcontext *vg, float w, float h) { | void draw(NVGcontext *vg, float w, float h) { | ||||
@@ -427,31 +528,28 @@ void draw(NVGcontext *vg, float w, float h) { | |||||
uiClear(); | uiClear(); | ||||
int root = uiItem(); | |||||
// position root element | // position root element | ||||
uiSetLayout(0,UI_LEFT|UI_TOP); | uiSetLayout(0,UI_LEFT|UI_TOP); | ||||
uiSetMargins(0,600,10,0,0); | uiSetMargins(0,600,10,0,0); | ||||
uiSetSize(0,250,400); | uiSetSize(0,250,400); | ||||
int c = button(1, BND_ICONID(6,3), "Item 1", demohandler); | |||||
uiSetParent(c, 0); | |||||
uiSetSize(c, 100, 100); | |||||
uiSetLayout(c, UI_CENTER); | |||||
int col = column(0); | |||||
uiSetLayout(col, UI_TOP|UI_HFILL); | |||||
addVList(0, button(1, BND_ICONID(6,3), "Item 1", demohandler)); | |||||
addVList(0, button(2, BND_ICONID(6,3), "Item 2", demohandler)); | |||||
button(col, 1, BND_ICONID(6,3), "Item 1", demohandler); | |||||
button(col, 2, BND_ICONID(6,3), "Item 2", demohandler); | |||||
static int enum1 = 0; | static int enum1 = 0; | ||||
{ | { | ||||
int h = addVList(0, uiItem()); | |||||
addHGroup(h, radio(3, BND_ICONID(6,3), "Item 3.0", &enum1)); | |||||
addHGroup(h, radio(4, BND_ICONID(0,10), NULL, &enum1)); | |||||
addHGroup(h, radio(5, BND_ICONID(1,10), NULL, &enum1)); | |||||
addHGroup(h, radio(6, BND_ICONID(6,3), "Item 3.3", &enum1)); | |||||
int h = hgroup(col); | |||||
radio(h, 3, BND_ICONID(6,3), "Item 3.0", &enum1); | |||||
radio(h, 4, BND_ICONID(0,10), NULL, &enum1); | |||||
radio(h, 5, BND_ICONID(1,10), NULL, &enum1); | |||||
radio(h, 6, BND_ICONID(6,3), "Item 3.3", &enum1); | |||||
} | } | ||||
/* | |||||
static float progress1 = 0.25f; | static float progress1 = 0.25f; | ||||
static float progress2 = 0.75f; | static float progress2 = 0.75f; | ||||
@@ -470,7 +568,6 @@ void draw(NVGcontext *vg, float w, float h) { | |||||
} | } | ||||
button(col, 11, BND_ICONID(6,3), "Item 5", NULL); | button(col, 11, BND_ICONID(6,3), "Item 5", NULL); | ||||
*/ | |||||
uiProcess(); | uiProcess(); | ||||
@@ -93,6 +93,8 @@ typedef enum UIevent { | |||||
UI_BUTTON0_HOT_UP = 0x04, | UI_BUTTON0_HOT_UP = 0x04, | ||||
// item is being captured (button 0 constantly pressed) | // item is being captured (button 0 constantly pressed) | ||||
UI_BUTTON0_CAPTURE = 0x08, | UI_BUTTON0_CAPTURE = 0x08, | ||||
// item has been added to container | |||||
UI_APPEND = 0x10, | |||||
} UIevent; | } UIevent; | ||||
// handler callback; event is one of UI_EVENT_* | // handler callback; event is one of UI_EVENT_* | ||||
@@ -164,10 +166,9 @@ void uiClear(); | |||||
int uiItem(); | int uiItem(); | ||||
// assign an item to a container. | // assign an item to a container. | ||||
// parent is the item ID of the containing item; an item ID of 0 refers to the | |||||
// root item. | |||||
// if item is already assigned to a parent, an assertion will be thrown. | |||||
void uiSetParent(int item, int parent); | |||||
// an item ID of 0 refers to the root item. | |||||
// if child is already assigned to a parent, an assertion will be thrown. | |||||
int uiAppend(int item, int child); | |||||
// layout all added items and update the internal state according to the | // layout all added items and update the internal state according to the | ||||
// current cursor position and button states. | // current cursor position and button states. | ||||
@@ -203,11 +204,29 @@ int uiGetChildId(int item); | |||||
// returns an items next sibling in the list of the parent containers children. | // 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. | // if item is 0 or the item is the last child item, -1 will be returned. | ||||
int uiNextSibling(int item); | int uiNextSibling(int item); | ||||
// returns an items previous sibling in the list of the parent containers | |||||
// children. | |||||
// if item is 0 or the item is the first child item, -1 will be returned. | |||||
int uiPrevSibling(int item); | |||||
void uiSetSize(int item, int w, int h); | void uiSetSize(int item, int w, int h); | ||||
int uiGetWidth(int item); | |||||
int uiGetHeight(int item); | |||||
void uiSetLayout(int item, int flags); | void uiSetLayout(int item, int flags); | ||||
int uiGetLayout(int item); | |||||
void uiSetMargins(int item, int t, int r, int b, int l); | void uiSetMargins(int item, int t, int r, int b, int l); | ||||
void uiSetRelativeTo(int item, int titem, int ritem, int bitem, int litem); | |||||
int uiGetMarginLeft(int item); | |||||
int uiGetMarginTop(int item); | |||||
int uiGetMarginRight(int item); | |||||
int uiGetMarginDown(int item); | |||||
void uiSetRelToLeft(int item, int other); | |||||
int uiGetRelToLeft(int item); | |||||
void uiSetRelToTop(int item, int other); | |||||
int uiGetRelToTop(int item); | |||||
void uiSetRelToRight(int item, int other); | |||||
int uiGetRelToRight(int item); | |||||
void uiSetRelToDown(int item, int other); | |||||
int uiGetRelToDown(int item); | |||||
// returns the items layout rectangle relative to the parent. If uiGetRect() | // returns the items layout rectangle relative to the parent. If uiGetRect() | ||||
// is called before uiProcess(), the values of the returned rectangle are | // is called before uiProcess(), the values of the returned rectangle are | ||||
@@ -293,6 +312,8 @@ typedef struct UIitem { | |||||
int kidid; | int kidid; | ||||
// index of next sibling with same parent | // index of next sibling with same parent | ||||
int nextitem; | int nextitem; | ||||
// index of previous sibling with same parent | |||||
int previtem; | |||||
// one or multiple of UIlayoutFlags | // one or multiple of UIlayoutFlags | ||||
int layout_flags; | int layout_flags; | ||||
@@ -303,6 +324,9 @@ typedef struct UIitem { | |||||
int margins[4]; | int margins[4]; | ||||
// neighbors to position borders to | // neighbors to position borders to | ||||
int relto[4]; | int relto[4]; | ||||
// computed size | |||||
UIvec2 computed_size; | |||||
// relative rect | // relative rect | ||||
UIrect rect; | UIrect rect; | ||||
@@ -439,20 +463,10 @@ UIitem *uiItemPtr(int item) { | |||||
void uiClear() { | void uiClear() { | ||||
assert(ui_context); | assert(ui_context); | ||||
ui_context->count = 1; | |||||
ui_context->count = 0; | |||||
ui_context->datasize = 0; | ui_context->datasize = 0; | ||||
ui_context->hot_item = -1; | ui_context->hot_item = -1; | ||||
ui_context->active_item = -1; | ui_context->active_item = -1; | ||||
// init root object | |||||
UIitem *item = ui_context->items; | |||||
memset(item, 0, sizeof(UIitem)); | |||||
item->parent = -1; | |||||
item->firstkid = -1; | |||||
item->lastkid = -1; | |||||
item->nextitem = -1; | |||||
item->data = -1; | |||||
} | } | ||||
int uiItem() { | int uiItem() { | ||||
@@ -464,26 +478,37 @@ int uiItem() { | |||||
item->firstkid = -1; | item->firstkid = -1; | ||||
item->lastkid = -1; | item->lastkid = -1; | ||||
item->nextitem = -1; | item->nextitem = -1; | ||||
item->previtem = -1; | |||||
item->data = -1; | item->data = -1; | ||||
for (int i = 0; i < 4; ++i) | for (int i = 0; i < 4; ++i) | ||||
item->relto[i] = -1; | item->relto[i] = -1; | ||||
return idx; | return idx; | ||||
} | } | ||||
void uiSetParent(int item, int parent) { | |||||
assert(item > 0); | |||||
assert(uiParent(item) == -1); | |||||
void uiNotifyItem(int item, UIevent event) { | |||||
UIitem *pitem = uiItemPtr(item); | UIitem *pitem = uiItemPtr(item); | ||||
UIitem *pparent = uiItemPtr(parent); | |||||
pitem->parent = parent; | |||||
if (pitem->handler && (pitem->event_flags & event)) { | |||||
pitem->handler(item, event); | |||||
} | |||||
} | |||||
int uiAppend(int item, int child) { | |||||
assert(child > 0); | |||||
assert(uiParent(child) == -1); | |||||
UIitem *pitem = uiItemPtr(child); | |||||
UIitem *pparent = uiItemPtr(item); | |||||
pitem->parent = item; | |||||
pitem->kidid = pparent->numkids++; | pitem->kidid = pparent->numkids++; | ||||
if (pparent->lastkid < 0) { | if (pparent->lastkid < 0) { | ||||
pparent->firstkid = item; | |||||
pparent->lastkid = item; | |||||
pparent->firstkid = child; | |||||
pparent->lastkid = child; | |||||
} else { | } else { | ||||
uiItemPtr(pparent->lastkid)->nextitem = item; | |||||
pparent->lastkid = item; | |||||
pitem->previtem = pparent->lastkid; | |||||
uiItemPtr(pparent->lastkid)->nextitem = child; | |||||
pparent->lastkid = child; | |||||
} | } | ||||
uiNotifyItem(item, UI_APPEND); | |||||
return child; | |||||
} | } | ||||
void uiSetSize(int item, int w, int h) { | void uiSetSize(int item, int w, int h) { | ||||
@@ -492,9 +517,20 @@ void uiSetSize(int item, int w, int h) { | |||||
pitem->size.y = h; | pitem->size.y = h; | ||||
} | } | ||||
int uiGetWidth(int item) { | |||||
return uiItemPtr(item)->size.x; | |||||
} | |||||
int uiGetHeight(int item) { | |||||
return uiItemPtr(item)->size.y; | |||||
} | |||||
void uiSetLayout(int item, int flags) { | void uiSetLayout(int item, int flags) { | ||||
UIitem *pitem = uiItemPtr(item); | |||||
pitem->layout_flags = flags; | |||||
uiItemPtr(item)->layout_flags = flags; | |||||
} | |||||
int uiGetLayout(int item) { | |||||
return uiItemPtr(item)->layout_flags; | |||||
} | } | ||||
void uiSetMargins(int item, int l, int t, int r, int b) { | void uiSetMargins(int item, int l, int t, int r, int b) { | ||||
@@ -505,14 +541,54 @@ void uiSetMargins(int item, int l, int t, int r, int b) { | |||||
pitem->margins[3] = b; | pitem->margins[3] = b; | ||||
} | } | ||||
void uiSetRelativeTo(int item, int litem, int titem, int ritem, int bitem) { | |||||
UIitem *pitem = uiItemPtr(item); | |||||
pitem->relto[0] = litem; | |||||
pitem->relto[1] = titem; | |||||
pitem->relto[2] = ritem; | |||||
pitem->relto[3] = bitem; | |||||
int uiGetMarginLeft(int item) { | |||||
return uiItemPtr(item)->margins[0]; | |||||
} | |||||
int uiGetMarginTop(int item) { | |||||
return uiItemPtr(item)->margins[1]; | |||||
} | |||||
int uiGetMarginRight(int item) { | |||||
return uiItemPtr(item)->margins[2]; | |||||
} | |||||
int uiGetMarginDown(int item) { | |||||
return uiItemPtr(item)->margins[3]; | |||||
} | |||||
void uiSetRelToLeft(int item, int other) { | |||||
assert((other < 0) || (uiParent(other) == uiParent(item))); | |||||
uiItemPtr(item)->relto[0] = other; | |||||
} | |||||
int uiGetRelToLeft(int item) { | |||||
return uiItemPtr(item)->relto[0]; | |||||
} | } | ||||
void uiSetRelToTop(int item, int other) { | |||||
assert((other < 0) || (uiParent(other) == uiParent(item))); | |||||
uiItemPtr(item)->relto[1] = other; | |||||
} | |||||
int uiGetRelToTop(int item) { | |||||
return uiItemPtr(item)->relto[1]; | |||||
} | |||||
void uiSetRelToRight(int item, int other) { | |||||
assert((other < 0) || (uiParent(other) == uiParent(item))); | |||||
uiItemPtr(item)->relto[2] = other; | |||||
} | |||||
int uiGetRelToRight(int item) { | |||||
return uiItemPtr(item)->relto[2]; | |||||
} | |||||
void uiSetRelToDown(int item, int other) { | |||||
assert((other < 0) || (uiParent(other) == uiParent(item))); | |||||
uiItemPtr(item)->relto[3] = other; | |||||
} | |||||
int uiGetRelToDown(int item) { | |||||
return uiItemPtr(item)->relto[3]; | |||||
} | |||||
UI_INLINE int uiComputeChainSize(UIitem *pkid, int dim) { | UI_INLINE int uiComputeChainSize(UIitem *pkid, int dim) { | ||||
UIitem *pitem = pkid; | UIitem *pitem = pkid; | ||||
int wdim = dim+2; | int wdim = dim+2; | ||||
@@ -560,6 +636,7 @@ UI_INLINE void uiComputeSizeDim(UIitem *pitem, int dim) { | |||||
} | } | ||||
pitem->rect.v[wdim] = size; | pitem->rect.v[wdim] = size; | ||||
pitem->computed_size.v[dim] = size; | |||||
} | } | ||||
} | } | ||||
@@ -577,28 +654,35 @@ static void uiComputeBestSize(int item) { | |||||
uiComputeSizeDim(pitem, 1); | uiComputeSizeDim(pitem, 1); | ||||
} | } | ||||
static void uiLayoutChildItem(UIitem *pparent, UIitem *pitem, int dim) { | |||||
static void uiLayoutChildItem(UIitem *pparent, UIitem *pitem, int *dyncount, int dim) { | |||||
if (pitem->visited & (4<<dim)) return; | if (pitem->visited & (4<<dim)) return; | ||||
pitem->visited |= (4<<dim); | pitem->visited |= (4<<dim); | ||||
if (!pitem->size.v[dim]) { | |||||
*dyncount = (*dyncount)+1; | |||||
} | |||||
int wdim = dim+2; | int wdim = dim+2; | ||||
int wl = 0; | int wl = 0; | ||||
int wr = pparent->rect.v[wdim]; | int wr = pparent->rect.v[wdim]; | ||||
int flags = pitem->layout_flags>>dim; | int flags = pitem->layout_flags>>dim; | ||||
if ((flags & UI_LEFT) && (pitem->relto[dim] > 0)) { | |||||
int hasl = (flags & UI_LEFT) && (pitem->relto[dim] > 0); | |||||
int hasr = (flags & UI_RIGHT) && (pitem->relto[wdim] > 0); | |||||
if (hasl) { | |||||
UIitem *pl = uiItemPtr(pitem->relto[dim]); | UIitem *pl = uiItemPtr(pitem->relto[dim]); | ||||
uiLayoutChildItem(pparent, pl, dim); | |||||
wl = pl->rect.v[dim]+pl->rect.v[wdim]; | |||||
uiLayoutChildItem(pparent, pl, dyncount, dim); | |||||
wl = pl->rect.v[dim]+pl->rect.v[wdim]+pl->margins[wdim]; | |||||
wr -= wl; | wr -= wl; | ||||
} | } | ||||
if ((flags & UI_RIGHT) && (pitem->relto[wdim] > 0)) { | |||||
if (hasr) { | |||||
UIitem *pl = uiItemPtr(pitem->relto[wdim]); | UIitem *pl = uiItemPtr(pitem->relto[wdim]); | ||||
uiLayoutChildItem(pparent, pl, dim); | |||||
wr = pl->rect.v[dim]-wl; | |||||
uiLayoutChildItem(pparent, pl, dyncount, dim); | |||||
wr = pl->rect.v[dim]-pl->margins[dim]-wl; | |||||
} | } | ||||
switch(flags & UI_HFILL) { | switch(flags & UI_HFILL) { | ||||
default: | default: | ||||
case UI_HCENTER: { | case UI_HCENTER: { | ||||
@@ -611,8 +695,28 @@ static void uiLayoutChildItem(UIitem *pparent, UIitem *pitem, int dim) { | |||||
pitem->rect.v[dim] = wl+wr-pitem->rect.v[wdim]-pitem->margins[wdim]; | pitem->rect.v[dim] = wl+wr-pitem->rect.v[wdim]-pitem->margins[wdim]; | ||||
} break; | } break; | ||||
case UI_HFILL: { | case UI_HFILL: { | ||||
pitem->rect.v[dim] = wl+pitem->margins[dim]; | |||||
pitem->rect.v[wdim] = wr-pitem->margins[dim]-pitem->margins[wdim]; | |||||
if (pitem->size.v[dim]) { // hard maximum size; can't stretch | |||||
if (hasl) | |||||
pitem->rect.v[dim] = wl+wr-pitem->rect.v[wdim]-pitem->margins[wdim]; | |||||
else | |||||
pitem->rect.v[dim] = wl+pitem->margins[dim]; | |||||
} else { | |||||
if (1) { //!pitem->rect.v[wdim]) { | |||||
int width = (pparent->rect.v[wdim] - pparent->computed_size.v[dim]); | |||||
int space = width / (*dyncount); | |||||
//int rest = width - space*(*dyncount); | |||||
if (!hasl) { | |||||
pitem->rect.v[dim] = wl+pitem->margins[dim]; | |||||
pitem->rect.v[wdim] = wr-pitem->margins[dim]-pitem->margins[wdim]; | |||||
} else { | |||||
pitem->rect.v[wdim] = space-pitem->margins[dim]-pitem->margins[wdim]; | |||||
pitem->rect.v[dim] = wl+wr-pitem->rect.v[wdim]-pitem->margins[wdim]; | |||||
} | |||||
} else { | |||||
pitem->rect.v[dim] = wl+pitem->margins[dim]; | |||||
pitem->rect.v[wdim] = wr-pitem->margins[dim]-pitem->margins[wdim]; | |||||
} | |||||
} | |||||
} break; | } break; | ||||
} | } | ||||
} | } | ||||
@@ -621,7 +725,8 @@ UI_INLINE void uiLayoutItemDim(UIitem *pitem, int dim) { | |||||
int kid = pitem->firstkid; | int kid = pitem->firstkid; | ||||
while (kid > 0) { | while (kid > 0) { | ||||
UIitem *pkid = uiItemPtr(kid); | UIitem *pkid = uiItemPtr(kid); | ||||
uiLayoutChildItem(pitem, pkid, dim); | |||||
int dyncount = 0; | |||||
uiLayoutChildItem(pitem, pkid, &dyncount, dim); | |||||
kid = uiNextSibling(kid); | kid = uiNextSibling(kid); | ||||
} | } | ||||
} | } | ||||
@@ -655,6 +760,10 @@ int uiNextSibling(int item) { | |||||
return uiItemPtr(item)->nextitem; | return uiItemPtr(item)->nextitem; | ||||
} | } | ||||
int uiPrevSibling(int item) { | |||||
return uiItemPtr(item)->previtem; | |||||
} | |||||
int uiParent(int item) { | int uiParent(int item) { | ||||
return uiItemPtr(item)->parent; | return uiItemPtr(item)->parent; | ||||
} | } | ||||
@@ -730,14 +839,8 @@ int uiFindItem(int item, int x, int y) { | |||||
return -1; | return -1; | ||||
} | } | ||||
void uiNotifyItem(int item, UIevent event) { | |||||
UIitem *pitem = uiItemPtr(item); | |||||
if (pitem->handler && (pitem->event_flags & event)) { | |||||
pitem->handler(item, event); | |||||
} | |||||
} | |||||
void uiProcess() { | void uiProcess() { | ||||
if (!ui_context->count) return; | |||||
uiComputeBestSize(0); | uiComputeBestSize(0); | ||||
// position root element rect | // position root element rect | ||||
uiItemPtr(0)->rect.x = uiItemPtr(0)->margins[0]; | uiItemPtr(0)->rect.x = uiItemPtr(0)->margins[0]; | ||||