DJUI: Added keyboard/gamepad support

This commit is contained in:
MysterD 2021-06-22 20:01:16 -07:00
parent a3947b3800
commit 580f19dcc9
10 changed files with 267 additions and 72 deletions

View file

@ -3944,6 +3944,7 @@
<ClCompile Include="..\src\pc\djui\djui.c" />
<ClCompile Include="..\src\pc\djui\djui_base.c" />
<ClCompile Include="..\src\pc\djui\djui_button.c" />
<ClCompile Include="..\src\pc\djui\djui_cursor.c" />
<ClCompile Include="..\src\pc\djui\djui_flow_layout.c" />
<ClCompile Include="..\src\pc\djui\djui_font.c" />
<ClCompile Include="..\src\pc\djui\djui_gfx.c" />
@ -4371,6 +4372,7 @@
<ClInclude Include="..\src\pc\djui\djui.h" />
<ClInclude Include="..\src\pc\djui\djui_base.h" />
<ClInclude Include="..\src\pc\djui\djui_button.h" />
<ClInclude Include="..\src\pc\djui\djui_cursor.h" />
<ClInclude Include="..\src\pc\djui\djui_flow_layout.h" />
<ClInclude Include="..\src\pc\djui\djui_font.h" />
<ClInclude Include="..\src\pc\djui\djui_gbi.h" />

View file

@ -15207,6 +15207,9 @@
<ClCompile Include="..\src\pc\djui\djui_panel_options.c">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClCompile>
<ClCompile Include="..\src\pc\djui\djui_cursor.c">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\actors\common0.h">
@ -16234,5 +16237,8 @@
<ClInclude Include="..\src\pc\djui\djui_panel_options.h">
<Filter>Source Files\src\pc\djui\panel</Filter>
</ClInclude>
<ClInclude Include="..\src\pc\djui\djui_cursor.h">
<Filter>Source Files\src\pc\djui\component</Filter>
</ClInclude>
</ItemGroup>
</Project>

View file

@ -18,6 +18,7 @@
#include "engine/math_util.h"
#include "menu/file_select.h"
#include "game/chat.h"
#include "src/pc/djui/djui.h"
// TODO: use some common lookup header
#define SCANCODE_BACKSPACE 0x0E
@ -86,6 +87,8 @@ bool keyboard_on_key_down(int scancode) {
// alter the held value of modifier keys
keyboard_alter_modifier(scancode, true);
djui_interactable_on_key_down(scancode);
#ifdef DEBUG
if (!sInTextInput) {
debug_keyboard_on_key_down(scancode);
@ -132,6 +135,8 @@ bool keyboard_on_key_up(int scancode) {
// alter the held value of modifier keys
keyboard_alter_modifier(scancode, false);
djui_interactable_on_key_up(scancode);
if (sInTextInput) {
// ignore any key up event if we're in text-input mode
return FALSE;

View file

@ -1,49 +1,17 @@
#include "djui.h"
#include "../debuglog.h"
#include "src/pc/controller/controller_sdl.h"
#include "src/pc/controller/controller_mouse.h"
ALIGNED8 static u8 texture_hand_open[] = {
#include "textures/intro_raw/hand_open.rgba16.inc.c"
};
ALIGNED8 static u8 texture_hand_closed[] = {
#include "textures/intro_raw/hand_closed.rgba16.inc.c"
};
static Gfx* sSavedDisplayListHead = NULL;
struct DjuiRoot* gDjuiRoot = NULL;
static struct DjuiImage* sMouseCursor = NULL;
struct DjuiFlowLayout* buttonContainer;
static void djui_init(void) {
gDjuiRoot = djui_root_create();
sMouseCursor = djui_image_create(NULL, texture_hand_open, 32, 32, 16);
djui_base_set_location(&sMouseCursor->base, 0, 0);
djui_base_set_size(&sMouseCursor->base, 64, 64);
djui_panel_main_create();
//djui_panel_debug_create();
}
static void djui_mouse_update(void) {
#if defined(CAPI_SDL2) || defined(CAPI_SDL1)
controller_sdl_read_mouse_window();
djui_interactable_update();
// adjust mouse cursor
djui_base_set_location(&sMouseCursor->base, mouse_window_x - 13, mouse_window_y - 13);
if (mouse_window_buttons & 0b0001) {
djui_image_set_image(sMouseCursor, texture_hand_closed, 32, 32, 16);
} else {
djui_image_set_image(sMouseCursor, texture_hand_open, 32, 32, 16);
}
#endif
djui_cursor_create();
}
void djui_render_patch(void) {
@ -60,8 +28,8 @@ void djui_render(void) {
sSavedDisplayListHead = gDisplayListHead;
create_dl_ortho_matrix();
djui_mouse_update();
djui_base_render(&gDjuiRoot->base);
djui_base_render(&sMouseCursor->base);
djui_cursor_update();
djui_interactable_update();
}

View file

@ -14,6 +14,7 @@
#include "djui_interactable.h"
#include "djui_root.h"
#include "djui_cursor.h"
#include "djui_rect.h"
#include "djui_text.h"
#include "djui_image.h"

View file

@ -18,14 +18,14 @@ static void djui_button_on_hover_end(struct DjuiBase* base) {
djui_button_set_default_style(base);
}
static void djui_button_on_mouse_down_begin(struct DjuiBase* base) {
static void djui_button_on_cursor_down_begin(struct DjuiBase* base) {
struct DjuiButton* button = (struct DjuiButton*)base;
djui_base_set_border_color(base, 0, 84, 153, 255);
djui_base_set_color(&button->rect->base, 204, 228, 247, 255);
djui_base_set_location(&button->text->base, 0.5f, 0.5f);
}
static void djui_button_on_mouse_down_end(struct DjuiBase* base) {
static void djui_button_on_cursor_down_end(struct DjuiBase* base) {
djui_button_set_default_style(base);
}
@ -44,8 +44,8 @@ struct DjuiButton* djui_button_create(struct DjuiBase* parent, const char* messa
djui_interactable_create(base,
djui_button_on_hover_begin,
djui_button_on_hover_end,
djui_button_on_mouse_down_begin,
djui_button_on_mouse_down_end);
djui_button_on_cursor_down_begin,
djui_button_on_cursor_down_end);
struct DjuiRect* rect = djui_rect_create(&button->base);
djui_base_set_size_type(&rect->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);

123
src/pc/djui/djui_cursor.c Normal file
View file

@ -0,0 +1,123 @@
#include "djui.h"
#include "src/pc/controller/controller_sdl.h"
#include "src/pc/controller/controller_mouse.h"
ALIGNED8 static u8 texture_hand_open[] = {
#include "textures/intro_raw/hand_open.rgba16.inc.c"
};
ALIGNED8 static u8 texture_hand_closed[] = {
#include "textures/intro_raw/hand_closed.rgba16.inc.c"
};
static struct DjuiImage* sMouseCursor = NULL;
static bool sCursorMouseControlled = false;
static f32 sSavedMouseX = 0;
static f32 sSavedMouseY = 0;
static f32 sCursorX = 0;
static f32 sCursorY = 0;
bool djui_cursor_inside_base(struct DjuiBase* base) {
struct DjuiBaseRect* clip = &base->elem;
if (sCursorX < clip->x) { return false; }
if (sCursorX > clip->x + clip->width) { return false; }
if (sCursorY < clip->y) { return false; }
if (sCursorY > clip->y + clip->height) { return false; }
return true;
}
static void djui_cursor_base_hover_location(struct DjuiBase* base, f32* x, f32* y) {
*x = (base->elem.x + base->elem.width * 3.0f / 4.0f);
*y = (base->elem.y + base->elem.height * 3.0f / 4.0f);
}
static f32 djui_cursor_base_distance(struct DjuiBase* base) {
f32 x, y;
djui_cursor_base_hover_location(base, &x, &y);
x -= sCursorX;
y -= sCursorY;
return sqrtf((x * x) + (y * y));
}
static void djui_cursor_move_check(s8 xDir, s8 yDir, struct DjuiBase** pick, struct DjuiBase* base) {
if (!base->visible) { return; }
if (!base->enabled) { return; }
if (base->interactable != NULL) {
f32 xH, yH;
djui_cursor_base_hover_location(base, &xH, &yH);
bool valid = true;
if (xDir > 0 && sCursorX >= xH) { valid = false; }
if (xDir < 0 && sCursorX <= xH) { valid = false; }
if (yDir > 0 && sCursorY >= yH) { valid = false; }
if (yDir < 0 && sCursorY <= yH) { valid = false; }
if (valid) {
if (*pick == NULL) {
*pick = base;
} else {
f32 pickDist = djui_cursor_base_distance(*pick);
f32 baseDist = djui_cursor_base_distance(base);
if (baseDist < pickDist) {
*pick = base;
}
}
}
}
// check all children
struct DjuiBaseChild* child = base->child;
while (child != NULL) {
djui_cursor_move_check(xDir, yDir, pick, child->base);
child = child->next;
}
}
void djui_cursor_move(s8 xDir, s8 yDir) {
if (xDir == 0 && yDir == 0) { return; }
struct DjuiBase* pick = NULL;
djui_cursor_move_check(xDir, yDir, &pick, &gDjuiRoot->base);
if (pick != NULL) {
if (sCursorMouseControlled) {
sCursorMouseControlled = false;
sSavedMouseX = sCursorX;
sSavedMouseY = sCursorY;
}
djui_cursor_base_hover_location(pick, &sCursorX, &sCursorY);
}
}
void djui_cursor_update(void) {
#if defined(CAPI_SDL2) || defined(CAPI_SDL1)
controller_sdl_read_mouse_window();
// adjust mouse cursor
if (!sCursorMouseControlled) {
f32 dist = sqrtf(powf(mouse_window_x - sSavedMouseX, 2) + powf(mouse_window_y - sSavedMouseY, 2));
if (dist > 2) {
sCursorMouseControlled = true;
}
}
if (sCursorMouseControlled) {
sCursorX = mouse_window_x;
sCursorY = mouse_window_y;
}
djui_base_set_location(&sMouseCursor->base, sCursorX - 13, sCursorY - 13);
if (mouse_window_buttons & 0b0001) {
djui_image_set_image(sMouseCursor, texture_hand_closed, 32, 32, 16);
}
else {
djui_image_set_image(sMouseCursor, texture_hand_open, 32, 32, 16);
}
#endif
djui_base_render(&sMouseCursor->base);
}
void djui_cursor_create(void) {
sMouseCursor = djui_image_create(NULL, texture_hand_open, 32, 32, 16);
djui_base_set_location(&sMouseCursor->base, 0, 0);
djui_base_set_size(&sMouseCursor->base, 64, 64);
}

View file

@ -0,0 +1,8 @@
#pragma once
#include "djui.h"
#include "djui_base.h"
bool djui_cursor_inside_base(struct DjuiBase* base);
void djui_cursor_move(s8 xDir, s8 yDir);
void djui_cursor_update(void);
void djui_cursor_create(void);

View file

@ -1,20 +1,28 @@
#include <string.h>
#include <time.h>
#include "djui.h"
#include "src/pc/controller/controller_sdl.h"
#include "src/pc/controller/controller_mouse.h"
#include "src/pc/controller/controller_keyboard.h"
struct DjuiBase* sHovered = NULL;
struct DjuiBase* sMouseDown = NULL;
#define PAD_BUTTON_A (1 << 15)
static bool djui_interactable_mouse_inside(struct DjuiBase* base) {
struct DjuiBaseRect* clip = &base->elem;
if (mouse_window_x < clip->x) { return false; }
if (mouse_window_x > clip->x + clip->width) { return false; }
if (mouse_window_y < clip->y) { return false; }
if (mouse_window_y > clip->y + clip->height) { return false; }
return true;
}
#define SCANCODE_UP 328
#define SCANCODE_DOWN 336
#define SCANCODE_LEFT 331
#define SCANCODE_RIGHT 333
#define SCANCODE_ENTER 28
#define SCANCODE_SPACE 57
#define SCANCODE_ESCAPE 1
enum PadHoldDirection { PAD_HOLD_DIR_NONE, PAD_HOLD_DIR_UP, PAD_HOLD_DIR_DOWN, PAD_HOLD_DIR_LEFT, PAD_HOLD_DIR_RIGHT };
static enum PadHoldDirection sKeyboardHoldDirection = PAD_HOLD_DIR_NONE;
static struct DjuiBase* sHovered = NULL;
static struct DjuiBase* sMouseDown = NULL;
static u8 sInputCursorDown = false;
static void djui_interactable_on_click(struct DjuiBase* base) {
if (base == NULL) { return; }
@ -37,37 +45,37 @@ static void djui_interactable_on_hover_end(struct DjuiBase* base) {
base->interactable->on_hover_end(base);
}
static void djui_interactable_on_mouse_down_begin(struct DjuiBase* base) {
static void djui_interactable_on_cursor_down_begin(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_mouse_down_begin == NULL) { return; }
if (base->interactable->on_cursor_down_begin == NULL) { return; }
if (sHovered != NULL) {
djui_interactable_on_hover_end(sHovered);
sHovered = NULL;
}
base->interactable->on_mouse_down_begin(base);
base->interactable->on_cursor_down_begin(base);
}
static void djui_interactable_on_mouse_down_end(struct DjuiBase* base) {
static void djui_interactable_on_cursor_down_end(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
if (base->interactable->on_mouse_down_end == NULL) { return; }
base->interactable->on_mouse_down_end(base);
if (base->interactable->on_cursor_down_end == NULL) { return; }
base->interactable->on_cursor_down_end(base);
if (djui_interactable_mouse_inside(base)) {
if (djui_cursor_inside_base(base)) {
djui_interactable_on_click(base);
}
}
static void djui_interactable_mouse_update_active(struct DjuiBase* base) {
static void djui_interactable_cursor_update_active(struct DjuiBase* base) {
if (!base->visible) { return; }
if (!base->enabled) { return; }
static struct DjuiBase* insideParent = NULL;
if (!djui_interactable_mouse_inside(base)) { return; }
if (!djui_cursor_inside_base(base)) { return; }
if (base->interactable != NULL) {
sHovered = base;
@ -79,7 +87,7 @@ static void djui_interactable_mouse_update_active(struct DjuiBase* base) {
// check all children
struct DjuiBaseChild* child = base->child;
while (child != NULL) {
djui_interactable_mouse_update_active(child->base);
djui_interactable_cursor_update_active(child->base);
child = child->next;
}
@ -88,21 +96,93 @@ static void djui_interactable_mouse_update_active(struct DjuiBase* base) {
}
}
void djui_interactable_on_key_down(int scancode) {
switch (scancode) {
case SCANCODE_UP: sKeyboardHoldDirection = PAD_HOLD_DIR_UP; break;
case SCANCODE_DOWN: sKeyboardHoldDirection = PAD_HOLD_DIR_DOWN; break;
case SCANCODE_LEFT: sKeyboardHoldDirection = PAD_HOLD_DIR_LEFT; break;
case SCANCODE_RIGHT: sKeyboardHoldDirection = PAD_HOLD_DIR_RIGHT; break;
case SCANCODE_ENTER: sInputCursorDown |= (1 << 0); break;
}
}
void djui_interactable_on_key_up(int scancode) {
switch (scancode) {
case SCANCODE_UP: if (sKeyboardHoldDirection == PAD_HOLD_DIR_UP) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; } break;
case SCANCODE_DOWN: if (sKeyboardHoldDirection == PAD_HOLD_DIR_DOWN) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; } break;
case SCANCODE_LEFT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_LEFT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; } break;
case SCANCODE_RIGHT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_RIGHT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; } break;
case SCANCODE_ENTER: sInputCursorDown &= ~(1 << 0); break;
}
if (scancode == SCANCODE_ENTER) {
sInputCursorDown &= ~(1 << 0);
}
}
void djui_interactable_update_pad(void) {
OSContPad* pad = &gControllerPads[0];
sInputCursorDown &= ~(1 << 1);
if (pad->button & PAD_BUTTON_A) {
sInputCursorDown |= (1 << 1);
}
static enum PadHoldDirection lastPadHoldDirection = PAD_HOLD_DIR_NONE;
static clock_t padHoldTimer = 0;
enum PadHoldDirection padHoldDirection = PAD_HOLD_DIR_NONE;
if (pad->stick_x == 0 && pad->stick_y == 0) {
padHoldDirection = PAD_HOLD_DIR_NONE;
} else if (abs(pad->stick_x) > abs(pad->stick_y)) {
padHoldDirection = (pad->stick_x < 0) ? PAD_HOLD_DIR_LEFT : PAD_HOLD_DIR_RIGHT;
} else {
padHoldDirection = (pad->stick_y > 0) ? PAD_HOLD_DIR_UP : PAD_HOLD_DIR_DOWN;
}
if (sKeyboardHoldDirection != PAD_HOLD_DIR_NONE) {
padHoldDirection = sKeyboardHoldDirection;
}
bool validPadHold = false;
if (padHoldDirection == PAD_HOLD_DIR_NONE) {
// nothing to do
} else if (padHoldDirection != lastPadHoldDirection) {
padHoldTimer = clock() + CLOCKS_PER_SEC * 0.25f;
validPadHold = true;
} else if (clock() > padHoldTimer) {
padHoldTimer = clock() + CLOCKS_PER_SEC * 0.10f;
validPadHold = true;
}
if (validPadHold) {
switch (padHoldDirection) {
case PAD_HOLD_DIR_UP: djui_cursor_move( 0, -1); break;
case PAD_HOLD_DIR_DOWN: djui_cursor_move( 0, 1); break;
case PAD_HOLD_DIR_LEFT: djui_cursor_move(-1, 0); break;
case PAD_HOLD_DIR_RIGHT: djui_cursor_move( 1, 0); break;
default: break;
}
}
lastPadHoldDirection = padHoldDirection;
}
void djui_interactable_update(void) {
if (mouse_window_buttons & 0b0001) {
djui_interactable_update_pad();
if ((sInputCursorDown) || (mouse_window_buttons & 0b0001)) {
if (sHovered != NULL) {
sMouseDown = sHovered;
sHovered = NULL;
djui_interactable_on_mouse_down_begin(sMouseDown);
djui_interactable_on_cursor_down_begin(sMouseDown);
}
} else {
if (sMouseDown != NULL) {
djui_interactable_on_mouse_down_end(sMouseDown);
djui_interactable_on_cursor_down_end(sMouseDown);
sMouseDown = NULL;
}
struct DjuiBase* lastHovered = sHovered;
sHovered = NULL;
djui_interactable_mouse_update_active(&gDjuiRoot->base);
djui_interactable_cursor_update_active(&gDjuiRoot->base);
if (lastHovered != sHovered) {
djui_interactable_on_hover_end(lastHovered);
}
@ -114,8 +194,8 @@ void djui_interactable_update(void) {
void djui_interactable_create(struct DjuiBase* base,
void (*on_hover_begin)(struct DjuiBase*),
void (*on_hover_end)(struct DjuiBase*),
void (*on_mouse_down_begin)(struct DjuiBase*),
void (*on_mouse_down_end)(struct DjuiBase*)) {
void (*on_cursor_down_begin)(struct DjuiBase*),
void (*on_cursor_down_end)(struct DjuiBase*)) {
if (base->interactable != NULL) {
free(base->interactable);
@ -124,8 +204,8 @@ void djui_interactable_create(struct DjuiBase* base,
struct DjuiInteractable* interactable = malloc(sizeof(struct DjuiInteractable));
interactable->on_hover_begin = on_hover_begin;
interactable->on_hover_end = on_hover_end;
interactable->on_mouse_down_begin = on_mouse_down_begin;
interactable->on_mouse_down_end = on_mouse_down_end;
interactable->on_cursor_down_begin = on_cursor_down_begin;
interactable->on_cursor_down_end = on_cursor_down_end;
interactable->on_click = NULL;
base->interactable = interactable;

View file

@ -7,15 +7,17 @@ struct DjuiInteractable {
bool enabled;
void (*on_hover_begin)(struct DjuiBase*);
void (*on_hover_end)(struct DjuiBase*);
void (*on_mouse_down_begin)(struct DjuiBase*);
void (*on_mouse_down_end)(struct DjuiBase*);
void (*on_cursor_down_begin)(struct DjuiBase*);
void (*on_cursor_down_end)(struct DjuiBase*);
void (*on_click)(struct DjuiBase*);
};
void djui_interactable_on_key_down(int scancode);
void djui_interactable_on_key_up(int scancode);
void djui_interactable_update(void);
void djui_interactable_create(struct DjuiBase* base,
void (*on_hover_begin)(struct DjuiBase*),
void (*on_hover_end)(struct DjuiBase*),
void (*on_mouse_down_begin)(struct DjuiBase*),
void (*on_mouse_down_end)(struct DjuiBase*));
void (*on_cursor_down_begin)(struct DjuiBase*),
void (*on_cursor_down_end)(struct DjuiBase*));