mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-23 07:43:01 +01:00
Implement custom window tabs
This commit is contained in:
34
distribution/openrct2.d.ts
vendored
34
distribution/openrct2.d.ts
vendored
@@ -737,6 +737,11 @@ declare global {
|
||||
}
|
||||
|
||||
interface ButtonWidget extends Widget {
|
||||
/**
|
||||
* Whether the button has a 3D border.
|
||||
* By default, text buttons have borders and image buttons do not but it can be overridden.
|
||||
*/
|
||||
border?: boolean;
|
||||
image: number;
|
||||
text: string;
|
||||
onClick: () => void;
|
||||
@@ -745,18 +750,18 @@ declare global {
|
||||
interface CheckboxWidget extends Widget {
|
||||
text: string;
|
||||
isChecked: boolean;
|
||||
onChanged: (isChecked: boolean) => void;
|
||||
onChange: (isChecked: boolean) => void;
|
||||
}
|
||||
|
||||
interface DropdownWidget extends Widget {
|
||||
items: string[];
|
||||
selectedIndex: number;
|
||||
onChanged: (index: number) => void;
|
||||
onChange: (index: number) => void;
|
||||
}
|
||||
|
||||
interface LabelWidget extends Widget {
|
||||
text: string;
|
||||
onChanged: (index: number) => void;
|
||||
onChange: (index: number) => void;
|
||||
}
|
||||
|
||||
interface SpinnerWidget extends Widget {
|
||||
@@ -776,10 +781,15 @@ declare global {
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
minWidth: number;
|
||||
maxWidth: number;
|
||||
minHeight: number;
|
||||
maxHeight: number;
|
||||
isSticky: boolean;
|
||||
colours: number[];
|
||||
title: string;
|
||||
widgets: Widget[];
|
||||
tabIndex: number;
|
||||
|
||||
close(): void;
|
||||
bringToFront(): void;
|
||||
@@ -796,10 +806,28 @@ declare global {
|
||||
id?: number;
|
||||
minWidth?: number;
|
||||
minHeight?: number;
|
||||
maxWidth?: number;
|
||||
maxHeight?: number;
|
||||
widgets?: Widget[];
|
||||
colours?: number[];
|
||||
tabs: WindowTabDesc[];
|
||||
|
||||
onClose?: () => void;
|
||||
onUpdate?: () => void;
|
||||
tabChange?: () => void;
|
||||
}
|
||||
|
||||
interface ImageAnimation {
|
||||
frameBase: number;
|
||||
frameCount?: number;
|
||||
frameDuration?: number;
|
||||
offsetX?: number;
|
||||
offsetY?: number;
|
||||
}
|
||||
|
||||
interface WindowTabDesc {
|
||||
image: number | ImageAnimation;
|
||||
widgets?: Widget[];
|
||||
}
|
||||
|
||||
interface Viewport {
|
||||
|
||||
@@ -146,6 +146,10 @@ rct_window* window_create(
|
||||
w->windowPos = screenCoords;
|
||||
w->width = width;
|
||||
w->height = height;
|
||||
w->min_width = width;
|
||||
w->max_width = width;
|
||||
w->min_height = height;
|
||||
w->max_height = height;
|
||||
w->viewport = nullptr;
|
||||
w->event_handlers = event_handlers;
|
||||
w->enabled_widgets = 0;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
# include <openrct2/localisation/Localisation.h>
|
||||
# include <openrct2/localisation/StringIds.h>
|
||||
# include <openrct2/scripting/Plugin.h>
|
||||
# include <openrct2/sprites.h>
|
||||
# include <openrct2/world/Sprite.h>
|
||||
# include <optional>
|
||||
# include <string>
|
||||
@@ -37,6 +38,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
WIDX_TITLE,
|
||||
WIDX_CLOSE,
|
||||
WIDX_CONTENT_PANEL,
|
||||
WIDX_TAB_0,
|
||||
WIDX_CUSTOM_BEGIN,
|
||||
};
|
||||
|
||||
@@ -52,6 +54,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
static void window_custom_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget);
|
||||
static void window_custom_resize(rct_window* w);
|
||||
static void window_custom_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex);
|
||||
static void window_custom_update(rct_window* w);
|
||||
static void window_custom_invalidate(rct_window* w);
|
||||
static void window_custom_paint(rct_window* w, rct_drawpixelinfo* dpi);
|
||||
static void window_custom_update_viewport(rct_window* w);
|
||||
@@ -62,7 +65,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
window_custom_mousedown,
|
||||
window_custom_dropdown,
|
||||
nullptr,
|
||||
nullptr,
|
||||
window_custom_update,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -100,6 +103,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
int32_t SelectedIndex{};
|
||||
bool IsChecked{};
|
||||
bool IsDisabled{};
|
||||
bool HasBorder{};
|
||||
|
||||
// Event handlers
|
||||
DukValue OnClick;
|
||||
@@ -135,10 +139,12 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
auto img = dukImage.as_uint();
|
||||
result.Image = ImageId::FromUInt32(img);
|
||||
result.HasBorder = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Text = ProcessString(desc["text"]);
|
||||
result.HasBorder = true;
|
||||
}
|
||||
result.OnClick = desc["onClick"];
|
||||
}
|
||||
@@ -172,6 +178,46 @@ namespace OpenRCT2::Ui::Windows
|
||||
result.OnIncrement = desc["onIncrement"];
|
||||
result.OnDecrement = desc["onDecrement"];
|
||||
}
|
||||
if (desc["border"].type() == DukValue::Type::BOOLEAN)
|
||||
{
|
||||
result.HasBorder = desc["border"].as_bool();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct CustomTabDesc
|
||||
{
|
||||
ImageId imageFrameBase;
|
||||
uint32_t imageFrameCount;
|
||||
uint32_t imageFrameDuration;
|
||||
int32_t offsetX;
|
||||
int32_t offsetY;
|
||||
std::vector<CustomWidgetDesc> Widgets;
|
||||
|
||||
static CustomTabDesc FromDukValue(const DukValue& desc)
|
||||
{
|
||||
CustomTabDesc result;
|
||||
auto dukImage = desc["image"];
|
||||
if (dukImage.type() == DukValue::Type::NUMBER)
|
||||
{
|
||||
result.imageFrameBase = ImageId::FromUInt32(static_cast<uint32_t>(dukImage.as_int()));
|
||||
}
|
||||
else if (dukImage.type() == DukValue::Type::OBJECT)
|
||||
{
|
||||
result.imageFrameBase = ImageId::FromUInt32(static_cast<uint32_t>(dukImage["frameBase"].as_int()));
|
||||
result.imageFrameCount = AsOrDefault(dukImage["frameCount"], 0);
|
||||
result.imageFrameDuration = AsOrDefault(dukImage["frameDuration"], 0);
|
||||
result.offsetX = AsOrDefault(dukImage["offsetX"], 0);
|
||||
result.offsetY = AsOrDefault(dukImage["offsetY"], 0);
|
||||
}
|
||||
if (desc["widgets"].is_array())
|
||||
{
|
||||
auto dukWidgets = desc["widgets"].as_array();
|
||||
std::transform(dukWidgets.begin(), dukWidgets.end(), std::back_inserter(result.Widgets), [](const DukValue& w) {
|
||||
return CustomWidgetDesc::FromDukValue(w);
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
@@ -191,9 +237,12 @@ namespace OpenRCT2::Ui::Windows
|
||||
std::optional<int32_t> Id;
|
||||
std::vector<CustomWidgetDesc> Widgets;
|
||||
std::vector<colour_t> Colours;
|
||||
std::vector<CustomTabDesc> Tabs;
|
||||
|
||||
// Event handlers
|
||||
DukValue OnClose;
|
||||
DukValue OnUpdate;
|
||||
DukValue OnTabChange;
|
||||
|
||||
CustomWindowDesc() = default;
|
||||
|
||||
@@ -225,6 +274,14 @@ namespace OpenRCT2::Ui::Windows
|
||||
});
|
||||
}
|
||||
|
||||
if (desc["tabs"].is_array())
|
||||
{
|
||||
auto dukTabs = desc["tabs"].as_array();
|
||||
std::transform(dukTabs.begin(), dukTabs.end(), std::back_inserter(result.Tabs), [](const DukValue& w) {
|
||||
return CustomTabDesc::FromDukValue(w);
|
||||
});
|
||||
}
|
||||
|
||||
if (desc["colours"].is_array())
|
||||
{
|
||||
auto dukColours = desc["colours"].as_array();
|
||||
@@ -239,6 +296,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
}
|
||||
|
||||
result.OnClose = desc["onClose"];
|
||||
result.OnUpdate = desc["onUpdate"];
|
||||
result.OnTabChange = desc["onTabChange"];
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -265,7 +324,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
CustomWindowInfo(const CustomWindowInfo&) = delete;
|
||||
|
||||
const CustomWidgetDesc* GetCustomWidgetDesc(size_t widgetIndex) const
|
||||
const CustomWidgetDesc* GetCustomWidgetDesc(rct_window* w, size_t widgetIndex) const
|
||||
{
|
||||
if (widgetIndex < WidgetIndexMap.size())
|
||||
{
|
||||
@@ -274,13 +333,26 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
return &Desc.Widgets[widgetDescIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
auto page = w->page;
|
||||
if (Desc.Tabs.size() > page)
|
||||
{
|
||||
auto& widgets = Desc.Tabs[page].Widgets;
|
||||
auto tabWidgetIndex = widgetDescIndex - Desc.Widgets.size();
|
||||
if (tabWidgetIndex < widgets.size())
|
||||
{
|
||||
return &widgets[widgetDescIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CustomWidgetDesc* GetCustomWidgetDesc(size_t widgetIndex)
|
||||
CustomWidgetDesc* GetCustomWidgetDesc(rct_window* w, size_t widgetIndex)
|
||||
{
|
||||
return const_cast<CustomWidgetDesc*>(std::as_const(*this).GetCustomWidgetDesc(widgetIndex));
|
||||
return const_cast<CustomWidgetDesc*>(std::as_const(*this).GetCustomWidgetDesc(w, widgetIndex));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -297,11 +369,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
auto desc = CustomWindowDesc::FromDukValue(dukDesc);
|
||||
|
||||
uint16_t windowFlags = 0;
|
||||
if (desc.IsResizable())
|
||||
{
|
||||
windowFlags |= WF_RESIZABLE;
|
||||
}
|
||||
uint16_t windowFlags = WF_RESIZABLE;
|
||||
|
||||
rct_window* window{};
|
||||
if (desc.X && desc.Y)
|
||||
@@ -352,6 +420,23 @@ namespace OpenRCT2::Ui::Windows
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_change_tab(rct_window* w, size_t tabIndex)
|
||||
{
|
||||
const auto& info = GetInfo(w);
|
||||
|
||||
w->page = static_cast<int16_t>(tabIndex);
|
||||
w->frame_no = 0;
|
||||
RefreshWidgets(w);
|
||||
|
||||
w->Invalidate();
|
||||
window_event_resize_call(w);
|
||||
window_event_invalidate_call(w);
|
||||
window_init_scroll_widgets(w);
|
||||
w->Invalidate();
|
||||
|
||||
InvokeEventHandler(info.Owner, info.Desc.OnTabChange);
|
||||
}
|
||||
|
||||
static void window_custom_mouseup(rct_window* w, rct_widgetindex widgetIndex)
|
||||
{
|
||||
switch (widgetIndex)
|
||||
@@ -362,7 +447,13 @@ namespace OpenRCT2::Ui::Windows
|
||||
default:
|
||||
{
|
||||
const auto& info = GetInfo(w);
|
||||
const auto widgetDesc = info.GetCustomWidgetDesc(widgetIndex);
|
||||
if (widgetIndex >= WIDX_TAB_0 && widgetIndex < WIDX_TAB_0 + info.Desc.Tabs.size())
|
||||
{
|
||||
window_custom_change_tab(w, widgetIndex - WIDX_TAB_0);
|
||||
break;
|
||||
}
|
||||
|
||||
const auto widgetDesc = info.GetCustomWidgetDesc(w, widgetIndex);
|
||||
if (widgetDesc != nullptr)
|
||||
{
|
||||
if (widgetDesc->Type == "button")
|
||||
@@ -390,9 +481,6 @@ namespace OpenRCT2::Ui::Windows
|
||||
}
|
||||
|
||||
static void window_custom_resize(rct_window* w)
|
||||
{
|
||||
const auto& desc = GetInfo(w).Desc;
|
||||
if (desc.IsResizable())
|
||||
{
|
||||
if (w->width < w->min_width)
|
||||
{
|
||||
@@ -404,14 +492,13 @@ namespace OpenRCT2::Ui::Windows
|
||||
w->Invalidate();
|
||||
w->height = w->min_height;
|
||||
}
|
||||
}
|
||||
window_custom_update_viewport(w);
|
||||
}
|
||||
|
||||
static void window_custom_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget)
|
||||
{
|
||||
const auto& info = GetInfo(w);
|
||||
const auto widgetDesc = info.GetCustomWidgetDesc(widgetIndex);
|
||||
const auto widgetDesc = info.GetCustomWidgetDesc(w, widgetIndex);
|
||||
if (widgetDesc != nullptr)
|
||||
{
|
||||
if (widgetDesc->Type == "dropdown")
|
||||
@@ -451,7 +538,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
return;
|
||||
|
||||
auto& info = GetInfo(w);
|
||||
auto widgetDesc = info.GetCustomWidgetDesc(widgetIndex);
|
||||
auto widgetDesc = info.GetCustomWidgetDesc(w, widgetIndex);
|
||||
if (widgetDesc != nullptr)
|
||||
{
|
||||
if (widgetDesc->Type == "dropdown")
|
||||
@@ -473,6 +560,36 @@ namespace OpenRCT2::Ui::Windows
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_update(rct_window* w)
|
||||
{
|
||||
const auto& info = GetInfo(w);
|
||||
if (info.Desc.Tabs.size() > w->page)
|
||||
{
|
||||
const auto& tab = info.Desc.Tabs[w->page];
|
||||
if (tab.imageFrameCount != 0)
|
||||
{
|
||||
w->frame_no++;
|
||||
if (w->frame_no >= tab.imageFrameCount * tab.imageFrameDuration)
|
||||
{
|
||||
w->frame_no = 0;
|
||||
}
|
||||
widget_invalidate(w, WIDX_TAB_0 + w->page);
|
||||
}
|
||||
InvokeEventHandler(info.Owner, info.Desc.OnUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_set_pressed_tab(rct_window* w)
|
||||
{
|
||||
const auto& info = GetInfo(w);
|
||||
auto numTabs = info.Desc.Tabs.size();
|
||||
for (size_t i = 0; i < numTabs; i++)
|
||||
{
|
||||
w->pressed_widgets &= ~(1 << (WIDX_TAB_0 + i));
|
||||
}
|
||||
w->pressed_widgets |= 1LL << (WIDX_TAB_0 + w->page);
|
||||
}
|
||||
|
||||
static void window_custom_invalidate(rct_window* w)
|
||||
{
|
||||
w->widgets[WIDX_BACKGROUND].right = w->width - 1;
|
||||
@@ -483,13 +600,42 @@ namespace OpenRCT2::Ui::Windows
|
||||
w->widgets[WIDX_CONTENT_PANEL].right = w->width - 1;
|
||||
w->widgets[WIDX_CONTENT_PANEL].bottom = w->height - 1;
|
||||
|
||||
window_custom_set_pressed_tab(w);
|
||||
|
||||
const auto& desc = GetInfo(w).Desc;
|
||||
set_format_arg(0, void*, desc.Title.c_str());
|
||||
}
|
||||
|
||||
static void window_custom_draw_tab_images(rct_window* w, rct_drawpixelinfo* dpi)
|
||||
{
|
||||
const auto& customInfo = GetInfo(w);
|
||||
const auto& tabs = customInfo.Desc.Tabs;
|
||||
size_t tabIndex = 0;
|
||||
for (auto tab : tabs)
|
||||
{
|
||||
auto widgetIndex = static_cast<rct_widgetindex>(WIDX_TAB_0 + tabIndex);
|
||||
auto widget = &w->widgets[widgetIndex];
|
||||
if (widget_is_enabled(w, widgetIndex))
|
||||
{
|
||||
auto l = w->windowPos.x + widget->left + tab.offsetX;
|
||||
auto t = w->windowPos.y + widget->top + tab.offsetY;
|
||||
auto image = tab.imageFrameBase;
|
||||
if (w->page == tabIndex && tab.imageFrameDuration != 0 && tab.imageFrameCount != 0)
|
||||
{
|
||||
auto frame = w->frame_no / tab.imageFrameDuration;
|
||||
auto imageOffset = frame % tab.imageFrameCount;
|
||||
image = image.WithIndex(image.GetIndex() + imageOffset);
|
||||
}
|
||||
gfx_draw_sprite(dpi, image.ToUInt32(), l, t, image.GetTertiary());
|
||||
}
|
||||
tabIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_paint(rct_window* w, rct_drawpixelinfo* dpi)
|
||||
{
|
||||
window_draw_widgets(w, dpi);
|
||||
window_custom_draw_tab_images(w, dpi);
|
||||
if (w->viewport != nullptr)
|
||||
{
|
||||
window_draw_viewport(dpi, w);
|
||||
@@ -517,7 +663,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
auto viewportWidget = &w->widgets[*viewportWidgetIndex];
|
||||
auto& customInfo = GetInfo(w);
|
||||
auto widgetInfo = customInfo.GetCustomWidgetDesc(*viewportWidgetIndex);
|
||||
auto widgetInfo = customInfo.GetCustomWidgetDesc(w, *viewportWidgetIndex);
|
||||
if (widgetInfo != nullptr)
|
||||
{
|
||||
if (w->viewport == nullptr)
|
||||
@@ -560,8 +706,8 @@ namespace OpenRCT2::Ui::Windows
|
||||
widget.colour = 1;
|
||||
widget.left = desc.X;
|
||||
widget.top = desc.Y;
|
||||
widget.right = desc.X + desc.Width;
|
||||
widget.bottom = desc.Y + desc.Height;
|
||||
widget.right = desc.X + desc.Width - 1;
|
||||
widget.bottom = desc.Y + desc.Height - 1;
|
||||
widget.content = std::numeric_limits<uint32_t>::max();
|
||||
widget.tooltip = STR_NONE;
|
||||
widget.flags = WIDGET_FLAGS::IS_ENABLED;
|
||||
@@ -572,7 +718,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
if (desc.Image.HasValue())
|
||||
{
|
||||
widget.type = WWT_FLATBTN;
|
||||
widget.type = desc.HasBorder ? WWT_IMGBTN : WWT_FLATBTN;
|
||||
widget.image = desc.Image.ToUInt32();
|
||||
}
|
||||
else
|
||||
@@ -608,10 +754,10 @@ namespace OpenRCT2::Ui::Windows
|
||||
widget = {};
|
||||
widget.type = WWT_BUTTON;
|
||||
widget.colour = 1;
|
||||
widget.left = desc.X + desc.Width - 11;
|
||||
widget.right = desc.X + desc.Width - 1;
|
||||
widget.left = desc.X + desc.Width - 12;
|
||||
widget.right = desc.X + desc.Width - 2;
|
||||
widget.top = desc.Y + 1;
|
||||
widget.bottom = desc.Y + desc.Height - 1;
|
||||
widget.bottom = desc.Y + desc.Height - 2;
|
||||
widget.text = STR_DROPDOWN_GLYPH;
|
||||
widget.tooltip = STR_NONE;
|
||||
widget.flags |= WIDGET_FLAGS::IS_ENABLED;
|
||||
@@ -642,17 +788,17 @@ namespace OpenRCT2::Ui::Windows
|
||||
widget = {};
|
||||
widget.type = WWT_BUTTON;
|
||||
widget.colour = 1;
|
||||
widget.left = desc.X + desc.Width - 25;
|
||||
widget.left = desc.X + desc.Width - 26;
|
||||
widget.right = widget.left + 12;
|
||||
widget.top = desc.Y + 1;
|
||||
widget.bottom = desc.Y + desc.Height - 1;
|
||||
widget.bottom = desc.Y + desc.Height - 2;
|
||||
widget.text = STR_NUMERIC_DOWN;
|
||||
widget.tooltip = STR_NONE;
|
||||
widget.flags |= WIDGET_FLAGS::IS_ENABLED;
|
||||
widgetList.push_back(widget);
|
||||
|
||||
// Add the increment button
|
||||
widget.left = desc.X + desc.Width - 12;
|
||||
widget.left = desc.X + desc.Width - 13;
|
||||
widget.right = widget.left + 11;
|
||||
widget.text = STR_NUMERIC_UP;
|
||||
widgetList.push_back(widget);
|
||||
@@ -667,10 +813,15 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
static void RefreshWidgets(rct_window* w)
|
||||
{
|
||||
w->enabled_widgets = 0;
|
||||
w->pressed_widgets = 0;
|
||||
w->disabled_widgets = 0;
|
||||
|
||||
auto& info = GetInfo(w);
|
||||
auto& widgets = info.Widgets;
|
||||
|
||||
widgets.clear();
|
||||
info.WidgetIndexMap.clear();
|
||||
|
||||
// Add default widgets (window shim)
|
||||
widgets.insert(widgets.begin(), std::begin(CustomDefaultWidgets), std::end(CustomDefaultWidgets));
|
||||
@@ -678,11 +829,41 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
info.WidgetIndexMap.push_back(std::numeric_limits<size_t>::max());
|
||||
}
|
||||
w->enabled_widgets = 1ULL << WIDX_CLOSE;
|
||||
|
||||
// Add window tabs
|
||||
if (info.Desc.Tabs.size() != 0)
|
||||
{
|
||||
widgets[WIDX_CONTENT_PANEL].top = 43;
|
||||
}
|
||||
for (size_t tabDescIndex = 0; tabDescIndex < info.Desc.Tabs.size(); tabDescIndex++)
|
||||
{
|
||||
rct_widget widget{};
|
||||
widget.type = WWT_TAB;
|
||||
widget.colour = 1;
|
||||
widget.left = static_cast<int16_t>(3 + (tabDescIndex * 31));
|
||||
widget.right = widget.left + 30;
|
||||
widget.top = 17;
|
||||
widget.bottom = 43;
|
||||
widget.image = IMAGE_TYPE_REMAP | SPR_TAB;
|
||||
widget.tooltip = STR_NONE;
|
||||
widgets.push_back(widget);
|
||||
info.WidgetIndexMap.push_back(std::numeric_limits<size_t>::max());
|
||||
w->enabled_widgets |= 1ULL << (widgets.size() - 1);
|
||||
}
|
||||
|
||||
// Add custom widgets
|
||||
for (size_t widgetDescIndex = 0; widgetDescIndex < info.Desc.Widgets.size(); widgetDescIndex++)
|
||||
auto totalWidgets = info.Desc.Widgets.size();
|
||||
auto tabWidgetsOffset = totalWidgets;
|
||||
if (info.Desc.Tabs.size() != 0)
|
||||
{
|
||||
const auto& widgetDesc = info.Desc.Widgets[widgetDescIndex];
|
||||
totalWidgets += info.Desc.Tabs[w->page].Widgets.size();
|
||||
}
|
||||
for (size_t widgetDescIndex = 0; widgetDescIndex < totalWidgets; widgetDescIndex++)
|
||||
{
|
||||
const auto& widgetDesc = widgetDescIndex < info.Desc.Widgets.size()
|
||||
? info.Desc.Widgets[widgetDescIndex]
|
||||
: info.Desc.Tabs[w->page].Widgets[widgetDescIndex - tabWidgetsOffset];
|
||||
auto preWidgetSize = widgets.size();
|
||||
CreateWidget(widgets, widgetDesc);
|
||||
auto numWidetsAdded = widgets.size() - preWidgetSize;
|
||||
@@ -690,17 +871,10 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
info.WidgetIndexMap.push_back(widgetDescIndex);
|
||||
}
|
||||
}
|
||||
|
||||
widgets.push_back({ WIDGETS_END });
|
||||
w->widgets = widgets.data();
|
||||
|
||||
// Enable widgets
|
||||
w->enabled_widgets = 1ULL << WIDX_CLOSE;
|
||||
for (size_t i = 0; i < std::min<size_t>(widgets.size(), 64); i++)
|
||||
{
|
||||
auto mask = 1ULL << i;
|
||||
auto flags = widgets[i].flags;
|
||||
auto widgetIndex = widgets.size() - 1;
|
||||
auto mask = 1ULL << widgetIndex;
|
||||
auto flags = widgets[widgetIndex].flags;
|
||||
if (flags & WIDGET_FLAGS::IS_ENABLED)
|
||||
{
|
||||
w->enabled_widgets |= mask;
|
||||
@@ -714,6 +888,9 @@ namespace OpenRCT2::Ui::Windows
|
||||
w->disabled_widgets |= mask;
|
||||
}
|
||||
}
|
||||
|
||||
widgets.push_back({ WIDGETS_END });
|
||||
w->widgets = widgets.data();
|
||||
}
|
||||
|
||||
static void InvokeEventHandler(const std::shared_ptr<Plugin>& owner, const DukValue& dukHandler)
|
||||
@@ -753,7 +930,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
if (w->custom_info != nullptr)
|
||||
{
|
||||
auto& customInfo = GetInfo(w);
|
||||
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(widgetIndex);
|
||||
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(w, widgetIndex);
|
||||
if (customWidgetInfo != nullptr)
|
||||
{
|
||||
customWidgetInfo->Text = language_convert_string(value);
|
||||
@@ -786,7 +963,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
auto& customInfo = GetInfo(w);
|
||||
for (size_t i = 0; i < customInfo.Widgets.size(); i++)
|
||||
{
|
||||
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(i);
|
||||
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(w, i);
|
||||
if (customWidgetInfo != nullptr)
|
||||
{
|
||||
if (customWidgetInfo->Name == name)
|
||||
|
||||
@@ -101,6 +101,7 @@ namespace OpenRCT2::Scripting
|
||||
if (widget != nullptr)
|
||||
{
|
||||
Invalidate();
|
||||
widget->right = value + widget->right - widget->left;
|
||||
widget->left = value;
|
||||
Invalidate();
|
||||
}
|
||||
@@ -121,6 +122,7 @@ namespace OpenRCT2::Scripting
|
||||
if (widget != nullptr)
|
||||
{
|
||||
Invalidate();
|
||||
widget->bottom = value + widget->bottom - widget->top;
|
||||
widget->top = value;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
@@ -71,11 +71,105 @@ namespace OpenRCT2::Scripting
|
||||
}
|
||||
int32_t width_get() const
|
||||
{
|
||||
return GetWindow()->width;
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return w->width;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void width_set(int32_t value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_resize(w, value - w->width, 0);
|
||||
}
|
||||
}
|
||||
int32_t height_get() const
|
||||
{
|
||||
return GetWindow()->height;
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return w->height;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void height_set(int32_t value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_resize(w, 0, value - w->height);
|
||||
}
|
||||
}
|
||||
int32_t minWidth_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return w->min_width;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void minWidth_set(int32_t value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_set_resize(w, value, w->min_height, w->max_width, w->max_height);
|
||||
}
|
||||
}
|
||||
int32_t maxWidth_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return w->max_width;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void maxWidth_set(int32_t value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_set_resize(w, w->min_width, w->min_height, value, w->max_height);
|
||||
}
|
||||
}
|
||||
int32_t minHeight_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return w->min_height;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void minHeight_set(int32_t value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_set_resize(w, w->min_width, value, w->max_width, w->max_height);
|
||||
}
|
||||
}
|
||||
int32_t maxHeight_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return w->max_height;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void maxHeight_set(int32_t value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_set_resize(w, w->min_width, w->min_height, w->max_width, value);
|
||||
}
|
||||
}
|
||||
bool isSticky_get() const
|
||||
{
|
||||
@@ -144,6 +238,16 @@ namespace OpenRCT2::Scripting
|
||||
}
|
||||
}
|
||||
|
||||
int32_t tabIndex_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr && w->classification == WC_CUSTOM)
|
||||
{
|
||||
return w->page;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
auto w = GetWindow();
|
||||
@@ -183,12 +287,17 @@ namespace OpenRCT2::Scripting
|
||||
dukglue_register_property(ctx, &ScWindow::number_get, nullptr, "number");
|
||||
dukglue_register_property(ctx, &ScWindow::x_get, &ScWindow::x_set, "x");
|
||||
dukglue_register_property(ctx, &ScWindow::y_get, &ScWindow::y_set, "y");
|
||||
dukglue_register_property(ctx, &ScWindow::width_get, nullptr, "width");
|
||||
dukglue_register_property(ctx, &ScWindow::height_get, nullptr, "height");
|
||||
dukglue_register_property(ctx, &ScWindow::width_get, &ScWindow::width_set, "width");
|
||||
dukglue_register_property(ctx, &ScWindow::height_get, &ScWindow::height_set, "height");
|
||||
dukglue_register_property(ctx, &ScWindow::minWidth_get, &ScWindow::minWidth_set, "minWidth");
|
||||
dukglue_register_property(ctx, &ScWindow::maxWidth_get, &ScWindow::maxWidth_set, "maxWidth");
|
||||
dukglue_register_property(ctx, &ScWindow::minHeight_get, &ScWindow::minHeight_set, "minHeight");
|
||||
dukglue_register_property(ctx, &ScWindow::maxHeight_get, &ScWindow::maxHeight_set, "maxHeight");
|
||||
dukglue_register_property(ctx, &ScWindow::isSticky_get, nullptr, "isSticky");
|
||||
dukglue_register_property(ctx, &ScWindow::widgets_get, nullptr, "widgets");
|
||||
dukglue_register_property(ctx, &ScWindow::colours_get, &ScWindow::colours_set, "colours");
|
||||
dukglue_register_property(ctx, &ScWindow::title_get, &ScWindow::title_set, "title");
|
||||
dukglue_register_property(ctx, &ScWindow::tabIndex_get, nullptr, "tabIndex");
|
||||
|
||||
dukglue_register_method(ctx, &ScWindow::close, "close");
|
||||
dukglue_register_method(ctx, &ScWindow::findWidget, "findWidget");
|
||||
|
||||
@@ -1317,8 +1317,8 @@ void window_set_resize(rct_window* w, int32_t minWidth, int32_t minHeight, int32
|
||||
w->max_height = maxHeight;
|
||||
|
||||
// Clamp width and height to minimum and maximum
|
||||
int32_t width = std::clamp<int32_t>(w->width, minWidth, maxWidth);
|
||||
int32_t height = std::clamp<int32_t>(w->height, minHeight, maxHeight);
|
||||
int32_t width = std::clamp<int32_t>(w->width, std::min(minWidth, maxWidth), std::max(minWidth, maxWidth));
|
||||
int32_t height = std::clamp<int32_t>(w->height, std::min(minHeight, maxHeight), std::max(minHeight, maxHeight));
|
||||
|
||||
// Resize window if size has changed
|
||||
if (w->width != width || w->height != height)
|
||||
|
||||
@@ -208,7 +208,7 @@ std::string language_convert_string(const std::string_view& s)
|
||||
state = PARSE_STATE::TOKEN;
|
||||
break;
|
||||
default:
|
||||
if (c >= 32)
|
||||
if (static_cast<uint8_t>(c) >= 32)
|
||||
{
|
||||
result.push_back(c);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user