1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-22 14:24:33 +01:00
Files
OpenRCT2/src/openrct2-ui/windows/About.cpp
2025-09-17 23:49:17 +02:00

294 lines
11 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2025 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include "../UiStringIds.h"
#include <SDL_clipboard.h>
#include <openrct2-ui/interface/Widget.h>
#include <openrct2-ui/windows/Windows.h>
#include <openrct2/OpenRCT2.h>
#include <openrct2/SpriteIds.h>
#include <openrct2/Version.h>
#include <openrct2/drawing/Drawing.h>
#include <openrct2/localisation/Formatter.h>
#include <openrct2/localisation/StringIds.h>
#include <openrct2/ui/UiContext.h>
#include <openrct2/ui/WindowManager.h>
namespace OpenRCT2::Ui::Windows
{
static constexpr ScreenSize kWindowSize = { 400, 450 };
static constexpr StringId kWindowTitle = STR_ABOUT;
static constexpr int32_t kTabHeight = 50;
static constexpr auto kPadding = 10;
enum
{
WINDOW_ABOUT_PAGE_OPENRCT2,
WINDOW_ABOUT_PAGE_RCT2,
};
enum WindowAboutWidgetIdx
{
WIDX_BACKGROUND,
WIDX_TITLE,
WIDX_CLOSE,
WIDX_PAGE_BACKGROUND,
WIDX_TAB_ABOUT_OPENRCT2,
WIDX_TAB_ABOUT_RCT2,
WIDX_PAGE_START,
// About OpenRCT2
WIDX_INTRO = WIDX_PAGE_START,
WIDX_OPENRCT2_LOGO,
WIDX_VERSION,
WIDX_COPY_BUILD_INFO,
WIDX_NEW_VERSION,
WIDX_CHANGELOG,
WIDX_JOIN_DISCORD,
WIDX_CONTRIBUTORS_BUTTON,
};
// clang-format off
static constexpr auto kMainWidgets = makeWidgets(
makeWindowShim (kWindowTitle, kWindowSize),
makeWidget ({ 0, kTabHeight }, { kWindowSize.width, kWindowSize.height - kTabHeight }, WidgetType::frame, WindowColour::secondary),
makeRemapWidget({ 3, 17 }, { 91, kTabHeight - 16 }, WidgetType::tab, WindowColour::secondary, SPR_TAB_LARGE),
makeRemapWidget({ 94, 17 }, { 91, kTabHeight - 16 }, WidgetType::tab, WindowColour::secondary, SPR_TAB_LARGE)
);
static constexpr auto _windowAboutOpenRCT2Widgets = makeWidgets(
kMainWidgets,
makeWidget({10, 60}, {kWindowSize.width - 20, 20}, WidgetType::labelCentred, WindowColour::secondary, STR_ABOUT_OPENRCT2_DESCRIPTION ), // Introduction
makeWidget({30, 90}, {128, 128}, WidgetType::placeholder, WindowColour::secondary, kStringIdNone ), // OpenRCT2 Logo
makeWidget({168, 100}, {173, 24}, WidgetType::placeholder, WindowColour::secondary, kStringIdNone ), // Build version
makeWidget({344, 100 }, {24, 24}, WidgetType::imgBtn, WindowColour::secondary, ImageId(SPR_G2_COPY), STR_COPY_BUILD_HASH), // "Copy build info" button
makeWidget({168, 115 + 20}, {200, 14}, WidgetType::placeholder, WindowColour::secondary, STR_UPDATE_AVAILABLE ), // "new version" button
makeWidget({168, 115 + 40}, {200, 14}, WidgetType::button, WindowColour::secondary, STR_CHANGELOG_ELLIPSIS ), // changelog button
makeWidget({168, 115 + 60}, {200, 14}, WidgetType::button, WindowColour::secondary, STR_JOIN_DISCORD ), // "join discord" button
makeWidget({168, 115 + 80}, {200, 14}, WidgetType::button, WindowColour::secondary, STR_CONTRIBUTORS_WINDOW_BUTTON ) // "contributors" button
);
// clang-format on
static constexpr auto _windowAboutRCT2Widgets = makeWidgets(kMainWidgets);
static constexpr std::span<const Widget> _windowAboutPageWidgets[] = {
_windowAboutOpenRCT2Widgets,
_windowAboutRCT2Widgets,
};
// clang-format off
static const StringId _OpenRCT2InfoStrings[] = {
STR_ABOUT_OPENRCT2_DESCRIPTION_2,
STR_ABOUT_OPENRCT2_DESCRIPTION_3,
STR_ABOUT_OPENRCT2_TITLE,
STR_ABOUT_FAIRGROUND_ORGAN,
STR_ABOUT_SPECIAL_THANKS_1,
STR_ABOUT_SPECIAL_THANKS_2,
};
// clang-format on
static const StringId _RCT2InfoStrings[] = {
STR_COPYRIGHT_CS,
STR_DESIGNED_AND_PROGRAMMED_BY_CS,
STR_GRAPHICS_BY_SF,
STR_SOUND_AND_MUSIC_BY_AB,
STR_ADDITIONAL_SOUNDS_RECORDED_BY_DE,
STR_REPRESENTATION_BY_JL,
kStringIdEmpty,
STR_THANKS_TO,
STR_THANKS_TO_PEOPLE,
kStringIdEmpty,
STR_LICENSED_TO_INFOGRAMES_INTERACTIVE_INC,
};
class AboutWindow final : public Window
{
public:
void onOpen() override
{
setPage(WINDOW_ABOUT_PAGE_OPENRCT2);
}
void onMouseUp(WidgetIndex widgetIndex) override
{
switch (widgetIndex)
{
case WIDX_CLOSE:
close();
break;
case WIDX_TAB_ABOUT_OPENRCT2:
case WIDX_TAB_ABOUT_RCT2:
setPage(widgetIndex - WIDX_TAB_ABOUT_OPENRCT2);
break;
case WIDX_JOIN_DISCORD:
OpenRCT2::GetContext()->GetUiContext().OpenURL("https://discord.gg/ZXZd8D8");
break;
case WIDX_CHANGELOG:
ContextOpenWindow(WindowClass::changelog);
break;
case WIDX_NEW_VERSION:
ContextOpenWindowView(WindowView::newVersionInfo);
break;
case WIDX_COPY_BUILD_INFO:
OpenRCT2::GetContext()->GetUiContext().SetClipboardText(gVersionInfoFull);
break;
case WIDX_CONTRIBUTORS_BUTTON:
ContextOpenWindowView(WindowView::contributors);
break;
}
}
void onDraw(RenderTarget& rt) override
{
drawWidgets(rt);
const auto& aboutOpenRCT2 = widgets[WIDX_TAB_ABOUT_OPENRCT2];
const auto& aboutRCT2 = widgets[WIDX_TAB_ABOUT_RCT2];
int32_t y = windowPos.y + aboutOpenRCT2.midY() - 3;
ScreenCoordsXY aboutOpenRCT2Coords(windowPos.x + aboutOpenRCT2.left + 45, y);
ScreenCoordsXY aboutRCT2Coords(windowPos.x + aboutRCT2.left + 45, y);
// Draw tab names
{
// TODO: this string shouldn't be reused for this tab
auto ft = Formatter();
ft.Add<StringId>(STR_TITLE_SEQUENCE_OPENRCT2);
DrawTextWrapped(
rt, aboutOpenRCT2Coords, 87, STR_WINDOW_COLOUR_2_STRINGID, ft,
{ COLOUR_AQUAMARINE, TextAlignment::CENTRE });
}
{
// TODO: this string shouldn't be reused for this tab
auto ft = Formatter();
ft.Add<StringId>(STR_TITLE_SEQUENCE_RCT2);
DrawTextWrapped(
rt, aboutRCT2Coords, 87, STR_WINDOW_COLOUR_2_STRINGID, ft, { COLOUR_AQUAMARINE, TextAlignment::CENTRE });
}
int32_t newHeight = 0;
if (page == WINDOW_ABOUT_PAGE_OPENRCT2)
{
newHeight = DrawOpenRCT2Info(rt) + kPadding;
}
else if (page == WINDOW_ABOUT_PAGE_RCT2)
{
newHeight = DrawRCT2Info(rt) + kPadding;
}
if (newHeight != height)
{
invalidate();
widgets[WIDX_PAGE_BACKGROUND].bottom = newHeight;
widgets[WIDX_BACKGROUND].bottom = newHeight;
height = newHeight;
}
}
private:
void setPage(int32_t p)
{
// Skip setting page if we're already on this page, unless we're initialising the window
if (page == p && !widgets.empty())
return;
page = p;
currentFrame = 0;
pressedWidgets = 0;
WindowSetResize(*this, kWindowSize, kWindowSize);
setWidgets(_windowAboutPageWidgets[p]);
switch (p)
{
case WINDOW_ABOUT_PAGE_OPENRCT2:
pressedWidgets |= (1uLL << WIDX_TAB_ABOUT_OPENRCT2);
break;
case WINDOW_ABOUT_PAGE_RCT2:
pressedWidgets |= (1uLL << WIDX_TAB_ABOUT_RCT2);
break;
}
}
int32_t DrawOpenRCT2Info(RenderTarget& rt)
{
// Draw logo on placeholder widget
const auto& logoWidget = widgets[WIDX_OPENRCT2_LOGO];
auto logoCoords = windowPos + ScreenCoordsXY(logoWidget.left, logoWidget.top);
GfxDrawSprite(rt, ImageId(SPR_G2_LOGO), logoCoords);
u8string versionInfo = gVersionInfoFull;
auto ft = Formatter();
ft.Add<const char*>(versionInfo.c_str());
const auto& versionWidget = widgets[WIDX_VERSION];
auto centreX = versionWidget.midX();
auto centreY = versionWidget.midY() - FontGetLineHeight(FontStyle::Medium) / 2;
auto centrePos = windowPos + ScreenCoordsXY(centreX, centreY);
DrawTextWrapped(rt, centrePos, versionWidget.width(), STR_STRING, ft, { colours[1], TextAlignment::CENTRE });
// Shows the update available button
if (OpenRCT2::GetContext()->HasNewVersionInfo())
{
widgets[WIDX_NEW_VERSION].type = WidgetType::button;
}
// Draw the rest of the text
TextPaint tp{ colours[1], TextAlignment::CENTRE };
auto textCoords = windowPos + ScreenCoordsXY((width / 2) - 1, 240);
auto textWidth = kWindowSize.width - (kPadding * 2);
for (auto stringId : _OpenRCT2InfoStrings)
textCoords.y += DrawTextWrapped(rt, textCoords, textWidth, stringId, {}, tp) + 5;
return textCoords.y - windowPos.y;
}
int32_t DrawRCT2Info(RenderTarget& rt)
{
auto& backgroundWidget = widgets[WIDX_PAGE_BACKGROUND];
auto textCoords = windowPos + ScreenCoordsXY{ backgroundWidget.midX(), backgroundWidget.top + kPadding };
auto textWidth = kWindowSize.width - 20;
TextPaint tp{ colours[1], TextAlignment::CENTRE };
// Draw credits
for (auto stringId : _RCT2InfoStrings)
{
if (stringId == kStringIdEmpty)
{
textCoords.y += 16;
continue;
}
textCoords.y += DrawTextWrapped(rt, textCoords, textWidth, stringId, {}, tp);
if (stringId == STR_COPYRIGHT_CS)
textCoords.y += 74;
}
// Draw images
auto imageCoords = windowPos + ScreenCoordsXY{ 92, backgroundWidget.top + 5 + 24 };
GfxDrawSprite(rt, ImageId(SPR_CREDITS_CHRIS_SAWYER_SMALL), imageCoords);
return textCoords.y - windowPos.y;
}
};
/**
*
* rct2: 0x0066D2AC
*/
WindowBase* AboutOpen()
{
auto* windowMgr = GetWindowManager();
return windowMgr->FocusOrCreate<AboutWindow>(WindowClass::about, kWindowSize, WF_CENTRE_SCREEN);
}
} // namespace OpenRCT2::Ui::Windows