Improved handling of multi-line strings:

- Centered/right-aligned string drawing now properly handles newlines
- Measuring string width/height takes newlines into account
- String height also takes V_RETURN8 into account
- Cleaned up menu message code, removed now-redundant M_StringHeight
This commit is contained in:
spherallic 2023-03-09 11:20:26 +01:00
parent 759ac6cf35
commit 66042ef8a1
3 changed files with 87 additions and 182 deletions

View file

@ -4957,22 +4957,6 @@ static void M_DrawCenteredMenu(void)
} }
} }
//
// M_StringHeight
//
// Find string height from hu_font chars
//
static inline size_t M_StringHeight(const char *string)
{
size_t h = 8, i;
for (i = 0; i < strlen(string); i++)
if (string[i] == '\n')
h += 8;
return h;
}
// ========================================================================== // ==========================================================================
// Extraneous menu patching functions // Extraneous menu patching functions
// ========================================================================== // ==========================================================================
@ -6099,56 +6083,16 @@ menu_t MessageDef =
NULL NULL
}; };
void M_StartMessage(const char *string, void *routine, menumessagetype_t itemtype)
void M_StartMessage(const char *string, void *routine,
menumessagetype_t itemtype)
{ {
size_t max = 0, start = 0, i, strlines; static char *message;
static char *message = NULL;
Z_Free(message); Z_Free(message);
message = Z_StrDup(string); message = V_WordWrap(0,0,V_ALLOWLOWERCASE,string);
DEBFILE(message); DEBFILE(message);
// Rudementary word wrapping.
// Simple and effective. Does not handle nonuniform letter sizes, colors, etc. but who cares.
strlines = 0;
for (i = 0; message[i]; i++)
{
if (message[i] == ' ')
{
start = i;
max += 4;
}
else if (message[i] == '\n')
{
strlines = i;
start = 0;
max = 0;
continue;
}
else
max += 8;
// Start trying to wrap if presumed length exceeds the screen width.
if (max >= BASEVIDWIDTH && start > 0)
{
message[start] = '\n';
max -= (start-strlines)*8;
strlines = start;
start = 0;
}
}
start = 0;
max = 0;
M_StartControlPanel(); // can't put menuactive to true M_StartControlPanel(); // can't put menuactive to true
if (currentMenu == &MessageDef) // Prevent recursion MessageDef.prevMenu = (currentMenu == &MessageDef) ? &MainDef : currentMenu; // Prevent recursion
MessageDef.prevMenu = &MainDef;
else
MessageDef.prevMenu = currentMenu;
MessageDef.menuitems[0].text = message; MessageDef.menuitems[0].text = message;
MessageDef.menuitems[0].alphaKey = (UINT8)itemtype; MessageDef.menuitems[0].alphaKey = (UINT8)itemtype;
if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING; if (!routine && itemtype != MM_NOTHING) itemtype = MM_NOTHING;
@ -6167,51 +6111,17 @@ void M_StartMessage(const char *string, void *routine,
MessageDef.menuitems[0].itemaction = routine; MessageDef.menuitems[0].itemaction = routine;
break; break;
} }
//added : 06-02-98: now draw a textbox around the message MessageDef.x = (INT16)((BASEVIDWIDTH - V_StringWidth(message, 0)-32)/2);
// compute lenght max and the numbers of lines MessageDef.y = (INT16)((BASEVIDHEIGHT - V_StringHeight(message, V_RETURN8))/2);
for (strlines = 0; *(message+start); strlines++)
{
for (i = 0;i < strlen(message+start);i++)
{
if (*(message+start+i) == '\n')
{
if (i > max)
max = i;
start += i;
i = (size_t)-1; //added : 07-02-98 : damned!
start++;
break;
}
}
if (i == strlen(message+start))
start += i;
}
MessageDef.x = (INT16)((BASEVIDWIDTH - 8*max-16)/2);
MessageDef.y = (INT16)((BASEVIDHEIGHT - M_StringHeight(message))/2);
MessageDef.lastOn = (INT16)((strlines<<8)+max);
//M_SetupNextMenu();
currentMenu = &MessageDef; currentMenu = &MessageDef;
itemOn = 0; itemOn = 0;
} }
#define MAXMSGLINELEN 256
static void M_DrawMessageMenu(void) static void M_DrawMessageMenu(void)
{ {
INT32 y = currentMenu->y;
size_t i, start = 0;
INT16 max;
char string[MAXMSGLINELEN];
INT32 mlines;
const char *msg = currentMenu->menuitems[0].text; const char *msg = currentMenu->menuitems[0].text;
mlines = currentMenu->lastOn>>8;
max = (INT16)((UINT8)(currentMenu->lastOn & 0xFF)*8);
// hack: draw RA background in RA menus // hack: draw RA background in RA menus
if (gamestate == GS_TIMEATTACK) if (gamestate == GS_TIMEATTACK)
{ {
@ -6235,51 +6145,8 @@ static void M_DrawMessageMenu(void)
V_DrawFadeScreen(0xFF00, curfadevalue); V_DrawFadeScreen(0xFF00, curfadevalue);
} }
M_DrawTextBox(currentMenu->x, y - 8, (max+7)>>3, mlines); M_DrawTextBox(currentMenu->x, currentMenu->y - 8, 2+V_StringWidth(msg, 0)/8, V_StringHeight(msg, V_RETURN8)/8);
V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, V_ALLOWLOWERCASE|V_RETURN8, msg);
while (*(msg+start))
{
size_t len = strlen(msg+start);
for (i = 0; i < len; i++)
{
if (*(msg+start+i) == '\n')
{
memset(string, 0, MAXMSGLINELEN);
if (i >= MAXMSGLINELEN)
{
CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
return;
}
else
{
strncpy(string,msg+start, i);
string[i] = '\0';
start += i;
i = (size_t)-1; //added : 07-02-98 : damned!
start++;
}
break;
}
}
if (i == strlen(msg+start))
{
if (i >= MAXMSGLINELEN)
{
CONS_Printf("M_DrawMessageMenu: too long segment in %s\n", msg);
return;
}
else
{
strcpy(string, msg + start);
start += i;
}
}
V_DrawString((BASEVIDWIDTH - V_StringWidth(string, 0))/2,y,V_ALLOWLOWERCASE,string);
y += 8; //hu_font.chars[0]->height;
}
} }
// default message handler // default message handler

View file

@ -1990,10 +1990,7 @@ void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fi
flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK); flags = c & ~(V_CHARCOLORMASK | V_PARAMMASK);
c &= 0x7f; c &= 0x7f;
if (lowercaseallowed) c = (lowercaseallowed ? c : toupper(c)) - FONTSTART;
c -= FONTSTART;
else
c = toupper(c) - FONTSTART;
if (c < 0 || c >= FONTSIZE || !font.chars[c]) if (c < 0 || c >= FONTSIZE || !font.chars[c])
return; return;
@ -2009,8 +2006,7 @@ void V_DrawFontCharacter(INT32 x, INT32 y, INT32 c, boolean lowercaseallowed, fi
char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font) char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *string, fontdef_t font)
{ {
int c; int c;
size_t chw, i, lastusablespace = 0; size_t slen, chw, i, lastusablespace = 0;
size_t slen;
char *newstring = Z_StrDup(string); char *newstring = Z_StrDup(string);
INT32 spacewidth = font.spacewidth, charwidth = 0; INT32 spacewidth = font.spacewidth, charwidth = 0;
@ -2048,10 +2044,7 @@ char *V_FontWordWrap(INT32 x, INT32 w, INT32 option, fixed_t scale, const char *
continue; continue;
} }
if (!(option & V_ALLOWLOWERCASE)) c = (option & V_ALLOWLOWERCASE ? c : toupper(c)) - FONTSTART;
c = toupper(c);
c -= FONTSTART;
if (c < 0 || c >= FONTSIZE || !font.chars[c]) if (c < 0 || c >= FONTSIZE || !font.chars[c])
{ {
chw = spacewidth; chw = spacewidth;
@ -2148,20 +2141,11 @@ void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale,
if (*ch == '\n') if (*ch == '\n')
{ {
cx = x; cx = x;
cy += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, dupy);
if (option & V_RETURN8)
cy += FixedMul((8<<FRACBITS), dupy);
else
cy += FixedMul((font.linespacing<<FRACBITS), dupy);
continue; continue;
} }
c = *ch; c = (lowercase ? *ch : toupper(*ch)) - FONTSTART;
if (!lowercase)
c = toupper(c);
c -= FONTSTART;
if (c < 0 || c >= FONTSIZE || !font.chars[c]) if (c < 0 || c >= FONTSIZE || !font.chars[c])
{ {
cx += FixedMul((spacewidth<<FRACBITS), dupx); cx += FixedMul((spacewidth<<FRACBITS), dupx);
@ -2190,16 +2174,58 @@ void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale,
} }
} }
#define MAXLINELEN 256
void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, boolean center)
{
char line[MAXLINELEN];
size_t i, start = 0;
fixed_t lx = x, ly = y;
while (*(string+start))
{
for (i = 0; i < strlen(string+start); i++)
{
if (*(string+start+i) == '\n')
{
memset(line, 0, MAXLINELEN);
if (i >= MAXLINELEN)
{
CONS_Printf("V_DrawAlignedFontStringAtFixed: a line exceeds max. length %d (string: %s)\n", MAXLINELEN, string);
return;
}
strncpy(line,string + start, i);
line[i] = '\0';
start += i + 1;
i = (size_t)-1; //added : 07-02-98 : damned!
break;
}
}
if (i == strlen(string + start))
{
if (i >= MAXLINELEN)
{
CONS_Printf("V_DrawAlignedFontStringAtFixed: a line exceeds max. length %d (string: %s)\n", MAXLINELEN, string);
return;
}
strcpy(line, string + start);
start += i;
}
lx = x - (V_FontStringWidth(line, option, font)*pscale) / (center ? 2 : 1);
V_DrawFontStringAtFixed(lx, ly, option, pscale, vscale, line, font);
ly += FixedMul(((option & V_RETURN8) ? 8 : font.linespacing)<<FRACBITS, vscale);
}
}
void V_DrawCenteredFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font) void V_DrawCenteredFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
{ {
x -= (V_FontStringWidth(string, option, font)*pscale)/2; V_DrawAlignedFontStringAtFixed(x, y, option, pscale, vscale, string, font, true);
V_DrawFontStringAtFixed(x, y, option, pscale, vscale, string, font);
} }
void V_DrawRightAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font) void V_DrawRightAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font)
{ {
x -= V_FontStringWidth(string, option, font)*pscale; V_DrawAlignedFontStringAtFixed(x, y, option, pscale, vscale, string, font, false);
V_DrawFontStringAtFixed(x, y, option, pscale, vscale, string, font);
} }
// Draws a tallnum. Replaces two functions in y_inter and st_stuff // Draws a tallnum. Replaces two functions in y_inter and st_stuff
@ -2324,10 +2350,7 @@ static void V_DrawNameTagLine(INT32 x, INT32 y, INT32 option, fixed_t scale, UIN
continue; continue;
} }
c = toupper(*ch); c = toupper(*ch) - FONTSTART;
c -= FONTSTART;
// character does not exist or is a space
if (c < 0 || c >= FONTSIZE || !ntb_font.chars[c] || !nto_font.chars[c]) if (c < 0 || c >= FONTSIZE || !ntb_font.chars[c] || !nto_font.chars[c])
{ {
cx += FixedMul((ntb_font.spacewidth * dupx)*FRACUNIT, scale); cx += FixedMul((ntb_font.spacewidth * dupx)*FRACUNIT, scale);
@ -2464,9 +2487,8 @@ INT32 V_CountNameTagLines(const char *string)
// //
INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font) INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
{ {
INT32 c, w = 0; INT32 c, w = 0, wline = 0;
INT32 spacewidth = font.spacewidth, charwidth = 0; INT32 spacewidth = font.spacewidth, charwidth = 0;
size_t i;
switch (option & V_SPACINGMASK) switch (option & V_SPACINGMASK)
{ {
@ -2482,16 +2504,24 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
break; break;
} }
for (i = 0; i < strlen(string); i++) for (size_t i = 0; i < strlen(string); i++)
{ {
if (string[i] == '\n')
{
if (wline < w) wline = w;
w = 0;
continue;
}
if (string[i] & 0x80) if (string[i] & 0x80)
continue; continue;
c = ((option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART);
c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
if (c < 0 || c >= FONTSIZE || !font.chars[c]) if (c < 0 || c >= FONTSIZE || !font.chars[c])
w += spacewidth; w += spacewidth;
else else
w += (charwidth ? charwidth : (font.chars[c]->width)) + font.kerning; w += (charwidth ? charwidth : (font.chars[c]->width)) + font.kerning;
} }
w = max(wline, w);
if (option & (V_NOSCALESTART|V_NOSCALEPATCH)) if (option & (V_NOSCALESTART|V_NOSCALEPATCH))
w *= vid.dupx; w *= vid.dupx;
@ -2501,22 +2531,28 @@ INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font)
// Find max string height from supplied font characters // Find max string height from supplied font characters
// //
INT32 V_FontStringHeight(const char *string, fontdef_t font) INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font)
{ {
INT32 c, h = 0; INT32 c, h = 0, result = 0;
size_t i;
for (i = 0; i < strlen(string); i++) for (size_t i = 0; i < strlen(string); i++)
{ {
c = string[i] - FONTSTART; c = (option & V_ALLOWLOWERCASE ? string[i] : toupper(string[i])) - FONTSTART;
if (c < 0 || c >= FONTSIZE || !font.chars[c]) if (c < 0 || c >= FONTSIZE || !font.chars[c])
{
if (string[i] == '\n')
{
result += (option & V_RETURN8) ? 8 : font.linespacing;
h = 0;
}
continue; continue;
}
if (font.chars[c]->height > h) if (font.chars[c]->height > h)
h = font.chars[c]->height; h = font.chars[c]->height;
} }
return h; return result + h;
} }
boolean *heatshifter = NULL; boolean *heatshifter = NULL;

View file

@ -213,6 +213,7 @@ void V_DrawCenteredFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fi
void V_DrawRightAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); void V_DrawRightAlignedFontString(INT32 x, INT32 y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
// Draw a string, using a supplied font and scale, at fixed_t coordinates. // Draw a string, using a supplied font and scale, at fixed_t coordinates.
void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); void V_DrawFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
void V_DrawAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font, boolean center);
void V_DrawCenteredFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); void V_DrawCenteredFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
void V_DrawRightAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font); void V_DrawRightAlignedFontStringAtFixed(fixed_t x, fixed_t y, INT32 option, fixed_t pscale, fixed_t vscale, const char *string, fontdef_t font);
@ -266,7 +267,7 @@ INT32 V_CountNameTagLines(const char *string);
// Find string width or height from supplied font chars // Find string width or height from supplied font chars
INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font); INT32 V_FontStringWidth(const char *string, INT32 option, fontdef_t font);
INT32 V_FontStringHeight(const char *string, fontdef_t font); INT32 V_FontStringHeight(const char *string, INT32 option, fontdef_t font);
// Defines for old string width functions. // Defines for old string width functions.
#define V_StringWidth(str,o) V_FontStringWidth(str,o,hu_font) #define V_StringWidth(str,o) V_FontStringWidth(str,o,hu_font)
@ -276,7 +277,8 @@ INT32 V_FontStringHeight(const char *string, fontdef_t font);
#define V_CreditStringWidth(str) V_FontStringWidth(str,0,cred_font) #define V_CreditStringWidth(str) V_FontStringWidth(str,0,cred_font)
#define V_NameTagWidth(str) V_FontStringWidth(str,0,ntb_font) #define V_NameTagWidth(str) V_FontStringWidth(str,0,ntb_font)
#define V_LevelNameWidth(str) V_FontStringWidth(str,V_ALLOWLOWERCASE,lt_font) #define V_LevelNameWidth(str) V_FontStringWidth(str,V_ALLOWLOWERCASE,lt_font)
#define V_LevelNameHeight(str) V_FontStringHeight(str,lt_font) #define V_LevelNameHeight(str) V_FontStringHeight(str,0,lt_font)
#define V_StringHeight(str,o) V_FontStringHeight(str,o,hu_font)
void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param); void V_DoPostProcessor(INT32 view, postimg_t type, INT32 param);