diff --git a/contributors.md b/contributors.md index f00cac15b7..69e2e5c2cb 100644 --- a/contributors.md +++ b/contributors.md @@ -199,6 +199,7 @@ The following people are not part of the development team, but have been contrib * Dan Stevens (MajeureX) * 73 (733737) * Raymond Zhao (rzhao271) +* Xixiang Chen (jacknull1991) ## Toolchain * (Balletie) - macOS diff --git a/src/openrct2-ui/windows/Tooltip.cpp b/src/openrct2-ui/windows/Tooltip.cpp index 3b1ade74f2..eb75a3b4ce 100644 --- a/src/openrct2-ui/windows/Tooltip.cpp +++ b/src/openrct2-ui/windows/Tooltip.cpp @@ -26,18 +26,102 @@ static rct_widget window_tooltip_widgets[] = { WIDGETS_END, }; -static void WindowTooltipUpdate(rct_window *w); -static void WindowTooltipPaint(rct_window *w, rct_drawpixelinfo *dpi); - -static WindowEventList window_tooltip_events([](auto& events) -{ - events.update = &WindowTooltipUpdate; - events.paint = &WindowTooltipPaint; -}); // clang-format on -static utf8 _tooltipText[sizeof(gCommonStringFormatBuffer)]; -static int16_t _tooltipNumLines; +class TooltipWindow final : public Window +{ +private: + utf8 _tooltipText[sizeof(gCommonStringFormatBuffer)]{}; + int16_t _tooltipNumLines = 1; + +public: + TooltipWindow(const OpenRCT2String& message, ScreenCoordsXY screenCoords) + { + int32_t textWidth = FormatTextForTooltip(message); + width = textWidth + 3; + height = ((_tooltipNumLines + 1) * font_get_line_height(FontStyle::Small)) + 4; + + window_tooltip_widgets[WIDX_BACKGROUND].right = width; + window_tooltip_widgets[WIDX_BACKGROUND].bottom = height; + + int32_t screenWidth = context_get_width(); + int32_t screenHeight = context_get_height(); + screenCoords.x = std::clamp(screenCoords.x - (width / 2), 0, screenWidth - width); + + // TODO The cursor size will be relative to the window DPI. + // The amount to offset the y should be adjusted. + + int32_t max_y = screenHeight - height; + screenCoords.y += 26; // Normally, we'd display the tooltip 26 lower + if (screenCoords.y > max_y) + // If y is too large, the tooltip could be forced below the cursor if we'd just clamped y, + // so we'll subtract a bit more + screenCoords.y -= height + 40; + screenCoords.y = std::clamp(screenCoords.y, 22, max_y); + + windowPos = screenCoords; + } + + void OnOpen() override + { + widgets = window_tooltip_widgets; + reset_tooltip_not_shown(); + } + + void OnUpdate() override + { + reset_tooltip_not_shown(); + } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + int32_t left = windowPos.x; + int32_t top = windowPos.y; + int32_t right = windowPos.x + width - 1; + int32_t bottom = windowPos.y + height - 1; + + // Background + gfx_filter_rect(&dpi, { { left + 1, top + 1 }, { right - 1, bottom - 1 } }, FilterPaletteID::Palette45); + gfx_filter_rect(&dpi, { { left + 1, top + 1 }, { right - 1, bottom - 1 } }, FilterPaletteID::PaletteGlassLightOrange); + + // Sides + gfx_filter_rect(&dpi, { { left + 0, top + 2 }, { left + 0, bottom - 2 } }, FilterPaletteID::PaletteDarken3); + gfx_filter_rect(&dpi, { { right + 0, top + 2 }, { right + 0, bottom - 2 } }, FilterPaletteID::PaletteDarken3); + gfx_filter_rect(&dpi, { { left + 2, bottom + 0 }, { right - 2, bottom + 0 } }, FilterPaletteID::PaletteDarken3); + gfx_filter_rect(&dpi, { { left + 2, top + 0 }, { right - 2, top + 0 } }, FilterPaletteID::PaletteDarken3); + + // Corners + gfx_filter_pixel(&dpi, { left + 1, top + 1 }, FilterPaletteID::PaletteDarken3); + gfx_filter_pixel(&dpi, { right - 1, top + 1 }, FilterPaletteID::PaletteDarken3); + gfx_filter_pixel(&dpi, { left + 1, bottom - 1 }, FilterPaletteID::PaletteDarken3); + gfx_filter_pixel(&dpi, { right - 1, bottom - 1 }, FilterPaletteID::PaletteDarken3); + + // Text + left = windowPos.x + ((width + 1) / 2) - 1; + top = windowPos.y + 1; + draw_string_centred_raw(&dpi, { left, top }, _tooltipNumLines, _tooltipText, FontStyle::Small); + } + +private: + // Returns the width of the new tooltip text + int32_t FormatTextForTooltip(const OpenRCT2String& message) + { + utf8 tempBuffer[sizeof(gCommonStringFormatBuffer)]; + format_string(tempBuffer, sizeof(tempBuffer), message.str, message.args.Data()); + + OpenRCT2String formattedMessage{ STR_STRING_TOOLTIP, Formatter() }; + formattedMessage.args.Add(tempBuffer); + format_string(_tooltipText, sizeof(_tooltipText), formattedMessage.str, formattedMessage.args.Data()); + + auto textWidth = gfx_get_string_width_new_lined(_tooltipText, FontStyle::Small); + textWidth = std::min(textWidth, 196); + + int32_t numLines; + textWidth = gfx_wrap_string(_tooltipText, textWidth + 1, FontStyle::Small, &numLines); + _tooltipNumLines = numLines; + return textWidth; + } +}; void WindowTooltipReset(const ScreenCoordsXY& screenCoords) { @@ -48,64 +132,19 @@ void WindowTooltipReset(const ScreenCoordsXY& screenCoords) input_set_flag(INPUT_FLAG_4, false); } -// Returns the width of the new tooltip text -static int32_t FormatTextForTooltip(const OpenRCT2String& message) -{ - utf8 tempBuffer[sizeof(gCommonStringFormatBuffer)]; - format_string(tempBuffer, sizeof(tempBuffer), message.str, message.args.Data()); - - OpenRCT2String formattedMessage{ STR_STRING_TOOLTIP, Formatter() }; - formattedMessage.args.Add(tempBuffer); - format_string(_tooltipText, sizeof(_tooltipText), formattedMessage.str, formattedMessage.args.Data()); - - auto textWidth = gfx_get_string_width_new_lined(_tooltipText, FontStyle::Small); - textWidth = std::min(textWidth, 196); - - int32_t numLines; - textWidth = gfx_wrap_string(_tooltipText, textWidth + 1, FontStyle::Small, &numLines); - _tooltipNumLines = numLines; - return textWidth; -} - void WindowTooltipShow(const OpenRCT2String& message, ScreenCoordsXY screenCoords) { auto* w = window_find_by_class(WindowClass::Error); if (w != nullptr) return; - int32_t textWidth = FormatTextForTooltip(message); - int32_t width = textWidth + 3; - int32_t height = ((_tooltipNumLines + 1) * font_get_line_height(FontStyle::Small)) + 4; - window_tooltip_widgets[WIDX_BACKGROUND].right = width; - window_tooltip_widgets[WIDX_BACKGROUND].bottom = height; - - int32_t screenWidth = context_get_width(); - int32_t screenHeight = context_get_height(); - screenCoords.x = std::clamp(screenCoords.x - (width / 2), 0, screenWidth - width); - - // TODO The cursor size will be relative to the window DPI. - // The amount to offset the y should be adjusted. - - int32_t max_y = screenHeight - height; - screenCoords.y += 26; // Normally, we'd display the tooltip 26 lower - if (screenCoords.y > max_y) - // If y is too large, the tooltip could be forced below the cursor if we'd just clamped y, - // so we'll subtract a bit more - screenCoords.y -= height + 40; - screenCoords.y = std::clamp(screenCoords.y, 22, max_y); - - w = WindowCreate( - screenCoords, width, height, &window_tooltip_events, WindowClass::Tooltip, WF_TRANSPARENT | WF_STICK_TO_FRONT); - w->widgets = window_tooltip_widgets; - - reset_tooltip_not_shown(); + auto tooltipWindow = std::make_unique(message, screenCoords); + WindowCreate( + std::move(tooltipWindow), WindowClass::Tooltip, tooltipWindow->windowPos, tooltipWindow->width, tooltipWindow->height, + WF_TRANSPARENT | WF_STICK_TO_FRONT); } -/** - * - * rct2: 0x006EA10D - */ -void WindowTooltipOpen(rct_window* widgetWindow, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCords) +void WindowTooltipOpen(rct_window* widgetWindow, WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords) { if (widgetWindow == nullptr || widgetIndex == -1) return; @@ -142,58 +181,12 @@ void WindowTooltipOpen(rct_window* widgetWindow, WidgetIndex widgetIndex, const return; } - WindowTooltipShow(result, screenCords); + WindowTooltipShow(result, screenCoords); } -/** - * - * rct2: 0x006E98C6 - */ void WindowTooltipClose() { window_close_by_class(WindowClass::Tooltip); gTooltipTimeout = 0; gTooltipWidget.window_classification = WindowClass::Null; } - -/** - * - * rct2: 0x006EA580 - */ -static void WindowTooltipUpdate(rct_window* w) -{ - reset_tooltip_not_shown(); -} - -/** - * - * rct2: 0x006EA41D - */ -static void WindowTooltipPaint(rct_window* w, rct_drawpixelinfo* dpi) -{ - int32_t left = w->windowPos.x; - int32_t top = w->windowPos.y; - int32_t right = w->windowPos.x + w->width - 1; - int32_t bottom = w->windowPos.y + w->height - 1; - - // Background - gfx_filter_rect(dpi, { { left + 1, top + 1 }, { right - 1, bottom - 1 } }, FilterPaletteID::Palette45); - gfx_filter_rect(dpi, { { left + 1, top + 1 }, { right - 1, bottom - 1 } }, FilterPaletteID::PaletteGlassLightOrange); - - // Sides - gfx_filter_rect(dpi, { { left + 0, top + 2 }, { left + 0, bottom - 2 } }, FilterPaletteID::PaletteDarken3); - gfx_filter_rect(dpi, { { right + 0, top + 2 }, { right + 0, bottom - 2 } }, FilterPaletteID::PaletteDarken3); - gfx_filter_rect(dpi, { { left + 2, bottom + 0 }, { right - 2, bottom + 0 } }, FilterPaletteID::PaletteDarken3); - gfx_filter_rect(dpi, { { left + 2, top + 0 }, { right - 2, top + 0 } }, FilterPaletteID::PaletteDarken3); - - // Corners - gfx_filter_pixel(dpi, { left + 1, top + 1 }, FilterPaletteID::PaletteDarken3); - gfx_filter_pixel(dpi, { right - 1, top + 1 }, FilterPaletteID::PaletteDarken3); - gfx_filter_pixel(dpi, { left + 1, bottom - 1 }, FilterPaletteID::PaletteDarken3); - gfx_filter_pixel(dpi, { right - 1, bottom - 1 }, FilterPaletteID::PaletteDarken3); - - // Text - left = w->windowPos.x + ((w->width + 1) / 2) - 1; - top = w->windowPos.y + 1; - draw_string_centred_raw(dpi, { left, top }, _tooltipNumLines, _tooltipText, FontStyle::Small); -}