diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj
index 78c070a1..2ae16f34 100644
--- a/build-windows-visual-studio/sm64ex.vcxproj
+++ b/build-windows-visual-studio/sm64ex.vcxproj
@@ -87,7 +87,7 @@
Level3
true
- _DEBUG;_CONSOLE;WINSOCK;DEBUG;CAPI_SDL2;WAPI_SDL2;RAPI_GL;F3DEX_GBI_2;_LANGUAGE_C;BETTERCAMERA;VERSION_US;%(PreprocessorDefinitions)
+ _DEBUG;_CONSOLE;WINSOCK;DEBUG;CAPI_SDL2;WAPI_SDL2;RAPI_GL;F3DEX_GBI_2;_LANGUAGE_C;BETTERCAMERA;VERSION_US;EXT_OPTIONS_MENU;%(PreprocessorDefinitions)
true
@@ -3958,6 +3958,7 @@
+
@@ -4390,6 +4391,7 @@
+
diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters
index d1fdb42f..5093c66f 100644
--- a/build-windows-visual-studio/sm64ex.vcxproj.filters
+++ b/build-windows-visual-studio/sm64ex.vcxproj.filters
@@ -15219,6 +15219,9 @@
Source Files\src\pc\djui\panel
+
+ Source Files\src\pc\djui\component\compound
+
@@ -16258,5 +16261,8 @@
Source Files\src\pc\djui\panel
+
+ Source Files\src\pc\djui\component\compound
+
\ No newline at end of file
diff --git a/src/game/game_init.c b/src/game/game_init.c
index 8f518ad4..067e7318 100644
--- a/src/game/game_init.c
+++ b/src/game/game_init.c
@@ -21,6 +21,7 @@
#include "segment_symbols.h"
#include "thread6.h"
#include "rng_position.h"
+#include "src/pc/djui/djui.h"
#include
#ifdef BETTERCAMERA
#include "bettercamera.h"
@@ -463,7 +464,7 @@ void read_controller_inputs(void) {
// controller information.
if (gControllerBits) {
osRecvMesg(&gSIEventMesgQueue, &D_80339BEC, OS_MESG_BLOCK);
- osContGetReadData(&gControllerPads[0]);
+ osContGetReadData(gInteractableOverridePad ? &gInteractablePad : &gControllerPads[0]);
}
run_demo_inputs();
diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h
index 6b90b747..2c49cf10 100644
--- a/src/pc/djui/djui.h
+++ b/src/pc/djui/djui.h
@@ -22,6 +22,7 @@
#include "djui_button.h"
#include "djui_flow_layout.h"
+#include "djui_slider.h"
#include "djui_panel.h"
#include "djui_panel_debug.h"
diff --git a/src/pc/djui/djui_button.c b/src/pc/djui/djui_button.c
index 1f02bd77..46c72a51 100644
--- a/src/pc/djui/djui_button.c
+++ b/src/pc/djui/djui_button.c
@@ -7,7 +7,7 @@ static void djui_button_set_default_style(struct DjuiBase* base) {
djui_base_set_location(&button->text->base, 0.0f, 0.0f);
}
-static void djui_button_on_hover_begin(struct DjuiBase* base) {
+static void djui_button_on_hover(struct DjuiBase* base) {
struct DjuiButton* button = (struct DjuiButton*)base;
djui_base_set_border_color(base, 0, 120, 215, 255);
djui_base_set_color(&button->rect->base, 229, 241, 251, 255);
@@ -18,7 +18,7 @@ static void djui_button_on_hover_end(struct DjuiBase* base) {
djui_button_set_default_style(base);
}
-static void djui_button_on_cursor_down_begin(struct DjuiBase* base) {
+static void djui_button_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) {
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);
@@ -41,11 +41,9 @@ struct DjuiButton* djui_button_create(struct DjuiBase* parent, const char* messa
djui_base_init(parent, base, NULL, djui_button_destroy);
djui_base_set_size(base, 200, 64);
djui_base_set_border_width(base, 2);
- djui_interactable_create(base,
- djui_button_on_hover_begin,
- djui_button_on_hover_end,
- djui_button_on_cursor_down_begin,
- djui_button_on_cursor_down_end);
+ djui_interactable_create(base);
+ djui_interactable_hook_hover(base, djui_button_on_hover, djui_button_on_hover_end);
+ djui_interactable_hook_cursor_down(base, djui_button_on_cursor_down_begin, NULL, 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);
diff --git a/src/pc/djui/djui_cursor.c b/src/pc/djui/djui_cursor.c
index fb6d6057..9b959f4f 100644
--- a/src/pc/djui/djui_cursor.c
+++ b/src/pc/djui/djui_cursor.c
@@ -18,15 +18,19 @@ static struct DjuiBase* sInputControlledBase = NULL;
static f32 sSavedMouseX = 0;
static f32 sSavedMouseY = 0;
-static f32 sCursorX = 0;
-static f32 sCursorY = 0;
+f32 gCursorX = 0;
+f32 gCursorY = 0;
+
+void djui_cursor_set_visible(bool visible) {
+ djui_base_set_visible(&sMouseCursor->base, visible);
+}
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; }
+ if (gCursorX < clip->x) { return false; }
+ if (gCursorX > clip->x + clip->width) { return false; }
+ if (gCursorY < clip->y) { return false; }
+ if (gCursorY > clip->y + clip->height) { return false; }
return true;
}
@@ -49,8 +53,8 @@ void djui_cursor_input_controlled_center(struct DjuiBase* base) {
static f32 djui_cursor_base_distance(struct DjuiBase* base) {
f32 x, y;
djui_cursor_base_hover_location(base, &x, &y);
- x -= sCursorX;
- y -= sCursorY;
+ x -= gCursorX;
+ y -= gCursorY;
return sqrtf((x * x) + (y * y));
}
@@ -62,10 +66,10 @@ static void djui_cursor_move_check(s8 xDir, s8 yDir, struct DjuiBase** pick, str
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 (xDir > 0 && gCursorX >= xH) { valid = false; }
+ if (xDir < 0 && gCursorX <= xH) { valid = false; }
+ if (yDir > 0 && gCursorY >= yH) { valid = false; }
+ if (yDir < 0 && gCursorY <= yH) { valid = false; }
if (valid) {
if (*pick == NULL) {
*pick = base;
@@ -102,27 +106,31 @@ void djui_cursor_update(void) {
#if defined(CAPI_SDL2) || defined(CAPI_SDL1)
controller_sdl_read_mouse_window();
- // adjust mouse cursor
- if (sCursorMouseControlled) {
- sCursorX = mouse_window_x;
- sCursorY = mouse_window_y;
- } else {
- if (sInputControlledBase != NULL) {
- djui_cursor_base_hover_location(sInputControlledBase, &sCursorX, &sCursorY);
- }
+ // check if mouse is in control again
+ if (!sCursorMouseControlled) {
f32 dist = sqrtf(powf(mouse_window_x - sSavedMouseX, 2) + powf(mouse_window_y - sSavedMouseY, 2));
if (dist > 5) {
sCursorMouseControlled = true;
+ djui_interactable_set_input_focus(NULL);
djui_base_set_visible(&sMouseCursor->base, true);
}
}
- djui_base_set_location(&sMouseCursor->base, sCursorX - 13, sCursorY - 13);
+ // update mouse cursor
+ if (sCursorMouseControlled) {
+ gCursorX = mouse_window_x;
+ gCursorY = mouse_window_y;
+ } else if (sInputControlledBase != NULL) {
+ djui_cursor_base_hover_location(sInputControlledBase, &gCursorX, &gCursorY);
+ }
+ // set cursor position
+ djui_base_set_location(&sMouseCursor->base, gCursorX - 13, gCursorY - 13);
+
+ // set cursor sprite
if (mouse_window_buttons & 0b0001) {
djui_image_set_image(sMouseCursor, texture_hand_closed, 32, 32, 16);
- }
- else {
+ } else {
djui_image_set_image(sMouseCursor, texture_hand_open, 32, 32, 16);
}
#endif
diff --git a/src/pc/djui/djui_cursor.h b/src/pc/djui/djui_cursor.h
index 6b902499..570ac226 100644
--- a/src/pc/djui/djui_cursor.h
+++ b/src/pc/djui/djui_cursor.h
@@ -2,6 +2,10 @@
#include "djui.h"
#include "djui_base.h"
+extern f32 gCursorX;
+extern f32 gCursorY;
+
+void djui_cursor_set_visible(bool visible);
bool djui_cursor_inside_base(struct DjuiBase* base);
void djui_cursor_input_controlled_center(struct DjuiBase* base);
void djui_cursor_move(s8 xDir, s8 yDir);
diff --git a/src/pc/djui/djui_interactable.c b/src/pc/djui/djui_interactable.c
index 780ca7ae..4cfd7408 100644
--- a/src/pc/djui/djui_interactable.c
+++ b/src/pc/djui/djui_interactable.c
@@ -6,7 +6,10 @@
#include "src/pc/controller/controller_mouse.h"
#include "src/pc/controller/controller_keyboard.h"
-#define PAD_BUTTON_A (1 << 15)
+#define PAD_BUTTON_A ((u16)(1 << 15))
+#define PAD_BUTTON_B ((u16)(1 << 14))
+
+#define MOUSE_BUTTON_1 ((u16)(1 << 0))
#define SCANCODE_UP 328
#define SCANCODE_DOWN 336
@@ -19,10 +22,14 @@
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 u16 sKeyboardButtons = 0;
-static struct DjuiBase* sHovered = NULL;
-static struct DjuiBase* sMouseDown = NULL;
-static u8 sInputCursorDown = false;
+static struct DjuiBase* sInteractableFocus = NULL;
+static struct DjuiBase* sHovered = NULL;
+static struct DjuiBase* sMouseDown = NULL;
+bool gInteractableOverridePad = false;
+OSContPad gInteractablePad = { 0 };
+OSContPad sLastInteractablePad = { 0 };
static void djui_interactable_on_click(struct DjuiBase* base) {
if (base == NULL) { return; }
@@ -31,23 +38,23 @@ static void djui_interactable_on_click(struct DjuiBase* base) {
base->interactable->on_click(base);
}
-static void djui_interactable_on_hover_begin(struct DjuiBase* base) {
+static void djui_interactable_on_hover(struct DjuiBase* base) {
if (base == NULL) { return; }
if (base->interactable == NULL) { return; }
- if (base->interactable->on_hover_begin == NULL) { return; }
- base->interactable->on_hover_begin(base);
+ if (base->interactable->on_hover == NULL) { return; }
+ base->interactable->on_hover(base);
}
static void djui_interactable_on_hover_end(struct DjuiBase* base) {
- if (base == NULL) { return; }
- if (base->interactable == NULL) { return; }
- if (base->interactable->on_hover_begin == NULL) { return; }
+ if (base == NULL) { return; }
+ if (base->interactable == NULL) { return; }
+ if (base->interactable->on_hover == NULL) { return; }
base->interactable->on_hover_end(base);
}
-static void djui_interactable_on_cursor_down_begin(struct DjuiBase* base) {
- if (base == NULL) { return; }
- if (base->interactable == NULL) { return; }
+static void djui_interactable_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) {
+ if (base == NULL) { return; }
+ if (base->interactable == NULL) { return; }
if (base->interactable->on_cursor_down_begin == NULL) { return; }
if (sHovered != NULL) {
@@ -55,12 +62,20 @@ static void djui_interactable_on_cursor_down_begin(struct DjuiBase* base) {
sHovered = NULL;
}
- base->interactable->on_cursor_down_begin(base);
+ base->interactable->on_cursor_down_begin(base, inputCursor);
+}
+
+static void djui_interactable_on_cursor_down(struct DjuiBase* base) {
+ if (base == NULL) { return; }
+ if (base->interactable == NULL) { return; }
+ if (base->interactable->on_cursor_down == NULL) { return; }
+
+ base->interactable->on_cursor_down(base);
}
static void djui_interactable_on_cursor_down_end(struct DjuiBase* base) {
- if (base == NULL) { return; }
- if (base->interactable == NULL) { return; }
+ if (base == NULL) { return; }
+ if (base->interactable == NULL) { return; }
if (base->interactable->on_cursor_down_end == NULL) { return; }
base->interactable->on_cursor_down_end(base);
@@ -69,6 +84,27 @@ static void djui_interactable_on_cursor_down_end(struct DjuiBase* base) {
}
}
+static void djui_interactable_on_focus_begin(struct DjuiBase* base) {
+ if (base == NULL) { return; }
+ if (base->interactable == NULL) { return; }
+ if (base->interactable->on_focus_begin == NULL) { return; }
+ base->interactable->on_focus_begin(base);
+}
+
+static void djui_interactable_on_focus(struct DjuiBase* base) {
+ if (base == NULL) { return; }
+ if (base->interactable == NULL) { return; }
+ if (base->interactable->on_focus == NULL) { return; }
+ base->interactable->on_focus(base, &gInteractablePad);
+}
+
+static void djui_interactable_on_focus_end(struct DjuiBase* base) {
+ if (base == NULL) { return; }
+ if (base->interactable == NULL) { return; }
+ if (base->interactable->on_focus_end == NULL) { return; }
+ base->interactable->on_focus_end(base);
+}
+
static void djui_interactable_cursor_update_active(struct DjuiBase* base) {
if (!base->visible) { return; }
if (!base->enabled) { return; }
@@ -96,42 +132,52 @@ static void djui_interactable_cursor_update_active(struct DjuiBase* base) {
}
}
+void djui_interactable_set_input_focus(struct DjuiBase* base) {
+ djui_interactable_on_focus_end(base);
+ sInteractableFocus = base;
+ djui_interactable_on_focus_begin(base);
+ djui_cursor_set_visible(base == NULL);
+}
+
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;
+ case SCANCODE_ENTER: sKeyboardButtons |= PAD_BUTTON_A; break;
}
}
void djui_interactable_on_key_up(int scancode) {
+ OSContPad* pad = &gInteractablePad;
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);
+ case SCANCODE_UP: if (sKeyboardHoldDirection == PAD_HOLD_DIR_UP) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
+ case SCANCODE_DOWN: if (sKeyboardHoldDirection == PAD_HOLD_DIR_DOWN) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_y = 0; } break;
+ case SCANCODE_LEFT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_LEFT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_x = 0; } break;
+ case SCANCODE_RIGHT: if (sKeyboardHoldDirection == PAD_HOLD_DIR_RIGHT) { sKeyboardHoldDirection = PAD_HOLD_DIR_NONE; pad->stick_x = 0; } break;
+ case SCANCODE_ENTER: sKeyboardButtons &= ~PAD_BUTTON_A; break;
}
}
void djui_interactable_update_pad(void) {
- OSContPad* pad = &gControllerPads[0];
+ OSContPad* pad = &gInteractablePad;
- sInputCursorDown &= ~(1 << 1);
- if (pad->button & PAD_BUTTON_A) {
- sInputCursorDown |= (1 << 1);
- }
+ pad->button |= sKeyboardButtons;
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) {
+ enum PadHoldDirection padHoldDirection = sKeyboardHoldDirection;
+ if (padHoldDirection != PAD_HOLD_DIR_NONE) {
+ switch (padHoldDirection) {
+ case PAD_HOLD_DIR_UP: pad->stick_x = 0; pad->stick_y = -64; break;
+ case PAD_HOLD_DIR_DOWN: pad->stick_x = 0; pad->stick_y = 64; break;
+ case PAD_HOLD_DIR_LEFT: pad->stick_x = -64; pad->stick_y = 0; break;
+ case PAD_HOLD_DIR_RIGHT: pad->stick_x = 64; pad->stick_y = 0; break;
+ default: break;
+ }
+ } else 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;
@@ -139,10 +185,6 @@ void djui_interactable_update_pad(void) {
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
@@ -154,7 +196,7 @@ void djui_interactable_update_pad(void) {
validPadHold = true;
}
- if (validPadHold) {
+ if (validPadHold && sInteractableFocus == NULL) {
switch (padHoldDirection) {
case PAD_HOLD_DIR_UP: djui_cursor_move( 0, -1); break;
case PAD_HOLD_DIR_DOWN: djui_cursor_move( 0, 1); break;
@@ -168,14 +210,28 @@ void djui_interactable_update_pad(void) {
}
void djui_interactable_update(void) {
+ // update pad
djui_interactable_update_pad();
- if ((sInputCursorDown) || (mouse_window_buttons & 0b0001)) {
+
+ if (sInteractableFocus != NULL) {
+ // escape focus
+ u16 buttons = PAD_BUTTON_A | PAD_BUTTON_B;
+ if ((gInteractablePad.button & buttons) && !(sLastInteractablePad.button & buttons)) {
+ djui_interactable_set_input_focus(NULL);
+ } else {
+ djui_interactable_on_focus(sInteractableFocus);
+ }
+ } else if ((gInteractablePad.button & PAD_BUTTON_A) || (mouse_window_buttons & MOUSE_BUTTON_1)) {
+ // cursor down events
if (sHovered != NULL) {
sMouseDown = sHovered;
sHovered = NULL;
- djui_interactable_on_cursor_down_begin(sMouseDown);
+ djui_interactable_on_cursor_down_begin(sMouseDown, !mouse_window_buttons);
+ } else {
+ djui_interactable_on_cursor_down(sMouseDown);
}
} else {
+ // cursor up event
if (sMouseDown != NULL) {
djui_interactable_on_cursor_down_end(sMouseDown);
sMouseDown = NULL;
@@ -186,27 +242,53 @@ void djui_interactable_update(void) {
if (lastHovered != sHovered) {
djui_interactable_on_hover_end(lastHovered);
}
- djui_interactable_on_hover_begin(sHovered);
+ djui_interactable_on_hover(sHovered);
}
+ sLastInteractablePad = gInteractablePad;
}
-void djui_interactable_create(struct DjuiBase* base,
- void (*on_hover_begin)(struct DjuiBase*),
- void (*on_hover_end)(struct DjuiBase*),
- void (*on_cursor_down_begin)(struct DjuiBase*),
- void (*on_cursor_down_end)(struct DjuiBase*)) {
+void djui_interactable_hook_hover(struct DjuiBase* base,
+ void (*on_hover)(struct DjuiBase*),
+ void (*on_hover_end)(struct DjuiBase*)) {
+ struct DjuiInteractable* interactable = base->interactable;
+ interactable->on_hover = on_hover;
+ interactable->on_hover_end = on_hover_end;
+}
+
+void djui_interactable_hook_cursor_down(struct DjuiBase* base,
+ void (*on_cursor_down_begin)(struct DjuiBase*, bool),
+ void (*on_cursor_down)(struct DjuiBase*),
+ void (*on_cursor_down_end)(struct DjuiBase*)) {
+ struct DjuiInteractable* interactable = base->interactable;
+ interactable->on_cursor_down_begin = on_cursor_down_begin;
+ interactable->on_cursor_down = on_cursor_down;
+ interactable->on_cursor_down_end = on_cursor_down_end;
+}
+
+void djui_interactable_hook_focus(struct DjuiBase* base,
+ void (*on_focus_begin)(struct DjuiBase*),
+ void (*on_focus)(struct DjuiBase*, OSContPad*),
+ void (*on_focus_end)(struct DjuiBase*)) {
+ struct DjuiInteractable* interactable = base->interactable;
+ interactable->on_focus_begin = on_focus_begin;
+ interactable->on_focus = on_focus;
+ interactable->on_focus_end = on_focus_end;
+}
+
+void djui_interactable_hook_click(struct DjuiBase* base,
+ void (*on_click)(struct DjuiBase*)) {
+ struct DjuiInteractable* interactable = base->interactable;
+ interactable->on_click = on_click;
+}
+
+void djui_interactable_create(struct DjuiBase* base) {
if (base->interactable != NULL) {
free(base->interactable);
}
struct DjuiInteractable* interactable = malloc(sizeof(struct DjuiInteractable));
- interactable->on_hover_begin = on_hover_begin;
- interactable->on_hover_end = on_hover_end;
- interactable->on_cursor_down_begin = on_cursor_down_begin;
- interactable->on_cursor_down_end = on_cursor_down_end;
- interactable->on_click = NULL;
-
+ memset(interactable, 0, sizeof(struct DjuiInteractable));
base->interactable = interactable;
-}
\ No newline at end of file
+}
diff --git a/src/pc/djui/djui_interactable.h b/src/pc/djui/djui_interactable.h
index c5448f76..19e04bde 100644
--- a/src/pc/djui/djui_interactable.h
+++ b/src/pc/djui/djui_interactable.h
@@ -5,19 +5,41 @@
#pragma pack(1)
struct DjuiInteractable {
bool enabled;
- void (*on_hover_begin)(struct DjuiBase*);
+ void (*on_hover)(struct DjuiBase*);
void (*on_hover_end)(struct DjuiBase*);
- void (*on_cursor_down_begin)(struct DjuiBase*);
+ void (*on_cursor_down_begin)(struct DjuiBase*, bool);
+ void (*on_cursor_down)(struct DjuiBase*);
void (*on_cursor_down_end)(struct DjuiBase*);
+ void (*on_focus_begin)(struct DjuiBase*);
+ void (*on_focus)(struct DjuiBase*, OSContPad*);
+ void (*on_focus_end)(struct DjuiBase*);
void (*on_click)(struct DjuiBase*);
};
+extern bool gInteractableOverridePad;
+extern OSContPad gInteractablePad;
+
+void djui_interactable_set_input_focus(struct DjuiBase* base);
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_cursor_down_begin)(struct DjuiBase*),
- void (*on_cursor_down_end)(struct DjuiBase*));
+
+void djui_interactable_hook_hover(struct DjuiBase* base,
+ void (*on_hover)(struct DjuiBase*),
+ void (*on_hover_end)(struct DjuiBase*));
+
+void djui_interactable_hook_cursor_down(struct DjuiBase* base,
+ void (*on_cursor_down_begin)(struct DjuiBase*, bool),
+ void (*on_cursor_down)(struct DjuiBase*),
+ void (*on_cursor_down_end)(struct DjuiBase*));
+
+void djui_interactable_hook_focus(struct DjuiBase* base,
+ void (*on_focus_begin)(struct DjuiBase*),
+ void (*on_focus)(struct DjuiBase*, OSContPad*),
+ void (*on_focus_end)(struct DjuiBase*));
+
+void djui_interactable_hook_click(struct DjuiBase* base,
+ void (*on_click)(struct DjuiBase*));
+
+void djui_interactable_create(struct DjuiBase* base);
diff --git a/src/pc/djui/djui_panel_main.c b/src/pc/djui/djui_panel_main.c
index bd959efe..2dec533f 100644
--- a/src/pc/djui/djui_panel_main.c
+++ b/src/pc/djui/djui_panel_main.c
@@ -1,4 +1,5 @@
#include "djui.h"
+#include "src/pc/controller/controller_sdl.h"
void djui_panel_main_create(struct DjuiBase* caller) {
f32 bodyHeight = 64 * 4 + 16 * 3;
@@ -46,7 +47,8 @@ void djui_panel_main_create(struct DjuiBase* caller) {
button4->base.interactable->on_click = djui_panel_quit_create;
}
- struct DjuiText* footer = djui_text_create(&panel->base, "version - unst 5");
+ char* version = get_version();
+ struct DjuiText* footer = djui_text_create(&panel->base, version);
djui_base_set_size_type(&footer->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&footer->base, 1.0f, 1.0f);
djui_base_set_color(&footer->base, 50, 50, 50, 255);
@@ -54,4 +56,5 @@ void djui_panel_main_create(struct DjuiBase* caller) {
}
djui_panel_add(caller, &panel->base, &buttonHost->base);
+ gInteractableOverridePad = true;
}
diff --git a/src/pc/djui/djui_panel_sound.c b/src/pc/djui/djui_panel_sound.c
index 8f99ecbd..36bc7969 100644
--- a/src/pc/djui/djui_panel_sound.c
+++ b/src/pc/djui/djui_panel_sound.c
@@ -1,14 +1,15 @@
#include "djui.h"
#include "src/pc/utils/misc.h"
+#include "src/pc/configfile.h"
static void djui_panel_sound_back(struct DjuiBase* base) {
djui_panel_back();
}
void djui_panel_sound_create(struct DjuiBase* caller) {
- f32 bodyHeight = 64 * 6 + 16 * 5;
+ f32 bodyHeight = 32 * 4 + 64 * 1 + 16 * 4;
- struct DjuiButton* button1 = NULL;
+ struct DjuiSlider* slider1 = NULL;
struct DjuiThreePanel* panel = djui_three_panel_create(&gDjuiRoot->base, 64, bodyHeight, 0);
djui_base_set_size_type(&panel->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_RELATIVE);
@@ -34,25 +35,21 @@ void djui_panel_sound_create(struct DjuiBase* caller) {
djui_flow_layout_set_margin(body, 16);
djui_flow_layout_set_flow_direction(body, DJUI_FLOW_DIR_DOWN);
{
- button1 = djui_button_create(&body->base, "Player");
- djui_base_set_size_type(&button1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
- djui_base_set_size(&button1->base, 1.0f, 64);
+ slider1 = djui_slider_create(&body->base, "Master Volume", &configMasterVolume, 0, 127);
+ djui_base_set_size_type(&slider1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&slider1->base, 1.0f, 32);
- struct DjuiButton* button2 = djui_button_create(&body->base, "Camera");
- djui_base_set_size_type(&button2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
- djui_base_set_size(&button2->base, 1.0f, 64);
+ struct DjuiSlider* slider2 = djui_slider_create(&body->base, "Music Volume", &configMusicVolume, 0, 127);
+ djui_base_set_size_type(&slider2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&slider2->base, 1.0f, 32);
- struct DjuiButton* button3 = djui_button_create(&body->base, "Controls");
- djui_base_set_size_type(&button3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
- djui_base_set_size(&button3->base, 1.0f, 64);
+ struct DjuiSlider* slider3 = djui_slider_create(&body->base, "Sfx Volume", &configSfxVolume, 0, 127);
+ djui_base_set_size_type(&slider3->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&slider3->base, 1.0f, 32);
- struct DjuiButton* button4 = djui_button_create(&body->base, "Display");
- djui_base_set_size_type(&button4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
- djui_base_set_size(&button4->base, 1.0f, 64);
-
- struct DjuiButton* button5 = djui_button_create(&body->base, "Sound");
- djui_base_set_size_type(&button5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
- djui_base_set_size(&button5->base, 1.0f, 64);
+ struct DjuiSlider* slider4 = djui_slider_create(&body->base, "Env Volume", &configEnvVolume, 0, 127);
+ djui_base_set_size_type(&slider4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
+ djui_base_set_size(&slider4->base, 1.0f, 32);
struct DjuiButton* button6 = djui_button_create(&body->base, "Back");
djui_base_set_size_type(&button6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
@@ -61,5 +58,5 @@ void djui_panel_sound_create(struct DjuiBase* caller) {
}
}
- djui_panel_add(caller, &panel->base, &button1->base);
+ djui_panel_add(caller, &panel->base, &slider1->base);
}
diff --git a/src/pc/djui/djui_slider.c b/src/pc/djui/djui_slider.c
new file mode 100644
index 00000000..db3e5a60
--- /dev/null
+++ b/src/pc/djui/djui_slider.c
@@ -0,0 +1,141 @@
+#include "djui.h"
+
+static void djui_slider_update_value(struct DjuiBase* base) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ u32 min = slider->min;
+ u32 max = slider->max;
+ u32* value = slider->value;
+ djui_base_set_size(&slider->rectValue->base, ((f32)*value - min) / ((f32)max - min), 1.0f);
+}
+
+static void djui_slider_set_default_style(struct DjuiBase* base) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ djui_base_set_border_color(&slider->rect->base, 173, 173, 173, 255);
+ djui_base_set_color(&slider->rect->base, 0, 0, 0, 0);
+ djui_base_set_color(&slider->text->base, 200, 200, 200, 255);
+ djui_base_set_color(&slider->rectValue->base, 200, 200, 200, 255);
+}
+
+static void djui_slider_on_hover(struct DjuiBase* base) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ f32 x = slider->rect->base.elem.x;
+ if (gCursorX >= x) {
+ djui_base_set_border_color(&slider->rect->base, 0, 120, 215, 255);
+ djui_base_set_color(&slider->text->base, 229, 241, 251, 255);
+ djui_base_set_color(&slider->rectValue->base, 229, 241, 251, 255);
+ } else {
+ djui_slider_set_default_style(base);
+ }
+}
+
+static void djui_slider_on_hover_end(struct DjuiBase* base) {
+ djui_slider_set_default_style(base);
+}
+
+static void djui_slider_on_cursor_down(struct DjuiBase* base) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ u32 min = slider->min;
+ u32 max = slider->max;
+ u32* value = slider->value;
+ f32 x = slider->rect->base.elem.x;
+ f32 w = slider->rect->base.elem.width;
+ f32 cursorX = gCursorX;
+ cursorX = fmax(cursorX, x);
+ cursorX = fmin(cursorX, x + w);
+ *value = ((cursorX - x) / w) * (max - min) + min;
+ djui_slider_update_value(base);
+}
+
+static void djui_slider_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ f32 x = slider->rect->base.elem.x;
+ if (gCursorX >= x) {
+ djui_base_set_border_color(&slider->rect->base, 20, 170, 255, 255);
+ djui_base_set_color(&slider->rect->base, 255, 255, 255, 32);
+ djui_base_set_color(&slider->text->base, 229, 241, 251, 255);
+ djui_base_set_color(&slider->rectValue->base, 255, 255, 255, 255);
+ if (inputCursor) {
+ djui_interactable_set_input_focus(base);
+ } else {
+ slider->base.interactable->on_cursor_down = djui_slider_on_cursor_down;
+ }
+ }
+ else {
+ djui_slider_set_default_style(base);
+ slider->base.interactable->on_cursor_down = NULL;
+ }
+}
+
+static void djui_slider_on_cursor_down_end(struct DjuiBase* base) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ slider->base.interactable->on_cursor_down = NULL;
+ djui_slider_set_default_style(base);
+}
+
+static void djui_slider_on_focus_begin(struct DjuiBase* base) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ djui_base_set_border_color(&slider->rect->base, 20, 170, 255, 255);
+ djui_base_set_color(&slider->rect->base, 255, 255, 255, 32);
+ djui_base_set_color(&slider->text->base, 229, 241, 251, 255);
+ djui_base_set_color(&slider->rectValue->base, 255, 255, 255, 255);
+}
+
+static void djui_slider_on_focus(struct DjuiBase* base, OSContPad* pad) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ if (abs(pad->stick_x) < 32) { return; }
+ int value = *slider->value;
+ value += (pad->stick_x > 0) ? 1 : -1;
+ value = fmin(value, (int)slider->max);
+ value = fmax(value, (int)slider->min);
+ *slider->value = value;
+ djui_slider_update_value(base);
+}
+
+static void djui_slider_on_focus_end(struct DjuiBase* base) {
+ djui_slider_set_default_style(base);
+}
+
+static void djui_slider_destroy(struct DjuiBase* base) {
+ struct DjuiSlider* slider = (struct DjuiSlider*)base;
+ free(slider);
+}
+
+struct DjuiSlider* djui_slider_create(struct DjuiBase* parent, const char* message, unsigned int* value, unsigned int min, unsigned int max) {
+ struct DjuiSlider* slider = malloc(sizeof(struct DjuiSlider));
+ struct DjuiBase* base = &slider->base;
+
+ slider->value = value;
+ slider->min = min;
+ slider->max = max;
+
+ djui_base_init(parent, base, NULL, djui_slider_destroy);
+ djui_interactable_create(base);
+ djui_interactable_hook_hover(base, djui_slider_on_hover, djui_slider_on_hover_end);
+ djui_interactable_hook_cursor_down(base, djui_slider_on_cursor_down_begin, NULL, djui_slider_on_cursor_down_end);
+ djui_interactable_hook_focus(base, djui_slider_on_focus_begin, djui_slider_on_focus, djui_slider_on_focus_end);
+
+ struct DjuiText* text = djui_text_create(&slider->base, message);
+ djui_base_set_alignment(&text->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_CENTER);
+ djui_base_set_size_type(&text->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
+ djui_base_set_size(&text->base, 0.5f, 1.0f);
+ djui_text_set_alignment(text, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM);
+ djui_text_set_drop_shadow(text, 120, 120, 120, 64);
+ slider->text = text;
+
+ struct DjuiRect* rect = djui_rect_create(&slider->base);
+ djui_base_set_alignment(&rect->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_CENTER);
+ djui_base_set_size_type(&rect->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
+ djui_base_set_size(&rect->base, 0.5f, 1.0f);
+ djui_base_set_color(&rect->base, 0, 0, 0, 0);
+ djui_base_set_border_width(&rect->base, 2);
+ slider->rect = rect;
+
+ struct DjuiRect* rectValue = djui_rect_create(&rect->base);
+ djui_base_set_size_type(&rectValue->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE);
+ slider->rectValue = rectValue;
+
+ djui_slider_update_value(base);
+ djui_slider_set_default_style(base);
+
+ return slider;
+}
diff --git a/src/pc/djui/djui_slider.h b/src/pc/djui/djui_slider.h
new file mode 100644
index 00000000..8ccc5fb5
--- /dev/null
+++ b/src/pc/djui/djui_slider.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "djui.h"
+
+#pragma pack(1)
+struct DjuiSlider {
+ struct DjuiBase base;
+ struct DjuiRect* rect;
+ struct DjuiRect* rectValue;
+ struct DjuiText* text;
+ unsigned int* value;
+ unsigned int min;
+ unsigned int max;
+};
+
+struct DjuiSlider* djui_slider_create(struct DjuiBase* parent, const char* message, unsigned int* value, unsigned int min, unsigned int max);