From f30ddcfad2d29073c0aa31efead47287cd7811da Mon Sep 17 00:00:00 2001 From: GenericHeroGuy Date: Thu, 12 Jun 2025 16:49:50 +0200 Subject: [PATCH] Three(!?) new methods for placing menu items Relative: changes the coordinates relative to the current ones Temporary relative: displaces the coordinates temporarily Overlay: draws at absolute coordinates, no clipping Along with custom cursor offsets and Item Styles(tm), this eliminates M_DrawControl --- src/deh_soc.c | 42 ++++++++++++++++-- src/deh_tables.c | 1 - src/m_menu.c | 113 ++++++++++++++++++++++++++++------------------- src/m_menu.h | 13 +++--- 4 files changed, 114 insertions(+), 55 deletions(-) diff --git a/src/deh_soc.c b/src/deh_soc.c index 89749da11..f5425e369 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1908,10 +1908,28 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) { menuitem->x = get_number(word2); } + else if (fastcmp(word, "OFSX")) + { + menuitem->x = get_number(word2); + status |= IT_OFSX; + } else if (fastcmp(word, "Y")) { menuitem->y = get_number(word2); } + else if (fastcmp(word, "OFSY")) + { + menuitem->y = get_number(word2); + status |= IT_OFSY; + } + else if (fastcmp(word, "OVERLAY")) + { + status |= IT_OVERLAY; + } + else if (fastcmp(word, "TEMPOFFSET")) + { + status |= IT_TEMPORARY; + } else if (fastcmp(word, "ARGUMENT")) { menuitem->argument = get_number(word2); @@ -1924,6 +1942,13 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) { menuitem->tooltip = Z_StrDup(word2); } + else if (fastcmp(word, "STYLE")) + { + if (fasticmp(word2, "CENTER")) + status |= IT_CENTER; + else + WARN("unknown style '%s'", word2); + } else if (fastncmp(word, "TEXT", 4)) { UINT16 flags = IT_STRING; @@ -1952,8 +1977,8 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) flags |= IT_CV_SLIDER; else if (fastcmp(word+4, "STRING")) flags |= IT_CV_STRING; - else if (fastcmp(word+4, "INTEGER")) - flags |= IT_CV_INTEGERSTEP; + //else if (fastcmp(word+4, "INTEGER")) + //flags |= IT_CV_INTEGERSTEP; else if (word[4]) { WARN("unknown word '%s'", word); @@ -1984,7 +2009,6 @@ static void readmenuitem(MYFILE *f, menuitem_t *menuitem) WARN("unknown menu '%s'", word2); continue; } - status |= IT_SUBMENU; menuitem->submenu = mn; } else if (fastcmp(word, "CALL") || fastcmp(word, "ARROWS")) @@ -2256,6 +2280,14 @@ void readmenu(MYFILE *f, INT32 num) { menudef->scrollheight = get_number(word2); } + else if (fastcmp(word, "CURSOROFFSET")) + { + menudef->cursoroffset = get_number(word2); + } + else if (fastcmp(word, "LINEHEIGHT")) + { + menudef->lineheight = get_number(word2); + } else if (fastcmp(word, "ENTERROUTINE")) { menufunc_f *routine = get_menuroutine(word2); @@ -2291,6 +2323,10 @@ void readmenu(MYFILE *f, INT32 num) } } while (!myfeof(f)); // finish when the line is empty + // default line height + if (!menudef->lineheight) + menudef->lineheight = 8; + Z_Free(s); } #undef WARN diff --git a/src/deh_tables.c b/src/deh_tables.c index 665bb0453..fc1063933 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -772,7 +772,6 @@ struct menu_drawer_s const MENU_DRAWERS[] = { { "DRAWPLAYBACKMENU", &M_DrawPlaybackMenu }, { "DRAWIMAGEDEF", &M_DrawImageDef }, { "DRAWMUSICTEST", &M_DrawMusicTest }, - { "DRAWCONTROL", &M_DrawControl }, { "DRAWJOYSTICK", &M_DrawJoystick }, { "DRAWMONITORTOGGLES", &M_DrawMonitorToggles }, { "DRAWCONNECTMENU", &M_DrawConnectMenu }, diff --git a/src/m_menu.c b/src/m_menu.c index b24639138..fdc819d93 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -102,7 +102,6 @@ int snprintf(char *str, size_t n, const char *fmt, ...); #include "qs22j.h" -#define LINEHEIGHT 8 #define SLIDER_RANGE 10 #define SLIDER_WIDTH (8*SLIDER_RANGE+6) #define MAXIPADDRESSLEN 28 @@ -283,7 +282,7 @@ static void M_ChangeItemStatus(menutype_t type, const char *name, UINT16 flag, b static boolean M_ItemSelectable(menuitem_t *item) { - return !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET)) && (item->status & IT_TYPE); + return !(item->status & (IT_HIDDEN|IT_GRAYEDOUT|IT_SECRET)) && (item->submenu || item->routine || item->cvar); } // bruh... @@ -832,14 +831,14 @@ static INT32 M_ChangeCvar(INT32 choice) } else if (cv->flags & CV_FLOAT) { - if (!(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP)) + /*if (!(currentMenu->menuitems[itemOn].status & IT_CV_INTEGERSTEP)) { char s[20]; float n = FIXED_TO_FLOAT(cv->value)+(choice)*(1.0f/16.0f); sprintf(s,"%ld%s",(long)n,M_Ftrim(n)); CV_Set(cv,s); } - else + else*/ CV_SetValue(cv,FIXED_TO_FLOAT(cv->value)+(choice)); } else @@ -2102,7 +2101,7 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo break; case IT_STRING: case IT_WHITESTRING: - if (vflags & MDF_CENTERED) + if (vflags & MDF_CENTERED || item->status & IT_CENTER) V_DrawCenteredString(x, y, vflags|highlight, string); else V_DrawString(x, y, vflags|highlight, string); @@ -2225,7 +2224,7 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo } break; case IT_HEADERTEXT: // draws 16 pixels to the left, in yellow text - V_DrawString(x - (vflags & MDF_CONTROLS ? 7 : 16), y - (vflags & MDF_CONTROLS ? 2 : 0), vflags|highlight, string); + V_DrawString(x - 16, y, vflags|highlight, string); break; default: break; @@ -2234,12 +2233,22 @@ static INT16 M_DrawMenuItem(menuitem_t *item, INT16 x, INT16 y, INT32 vflags, bo return V_StringWidth(string, vflags); } +// gets the absolute Y coordinate where this menuitem should be drawn (in a broken way) +// TODO: merge this with the actual drawing loop somehow static INT16 getheight(INT16 index) { + // gotta skip overlay items... + INT16 i = 0; + while (index + i < currentMenu->numitems && currentMenu->menuitems[index + i].status & IT_OVERLAY) + i++; + index += i; + if (index >= currentMenu->numitems) + return 0; + INT16 y = currentMenu->menuitems[index].y; - if (!y) for (INT16 i = 0; i < index; i++) - if (!(currentMenu->menuitems[i].status & IT_HIDDEN)) - y += 8; + if (!y) while (i < index) + if (!(currentMenu->menuitems[i++].status & (IT_HIDDEN|IT_OVERLAY))) + y += currentMenu->lineheight; return y; } @@ -2249,6 +2258,8 @@ static void M_DrawBaseMenu(INT32 flags) INT16 scrollheight = currentMenu->scrollheight; if (!scrollheight) scrollheight = INT16_MAX; + if (!currentMenu->numitems) + return; INT16 topy = getheight(0); INT16 boty = getheight(currentMenu->numitems-1); @@ -2275,48 +2286,68 @@ static void M_DrawBaseMenu(INT32 flags) for (i = 0; i < currentMenu->numitems; i++) { + INT16 dx, dy; INT32 vflags = flags; + menuitem_t *item = ¤tMenu->menuitems[i]; - if (currentMenu->menuitems[i].status & IT_HIDDEN) - { - if (!(vflags & MDF_CONTROLS)) // don't leave gaps when buttons are hidden for P2/P3/P4 - y += LINEHEIGHT; + if (item->status & IT_HIDDEN) continue; + + if (item->status & IT_OVERLAY) + { + // draw at absolute coordinates; no clipping needed + dx = item->x; + dy = item->y; + } + else + { + dx = x + item->x; + if (item->x) + { + if (!(item->status & IT_OFSX)) + x = dx = item->x + scrollx; + else if (!(item->status & IT_TEMPORARY)) + x = dx; + } + + dy = y + item->y; + if (item->y) + { + if (!(item->status & IT_OFSY)) + y = dy = item->y + scrolly; + else if (!(item->status & IT_TEMPORARY)) + y = dy; + } + + if (dy < currentMenu->y) + { + cliptop = true; + goto nodraw; + } + else if (dy > currentMenu->y + scrollheight) + { + clipbot = true; + goto nodraw; + } } - 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; - } - - w = M_DrawMenuItem(¤tMenu->menuitems[i], x, y, vflags, i == itemOn); + w = M_DrawMenuItem(item, dx, dy, vflags, i == itemOn); if (i == itemOn) { cursory = y; - cursorx = x - (vflags & MDF_CENTERED ? w/2 : 0) - (vflags & MDF_CONTROLS ? 18 : 24); + cursorx = x - (vflags & MDF_CENTERED ? w/2 : 0) - 24 + currentMenu->cursoroffset; } - y += LINEHEIGHT; + nodraw: + if (!(item->status & IT_OVERLAY)) + y += currentMenu->lineheight; } // DRAW THE SKULL CURSOR V_DrawScaledPatch(cursorx, cursory, 0, W_CachePatchName("M_CURSOR", PU_CACHE)); - x = currentMenu->x - (flags & MDF_CONTROLS ? 16 : 20); + x = currentMenu->x - 20 + currentMenu->cursoroffset; if (cliptop) V_DrawCharacter(x, currentMenu->y - (skullAnimCounter/5), '\x1A' | highlightflags, false); // up arrow if (clipbot) @@ -3963,7 +3994,7 @@ void M_DrawPlaybackMenu(void) V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y + 18, transmap|V_SNAPTOTOP|V_ALLOWLOWERCASE, currentMenu->menuitems[i].text); - if ((currentMenu->menuitems[i].status & IT_TYPE) == IT_ARROWS) + if (currentMenu->menuitems[i].status & IT_ARROWS) { char *str = NULL; @@ -6999,16 +7030,6 @@ INT32 MR_HandleControlsMenu(INT32 ch) return true; } -// Draws the Customise Controls menu -void M_DrawControl(void) -{ - M_CentreText(28, - (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(MDF_CONTROLS|MENUCAPS); -} - static INT32 controltochange; static char controltochangetext[33]; diff --git a/src/m_menu.h b/src/m_menu.h index 00592d7e9..c532542e1 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -157,10 +157,9 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); // flags for items in the menu // menu handle (what we do when key is pressed -#define IT_TYPE (1+2+4+8192) #define IT_CALL 1 // call the function #define IT_ARROWS 2 // call function with 0 for left arrow and 1 for right arrow in param -#define IT_SUBMENU 4 // go to sub menu +//#define IT_SUBMENU 4 // go to sub menu #define IT_CVAR 8192 // handle as a cvar // display flags @@ -176,18 +175,21 @@ boolean M_CanShowLevelInList(INT32 mapnum, INT32 gt); //consvar specific #define IT_CV_SLIDER 64 #define IT_CV_STRING 128 -#define IT_CV_INTEGERSTEP 256 // if cvar is CV_FLOAT, modify it by 1 instead of 0.0625 +//#define IT_CV_INTEGERSTEP 256 // if cvar is CV_FLOAT, modify it by 1 instead of 0.0625 // extra flags #define IT_CENTER 512 // if IT_PATCH, center it on screen #define IT_HIDDEN 1024 // invisible, unselectable #define IT_GRAYEDOUT 2048 // grayed out, unselectable #define IT_SECRET 4096 // ??????? ???????????? +#define IT_OFSX 16384 // x coordinate is relative +#define IT_OFSY 32768 // ditto +#define IT_TEMPORARY 4 // offset is only applied temporarily +#define IT_OVERLAY 256 // no scrolling, draw at absolute coordinates // carefully chosen to not conflict with V_ flags #define MDF_CENTERED 0x20 #define MDF_TIMEATTACK 0x40 -#define MDF_CONTROLS 0x80 #define MAXSTRINGLENGTH 32 @@ -226,6 +228,8 @@ struct menu_t INT16 x, y; // x, y of menu INT16 scrollheight; // height of scrolling area INT16 lastOn; // last item user was on in menu + INT16 cursoroffset; // X offset of cursor + INT16 lineheight; // default Y offset to add for each item menufunc_f *enterroutine; // called before enter a menu menufunc_f *quitroutine; // called before quit a menu menufunc_f *keyhandler; // called before key press is processed @@ -333,7 +337,6 @@ void M_DrawReplayStartMenu(void); void M_DrawPlaybackMenu(void); void M_DrawImageDef(void); void M_DrawMusicTest(void); -void M_DrawControl(void); void M_DrawJoystick(void); void M_DrawMonitorToggles(void); #ifdef HAVE_DISCORDRPC