From aac982a3eb72012c37a2e4ff85130ad07eb7cf00 Mon Sep 17 00:00:00 2001 From: Cooliokid956 <68075390+Cooliokid956@users.noreply.github.com> Date: Thu, 22 May 2025 07:26:29 -0500 Subject: [PATCH] Add missing mouse scrolling in console + Smooth Scrolling (#790) * Add mouse wheel scrolling for DJUI Console forgot to do that before Bonus: optional Smooth Scrolling (activate in menu options) Dutch - @benjipg English - me French - @Blockyyy German - @iZePlayzYT Italian - @wall_e20 Russian - @yoyeet961 Spanish - me Missing translations: Czech-Help Japanese-uhhhh Polish-maybe Portuguese- might be able to get this one in tomorrow i really think something needs to be done about the DJUI prefixing * Return of the eepy - actually added the config option - NEW TRANSLATION: - portuguese - @saniky * Czech translation by @Dominicentek * add missing translations, correct others since this is an actual feature present in major programs (e.g. Chromium), it is widely localized and i can find accepted translations for the term I have gone and used those instead where applicable * address nitpicking * unified clamping * new clamp + fixed chat jumping to 0 when below max --- lang/Czech.ini | 1 + lang/Dutch.ini | 1 + lang/English.ini | 1 + lang/French.ini | 1 + lang/German.ini | 1 + lang/Italian.ini | 1 + lang/Japanese.ini | 1 + lang/Polish.ini | 1 + lang/Portuguese.ini | 1 + lang/Russian.ini | 1 + lang/Spanish.ini | 1 + src/pc/configfile.c | 2 + src/pc/configfile.h | 1 + src/pc/djui/djui_chat_box.c | 95 +++++++++++++-------------- src/pc/djui/djui_chat_box.h | 1 + src/pc/djui/djui_console.c | 51 +++++++++++--- src/pc/djui/djui_console.h | 1 + src/pc/djui/djui_panel_menu_options.c | 2 + 18 files changed, 103 insertions(+), 61 deletions(-) diff --git a/lang/Czech.ini b/lang/Czech.ini index 01c9ced13..a5be025a5 100644 --- a/lang/Czech.ini +++ b/lang/Czech.ini @@ -176,6 +176,7 @@ DJUI_FONT = "DJUI Font" AUTO = "Automatický" CENTER = "Střed" GRADIENTS = "Gradienty" +SMOOTH_SCROLLING = "Plynulé Posouvání" FONT_NORMAL = "Normální" FONT_ALIASED = "Hladký" LIGHT_THEME = "Světlo" diff --git a/lang/Dutch.ini b/lang/Dutch.ini index 3bf65289b..04828b1a6 100644 --- a/lang/Dutch.ini +++ b/lang/Dutch.ini @@ -176,6 +176,7 @@ DJUI_FONT = "DJUI-lettertype" AUTO = "Automatisch" CENTER = "Centreren" GRADIENTS = "Kleurverlopen" +SMOOTH_SCROLLING = "Soepel Scrollen" FONT_NORMAL = "Normaal" FONT_ALIASED = "Glad" LIGHT_THEME = "Licht" diff --git a/lang/English.ini b/lang/English.ini index aab1ff042..a301f02de 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -176,6 +176,7 @@ DJUI_FONT = "DJUI Font" AUTO = "Auto" CENTER = "DJUI Center" GRADIENTS = "DJUI Gradients" +SMOOTH_SCROLLING = "DJUI Smooth Scrolling" FONT_NORMAL = "Normal" FONT_ALIASED = "Aliased" LIGHT_THEME = "Light" diff --git a/lang/French.ini b/lang/French.ini index 02047248a..5e03453a0 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -176,6 +176,7 @@ DJUI_FONT = "Police DJUI" AUTO = "Automatique" CENTER = "Centrer le menu" GRADIENTS = "Dégradés" +SMOOTH_SCROLLING = "Défilement Fluide" FONT_NORMAL = "Normal" FONT_ALIASED = "Lisse" LIGHT_THEME = "Clair" diff --git a/lang/German.ini b/lang/German.ini index 23b4da1f5..97f2f3251 100644 --- a/lang/German.ini +++ b/lang/German.ini @@ -176,6 +176,7 @@ DJUI_FONT = "DJUI-Schriftart" AUTO = "Automatisch" CENTER = "Zentrieren" GRADIENTS = "Farbverläufe" +SMOOTH_SCROLLING = "Flüssiges Scrollen" FONT_NORMAL = "Normal" FONT_ALIASED = "Glatt" LIGHT_THEME = "Hell" diff --git a/lang/Italian.ini b/lang/Italian.ini index 53d10afaa..f28c7f732 100644 --- a/lang/Italian.ini +++ b/lang/Italian.ini @@ -174,6 +174,7 @@ DJUI_FONT = "Font DJUI" AUTO = "Automatico" CENTER = "Centrare" GRADIENTS = "Gradienti" +SMOOTH_SCROLLING = "Scorrimento Fluido" FONT_NORMAL = "Normale" FONT_ALIASED = "Liscio" LIGHT_THEME = "Luce" diff --git a/lang/Japanese.ini b/lang/Japanese.ini index 1c56cdd7a..e51d98e4d 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -177,6 +177,7 @@ DJUI_FONT = "DJUIのフォント" AUTO = "自動" CENTER = "中心にDJUIを表示" GRADIENTS = "グラデーション" +SMOOTH_SCROLLING = "スムーススクロール" FONT_NORMAL = "普通" FONT_ALIASED = "エイリアス" LIGHT_THEME = "ライト" diff --git a/lang/Polish.ini b/lang/Polish.ini index 6305f07c4..f38821a7d 100644 --- a/lang/Polish.ini +++ b/lang/Polish.ini @@ -176,6 +176,7 @@ DJUI_FONT = "Czcionka DJUI" AUTO = "Automatyczna" CENTER = "Wyśrodkowane" GRADIENTS = "Gradienty" +SMOOTH_SCROLLING = "Płynne Przewijanie" FONT_NORMAL = "Normalna" FONT_ALIASED = "Wygładzona" LIGHT_THEME = "Jasny" diff --git a/lang/Portuguese.ini b/lang/Portuguese.ini index 535bcce03..0d3f3ee06 100644 --- a/lang/Portuguese.ini +++ b/lang/Portuguese.ini @@ -176,6 +176,7 @@ DJUI_FONT = "Fonte da DJUI" AUTO = "Automático" CENTER = "Centralizar" GRADIENTS = "Gradientes" +SMOOTH_SCROLLING = "Rolagem Suave" FONT_NORMAL = "Normal" FONT_ALIASED = "Suave" LIGHT_THEME = "Claro" diff --git a/lang/Russian.ini b/lang/Russian.ini index a26889fe5..47a392687 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -175,6 +175,7 @@ DJUI_FONT = "Шрифт DJUI" AUTO = "Автоматический" CENTER = "Центр" GRADIENTS = "Градиенты" +SMOOTH_SCROLLING = "Плавная Прокрутка" FONT_NORMAL = "Обычный" FONT_ALIASED = "Гладкий" LIGHT_THEME = "Свет" diff --git a/lang/Spanish.ini b/lang/Spanish.ini index 22fc17c03..4d92bfa5a 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -176,6 +176,7 @@ DJUI_FONT = "Fuente DJUI" AUTO = "Automático" CENTER = "Centrar" GRADIENTS = "Gradientes" +SMOOTH_SCROLLING = "Desplazamiento Suave" FONT_NORMAL = "Normal" FONT_ALIASED = "Alias" LIGHT_THEME = "Claro" diff --git a/src/pc/configfile.c b/src/pc/configfile.c index e5a7c457e..3477ab40c 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -128,6 +128,7 @@ unsigned int configGamepadNumber = 0; bool configBackgroundGamepad = true; bool configDisableGamepads = false; bool configUseStandardKeyBindingsChat = false; +bool configSmoothScrolling = false; // free camera settings bool configEnableFreeCamera = false; bool configFreeCameraAnalog = false; @@ -270,6 +271,7 @@ static const struct ConfigOption options[] = { {.name = "disable_gamepads", .type = CONFIG_TYPE_BOOL, .boolValue = &configDisableGamepads}, #endif {.name = "use_standard_key_bindings_chat", .type = CONFIG_TYPE_BOOL, .boolValue = &configUseStandardKeyBindingsChat}, + {.name = "smooth_scrolling", .type = CONFIG_TYPE_BOOL, .boolValue = &configSmoothScrolling}, {.name = "stick_rotate_left", .type = CONFIG_TYPE_BOOL, .boolValue = &configStick.rotateLeft}, {.name = "stick_invert_left_x", .type = CONFIG_TYPE_BOOL, .boolValue = &configStick.invertLeftX}, {.name = "stick_invert_left_y", .type = CONFIG_TYPE_BOOL, .boolValue = &configStick.invertLeftY}, diff --git a/src/pc/configfile.h b/src/pc/configfile.h index 02fa38ece..f7503a050 100644 --- a/src/pc/configfile.h +++ b/src/pc/configfile.h @@ -87,6 +87,7 @@ extern unsigned int configGamepadNumber; extern bool configBackgroundGamepad; extern bool configDisableGamepads; extern bool configUseStandardKeyBindingsChat; +extern bool configSmoothScrolling; // free camera settings extern bool configEnableFreeCamera; extern bool configFreeCameraAnalog; diff --git a/src/pc/djui/djui_chat_box.c b/src/pc/djui/djui_chat_box.c index 011eaaf92..f3f2e590a 100644 --- a/src/pc/djui/djui_chat_box.c +++ b/src/pc/djui/djui_chat_box.c @@ -6,6 +6,7 @@ #include "pc/chat_commands.h" #include "pc/configfile.h" #include "djui.h" +#include "engine/math_util.h" struct DjuiChatBox* gDjuiChatBox = NULL; bool gDjuiChatBoxFocus = false; @@ -100,6 +101,17 @@ bool djui_chat_box_render(struct DjuiBase* base) { struct DjuiChatBox* chatBox = (struct DjuiChatBox*)base; struct DjuiBase* ccBase = &chatBox->chatContainer->base; djui_base_set_size(ccBase, 1.0f, chatBox->base.comp.height - 32 - 8); + if (chatBox->scrolling) { + f32 yMax = chatBox->chatContainer->base.elem.height - chatBox->chatFlow->base.height.value; + f32 target = chatBox->chatFlow->base.y.value + (chatBox->scrollY - chatBox->chatFlow->base.y.value) * (configSmoothScrolling ? 0.5f : 1.f); + + chatBox->chatFlow->base.y.value = clamp(target, yMax, 0.f); + if (target < yMax || 0.f < target) { + chatBox->scrollY = clamp(target, yMax, 0.f); + } + } else { chatBox->scrollY = chatBox->chatFlow->base.y.value; } + + printf("%f\n", chatBox->chatFlow->base.y.value); if (sDjuiChatBoxClearText) { sDjuiChatBoxClearText = false; djui_inputbox_set_text(gDjuiChatBox->chatInput, ""); @@ -407,10 +419,7 @@ static bool djui_chat_box_input_on_key_down(struct DjuiBase* base, int scancode) if (gDjuiChatBox == NULL) { return false; } f32 yMax = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value; - - f32* yValue = &gDjuiChatBox->chatFlow->base.y.value; - bool canScrollUp = (*yValue > yMax); - bool canScrollDown = (*yValue < 0); + f32 pageAmount = gDjuiChatBox->chatContainer->base.elem.height * 3.0f / 4.0f; char previousText[MAX_CHAT_MSG_LENGTH]; @@ -419,74 +428,59 @@ static bool djui_chat_box_input_on_key_down(struct DjuiBase* base, int scancode) switch (scancode) { case SCANCODE_UP: if (!configUseStandardKeyBindingsChat && (gDjuiChatBox->chatInput && gDjuiChatBox->chatInput->buffer && gDjuiChatBox->chatInput->buffer[0] != '/')) { - gDjuiChatBox->scrolling = true; - if (canScrollDown) { *yValue = fmin(*yValue + 15, 0); } + gDjuiChatBox->scrollY += 15; } else { sent_history_update_current_message(&sentHistory, gDjuiChatBox->chatInput->buffer); sent_history_navigate(&sentHistory, true); if (strcmp(previousText, gDjuiChatBox->chatInput->buffer) != 0) { reset_tab_completion_all(); } } - return true; + break; case SCANCODE_DOWN: if (!configUseStandardKeyBindingsChat && (gDjuiChatBox->chatInput && gDjuiChatBox->chatInput->buffer && gDjuiChatBox->chatInput->buffer[0] != '/')) { - gDjuiChatBox->scrolling = true; - if (canScrollUp) { *yValue = fmax(*yValue - 15, yMax); } + gDjuiChatBox->scrollY -= 15; } else { sent_history_update_current_message(&sentHistory, gDjuiChatBox->chatInput->buffer); sent_history_navigate(&sentHistory, false); if (strcmp(previousText, gDjuiChatBox->chatInput->buffer) != 0) { reset_tab_completion_all(); } } - return true; + break; case SCANCODE_PAGE_UP: - gDjuiChatBox->scrolling = true; - if (canScrollDown) { - if (configUseStandardKeyBindingsChat) { - *yValue = fmin(*yValue + 15, 0); - } else { - *yValue = fmin(*yValue + pageAmount, 0); - } - } - return true; + gDjuiChatBox->scrollY += configUseStandardKeyBindingsChat ? 15 : pageAmount; + break; case SCANCODE_PAGE_DOWN: - gDjuiChatBox->scrolling = true; - if (canScrollUp) { - if (configUseStandardKeyBindingsChat) { - *yValue = fmax(*yValue - 15, yMax); - } else { - *yValue = fmax(*yValue - pageAmount, yMax); - } - } - return true; + gDjuiChatBox->scrollY -= configUseStandardKeyBindingsChat ? 15 : pageAmount; + break; case SCANCODE_POS1: - gDjuiChatBox->scrolling = true; - if (canScrollDown) { *yValue = fmin(*yValue + pageAmount, 0); } - return true; + gDjuiChatBox->scrollY += pageAmount; + break; case SCANCODE_END: - gDjuiChatBox->scrolling = true; - if (canScrollUp) { *yValue = fmax(*yValue - pageAmount, yMax); } - return true; + gDjuiChatBox->scrollY -= pageAmount; + break; case SCANCODE_TAB: handle_tab_completion(); - return true; + break; case SCANCODE_ENTER: reset_tab_completion_all(); sent_history_reset_navigation(&sentHistory); djui_chat_box_input_enter(gDjuiChatBox->chatInput); - return true; + break; case SCANCODE_ESCAPE: reset_tab_completion_all(); sent_history_reset_navigation(&sentHistory); djui_chat_box_input_escape(gDjuiChatBox->chatInput); - return true; + break; default: - { - bool returnValueOnOtherKeyDown = djui_inputbox_on_key_down(base, scancode); - if (strcmp(previousText, gDjuiChatBox->chatInput->buffer) != 0) { - reset_tab_completion_all(); - } - return returnValueOnOtherKeyDown; + bool returnValueOnOtherKeyDown = djui_inputbox_on_key_down(base, scancode); + if (strcmp(previousText, gDjuiChatBox->chatInput->buffer) != 0) { + reset_tab_completion_all(); } + return returnValueOnOtherKeyDown; } + + if (!gDjuiConsole->scrolling) { + gDjuiConsole->scrolling = gDjuiConsole->scrollY < 0 && gDjuiConsole->scrollY > yMax; + } + return true; } static void djui_chat_box_input_on_text_input(struct DjuiBase *base, char* text) { @@ -506,17 +500,16 @@ static void djui_chat_box_input_on_scroll(UNUSED struct DjuiBase *base, UNUSED f if (gDjuiChatBox == NULL) { return; } f32 yMax = gDjuiChatBox->chatContainer->base.elem.height - gDjuiChatBox->chatFlow->base.height.value; - f32* yValue = &gDjuiChatBox->chatFlow->base.y.value; - bool canScrollUp = (*yValue > yMax); - bool canScrollDown = (*yValue < 0); - - y *= 24; + + y *= 24.f; if (gDjuiInputHeldControl) { y /= 2; } if (gDjuiInputHeldShift) { y *= 3; } - gDjuiChatBox->scrolling = true; - if (y > 0 && canScrollDown) { *yValue = fmin(*yValue + y, 0); } - if (y < 0 && canScrollUp) { *yValue = fmax(*yValue + y, yMax); } + gDjuiChatBox->scrollY += y; + + if (!gDjuiConsole->scrolling) { + gDjuiConsole->scrolling = gDjuiConsole->scrollY < 0 && gDjuiConsole->scrollY > yMax; + } } void djui_chat_box_toggle(void) { diff --git a/src/pc/djui/djui_chat_box.h b/src/pc/djui/djui_chat_box.h index e034f8ac8..1c5a7d150 100644 --- a/src/pc/djui/djui_chat_box.h +++ b/src/pc/djui/djui_chat_box.h @@ -7,6 +7,7 @@ struct DjuiChatBox { struct DjuiFlowLayout* chatFlow; struct DjuiInputbox* chatInput; bool scrolling; + f32 scrollY; }; extern struct DjuiChatBox* gDjuiChatBox; diff --git a/src/pc/djui/djui_console.c b/src/pc/djui/djui_console.c index 8104c2ca7..3f6b1372a 100644 --- a/src/pc/djui/djui_console.c +++ b/src/pc/djui/djui_console.c @@ -3,6 +3,7 @@ #include "djui.h" #include "djui_console.h" #include "pc/pc_main.h" +#include "engine/math_util.h" #define MAX_CONSOLE_MESSAGES 500 @@ -50,7 +51,18 @@ void djui_console_message_dequeue(void) { } bool djui_console_render(struct DjuiBase* base) { + struct DjuiConsole* console = (struct DjuiConsole*)base; djui_base_set_size(base, gDjuiRoot->base.width.value, gDjuiRoot->base.height.value * 0.5f); + if (console->scrolling) { + f32 yMax = console->base.comp.height - console->flow->base.height.value; + f32 target = console->flow->base.y.value + (console->scrollY - console->flow->base.y.value) * (configSmoothScrolling ? 0.5f : 1.f); + + console->flow->base.y.value = clamp(target, yMax, 0.f); + if (target < yMax || 0.f < target) { + console->scrollY = clamp(target, yMax, 0.f); + if (target > 0.f) { gDjuiConsole->scrolling = false; } + } + } else { console->scrollY = console->flow->base.y.value; } djui_rect_render(base); return true; @@ -74,32 +86,48 @@ void djui_console_toggle(void) { } } +static void djui_console_on_scroll(UNUSED struct DjuiBase *base, UNUSED float x, float y) { + if (gDjuiConsole == NULL) { return; } + + f32 yMax = gDjuiConsole->base.comp.height - gDjuiConsole->flow->base.height.value; + + y *= 24.f; + if (gDjuiInputHeldControl) { y /= 2; } + if (gDjuiInputHeldShift) { y *= 3; } + + gDjuiConsole->scrollY -= y; + + if (!gDjuiConsole->scrolling) { + gDjuiConsole->scrolling = y > 0 && gDjuiConsole->scrollY > yMax; + } +} + static bool djui_console_on_key_down(UNUSED struct DjuiBase* base, int scancode) { if (gDjuiConsole == NULL) { return false; } f32 yMax = gDjuiConsole->base.comp.height - gDjuiConsole->flow->base.height.value; - f32* yValue = &gDjuiConsole->flow->base.y.value; - bool canScrollUp = (*yValue > yMax); - bool canScrollDown = (*yValue < 0); f32 pageAmount = gDjuiConsole->base.comp.height * 3.0f / 4.0f; switch (scancode) { case SCANCODE_UP: - if (canScrollUp) { *yValue = fmax(*yValue - 15, yMax); } + gDjuiConsole->scrollY -= 15; break; case SCANCODE_DOWN: - if (canScrollDown) { *yValue = fmin(*yValue + 15, 0); } + gDjuiConsole->scrollY += 15; break; case SCANCODE_PAGE_UP: - if (canScrollUp) { *yValue = fmax(*yValue - pageAmount, yMax); } + gDjuiConsole->scrollY -= pageAmount; break; case SCANCODE_PAGE_DOWN: - if (canScrollDown) { *yValue = fmin(*yValue + pageAmount, 0); } + gDjuiConsole->scrollY += pageAmount; break; case SCANCODE_ESCAPE: djui_console_toggle(); break; default: break; } - gDjuiConsole->scrolling = (*yValue != 0); + + if (!gDjuiConsole->scrolling) { + gDjuiConsole->scrolling = gDjuiConsole->scrollY < 0 && gDjuiConsole->scrollY > yMax; + } return true; } @@ -139,8 +167,9 @@ void djui_console_message_create(const char* message, enum ConsoleMessageLevel l f32 heightAdjust = messageHeight + gDjuiConsole->flow->margin.value; cfBase->height.value += heightAdjust; - if (gDjuiConsole->scrolling) { + if (gDjuiConsole->scrolling && gDjuiConsole->scrollY != 0) { cfBase->y.value -= heightAdjust; + gDjuiConsole->scrollY -= heightAdjust; } sDjuiConsoleMessages++; @@ -148,8 +177,9 @@ void djui_console_message_create(const char* message, enum ConsoleMessageLevel l if (cfBase->child) { heightAdjust = cfBase->child->base->height.value + gDjuiConsole->flow->margin.value; cfBase->height.value -= heightAdjust; - if (gDjuiConsole->scrolling) { + if (gDjuiConsole->scrolling && gDjuiConsole->scrollY != 0) { cfBase->y.value += heightAdjust; + gDjuiConsole->scrollY += heightAdjust; } } @@ -177,6 +207,7 @@ struct DjuiConsole* djui_console_create(void) { djui_interactable_create(base, NULL); djui_interactable_hook_key(base, djui_console_on_key_down, NULL); + djui_interactable_hook_scroll(base, djui_console_on_scroll); struct DjuiFlowLayout* flow = djui_flow_layout_create(base); struct DjuiBase* cfBase = &flow->base; diff --git a/src/pc/djui/djui_console.h b/src/pc/djui/djui_console.h index 224fad6a8..e7dee2416 100644 --- a/src/pc/djui/djui_console.h +++ b/src/pc/djui/djui_console.h @@ -11,6 +11,7 @@ struct DjuiConsole { struct DjuiBase base; struct DjuiFlowLayout* flow; bool scrolling; + f32 scrollY; }; #define CONSOLE_MAX_TMP_BUFFER 512 diff --git a/src/pc/djui/djui_panel_menu_options.c b/src/pc/djui/djui_panel_menu_options.c index d85aa1d43..c2a54cdd3 100644 --- a/src/pc/djui/djui_panel_menu_options.c +++ b/src/pc/djui/djui_panel_menu_options.c @@ -137,6 +137,8 @@ void djui_panel_main_menu_create(struct DjuiBase* caller) { char* djuiFontChoices[2] = {DLANG(DJUI_THEMES, FONT_NORMAL), DLANG(DJUI_THEMES, FONT_ALIASED)}; djui_selectionbox_create(body, DLANG(DJUI_THEMES, DJUI_FONT), djuiFontChoices, 2, &configDjuiThemeFont, djui_panel_menu_options_djui_setting_change); + djui_checkbox_create(body, DLANG(DJUI_THEMES, SMOOTH_SCROLLING), &configSmoothScrolling, NULL); + if (gDjuiInMainMenu) { // copy sound choices from gMainMenuSounds int numSounds = sizeof(gMainMenuSounds) / sizeof(gMainMenuSounds[0]);