mirror of https://github.com/OpenTTD/OpenTTD
(svn r25472) -Cleanup: remove the old methods for drawing text
parent
8bbbb1b37a
commit
f980d1a43c
537
src/gfx.cpp
537
src/gfx.cpp
|
@ -363,128 +363,6 @@ static void SetColourRemap(TextColour colour)
|
||||||
_colour_remap_ptr = _string_colourremap;
|
_colour_remap_ptr = _string_colourremap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(WITH_ICU)
|
|
||||||
static WChar *HandleBiDiAndArabicShapes(WChar *text) { return text; }
|
|
||||||
#else
|
|
||||||
#include <unicode/ubidi.h>
|
|
||||||
#include <unicode/ushape.h>
|
|
||||||
#include <unicode/ustring.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to be able to handle right-to-left text and Arabic chars properly.
|
|
||||||
*
|
|
||||||
* First: right-to-left (RTL) is stored 'logically' in almost all applications
|
|
||||||
* and so do we. This means that their text is stored from right to the
|
|
||||||
* left in memory and any non-RTL text (like numbers or English) are
|
|
||||||
* then stored from left-to-right. When we want to actually draw the
|
|
||||||
* text we need to reverse the RTL text in memory, which is what
|
|
||||||
* happens in ubidi_writeReordered.
|
|
||||||
* Second: Arabic characters "differ" based on their context. To draw the
|
|
||||||
* correct variant we pass it through u_shapeArabic. This function can
|
|
||||||
* add or remove some characters. This is the reason for the lastof
|
|
||||||
* so we know till where we can fill the output.
|
|
||||||
*
|
|
||||||
* Sadly enough these functions work with a custom character format, UChar,
|
|
||||||
* which isn't the same size as WChar. Because of that we need to transform
|
|
||||||
* our text first to UChars and then back to something we can use.
|
|
||||||
*
|
|
||||||
* To be able to truncate strings properly you must truncate before passing to
|
|
||||||
* this function. This way the logical begin of the string remains and the end
|
|
||||||
* gets chopped of instead of the other way around.
|
|
||||||
*
|
|
||||||
* The reshaping of Arabic characters might increase or decrease the width of
|
|
||||||
* the characters/string. So it might still overflow after truncation, though
|
|
||||||
* the chance is fairly slim as most characters get shorter instead of longer.
|
|
||||||
* @param buffer the buffer to read from/to
|
|
||||||
* @param lastof the end of the buffer
|
|
||||||
* @return the buffer to draw from
|
|
||||||
*/
|
|
||||||
static WChar *HandleBiDiAndArabicShapes(WChar *buffer)
|
|
||||||
{
|
|
||||||
UChar input[DRAW_STRING_BUFFER];
|
|
||||||
UChar intermediate[DRAW_STRING_BUFFER];
|
|
||||||
static WChar output[DRAW_STRING_BUFFER];
|
|
||||||
|
|
||||||
/* Transform from UTF-32 to internal ICU format of UTF-16. */
|
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
|
||||||
int32_t length = 0;
|
|
||||||
u_strFromUTF32(input, lengthof(input), &length, (UChar32 *)buffer, -1, &err);
|
|
||||||
if (U_FAILURE(err)) return buffer;
|
|
||||||
|
|
||||||
UBiDi *para = ubidi_openSized(length, 0, &err);
|
|
||||||
if (para == NULL) return buffer;
|
|
||||||
|
|
||||||
ubidi_setPara(para, input, length, _current_text_dir == TD_RTL ? UBIDI_DEFAULT_RTL : UBIDI_DEFAULT_LTR, NULL, &err);
|
|
||||||
length = ubidi_writeReordered(para, intermediate, lengthof(intermediate), UBIDI_REMOVE_BIDI_CONTROLS, &err);
|
|
||||||
length = u_shapeArabic(intermediate, length, input, lengthof(input), U_SHAPE_TEXT_DIRECTION_VISUAL_LTR | U_SHAPE_LETTERS_SHAPE, &err);
|
|
||||||
ubidi_close(para);
|
|
||||||
if (U_FAILURE(err)) return buffer;
|
|
||||||
|
|
||||||
/* Transform back to UTF-32. */
|
|
||||||
u_strToUTF32((UChar32 *)output, lengthof(output), NULL, input, length, &err);
|
|
||||||
if (U_FAILURE(err)) return buffer;
|
|
||||||
|
|
||||||
/* u_strToUTF32 doesn't add a NUL charcter if the buffer is too small, be safe. */
|
|
||||||
output[lengthof(output) - 1] = '\0';
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
#endif /* WITH_ICU */
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Truncate a given string to a maximum width if necessary.
|
|
||||||
* If the string is truncated, add three dots ('...') to show this.
|
|
||||||
* @param *str string that is checked and possibly truncated
|
|
||||||
* @param maxw maximum width in pixels of the string
|
|
||||||
* @param start_fontsize Fontsize to start the text with
|
|
||||||
* @return new width of (truncated) string
|
|
||||||
*/
|
|
||||||
static int TruncateString(char *str, int maxw, FontSize start_fontsize)
|
|
||||||
{
|
|
||||||
int w = 0;
|
|
||||||
FontSize size = start_fontsize;
|
|
||||||
int ddd, ddd_w;
|
|
||||||
|
|
||||||
WChar c;
|
|
||||||
char *ddd_pos;
|
|
||||||
|
|
||||||
ddd_w = ddd = GetCharacterWidth(size, '.') * 3;
|
|
||||||
|
|
||||||
for (ddd_pos = str; (c = Utf8Consume(const_cast<const char **>(&str))) != '\0'; ) {
|
|
||||||
if (IsPrintable(c) && !IsTextDirectionChar(c)) {
|
|
||||||
w += GetCharacterWidth(size, c);
|
|
||||||
|
|
||||||
if (w > maxw) {
|
|
||||||
/* string got too big... insert dotdotdot, but make sure we do not
|
|
||||||
* print anything beyond the string termination character. */
|
|
||||||
for (int i = 0; *ddd_pos != '\0' && i < 3; i++, ddd_pos++) *ddd_pos = '.';
|
|
||||||
*ddd_pos = '\0';
|
|
||||||
return ddd_w;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (c == SCC_TINYFONT) {
|
|
||||||
size = FS_SMALL;
|
|
||||||
ddd = GetCharacterWidth(size, '.') * 3;
|
|
||||||
} else if (c == SCC_BIGFONT) {
|
|
||||||
size = FS_LARGE;
|
|
||||||
ddd = GetCharacterWidth(size, '.') * 3;
|
|
||||||
} else if (c == '\n') {
|
|
||||||
DEBUG(misc, 0, "Drawing string using newlines with DrawString instead of DrawStringMultiLine. Please notify the developers of this: [%s]", str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remember the last position where three dots fit. */
|
|
||||||
if (w + ddd < maxw) {
|
|
||||||
ddd_w = w + ddd;
|
|
||||||
ddd_pos = str;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ReallyDoDrawString(const WChar *string, int x, int y, DrawStringParams ¶ms, bool parse_string_also_when_clipped = false);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Drawing routine for drawing a laid out line of text.
|
* Drawing routine for drawing a laid out line of text.
|
||||||
* @param line String to draw.
|
* @param line String to draw.
|
||||||
|
@ -632,109 +510,6 @@ static int DrawLayoutLine(ParagraphLayout::Line *line, int y, int left, int righ
|
||||||
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;
|
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the real width of the string.
|
|
||||||
* @param str the string to draw
|
|
||||||
* @param start_fontsize Fontsize to start the text with
|
|
||||||
* @return the width.
|
|
||||||
*/
|
|
||||||
static int GetStringWidth(const WChar *str, FontSize start_fontsize)
|
|
||||||
{
|
|
||||||
FontSize size = start_fontsize;
|
|
||||||
int max_width;
|
|
||||||
int width;
|
|
||||||
WChar c;
|
|
||||||
|
|
||||||
width = max_width = 0;
|
|
||||||
for (;;) {
|
|
||||||
c = *str++;
|
|
||||||
if (c == 0) break;
|
|
||||||
if (IsPrintable(c) && !IsTextDirectionChar(c)) {
|
|
||||||
width += GetCharacterWidth(size, c);
|
|
||||||
} else {
|
|
||||||
switch (c) {
|
|
||||||
case SCC_TINYFONT: size = FS_SMALL; break;
|
|
||||||
case SCC_BIGFONT: size = FS_LARGE; break;
|
|
||||||
case '\n':
|
|
||||||
max_width = max(max_width, width);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return max(max_width, width);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw string, possibly truncated to make it fit in its allocated space
|
|
||||||
*
|
|
||||||
* @param left The left most position to draw on.
|
|
||||||
* @param right The right most position to draw on.
|
|
||||||
* @param top The top most position to draw on.
|
|
||||||
* @param str String to draw.
|
|
||||||
* @param last The end of the string buffer to draw.
|
|
||||||
* @param params Text drawing parameters.
|
|
||||||
* @param align The alignment of the string when drawing left-to-right. In the
|
|
||||||
* case a right-to-left language is chosen this is inverted so it
|
|
||||||
* will be drawn in the right direction.
|
|
||||||
* @param underline Whether to underline what has been drawn or not.
|
|
||||||
* @param truncate Whether to truncate the string or not.
|
|
||||||
*
|
|
||||||
* @return In case of left or center alignment the right most pixel we have drawn to.
|
|
||||||
* In case of right alignment the left most pixel we have drawn to.
|
|
||||||
*/
|
|
||||||
static int DrawString(int left, int right, int top, char *str, const char *last, DrawStringParams ¶ms, StringAlignment align, bool underline = false, bool truncate = true)
|
|
||||||
{
|
|
||||||
if (truncate) TruncateString(str, right - left + 1, params.fontsize);
|
|
||||||
|
|
||||||
WChar draw_buffer[DRAW_STRING_BUFFER];
|
|
||||||
WChar *p = draw_buffer;
|
|
||||||
|
|
||||||
const char *text = str;
|
|
||||||
for (WChar c = Utf8Consume(&text); c != '\0'; c = Utf8Consume(&text)) {
|
|
||||||
*p++ = c;
|
|
||||||
}
|
|
||||||
*p++ = '\0';
|
|
||||||
|
|
||||||
/* In case we have a RTL language we swap the alignment. */
|
|
||||||
if (!(align & SA_FORCE) && _current_text_dir == TD_RTL && (align & SA_HOR_MASK) != SA_HOR_CENTER) align ^= SA_RIGHT;
|
|
||||||
|
|
||||||
WChar *to_draw = HandleBiDiAndArabicShapes(draw_buffer);
|
|
||||||
int w = GetStringWidth(to_draw, params.fontsize);
|
|
||||||
|
|
||||||
/* right is the right most position to draw on. In this case we want to do
|
|
||||||
* calculations with the width of the string. In comparison right can be
|
|
||||||
* seen as lastof(todraw) and width as lengthof(todraw). They differ by 1.
|
|
||||||
* So most +1/-1 additions are to move from lengthof to 'indices'.
|
|
||||||
*/
|
|
||||||
switch (align & SA_HOR_MASK) {
|
|
||||||
case SA_LEFT:
|
|
||||||
/* right + 1 = left + w */
|
|
||||||
right = left + w - 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SA_HOR_CENTER:
|
|
||||||
left = RoundDivSU(right + 1 + left - w, 2);
|
|
||||||
/* right + 1 = left + w */
|
|
||||||
right = left + w - 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SA_RIGHT:
|
|
||||||
left = right + 1 - w;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
ReallyDoDrawString(to_draw, left, top, params, !truncate);
|
|
||||||
if (underline) {
|
|
||||||
GfxFillRect(left, top + FONT_HEIGHT_NORMAL, right, top + FONT_HEIGHT_NORMAL, _string_colourremap[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (align & SA_HOR_MASK) == SA_RIGHT ? left : right;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw string, possibly truncated to make it fit in its allocated space
|
* Draw string, possibly truncated to make it fit in its allocated space
|
||||||
*
|
*
|
||||||
|
@ -778,141 +553,6 @@ int DrawString(int left, int right, int top, StringID str, TextColour colour, St
|
||||||
return DrawString(left, right, top, buffer, colour, align, underline, fontsize);
|
return DrawString(left, right, top, buffer, colour, align, underline, fontsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 'Correct' a string to a maximum length. Longer strings will be cut into
|
|
||||||
* additional lines at whitespace characters if possible. The string parameter
|
|
||||||
* is modified with terminating characters mid-string which are the
|
|
||||||
* placeholders for the newlines.
|
|
||||||
* The string WILL be truncated if there was no whitespace for the current
|
|
||||||
* line's maximum width.
|
|
||||||
*
|
|
||||||
* @note To know if the terminating '\0' is the string end or just a
|
|
||||||
* newline, the returned 'num' value should be consulted. The num'th '\0',
|
|
||||||
* starting with index 0 is the real string end.
|
|
||||||
*
|
|
||||||
* @param str string to check and correct for length restrictions
|
|
||||||
* @param last the last valid location (for '\0') in the buffer of str
|
|
||||||
* @param maxw the maximum width the string can have on one line
|
|
||||||
* @param size Fontsize to start the text with
|
|
||||||
* @return return a 32bit wide number consisting of 2 packed values:
|
|
||||||
* 0 - 15 the number of lines ADDED to the string
|
|
||||||
* 16 - 31 the fontsize in which the length calculation was done at
|
|
||||||
*/
|
|
||||||
static uint32 FormatStringLinebreaks(char *str, const char *last, int maxw, FontSize size = FS_NORMAL)
|
|
||||||
{
|
|
||||||
int num = 0;
|
|
||||||
|
|
||||||
assert(maxw > 0);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
/* The character *after* the last space. */
|
|
||||||
char *last_space = NULL;
|
|
||||||
int w = 0;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
WChar c = Utf8Consume(const_cast<const char **>(&str));
|
|
||||||
/* whitespace is where we will insert the line-break */
|
|
||||||
if (IsWhitespace(c)) last_space = str;
|
|
||||||
|
|
||||||
if (IsPrintable(c) && !IsTextDirectionChar(c)) {
|
|
||||||
int char_w = GetCharacterWidth(size, c);
|
|
||||||
w += char_w;
|
|
||||||
if (w > maxw) {
|
|
||||||
/* The string is longer than maximum width so we need to decide
|
|
||||||
* what to do with it. */
|
|
||||||
if (w == char_w) {
|
|
||||||
/* The character is wider than allowed width; don't know
|
|
||||||
* what to do with this case... bail out! */
|
|
||||||
return num + (size << 16);
|
|
||||||
}
|
|
||||||
if (last_space == NULL) {
|
|
||||||
/* No space has been found. Just terminate at our current
|
|
||||||
* location. This usually happens for languages that do not
|
|
||||||
* require spaces in strings, like Chinese, Japanese and
|
|
||||||
* Korean. For other languages terminating mid-word might
|
|
||||||
* not be the best, but terminating the whole string instead
|
|
||||||
* of continuing the word at the next line is worse. */
|
|
||||||
str = Utf8PrevChar(str);
|
|
||||||
size_t len = strlen(str);
|
|
||||||
char *terminator = str + len;
|
|
||||||
|
|
||||||
/* The string location + length of the string + 1 for '\0'
|
|
||||||
* always fits; otherwise there's no trailing '\0' and it
|
|
||||||
* it not a valid string. */
|
|
||||||
assert(terminator <= last);
|
|
||||||
assert(*terminator == '\0');
|
|
||||||
|
|
||||||
/* If the string is too long we have to terminate it earlier. */
|
|
||||||
if (terminator == last) {
|
|
||||||
/* Get the 'begin' of the previous character and make that
|
|
||||||
* the terminator of the string; we truncate it 'early'. */
|
|
||||||
*Utf8PrevChar(terminator) = '\0';
|
|
||||||
len = strlen(str);
|
|
||||||
}
|
|
||||||
/* Also move the terminator! */
|
|
||||||
memmove(str + 1, str, len + 1);
|
|
||||||
*str = '\0';
|
|
||||||
/* str needs to point to the character *after* the last space */
|
|
||||||
str++;
|
|
||||||
} else {
|
|
||||||
/* A space is found; perfect place to terminate */
|
|
||||||
str = last_space;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch (c) {
|
|
||||||
case '\0': return num + (size << 16);
|
|
||||||
case SCC_TINYFONT: size = FS_SMALL; break;
|
|
||||||
case SCC_BIGFONT: size = FS_LARGE; break;
|
|
||||||
case '\n': goto end_of_inner_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end_of_inner_loop:
|
|
||||||
/* String didn't fit on line (or a '\n' was encountered), so 'dummy' terminate
|
|
||||||
* and increase linecount. We use Utf8PrevChar() as also non 1 char long
|
|
||||||
* whitespace separators are supported */
|
|
||||||
num++;
|
|
||||||
char *s = Utf8PrevChar(str);
|
|
||||||
*s++ = '\0';
|
|
||||||
|
|
||||||
/* In which case (see above) we will shift remainder to left and close the gap */
|
|
||||||
if (str - s >= 1) {
|
|
||||||
for (; str[-1] != '\0';) *s++ = *str++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates height of string (in pixels). Accepts multiline string with '\0' as separators.
|
|
||||||
* @param src string to check
|
|
||||||
* @param num number of extra lines (output of FormatStringLinebreaks())
|
|
||||||
* @param start_fontsize Fontsize to start the text with
|
|
||||||
* @note assumes text won't be truncated. FormatStringLinebreaks() is a good way to ensure that.
|
|
||||||
* @return height of pixels of string when it is drawn
|
|
||||||
*/
|
|
||||||
static int GetMultilineStringHeight(const char *src, int num, FontSize start_fontsize)
|
|
||||||
{
|
|
||||||
int maxy = 0;
|
|
||||||
int y = 0;
|
|
||||||
int fh = GetCharacterHeight(start_fontsize);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
WChar c = Utf8Consume(&src);
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
case 0: y += fh; if (--num < 0) return maxy; break;
|
|
||||||
case '\n': y += fh; break;
|
|
||||||
case SCC_TINYFONT: fh = GetCharacterHeight(FS_SMALL); break;
|
|
||||||
case SCC_BIGFONT: fh = GetCharacterHeight(FS_LARGE); break;
|
|
||||||
default: maxy = max<int>(maxy, y + fh); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates height of string (in pixels). The string is changed to a multiline string if needed.
|
* Calculates height of string (in pixels). The string is changed to a multiline string if needed.
|
||||||
* @param str string to check
|
* @param str string to check
|
||||||
|
@ -977,103 +617,6 @@ Dimension GetStringMultiLineBoundingBox(const char *str, const Dimension &sugges
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw string, possibly over multiple lines.
|
|
||||||
*
|
|
||||||
* @param left The left most position to draw on.
|
|
||||||
* @param right The right most position to draw on.
|
|
||||||
* @param top The top most position to draw on.
|
|
||||||
* @param bottom The bottom most position to draw on.
|
|
||||||
* @param str String to draw.
|
|
||||||
* @param last The end of the string buffer to draw.
|
|
||||||
* @param colour Colour used for drawing the string, see DoDrawString() for details
|
|
||||||
* @param align The horizontal and vertical alignment of the string.
|
|
||||||
* @param underline Whether to underline all strings
|
|
||||||
* @param fontsize The size of the initial characters.
|
|
||||||
*
|
|
||||||
* @return If \a align is #SA_BOTTOM, the top to where we have written, else the bottom to where we have written.
|
|
||||||
*/
|
|
||||||
static int DrawStringMultiLine(int left, int right, int top, int bottom, char *str, const char *last, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
|
|
||||||
{
|
|
||||||
int maxw = right - left + 1;
|
|
||||||
int maxh = bottom - top + 1;
|
|
||||||
|
|
||||||
/* It makes no sense to even try if it can't be drawn anyway, or
|
|
||||||
* do we really want to support fonts of 0 or less pixels high? */
|
|
||||||
if (maxh <= 0) return top;
|
|
||||||
|
|
||||||
uint32 tmp = FormatStringLinebreaks(str, last, maxw);
|
|
||||||
int num = GB(tmp, 0, 16) + 1;
|
|
||||||
|
|
||||||
int mt = GetCharacterHeight((FontSize)GB(tmp, 16, 16));
|
|
||||||
int total_height = num * mt;
|
|
||||||
|
|
||||||
int skip_lines = 0;
|
|
||||||
if (total_height > maxh) {
|
|
||||||
if (maxh < mt) return top; // Not enough room for a single line.
|
|
||||||
if ((align & SA_VERT_MASK) == SA_BOTTOM) {
|
|
||||||
skip_lines = num;
|
|
||||||
num = maxh / mt;
|
|
||||||
skip_lines -= num;
|
|
||||||
} else {
|
|
||||||
num = maxh / mt;
|
|
||||||
}
|
|
||||||
total_height = num * mt;
|
|
||||||
}
|
|
||||||
|
|
||||||
int y;
|
|
||||||
switch (align & SA_VERT_MASK) {
|
|
||||||
case SA_TOP:
|
|
||||||
y = top;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SA_VERT_CENTER:
|
|
||||||
y = RoundDivSU(bottom + top - total_height, 2);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SA_BOTTOM:
|
|
||||||
y = bottom - total_height;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *src = str;
|
|
||||||
DrawStringParams params(colour, fontsize);
|
|
||||||
int written_top = bottom; // Uppermost position of rendering a line of text
|
|
||||||
for (;;) {
|
|
||||||
if (skip_lines == 0) {
|
|
||||||
char buf2[DRAW_STRING_BUFFER];
|
|
||||||
strecpy(buf2, src, lastof(buf2));
|
|
||||||
DrawString(left, right, y, buf2, lastof(buf2), params, align, underline, false);
|
|
||||||
if (written_top > y) written_top = y;
|
|
||||||
y += mt;
|
|
||||||
num--;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
WChar c = Utf8Consume(&src);
|
|
||||||
if (c == 0) {
|
|
||||||
break;
|
|
||||||
} else if (skip_lines > 0) {
|
|
||||||
/* Skipped drawing, so do additional processing to update params. */
|
|
||||||
if (c >= SCC_BLUE && c <= SCC_BLACK) {
|
|
||||||
params.SetColour((TextColour)(c - SCC_BLUE));
|
|
||||||
} else if (c == SCC_PREVIOUS_COLOUR) { // Revert to the previous colour.
|
|
||||||
params.SetPreviousColour();
|
|
||||||
} else if (c == SCC_TINYFONT) {
|
|
||||||
params.SetFontSize(FS_SMALL);
|
|
||||||
} else if (c == SCC_BIGFONT) {
|
|
||||||
params.SetFontSize(FS_LARGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (skip_lines > 0) skip_lines--;
|
|
||||||
if (num == 0) return ((align & SA_VERT_MASK) == SA_BOTTOM) ? written_top : y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw string, possibly over multiple lines.
|
* Draw string, possibly over multiple lines.
|
||||||
*
|
*
|
||||||
|
@ -1201,86 +744,6 @@ void DrawCharCentered(WChar c, int x, int y, TextColour colour)
|
||||||
GfxMainBlitter(GetGlyph(FS_NORMAL, c), x - GetCharacterWidth(FS_NORMAL, c) / 2, y, BM_COLOUR_REMAP);
|
GfxMainBlitter(GetGlyph(FS_NORMAL, c), x - GetCharacterWidth(FS_NORMAL, c) / 2, y, BM_COLOUR_REMAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Draw a string at the given coordinates with the given colour.
|
|
||||||
* While drawing the string, parse it in case some formatting is specified,
|
|
||||||
* like new colour, new size or even positioning.
|
|
||||||
* @param string The string to draw. This is already bidi reordered.
|
|
||||||
* @param x Offset from left side of the screen
|
|
||||||
* @param y Offset from top side of the screen
|
|
||||||
* @param params Text drawing parameters
|
|
||||||
* @param parse_string_also_when_clipped
|
|
||||||
* By default, always test the available space where to draw the string.
|
|
||||||
* When in multiline drawing, it would already be done,
|
|
||||||
* so no need to re-perform the same kind (more or less) of verifications.
|
|
||||||
* It's not only an optimisation, it's also a way to ensures the string will be parsed
|
|
||||||
* (as there are certain side effects on global variables, which are important for the next line)
|
|
||||||
* @return the x-coordinates where the drawing has finished.
|
|
||||||
* If nothing is drawn, the originally passed x-coordinate is returned
|
|
||||||
*/
|
|
||||||
static int ReallyDoDrawString(const WChar *string, int x, int y, DrawStringParams ¶ms, bool parse_string_also_when_clipped)
|
|
||||||
{
|
|
||||||
DrawPixelInfo *dpi = _cur_dpi;
|
|
||||||
bool draw_shadow = GetDrawGlyphShadow(FS_NORMAL);
|
|
||||||
WChar c;
|
|
||||||
int xo = x;
|
|
||||||
|
|
||||||
if (!parse_string_also_when_clipped) {
|
|
||||||
/* in "mode multiline", the available space have been verified. Not in regular one.
|
|
||||||
* So if the string cannot be drawn, return the original start to say so.*/
|
|
||||||
if (x >= dpi->left + dpi->width || y >= dpi->top + dpi->height) return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch_colour:;
|
|
||||||
SetColourRemap(params.cur_colour);
|
|
||||||
|
|
||||||
check_bounds:
|
|
||||||
if (y + _max_char_height <= dpi->top || dpi->top + dpi->height <= y) {
|
|
||||||
skip_char:;
|
|
||||||
for (;;) {
|
|
||||||
c = *string++;
|
|
||||||
if (!IsPrintable(c)) goto skip_cont;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
c = *string++;
|
|
||||||
skip_cont:;
|
|
||||||
if (c == 0) {
|
|
||||||
return x; // Nothing more to draw, get out. And here is the new x position
|
|
||||||
}
|
|
||||||
if (IsPrintable(c) && !IsTextDirectionChar(c)) {
|
|
||||||
if (x >= dpi->left + dpi->width) goto skip_char;
|
|
||||||
if (x + _max_char_width >= dpi->left) {
|
|
||||||
const Sprite *glyph = GetGlyph(params.fontsize, c);
|
|
||||||
if (draw_shadow && params.fontsize == FS_NORMAL && params.cur_colour != TC_BLACK && !(c >= SCC_SPRITE_START && c <= SCC_SPRITE_END)) {
|
|
||||||
SetColourRemap(TC_BLACK);
|
|
||||||
GfxMainBlitter(glyph, x + 1, y + 1, BM_COLOUR_REMAP);
|
|
||||||
SetColourRemap(params.cur_colour);
|
|
||||||
}
|
|
||||||
GfxMainBlitter(glyph, x, y, BM_COLOUR_REMAP);
|
|
||||||
}
|
|
||||||
x += GetCharacterWidth(params.fontsize, c);
|
|
||||||
} else if (c == '\n') { // newline = {}
|
|
||||||
x = xo; // We require a new line, so the x coordinate is reset
|
|
||||||
y += GetCharacterHeight(params.fontsize);
|
|
||||||
goto check_bounds;
|
|
||||||
} else if (c >= SCC_BLUE && c <= SCC_BLACK) { // change colour?
|
|
||||||
params.SetColour((TextColour)(c - SCC_BLUE));
|
|
||||||
goto switch_colour;
|
|
||||||
} else if (c == SCC_PREVIOUS_COLOUR) { // revert to the previous colour
|
|
||||||
params.SetPreviousColour();
|
|
||||||
goto switch_colour;
|
|
||||||
} else if (c == SCC_TINYFONT) { // {TINYFONT}
|
|
||||||
params.SetFontSize(FS_SMALL);
|
|
||||||
} else if (c == SCC_BIGFONT) { // {BIGFONT}
|
|
||||||
params.SetFontSize(FS_LARGE);
|
|
||||||
} else if (!IsTextDirectionChar(c)) {
|
|
||||||
DEBUG(misc, 0, "[utf8] unknown string command character %d", c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the size of a sprite.
|
* Get the size of a sprite.
|
||||||
* @param sprid Sprite to examine.
|
* @param sprid Sprite to examine.
|
||||||
|
|
Loading…
Reference in New Issue