(svn r15837) -Codechange: support SETX(Y) with RTL text, swap alignment for RTL text.

This commit is contained in:
rubidium 2009-03-24 21:23:56 +00:00
parent 8cba245791
commit 5c44bb6b63
2 changed files with 101 additions and 29 deletions

View File

@ -18,6 +18,7 @@
#include "core/sort_func.hpp"
#include "landscape_type.h"
#include "network/network_func.h"
#include "core/smallvec_type.hpp"
#include "table/palettes.h"
#include "table/sprites.h"
@ -394,42 +395,113 @@ static int TruncateString(char *str, int maxw)
*/
static int DrawString(int left, int right, int top, char *str, const char *last, TextColour colour, StringAlignment align, bool underline = false, bool truncate = true)
{
/* We need the outer limits of both left/right */
int min_left = INT32_MAX;
int max_right = INT32_MIN;
int initial_left = left;
int initial_right = right;
int initial_top = top;
if (truncate) TruncateString(str, right - left);
HandleBiDiAndArabicShapes(str, last);
int w = GetStringBoundingBox(str).width;
/* 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'.
/*
* To support SETX and SETXY properly with RTL languages we have to
* calculate the offsets from the right. To do this we need to split
* the string and draw the parts separated by SETX(Y).
* So here we split
*/
switch (align) {
case SA_LEFT:
/* right + 1 = left + w */
right = left + w - 1;
break;
static SmallVector<char *, 4> setx_offsets;
setx_offsets.Clear();
*setx_offsets.Append() = str;
case SA_CENTER:
/* The second + 1 is to round to the closest number */
left = (right + 1 + left - w + 1) / 2;
/* right + 1 = left + w */
right = left + w - 1;
break;
char *loc = str;
for (;;) {
WChar c;
/* We cannot use Utf8Consume as we need the location of the SETX(Y) */
size_t len = Utf8Decode(&c, loc);
if (c == '\0') break;
if (c != SCC_SETX && c != SCC_SETXY) {
loc += len;
continue;
}
case SA_RIGHT:
left = right + 1 - w;
break;
if (align != SA_LEFT) {
DEBUG(grf, 1, "Using SETX and/or SETXY when not aligned to the left. Fixing alignment...");
align = SA_LEFT;
}
default:
NOT_REACHED();
}
ReallyDoDrawString(str, left, top, colour, !truncate);
if (underline) {
GfxFillRect(left, top + 10, right, top + 10, _string_colourremap[1]);
/* We add the begin of the string, but don't add it twice */
if (loc != str) *setx_offsets.Append() = loc;
/* Skip the SCC_SETX(Y) ... */
loc += len;
/* ... skip the x coordinate ... */
loc++;
/* ... and finally the y coordinate if it exists */
if (c == SCC_SETXY) loc++;
}
return align == SA_RIGHT ? left : right;
/* In case we have a RTL language we swap the alignment. */
if (_dynlang.text_dir == TD_RTL && align != SA_CENTER) align = (StringAlignment)(align ^ 2);
/* Now draw the parts. This is done in the reverse order so we can give the
* BiDi algorithm the room to replace characters. It also simplifies
* 'ending' the strings. */
for (char **iter = setx_offsets.End(); iter-- != setx_offsets.Begin(); ) {
char *to_draw = *iter;
WChar c;
size_t len = Utf8Decode(&c, to_draw);
int offset = 0;
/* Skip the SETX(Y) and set the appropriate offsets. */
if (c == SCC_SETX || c == SCC_SETXY) {
*to_draw = '\0';
to_draw += len;
offset = *to_draw++;
if (c == SCC_SETXY) top = initial_top + *to_draw++;
}
HandleBiDiAndArabicShapes(to_draw, last);
int w = GetStringBoundingBox(to_draw).width;
/* 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) {
case SA_LEFT:
/* right + 1 = left + w */
left = initial_left + offset;
right = left + w - 1;
break;
case SA_CENTER:
/* The second + 1 is to round to the closest number */
left = (initial_right + 1 + initial_left - w + 1) / 2;
/* right + 1 = left + w */
right = left + w - 1;
break;
case SA_RIGHT:
left = initial_right + 1 - w - offset;
break;
default:
NOT_REACHED();
}
min_left = min(left, min_left);
max_right = max(right, max_right);
ReallyDoDrawString(to_draw, left, top, colour, !truncate);
if (underline) {
GfxFillRect(left, top + 10, right, top + 10, _string_colourremap[1]);
}
}
return align == SA_RIGHT ? min_left : max_right;
}
/**

View File

@ -864,7 +864,7 @@ struct StationViewWindow : public Window {
assert(b < endof(string));
SetDParamStr(0, string);
DrawStringMultiLine(this->widget[SVW_ACCEPTLIST].left + 2, this->widget[SVW_ACCEPTLIST].right - 2, this->widget[SVW_ACCEPTLIST].top + 1,this->widget[SVW_ACCEPTLIST].bottom - 1, STR_JUST_RAW_STRING);
DrawStringMultiLine(this->widget[SVW_ACCEPTLIST].left + 2, this->widget[SVW_ACCEPTLIST].right - 2, this->widget[SVW_ACCEPTLIST].top + 1, this->widget[SVW_ACCEPTLIST].bottom - 1, STR_JUST_RAW_STRING);
} else { // extended window with list of cargo ratings
y = this->widget[SVW_RATINGLIST].top + 1;