Browse Source

updated example to include layout + ui test

pull/1/head
Leonard Ritter 10 years ago
parent
commit
3588acb251
2 changed files with 469 additions and 4 deletions
  1. +7
    -0
      blendish.h
  2. +462
    -4
      example.cpp

+ 7
- 0
blendish.h View File

@@ -192,6 +192,13 @@ typedef enum BNDcornerFlags {
// height of horizontal scrollbar
#define BND_SCROLLBAR_HEIGHT 14

// default vertical spacing
#define BND_VSPACING 1
// default vertical spacing between groups
#define BND_VSPACING_GROUP 8
// default horizontal spacing
#define BND_HSPACING 8

////////////////////////////////////////////////////////////////////////////////

// set the current theme all widgets will be drawn with.


+ 462
- 4
example.cpp View File

@@ -24,7 +24,28 @@
#ifndef _UI_H_
#define _UI_H_

#define UI_COLD 0x0000
#define UI_HOT 0x0001
#define UI_ACTIVE 0x0002
// containers
#define UI_ROOT 0x0100
#define UI_COLUMN 0x0101
#define UI_ROW 0x0102

// controls
#define UI_BUTTON 0x0203

#define UI_MAX_ITEMS 4096
#define UI_MAX_BUFFERSIZE 1048576
#define UI_MAX_DEPTH 64

typedef struct UIcontext UIcontext;
typedef unsigned long long UIhandle;

typedef struct UIrect {
int x, y, w, h;
} UIrect;

UIcontext *uiCreateContext();
void uiMakeCurrent(UIcontext *ctx);
@@ -36,24 +57,83 @@ int uiGetButton(int button);
void uiSetCursor(int x, int y);
void uiGetCursor(int *x, int *y);

void uiClear();

int uiItem(int parent, UIhandle handle, int kind,
int w, int h, void *data, int size);
int uiColumn(int parent, int spacing);
int uiRow(int parent, int spacing);

void uiLayout();

int uiFirstChild(int item);
int uiLastChild(int item);
int uiNextSibling(int item);
int uiParent(int item);

void uiSetSpacing(int item, int spacing);
int uiGetSpacing(int item);

int uiGetKind(int item);
UIrect uiGetRect(int item);
UIrect uiGetScreenRect(int item);
void uiSetRect(int item, int x, int y, int w, int h);
void *uiGetData(int item);
int uiGetChildId(int item);
int uiGetChildCount(int item);
int uiGetHandle(int item);
int uiGetState(int item);

#endif // _UI_H_

#ifdef UI_IMPLEMENTATION

#define UI_MAX_KIND 16

typedef struct UIitem {
UIhandle handle;
int parent;
// number of kids
int numkids;
// index of kid relative to parent
int kidid;
UIrect rect;
int absx,absy;
int kind;
int data;
int spacing;
// index of first kid
int firstkid;
// index of last kid
int lastkid;
// index of next sibling with same parent
int nextitem;
} UIitem;

struct UIcontext {
int cx, cy;
unsigned long long buttons;
int cx, cy;
UIhandle hot;
UIhandle active;
int count;
UIitem items[UI_MAX_ITEMS];
int datasize;
unsigned char data[UI_MAX_BUFFERSIZE];
};

static UIcontext *ui_context = NULL;

UIcontext *uiCreateContext() {
UIcontext *ctx = (UIcontext *)malloc(sizeof(UIcontext));
memset(ctx, 0, sizeof(UIcontext));
return ctx;
}

void uiMakeCurrent(UIcontext *ctx) {
ui_context = ctx;
uiClear();
}

void uiDestroyContext(UIcontext *ctx) {
@@ -85,17 +165,358 @@ void uiGetCursor(int *x, int *y) {
*y = ui_context->cy;
}

UIitem *uiItemPtr(int item) {
assert(ui_context && (item >= 0) && (item < ui_context->count));
return ui_context->items + item;
}

void uiClear() {
assert(ui_context);
ui_context->count = 1;
ui_context->datasize = 0;
ui_context->hot = 0;

// 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->kind = UI_ROOT;
item->data = -1;
}

int uiAllocItem(int parent, UIhandle handle, int kind, void *data, int size) {
assert(ui_context && (ui_context->count < UI_MAX_ITEMS));
assert((size >= 0) && ((ui_context->datasize+size) <= UI_MAX_BUFFERSIZE));
assert(parent >= 0);
int idx = ui_context->count++;
UIitem *item = uiItemPtr(idx);
memset(item, 0, sizeof(UIitem));
item->parent = parent;
item->handle = handle;
item->firstkid = -1;
item->lastkid = -1;
item->nextitem = -1;
item->kidid = ui_context->items[parent].numkids++;
if (ui_context->items[parent].lastkid < 0) {
ui_context->items[parent].firstkid = idx;
ui_context->items[parent].lastkid = idx;
} else {
ui_context->items[ui_context->items[parent].lastkid].nextitem = idx;
ui_context->items[parent].lastkid = idx;
}
item->kind = kind;
item->data = -1;
if (data && size) {
item->data = ui_context->datasize;
ui_context->datasize += size;
memcpy(ui_context->data + item->data, data, size);
}
return idx;
}

int uiItem(
int parent, UIhandle handle, int kind, int w, int h, void *data, int size) {
int idx = uiAllocItem(parent, handle, kind, data, size);
UIitem *item = uiItemPtr(idx);
item->rect.w = w;
item->rect.h = h;
return idx;
}

void uiSetSpacing(int item, int spacing) {
uiItemPtr(item)->spacing = spacing;
}

int uiGetSpacing(int item) {
return uiItemPtr(item)->spacing;
}

int uiColumn(int parent, int spacing) {
int idx = uiItem(parent, 0, UI_COLUMN, 0, 0, NULL, 0);
uiSetSpacing(idx, spacing);
return idx;
}

int uiRow(int parent, int spacing) {
int idx = uiItem(parent, 0, UI_ROW, 0, 0, NULL, 0);
uiSetSpacing(idx, spacing);
return idx;
}

UIrect uiGetRect(int item) {
return uiItemPtr(item)->rect;
}

UIrect uiGetScreenRect(int item) {
UIitem *pitem = uiItemPtr(item);
UIrect rect = pitem->rect;
rect.x = pitem->absx;
rect.y = pitem->absy;
return rect;
}

void uiSetRect(int item, int x, int y, int w, int h) {
UIitem *pitem = uiItemPtr(item);
pitem->rect.w = w;
pitem->rect.h = h;
pitem->rect.x = x;
pitem->rect.y = y;
}

int uiFirstChild(int item) {
return uiItemPtr(item)->firstkid;
}

int uiLastChild(int item) {
return uiItemPtr(item)->lastkid;
}

int uiNextSibling(int item) {
return uiItemPtr(item)->nextitem;
}

int uiParent(int item) {
return uiItemPtr(item)->parent;
}

int uiGetKind(int item) {
return uiItemPtr(item)->kind;
}

void *uiGetData(int item) {
UIitem *pitem = uiItemPtr(item);
if (pitem->data < 0) return NULL;
return ui_context->data + pitem->data;
}

int uiGetHandle(int item) {
return uiItemPtr(item)->handle;
}

int uiGetChildId(int item) {
return uiItemPtr(item)->kidid;
}

int uiGetChildCount(int item) {
return uiItemPtr(item)->numkids;
}

void uiLayoutItem(int item, int x, int y);
void uiLayoutChildren(int item, int x, int y) {
int kid = uiFirstChild(item);
while (kid > 0) {
uiLayoutItem(kid, x, y);
kid = uiNextSibling(kid);
}
}

void uiLayoutItem(int item, int x, int y) {
UIrect rect = uiGetRect(item);
rect.x += x;
rect.y += y;
switch(uiGetKind(item)) {
case UI_COLUMN:
case UI_ROOT: {
int kid = uiFirstChild(item);
while (kid > 0) {
UIitem *pitem = uiItemPtr(kid);
if (!pitem->rect.w || (pitem->rect.w > rect.w)) {
pitem->rect.w = rect.w;
}
kid = uiNextSibling(kid);
}
uiLayoutChildren(item, rect.x, rect.y);
int spacing = uiItemPtr(item)->spacing;
int h = -spacing;
// stack kids vertically
kid = uiFirstChild(item);
while (kid > 0) {
UIitem *pitem = uiItemPtr(kid);
h += spacing;
pitem->rect.y = h;
h += pitem->rect.h;
kid = uiNextSibling(kid);
}
if (h > rect.h) {
uiItemPtr(item)->rect.h = h;
}
} break;
case UI_ROW: {
uiLayoutChildren(item, rect.x, rect.y);

int spacing = uiItemPtr(item)->spacing;
// figure out height of row
// also see how much horizontal space is used
int lastkidid = uiGetChildCount(item)-1;
lastkidid = (lastkidid<0)?0:lastkidid;
int w = spacing*lastkidid;
// how many children have no explicit width?
int numdynkids = 0;
int kid = uiFirstChild(item);
while (kid > 0) {
UIitem *pitem = uiItemPtr(kid);
if (pitem->rect.h > rect.h)
rect.h = pitem->rect.h;
if (!pitem->rect.w)
numdynkids++;
else
w += pitem->rect.w;
kid = uiNextSibling(kid);
}
uiItemPtr(item)->rect.h = rect.h;
int space = rect.w - w;
// distribute remaining width across children
int dw = numdynkids?(space / numdynkids):0;
dw = (dw<0)?0:dw;
// rounding error
space -= numdynkids*dw;
w = -spacing;
// stack kids horizontally
kid = uiFirstChild(item);
while (kid > 0) {
UIitem *pitem = uiItemPtr(kid);
w += spacing;
pitem->rect.x = w;
if (!pitem->rect.w) {
--numdynkids;
// round last kid
if (!numdynkids)
dw += space;
pitem->rect.w = dw;
}
w += pitem->rect.w;
kid = uiNextSibling(kid);
}
} break;
default: break;
}
}

void uiUpdateItemState(int item, int x, int y) {
UIitem *pitem = uiItemPtr(item);
pitem->absx = pitem->rect.x+x;
pitem->absy = pitem->rect.y+y;
if (pitem->handle) {
int cx = ui_context->cx - pitem->absx;
int cy = ui_context->cy - pitem->absy;
if ((cx>=0)
&& (cy>=0)
&& (cx<pitem->rect.w)
&& (cy<pitem->rect.h)) {
ui_context->hot = pitem->handle;
if (!ui_context->active && uiGetButton(0)) {
ui_context->active = pitem->handle;
}
}
}
int kid = uiFirstChild(item);
while (kid > 0) {
uiUpdateItemState(kid, pitem->absx, pitem->absy);
kid = uiNextSibling(kid);
}

}

void uiLayout() {
uiLayoutItem(0, 0, 0);
uiUpdateItemState(0, 0, 0);
if (!uiGetButton(0)) {
ui_context->active = 0;
}
}

int uiIsActive(int item) {
assert(ui_context);
return (ui_context->active == uiItemPtr(item)->handle)?1:0;
}

int uiIsHot(int item) {
assert(ui_context);
return (ui_context->hot == uiItemPtr(item)->handle)?1:0;
}

int uiGetState(int item) {
return (!uiIsHot(item))?UI_COLD:(uiIsActive(item))?UI_ACTIVE:UI_HOT;

}

#endif // UI_IMPLEMENTATION

////////////////////////////////////////////////////////////////////////////////

typedef struct UIData {
int iconid;
const char *label;
} UIData;

////////////////////////////////////////////////////////////////////////////////

void init(NVGcontext *vg) {
bndSetFont(nvgCreateFont(vg, "system", "../droidsans.ttf"));
bndSetIconImage(nvgCreateImage(vg, "../blender_icons16.png"));
}

void draw(NVGcontext *vg, float w, float h) {
int cornerFlags(int item) {
int parent = uiParent(item);
int spacing = uiGetSpacing(parent);
if (spacing >= 0) return BND_CORNER_NONE;
int numkids = uiGetChildCount(parent);
int numid = uiGetChildId(item);
if (numkids == 0) return BND_CORNER_NONE;
switch(uiGetKind(parent)) {
case UI_COLUMN: {
if (!numid) return BND_CORNER_DOWN;
else if (numid == numkids-1) return BND_CORNER_TOP;
else return BND_CORNER_ALL;
} break;
case UI_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;
}

void drawUI(NVGcontext *vg, int item, int x, int y) {
UIData *data = (UIData *)uiGetData(item);
UIrect rect = uiGetRect(item);
rect.x += x;
rect.y += y;
switch(uiGetKind(item)) {
case UI_BUTTON: {
assert(data);
bndToolButton(vg,rect.x,rect.y,rect.w,rect.h,
cornerFlags(item),(BNDwidgetState)uiGetState(item),
data->iconid,data->label);
} break;
default: break;
}
int kid = uiFirstChild(item);
while (kid > 0) {
drawUI(vg, kid, rect.x, rect.y);
kid = uiNextSibling(kid);
}
}

void draw(NVGcontext *vg, float w, float h) {
bndBackground(vg, 0, 0, w, h);
int x = 10;
@@ -280,9 +701,46 @@ void draw(NVGcontext *vg, float w, float h) {
x += BND_TOOL_WIDTH-1;
bndRadioButton(vg,x,y,BND_TOOL_WIDTH,BND_WIDGET_HEIGHT,BND_CORNER_LEFT,
BND_DEFAULT,BND_ICONID(5,11),NULL);
uiClear();
uiSetRect(0,600,10,250,400);
int col = uiColumn(0,1);
UIData data = { BND_ICONID(6,3), "Item 1" };
uiItem(col, 1, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
data.label = "Item 2";
uiItem(col, 2, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
{ // nested row
int row = uiRow(col,-1);
data.label = "Item 3.0";
uiItem(row, 3, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
data.label = NULL;
data.iconid = BND_ICONID(0,10);
uiItem(row, 4, UI_BUTTON, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data, sizeof(data));
data.label = NULL;
data.iconid = BND_ICONID(1,10);
uiItem(row, 5, UI_BUTTON, BND_TOOL_WIDTH, BND_WIDGET_HEIGHT, &data, sizeof(data));
data.iconid = BND_ICONID(6,3);
data.label = "Item 3.3";
uiItem(row, 6, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
}
{ // nested column
int col2 = uiColumn(col,-2);
data.label = "Item 4.0";
uiItem(col2, 7, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
data.label = "Item 4.1";
uiItem(col2, 8, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
}
data.label = "Item 5";
uiItem(col, 9, UI_BUTTON, 0, BND_WIDGET_HEIGHT, &data, sizeof(data));
uiLayout();
drawUI(vg, 0, 0, 0);
}

////////////////////////////////////////////////////////////////////////////////


Loading…
Cancel
Save