diff --git a/build-windows-visual-studio/sm64ex.vcxproj b/build-windows-visual-studio/sm64ex.vcxproj index 2ae16f34..da065894 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj +++ b/build-windows-visual-studio/sm64ex.vcxproj @@ -3944,6 +3944,8 @@ + + @@ -3951,7 +3953,9 @@ + + @@ -4376,6 +4380,8 @@ + + @@ -4384,7 +4390,9 @@ + + diff --git a/build-windows-visual-studio/sm64ex.vcxproj.filters b/build-windows-visual-studio/sm64ex.vcxproj.filters index 5093c66f..195deb5e 100644 --- a/build-windows-visual-studio/sm64ex.vcxproj.filters +++ b/build-windows-visual-studio/sm64ex.vcxproj.filters @@ -15222,6 +15222,18 @@ Source Files\src\pc\djui\component\compound + + Source Files\src\pc\djui\panel + + + Source Files\src\pc\djui\component\compound + + + Source Files\src\pc\djui\panel + + + Source Files\src\pc\djui\component\compound + @@ -16264,5 +16276,17 @@ Source Files\src\pc\djui\component\compound + + Source Files\src\pc\djui\panel + + + Source Files\src\pc\djui\component\compound + + + Source Files\src\pc\djui\panel + + + Source Files\src\pc\djui\component\compound + \ No newline at end of file diff --git a/src/pc/djui/djui.h b/src/pc/djui/djui.h index fb0db8f5..e5bcceb5 100644 --- a/src/pc/djui/djui.h +++ b/src/pc/djui/djui.h @@ -24,12 +24,14 @@ #include "djui_flow_layout.h" #include "djui_slider.h" #include "djui_checkbox.h" +#include "djui_selectionbox.h" #include "djui_panel.h" #include "djui_panel_debug.h" #include "djui_panel_main.h" #include "djui_panel_options.h" #include "djui_panel_camera.h" +#include "djui_panel_display.h" #include "djui_panel_sound.h" #include "djui_panel_quit.h" diff --git a/src/pc/djui/djui_button.c b/src/pc/djui/djui_button.c index 46c72a51..06fa120c 100644 --- a/src/pc/djui/djui_button.c +++ b/src/pc/djui/djui_button.c @@ -2,7 +2,7 @@ static void djui_button_set_default_style(struct DjuiBase* base) { struct DjuiButton* button = (struct DjuiButton*)base; - djui_base_set_border_color(base, 173, 173, 173, 255); + djui_base_set_border_color(base, 150, 150, 150, 255); djui_base_set_color(&button->rect->base, 200, 200, 200, 255); djui_base_set_location(&button->text->base, 0.0f, 0.0f); } @@ -11,7 +11,7 @@ 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); - djui_base_set_location(&button->text->base, -0.5f, -0.5f); + djui_base_set_location(&button->text->base, -0.5f, -1.0f); } static void djui_button_on_hover_end(struct DjuiBase* base) { diff --git a/src/pc/djui/djui_checkbox.c b/src/pc/djui/djui_checkbox.c index 27bb2472..6273c6f7 100644 --- a/src/pc/djui/djui_checkbox.c +++ b/src/pc/djui/djui_checkbox.c @@ -27,6 +27,9 @@ static void djui_checkbox_on_cursor_down_begin(struct DjuiBase* base, bool input djui_base_set_color(&checkbox->rectValue->base, 255, 255, 255, 255); *checkbox->value = !(*checkbox->value); djui_base_set_visible(&checkbox->rectValue->base, *checkbox->value); + if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) { + base->interactable->on_value_change(base); + } } static void djui_checkbox_on_cursor_down_end(struct DjuiBase* base) { @@ -75,8 +78,8 @@ struct DjuiCheckbox* djui_checkbox_create(struct DjuiBase* parent, const char* m checkbox->rect = rect; struct DjuiRect* rectValue = djui_rect_create(&rect->base); - djui_base_set_size_type(&rectValue->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); - djui_base_set_size(&rectValue->base, 0.8f, 0.8f); + djui_base_set_size_type(&rectValue->base, DJUI_SVT_ABSOLUTE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&rectValue->base, 16, 16); djui_base_set_alignment(&rectValue->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); djui_base_set_visible(&rectValue->base, *value); checkbox->rectValue = rectValue; diff --git a/src/pc/djui/djui_interactable.c b/src/pc/djui/djui_interactable.c index a7ef0913..ff48e22d 100644 --- a/src/pc/djui/djui_interactable.c +++ b/src/pc/djui/djui_interactable.c @@ -27,8 +27,8 @@ OSContPad gInteractablePad = { 0 }; OSContPad sLastInteractablePad = { 0 }; static void djui_interactable_on_click(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_click == NULL) { return; } base->interactable->on_click(base); } @@ -100,6 +100,13 @@ static void djui_interactable_on_focus_end(struct DjuiBase* base) { base->interactable->on_focus_end(base); } +static void djui_interactable_on_value_change(struct DjuiBase* base) { + if (base == NULL) { return; } + if (base->interactable == NULL) { return; } + if (base->interactable->on_value_change == NULL) { return; } + base->interactable->on_value_change(base); +} + static void djui_interactable_cursor_update_active(struct DjuiBase* base) { if (!base->visible) { return; } if (!base->enabled) { return; } @@ -277,6 +284,12 @@ void djui_interactable_hook_click(struct DjuiBase* base, interactable->on_click = on_click; } +void djui_interactable_hook_value_change(struct DjuiBase* base, + void (*on_value_change)(struct DjuiBase*)) { + struct DjuiInteractable* interactable = base->interactable; + interactable->on_value_change = on_value_change; +} + void djui_interactable_create(struct DjuiBase* base) { if (base->interactable != NULL) { diff --git a/src/pc/djui/djui_interactable.h b/src/pc/djui/djui_interactable.h index d08f9e31..734dc0bf 100644 --- a/src/pc/djui/djui_interactable.h +++ b/src/pc/djui/djui_interactable.h @@ -19,6 +19,7 @@ struct DjuiInteractable { void (*on_focus)(struct DjuiBase*, OSContPad*); void (*on_focus_end)(struct DjuiBase*); void (*on_click)(struct DjuiBase*); + void (*on_value_change)(struct DjuiBase*); }; extern bool gInteractableOverridePad; @@ -47,4 +48,7 @@ void djui_interactable_hook_focus(struct DjuiBase* base, void djui_interactable_hook_click(struct DjuiBase* base, void (*on_click)(struct DjuiBase*)); +void djui_interactable_hook_value_change(struct DjuiBase* base, + void (*on_value_change)(struct DjuiBase*)); + void djui_interactable_create(struct DjuiBase* base); diff --git a/src/pc/djui/djui_panel_display.c b/src/pc/djui/djui_panel_display.c new file mode 100644 index 00000000..af4ca7bd --- /dev/null +++ b/src/pc/djui/djui_panel_display.c @@ -0,0 +1,69 @@ +#include "djui.h" +#include "src/pc/utils/misc.h" +#include "src/pc/configfile.h" + +static void djui_panel_display_back(struct DjuiBase* base) { + djui_panel_back(); +} + +static void djui_panel_display_apply(struct DjuiBase* caller) { + configWindow.settings_changed = true; +} + +void djui_panel_display_create(struct DjuiBase* caller) { + f32 bodyHeight = 32 * 5 + 64 * 1 + 16 * 4; + + struct DjuiCheckbox* checkbox1 = 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); + djui_base_set_size(&panel->base, 340.0f + (16 * 2.0f), 1.0f); + djui_base_set_color(&panel->base, 0, 0, 0, 240); + djui_base_set_border_color(&panel->base, 0, 0, 0, 200); + djui_base_set_border_width(&panel->base, 8); + djui_base_set_padding(&panel->base, 16, 16, 16, 16); + { + struct DjuiText* header = djui_text_create(&panel->base, "\\#ff0800\\D\\#1be700\\I\\#00b3ff\\S\\#ffef00\\P\\#ff0800\\L\\#1be700\\A\\#00b3ff\\Y"); + djui_base_set_size_type(&header->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&header->base, 1.0f, 1.0f); + djui_base_set_color(&header->base, 255, 8, 0, 255); + djui_text_set_alignment(header, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_text_set_font(header, &gDjuiFonts[1]); + djui_text_set_font_scale(header, gDjuiFonts[1].defaultFontScale); + + struct DjuiFlowLayout* body = djui_flow_layout_create(&panel->base); + djui_base_set_alignment(&body->base, DJUI_HALIGN_CENTER, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&body->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&body->base, 1.0f, bodyHeight); + djui_base_set_color(&body->base, 0, 0, 0, 0); + djui_flow_layout_set_margin(body, 16); + djui_flow_layout_set_flow_direction(body, DJUI_FLOW_DIR_DOWN); + { + checkbox1 = djui_checkbox_create(&body->base, "Fullscreen", &configWindow.fullscreen); + djui_base_set_size_type(&checkbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&checkbox1->base, 1.0f, 32); + djui_interactable_hook_value_change(&checkbox1->base, djui_panel_display_apply); + + struct DjuiCheckbox* checkbox2 = djui_checkbox_create(&body->base, "VSync", &configWindow.vsync); + djui_base_set_size_type(&checkbox2->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&checkbox2->base, 1.0f, 32); + djui_interactable_hook_value_change(&checkbox2->base, djui_panel_display_apply); + + struct DjuiCheckbox* checkbox4 = djui_checkbox_create(&body->base, "HUD", &configHUD); + djui_base_set_size_type(&checkbox4->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&checkbox4->base, 1.0f, 32); + + char* choices[3] = { "Nearest", "Linear", "Tripoint" }; + struct DjuiSelectionbox* selectionbox1 = djui_selectionbox_create(&body->base, "Filtering", choices, 3, &configFiltering); + djui_base_set_size_type(&selectionbox1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); + djui_base_set_size(&selectionbox1->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); + djui_base_set_size(&button6->base, 1.0f, 64); + button6->base.interactable->on_click = djui_panel_display_back; + } + } + + djui_panel_add(caller, &panel->base, &checkbox1->base); +} diff --git a/src/pc/djui/djui_panel_display.h b/src/pc/djui/djui_panel_display.h new file mode 100644 index 00000000..e38d8cc1 --- /dev/null +++ b/src/pc/djui/djui_panel_display.h @@ -0,0 +1,4 @@ +#pragma once +#include "djui.h" + +void djui_panel_display_create(struct DjuiBase* caller); diff --git a/src/pc/djui/djui_panel_options.c b/src/pc/djui/djui_panel_options.c index c8a4503c..e269a943 100644 --- a/src/pc/djui/djui_panel_options.c +++ b/src/pc/djui/djui_panel_options.c @@ -50,6 +50,7 @@ void djui_panel_options_create(struct DjuiBase* caller) { 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); + button4->base.interactable->on_click = djui_panel_display_create; struct DjuiButton* button5 = djui_button_create(&body->base, "Sound"); djui_base_set_size_type(&button5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE); diff --git a/src/pc/djui/djui_selectionbox.c b/src/pc/djui/djui_selectionbox.c new file mode 100644 index 00000000..c0d7b5c8 --- /dev/null +++ b/src/pc/djui/djui_selectionbox.c @@ -0,0 +1,123 @@ +#include +#include +#include "djui.h" + +ALIGNED8 static u8 texture_selectionbox_icon[] = { +#include "textures/segment2/custom_selectionbox_icon.rgba16.inc.c" +}; + +static void djui_selectionbox_set_default_style(struct DjuiBase* base) { + struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; + djui_base_set_border_color(&selectionbox->rect->base, 150, 150, 150, 255); + djui_base_set_color(&selectionbox->rect->base, 200, 200, 200, 255); + djui_base_set_color(&selectionbox->rectText->base, 11, 11, 11, 255); + djui_base_set_location(&selectionbox->rectText->base, 0.0f, 3.0f); + djui_base_set_color(&selectionbox->rectImage->base, 0, 0, 0, 255); + djui_base_set_color(&selectionbox->text->base, 200, 200, 200, 255); +} + +static void djui_selectionbox_on_hover(struct DjuiBase* base) { + struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; + f32 x = selectionbox->rect->base.elem.x; + if (gCursorX >= x) { + djui_base_set_border_color(&selectionbox->rect->base, 0, 120, 215, 255); + djui_base_set_color(&selectionbox->rect->base, 229, 241, 251, 255); + djui_base_set_location(&selectionbox->rectText->base, -1.0f, 2.0f); + djui_base_set_color(&selectionbox->text->base, 229, 241, 251, 255); + } else { + djui_selectionbox_set_default_style(base); + } +} + +static void djui_selectionbox_on_hover_end(struct DjuiBase* base) { + djui_selectionbox_set_default_style(base); +} + +static void djui_selectionbox_on_cursor_down_begin(struct DjuiBase* base, bool inputCursor) { + struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; + f32 x = selectionbox->rect->base.elem.x; + if (gCursorX >= x) { + djui_base_set_border_color(&selectionbox->rect->base, 0, 84, 153, 255); + djui_base_set_color(&selectionbox->rect->base, 204, 228, 247, 255); + djui_base_set_location(&selectionbox->rectText->base, 0.5f, 3.5f); + djui_base_set_color(&selectionbox->text->base, 229, 241, 251, 255); + + *selectionbox->value = (*selectionbox->value + 1) % selectionbox->choiceCount; + djui_text_set_text(selectionbox->rectText, selectionbox->choices[*selectionbox->value]); + if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) { + base->interactable->on_value_change(base); + } + } + else { + djui_selectionbox_set_default_style(base); + } +} + +static void djui_selectionbox_on_cursor_down_end(struct DjuiBase* base) { + struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; + djui_selectionbox_set_default_style(base); +} + +static void djui_selectionbox_destroy(struct DjuiBase* base) { + struct DjuiSelectionbox* selectionbox = (struct DjuiSelectionbox*)base; + for (int i = 0; i < selectionbox->choiceCount; i++) { + free(selectionbox->choices[i]); + } + free(selectionbox->choices); + free(selectionbox); +} + +struct DjuiSelectionbox* djui_selectionbox_create(struct DjuiBase* parent, const char* message, char* choices[], u8 choiceCount, unsigned int* value) { + struct DjuiSelectionbox* selectionbox = malloc(sizeof(struct DjuiSelectionbox)); + struct DjuiBase* base = &selectionbox->base; + + selectionbox->value = value; + selectionbox->choices = malloc(sizeof(char*) * choiceCount); + for (int i = 0; i < choiceCount; i++) { + u32 length = strlen(choices[i]); + selectionbox->choices[i] = malloc(sizeof(char) * (length + 1)); + memset(selectionbox->choices[i], 0, sizeof(char) * (length + 1)); + sprintf(selectionbox->choices[i], "%s", choices[i]); + } + selectionbox->choiceCount = choiceCount; + + djui_base_init(parent, base, NULL, djui_selectionbox_destroy); + djui_interactable_create(base); + djui_interactable_hook_hover(base, djui_selectionbox_on_hover, djui_selectionbox_on_hover_end); + djui_interactable_hook_cursor_down(base, djui_selectionbox_on_cursor_down_begin, NULL, djui_selectionbox_on_cursor_down_end); + + struct DjuiText* text = djui_text_create(&selectionbox->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); + selectionbox->text = text; + + struct DjuiRect* rect = djui_rect_create(&selectionbox->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); + djui_base_set_padding(&rect->base, 2, 2, 0, 4); + selectionbox->rect = rect; + + struct DjuiText* rectText = djui_text_create(&rect->base, choices[*value]); + djui_base_set_alignment(&rectText->base, DJUI_HALIGN_LEFT, DJUI_VALIGN_CENTER); + djui_base_set_size_type(&rectText->base, DJUI_SVT_RELATIVE, DJUI_SVT_RELATIVE); + djui_base_set_size(&rectText->base, 1.0f, 1.0f); + djui_text_set_alignment(rectText, DJUI_HALIGN_LEFT, DJUI_VALIGN_BOTTOM); + djui_text_set_drop_shadow(rectText, 120, 120, 120, 64); + selectionbox->rectText = rectText; + + struct DjuiImage* rectImage = djui_image_create(&rect->base, texture_selectionbox_icon, 16, 16, 16); + djui_base_set_location(&rectImage->base, 0, 0); + djui_base_set_size(&rectImage->base, 16, 16); + djui_base_set_alignment(&rectImage->base, DJUI_HALIGN_RIGHT, DJUI_VALIGN_CENTER); + selectionbox->rectImage = rectImage; + + djui_selectionbox_set_default_style(base); + + return selectionbox; +} diff --git a/src/pc/djui/djui_selectionbox.h b/src/pc/djui/djui_selectionbox.h new file mode 100644 index 00000000..7a1e5193 --- /dev/null +++ b/src/pc/djui/djui_selectionbox.h @@ -0,0 +1,16 @@ +#pragma once +#include "djui.h" + +#pragma pack(1) +struct DjuiSelectionbox { + struct DjuiBase base; + struct DjuiText* text; + struct DjuiRect* rect; + struct DjuiText* rectText; + struct DjuiImage* rectImage; + unsigned int* value; + char** choices; + u8 choiceCount; +}; + +struct DjuiSelectionbox* djui_selectionbox_create(struct DjuiBase* parent, const char* message, char* choices[], u8 choiceCount, unsigned int* value); \ No newline at end of file diff --git a/src/pc/djui/djui_slider.c b/src/pc/djui/djui_slider.c index db3e5a60..5cd8b01b 100644 --- a/src/pc/djui/djui_slider.c +++ b/src/pc/djui/djui_slider.c @@ -43,6 +43,9 @@ static void djui_slider_on_cursor_down(struct DjuiBase* base) { cursorX = fmax(cursorX, x); cursorX = fmin(cursorX, x + w); *value = ((cursorX - x) / w) * (max - min) + min; + if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) { + base->interactable->on_value_change(base); + } djui_slider_update_value(base); } @@ -88,6 +91,9 @@ static void djui_slider_on_focus(struct DjuiBase* base, OSContPad* pad) { value = fmin(value, (int)slider->max); value = fmax(value, (int)slider->min); *slider->value = value; + if (base != NULL && base->interactable != NULL && base->interactable->on_value_change != NULL) { + base->interactable->on_value_change(base); + } djui_slider_update_value(base); } diff --git a/textures/segment2/custom_selectionbox_icon.rgba16.png b/textures/segment2/custom_selectionbox_icon.rgba16.png new file mode 100644 index 00000000..b2865296 Binary files /dev/null and b/textures/segment2/custom_selectionbox_icon.rgba16.png differ