diff --git a/SpaceCadetPinball/TTextBox.cpp b/SpaceCadetPinball/TTextBox.cpp index 5467555..efeac20 100644 --- a/SpaceCadetPinball/TTextBox.cpp +++ b/SpaceCadetPinball/TTextBox.cpp @@ -4,6 +4,7 @@ #include "control.h" #include "fullscrn.h" #include "loader.h" +#include "pb.h" #include "render.h" #include "score.h" #include "timer.h" @@ -84,7 +85,7 @@ void TTextBox::Clear() OffsetX, OffsetY); else - gdrv::fill_bitmap(render::vscreen, Width, Height, OffsetX, OffsetY, 0); + gdrv::fill_bitmap(render::vscreen, Width, Height, OffsetX, OffsetY, 0); if (Timer) { if (Timer != -1) @@ -186,8 +187,7 @@ void TTextBox::Draw() if (display) { - auto font = Font; - if (!font) + if (!Font) { gdrv::grtext_draw_ttext_in_box( Message1->Text, @@ -199,64 +199,84 @@ void TTextBox::Draw() return; } - auto text = Message1->Text; - for (auto y = OffsetY; ; y += font->Height) + std::vector lines{}; + auto textHeight = 0; + for (auto text = Message1->Text; ; textHeight += Font->Height) { - auto curChar = *text; - if (!curChar || y + font->Height > OffsetY + Height) + if (!text[0] || textHeight + Font->Height > Height) break; - auto totalWidth = 0; - char* textEndSpace = nullptr; - auto textEnd = text; - while (true) - { - auto maskedChar = curChar & 0x7F; - if (!maskedChar || maskedChar == '\n') - break; - auto charBmp = font->Chars[maskedChar]; - if (charBmp) - { - auto width = charBmp->Width + font->GapWidth + totalWidth; - if (width > Width) - { - if (textEndSpace) - textEnd = textEndSpace; - break; - } - if (*textEnd == ' ') - textEndSpace = textEnd; - curChar = *(textEnd + 1); - totalWidth = width; - ++textEnd; - } - else - { - curChar = *textEnd; - } - } + auto line = LayoutTextLine(text); + if (line.Start == line.End) + break; + lines.push_back(line); + text = line.End; + } + // Textboxes in FT display texts centered + auto offY = OffsetY; + if (pb::FullTiltMode) + offY += (Height - textHeight) / 2; + for (auto line : lines) + { auto offX = OffsetX; - while (text < textEnd) + if (pb::FullTiltMode) + offX += (Width - line.Width) / 2; + for (auto text = line.Start; text < line.End; text++) { - auto charBmp = font->Chars[*text++ & 0x7F]; + auto charBmp = Font->Chars[*text & 0x7F]; if (charBmp) { auto height = charBmp->Height; auto width = charBmp->Width; if (render::background_bitmap) - gdrv::copy_bitmap_w_transparency(render::vscreen, width, height, offX, y, charBmp, 0, + gdrv::copy_bitmap_w_transparency(render::vscreen, width, height, offX, offY, charBmp, 0, 0); else - gdrv::copy_bitmap(render::vscreen, width, height, offX, y, charBmp, 0, 0); - font = Font; - offX += charBmp->Width + font->GapWidth; + gdrv::copy_bitmap(render::vscreen, width, height, offX, offY, charBmp, 0, 0); + offX += charBmp->Width + Font->GapWidth; } } - while ((*text & 0x7F) == ' ') - ++text; - if ((*text & 0x7F) == '\n') - ++text; + offY += Font->Height; } - } + } +} + +TTextBox::LayoutResult TTextBox::LayoutTextLine(char* textStart) const +{ + auto lineWidth = 0, wordWidth = 0; + char *wordBoundary = nullptr, *textEnd; + for (textEnd = textStart; ; ++textEnd) + { + auto maskedChar = textEnd[0] & 0x7F; + if (!maskedChar || maskedChar == '\n') + break; + + auto charBmp = Font->Chars[maskedChar]; + if (!charBmp) + continue; + + auto width = lineWidth + charBmp->Width + Font->GapWidth; + if (width > Width) + { + if (wordBoundary) + { + textEnd = wordBoundary; + lineWidth = wordWidth; + } + break; + } + if (maskedChar == ' ') + { + wordBoundary = textEnd; + wordWidth = width; + } + lineWidth = width; + } + + while ((*textEnd & 0x7F) == ' ') + ++textEnd; + if ((*textEnd & 0x7F) == '\n') + ++textEnd; + return LayoutResult{textStart, textEnd, lineWidth}; } diff --git a/SpaceCadetPinball/TTextBox.h b/SpaceCadetPinball/TTextBox.h index 3bcb174..ad2b908 100644 --- a/SpaceCadetPinball/TTextBox.h +++ b/SpaceCadetPinball/TTextBox.h @@ -22,7 +22,16 @@ public: int Message(int code, float value) override; void Clear(); void Display(const char* text, float time); - void Draw(); - static void TimerExpired(int timerId, void* tb); +private: + struct LayoutResult + { + char *Start, *End; + int Width; + }; + + static void TimerExpired(int timerId, void* caller); + + void Draw(); + LayoutResult LayoutTextLine(char* textStart) const; };