Add text field draft implementation
This commit is contained in:
parent
4127542d1d
commit
22973ef51d
@ -90,6 +90,7 @@ INTERNAL inline RenderQuad
|
||||
createDefaultTexQuad(Renderer *renderer, RenderTex renderTex)
|
||||
{
|
||||
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);
|
||||
result = createTexQuad(renderer, defaultQuad, renderTex);
|
||||
return result;
|
||||
|
@ -341,6 +341,8 @@ void worldTraveller_gameInit(GameState *state, v2 windowSize)
|
||||
DEBUG_LOG("World populated");
|
||||
#endif
|
||||
|
||||
state->uiState.keyEntered = keycode_null;
|
||||
|
||||
srand(CAST(u32)(time(NULL)));
|
||||
}
|
||||
|
||||
@ -375,24 +377,24 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
||||
// if a button ended down
|
||||
LOCAL_PERSIST b32 spaceBarWasDown = FALSE;
|
||||
|
||||
if (state->input.right)
|
||||
if (state->input.keys[keycode_right])
|
||||
{
|
||||
ddPos.x = 1.0f;
|
||||
hero->direction = direction_east;
|
||||
}
|
||||
|
||||
if (state->input.left)
|
||||
if (state->input.keys[keycode_left])
|
||||
{
|
||||
ddPos.x = -1.0f;
|
||||
hero->direction = direction_west;
|
||||
}
|
||||
|
||||
if (state->input.up)
|
||||
if (state->input.keys[keycode_up])
|
||||
{
|
||||
ddPos.y = 1.0f;
|
||||
}
|
||||
|
||||
if (state->input.down)
|
||||
if (state->input.keys[keycode_down])
|
||||
{
|
||||
ddPos.y = -1.0f;
|
||||
}
|
||||
@ -406,10 +408,18 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
||||
ddPos = v2_scale(ddPos, 0.70710678118f);
|
||||
}
|
||||
|
||||
if (state->input.keys[keycode_enter])
|
||||
{
|
||||
state->uiState.keyEntered = keycode_enter;
|
||||
}
|
||||
|
||||
LOCAL_PERSIST b32 toggleFlag = TRUE;
|
||||
// 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;
|
||||
f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h);
|
||||
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);
|
||||
entity_addGenericMob(&state->arena, &state->assetManager, world,
|
||||
pos);
|
||||
#endif
|
||||
spaceBarWasDown = TRUE;
|
||||
}
|
||||
else if (!state->input.space)
|
||||
else if (!state->input.keys[keycode_space])
|
||||
{
|
||||
spaceBarWasDown = FALSE;
|
||||
}
|
||||
@ -444,8 +455,16 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->uiState.keyMod = keycode_null;
|
||||
}
|
||||
|
||||
ddPos = v2_scale(ddPos, heroSpeed);
|
||||
// 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))
|
||||
{
|
||||
DEBUG_PUSH_STRING("POINT IN RECT");
|
||||
uiState->hotItem = id;
|
||||
if (uiState->activeItem == 0 && input.mouseLeft)
|
||||
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
|
||||
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
|
||||
if (uiState->kbdItem == id)
|
||||
{
|
||||
if (input.space)
|
||||
switch (uiState->keyEntered)
|
||||
{
|
||||
case keycode_space:
|
||||
// Set focus to nothing and let next widget get focus
|
||||
uiState->kbdItem = 0;
|
||||
if (input.leftShift)
|
||||
if (uiState->keyMod == keycode_leftShift)
|
||||
uiState->kbdItem = uiState->lastWidget;
|
||||
|
||||
// Clear key state so next widget doesn't auto grab
|
||||
input.space = FALSE;
|
||||
input.leftShift = FALSE;
|
||||
uiState->keyEntered = keycode_null;
|
||||
break;
|
||||
case keycode_enter:
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uiState->lastWidget = id;
|
||||
|
||||
if (!input.mouseLeft &&
|
||||
if (!input.keys[keycode_mouseLeft] &&
|
||||
uiState->hotItem == id &&
|
||||
uiState->activeItem == id)
|
||||
{
|
||||
@ -961,12 +984,25 @@ INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
|
||||
if (math_pointInRect(scrollBarRect, input.mouseP))
|
||||
{
|
||||
uiState->hotItem = id;
|
||||
if (uiState->activeItem == 0 && input.mouseLeft)
|
||||
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
|
||||
uiState->activeItem = id;
|
||||
}
|
||||
|
||||
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
|
||||
renderer_staticRect(renderer, scrollBarRect.pos, scrollBarRect.size,
|
||||
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,
|
||||
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)
|
||||
{
|
||||
f32 mouseYRelToRect = input.mouseP.y - scrollBarRect.pos.y;
|
||||
@ -1012,6 +1080,103 @@ INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
|
||||
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)
|
||||
{
|
||||
if (dt >= 1.0f) dt = 1.0f;
|
||||
@ -1276,12 +1441,22 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
||||
|
||||
LOCAL_PERSIST i32 scrollValue = 30;
|
||||
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);
|
||||
|
||||
LOCAL_PERSIST char fieldString[80] = "Hello world";
|
||||
textField(&state->uiState, &state->arena, assetManager, renderer, font,
|
||||
state->input, 5, V2(1000, 500), fieldString);
|
||||
|
||||
// RESET IMGUI
|
||||
if (!state->input.mouseLeft) state->uiState.activeItem = 0;
|
||||
else if (state->uiState.activeItem == 0) state->uiState.activeItem = -1;
|
||||
if (!state->input.keys[keycode_mouseLeft])
|
||||
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 */
|
||||
TexAtlas *heroAtlas = asset_getTextureAtlas(assetManager, texlist_hero);
|
||||
|
@ -24,24 +24,33 @@ INTERNAL void keyCallback(GLFWwindow *window, int key, int scancode, int action,
|
||||
switch (key)
|
||||
{
|
||||
case GLFW_KEY_UP:
|
||||
processKey(&game->input.up, key, action);
|
||||
processKey(&game->input.keys[keycode_up], key, action);
|
||||
break;
|
||||
case GLFW_KEY_DOWN:
|
||||
processKey(&game->input.down, key, action);
|
||||
processKey(&game->input.keys[keycode_down], key, action);
|
||||
break;
|
||||
case GLFW_KEY_LEFT:
|
||||
processKey(&game->input.left, key, action);
|
||||
processKey(&game->input.keys[keycode_left], key, action);
|
||||
break;
|
||||
case GLFW_KEY_RIGHT:
|
||||
processKey(&game->input.right, key, action);
|
||||
break;
|
||||
case GLFW_KEY_SPACE:
|
||||
processKey(&game->input.space, key, action);
|
||||
processKey(&game->input.keys[keycode_right], key, action);
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
if (key >= ' ' && key <= '~')
|
||||
{
|
||||
processKey(&game->input.keys[key - ' '], key, action);
|
||||
// TODO(doyle): Temporary
|
||||
game->uiState.keyChar = key - ' ';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -64,7 +73,7 @@ INTERNAL void mouseButtonCallback(GLFWwindow *window, int button, int action,
|
||||
switch(button)
|
||||
{
|
||||
case GLFW_MOUSE_BUTTON_LEFT:
|
||||
processKey(&game->input.mouseLeft, button, action);
|
||||
processKey(&game->input.keys[keycode_mouseLeft], button, action);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -7,35 +7,123 @@
|
||||
/* Forward Declaration */
|
||||
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_down,
|
||||
keycode_left,
|
||||
keycode_right,
|
||||
keycode_space,
|
||||
keycode_leftShift,
|
||||
keycode_mouseLeft,
|
||||
keycode_enter,
|
||||
keycode_count,
|
||||
keycode_backspace,
|
||||
keycode_tab,
|
||||
keycode_null,
|
||||
};
|
||||
|
||||
typedef struct KeyInput
|
||||
{
|
||||
v2 mouseP;
|
||||
union
|
||||
{
|
||||
b32 keys[keycode_count - 1];
|
||||
struct
|
||||
{
|
||||
b32 up;
|
||||
b32 down;
|
||||
b32 left;
|
||||
b32 right;
|
||||
b32 space;
|
||||
b32 leftShift;
|
||||
b32 mouseLeft;
|
||||
};
|
||||
};
|
||||
} KeyInput;
|
||||
|
||||
typedef struct PlatformFileRead
|
||||
|
@ -19,8 +19,9 @@ typedef struct UiState
|
||||
i32 activeItem;
|
||||
|
||||
i32 kbdItem;
|
||||
i32 keyEntered;
|
||||
i32 keyMod;
|
||||
enum KeyCode keyEntered;
|
||||
enum KeyCode keyMod;
|
||||
enum KeyCode keyChar;
|
||||
|
||||
i32 lastWidget;
|
||||
} UiState;
|
||||
|
Loading…
Reference in New Issue
Block a user