Separate UI code into own file
This commit is contained in:
parent
5cd7239c8a
commit
e90b31de55
@ -129,6 +129,7 @@
|
|||||||
<ClCompile Include="src\Platform.c" />
|
<ClCompile Include="src\Platform.c" />
|
||||||
<ClCompile Include="src\Renderer.c" />
|
<ClCompile Include="src\Renderer.c" />
|
||||||
<ClCompile Include="src\Shader.c" />
|
<ClCompile Include="src\Shader.c" />
|
||||||
|
<ClCompile Include="src\UserInterface.c" />
|
||||||
<ClCompile Include="src\WorldTraveller.c" />
|
<ClCompile Include="src\WorldTraveller.c" />
|
||||||
<ClCompile Include="src\Texture.c" />
|
<ClCompile Include="src\Texture.c" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
@ -153,6 +154,7 @@
|
|||||||
<ClInclude Include="src\include\Dengine\Renderer.h" />
|
<ClInclude Include="src\include\Dengine\Renderer.h" />
|
||||||
<ClInclude Include="src\include\Dengine\Shader.h" />
|
<ClInclude Include="src\include\Dengine\Shader.h" />
|
||||||
<ClInclude Include="src\include\Dengine\Texture.h" />
|
<ClInclude Include="src\include\Dengine\Texture.h" />
|
||||||
|
<ClInclude Include="src\include\Dengine\UserInterface.h" />
|
||||||
<ClInclude Include="src\include\Dengine\WorldTraveller.h" />
|
<ClInclude Include="src\include\Dengine\WorldTraveller.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -48,6 +48,9 @@
|
|||||||
<ClCompile Include="src\dengine.c">
|
<ClCompile Include="src\dengine.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="src\UserInterface.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="data\shaders\default.vert.glsl" />
|
<None Include="data\shaders\default.vert.glsl" />
|
||||||
@ -101,5 +104,8 @@
|
|||||||
<ClInclude Include="src\include\Dengine\WorldTraveller.h">
|
<ClInclude Include="src\include\Dengine\WorldTraveller.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="src\include\Dengine\UserInterface.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -36,7 +36,8 @@ AudioVorbis *asset_getVorbis(AssetManager *assetManager,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture *asset_getTexture(AssetManager *assetManager, const enum TexList type)
|
Texture *asset_getTexture(AssetManager *const assetManager,
|
||||||
|
const enum TexList type)
|
||||||
{
|
{
|
||||||
if (type < texlist_count)
|
if (type < texlist_count)
|
||||||
return &assetManager->textures[type];
|
return &assetManager->textures[type];
|
||||||
|
@ -168,7 +168,7 @@ INTERNAL v2 mapWorldToCameraSpace(v2 worldPos, v4 cameraBounds)
|
|||||||
return posInCameraSpace;
|
return posInCameraSpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderTex renderer_createNullRenderTex(AssetManager *assetManager)
|
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager)
|
||||||
{
|
{
|
||||||
Texture *emptyTex = asset_getTexture(assetManager, texlist_empty);
|
Texture *emptyTex = asset_getTexture(assetManager, texlist_empty);
|
||||||
RenderTex result = {emptyTex, V4(0, 1, 1, 0)};
|
RenderTex result = {emptyTex, V4(0, 1, 1, 0)};
|
||||||
|
295
src/UserInterface.c
Normal file
295
src/UserInterface.c
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
#include "Dengine/UserInterface.h"
|
||||||
|
#include "Dengine/Assets.h"
|
||||||
|
#include "Dengine/Renderer.h"
|
||||||
|
|
||||||
|
i32 userInterface_button(UiState *const uiState,
|
||||||
|
AssetManager *const assetManager,
|
||||||
|
Renderer *const renderer, const KeyInput input,
|
||||||
|
const i32 id, const Rect rect)
|
||||||
|
{
|
||||||
|
if (math_pointInRect(rect, input.mouseP))
|
||||||
|
{
|
||||||
|
uiState->hotItem = id;
|
||||||
|
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
|
||||||
|
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), rect.pos),
|
||||||
|
v2_add(V2(20, 20), rect.size), V2(0, 0), 0, renderTex,
|
||||||
|
V4(1.0f, 0, 0, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw shadow
|
||||||
|
renderer_staticRect(renderer, v2_add(V2(8, 8), rect.pos), rect.size,
|
||||||
|
V2(0, 0), 0, renderTex, V4(0, 0, 0, 1));
|
||||||
|
|
||||||
|
if (uiState->hotItem == id)
|
||||||
|
{
|
||||||
|
if (uiState->activeItem == id)
|
||||||
|
{
|
||||||
|
renderer_staticRect(renderer, v2_add(V2(2, 2), rect.pos), rect.size,
|
||||||
|
V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
|
||||||
|
V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
|
||||||
|
V2(0, 0), 0, renderTex, V4(0.5f, 0.5f, 0.5f, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// After renderering before click check, see if we need to process keys
|
||||||
|
if (uiState->kbdItem == id)
|
||||||
|
{
|
||||||
|
switch (uiState->keyEntered)
|
||||||
|
{
|
||||||
|
case keycode_tab:
|
||||||
|
// Set focus to nothing and let next widget get focus
|
||||||
|
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_enter:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uiState->lastWidget = id;
|
||||||
|
|
||||||
|
if (!input.keys[keycode_mouseLeft].endedDown &&
|
||||||
|
uiState->hotItem == id &&
|
||||||
|
uiState->activeItem == id)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 userInterface_scrollBar(UiState *const uiState,
|
||||||
|
AssetManager *const assetManager,
|
||||||
|
Renderer *const renderer, const KeyInput input,
|
||||||
|
const i32 id, const Rect scrollBarRect,
|
||||||
|
i32 *const value, const i32 maxValue)
|
||||||
|
{
|
||||||
|
#ifdef DENGINE_DEBUG
|
||||||
|
ASSERT(*value <= maxValue);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (math_pointInRect(scrollBarRect, input.mouseP))
|
||||||
|
{
|
||||||
|
uiState->hotItem = id;
|
||||||
|
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
|
||||||
|
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));
|
||||||
|
|
||||||
|
// Render scroll bar slider
|
||||||
|
v2 sliderSize = V2(16, 16);
|
||||||
|
v4 sliderColor = V4(0, 0, 0, 1);
|
||||||
|
|
||||||
|
f32 sliderPercentageOffset = (CAST(f32) *value / CAST(f32) maxValue);
|
||||||
|
f32 sliderYOffsetToBar =
|
||||||
|
(scrollBarRect.size.h - sliderSize.h) * sliderPercentageOffset;
|
||||||
|
v2 sliderPos = v2_add(scrollBarRect.pos, V2(0, sliderYOffsetToBar));
|
||||||
|
|
||||||
|
if (uiState->hotItem == id || uiState->activeItem == id)
|
||||||
|
sliderColor = V4(1.0f, 0, 0, 1);
|
||||||
|
else
|
||||||
|
sliderColor = V4(0.0f, 1.0f, 0, 1);
|
||||||
|
|
||||||
|
renderer_staticRect(renderer, sliderPos, sliderSize, V2(0, 0), 0, renderTex,
|
||||||
|
sliderColor);
|
||||||
|
|
||||||
|
if (uiState->kbdItem == id)
|
||||||
|
{
|
||||||
|
switch (uiState->keyEntered)
|
||||||
|
{
|
||||||
|
case keycode_tab:
|
||||||
|
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;
|
||||||
|
|
||||||
|
// Bounds check
|
||||||
|
if (mouseYRelToRect < 0)
|
||||||
|
mouseYRelToRect = 0;
|
||||||
|
else if (mouseYRelToRect > scrollBarRect.size.h)
|
||||||
|
mouseYRelToRect = scrollBarRect.size.h;
|
||||||
|
|
||||||
|
f32 newSliderPercentOffset =
|
||||||
|
(CAST(f32) mouseYRelToRect / scrollBarRect.size.h);
|
||||||
|
|
||||||
|
i32 newValue = CAST(i32)(newSliderPercentOffset * CAST(f32)maxValue);
|
||||||
|
if (newValue != *value)
|
||||||
|
{
|
||||||
|
*value = newValue;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 userInterface_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].endedDown)
|
||||||
|
{
|
||||||
|
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 text field
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(doyle): Figure out why we need to offset text ..
|
||||||
|
v2 strPos = v2_add(textRect.pos, V2(0, -font->maxSize.h));
|
||||||
|
|
||||||
|
renderer_staticString(renderer, arena, font, string, strPos, V2(0, 0), 0,
|
||||||
|
V4(0, 0, 0, 1));
|
||||||
|
|
||||||
|
if (uiState->kbdItem == id)
|
||||||
|
{
|
||||||
|
switch (uiState->keyEntered)
|
||||||
|
{
|
||||||
|
case keycode_tab:
|
||||||
|
uiState->kbdItem = 0;
|
||||||
|
if (uiState->keyMod == keycode_leftShift)
|
||||||
|
uiState->kbdItem = uiState->lastWidget;
|
||||||
|
|
||||||
|
uiState->keyEntered = keycode_null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case keycode_backspace:
|
||||||
|
if (strLen > 0)
|
||||||
|
{
|
||||||
|
string[--strLen] = 0;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uiState->keyChar >= keycode_space &&
|
||||||
|
uiState->keyChar <= keycode_tilda && strLen < 30)
|
||||||
|
{
|
||||||
|
string[strLen++] = uiState->keyChar + ' ';
|
||||||
|
string[strLen] = 0;
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input.keys[keycode_mouseLeft].endedDown &&
|
||||||
|
uiState->hotItem == id &&
|
||||||
|
uiState->activeItem == id)
|
||||||
|
{
|
||||||
|
uiState->kbdItem = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uiState->lastWidget = id;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@
|
|||||||
#include "Dengine/Debug.h"
|
#include "Dengine/Debug.h"
|
||||||
#include "Dengine/Entity.h"
|
#include "Dengine/Entity.h"
|
||||||
#include "Dengine/Platform.h"
|
#include "Dengine/Platform.h"
|
||||||
|
#include "Dengine/UserInterface.h"
|
||||||
|
|
||||||
enum State
|
enum State
|
||||||
{
|
{
|
||||||
@ -1001,289 +1002,6 @@ INTERNAL void sortWorldEntityList(World *world, i32 numDeadEntities)
|
|||||||
world->freeEntityIndex -= numDeadEntities;
|
world->freeEntityIndex -= numDeadEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL i32 button(UiState *uiState, AssetManager *assetManager,
|
|
||||||
Renderer *renderer, KeyInput input, i32 id, Rect rect)
|
|
||||||
{
|
|
||||||
if (math_pointInRect(rect, input.mouseP))
|
|
||||||
{
|
|
||||||
uiState->hotItem = id;
|
|
||||||
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
|
|
||||||
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), rect.pos),
|
|
||||||
v2_add(V2(20, 20), rect.size), V2(0, 0), 0, renderTex,
|
|
||||||
V4(1.0f, 0, 0, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw shadow
|
|
||||||
renderer_staticRect(renderer, v2_add(V2(8, 8), rect.pos), rect.size,
|
|
||||||
V2(0, 0), 0, renderTex, V4(0, 0, 0, 1));
|
|
||||||
|
|
||||||
if (uiState->hotItem == id)
|
|
||||||
{
|
|
||||||
if (uiState->activeItem == id)
|
|
||||||
{
|
|
||||||
renderer_staticRect(renderer, v2_add(V2(2, 2), rect.pos), rect.size,
|
|
||||||
V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
|
|
||||||
V2(0, 0), 0, renderTex, V4(1, 1, 1, 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
renderer_staticRect(renderer, v2_add(V2(0, 0), rect.pos), rect.size,
|
|
||||||
V2(0, 0), 0, renderTex, V4(0.5f, 0.5f, 0.5f, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// After renderering before click check, see if we need to process keys
|
|
||||||
if (uiState->kbdItem == id)
|
|
||||||
{
|
|
||||||
switch (uiState->keyEntered)
|
|
||||||
{
|
|
||||||
case keycode_tab:
|
|
||||||
// Set focus to nothing and let next widget get focus
|
|
||||||
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_enter:
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uiState->lastWidget = id;
|
|
||||||
|
|
||||||
if (!input.keys[keycode_mouseLeft].endedDown &&
|
|
||||||
uiState->hotItem == id &&
|
|
||||||
uiState->activeItem == id)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
|
|
||||||
Renderer *renderer, KeyInput input, i32 id,
|
|
||||||
Rect scrollBarRect, i32 *value, i32 maxValue)
|
|
||||||
{
|
|
||||||
#ifdef DENGINE_DEBUG
|
|
||||||
ASSERT(*value <= maxValue);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (math_pointInRect(scrollBarRect, input.mouseP))
|
|
||||||
{
|
|
||||||
uiState->hotItem = id;
|
|
||||||
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
|
|
||||||
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));
|
|
||||||
|
|
||||||
// Render scroll bar slider
|
|
||||||
v2 sliderSize = V2(16, 16);
|
|
||||||
v4 sliderColor = V4(0, 0, 0, 1);
|
|
||||||
|
|
||||||
f32 sliderPercentageOffset = (CAST(f32) *value / CAST(f32) maxValue);
|
|
||||||
f32 sliderYOffsetToBar =
|
|
||||||
(scrollBarRect.size.h - sliderSize.h) * sliderPercentageOffset;
|
|
||||||
v2 sliderPos = v2_add(scrollBarRect.pos, V2(0, sliderYOffsetToBar));
|
|
||||||
|
|
||||||
if (uiState->hotItem == id || uiState->activeItem == id)
|
|
||||||
sliderColor = V4(1.0f, 0, 0, 1);
|
|
||||||
else
|
|
||||||
sliderColor = V4(0.0f, 1.0f, 0, 1);
|
|
||||||
|
|
||||||
renderer_staticRect(renderer, sliderPos, sliderSize, V2(0, 0), 0, renderTex,
|
|
||||||
sliderColor);
|
|
||||||
|
|
||||||
if (uiState->kbdItem == id)
|
|
||||||
{
|
|
||||||
switch (uiState->keyEntered)
|
|
||||||
{
|
|
||||||
case keycode_tab:
|
|
||||||
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;
|
|
||||||
|
|
||||||
// Bounds check
|
|
||||||
if (mouseYRelToRect < 0)
|
|
||||||
mouseYRelToRect = 0;
|
|
||||||
else if (mouseYRelToRect > scrollBarRect.size.h)
|
|
||||||
mouseYRelToRect = scrollBarRect.size.h;
|
|
||||||
|
|
||||||
f32 newSliderPercentOffset =
|
|
||||||
(CAST(f32) mouseYRelToRect / scrollBarRect.size.h);
|
|
||||||
|
|
||||||
i32 newValue = CAST(i32)(newSliderPercentOffset * CAST(f32)maxValue);
|
|
||||||
if (newValue != *value)
|
|
||||||
{
|
|
||||||
*value = newValue;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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].endedDown)
|
|
||||||
{
|
|
||||||
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_tab:
|
|
||||||
uiState->kbdItem = 0;
|
|
||||||
if (uiState->keyMod == keycode_leftShift)
|
|
||||||
uiState->kbdItem = uiState->lastWidget;
|
|
||||||
|
|
||||||
uiState->keyEntered = keycode_null;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case keycode_backspace:
|
|
||||||
if (strLen > 0)
|
|
||||||
{
|
|
||||||
string[--strLen] = 0;
|
|
||||||
changed = TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uiState->keyChar >= keycode_space &&
|
|
||||||
uiState->keyChar <= keycode_tilda && strLen < 30)
|
|
||||||
{
|
|
||||||
string[strLen++] = uiState->keyChar + ' ';
|
|
||||||
string[strLen] = 0;
|
|
||||||
changed = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!input.keys[keycode_mouseLeft].endedDown &&
|
|
||||||
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;
|
||||||
@ -1535,25 +1253,26 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
|
|
||||||
/* Draw ui */
|
/* Draw ui */
|
||||||
Rect buttonRectA = {V2(300, 500), V2(100, 50)};
|
Rect buttonRectA = {V2(300, 500), V2(100, 50)};
|
||||||
button(&state->uiState, assetManager, renderer, state->input, 1,
|
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
||||||
buttonRectA);
|
1, buttonRectA);
|
||||||
|
|
||||||
Rect buttonRectB = {V2(500, 500), V2(100, 50)};
|
Rect buttonRectB = {V2(500, 500), V2(100, 50)};
|
||||||
button(&state->uiState, assetManager, renderer, state->input, 2,
|
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
||||||
buttonRectB);
|
2, buttonRectB);
|
||||||
|
|
||||||
Rect buttonRectC = {V2(700, 500), V2(100, 50)};
|
Rect buttonRectC = {V2(700, 500), V2(100, 50)};
|
||||||
button(&state->uiState, assetManager, renderer, state->input, 3,
|
userInterface_button(&state->uiState, assetManager, renderer, state->input,
|
||||||
buttonRectC);
|
3, buttonRectC);
|
||||||
|
|
||||||
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, 4,
|
userInterface_scrollBar(&state->uiState, assetManager, renderer,
|
||||||
scrollRectA, &scrollValue, 160);
|
state->input, 4, scrollRectA, &scrollValue, 160);
|
||||||
|
|
||||||
LOCAL_PERSIST char fieldString[80] = "Hello world";
|
LOCAL_PERSIST char fieldString[80] = "Hello world";
|
||||||
textField(&state->uiState, &state->arena, assetManager, renderer, font,
|
userInterface_textField(&state->uiState, &state->arena, assetManager,
|
||||||
state->input, 5, V2(1000, 500), fieldString);
|
renderer, font, state->input, 5, V2(1000, 500),
|
||||||
|
fieldString);
|
||||||
|
|
||||||
// RESET IMGUI
|
// RESET IMGUI
|
||||||
if (!state->input.keys[keycode_mouseLeft].endedDown)
|
if (!state->input.keys[keycode_mouseLeft].endedDown)
|
||||||
|
@ -22,7 +22,8 @@ typedef struct AssetManager
|
|||||||
|
|
||||||
AudioVorbis *asset_getVorbis(AssetManager *assetManager,
|
AudioVorbis *asset_getVorbis(AssetManager *assetManager,
|
||||||
const enum AudioList type);
|
const enum AudioList type);
|
||||||
Texture *asset_getTexture(AssetManager *assetManager, const enum TexList type);
|
Texture *asset_getTexture(AssetManager *const assetManager,
|
||||||
|
const enum TexList type);
|
||||||
Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type);
|
Shader *asset_getShader(AssetManager *assetManager, const enum ShaderList type);
|
||||||
TexAtlas *asset_getTextureAtlas(AssetManager *assetManager,
|
TexAtlas *asset_getTextureAtlas(AssetManager *assetManager,
|
||||||
const enum TexList type);
|
const enum TexList type);
|
||||||
|
@ -28,7 +28,7 @@ typedef struct RenderTex
|
|||||||
v4 texRect;
|
v4 texRect;
|
||||||
} RenderTex;
|
} RenderTex;
|
||||||
|
|
||||||
RenderTex renderer_createNullRenderTex(AssetManager *assetManager);
|
RenderTex renderer_createNullRenderTex(AssetManager *const assetManager);
|
||||||
|
|
||||||
// TODO(doyle): Clean up lines
|
// TODO(doyle): Clean up lines
|
||||||
// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
|
// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
|
||||||
|
43
src/include/Dengine/UserInterface.h
Normal file
43
src/include/Dengine/UserInterface.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#ifndef DENGINE_USER_INTERFACE_H
|
||||||
|
#define DENGINE_USER_INTERFACE_H
|
||||||
|
|
||||||
|
#include "Dengine/Common.h"
|
||||||
|
#include "Dengine/Math.h"
|
||||||
|
#include "Dengine/Platform.h"
|
||||||
|
|
||||||
|
/* Forward Declaration */
|
||||||
|
typedef struct AssetManager AssetManager;
|
||||||
|
typedef struct Font Font;
|
||||||
|
typedef struct MemoryArena MemoryArena;
|
||||||
|
typedef struct Renderer Renderer;
|
||||||
|
|
||||||
|
typedef struct UiState
|
||||||
|
{
|
||||||
|
i32 hotItem;
|
||||||
|
i32 activeItem;
|
||||||
|
|
||||||
|
i32 kbdItem;
|
||||||
|
enum KeyCode keyEntered;
|
||||||
|
enum KeyCode keyMod;
|
||||||
|
enum KeyCode keyChar;
|
||||||
|
|
||||||
|
i32 lastWidget;
|
||||||
|
} UiState;
|
||||||
|
|
||||||
|
i32 userInterface_button(UiState *const uiState,
|
||||||
|
AssetManager *const assetManager,
|
||||||
|
Renderer *const renderer, const KeyInput input,
|
||||||
|
const i32 id, const Rect rect);
|
||||||
|
|
||||||
|
i32 userInterface_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 userInterface_scrollBar(UiState *const uiState,
|
||||||
|
AssetManager *const assetManager,
|
||||||
|
Renderer *const renderer, const KeyInput input,
|
||||||
|
const i32 id, const Rect scrollBarRect,
|
||||||
|
i32 *const value, const i32 maxValue);
|
||||||
|
#endif
|
@ -4,27 +4,17 @@
|
|||||||
#include "Dengine/AssetManager.h"
|
#include "Dengine/AssetManager.h"
|
||||||
#include "Dengine/Audio.h"
|
#include "Dengine/Audio.h"
|
||||||
#include "Dengine/Common.h"
|
#include "Dengine/Common.h"
|
||||||
#include "Dengine/Entity.h"
|
|
||||||
#include "Dengine/Math.h"
|
#include "Dengine/Math.h"
|
||||||
#include "Dengine/MemoryArena.h"
|
#include "Dengine/MemoryArena.h"
|
||||||
#include "Dengine/Platform.h"
|
#include "Dengine/Platform.h"
|
||||||
#include "Dengine/Renderer.h"
|
#include "Dengine/Renderer.h"
|
||||||
|
#include "Dengine/UserInterface.h"
|
||||||
|
|
||||||
#define NUM_KEYS 1024
|
#define NUM_KEYS 1024
|
||||||
#define METERS_TO_PIXEL 240
|
#define METERS_TO_PIXEL 240
|
||||||
|
|
||||||
typedef struct UiState
|
/* Forward declaration */
|
||||||
{
|
typedef struct Entity Entity;
|
||||||
i32 hotItem;
|
|
||||||
i32 activeItem;
|
|
||||||
|
|
||||||
i32 kbdItem;
|
|
||||||
enum KeyCode keyEntered;
|
|
||||||
enum KeyCode keyMod;
|
|
||||||
enum KeyCode keyChar;
|
|
||||||
|
|
||||||
i32 lastWidget;
|
|
||||||
} UiState;
|
|
||||||
|
|
||||||
typedef struct World
|
typedef struct World
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user