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);