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 - // - UI setup code goes here -
app_setup_ui(); app_setup_ui();
// layout UI, update states and fire handlers
uiProcess();
// layout UI
uiLayout();
// draw UI // draw UI
app_draw_ui(render_context,0,0,0); app_draw_ui(render_context,0,0,0);
// update states and fire handlers
uiProcess();
} }


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


// limits // 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 #define UI_MAX_ITEMS 4096
// maximum size in bytes reserved for storage of application dependent data // maximum size in bytes reserved for storage of application dependent data
// as passed to uiAllocData(). // as passed to uiAllocData().
@@ -451,6 +454,10 @@ UIitemState uiGetState(int item);
// return the application-dependent handle of the item as passed to uiSetHandle(). // return the application-dependent handle of the item as passed to uiSetHandle().
UIhandle uiGetHandle(int item); 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 // return the application-dependent context data for an item as passed to
// uiAllocData(). The memory of the pointer is managed by the UI context // uiAllocData(). The memory of the pointer is managed by the UI context
// and must not be altered. // and must not be altered.
@@ -590,6 +597,11 @@ typedef enum UIstate {
UI_STATE_CAPTURE, UI_STATE_CAPTURE,
} UIstate; } UIstate;


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

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


UI_INLINE int ui_max(int a, int b) { UI_INLINE int ui_max(int a, int b) {
@@ -645,6 +656,80 @@ void uiDestroyContext(UIcontext *ctx) {
free(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) { void uiSetButton(int button, int enabled) {
assert(ui_context); assert(ui_context);
unsigned long long mask = 1ull<<button; unsigned long long mask = 1ull<<button;
@@ -717,8 +802,7 @@ void uiClear() {
assert(ui_context); assert(ui_context);
ui_context->count = 0; ui_context->count = 0;
ui_context->datasize = 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() { int uiItem() {
@@ -1066,10 +1150,7 @@ void *uiAllocData(int item, int size) {
void uiSetHandle(int item, UIhandle handle) { void uiSetHandle(int item, UIhandle handle) {
uiItemPtr(item)->handle = handle; uiItemPtr(item)->handle = handle;
if (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() { void uiProcess() {
if (!ui_context->count) return; 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, int hot = uiFindItem(0,
ui_context->cursor.x, ui_context->cursor.y, 0, 0); ui_context->cursor.x, ui_context->cursor.y, 0, 0);


@@ -1152,54 +1236,54 @@ void uiProcess() {
case UI_STATE_IDLE: { case UI_STATE_IDLE: {
ui_context->start_cursor = ui_context->cursor; ui_context->start_cursor = ui_context->cursor;
if (uiGetButton(0)) { if (uiGetButton(0)) {
ui_context->hot_item = -1;
hot_item = -1;
ui_context->active_rect = ui_context->hot_rect; 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; ui_context->state = UI_STATE_CAPTURE;
} else { } else {
ui_context->hot_item = hot;
hot_item = hot;
} }
} break; } break;
case UI_STATE_CAPTURE: { case UI_STATE_CAPTURE: {
if (!uiGetButton(0)) { 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; ui_context->state = UI_STATE_IDLE;
} else { } 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 else
ui_context->hot_item = -1;
hot_item = -1;
} }
} break; } break;
} }
ui_context->last_cursor = ui_context->cursor; 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) { static int uiIsActive(int item) {
assert(ui_context); 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) { static int uiIsHot(int item) {
assert(ui_context); assert(ui_context);
return ui_context->hot_item == item;
return (ui_context->hot_handle)&&(uiGetHandle(item) == ui_context->hot_handle);
} }


UIitemState uiGetState(int item) { UIitemState uiGetState(int item) {


Loading…
Cancel
Save