1
0
mirror of https://github.com/TerryCavanagh/VVVVVV.git synced 2024-06-03 03:23:33 +02:00
VVVVVV/desktop_version/src/Textbox.cpp
Misa 12518b3c60 Save textbox state, allow lang switches w/ textbox
This allows switching languages while a text box is on screen by saving
the necessary state for a text box to be retranslated when the language
is switched.

This saves the state of the position and direction of the crewmate that
the text box position is based off of (if applicable), and the text
case of the text box, the script name of the script, and the original
(English) lines of the text box. I did not explicitly label the original
lines as English lines except in a main game context, because
technically, custom levels could have original lines in a different
language.

Unfortunately, this doesn't work for every text box in the game.
Notably, the Level Complete, Game Complete, number of crewmates
remaining, trinket collection, Intermission 1 guides, etc. text boxes
are special and require further fixes, but that will be coming in later
commits.
2024-02-02 15:02:16 -08:00

309 lines
6.6 KiB
C++

#include "Textbox.h"
#include <SDL.h>
#include "Font.h"
#include "Localization.h"
#include "UTF8.h"
textboxclass::textboxclass(int gap)
{
w = 0;
h = 0;
tl = 0;
prev_tl = 0;
tm = 0;
timer = 0;
xp = 0;
yp = 0;
r = 0;
g = 0;
b = 0;
linegap = gap;
flipme = false;
rand = 0;
large = false;
print_flags = PR_FONT_LEVEL;
fill_buttons = false;
sprites.clear();
image = TEXTIMAGE_NONE;
crewmate_position = TextboxCrewmatePosition();
original = TextboxOriginalContext();
original.text_case = 1;
}
void textboxclass::addsprite(int x, int y, int tile, int col)
{
TextboxSprite sprite;
sprite.x = x;
sprite.y = y;
sprite.tile = tile;
sprite.col = col;
sprites.push_back(sprite);
}
void textboxclass::setimage(TextboxImage new_image)
{
image = new_image;
}
void textboxclass::centerx(void)
{
resize();
xp = 160 - (w / 2);
resize();
}
void textboxclass::centery(void)
{
resize();
yp = 120 - (h / 2);
resize();
}
void textboxclass::adjust(void)
{
resize();
repositionfromcrewmate();
if (xp < 10) xp = 10;
if (yp < 10) yp = 10;
if (xp + w > 310) xp = 310 - w;
if (yp + h > 230) yp = 230 - h;
resize();
}
void textboxclass::initcol(int rr, int gg, int bb)
{
r = rr;
g = gg;
b = bb;
tl = 0.5;
}
void textboxclass::update(void)
{
prev_tl = tl;
if (tm == 0)
{
tl += .1f;
if (tl >= 1)
{
tl = 1;
tm = 1;
}
}
else if (tm == 2)
{
tl -= .1f;
if (tl <= 0.5)
{
tl = 0.5;
//this textbox will be removed by updatetextboxes() later
}
}
if (timer > 0)
{
timer--;
if (timer == 0) tm = 2;
}
}
void textboxclass::remove(void)
{
tm = 2;
tl = 1.0f; //Remove mode
}
void textboxclass::removefast(void)
{
tm = 2;
tl = 0.4f; //Remove mode
}
void textboxclass::resize(void)
{
//Set the width and height to the correct sizes
int max = 0;
for (size_t iter = 0; iter < lines.size(); iter++)
{
int len = font::len(print_flags, lines[iter].c_str());
if (len > max) max = len;
}
// 16 for the borders
w = max + 16;
h = lines.size()*(font::height(print_flags) + linegap) + 16 - linegap;
}
void textboxclass::repositionfromcrewmate(void)
{
const int font_height = font::height(print_flags);
// Reposition based off crewmate position, if applicable
if (crewmate_position.override_x)
{
if (crewmate_position.dir == 1) // left
{
xp = crewmate_position.x - w + 16;
}
else if (crewmate_position.dir == 0) // right
{
xp = crewmate_position.x - 16;
}
}
if (crewmate_position.override_y)
{
if (crewmate_position.text_above)
{
if (crewmate_position.dir == 1) // left
{
yp = crewmate_position.y - 16 - (lines.size() * (font_height + linegap) - linegap);
}
else if (crewmate_position.dir == 0) // right
{
yp = crewmate_position.y - 18 - (lines.size() * (font_height + linegap) - linegap);
}
}
else
{
yp = crewmate_position.y + 26;
}
}
}
void textboxclass::addline(const std::string& t)
{
lines.push_back(t);
resize();
if ((int)lines.size() > (large ? 26 : 11))
{
lines.clear();
}
}
void textboxclass::pad(size_t left_pad, size_t right_pad)
{
// Pad the current text with a certain number of spaces on the left and right
if (font::is_rtl(print_flags))
{
// Swap left and right, because left will end up on the right and vice versa...
size_t old_left_pad = left_pad;
left_pad = right_pad;
right_pad = old_left_pad;
}
for (size_t iter = 0; iter < lines.size(); iter++)
{
lines[iter] = std::string(left_pad, ' ') + lines[iter] + std::string(right_pad, ' ');
}
resize();
}
void textboxclass::padtowidth(size_t new_w)
{
/* Pad the current text so that each line is new_w pixels wide.
* Each existing line is centered in that width. */
resize();
uint8_t glyph_w = 8;
font::glyph_dimensions(print_flags, &glyph_w, NULL);
size_t chars_w = SDL_max(w-16, new_w) / glyph_w;
for (size_t iter = 0; iter < lines.size(); iter++)
{
size_t n_glyphs = font::len(print_flags, lines[iter].c_str()) / glyph_w;
signed int padding_needed = chars_w - n_glyphs;
if (padding_needed < 0)
{
continue;
}
size_t left_pad = padding_needed / 2;
size_t right_pad = padding_needed - left_pad;
lines[iter] = std::string(left_pad, ' ') + lines[iter] + std::string(right_pad, ' ');
}
resize();
}
void textboxclass::centertext(void)
{
padtowidth(w-16);
}
void textboxclass::translate(void)
{
if (!loc::is_cutscene_translated(original.script_name))
{
// Copy the original back
lines = std::vector<std::string>(original.lines);
return;
}
// English text needs to be un-wordwrapped, translated, and re-wordwrapped
std::string eng;
for (size_t i = 0; i < original.lines.size(); i++)
{
if (i != 0)
{
eng.append("\n");
}
eng.append(original.lines[i]);
}
eng = font::string_unwordwrap(eng);
const loc::TextboxFormat* format = loc::gettext_cutscene(original.script_name, eng, original.text_case);
if (format == NULL || format->text == NULL || format->text[0] == '\0')
{
return;
}
std::string tra;
if (format->tt)
{
tra = std::string(format->text);
size_t pipe;
while (true)
{
pipe = tra.find('|', 0);
if (pipe == std::string::npos)
{
break;
}
tra.replace(pipe, 1, "\n");
}
}
else
{
tra = font::string_wordwrap_balanced(PR_FONT_LEVEL, format->text, format->wraplimit);
}
lines.clear();
size_t startline = 0;
size_t newline;
do
{
newline = tra.find('\n', startline);
lines.push_back(tra.substr(startline, newline - startline));
startline = newline + 1;
}
while (newline != std::string::npos);
if (format->centertext)
{
centertext();
}
if (format->pad_left > 0 || format->pad_right > 0)
{
pad(format->pad_left, format->pad_right);
}
if (format->padtowidth > 0)
{
padtowidth(format->padtowidth);
}
}