1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-23 15:52:55 +01:00

Merge pull request #25392 from Gymnasiast/feature/image-buttons-with-border

Add theme feature to draw border around image buttons
This commit is contained in:
Michael Steenbeek
2025-10-23 18:31:00 +02:00
committed by GitHub
10 changed files with 57 additions and 24 deletions

View File

@@ -3844,3 +3844,4 @@ STR_7002 :{STRINGID} {STRINGID}
STR_7003 :Audio file {STRING} is truncated. Expected sample {INT32}, but only {INT32} are available. Consider reinstalling RCT2.
STR_7004 :Force Redraw
STR_7005 :Drag an area of footpath
STR_7006 :Draw border around image buttons

View File

@@ -1972,6 +1972,7 @@ namespace OpenRCT2
STR_THEMES_OPTION_RCT1_PARK_CONTROLS = 5283,
STR_THEMES_OPTION_RCT1_RIDE_CONTROLS = 5282,
STR_THEMES_OPTION_RCT1_SCENARIO_SELECTION_FONT = 5284,
STR_THEMES_OPTION_USE_3D_IMAGE_BUTTONS = 7006,
STR_THEMES_PROMPT_ENTER_THEME_NAME = 5240,
STR_THEMES_TAB_EDITORS_TIP = 5232,
STR_THEMES_TAB_FEATURES_TIP = 5281,

View File

@@ -1115,6 +1115,7 @@ namespace OpenRCT2
case WidgetType::trnBtn:
case WidgetType::tab:
case WidgetType::flatBtn:
case WidgetType::hiddenButton:
case WidgetType::button:
case WidgetType::tableHeader:
case WidgetType::spinner:

View File

@@ -158,7 +158,7 @@ namespace OpenRCT2::Ui
{
// WindowClass WindowClassSZ WindowName windowColours
{ WindowClass::topToolbar, "WC_TOP_TOOLBAR", STR_THEMES_WINDOW_TOP_TOOLBAR, { opaque(COLOUR_LIGHT_BLUE), opaque(COLOUR_DARK_GREEN), opaque(COLOUR_DARK_BROWN), opaque(COLOUR_GREY) } },
{ WindowClass::bottomToolbar, "WC_BOTTOM_TOOLBAR", STR_THEMES_WINDOW_BOTTOM_TOOLBAR, { translucent(COLOUR_DARK_GREEN), translucent(COLOUR_DARK_GREEN), opaque(COLOUR_BLACK), opaque(COLOUR_BRIGHT_GREEN) } },
{ WindowClass::bottomToolbar, "WC_BOTTOM_TOOLBAR", STR_THEMES_WINDOW_BOTTOM_TOOLBAR, { translucent(COLOUR_DARK_GREEN), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK), opaque(COLOUR_BRIGHT_GREEN) } },
{ WindowClass::ride, "WC_RIDE", STR_THEMES_WINDOW_RIDE, { opaque(COLOUR_GREY), opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_SATURATED_GREEN) } },
{ WindowClass::rideConstruction, "WC_RIDE_CONSTRUCTION", STR_THEMES_WINDOW_RIDE_CONSTRUCTION, { opaque(COLOUR_DARK_BROWN), opaque(COLOUR_DARK_BROWN), opaque(COLOUR_DARK_BROWN) } },
{ WindowClass::rideList, "WC_RIDE_LIST", STR_THEMES_WINDOW_RIDE_LIST, { opaque(COLOUR_GREY), opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_BORDEAUX_RED) } },
@@ -232,7 +232,7 @@ namespace OpenRCT2::Ui
static constexpr std::array kPredefinedThemeRCT1Entries = std::to_array<UIThemeWindowEntry>({
{ WindowClass::topToolbar, { opaque(COLOUR_GREY), opaque(COLOUR_GREY), opaque(COLOUR_GREY), opaque(COLOUR_GREY), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK) } },
{ WindowClass::bottomToolbar, { translucent(COLOUR_GREY), translucent(COLOUR_GREY), opaque(COLOUR_VOID), opaque(COLOUR_YELLOW), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK) } },
{ WindowClass::bottomToolbar, { translucent(COLOUR_GREY), opaque(COLOUR_GREY), opaque(COLOUR_VOID), opaque(COLOUR_YELLOW), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK) } },
{ WindowClass::ride, { opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_GREY), opaque(COLOUR_SATURATED_GREEN), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK) } },
{ WindowClass::rideList, { opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_GREY), opaque(COLOUR_GREY), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK) } },
{ WindowClass::constructRide, { opaque(COLOUR_BORDEAUX_RED), opaque(COLOUR_GREY), opaque(COLOUR_GREY), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK), opaque(COLOUR_BLACK) } },
@@ -262,7 +262,7 @@ namespace OpenRCT2::Ui
const UITheme kPredefinedThemeRCT1 = UITheme::CreatePredefined(
"*RCT1", kPredefinedThemeRCT1Entries,
UITHEME_FLAG_USE_LIGHTS_RIDE | UITHEME_FLAG_USE_LIGHTS_PARK | UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT
| UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR);
| UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR | UITHEME_FLAG_USE_3D_IMAGE_BUTTONS);
const UITheme kPredefinedThemeRCT2 = UITheme::CreatePredefined("*RCT2", kPredefinedThemeRCT2Entries, 0);
@@ -441,6 +441,7 @@ namespace OpenRCT2::Ui
{ "useLightsPark", (Flags & UITHEME_FLAG_USE_LIGHTS_PARK) != 0 },
{ "useAltScenarioSelectFont", (Flags & UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT) != 0 },
{ "useFullBottomToolbar", (Flags & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR) != 0 },
{ "use3dImageButtons", (Flags & UITHEME_FLAG_USE_3D_IMAGE_BUTTONS) != 0 },
};
return jsonTheme;
@@ -489,6 +490,7 @@ namespace OpenRCT2::Ui
{ "useLightsPark", UITHEME_FLAG_USE_LIGHTS_PARK },
{ "useAltScenarioSelectFont", UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT },
{ "useFullBottomToolbar", UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR },
{ "use3dImageButtons", UITHEME_FLAG_USE_3D_IMAGE_BUTTONS },
});
if (jsonEntries.is_object())

View File

@@ -21,6 +21,7 @@ namespace OpenRCT2::Ui
UITHEME_FLAG_USE_LIGHTS_PARK = 1 << 2,
UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT = 1 << 3,
UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR = 1 << 4,
UITHEME_FLAG_USE_3D_IMAGE_BUTTONS = 1 << 5,
};
void ColourSchemeUpdate(WindowBase* window);

View File

@@ -12,6 +12,7 @@
#include <algorithm>
#include <cmath>
#include <openrct2-ui/UiStringIds.h>
#include <openrct2-ui/interface/Theme.h>
#include <openrct2-ui/windows/Windows.h>
#include <openrct2/Diagnostic.h>
#include <openrct2/Game.h>
@@ -80,6 +81,7 @@ namespace OpenRCT2::Ui
WidgetTabDraw(rt, w, widgetIndex);
break;
case WidgetType::flatBtn:
case WidgetType::hiddenButton:
WidgetFlatButtonDraw(rt, w, widgetIndex);
break;
case WidgetType::button:
@@ -270,15 +272,15 @@ namespace OpenRCT2::Ui
*/
static void WidgetFlatButtonDraw(RenderTarget& rt, WindowBase& w, WidgetIndex widgetIndex)
{
if (!widgetIsDisabled(w, widgetIndex) && widgetIsHighlighted(w, widgetIndex))
const auto& widget = w.widgets[widgetIndex];
// First check is needed as this function handles both WidgetType::flatBtn and WidgetType::hiddenButton
const bool alwaysDrawAs3d = widget.type == WidgetType::flatBtn && (ThemeGetFlags() & UITHEME_FLAG_USE_3D_IMAGE_BUTTONS);
if (alwaysDrawAs3d || (!widgetIsDisabled(w, widgetIndex) && widgetIsHighlighted(w, widgetIndex)))
{
WidgetButtonDraw(rt, w, widgetIndex);
return;
}
// Get the widget
const auto& widget = w.widgets[widgetIndex];
// Resolve the absolute ltrb
ScreenRect rect{ w.windowPos + ScreenCoordsXY{ widget.left, widget.top },
w.windowPos + ScreenCoordsXY{ widget.right, widget.bottom } };

View File

@@ -79,6 +79,7 @@ namespace OpenRCT2::Scripting
case WidgetType::imgBtn:
case WidgetType::trnBtn:
case WidgetType::flatBtn:
case WidgetType::hiddenButton:
case WidgetType::button:
case WidgetType::closeBox:
return "button";

View File

@@ -57,18 +57,18 @@ namespace OpenRCT2::Ui::Windows
{
makeWidget({ 0, 0}, {142, 34}, WidgetType::imgBtn, WindowColour::primary ), // Left outset panel
makeWidget({ 2, 2}, {138, 30}, WidgetType::imgBtn, WindowColour::primary ), // Left inset panel
makeWidget({ 2, 1}, {138, 12}, WidgetType::flatBtn, WindowColour::primary , 0xFFFFFFFF, STR_PROFIT_PER_WEEK_AND_PARK_VALUE_TIP), // Money window
makeWidget({ 2, 11}, {138, 12}, WidgetType::flatBtn, WindowColour::primary ), // Guests window
makeWidget({ 2, 21}, {138, 11}, WidgetType::flatBtn, WindowColour::primary , 0xFFFFFFFF, STR_PARK_RATING_TIP ), // Park rating window
makeWidget({ 2, 1}, {138, 12}, WidgetType::hiddenButton,WindowColour::primary , 0xFFFFFFFF, STR_PROFIT_PER_WEEK_AND_PARK_VALUE_TIP), // Money window
makeWidget({ 2, 11}, {138, 12}, WidgetType::hiddenButton,WindowColour::primary ), // Guests window
makeWidget({ 2, 21}, {138, 11}, WidgetType::hiddenButton,WindowColour::primary , 0xFFFFFFFF, STR_PARK_RATING_TIP ), // Park rating window
makeWidget({142, 0}, {356, 34}, WidgetType::imgBtn, WindowColour::tertiary ), // Middle outset panel
makeWidget({144, 2}, {352, 30}, WidgetType::flatBtn, WindowColour::tertiary ), // Middle inset panel
makeWidget({147, 5}, { 24, 24}, WidgetType::flatBtn, WindowColour::tertiary, 0xFFFFFFFF, STR_SHOW_SUBJECT_TIP ), // Associated news item window
makeWidget({469, 5}, { 24, 24}, WidgetType::flatBtn, WindowColour::tertiary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP ), // Scroll to news item target
makeWidget({144, 2}, {352, 30}, WidgetType::hiddenButton,WindowColour::tertiary ), // Middle inset panel
makeWidget({147, 5}, { 24, 24}, WidgetType::flatBtn, WindowColour::secondary, 0xFFFFFFFF, STR_SHOW_SUBJECT_TIP ), // Associated news item window
makeWidget({469, 5}, { 24, 24}, WidgetType::flatBtn, WindowColour::secondary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP ), // Scroll to news item target
makeWidget({498, 0}, {142, 34}, WidgetType::imgBtn, WindowColour::primary ), // Right outset panel
makeWidget({500, 2}, {138, 30}, WidgetType::imgBtn, WindowColour::primary ), // Right inset panel
makeWidget({500, 2}, {138, 12}, WidgetType::flatBtn, WindowColour::primary ), // Date
makeWidget({500, 2}, {138, 12}, WidgetType::hiddenButton,WindowColour::primary ), // Date
};
// clang-format on
@@ -92,7 +92,7 @@ namespace OpenRCT2::Ui::Windows
const auto topLeft = windowPos + ScreenCoordsXY{ leftPanelWidget.left + 1, leftPanelWidget.top + 1 };
const auto bottomRight = windowPos + ScreenCoordsXY{ leftPanelWidget.right - 1, leftPanelWidget.bottom - 1 };
// Draw green inset rectangle on panel
GfxFillRectInset(rt, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30);
GfxFillRectInset(rt, { topLeft, bottomRight }, colours[0], INSET_RECT_F_30);
// Figure out how much line height we have to work with.
uint32_t line_height = FontGetLineHeight(FontStyle::Medium);
@@ -152,7 +152,7 @@ namespace OpenRCT2::Ui::Windows
{
int16_t bar_width = (factor * 114) / 255;
GfxFillRectInset(
rt, { coords + ScreenCoordsXY{ 1, 1 }, coords + ScreenCoordsXY{ 114, 9 } }, colours[1], INSET_RECT_F_30);
rt, { coords + ScreenCoordsXY{ 1, 1 }, coords + ScreenCoordsXY{ 114, 9 } }, colours[0], INSET_RECT_F_30);
if (!(colour & kBarBlink) || GameIsPaused() || (gCurrentRealTimeTicks & 8))
{
if (bar_width > 2)
@@ -175,7 +175,7 @@ namespace OpenRCT2::Ui::Windows
const auto topLeft = windowPos + ScreenCoordsXY{ rightPanelWidget.left + 1, rightPanelWidget.top + 1 };
const auto bottomRight = windowPos + ScreenCoordsXY{ rightPanelWidget.right - 1, rightPanelWidget.bottom - 1 };
// Draw green inset rectangle on panel
GfxFillRectInset(rt, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30);
GfxFillRectInset(rt, { topLeft, bottomRight }, colours[0], INSET_RECT_F_30);
auto screenCoords = ScreenCoordsXY{ (rightPanelWidget.left + rightPanelWidget.right) / 2 + windowPos.x,
rightPanelWidget.top + windowPos.y + 2 };
@@ -352,7 +352,7 @@ namespace OpenRCT2::Ui::Windows
rt,
{ windowPos + ScreenCoordsXY{ middleOutsetWidget->left + 1, middleOutsetWidget->top + 1 },
windowPos + ScreenCoordsXY{ middleOutsetWidget->right - 1, middleOutsetWidget->bottom - 1 } },
colours[1], INSET_RECT_F_30);
colours[0], INSET_RECT_F_30);
// Figure out how much line height we have to work with.
uint32_t line_height = FontGetLineHeight(FontStyle::Medium);
@@ -524,7 +524,7 @@ namespace OpenRCT2::Ui::Windows
}
else
{
widgets[WIDX_MONEY].type = WidgetType::flatBtn;
widgets[WIDX_MONEY].type = WidgetType::hiddenButton;
widgets[WIDX_MONEY].bottom = widgets[WIDX_MONEY].top + line_height;
widgets[WIDX_GUESTS].top = widgets[WIDX_MONEY].bottom + 1;
widgets[WIDX_GUESTS].bottom = widgets[WIDX_GUESTS].top + line_height;
@@ -572,7 +572,7 @@ namespace OpenRCT2::Ui::Windows
else
{
widgets[WIDX_MIDDLE_OUTSET].type = WidgetType::imgBtn;
widgets[WIDX_MIDDLE_INSET].type = WidgetType::flatBtn;
widgets[WIDX_MIDDLE_INSET].type = WidgetType::hiddenButton;
widgets[WIDX_NEWS_SUBJECT].type = WidgetType::empty;
widgets[WIDX_NEWS_LOCATE].type = WidgetType::empty;
widgets[WIDX_MIDDLE_OUTSET].colour = 0;
@@ -583,7 +583,7 @@ namespace OpenRCT2::Ui::Windows
{
News::Item* newsItem = News::GetItem(0);
widgets[WIDX_MIDDLE_OUTSET].type = WidgetType::imgBtn;
widgets[WIDX_MIDDLE_INSET].type = WidgetType::flatBtn;
widgets[WIDX_MIDDLE_INSET].type = WidgetType::hiddenButton;
widgets[WIDX_NEWS_SUBJECT].type = WidgetType::flatBtn;
widgets[WIDX_NEWS_LOCATE].type = WidgetType::flatBtn;
widgets[WIDX_MIDDLE_OUTSET].colour = 2;

View File

@@ -67,7 +67,8 @@ namespace OpenRCT2::Ui::Windows
WIDX_THEMES_RCT1_RIDE_LIGHTS,
WIDX_THEMES_RCT1_PARK_LIGHTS,
WIDX_THEMES_RCT1_SCENARIO_FONT,
WIDX_THEMES_RCT1_BOTTOM_TOOLBAR
WIDX_THEMES_RCT1_BOTTOM_TOOLBAR,
WIDX_THEMES_USE_3D_IMAGE_BUTTONS,
};
static constexpr StringId kWindowTitle = STR_THEMES_TITLE;
@@ -101,7 +102,8 @@ namespace OpenRCT2::Ui::Windows
makeWidget({ 10, 54}, {290, 12}, WidgetType::checkbox, WindowColour::secondary, STR_THEMES_OPTION_RCT1_RIDE_CONTROLS ), // rct1 ride lights
makeWidget({ 10, 69}, {290, 12}, WidgetType::checkbox, WindowColour::secondary, STR_THEMES_OPTION_RCT1_PARK_CONTROLS ), // rct1 park lights
makeWidget({ 10, 84}, {290, 12}, WidgetType::checkbox, WindowColour::secondary, STR_THEMES_OPTION_RCT1_SCENARIO_SELECTION_FONT ), // rct1 scenario font
makeWidget({ 10, 99}, {290, 12}, WidgetType::checkbox, WindowColour::secondary, STR_THEMES_OPTION_RCT1_BOTTOM_TOOLBAR ) // rct1 bottom toolbar
makeWidget({ 10, 99}, {290, 12}, WidgetType::checkbox, WindowColour::secondary, STR_THEMES_OPTION_RCT1_BOTTOM_TOOLBAR ), // rct1 bottom toolbar
makeWidget({ 10,114}, {290, 12}, WidgetType::checkbox, WindowColour::secondary, STR_THEMES_OPTION_USE_3D_IMAGE_BUTTONS ) // use 3D image buttons
);
// clang-format on
@@ -281,7 +283,7 @@ namespace OpenRCT2::Ui::Windows
}
else if (_selectedTab == WINDOW_THEMES_TAB_FEATURES)
{
if (WindowSetResize(*this, { 320, 122 }, { 320, 122 }))
if (WindowSetResize(*this, { 320, 137 }, { 320, 137 }))
GfxInvalidateScreen();
}
else
@@ -329,6 +331,7 @@ namespace OpenRCT2::Ui::Windows
widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WidgetType::empty;
widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WidgetType::empty;
widgets[WIDX_THEMES_RCT1_BOTTOM_TOOLBAR].type = WidgetType::empty;
widgets[WIDX_THEMES_USE_3D_IMAGE_BUTTONS].type = WidgetType::empty;
widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WidgetType::button;
widgets[WIDX_THEMES_DELETE_BUTTON].type = WidgetType::button;
widgets[WIDX_THEMES_RENAME_BUTTON].type = WidgetType::button;
@@ -346,6 +349,7 @@ namespace OpenRCT2::Ui::Windows
widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WidgetType::checkbox;
widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WidgetType::checkbox;
widgets[WIDX_THEMES_RCT1_BOTTOM_TOOLBAR].type = WidgetType::checkbox;
widgets[WIDX_THEMES_USE_3D_IMAGE_BUTTONS].type = WidgetType::checkbox;
widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WidgetType::empty;
widgets[WIDX_THEMES_DELETE_BUTTON].type = WidgetType::empty;
widgets[WIDX_THEMES_RENAME_BUTTON].type = WidgetType::empty;
@@ -358,6 +362,7 @@ namespace OpenRCT2::Ui::Windows
setCheckboxValue(
WIDX_THEMES_RCT1_SCENARIO_FONT, ThemeGetFlags() & UITHEME_FLAG_USE_ALTERNATIVE_SCENARIO_SELECT_FONT);
setCheckboxValue(WIDX_THEMES_RCT1_BOTTOM_TOOLBAR, ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR);
setCheckboxValue(WIDX_THEMES_USE_3D_IMAGE_BUTTONS, ThemeGetFlags() & UITHEME_FLAG_USE_3D_IMAGE_BUTTONS);
}
else
{
@@ -369,6 +374,7 @@ namespace OpenRCT2::Ui::Windows
widgets[WIDX_THEMES_RCT1_PARK_LIGHTS].type = WidgetType::empty;
widgets[WIDX_THEMES_RCT1_SCENARIO_FONT].type = WidgetType::empty;
widgets[WIDX_THEMES_RCT1_BOTTOM_TOOLBAR].type = WidgetType::empty;
widgets[WIDX_THEMES_USE_3D_IMAGE_BUTTONS].type = WidgetType::empty;
widgets[WIDX_THEMES_DUPLICATE_BUTTON].type = WidgetType::empty;
widgets[WIDX_THEMES_DELETE_BUTTON].type = WidgetType::empty;
widgets[WIDX_THEMES_RENAME_BUTTON].type = WidgetType::empty;
@@ -497,6 +503,19 @@ namespace OpenRCT2::Ui::Windows
ThemeSave();
windowMgr->InvalidateAll();
}
break;
case WIDX_THEMES_USE_3D_IMAGE_BUTTONS:
if (ThemeGetFlags() & UITHEME_FLAG_PREDEFINED)
{
ContextShowError(STR_THEMES_ERR_CANT_CHANGE_THIS_THEME, kStringIdNone, {});
}
else
{
ThemeSetFlags(ThemeGetFlags() ^ static_cast<uint8_t>(UITHEME_FLAG_USE_3D_IMAGE_BUTTONS));
ThemeSave();
windowMgr->InvalidateAll();
}
break;
}
}

View File

@@ -32,6 +32,11 @@ namespace OpenRCT2
trnBtn = 7,
tab = 8,
flatBtn = 9,
/**
* For stuff that mostly acts as a label, while providing a way for power users to quickly
* open the associated window. For example: the money display in the lower left of the screen.
*/
hiddenButton = 11,
button = 10,
labelCentred = 12, // Centred text
tableHeader = 13, // Left-aligned textual button