Browse Source

oui.h: support for text input & example

pull/1/head
Leonard Ritter 10 years ago
parent
commit
d97023bf47
2 changed files with 195 additions and 13 deletions
  1. +74
    -1
      example.cpp
  2. +121
    -12
      oui.h

+ 74
- 1
example.cpp View File

@@ -38,6 +38,8 @@ typedef enum {
ST_CHECK = 6,
// panel
ST_PANEL = 7,
// text
ST_TEXT = 8,
} SubType;

typedef struct {
@@ -69,6 +71,12 @@ typedef struct {
float *progress;
} UISliderData;

typedef struct {
UIData head;
char *text;
int maxsize;
} UITextData;

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

void init(NVGcontext *vg) {
@@ -167,6 +175,13 @@ void drawUI(NVGcontext *vg, int item, int x, int y) {
cornerFlags(item),state,
*data->progress,data->label,value);
} break;
case ST_TEXT: {
const UITextData *data = (UITextData*)head;
BNDwidgetState state = (BNDwidgetState)uiGetState(item);
int idx = strlen(data->text);
bndTextField(vg,rect.x,rect.y,rect.w,rect.h,
cornerFlags(item),state, -1, data->text, idx, idx);
} break;
}
} else {
testrect(vg,rect);
@@ -295,6 +310,53 @@ int slider(int parent, UIhandle handle, const char *label, float *progress) {
return item;
}

void textboxhandler(int item, UIevent event) {
UITextData *data = (UITextData *)uiGetData(item);
switch(event) {
default: break;
case UI_BUTTON0_DOWN: {
uiFocus(item);
} break;
case UI_KEY_DOWN: {
int key = uiGetActiveKey();
switch(key) {
default: break;
case GLFW_KEY_BACKSPACE: {
int size = strlen(data->text);
if (!size) return;
data->text[size-1] = 0;
} break;
case GLFW_KEY_ENTER: {
uiFocus(-1);
} break;
}
} break;
case UI_CHAR: {
unsigned int key = uiGetActiveKey();
if ((key > 255)||(key < 32)) return;
int size = strlen(data->text);
if (size >= (data->maxsize-1)) return;
data->text[size] = (char)key;
} break;
}
}

int textbox(int parent, UIhandle handle, char *text, int maxsize) {
int item = uiItem();
uiSetHandle(item, handle);
uiSetSize(item, 0, BND_WIDGET_HEIGHT);
uiSetHandler(item, textboxhandler,
UI_BUTTON0_DOWN | UI_KEY_DOWN | UI_CHAR);
// 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.
UITextData *data = (UITextData *)uiAllocData(item, sizeof(UITextData));
data->head.subtype = ST_TEXT;
data->text = text;
data->maxsize = maxsize;
uiAppend(parent, item);
return item;
}

// simple logic for a radio button
void radiohandler(int item, UIevent event) {
UIRadioData *data = (UIRadioData *)uiGetData(item);
@@ -636,6 +698,10 @@ void draw(NVGcontext *vg, float w, float h) {
check(col, 13, "Item 7", &option2);
check(col, 14, "Item 8", &option3);
static char textbuffer[32] = "click and edit";
textbox(col, (UIhandle)textbuffer, textbuffer, 32);
uiLayout();
drawUI(vg, 0, 0, 0);
uiProcess();
@@ -659,12 +725,18 @@ static void cursorpos(GLFWwindow *window, double x, double y) {
uiSetCursor((int)x,(int)y);
}

static void charevent(GLFWwindow *window, unsigned int value) {
NVG_NOTUSED(window);
uiSetChar(value);
}

static void key(GLFWwindow* window, int key, int scancode, int action, int mods)
{
NVG_NOTUSED(scancode);
NVG_NOTUSED(mods);
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
uiSetKey(key, action);
}

int main()
@@ -697,8 +769,9 @@ int main()
}

glfwSetKeyCallback(window, key);
glfwSetCharCallback(window, charevent);
glfwSetCursorPosCallback(window, cursorpos);
glfwSetMouseButtonCallback(window, mousebutton);
glfwSetMouseButtonCallback(window, mousebutton);

glfwMakeContextCurrent(window);
#ifdef NANOVG_GLEW


+ 121
- 12
oui.h View File

@@ -193,6 +193,8 @@ See example.cpp in the repository for a full usage example.
#define UI_MAX_DATASIZE 4096
// maximum depth of nested containers
#define UI_MAX_DEPTH 64
// maximum number of buffered input events
#define UI_MAX_INPUT_EVENTS 64

typedef unsigned int UIuint;

@@ -209,10 +211,10 @@ typedef enum UIitemState {
UI_COLD = 0,
// the item is inactive, but the cursor is hovering over this item
UI_HOT = 1,
// the item is toggled or activated (depends on item kind)
// the item is toggled, activated, focused (depends on item kind)
UI_ACTIVE = 2,
// the item is unresponsive
UI_FROZEN = 3
UI_FROZEN = 3,
} UIitemState;

// layout flags
@@ -260,6 +262,15 @@ typedef enum UIevent {
// this can be used to allow container items to configure child items
// as they appear.
UI_APPEND = 0x10,
// item is focused and has received a key-down event
// the respective key can be queried using uiGetActiveKey()
UI_KEY_DOWN = 0x20,
// item is focused and has received a key-up event
// the respective key can be queried using uiGetActiveKey()
UI_KEY_UP = 0x40,
// item is focused and has received a character event
// the respective character can be queried using uiGetActiveKey()
UI_CHAR = 0x80,
} UIevent;

// handler callback; event is one of UI_EVENT_*
@@ -331,6 +342,17 @@ void uiSetButton(int button, int enabled);
// the function returns 1 if the button has been set to pressed, 0 for released.
int uiGetButton(int button);

// sets a key as down/up; the key can be any application defined keycode
// enabled is 1 for key down, 0 for key up
// all key events are being buffered until the next call to uiProcess()
void uiSetKey(unsigned int key, int enabled);

// sends a single character for text input; the character is usually in the
// unicode range, but can be application defined.
// all char events are being buffered until the next call to uiProcess()
void uiSetChar(unsigned int value);


// Stages
// ------

@@ -418,6 +440,10 @@ void uiSetRelToRight(int item, int other);
// sibling is below this item.
void uiSetRelToDown(int item, int other);

// set item as recipient of all keyboard events; the item must have a handle
// assigned; if item is -1, no item will be focused.
void uiFocus(int item);

// Iteration
// ---------

@@ -458,9 +484,12 @@ UIhandle uiGetHandle(int item);
// uiSetHandle() or -1 if unsuccessful.
int uiGetItem(UIhandle handle);

// return the item that is currently under the cursor
// return the item that is currently under the cursor or -1 for none
int uiGetHotItem();

// return the item that is currently focused or -1 for none
int uiGetFocusedItem();

// 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 should not be altered.
@@ -470,6 +499,8 @@ const void *uiGetData(int item);
UIhandler uiGetHandler(int item);
// return the handler flags for an item as passed to uiSetHandler()
int uiGetHandlerFlags(int item);
// when handling a KEY_DOWN/KEY_UP event: the key that triggered this event
unsigned int uiGetActiveKey();

// 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.
@@ -600,10 +631,15 @@ typedef enum UIstate {
UI_STATE_CAPTURE,
} UIstate;

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

typedef struct UIinputEvent {
unsigned int key;
UIevent event;
} UIinputEvent;

struct UIcontext {
// button state in this frame
@@ -620,16 +656,21 @@ struct UIcontext {
UIhandle hot_handle;
UIhandle active_handle;
UIhandle focus_handle;
UIrect hot_rect;
UIrect active_rect;
UIstate state;
int hot_item;
int active_key;
int count;
UIitem items[UI_MAX_ITEMS];
int datasize;
int eventcount;
UIitem items[UI_MAX_ITEMS];
unsigned char data[UI_MAX_BUFFERSIZE];
UIhandle_entry handles[UI_MAX_ITEMS];
UIhandleEntry handles[UI_MAX_ITEMS];
UIinputEvent events[UI_MAX_INPUT_EVENTS];
};

UI_INLINE int ui_max(int a, int b) {
@@ -678,12 +719,12 @@ UI_INLINE unsigned int uiHashProbeDistance(unsigned int key, unsigned int slot_i
return (slot_index + UI_MAX_ITEMS - pos) & (UI_MAX_ITEMS-1);
}

UI_INLINE UIhandle_entry *uiHashLookupHandle(unsigned int key) {
UI_INLINE UIhandleEntry *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;
UIhandleEntry *entry = ui_context->handles + pos;
unsigned int pos_key = entry->key;
if (!pos_key) return NULL;
else if (entry->key == key)
@@ -697,13 +738,13 @@ UI_INLINE UIhandle_entry *uiHashLookupHandle(unsigned int key) {

int uiGetItem(UIhandle handle) {
unsigned int key = uiHashHandle(handle);
UIhandle_entry *e = uiHashLookupHandle(key);
UIhandleEntry *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);
UIhandleEntry *e = uiHashLookupHandle(key);
if (e) { // update
e->item = item;
return;
@@ -743,6 +784,29 @@ void uiSetButton(int button, int enabled) {
(ui_context->buttons & ~mask);
}

static void uiAddInputEvent(UIinputEvent event) {
assert(ui_context);
if (ui_context->eventcount == UI_MAX_INPUT_EVENTS) return;
ui_context->events[ui_context->eventcount++] = event;
}

static void uiClearInputEvents() {
assert(ui_context);
ui_context->eventcount = 0;
}

void uiSetKey(unsigned int key, int enabled) {
assert(ui_context);
UIinputEvent event = { key, enabled?UI_KEY_DOWN:UI_KEY_UP };
uiAddInputEvent(event);
}

void uiSetChar(unsigned int value) {
assert(ui_context);
UIinputEvent event = { value, UI_CHAR };
uiAddInputEvent(event);
}

int uiGetLastButton(int button) {
assert(ui_context);
return (ui_context->last_buttons & (1ull<<button))?1:0;
@@ -797,6 +861,11 @@ UIvec2 uiGetCursorStartDelta() {
return result;
}

unsigned int uiGetActiveKey() {
assert(ui_context);
return ui_context->active_key;
}

UIitem *uiItemPtr(int item) {
assert(ui_context && (item >= 0) && (item < ui_context->count));
return ui_context->items + item;
@@ -807,6 +876,16 @@ int uiGetHotItem() {
return ui_context->hot_item;
}

void uiFocus(int item) {
assert(ui_context && (item >= -1) && (item < ui_context->count));
ui_context->focus_handle = (item < 0)?0:uiGetHandle(item);
}

int uiGetFocusedItem() {
assert(ui_context);
return ui_context->focus_handle?uiGetItem(ui_context->focus_handle):-1;
}

void uiClear() {
assert(ui_context);
ui_context->count = 0;
@@ -1240,10 +1319,26 @@ void uiLayout() {

void uiProcess() {
assert(ui_context);
if (!ui_context->count) return;
if (!ui_context->count) {
uiClearInputEvents();
return;
}
int hot_item = uiGetItem(ui_context->hot_handle);
int active_item = uiGetItem(ui_context->active_handle);
int focus_item = uiGetItem(ui_context->focus_handle);

// send all keyboard events
if (focus_item >= 0) {
for (int i = 0; i < ui_context->eventcount; ++i) {
ui_context->active_key = ui_context->events[i].key;
uiNotifyItem(focus_item,
ui_context->events[i].event);
}
} else {
ui_context->focus_handle = 0;
}
uiClearInputEvents();

int hot = ui_context->hot_item;

@@ -1255,6 +1350,12 @@ void uiProcess() {
hot_item = -1;
ui_context->active_rect = ui_context->hot_rect;
active_item = hot;
if (active_item != focus_item) {
focus_item = -1;
ui_context->focus_handle = 0;
}
if (active_item >= 0) {
uiNotifyItem(active_item, UI_BUTTON0_DOWN);
}
@@ -1302,9 +1403,17 @@ static int uiIsHot(int item) {
return (ui_context->hot_handle)&&(uiGetHandle(item) == ui_context->hot_handle);
}

static int uiIsFocused(int item) {
assert(ui_context);
return (ui_context->focus_handle)&&(uiGetHandle(item) == ui_context->focus_handle);
}

UIitemState uiGetState(int item) {
UIitem *pitem = uiItemPtr(item);
if (pitem->frozen) return UI_FROZEN;
if (uiIsFocused(item)) {
if (pitem->event_flags & (UI_KEY_DOWN|UI_CHAR|UI_KEY_UP)) return UI_ACTIVE;
}
if (uiIsActive(item)) {
if (pitem->event_flags & (UI_BUTTON0_CAPTURE|UI_BUTTON0_UP)) return UI_ACTIVE;
if ((pitem->event_flags & UI_BUTTON0_HOT_UP)


Loading…
Cancel
Save