Use textinput_t for replay save prompt too

This commit is contained in:
NepDisk 2025-08-15 12:24:17 -04:00
parent 99f7a522a7
commit 5de315225c
5 changed files with 137 additions and 39 deletions

View file

@ -28,6 +28,7 @@
#include "m_misc.h"
#include "m_menu.h"
#include "m_argv.h"
#include "m_textinput.h"
#include "hu_stuff.h"
#include "z_zone.h"
#include "i_video.h"
@ -2776,7 +2777,19 @@ void G_BeginRecording(void)
// Full replay title
demobuf.p += 64;
snprintf(demo.titlename, 64, "%s - %s", G_BuildMapTitle(gamemap), modeattacking ? "Record Attack" : connectedservername);
{
char demotitlename[65];
char *title = G_BuildMapTitle(gamemap);
// Print to a separate temp buffer instead of demo.titlename, so we can use it in M_TextInputSetString
snprintf(demotitlename, 64, "%s - %s", title, modeattacking ? "Time Attack" : connectedservername);
// Init just in case it isn't initialized already
M_TextInputInit(&demo.titlenameinput, demo.titlename, sizeof(demo.titlename));
// This will indirectly assign to demo.titlename too
M_TextInputSetString(&demo.titlenameinput, demotitlename);
Z_Free(title);
}
// demo checksum
demobuf.p += sizeof(UINT64);
@ -4410,7 +4423,6 @@ void G_SaveDemo(void)
boolean G_DemoTitleResponder(event_t *ev)
{
size_t len;
INT32 ch;
if (ev->type != ev_keydown)
@ -4431,28 +4443,7 @@ boolean G_DemoTitleResponder(event_t *ev)
return true;
}
if ((ch >= HU_FONTSTART && ch <= HU_FONTEND && fontv[HU_FONT].font[ch-HU_FONTSTART])
|| ch == ' ') // Allow spaces, of course
{
len = strlen(demo.titlename);
if (len < 64)
{
demo.titlename[len+1] = 0;
demo.titlename[len] = CON_ShiftChar(ch);
}
}
else if (ch == KEY_BACKSPACE)
{
if (shiftdown)
memset(demo.titlename, 0, sizeof(demo.titlename));
else
{
len = strlen(demo.titlename);
if (len > 0)
demo.titlename[len-1] = 0;
}
}
M_TextInputHandle(&demo.titlenameinput, ch);
return true;
}

View file

@ -17,6 +17,7 @@
#include "doomdef.h"
#include "doomstat.h"
#include "d_event.h"
#include "m_textinput.h"
#ifdef __cplusplus
extern "C" {
@ -46,6 +47,7 @@ typedef enum
// Publicly-accessible demo vars
struct demovars_s {
char titlename[65];
textinput_t titlenameinput;
boolean recording, playback, timing;
UINT16 version; // Current file format of the demo being played
boolean title; // Title Screen demo can be cancelled by any key

View file

@ -815,27 +815,83 @@ static void ST_overlayDrawer(void)
}
}
void ST_DrawDemoTitleEntry(void)
static void ST_DrawTextInput(INT32 x, INT32 y, textinput_t *input, INT32 flags)
{
static UINT8 skullAnimCounter = 0;
char *nametodraw;
static const INT32 MAXINPUTWIDTH = (MAXSTRINGLENGTH-1)*8;
if (renderisnewtic)
skullAnimCounter++;
skullAnimCounter %= 8;
nametodraw = demo.titlename;
while (V_StringWidth(nametodraw, 0) > MAXSTRINGLENGTH*8 - 8)
nametodraw++;
char nametodraw[MAXSTRINGLENGTH*2+1] = {0};
#define x (BASEVIDWIDTH/2 - 139)
#define y (BASEVIDHEIGHT/2)
size_t drawstart = 0;
size_t drawend = 0; // Only used for selection
INT32 skullx = x;
while (V_SubStringWidth(input->buffer+drawstart, input->cursor-drawstart, V_ALLOWLOWERCASE) > MAXINPUTWIDTH)
++drawstart;
size_t drawlength = V_SubStringLengthToFit(input->buffer+drawstart, MAXINPUTWIDTH+8, V_ALLOWLOWERCASE)+1;
drawend = drawstart + drawlength;
memcpy(nametodraw, input->buffer+drawstart, drawlength);
if (input->length)
skullx += V_SubStringWidth(nametodraw, input->cursor-drawstart, V_ALLOWLOWERCASE);
V_DrawString(x, y, V_ALLOWLOWERCASE|flags, nametodraw);
// draw text cursor for name
if (skullAnimCounter < 4) // blink cursor
V_DrawCharacter(skullx, y+3, '_'|flags, false);
// draw selection
if (input->select != input->cursor)
{
size_t start = min(input->select, input->cursor);
size_t end = max(input->select, input->cursor);
INT32 startx = 0;
INT32 width = 0;
// I couldn't figure out one formula so here's bunch of separate cases
if (start < drawstart && end > drawend) // Selection covers whole visible portion of demo name
{
startx = -2;
width = V_StringWidth(nametodraw, V_ALLOWLOWERCASE);
}
else if (start < drawstart) // Only left side of selection is off visible part
{
startx = -2;
size_t len = (end - start) - (drawstart - start);
width = V_SubStringWidth(nametodraw, len, V_ALLOWLOWERCASE)+2;
}
else if (end > drawend) // Only right side of selection is off visible part
{
startx = V_SubStringWidth(nametodraw, start-drawstart, V_ALLOWLOWERCASE);
width = V_StringWidth(nametodraw+(start-drawstart), V_ALLOWLOWERCASE)+2;
}
else // All selection is on visible part
{
startx = V_SubStringWidth(nametodraw, start-drawstart, V_ALLOWLOWERCASE);
width = V_SubStringWidth(nametodraw+(start-drawstart), end-start, V_ALLOWLOWERCASE);
}
V_DrawFill(x+startx, y, width, 8, 103|V_TRANSLUCENT|flags);
}
}
void ST_DrawDemoTitleEntry(void)
{
#define x (BASEVIDWIDTH/2 - 139)
#define y (BASEVIDHEIGHT/2)
M_DrawTextBox(x, y + 4, MAXSTRINGLENGTH, 1);
V_DrawString(x + 8, y + 12, V_ALLOWLOWERCASE, nametodraw);
if (skullAnimCounter < 4)
V_DrawCharacter(x + 8 + V_StringWidth(nametodraw, 0), y + 12,
'_' | 0x80, false);
ST_DrawTextInput(x + 8, y + 12, &demo.titlenameinput, 0);
M_DrawTextBox(x + 30, y - 24, 26, 1);
V_DrawString(x + 38, y - 16, V_ALLOWLOWERCASE, "Enter the name of the replay.");
@ -843,8 +899,8 @@ void ST_DrawDemoTitleEntry(void)
M_DrawTextBox(x + 50, y + 20, 20, 1);
V_DrawThinString(x + 58, y + 28, V_ALLOWLOWERCASE, "Escape - Cancel");
V_DrawRightAlignedThinString(x + 220, y + 28, V_ALLOWLOWERCASE, "Enter - Confirm");
#undef x
#undef y
#undef x
#undef y
}
// MayonakaStatic: draw Midnight Channel's TV-like borders

View file

@ -3079,7 +3079,7 @@ INT32 V_ThinSubStringWidth(const char *string, INT32 length, INT32 option)
else
{
w += (charwidth ? charwidth
: ((option & V_6WIDTHSPACE && i < strlen(string)-1) ? max(1, fontv[TINY_FONT].font[c]->width-1) // Reuse this flag for the alternate bunched-up spacing
: ((option & V_6WIDTHSPACE && i < (ssize_t)strlen(string)-1) ? max(1, fontv[TINY_FONT].font[c]->width-1) // Reuse this flag for the alternate bunched-up spacing
: fontv[TINY_FONT].font[c]->width));
}
}
@ -3097,6 +3097,53 @@ INT32 V_SmallThinStringWidth(const char *string, INT32 option)
return w/2 + FRACUNIT; // +FRACUNIT because otherwise it's offset wrong.
}
//
// Find maximum length for substring taken from current string to fit into given width
//
INT32 V_SubStringLengthToFit(const char *string, INT32 width, INT32 option)
{
INT32 c, w = 0;
INT32 spacewidth = 4, charwidth = 0;
INT32 i;
switch (option & V_SPACINGMASK)
{
case V_MONOSPACE:
spacewidth = 8;
/* FALLTHRU */
case V_OLDSPACING:
charwidth = 8;
break;
case V_6WIDTHSPACE:
spacewidth = 6;
break;
default:
break;
}
for (i = 0; string[i] && w < width; i++)
{
c = string[i];
if ((UINT8)c >= 0x80 && (UINT8)c <= 0x8F) //color parsing! -Inuyasha 2.16.09
continue;
c = toupper(c) - HU_FONTSTART;
if (c < 0 || c >= HU_FONTSIZE || !fontv[HU_FONT].font[c])
w += spacewidth;
else
w += (charwidth ? charwidth : fontv[HU_FONT].font[c]->width);
}
return max(i-1, 0);
}
boolean *heatshifter = NULL;
INT32 lastheight = 0;
INT32 heatindex[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0};

View file

@ -338,6 +338,8 @@ INT32 V_SmallSubStringWidth(const char *string, INT32 length, INT32 option);
INT32 V_ThinSubStringWidth(const char *string, INT32 length, INT32 option);
#define V_ThinStringWidth(string, option) V_ThinSubStringWidth(string, -1, option)
INT32 V_SubStringLengthToFit(const char *string, INT32 width, INT32 option);
void V_DoPostProcessor(INT32 view, INT32 param);
void V_DrawPatchFill(patch_t *pat);