diff --git a/src/v_text.cpp b/src/v_text.cpp index 47fbf6f1b..324e22bc0 100644 --- a/src/v_text.cpp +++ b/src/v_text.cpp @@ -47,11 +47,14 @@ #include "doomstat.h" #include "templates.h" +//========================================================================== // // DrawChar // // Write a single character using the given font // +//========================================================================== + void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int character, int tag_first, ...) { if (font == NULL) @@ -79,11 +82,14 @@ void DCanvas::DrawChar (FFont *font, int normalcolor, double x, double y, int ch } } +//========================================================================== // // DrawText // // Write a string using the given font // +//========================================================================== + void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *string, int tag_first, ...) { int w; @@ -167,9 +173,12 @@ void DCanvas::DrawText(FFont *font, int normalcolor, int x, int y, const char *s } +//========================================================================== // // Break long lines of text into multiple lines no longer than maxwidth pixels // +//========================================================================== + static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const BYTE *stop, FString &linecolor) { if (!linecolor.IsEmpty()) @@ -181,20 +190,19 @@ static void breakit (FBrokenLines *line, FFont *font, const BYTE *start, const B line->Width = font->StringWidth (line->Text); } -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor) +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool preservecolor, unsigned int *count) { - FBrokenLines lines[128]; // Support up to 128 lines (should be plenty) + TArray Lines(128); const BYTE *space = NULL, *start = string; - size_t i, ii; int c, w, nw; FString lastcolor, linecolor; bool lastWasSpace = false; int kerning = font->GetDefaultKerning (); - i = w = 0; + w = 0; - while ( (c = *string++) && i < countof(lines) ) + while ( (c = *string++) ) { if (c == TEXTCOLOR_ESCAPE) { @@ -241,14 +249,14 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool if (!space) space = string - 1; - breakit (&lines[i], font, start, space, linecolor); + auto index = Lines.Reserve(1); + breakit (&Lines[index], font, start, space, linecolor); if (c == '\n' && !preservecolor) { lastcolor = ""; // Why, oh why, did I do it like this? } linecolor = lastcolor; - i++; w = 0; lastWasSpace = false; start = space; @@ -270,7 +278,7 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool } // String here is pointing one character after the '\0' - if (i < countof(lines) && --string - start >= 1) + if (--string - start >= 1) { const BYTE *s = start; @@ -279,20 +287,25 @@ FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *string, bool // If there is any non-white space in the remainder of the string, add it. if (!isspace (*s++)) { - breakit (&lines[i++], font, start, string, linecolor); + auto i = Lines.Reserve(1); + breakit (&Lines[i], font, start, string, linecolor); break; } } } // Make a copy of the broken lines and return them - FBrokenLines *broken = new FBrokenLines[i+1]; + FBrokenLines *broken = new FBrokenLines[Lines.Size() + 1]; - for (ii = 0; ii < i; ++ii) + for (unsigned ii = 0; ii < Lines.Size(); ++ii) { - broken[ii] = lines[ii]; + broken[ii] = Lines[ii]; + } + broken[Lines.Size()].Width = -1; + if (count != nullptr) + { + *count = Lines.Size(); } - broken[ii].Width = -1; return broken; } @@ -304,3 +317,56 @@ void V_FreeBrokenLines (FBrokenLines *lines) delete[] lines; } } + +class DBrokenLines : public DObject +{ + DECLARE_ABSTRACT_CLASS(DBrokenLines, DObject) + +public: + FBrokenLines *mBroken; + unsigned int mCount; + + DBrokenLines(FBrokenLines *broken, unsigned int count) + { + mBroken = broken; + mCount = count; + } + + void OnDestroy() override + { + V_FreeBrokenLines(mBroken); + } +}; + +IMPLEMENT_CLASS(DBrokenLines, true, false); + +DEFINE_ACTION_FUNCTION(DBrokenLines, Count) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + ACTION_RETURN_INT(self->mCount); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringWidth) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_INT((unsigned)index >= self->mCount? -1 : self->mBroken[index].Width); +} + +DEFINE_ACTION_FUNCTION(DBrokenLines, StringAt) +{ + PARAM_SELF_PROLOGUE(DBrokenLines); + PARAM_INT(index); + ACTION_RETURN_STRING((unsigned)index >= self->mCount? -1 : self->mBroken[index].Text); +} + +DEFINE_ACTION_FUNCTION(FFont, BreakLines) +{ + PARAM_SELF_STRUCT_PROLOGUE(FFont); + PARAM_STRING(text); + PARAM_INT(maxwidth); + + unsigned int count; + FBrokenLines *broken = V_BreakLines(self, maxwidth, text, true, &count); + ACTION_RETURN_OBJECT(new DBrokenLines(broken, count)); +} diff --git a/src/v_text.h b/src/v_text.h index 3baf62af7..bd24be405 100644 --- a/src/v_text.h +++ b/src/v_text.h @@ -75,11 +75,11 @@ struct FBrokenLines #define TEXTCOLOR_CHAT "\034*" #define TEXTCOLOR_TEAMCHAT "\034!" -FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false); +FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const BYTE *str, bool preservecolor = false, unsigned int *count = nullptr); void V_FreeBrokenLines (FBrokenLines *lines); -inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor); } -inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false) - { return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor); } +inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const char *str, bool preservecolor = false, unsigned int *count = nullptr) + { return V_BreakLines (font, maxwidth, (const BYTE *)str, preservecolor, count); } +inline FBrokenLines *V_BreakLines (FFont *font, int maxwidth, const FString &str, bool preservecolor = false, unsigned int *count = nullptr) + { return V_BreakLines (font, maxwidth, (const BYTE *)str.GetChars(), preservecolor, count); } #endif //__V_TEXT_H__ diff --git a/wadsrc/static/zscript/base.txt b/wadsrc/static/zscript/base.txt index cb5239a37..57ec1b6df 100644 --- a/wadsrc/static/zscript/base.txt +++ b/wadsrc/static/zscript/base.txt @@ -68,6 +68,13 @@ struct Screen native native static void DrawHUDTexture(TextureID tex, double x, double y); } +class BrokenLines : Object native +{ + native int Count(); + native int StringWidth(int line); + native String StringAt(int line); +} + struct Font native { native int GetCharWidth(int code); @@ -75,6 +82,7 @@ struct Font native native static int FindFontColor(Name color); native static Font FindFont(Name fontname); native static Font GetFont(Name fontname); + native static BrokenLines BreakLines(String text, int maxlen); } struct Console native