Add text field draft implementation

This commit is contained in:
Doyle Thai 2016-08-10 21:52:05 +10:00
parent 4127542d1d
commit 22973ef51d
5 changed files with 319 additions and 45 deletions

View File

@ -90,6 +90,7 @@ INTERNAL inline RenderQuad
createDefaultTexQuad(Renderer *renderer, RenderTex renderTex) createDefaultTexQuad(Renderer *renderer, RenderTex renderTex)
{ {
RenderQuad result = {0}; RenderQuad result = {0};
// TODO(doyle): We need to switch this so its xy bottom left, zw top right!!
v4 defaultQuad = V4(0.0f, renderer->size.h, renderer->size.w, 0.0f); v4 defaultQuad = V4(0.0f, renderer->size.h, renderer->size.w, 0.0f);
result = createTexQuad(renderer, defaultQuad, renderTex); result = createTexQuad(renderer, defaultQuad, renderTex);
return result; return result;

View File

@ -341,6 +341,8 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
DEBUG_LOG("World populated"); DEBUG_LOG("World populated");
#endif #endif
state->uiState.keyEntered = keycode_null;
srand(CAST(u32)(time(NULL))); srand(CAST(u32)(time(NULL)));
} }
@ -375,24 +377,24 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
// if a button ended down // if a button ended down
LOCAL_PERSIST b32 spaceBarWasDown = FALSE; LOCAL_PERSIST b32 spaceBarWasDown = FALSE;
if (state->input.right) if (state->input.keys[keycode_right])
{ {
ddPos.x = 1.0f; ddPos.x = 1.0f;
hero->direction = direction_east; hero->direction = direction_east;
} }
if (state->input.left) if (state->input.keys[keycode_left])
{ {
ddPos.x = -1.0f; ddPos.x = -1.0f;
hero->direction = direction_west; hero->direction = direction_west;
} }
if (state->input.up) if (state->input.keys[keycode_up])
{ {
ddPos.y = 1.0f; ddPos.y = 1.0f;
} }
if (state->input.down) if (state->input.keys[keycode_down])
{ {
ddPos.y = -1.0f; ddPos.y = -1.0f;
} }
@ -406,10 +408,18 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
ddPos = v2_scale(ddPos, 0.70710678118f); ddPos = v2_scale(ddPos, 0.70710678118f);
} }
if (state->input.keys[keycode_enter])
{
state->uiState.keyEntered = keycode_enter;
}
LOCAL_PERSIST b32 toggleFlag = TRUE; LOCAL_PERSIST b32 toggleFlag = TRUE;
// TODO(doyle): Revisit key input with state checking for last ended down // TODO(doyle): Revisit key input with state checking for last ended down
if (state->input.space && spaceBarWasDown == FALSE) if (state->input.keys[keycode_space] && spaceBarWasDown == FALSE)
{ {
state->uiState.keyEntered = keycode_space;
#if 0
Renderer *renderer = &state->renderer; Renderer *renderer = &state->renderer;
f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h); f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h);
f32 xModifier = 5.0f - CAST(f32)(rand() % 3); f32 xModifier = 5.0f - CAST(f32)(rand() % 3);
@ -417,9 +427,10 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
v2 pos = V2(renderer->size.w - (renderer->size.w / xModifier), yPos); v2 pos = V2(renderer->size.w - (renderer->size.w / xModifier), yPos);
entity_addGenericMob(&state->arena, &state->assetManager, world, entity_addGenericMob(&state->arena, &state->assetManager, world,
pos); pos);
#endif
spaceBarWasDown = TRUE; spaceBarWasDown = TRUE;
} }
else if (!state->input.space) else if (!state->input.keys[keycode_space])
{ {
spaceBarWasDown = FALSE; spaceBarWasDown = FALSE;
} }
@ -444,8 +455,16 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
} }
f32 heroSpeed = 6.2f * METERS_TO_PIXEL; f32 heroSpeed = 6.2f * METERS_TO_PIXEL;
if (state->input.leftShift) if (state->input.keys[keycode_leftShift])
{
// TODO: Context sensitive command separation
state->uiState.keyMod = keycode_leftShift;
heroSpeed = CAST(f32)(22.0f * 10.0f * METERS_TO_PIXEL); heroSpeed = CAST(f32)(22.0f * 10.0f * METERS_TO_PIXEL);
}
else
{
state->uiState.keyMod = keycode_null;
}
ddPos = v2_scale(ddPos, heroSpeed); ddPos = v2_scale(ddPos, heroSpeed);
// TODO(doyle): Counteracting force on player's acceleration is arbitrary // TODO(doyle): Counteracting force on player's acceleration is arbitrary
@ -878,9 +897,8 @@ INTERNAL i32 button(UiState *uiState, AssetManager *assetManager,
{ {
if (math_pointInRect(rect, input.mouseP)) if (math_pointInRect(rect, input.mouseP))
{ {
DEBUG_PUSH_STRING("POINT IN RECT");
uiState->hotItem = id; uiState->hotItem = id;
if (uiState->activeItem == 0 && input.mouseLeft) if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
uiState->activeItem = id; uiState->activeItem = id;
} }
@ -925,22 +943,27 @@ INTERNAL i32 button(UiState *uiState, AssetManager *assetManager,
// After renderering before click check, see if we need to process keys // After renderering before click check, see if we need to process keys
if (uiState->kbdItem == id) if (uiState->kbdItem == id)
{ {
if (input.space) switch (uiState->keyEntered)
{ {
case keycode_space:
// Set focus to nothing and let next widget get focus // Set focus to nothing and let next widget get focus
uiState->kbdItem = 0; uiState->kbdItem = 0;
if (input.leftShift) if (uiState->keyMod == keycode_leftShift)
uiState->kbdItem = uiState->lastWidget; uiState->kbdItem = uiState->lastWidget;
// Clear key state so next widget doesn't auto grab // Clear key state so next widget doesn't auto grab
input.space = FALSE; uiState->keyEntered = keycode_null;
input.leftShift = FALSE; break;
case keycode_enter:
return 1;
default:
break;
} }
} }
uiState->lastWidget = id; uiState->lastWidget = id;
if (!input.mouseLeft && if (!input.keys[keycode_mouseLeft] &&
uiState->hotItem == id && uiState->hotItem == id &&
uiState->activeItem == id) uiState->activeItem == id)
{ {
@ -961,12 +984,25 @@ INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
if (math_pointInRect(scrollBarRect, input.mouseP)) if (math_pointInRect(scrollBarRect, input.mouseP))
{ {
uiState->hotItem = id; uiState->hotItem = id;
if (uiState->activeItem == 0 && input.mouseLeft) if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
uiState->activeItem = id; uiState->activeItem = id;
} }
RenderTex renderTex = renderer_createNullRenderTex(assetManager); RenderTex renderTex = renderer_createNullRenderTex(assetManager);
/* If no widget has keyboard focus, take it */
if (uiState->kbdItem == 0)
uiState->kbdItem = id;
/* If we have keyboard focus, show it */
if (uiState->kbdItem == id)
{
// Draw outline
renderer_staticRect(renderer, v2_add(V2(-6, -6), scrollBarRect.pos),
v2_add(V2(20, 20), scrollBarRect.size), V2(0, 0), 0,
renderTex, V4(1.0f, 0, 0, 1));
}
// Render scroll bar background // Render scroll bar background
renderer_staticRect(renderer, scrollBarRect.pos, scrollBarRect.size, renderer_staticRect(renderer, scrollBarRect.pos, scrollBarRect.size,
V2(0, 0), 0, renderTex, V4(0.75f, 0.5f, 0.5f, 1)); V2(0, 0), 0, renderTex, V4(0.75f, 0.5f, 0.5f, 1));
@ -988,6 +1024,38 @@ INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
renderer_staticRect(renderer, sliderPos, sliderSize, V2(0, 0), 0, renderTex, renderer_staticRect(renderer, sliderPos, sliderSize, V2(0, 0), 0, renderTex,
sliderColor); sliderColor);
if (uiState->kbdItem == id)
{
switch (uiState->keyEntered)
{
case keycode_space:
uiState->kbdItem = 0;
if (uiState->keyMod == keycode_leftShift)
uiState->kbdItem = uiState->lastWidget;
// Clear key state so next widget doesn't auto grab
uiState->keyEntered = keycode_null;
break;
case keycode_up:
// TODO(doyle): Fix input for this to work, i.e. proper rate limited input poll
if (*value < maxValue)
{
(*value)++;
return 1;
}
case keycode_down:
if (*value > 0)
{
(*value)--;
return 1;
}
default:
break;
}
}
uiState->lastWidget = id;
if (uiState->activeItem == id) if (uiState->activeItem == id)
{ {
f32 mouseYRelToRect = input.mouseP.y - scrollBarRect.pos.y; f32 mouseYRelToRect = input.mouseP.y - scrollBarRect.pos.y;
@ -1012,6 +1080,103 @@ INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
return 0; return 0;
} }
INTERNAL i32 textField(UiState *const uiState, MemoryArena *arena,
AssetManager *const assetManager,
Renderer *const renderer, Font *const font,
KeyInput input, const i32 id, v2 pos,
char *const string)
{
i32 strLen = common_strlen(string);
b32 changed = FALSE;
Rect textRect = {0};
textRect.pos = pos;
textRect.size = V2(30 * font->maxSize.w, font->maxSize.h);
if (math_pointInRect(textRect, input.mouseP))
{
uiState->hotItem = id;
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
{
uiState->activeItem = id;
}
}
/* If no widget has keyboard focus, take it */
if (uiState->kbdItem == 0)
uiState->kbdItem = id;
RenderTex renderTex = renderer_createNullRenderTex(assetManager);
/* If we have keyboard focus, show it */
if (uiState->kbdItem == id)
{
// Draw outline
renderer_staticRect(renderer, v2_add(V2(-4, -4), textRect.pos),
v2_add(V2(16, 16), textRect.size), V2(0, 0), 0,
renderTex, V4(1.0f, 0, 0, 1));
}
// Render
renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
renderTex, V4(0.75f, 0.5f, 0.5f, 1));
if (uiState->activeItem == id || uiState->hotItem == id)
{
renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
renderTex, V4(0.75f, 0.75f, 0.0f, 1));
}
else
{
renderer_staticRect(renderer, textRect.pos, textRect.size, V2(0, 0), 0,
renderTex, V4(0.5f, 0.5f, 0.5f, 1));
}
renderer_staticString(renderer, arena, font, string, textRect.pos, V2(0, 0),
0, V4(0, 0, 0, 1));
if (uiState->kbdItem == id)
{
switch (uiState->keyEntered)
{
case keycode_space:
uiState->kbdItem = 0;
if (uiState->keyMod == keycode_leftShift)
uiState->kbdItem = uiState->lastWidget;
uiState->keyEntered = keycode_null;
break;
case keycode_backspace:
if (strLen > 0)
{
strLen--;
string[strLen] = 0;
changed = TRUE;
}
break;
default:
break;
}
if (uiState->keyChar >= keycode_space &&
uiState->keyChar <= keycode_Z && strLen < 30)
{
string[strLen++] = uiState->keyChar;
string[strLen] = 0;
changed = TRUE;
}
}
if (!input.keys[keycode_mouseLeft] &&
uiState->hotItem == id &&
uiState->activeItem == id)
{
uiState->kbdItem = id;
}
uiState->lastWidget = id;
return changed;
}
void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt) void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
{ {
if (dt >= 1.0f) dt = 1.0f; if (dt >= 1.0f) dt = 1.0f;
@ -1276,12 +1441,22 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
LOCAL_PERSIST i32 scrollValue = 30; LOCAL_PERSIST i32 scrollValue = 30;
Rect scrollRectA = {V2(900, 500), V2(16, 255)}; Rect scrollRectA = {V2(900, 500), V2(16, 255)};
scrollBar(&state->uiState, assetManager, renderer, state->input, 3, scrollBar(&state->uiState, assetManager, renderer, state->input, 4,
scrollRectA, &scrollValue, 160); scrollRectA, &scrollValue, 160);
LOCAL_PERSIST char fieldString[80] = "Hello world";
textField(&state->uiState, &state->arena, assetManager, renderer, font,
state->input, 5, V2(1000, 500), fieldString);
// RESET IMGUI // RESET IMGUI
if (!state->input.mouseLeft) state->uiState.activeItem = 0; if (!state->input.keys[keycode_mouseLeft])
else if (state->uiState.activeItem == 0) state->uiState.activeItem = -1; state->uiState.activeItem = 0;
else if (state->uiState.activeItem == 0)
state->uiState.activeItem = -1;
if (state->uiState.keyEntered == keycode_space) state->uiState.kbdItem = 0;
state->uiState.keyEntered = keycode_null;
state->uiState.keyChar = keycode_null;
/* Draw hero avatar */ /* Draw hero avatar */
TexAtlas *heroAtlas = asset_getTextureAtlas(assetManager, texlist_hero); TexAtlas *heroAtlas = asset_getTextureAtlas(assetManager, texlist_hero);

View File

@ -24,24 +24,33 @@ INTERNAL void keyCallback(GLFWwindow *window, int key, int scancode, int action,
switch (key) switch (key)
{ {
case GLFW_KEY_UP: case GLFW_KEY_UP:
processKey(&game->input.up, key, action); processKey(&game->input.keys[keycode_up], key, action);
break; break;
case GLFW_KEY_DOWN: case GLFW_KEY_DOWN:
processKey(&game->input.down, key, action); processKey(&game->input.keys[keycode_down], key, action);
break; break;
case GLFW_KEY_LEFT: case GLFW_KEY_LEFT:
processKey(&game->input.left, key, action); processKey(&game->input.keys[keycode_left], key, action);
break; break;
case GLFW_KEY_RIGHT: case GLFW_KEY_RIGHT:
processKey(&game->input.right, key, action); processKey(&game->input.keys[keycode_right], key, action);
break;
case GLFW_KEY_SPACE:
processKey(&game->input.space, key, action);
break; break;
case GLFW_KEY_LEFT_SHIFT: case GLFW_KEY_LEFT_SHIFT:
processKey(&game->input.leftShift, key, action); processKey(&game->input.keys[keycode_leftShift], key, action);
break;
case GLFW_KEY_ENTER:
processKey(&game->input.keys[keycode_enter], key, action);
break;
case GLFW_KEY_BACKSPACE:
processKey(&game->input.keys[keycode_backspace], key, action);
break; break;
default: default:
if (key >= ' ' && key <= '~')
{
processKey(&game->input.keys[key - ' '], key, action);
// TODO(doyle): Temporary
game->uiState.keyChar = key - ' ';
}
break; break;
} }
} }
@ -64,7 +73,7 @@ INTERNAL void mouseButtonCallback(GLFWwindow *window, int button, int action,
switch(button) switch(button)
{ {
case GLFW_MOUSE_BUTTON_LEFT: case GLFW_MOUSE_BUTTON_LEFT:
processKey(&game->input.mouseLeft, button, action); processKey(&game->input.keys[keycode_mouseLeft], button, action);
break; break;
default: default:
break; break;

View File

@ -7,35 +7,123 @@
/* Forward Declaration */ /* Forward Declaration */
typedef struct MemoryArena MemoryArena; typedef struct MemoryArena MemoryArena;
enum KeyCodes // TODO(doyle): Revise key code system -- should we store the extraneous keys or
// have a mapping function to map it back to ascii?
enum KeyCode
{ {
keycode_space = 0,
keycode_exclamation,
keycode_dbl_quotes,
keycode_hash,
keycode_dollar,
keycode_percent,
keycode_ampersand,
keycode_single_quote,
keycode_left_parenthesis,
keycode_right_parenthesis,
keycode_star,
keycode_plus,
keycode_comma,
keycode_minus,
keycode_hyphen,
keycode_dot,
keycode_forward_slash,
keycode_0,
keycode_1,
keycode_2,
keycode_3,
keycode_4,
keycode_5,
keycode_6,
keycode_7,
keycode_8,
keycode_9,
keycode_colon,
keycode_semi_colon,
keycode_left_angle_bracket,
keycode_equal,
keycode_right_angle_bracket,
keycode_question_mark,
keycode_at,
keycode_A,
keycode_B,
keycode_C,
keycode_D,
keycode_E,
keycode_F,
keycode_G,
keycode_H,
keycode_I,
keycode_J,
keycode_K,
keycode_L,
keycode_M,
keycode_N,
keycode_O,
keycode_P,
keycode_Q,
keycode_R,
keycode_S,
keycode_T,
keycode_U,
keycode_V,
keycode_W,
keycode_X,
keycode_Y,
keycode_Z,
keycode_left_square_bracket,
keycode_back_slash,
keycode_right_square_bracket,
keycode_up_hat,
keycode_underscore,
keycode_alt_tilda,
keycode_a,
keycode_b,
keycode_c,
keycode_d,
keycode_e,
keycode_f,
keycode_g,
keycode_h,
keycode_i,
keycode_j,
keycode_k,
keycode_l,
keycode_m,
keycode_n,
keycode_o,
keycode_p,
keycode_q,
keycode_r,
keycode_s,
keycode_t,
keycode_u,
keycode_v,
keycode_w,
keycode_x,
keycode_y,
keycode_z,
keycode_left_squiggly_bracket,
keycode_pipe,
keycode_right_squiggly_bracket,
keycode_tilda,
keycode_up, keycode_up,
keycode_down, keycode_down,
keycode_left, keycode_left,
keycode_right, keycode_right,
keycode_space,
keycode_leftShift, keycode_leftShift,
keycode_mouseLeft, keycode_mouseLeft,
keycode_enter,
keycode_count, keycode_count,
keycode_backspace,
keycode_tab,
keycode_null,
}; };
typedef struct KeyInput typedef struct KeyInput
{ {
v2 mouseP; v2 mouseP;
union b32 keys[keycode_count - 1];
{
b32 keys[keycode_count - 1];
struct
{
b32 up;
b32 down;
b32 left;
b32 right;
b32 space;
b32 leftShift;
b32 mouseLeft;
};
};
} KeyInput; } KeyInput;
typedef struct PlatformFileRead typedef struct PlatformFileRead

View File

@ -19,8 +19,9 @@ typedef struct UiState
i32 activeItem; i32 activeItem;
i32 kbdItem; i32 kbdItem;
i32 keyEntered; enum KeyCode keyEntered;
i32 keyMod; enum KeyCode keyMod;
enum KeyCode keyChar;
i32 lastWidget; i32 lastWidget;
} UiState; } UiState;