From 2252c16acbd33ee77f7085dfa07d2f435692d1f1 Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Sat, 7 Jun 2025 20:57:06 +0200 Subject: [PATCH] Rewritten scrolling and coordinate logic --- src/deh_soc.c | 4 + src/deh_tables.c | 1 - src/m_menu.c | 249 +++++++++++++++++------------------------------ src/m_menu.h | 2 +- 4 files changed, 95 insertions(+), 161 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 9bff11545..638757495 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -2286,6 +2286,10 @@ void readmenu(MYFILE *f, INT32 num) { menudef->y = value; } + else if (fastcmp(word, "SCROLLHEIGHT")) + { + menudef->scrollheight = get_number(word2); + } else if (fastcmp(word, "ENTERROUTINE")) { menufunc_f *routine = get_menuroutine(word2); diff --git a/src/deh_tables.c b/src/deh_tables.c index 1ac54a351..b42ad85fe 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -757,7 +757,6 @@ struct menu_routine_s const MENU_ROUTINES[] = { struct menu_drawer_s const MENU_DRAWERS[] = { { "DRAWGENERICMENU", &M_DrawGenericMenu }, - { "DRAWGENERICSCROLLMENU", &M_DrawGenericScrollMenu }, { "DRAWCENTEREDMENU", &M_DrawCenteredMenu }, { "DRAWPAUSEMENU", &M_DrawPauseMenu }, { "DRAWCHECKLIST", &M_DrawChecklist }, diff --git a/src/m_menu.c b/src/m_menu.c index 967dadfa2..3e3b7d6b0 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -102,11 +102,7 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "qs22j.h" -#define SKULLXOFF -32 -#define LINEHEIGHT 16 -#define STRINGHEIGHT 8 -#define FONTBHEIGHT 20 -#define SMALLLINEHEIGHT 8 +#define LINEHEIGHT 8 #define SLIDER_RANGE 10 #define SLIDER_WIDTH (8*SLIDER_RANGE+6) @@ -2003,8 +1999,6 @@ static void M_DrawMenuTitle(void) } } -#define scrollareaheight 72 - void M_DrawPauseMenu(void) { #ifdef HAVE_DISCORDRPC @@ -2029,131 +2023,91 @@ void M_DrawPauseMenu(void) M_DrawGenericMenu(); } -// this function is macro'd so it needs a wrapper -static void drawstringleft(INT32 x, INT32 y, INT32 option, const char *string) +static INT16 getheight(INT16 index) { - V_DrawString(x, y, option, string); + INT16 y = currentMenu->menuitems[index].y; + if (!y) for (INT16 i = 0; i < index; i++) + if (!(currentMenu->menuitems[i].status & IT_HIDDEN)) + y += 8; + return y; } -static void M_DrawBaseMenu(boolean centered, boolean scrollma, boolean tamenu, boolean controls) +static void M_DrawBaseMenu(boolean centered, boolean tamenu, boolean controls) { - INT32 x, y, i, cursory = 0; - INT32 w, max, bottom, tempcentery; + INT16 scrollx = currentMenu->x, scrolly = currentMenu->y; + INT16 scrollheight = currentMenu->scrollheight; + if (!scrollheight) + scrollheight = BASEVIDHEIGHT - currentMenu->y; - void (*DrawString)(INT32, INT32, INT32, const char *) = centered ? V_DrawCenteredString : drawstringleft; + INT16 topy = getheight(0); + INT16 boty = getheight(currentMenu->numitems-1); - // DRAW MENU - x = currentMenu->x; - y = currentMenu->y; - - if (scrollma) + if (boty - topy > scrollheight) { - if (currentMenu->menuitems[currentMenu->numitems-1].y < scrollareaheight) - tempcentery = currentMenu->y; // Not tall enough to scroll, but this thinker is used in case it becomes so - else if ((currentMenu->menuitems[itemOn].y*2 - currentMenu->menuitems[0].y*2) <= scrollareaheight) - tempcentery = currentMenu->y - currentMenu->menuitems[0].y*2; - else if ((currentMenu->menuitems[currentMenu->numitems-1].y*2 - currentMenu->menuitems[itemOn].y*2) <= scrollareaheight) - tempcentery = currentMenu->y - currentMenu->menuitems[currentMenu->numitems-1].y*2 + 2*scrollareaheight; - else - tempcentery = currentMenu->y - currentMenu->menuitems[itemOn].y*2 + scrollareaheight; - - for (i = 0; i < currentMenu->numitems; i++) - { - if (!(currentMenu->menuitems[i].status & IT_HIDDEN) && currentMenu->menuitems[i].y*2 + tempcentery >= currentMenu->y) - break; - } - - for (bottom = currentMenu->numitems; bottom > 0; bottom--) - { - if (!(currentMenu->menuitems[bottom-1].status & IT_HIDDEN)) - break; - } - - for (max = bottom; max > 0; max--) - { - if (!(currentMenu->menuitems[max-1].status & IT_HIDDEN) && currentMenu->menuitems[max-1].y*2 + tempcentery <= (currentMenu->y + 2*scrollareaheight)) - break; - } - - if (i) - V_DrawString(currentMenu->x - 20, currentMenu->y - (skullAnimCounter/5), highlightflags, "\x1A"); // up arrow - if (max != bottom) - V_DrawString(currentMenu->x - 20, currentMenu->y + 2*scrollareaheight + (skullAnimCounter/5), highlightflags, "\x1B"); // down arrow - } - else if (controls) - { -#define controlheight 18 - INT32 iter = (controlheight/2); - for (i = itemOn; ((iter || currentMenu->menuitems[i].status & IT_HIDDEN) && i > 0); i--) - { - if (!(currentMenu->menuitems[i].status & IT_HIDDEN)) - iter--; - } - if (currentMenu->menuitems[i].status & IT_HIDDEN) - i--; - - iter += (controlheight/2); - for (max = itemOn; (iter && max < currentMenu->numitems); max++) - { - if (!(currentMenu->menuitems[max].status & IT_HIDDEN)) - iter--; - } - - if (iter) - { - iter += (controlheight/2); - for (i = itemOn; ((iter || currentMenu->menuitems[i].status & IT_HIDDEN) && i > 0); i--) - { - if (!(currentMenu->menuitems[i].status & IT_HIDDEN)) - iter--; - } - } - - if (i) - V_DrawCharacter(currentMenu->x - 16, y-(skullAnimCounter/5), - '\x1A' | highlightflags, false); // up arrow - if (max != currentMenu->numitems) - V_DrawCharacter(currentMenu->x - 16, y+(SMALLLINEHEIGHT*(controlheight-1))+(skullAnimCounter/5) + (skullAnimCounter/5), - '\x1B' | highlightflags, false); // down arrow -#undef controlheight - } - else - { - i = 0; - max = currentMenu->numitems; + scrolly = scrolly - getheight(itemOn) + scrollheight/2; + if (scrolly > currentMenu->y - topy) + scrolly = currentMenu->y - topy; + else if (scrolly < currentMenu->y - boty + scrollheight) + scrolly = currentMenu->y - boty + scrollheight; } // draw title (or big pic) M_DrawMenuTitle(); - for (; i < max; i++) + INT16 w, x = scrollx, y = scrolly, cursorx = 0, cursory = 0; + boolean clipbot = false, cliptop = false; + + for (INT16 i = 0; i < currentMenu->numitems; i++) { - if (scrollma) - y = currentMenu->menuitems[i].y*2 + tempcentery; - if (i == itemOn) - cursory = y; + INT32 vflags = MENUCAPS; + const char *string = currentMenu->menuitems[i].text; + if (currentMenu->menuitems[i].status & IT_HIDDEN) { if (!controls) - y += LINEHEIGHT; + y += LINEHEIGHT; // don't leave gaps when buttons are hidden for P2/P3/P4 + continue; } - else if (currentMenu->menuitems[i].status & IT_SECRET) - { - if (currentMenu->menuitems[i].y) - y = currentMenu->y+currentMenu->menuitems[i].y; - DrawString(x, y, MENUCAPS|V_TRANSLUCENT|V_OLDSPACING, M_CreateSecretMenuOption(currentMenu->menuitems[i].text)); - y += SMALLLINEHEIGHT; + // coordinates setup + if (currentMenu->menuitems[i].y) + y = currentMenu->menuitems[i].y + scrolly; + if (currentMenu->menuitems[i].x) + x = currentMenu->menuitems[i].x + scrollx; + + if (y < currentMenu->y) + { + cliptop = true; + y += LINEHEIGHT; + continue; + } + else if (y > currentMenu->y + scrollheight) + { + clipbot = true; + y += LINEHEIGHT; + continue; + } + + if (i == itemOn) + { + cursory = y; + cursorx = x - (centered ? V_StringWidth(string, vflags)/2 : 0) - (controls ? 18 : 24); + } + + // vflags setup + if (i == itemOn || (currentMenu->menuitems[i].status & IT_WHITESTRING)) + vflags |= highlightflags; + + if (currentMenu->menuitems[i].status & IT_SECRET) + { + vflags |= V_TRANSLUCENT|V_OLDSPACING; + string = M_CreateSecretMenuOption(string); } else if (currentMenu->menuitems[i].status & IT_GRAYEDOUT) - { - if (currentMenu->menuitems[i].y) - y = currentMenu->y+currentMenu->menuitems[i].y; + vflags |= V_TRANSLUCENT; - DrawString(x, y, MENUCAPS|V_TRANSLUCENT, currentMenu->menuitems[i].text); - y += SMALLLINEHEIGHT; - } - else switch (currentMenu->menuitems[i].status & IT_DISPLAY) + // start drawing! + switch (currentMenu->menuitems[i].status & IT_DISPLAY) { case IT_PATCH: if (currentMenu->menuitems[i].patch && currentMenu->menuitems[i].patch[0]) @@ -2170,29 +2124,16 @@ static void M_DrawBaseMenu(boolean centered, boolean scrollma, boolean tamenu, b W_CachePatchName(currentMenu->menuitems[i].patch, PU_CACHE)); } } - /* FALLTHRU */ - default: - if (centered) - y += LINEHEIGHT; - else if (controls) - y += SMALLLINEHEIGHT; - else if (!scrollma) - y = currentMenu->y+currentMenu->menuitems[i].y;//+= LINEHEIGHT; break; case IT_STRING: case IT_WHITESTRING: - if (!scrollma && !controls) - { - if (currentMenu->menuitems[i].y) - y = currentMenu->y+currentMenu->menuitems[i].y; - if (i == itemOn) - cursory = y; - } - - if (i != itemOn && (currentMenu->menuitems[i].status & IT_DISPLAY)==IT_STRING) - DrawString(x, y, MENUCAPS, currentMenu->menuitems[i].text); + if (centered) + V_DrawCenteredString(x, y, vflags, string); else - DrawString(x, y, MENUCAPS|highlightflags, currentMenu->menuitems[i].text); + V_DrawString(x, y, vflags, string); + + if (currentMenu->menuitems[i].status & (IT_SECRET|IT_GRAYEDOUT)) + break; if (controls && i == M_GetMenuIndex(MN_OP_CHANGECONTROLS, "SETJOY")) // gamepad select { @@ -2216,7 +2157,7 @@ static void M_DrawBaseMenu(boolean centered, boolean scrollma, boolean tamenu, b M_DrawSlider(x, y, cv, (i == itemOn)); break; case IT_CV_STRING: - if (scrollma && y + 12 > (currentMenu->y + 2*scrollareaheight)) + if (y + 12 > currentMenu->y + scrollheight) break; #if 1 INT32 xofs = tamenu ? 32 : 0, yofs = tamenu ? -8 : 4; @@ -2238,7 +2179,7 @@ static void M_DrawBaseMenu(boolean centered, boolean scrollma, boolean tamenu, b V_DrawRightAlignedString(BASEVIDWIDTH - x, y, highlightflags|V_ALLOWLOWERCASE, cv->string); #endif - if (!scrollma && !tamenu) + if (!tamenu) y += 16; break; default: @@ -2289,28 +2230,24 @@ static void M_DrawBaseMenu(boolean centered, boolean scrollma, boolean tamenu, b break; } } - if (!scrollma) - y += controls ? SMALLLINEHEIGHT : STRINGHEIGHT; break; case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text - if (!scrollma && !controls && currentMenu->menuitems[i].y) - y = currentMenu->y+currentMenu->menuitems[i].y; - - if (!controls || i != max-1) - V_DrawString(controls ? 13 : x-16, controls ? y+6 : y, MENUCAPS|highlightflags, currentMenu->menuitems[i].text); - if (!scrollma) - y += SMALLLINEHEIGHT; + V_DrawString(x - (controls ? 7 : 16), y - (controls ? 2 : 0), vflags, string); + break; + default: break; } + + y += LINEHEIGHT; } // DRAW THE SKULL CURSOR - if (centered) - x -= V_StringWidth(currentMenu->menuitems[itemOn].text, MENUCAPS)/2; - else - x = currentMenu->x; - V_DrawScaledPatch(x + (controls ? -18 : -24), cursory, 0, - W_CachePatchName("M_CURSOR", PU_CACHE)); + V_DrawScaledPatch(cursorx, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); + + if (cliptop) + V_DrawCharacter(currentMenu->x - (controls ? 16 : 20), currentMenu->y - (skullAnimCounter/5), '\x1A' | highlightflags, false); // up arrow + if (clipbot) + V_DrawCharacter(currentMenu->x - (controls ? 16 : 20), currentMenu->y + scrollheight + (skullAnimCounter/5), '\x1B' | highlightflags, false); // down arrow if (menustack[0] == MN_MAIN) { @@ -2345,18 +2282,12 @@ texty -= 10*vid.dupy;\ void M_DrawGenericMenu(void) { - M_DrawBaseMenu(false, false, false, false); + M_DrawBaseMenu(false, false, false); } void M_DrawCenteredMenu(void) { - M_DrawBaseMenu(true, false, false, false); -} - -// note that alphakey is multiplied by 2 for scrolling menus to allow greater usage in UINT8 range. -void M_DrawGenericScrollMenu(void) -{ - M_DrawBaseMenu(false, true, false, false); + M_DrawBaseMenu(true, false, false); } // @@ -5333,7 +5264,7 @@ void M_DrawTimeAttackMenu(void) } } - M_DrawBaseMenu(false, false, true, false); + M_DrawBaseMenu(false, true, false); // Level record list if (cv_nextmap.value) @@ -7353,7 +7284,7 @@ void M_DrawJoystick(void) for (i = 0; i <= MAXGAMEPADS; i++) { - M_DrawTextBox(menudefs[MN_OP_JOYSTICKSET].x-8, menudefs[MN_OP_JOYSTICKSET].y+LINEHEIGHT*i-12, 28, 1); + M_DrawTextBox(menudefs[MN_OP_JOYSTICKSET].x-8, menudefs[MN_OP_JOYSTICKSET].y + 16*i - 8, 28, 1); #ifdef JOYSTICK_HOTPLUG if (atoi(cv_usejoystick[setupcontrolplayer-1].string) > I_NumJoys()) @@ -7362,7 +7293,7 @@ void M_DrawJoystick(void) #endif compareval = cv_usejoystick[setupcontrolplayer-1].value; - V_DrawString(menudefs[MN_OP_JOYSTICKSET].x, menudefs[MN_OP_JOYSTICKSET].y+LINEHEIGHT*i-4, ((i == compareval) ? V_GREENMAP : 0)|MENUCAPS, joystickInfo[i]); + V_DrawString(menudefs[MN_OP_JOYSTICKSET].x, menudefs[MN_OP_JOYSTICKSET].y + 16*i, ((i == compareval) ? V_GREENMAP : 0)|MENUCAPS, joystickInfo[i]); } } @@ -7516,7 +7447,7 @@ void M_DrawControl(void) (setupcontrolplayer > 1 ? va("\x86""Set controls for ""\x82""Player %d", setupcontrolplayer) : "\x86""Press ""\x82""ENTER""\x86"" to change, ""\x82""BACKSPACE""\x86"" to clear")); - M_DrawBaseMenu(false, false, false, true); + M_DrawBaseMenu(false, false, true); } static INT32 controltochange; diff --git a/src/m_menu.h b/src/m_menu.h index 0b7a4b71d..0bdb2f148 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -231,6 +231,7 @@ struct menu_t menuitem_t *menuitems; // menu items menudrawer_f *drawroutine; // draw routine INT16 x, y; // x, y of menu + INT16 scrollheight; // height of scrolling area INT16 lastOn; // last item user was on in menu menufunc_f *enterroutine; // called before enter a menu menufunc_f *quitroutine; // called before quit a menu @@ -323,7 +324,6 @@ INT32 MR_HandleDiscordRequests(INT32 choice); #endif void M_DrawGenericMenu(void); -void M_DrawGenericScrollMenu(void); void M_DrawCenteredMenu(void); void M_DrawPauseMenu(void); void M_DrawChecklist(void);