Fix: Viewport signs assume small font is smaller than normal font. (#12422)

If the small font is set to a larger size than the normal font for some reason, viewport signs would be drawn incorrect as the area marked dirty only considered the normal size font.
This commit is contained in:
Peter Nelson 2024-04-06 19:29:41 +01:00 committed by GitHub
parent 830c9e2de8
commit b905209421
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 15 additions and 12 deletions

View File

@ -1314,7 +1314,7 @@ void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const Vie
int right = left + dpi->width; int right = left + dpi->width;
int bottom = top + dpi->height; int bottom = top + dpi->height;
int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, dpi->zoom); int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, dpi->zoom);
int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom); int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, dpi->zoom);
if (bottom < sign->top || if (bottom < sign->top ||
@ -1338,8 +1338,7 @@ void ViewportAddString(const DrawPixelInfo *dpi, ZoomLevel small_from, const Vie
static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom) static Rect ExpandRectWithViewportSignMargins(Rect r, ZoomLevel zoom)
{ {
/* Pessimistically always use normal font, but also assume small font is never larger in either dimension */ const int fh = std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL));
const int fh = GetCharacterHeight(FS_NORMAL);
const int max_tw = _viewport_sign_maxwidth / 2 + 1; const int max_tw = _viewport_sign_maxwidth / 2 + 1;
const int expand_y = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + fh + WidgetDimensions::scaled.fullbevel.bottom, zoom); const int expand_y = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + fh + WidgetDimensions::scaled.fullbevel.bottom, zoom);
const int expand_x = ScaleByZoom(WidgetDimensions::scaled.fullbevel.left + max_tw + WidgetDimensions::scaled.fullbevel.right, zoom); const int expand_x = ScaleByZoom(WidgetDimensions::scaled.fullbevel.left + max_tw + WidgetDimensions::scaled.fullbevel.right, zoom);
@ -1490,12 +1489,16 @@ void ViewportSign::MarkDirty(ZoomLevel maxzoom) const
{ {
Rect zoomlevels[ZOOM_LVL_END]; Rect zoomlevels[ZOOM_LVL_END];
/* We don't know which size will be drawn, so mark the largest area dirty. */
const uint half_width = std::max(this->width_normal, this->width_small) / 2 + 1;
const uint height = WidgetDimensions::scaled.fullbevel.top + std::max(GetCharacterHeight(FS_NORMAL), GetCharacterHeight(FS_SMALL)) + WidgetDimensions::scaled.fullbevel.bottom + 1;
for (ZoomLevel zoom = ZOOM_LVL_BEGIN; zoom != ZOOM_LVL_END; zoom++) { for (ZoomLevel zoom = ZOOM_LVL_BEGIN; zoom != ZOOM_LVL_END; zoom++) {
/* FIXME: This doesn't switch to width_small when appropriate. */ /* FIXME: This doesn't switch to width_small when appropriate. */
zoomlevels[zoom].left = this->center - ScaleByZoom(this->width_normal / 2 + 1, zoom); zoomlevels[zoom].left = this->center - ScaleByZoom(half_width, zoom);
zoomlevels[zoom].top = this->top - ScaleByZoom(1, zoom); zoomlevels[zoom].top = this->top - ScaleByZoom(1, zoom);
zoomlevels[zoom].right = this->center + ScaleByZoom(this->width_normal / 2 + 1, zoom); zoomlevels[zoom].right = this->center + ScaleByZoom(half_width, zoom);
zoomlevels[zoom].bottom = this->top + ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom + 1, zoom); zoomlevels[zoom].bottom = this->top + ScaleByZoom(height, zoom);
} }
for (const Window *w : Window::Iterate()) { for (const Window *w : Window::Iterate()) {
@ -1709,7 +1712,7 @@ static void ViewportDrawStrings(ZoomLevel zoom, const StringSpriteToDrawVector *
int w = GB(ss.width, 0, 15); int w = GB(ss.width, 0, 15);
int x = UnScaleByZoom(ss.x, zoom); int x = UnScaleByZoom(ss.x, zoom);
int y = UnScaleByZoom(ss.y, zoom); int y = UnScaleByZoom(ss.y, zoom);
int h = WidgetDimensions::scaled.fullbevel.top + (small ? GetCharacterHeight(FS_SMALL) : GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.fullbevel.bottom; int h = WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom;
if (ss.colour != INVALID_COLOUR) { if (ss.colour != INVALID_COLOUR) {
if (IsTransparencySet(TO_SIGNS) && ss.string_id != STR_WHITE_SIGN) { if (IsTransparencySet(TO_SIGNS) && ss.string_id != STR_WHITE_SIGN) {
@ -2194,7 +2197,7 @@ static bool CheckClickOnViewportSign(const Viewport *vp, int x, int y, const Vie
{ {
bool small = (vp->zoom >= ZOOM_LVL_OUT_4X); bool small = (vp->zoom >= ZOOM_LVL_OUT_4X);
int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom); int sign_half_width = ScaleByZoom((small ? sign->width_small : sign->width_normal) / 2, vp->zoom);
int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + (small ? GetCharacterHeight(FS_SMALL) : GetCharacterHeight(FS_NORMAL)) + WidgetDimensions::scaled.fullbevel.bottom, vp->zoom); int sign_height = ScaleByZoom(WidgetDimensions::scaled.fullbevel.top + GetCharacterHeight(small ? FS_SMALL : FS_NORMAL) + WidgetDimensions::scaled.fullbevel.bottom, vp->zoom);
return y >= sign->top && y < sign->top + sign_height && return y >= sign->top && y < sign->top + sign_height &&
x >= sign->center - sign_half_width && x < sign->center + sign_half_width; x >= sign->center - sign_half_width && x < sign->center + sign_half_width;
@ -2296,7 +2299,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeStation(StationID id)
item.top = st->sign.top; item.top = st->sign.top;
/* Assume the sign can be a candidate for drawing, so measure its width */ /* Assume the sign can be a candidate for drawing, so measure its width */
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, st->sign.width_normal); _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, st->sign.width_normal, st->sign.width_small});
return item; return item;
} }
@ -2313,7 +2316,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeWaypoint(StationID id)
item.top = st->sign.top; item.top = st->sign.top;
/* Assume the sign can be a candidate for drawing, so measure its width */ /* Assume the sign can be a candidate for drawing, so measure its width */
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, st->sign.width_normal); _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, st->sign.width_normal, st->sign.width_small});
return item; return item;
} }
@ -2330,7 +2333,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeTown(TownID id)
item.top = town->cache.sign.top; item.top = town->cache.sign.top;
/* Assume the sign can be a candidate for drawing, so measure its width */ /* Assume the sign can be a candidate for drawing, so measure its width */
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, town->cache.sign.width_normal); _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, town->cache.sign.width_normal, town->cache.sign.width_small});
return item; return item;
} }
@ -2347,7 +2350,7 @@ ViewportSignKdtreeItem ViewportSignKdtreeItem::MakeSign(SignID id)
item.top = sign->sign.top; item.top = sign->sign.top;
/* Assume the sign can be a candidate for drawing, so measure its width */ /* Assume the sign can be a candidate for drawing, so measure its width */
_viewport_sign_maxwidth = std::max<int>(_viewport_sign_maxwidth, sign->sign.width_normal); _viewport_sign_maxwidth = std::max<int>({_viewport_sign_maxwidth, sign->sign.width_normal, sign->sign.width_small});
return item; return item;
} }