Browse Source

oui: support for resolving item from handle using hashtable

pull/1/head
Leonard Ritter 10 years ago
parent
commit
dfab0bef7f
1 changed files with 118 additions and 34 deletions
  1. +118
    -34
      oui.h

+ 118
- 34
oui.h View File

@@ -65,12 +65,15 @@ void app_main(...) {
// - UI setup code goes here -
app_setup_ui();
// layout UI, update states and fire handlers
uiProcess();
// layout UI
uiLayout();
// draw UI
app_draw_ui(render_context,0,0,0);
// update states and fire handlers
uiProcess();
}

uiDestroyContext(context);
@@ -181,7 +184,7 @@ See example.cpp in the repository for a full usage example.

// limits

// maximum number of items that may be added
// maximum number of items that may be added (must be power of 2)
#define UI_MAX_ITEMS 4096
// maximum size in bytes reserved for storage of application dependent data
// as passed to uiAllocData().
@@ -451,6 +454,10 @@ UIitemState uiGetState(int item);
// return the application-dependent handle of the item as passed to uiSetHandle().
UIhandle uiGetHandle(int item);

// return the item with the given application-dependent handle as assigned by
// uiSetHandle() or -1 if unsuccessful.
int uiGetItem(UIhandle handle);

// 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 must not be altered.
@@ -590,6 +597,11 @@ typedef enum UIstate {
UI_STATE_CAPTURE,
} UIstate;

typedef struct UIhandle_entry {
unsigned int key;
int item;
} UIhandle_entry;

struct UIcontext {
// button state in this frame
unsigned long long buttons;
@@ -605,8 +617,6 @@ struct UIcontext {
UIhandle hot_handle;
UIhandle active_handle;
int hot_item;
int active_item;
UIrect hot_rect;
UIrect active_rect;
UIstate state;
@@ -615,6 +625,7 @@ struct UIcontext {
UIitem items[UI_MAX_ITEMS];
int datasize;
unsigned char data[UI_MAX_BUFFERSIZE];
UIhandle_entry handles[UI_MAX_ITEMS];
};

UI_INLINE int ui_max(int a, int b) {
@@ -645,6 +656,80 @@ void uiDestroyContext(UIcontext *ctx) {
free(ctx);
}

UI_INLINE unsigned int uiHashHandle(UIhandle handle) {
handle = (handle+(handle>>32)) & 0xffffffff;
unsigned int x = (unsigned int)handle;
x += (x>>6)+(x>>19);
x += x<<16;
x ^= x<<3;
x += x>>5;
x ^= x<<2;
x += x>>15;
x ^= x<<10;
return x?x:1; // must not be zero
}

UI_INLINE unsigned int uiHashProbeDistance(unsigned int key, unsigned int slot_index) {
unsigned int pos = key & (UI_MAX_ITEMS-1);
return (slot_index + UI_MAX_ITEMS - pos) & (UI_MAX_ITEMS-1);
}

UI_INLINE UIhandle_entry *uiHashLookupHandle(unsigned int key) {
assert(ui_context);
int pos = key & (UI_MAX_ITEMS-1);
unsigned int dist = 0;
for (;;) {
UIhandle_entry *entry = ui_context->handles + pos;
unsigned int pos_key = entry->key;
if (!pos_key) return NULL;
else if (entry->key == key)
return entry;
else if (dist > uiHashProbeDistance(pos_key, pos))
return NULL;
pos = (pos+1) & (UI_MAX_ITEMS-1);
++dist;
}
}

int uiGetItem(UIhandle handle) {
unsigned int key = uiHashHandle(handle);
UIhandle_entry *e = uiHashLookupHandle(key);
return e?(e->item):-1;
}

static void uiHashInsertHandle(UIhandle handle, int item) {
unsigned int key = uiHashHandle(handle);
UIhandle_entry *e = uiHashLookupHandle(key);
if (e) { // update
e->item = item;
return;
}

int pos = key & (UI_MAX_ITEMS-1);
unsigned int dist = 0;
for (unsigned int i = 0; i < UI_MAX_ITEMS; ++i) {
int index = (pos + i) & (UI_MAX_ITEMS-1);
unsigned int pos_key = ui_context->handles[index].key;
if (!pos_key) {
ui_context->handles[index].key = key;
ui_context->handles[index].item = item;
break;
} else {
unsigned int probe_distance = uiHashProbeDistance(pos_key, index);
if (dist > probe_distance) {
unsigned int oldkey = ui_context->handles[index].key;
unsigned int olditem = ui_context->handles[index].item;
ui_context->handles[index].key = key;
ui_context->handles[index].item = item;
key = oldkey;
item = olditem;
dist = probe_distance;
}
}
++dist;
}
}

void uiSetButton(int button, int enabled) {
assert(ui_context);
unsigned long long mask = 1ull<<button;
@@ -717,8 +802,7 @@ void uiClear() {
assert(ui_context);
ui_context->count = 0;
ui_context->datasize = 0;
ui_context->hot_item = -1;
ui_context->active_item = -1;
memset(ui_context->handles, 0, sizeof(ui_context->handles));
}

int uiItem() {
@@ -1066,10 +1150,7 @@ void *uiAllocData(int item, int size) {
void uiSetHandle(int item, UIhandle handle) {
uiItemPtr(item)->handle = handle;
if (handle) {
if (handle == ui_context->hot_handle)
ui_context->hot_item = item;
if (handle == ui_context->active_handle)
ui_context->active_item = item;
uiHashInsertHandle(handle, item);
}
}

@@ -1144,6 +1225,9 @@ void uiLayout() {
void uiProcess() {
if (!ui_context->count) return;
int hot_item = uiGetItem(ui_context->hot_handle);
int active_item = uiGetItem(ui_context->active_handle);

int hot = uiFindItem(0,
ui_context->cursor.x, ui_context->cursor.y, 0, 0);

@@ -1152,54 +1236,54 @@ void uiProcess() {
case UI_STATE_IDLE: {
ui_context->start_cursor = ui_context->cursor;
if (uiGetButton(0)) {
ui_context->hot_item = -1;
hot_item = -1;
ui_context->active_rect = ui_context->hot_rect;
ui_context->active_item = hot;
if (ui_context->active_item >= 0) {
uiNotifyItem(ui_context->active_item, UI_BUTTON0_DOWN);
active_item = hot;
if (active_item >= 0) {
uiNotifyItem(active_item, UI_BUTTON0_DOWN);
}
ui_context->state = UI_STATE_CAPTURE;
} else {
ui_context->hot_item = hot;
hot_item = hot;
}
} break;
case UI_STATE_CAPTURE: {
if (!uiGetButton(0)) {
if (ui_context->active_item >= 0) {
uiNotifyItem(ui_context->active_item, UI_BUTTON0_UP);
if (ui_context->active_item == hot) {
uiNotifyItem(ui_context->active_item, UI_BUTTON0_HOT_UP);
if (active_item >= 0) {
uiNotifyItem(active_item, UI_BUTTON0_UP);
if (active_item == hot) {
uiNotifyItem(active_item, UI_BUTTON0_HOT_UP);
}
}
ui_context->active_item = -1;
active_item = -1;
ui_context->state = UI_STATE_IDLE;
} else {
if (ui_context->active_item >= 0) {
uiNotifyItem(ui_context->active_item, UI_BUTTON0_CAPTURE);
if (active_item >= 0) {
uiNotifyItem(active_item, UI_BUTTON0_CAPTURE);
}
if (hot == ui_context->active_item)
ui_context->hot_item = hot;
if (hot == active_item)
hot_item = hot;
else
ui_context->hot_item = -1;
hot_item = -1;
}
} break;
}
ui_context->last_cursor = ui_context->cursor;
ui_context->hot_handle = (ui_context->hot_item>=0)?
uiGetHandle(ui_context->hot_item):0;
ui_context->active_handle = (ui_context->active_item>=0)?
uiGetHandle(ui_context->active_item):0;
ui_context->hot_handle = (hot_item>=0)?
uiGetHandle(hot_item):0;
ui_context->active_handle = (active_item>=0)?
uiGetHandle(active_item):0;
}

static int uiIsActive(int item) {
assert(ui_context);
return ui_context->active_item == item;
return (ui_context->active_handle)&&(uiGetHandle(item) == ui_context->active_handle);
}

static int uiIsHot(int item) {
assert(ui_context);
return ui_context->hot_item == item;
return (ui_context->hot_handle)&&(uiGetHandle(item) == ui_context->hot_handle);
}

UIitemState uiGetState(int item) {


Loading…
Cancel
Save