You've already forked OpenRCT2-Unity
mirror of
https://github.com/izzy2lost/OpenRCT2-Unity.git
synced 2026-03-10 12:38:22 -07:00
Merge pull request #11685 from IntelOrca/plugin/listview-widget
[Plugin] Implement the list view widget
This commit is contained in:
2
.vscode/c_cpp_properties.json
vendored
2
.vscode/c_cpp_properties.json
vendored
@@ -65,7 +65,7 @@
|
||||
"_DEBUG",
|
||||
"UNICODE",
|
||||
"_UNICODE",
|
||||
"__ENABLE_SCRIPTING__"
|
||||
"ENABLE_SCRIPTING"
|
||||
],
|
||||
"intelliSenseMode": "msvc-x64",
|
||||
"browse": {
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
4C358E5221C445F700ADE6BC /* ReplayManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C358E5021C445F700ADE6BC /* ReplayManager.cpp */; };
|
||||
4C3B4236205914F7000C5BB7 /* InGameConsole.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C3B4234205914F7000C5BB7 /* InGameConsole.cpp */; };
|
||||
4C724B2221F0AD790012ADD0 /* BenchSpriteSort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C724B2121F0AD790012ADD0 /* BenchSpriteSort.cpp */; };
|
||||
4C81F7E124672C4D000E61BF /* CustomListView.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C81F7DF24672C4D000E61BF /* CustomListView.cpp */; };
|
||||
4C8A6FF323EB5326001A8255 /* Http.cURL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C8A6FF223EB5326001A8255 /* Http.cURL.cpp */; };
|
||||
4C93F1AD1F8CD9F000A9330D /* Input.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C93F1AC1F8CD9F000A9330D /* Input.cpp */; };
|
||||
4C93F1AF1F8CD9F600A9330D /* KeyboardShortcut.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C93F1AE1F8CD9F600A9330D /* KeyboardShortcut.cpp */; };
|
||||
@@ -838,6 +839,9 @@
|
||||
4C7B54792010DF4C00A52E21 /* Shared.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Shared.cpp; sourceTree = "<group>"; };
|
||||
4C7B547A2010DF4C00A52E21 /* Windows.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Windows.cpp; sourceTree = "<group>"; };
|
||||
4C7B547E2010DFF700A52E21 /* Crash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Crash.h; sourceTree = "<group>"; };
|
||||
4C81F7DF24672C4D000E61BF /* CustomListView.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CustomListView.cpp; path = scripting/CustomListView.cpp; sourceTree = "<group>"; };
|
||||
4C81F7E024672C4D000E61BF /* CustomListView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CustomListView.h; path = scripting/CustomListView.h; sourceTree = "<group>"; };
|
||||
4C81F7E224672C58000E61BF /* ScTileSelection.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ScTileSelection.hpp; path = scripting/ScTileSelection.hpp; sourceTree = "<group>"; };
|
||||
4C8667801EEFDCDF0024AAB8 /* RideGroupManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RideGroupManager.cpp; sourceTree = "<group>"; };
|
||||
4C8667811EEFDCDF0024AAB8 /* RideGroupManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RideGroupManager.h; sourceTree = "<group>"; };
|
||||
4C8A6FF123EB5325001A8255 /* Http.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Http.h; sourceTree = "<group>"; };
|
||||
@@ -1911,10 +1915,13 @@
|
||||
4C25594D244A326100CE7E45 /* scripting */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4C81F7DF24672C4D000E61BF /* CustomListView.cpp */,
|
||||
4C81F7E024672C4D000E61BF /* CustomListView.h */,
|
||||
4C25594F244A328A00CE7E45 /* CustomMenu.cpp */,
|
||||
4C255953244A328A00CE7E45 /* CustomMenu.h */,
|
||||
4C255957244A328B00CE7E45 /* CustomWindow.cpp */,
|
||||
4C25594E244A328A00CE7E45 /* CustomWindow.h */,
|
||||
4C81F7E224672C58000E61BF /* ScTileSelection.hpp */,
|
||||
4C255950244A328A00CE7E45 /* ScUi.hpp */,
|
||||
4C255955244A328A00CE7E45 /* ScViewport.hpp */,
|
||||
4C255951244A328A00CE7E45 /* ScWidget.hpp */,
|
||||
@@ -4019,6 +4026,7 @@
|
||||
C68878C020289B710084B384 /* ApplyPaletteShader.cpp in Sources */,
|
||||
C666EE791F37ACB10061AA04 /* ServerStart.cpp in Sources */,
|
||||
C61ADB231FBBCB8B0024F2EF /* GameBottomToolbar.cpp in Sources */,
|
||||
4C81F7E124672C4D000E61BF /* CustomListView.cpp in Sources */,
|
||||
6341F4E22400AA0F0052902B /* Drawing.Sprite.BMP.cpp in Sources */,
|
||||
C666EE7E1F37ACB10061AA04 /* TitleOptions.cpp in Sources */,
|
||||
F76C887A1EC5324E00FA49E2 /* AudioMixer.cpp in Sources */,
|
||||
|
||||
38
distribution/openrct2.d.ts
vendored
38
distribution/openrct2.d.ts
vendored
@@ -1072,7 +1072,7 @@ declare global {
|
||||
* Represents the type of a widget, e.g. button or label.
|
||||
*/
|
||||
type WidgetType =
|
||||
"button" | "checkbox" | "dropdown" | "groupbox" | "label" | "spinner" | "viewport";
|
||||
"button" | "checkbox" | "dropdown" | "groupbox" | "label" | "listview" | "spinner" | "viewport";
|
||||
|
||||
interface Widget {
|
||||
type: WidgetType;
|
||||
@@ -1113,6 +1113,42 @@ declare global {
|
||||
onChange: (index: number) => void;
|
||||
}
|
||||
|
||||
type SortOrder = "none" | "ascending" | "descending";
|
||||
|
||||
type ScrollbarType = "none" | "horizontal" | "vertical" | "both";
|
||||
|
||||
interface ListViewColumn {
|
||||
canSort?: boolean;
|
||||
sortOrder?: SortOrder;
|
||||
header?: string;
|
||||
headerTooltip?: string;
|
||||
width?: number;
|
||||
ratioWidth?: number;
|
||||
minWidth?: number;
|
||||
maxWidth?: number;
|
||||
}
|
||||
|
||||
type ListViewItem = string[];
|
||||
|
||||
interface RowColumn {
|
||||
row: number;
|
||||
column: number;
|
||||
}
|
||||
|
||||
interface ListView extends Widget {
|
||||
scrollbars?: ScrollbarType;
|
||||
isStriped?: boolean;
|
||||
showColumnHeaders?: boolean;
|
||||
columns?: ListViewColumn[];
|
||||
items?: string[] | ListViewItem[];
|
||||
selectedCell?: RowColumn;
|
||||
readonly highlightedCell?: RowColumn;
|
||||
canSelect?: boolean;
|
||||
|
||||
onHighlight: (item: number, column: number) => void;
|
||||
onClick: (item: number, column: number) => void;
|
||||
}
|
||||
|
||||
interface SpinnerWidget extends Widget {
|
||||
text: string;
|
||||
onDecrement: () => void;
|
||||
|
||||
683
src/openrct2-ui/scripting/CustomListView.cpp
Normal file
683
src/openrct2-ui/scripting/CustomListView.cpp
Normal file
File diff suppressed because it is too large
Load Diff
170
src/openrct2-ui/scripting/CustomListView.h
Normal file
170
src/openrct2-ui/scripting/CustomListView.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2020 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.
|
||||
*****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
|
||||
# include <cstdint>
|
||||
# include <memory>
|
||||
# include <openrct2/scripting/Duktape.hpp>
|
||||
# include <openrct2/scripting/ScriptEngine.h>
|
||||
# include <optional>
|
||||
# include <string>
|
||||
# include <vector>
|
||||
|
||||
namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
using namespace OpenRCT2::Scripting;
|
||||
|
||||
enum class ScrollbarType
|
||||
{
|
||||
None,
|
||||
Horizontal,
|
||||
Vertical,
|
||||
Both
|
||||
};
|
||||
|
||||
enum class ColumnSortOrder
|
||||
{
|
||||
None,
|
||||
Ascending,
|
||||
Descending,
|
||||
};
|
||||
|
||||
struct ListViewColumn
|
||||
{
|
||||
bool CanSort{};
|
||||
ColumnSortOrder SortOrder;
|
||||
std::string Header;
|
||||
std::string HeaderTooltip;
|
||||
std::optional<int32_t> RatioWidth{};
|
||||
std::optional<int32_t> MinWidth{};
|
||||
std::optional<int32_t> MaxWidth{};
|
||||
int32_t Width{};
|
||||
};
|
||||
|
||||
struct ListViewItem
|
||||
{
|
||||
std::vector<std::string> Cells;
|
||||
|
||||
ListViewItem() = default;
|
||||
explicit ListViewItem(const std::string_view& text)
|
||||
{
|
||||
Cells.emplace_back(text);
|
||||
}
|
||||
explicit ListViewItem(std::vector<std::string>&& cells)
|
||||
: Cells(cells)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct RowColumn
|
||||
{
|
||||
int32_t Row{};
|
||||
int32_t Column{};
|
||||
|
||||
RowColumn() = default;
|
||||
RowColumn(int32_t row, int32_t column)
|
||||
: Row(row)
|
||||
, Column(column)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const RowColumn& other) const
|
||||
{
|
||||
return Row == other.Row && Column == other.Column;
|
||||
}
|
||||
|
||||
bool operator!=(const RowColumn& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
class CustomListView
|
||||
{
|
||||
private:
|
||||
static constexpr int32_t HEADER_ROW = -1;
|
||||
|
||||
rct_window* ParentWindow{};
|
||||
size_t ScrollIndex{};
|
||||
std::vector<ListViewColumn> Columns;
|
||||
std::vector<ListViewItem> Items;
|
||||
ScrollbarType Scrollbars = ScrollbarType::Vertical;
|
||||
|
||||
public:
|
||||
std::shared_ptr<Plugin> Owner;
|
||||
std::vector<size_t> SortedItems;
|
||||
std::optional<RowColumn> HighlightedCell;
|
||||
std::optional<RowColumn> LastHighlightedCell;
|
||||
std::optional<RowColumn> SelectedCell;
|
||||
std::optional<int32_t> ColumnHeaderPressed;
|
||||
bool ColumnHeaderPressedCurrentState{};
|
||||
bool ShowColumnHeaders{};
|
||||
bool IsStriped{};
|
||||
ScreenSize LastKnownSize;
|
||||
ColumnSortOrder CurrentSortOrder{};
|
||||
int32_t CurrentSortColumn{};
|
||||
bool LastIsMouseDown{};
|
||||
bool IsMouseDown{};
|
||||
bool CanSelect{};
|
||||
|
||||
DukValue OnClick;
|
||||
DukValue OnHighlight;
|
||||
|
||||
CustomListView(rct_window* parent, size_t scrollIndex);
|
||||
ScrollbarType GetScrollbars() const;
|
||||
void SetScrollbars(ScrollbarType value, bool initialising = false);
|
||||
const std::vector<ListViewColumn>& GetColumns() const;
|
||||
void SetColumns(const std::vector<ListViewColumn>& columns, bool initialising = false);
|
||||
const std::vector<ListViewItem>& GetItems() const;
|
||||
void SetItems(const std::vector<ListViewItem>& items, bool initialising = false);
|
||||
void SetItems(std::vector<ListViewItem>&& items, bool initialising = false);
|
||||
bool SortItem(size_t indexA, size_t indexB, int32_t column);
|
||||
void SortItems(int32_t column);
|
||||
void SortItems(int32_t column, ColumnSortOrder order);
|
||||
void Resize(const ScreenSize& size);
|
||||
ScreenSize GetSize();
|
||||
void MouseOver(const ScreenCoordsXY& pos, bool isMouseDown);
|
||||
void MouseDown(const ScreenCoordsXY& pos);
|
||||
void MouseUp(const ScreenCoordsXY& pos);
|
||||
void Paint(rct_window* w, rct_drawpixelinfo* dpi, const rct_scroll* scroll) const;
|
||||
|
||||
private:
|
||||
void PaintHeading(
|
||||
rct_window* w, rct_drawpixelinfo* dpi, const ScreenCoordsXY& pos, const ScreenSize& size, const std::string& text,
|
||||
ColumnSortOrder sortOrder, bool isPressed) const;
|
||||
void PaintCell(
|
||||
rct_drawpixelinfo* dpi, const ScreenCoordsXY& pos, const ScreenSize& size, const char* text,
|
||||
bool isHighlighted) const;
|
||||
std::optional<RowColumn> GetItemIndexAt(const ScreenCoordsXY& pos);
|
||||
};
|
||||
} // namespace OpenRCT2::Ui::Windows
|
||||
|
||||
class DukValue;
|
||||
|
||||
namespace OpenRCT2::Scripting
|
||||
{
|
||||
using namespace OpenRCT2::Ui::Windows;
|
||||
|
||||
template<> ColumnSortOrder FromDuk(const DukValue& d);
|
||||
template<> std::optional<int32_t> FromDuk(const DukValue& d);
|
||||
template<> ListViewColumn FromDuk(const DukValue& d);
|
||||
template<> ListViewItem FromDuk(const DukValue& d);
|
||||
template<> std::vector<ListViewColumn> FromDuk(const DukValue& d);
|
||||
template<> std::vector<ListViewItem> FromDuk(const DukValue& d);
|
||||
template<> std::optional<RowColumn> FromDuk(const DukValue& d);
|
||||
template<> DukValue ToDuk(duk_context* ctx, const RowColumn& value);
|
||||
template<> DukValue ToDuk(duk_context* ctx, const ListViewColumn& value);
|
||||
template<> ScrollbarType FromDuk(const DukValue& d);
|
||||
template<> DukValue ToDuk(duk_context* ctx, const ScrollbarType& value);
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifdef ENABLE_SCRIPTING
|
||||
|
||||
# include "../interface/Dropdown.h"
|
||||
# include "CustomListView.h"
|
||||
# include "ScUi.hpp"
|
||||
# include "ScWindow.hpp"
|
||||
|
||||
@@ -54,8 +55,13 @@ namespace OpenRCT2::Ui::Windows
|
||||
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_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height);
|
||||
static void window_custom_scrollmousedrag(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
|
||||
static void window_custom_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
|
||||
static void window_custom_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords);
|
||||
static void window_custom_invalidate(rct_window* w);
|
||||
static void window_custom_paint(rct_window* w, rct_drawpixelinfo* dpi);
|
||||
static void window_custom_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex);
|
||||
static void window_custom_update_viewport(rct_window* w);
|
||||
|
||||
static rct_window_event_list window_custom_events = { window_custom_close,
|
||||
@@ -73,10 +79,10 @@ namespace OpenRCT2::Ui::Windows
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
window_custom_scrollgetsize,
|
||||
window_custom_scrollmousedown,
|
||||
window_custom_scrollmousedrag,
|
||||
window_custom_scrollmouseover,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
@@ -85,7 +91,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
nullptr,
|
||||
window_custom_invalidate,
|
||||
window_custom_paint,
|
||||
nullptr };
|
||||
window_custom_scrollpaint };
|
||||
|
||||
struct CustomWidgetDesc
|
||||
{
|
||||
@@ -100,23 +106,23 @@ namespace OpenRCT2::Ui::Windows
|
||||
std::string Text;
|
||||
std::string Tooltip;
|
||||
std::vector<std::string> Items;
|
||||
std::vector<ListViewItem> ListViewItems;
|
||||
std::vector<ListViewColumn> ListViewColumns;
|
||||
ScrollbarType Scrollbars{};
|
||||
int32_t SelectedIndex{};
|
||||
bool IsChecked{};
|
||||
bool IsDisabled{};
|
||||
bool HasBorder{};
|
||||
bool ShowColumnHeaders{};
|
||||
bool IsStriped{};
|
||||
bool CanSelect{};
|
||||
|
||||
// Event handlers
|
||||
DukValue OnClick;
|
||||
DukValue OnChange;
|
||||
DukValue OnIncrement;
|
||||
DukValue OnDecrement;
|
||||
|
||||
static std::string ProcessString(const DukValue& value)
|
||||
{
|
||||
if (value.type() == DukValue::Type::STRING)
|
||||
return language_convert_string(value.as_string());
|
||||
return {};
|
||||
}
|
||||
DukValue OnHighlight;
|
||||
|
||||
static CustomWidgetDesc FromDukValue(DukValue desc)
|
||||
{
|
||||
@@ -157,11 +163,6 @@ namespace OpenRCT2::Ui::Windows
|
||||
}
|
||||
else if (result.Type == "dropdown")
|
||||
{
|
||||
auto dukItems = desc["items"].as_array();
|
||||
for (const auto& dukItem : dukItems)
|
||||
{
|
||||
result.Items.push_back(ProcessString(dukItem));
|
||||
}
|
||||
result.SelectedIndex = desc["selectedIndex"].as_int();
|
||||
result.OnChange = desc["onChange"];
|
||||
}
|
||||
@@ -169,6 +170,20 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
result.Text = ProcessString(desc["text"]);
|
||||
}
|
||||
else if (result.Type == "listview")
|
||||
{
|
||||
result.ListViewColumns = FromDuk<std::vector<ListViewColumn>>(desc["columns"]);
|
||||
result.ListViewItems = FromDuk<std::vector<ListViewItem>>(desc["items"]);
|
||||
result.ShowColumnHeaders = AsOrDefault(desc["showColumnHeaders"], false);
|
||||
result.IsStriped = AsOrDefault(desc["isStriped"], false);
|
||||
result.OnClick = desc["onClick"];
|
||||
result.OnHighlight = desc["onHighlight"];
|
||||
result.CanSelect = AsOrDefault(desc["canSelect"], false);
|
||||
if (desc["scrollbars"].type() == DukValue::UNDEFINED)
|
||||
result.Scrollbars = ScrollbarType::Vertical;
|
||||
else
|
||||
result.Scrollbars = FromDuk<ScrollbarType>(desc["scrollbars"]);
|
||||
}
|
||||
else if (result.Type == "spinner")
|
||||
{
|
||||
result.Text = ProcessString(desc["text"]);
|
||||
@@ -312,6 +327,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
CustomWindowDesc Desc;
|
||||
std::vector<rct_widget> Widgets;
|
||||
std::vector<size_t> WidgetIndexMap;
|
||||
std::vector<CustomListView> ListViews;
|
||||
|
||||
CustomWindowInfo(std::shared_ptr<Plugin> owner, const CustomWindowDesc& desc)
|
||||
: Owner(owner)
|
||||
@@ -401,8 +417,6 @@ namespace OpenRCT2::Ui::Windows
|
||||
window->max_height = desc.MaxHeight.value_or(std::numeric_limits<uint16_t>::max());
|
||||
}
|
||||
RefreshWidgets(window);
|
||||
window_init_scroll_widgets(window);
|
||||
window_custom_update_viewport(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -576,6 +590,44 @@ namespace OpenRCT2::Ui::Windows
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height)
|
||||
{
|
||||
auto& info = GetInfo(w);
|
||||
if (scrollIndex < static_cast<int32_t>(info.ListViews.size()))
|
||||
{
|
||||
auto size = info.ListViews[scrollIndex].GetSize();
|
||||
*width = size.width;
|
||||
*height = size.height;
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
auto& info = GetInfo(w);
|
||||
if (scrollIndex < static_cast<int32_t>(info.ListViews.size()))
|
||||
{
|
||||
info.ListViews[scrollIndex].MouseDown(screenCoords);
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_scrollmousedrag(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
auto& info = GetInfo(w);
|
||||
if (scrollIndex < static_cast<int32_t>(info.ListViews.size()))
|
||||
{
|
||||
info.ListViews[scrollIndex].MouseOver(screenCoords, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords)
|
||||
{
|
||||
auto& info = GetInfo(w);
|
||||
if (scrollIndex < static_cast<int32_t>(info.ListViews.size()))
|
||||
{
|
||||
info.ListViews[scrollIndex].MouseOver(screenCoords, false);
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_set_pressed_tab(rct_window* w)
|
||||
{
|
||||
const auto& info = GetInfo(w);
|
||||
@@ -604,6 +656,28 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
const auto& desc = GetInfo(w).Desc;
|
||||
set_format_arg(0, void*, desc.Title.c_str());
|
||||
|
||||
auto& info = GetInfo(w);
|
||||
size_t scrollIndex = 0;
|
||||
for (auto widget = w->widgets; widget->type != WWT_LAST; widget++)
|
||||
{
|
||||
if (widget->type == WWT_SCROLL)
|
||||
{
|
||||
auto& listView = info.ListViews[scrollIndex];
|
||||
auto width = widget->right - widget->left + 1 - 2;
|
||||
auto height = widget->bottom - widget->top + 1 - 2;
|
||||
if (listView.GetScrollbars() == ScrollbarType::Horizontal || listView.GetScrollbars() == ScrollbarType::Both)
|
||||
{
|
||||
height -= SCROLLBAR_WIDTH + 1;
|
||||
}
|
||||
if (listView.GetScrollbars() == ScrollbarType::Vertical || listView.GetScrollbars() == ScrollbarType::Both)
|
||||
{
|
||||
width -= SCROLLBAR_WIDTH + 1;
|
||||
}
|
||||
listView.Resize({ width, height });
|
||||
scrollIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_draw_tab_images(rct_window* w, rct_drawpixelinfo* dpi)
|
||||
@@ -642,6 +716,15 @@ namespace OpenRCT2::Ui::Windows
|
||||
}
|
||||
}
|
||||
|
||||
static void window_custom_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex)
|
||||
{
|
||||
const auto& info = GetInfo(w);
|
||||
if (scrollIndex < static_cast<int32_t>(info.ListViews.size()))
|
||||
{
|
||||
info.ListViews[scrollIndex].Paint(w, dpi, &w->scrolls[scrollIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
static std::optional<rct_widgetindex> GetViewportWidgetIndex(rct_window* w)
|
||||
{
|
||||
rct_widgetindex widgetIndex = 0;
|
||||
@@ -752,6 +835,10 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
widget.string = const_cast<utf8*>(desc.Items[desc.SelectedIndex].c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
widget.string = const_cast<utf8*>("");
|
||||
}
|
||||
widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING;
|
||||
widgetList.push_back(widget);
|
||||
|
||||
@@ -782,6 +869,18 @@ namespace OpenRCT2::Ui::Windows
|
||||
widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING;
|
||||
widgetList.push_back(widget);
|
||||
}
|
||||
else if (desc.Type == "listview")
|
||||
{
|
||||
widget.type = WWT_SCROLL;
|
||||
widget.content = 0;
|
||||
if (desc.Scrollbars == ScrollbarType::Horizontal)
|
||||
widget.content = SCROLL_HORIZONTAL;
|
||||
else if (desc.Scrollbars == ScrollbarType::Vertical)
|
||||
widget.content = SCROLL_VERTICAL;
|
||||
else if (desc.Scrollbars == ScrollbarType::Both)
|
||||
widget.content = SCROLL_BOTH;
|
||||
widgetList.push_back(widget);
|
||||
}
|
||||
else if (desc.Type == "spinner")
|
||||
{
|
||||
widget.type = WWT_SPINNER;
|
||||
@@ -827,6 +926,7 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
widgets.clear();
|
||||
info.WidgetIndexMap.clear();
|
||||
info.ListViews.clear();
|
||||
|
||||
// Add default widgets (window shim)
|
||||
widgets.insert(widgets.begin(), std::begin(CustomDefaultWidgets), std::end(CustomDefaultWidgets));
|
||||
@@ -877,6 +977,20 @@ namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
info.WidgetIndexMap.push_back(widgetDescIndex);
|
||||
}
|
||||
|
||||
if (widgetDesc.Type == "listview")
|
||||
{
|
||||
CustomListView listView(w, info.ListViews.size());
|
||||
listView.SetScrollbars(widgetDesc.Scrollbars, true);
|
||||
listView.SetColumns(widgetDesc.ListViewColumns, true);
|
||||
listView.SetItems(widgetDesc.ListViewItems, true);
|
||||
listView.ShowColumnHeaders = widgetDesc.ShowColumnHeaders;
|
||||
listView.IsStriped = widgetDesc.IsStriped;
|
||||
listView.OnClick = widgetDesc.OnClick;
|
||||
listView.OnHighlight = widgetDesc.OnHighlight;
|
||||
listView.CanSelect = widgetDesc.CanSelect;
|
||||
info.ListViews.push_back(std::move(listView));
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = firstCustomWidgetIndex; i < widgets.size(); i++)
|
||||
@@ -899,6 +1013,9 @@ namespace OpenRCT2::Ui::Windows
|
||||
|
||||
widgets.push_back({ WIDGETS_END });
|
||||
w->widgets = widgets.data();
|
||||
|
||||
window_init_scroll_widgets(w);
|
||||
window_custom_update_viewport(w);
|
||||
}
|
||||
|
||||
static void InvokeEventHandler(const std::shared_ptr<Plugin>& owner, const DukValue& dukHandler)
|
||||
@@ -984,6 +1101,47 @@ namespace OpenRCT2::Ui::Windows
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::string GetWidgetName(rct_window* w, rct_widgetindex widgetIndex)
|
||||
{
|
||||
if (w->custom_info != nullptr)
|
||||
{
|
||||
const auto& customInfo = GetInfo(w);
|
||||
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(w, widgetIndex);
|
||||
if (customWidgetInfo != nullptr)
|
||||
{
|
||||
return customWidgetInfo->Name;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void SetWidgetName(rct_window* w, rct_widgetindex widgetIndex, const std::string_view& name)
|
||||
{
|
||||
if (w->custom_info != nullptr)
|
||||
{
|
||||
auto& customInfo = GetInfo(w);
|
||||
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(w, widgetIndex);
|
||||
if (customWidgetInfo != nullptr)
|
||||
{
|
||||
customWidgetInfo->Name = std::string(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomListView* GetCustomListView(rct_window* w, rct_widgetindex widgetIndex)
|
||||
{
|
||||
if (w->custom_info != nullptr)
|
||||
{
|
||||
auto& info = GetInfo(w);
|
||||
auto scrollIndex = window_get_scroll_data_index(w, widgetIndex);
|
||||
if (scrollIndex < static_cast<int32_t>(info.ListViews.size()))
|
||||
{
|
||||
return &info.ListViews[scrollIndex];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace OpenRCT2::Ui::Windows
|
||||
|
||||
#endif
|
||||
|
||||
@@ -18,11 +18,16 @@
|
||||
|
||||
namespace OpenRCT2::Ui::Windows
|
||||
{
|
||||
class CustomListView;
|
||||
|
||||
std::string GetWindowTitle(rct_window* w);
|
||||
void UpdateWindowTitle(rct_window* w, const std::string_view& value);
|
||||
void UpdateWidgetText(rct_window* w, rct_widgetindex widget, const std::string_view& string_view);
|
||||
rct_window* FindCustomWindowByClassification(const std::string_view& classification);
|
||||
std::optional<rct_widgetindex> FindWidgetIndexByName(rct_window* w, const std::string_view& name);
|
||||
std::string GetWidgetName(rct_window* w, rct_widgetindex widgetIndex);
|
||||
void SetWidgetName(rct_window* w, rct_widgetindex widgetIndex, const std::string_view& name);
|
||||
CustomListView* GetCustomListView(rct_window* w, rct_widgetindex widgetIndex);
|
||||
} // namespace OpenRCT2::Ui::Windows
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
# include "../interface/Widget.h"
|
||||
# include "../interface/Window.h"
|
||||
# include "CustomListView.h"
|
||||
# include "CustomWindow.h"
|
||||
# include "ScViewport.hpp"
|
||||
|
||||
@@ -26,7 +27,7 @@ namespace OpenRCT2::Scripting
|
||||
{
|
||||
class ScWidget
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
rct_windowclass _class{};
|
||||
rct_windownumber _number{};
|
||||
rct_widgetindex _widgetIndex{};
|
||||
@@ -39,7 +40,28 @@ namespace OpenRCT2::Scripting
|
||||
{
|
||||
}
|
||||
|
||||
static DukValue ToDukValue(duk_context* ctx, rct_window* w, rct_widgetindex widgetIndex);
|
||||
|
||||
private:
|
||||
std::string name_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr && IsCustomWindow())
|
||||
{
|
||||
return OpenRCT2::Ui::Windows::GetWidgetName(w, _widgetIndex);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void name_set(const std::string& value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr && IsCustomWindow())
|
||||
{
|
||||
OpenRCT2::Ui::Windows::SetWidgetName(w, _widgetIndex, value);
|
||||
}
|
||||
}
|
||||
|
||||
std::string type_get() const
|
||||
{
|
||||
auto widget = GetWidget();
|
||||
@@ -190,24 +212,6 @@ namespace OpenRCT2::Scripting
|
||||
}
|
||||
}
|
||||
|
||||
bool isChecked_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return widget_is_pressed(w, _widgetIndex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void isChecked_set(bool value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
widget_set_checkbox_value(w, _widgetIndex, value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t image_get() const
|
||||
{
|
||||
if (IsCustomWindow())
|
||||
@@ -268,6 +272,7 @@ namespace OpenRCT2::Scripting
|
||||
static void Register(duk_context* ctx)
|
||||
{
|
||||
// Common
|
||||
dukglue_register_property(ctx, &ScWidget::name_get, &ScWidget::name_set, "name");
|
||||
dukglue_register_property(ctx, &ScWidget::type_get, nullptr, "type");
|
||||
dukglue_register_property(ctx, &ScWidget::x_get, &ScWidget::x_set, "x");
|
||||
dukglue_register_property(ctx, &ScWidget::y_get, &ScWidget::y_set, "y");
|
||||
@@ -278,11 +283,10 @@ namespace OpenRCT2::Scripting
|
||||
// No so common
|
||||
dukglue_register_property(ctx, &ScWidget::image_get, &ScWidget::image_set, "image");
|
||||
dukglue_register_property(ctx, &ScWidget::text_get, &ScWidget::text_set, "text");
|
||||
dukglue_register_property(ctx, &ScWidget::isChecked_get, &ScWidget::isChecked_set, "isChecked");
|
||||
dukglue_register_property(ctx, &ScWidget::viewport_get, nullptr, "viewport");
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
rct_window* GetWindow() const
|
||||
{
|
||||
if (_class == WC_MAIN_WINDOW)
|
||||
@@ -316,6 +320,248 @@ namespace OpenRCT2::Scripting
|
||||
widget_invalidate_by_number(_class, _number, _widgetIndex);
|
||||
}
|
||||
};
|
||||
|
||||
class ScCheckBoxWidget : public ScWidget
|
||||
{
|
||||
public:
|
||||
ScCheckBoxWidget(rct_windowclass c, rct_windownumber n, rct_widgetindex widgetIndex)
|
||||
: ScWidget(c, n, widgetIndex)
|
||||
{
|
||||
}
|
||||
|
||||
static void Register(duk_context* ctx)
|
||||
{
|
||||
dukglue_set_base_class<ScWidget, ScCheckBoxWidget>(ctx);
|
||||
dukglue_register_property(ctx, &ScCheckBoxWidget::isChecked_get, &ScCheckBoxWidget::isChecked_set, "isChecked");
|
||||
}
|
||||
|
||||
private:
|
||||
bool isChecked_get() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return widget_is_pressed(w, _widgetIndex);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void isChecked_set(bool value)
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
widget_set_checkbox_value(w, _widgetIndex, value ? 1 : 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ScListViewWidget : public ScWidget
|
||||
{
|
||||
public:
|
||||
ScListViewWidget(rct_windowclass c, rct_windownumber n, rct_widgetindex widgetIndex)
|
||||
: ScWidget(c, n, widgetIndex)
|
||||
{
|
||||
}
|
||||
|
||||
static void Register(duk_context* ctx)
|
||||
{
|
||||
dukglue_set_base_class<ScWidget, ScListViewWidget>(ctx);
|
||||
dukglue_register_property(ctx, &ScListViewWidget::canSelect_get, &ScListViewWidget::canSelect_set, "canSelect");
|
||||
dukglue_register_property(ctx, &ScListViewWidget::isStriped_get, &ScListViewWidget::isStriped_set, "isStriped");
|
||||
dukglue_register_property(ctx, &ScListViewWidget::scrollbars_get, &ScListViewWidget::scrollbars_set, "scrollbars");
|
||||
dukglue_register_property(
|
||||
ctx, &ScListViewWidget::showColumnHeaders_get, &ScListViewWidget::showColumnHeaders_set, "showColumnHeaders");
|
||||
dukglue_register_property(ctx, &ScListViewWidget::highlightedCell_get, nullptr, "highlightedCell");
|
||||
dukglue_register_property(
|
||||
ctx, &ScListViewWidget::selectedCell_get, &ScListViewWidget::selectedCell_set, "selectedCell");
|
||||
dukglue_register_property(ctx, &ScListViewWidget::columns_get, &ScListViewWidget::columns_set, "columns");
|
||||
dukglue_register_property(ctx, &ScListViewWidget::items_get, &ScListViewWidget::items_set, "items");
|
||||
}
|
||||
|
||||
private:
|
||||
bool canSelect_get() const
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
return listView->CanSelect;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void canSelect_set(bool value)
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
listView->CanSelect = value;
|
||||
}
|
||||
}
|
||||
|
||||
bool isStriped_get() const
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
return listView->IsStriped;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void isStriped_set(bool value)
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
listView->IsStriped = value;
|
||||
}
|
||||
}
|
||||
|
||||
DukValue scrollbars_get() const
|
||||
{
|
||||
auto ctx = GetContext()->GetScriptEngine().GetContext();
|
||||
auto scrollType = ScrollbarType::None;
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
scrollType = listView->GetScrollbars();
|
||||
}
|
||||
return ToDuk(ctx, scrollType);
|
||||
}
|
||||
|
||||
void scrollbars_set(const DukValue& value)
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
listView->SetScrollbars(FromDuk<ScrollbarType>(value));
|
||||
}
|
||||
}
|
||||
|
||||
bool showColumnHeaders_get() const
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
return listView->ShowColumnHeaders;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void showColumnHeaders_set(bool value)
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
listView->ShowColumnHeaders = value;
|
||||
}
|
||||
}
|
||||
|
||||
DukValue highlightedCell_get()
|
||||
{
|
||||
auto ctx = GetContext()->GetScriptEngine().GetContext();
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
return ToDuk(ctx, listView->LastHighlightedCell);
|
||||
}
|
||||
return ToDuk(ctx, nullptr);
|
||||
}
|
||||
|
||||
DukValue selectedCell_get()
|
||||
{
|
||||
auto ctx = GetContext()->GetScriptEngine().GetContext();
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
return ToDuk(ctx, listView->SelectedCell);
|
||||
}
|
||||
return ToDuk(ctx, nullptr);
|
||||
}
|
||||
|
||||
void selectedCell_set(const DukValue& value)
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
listView->SelectedCell = FromDuk<std::optional<RowColumn>>(value);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>> items_get()
|
||||
{
|
||||
std::vector<std::vector<std::string>> result;
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
for (const auto& item : listView->GetItems())
|
||||
{
|
||||
result.push_back(item.Cells);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void items_set(const DukValue& value)
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
listView->SetItems(FromDuk<std::vector<ListViewItem>>(value));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DukValue> columns_get()
|
||||
{
|
||||
std::vector<DukValue> result;
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
auto ctx = GetContext()->GetScriptEngine().GetContext();
|
||||
for (const auto& column : listView->GetColumns())
|
||||
{
|
||||
result.push_back(ToDuk(ctx, column));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void columns_set(const DukValue& value)
|
||||
{
|
||||
auto listView = GetListView();
|
||||
if (listView != nullptr)
|
||||
{
|
||||
listView->SetColumns(FromDuk<std::vector<ListViewColumn>>(value));
|
||||
}
|
||||
}
|
||||
|
||||
CustomListView* GetListView() const
|
||||
{
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
return GetCustomListView(w, _widgetIndex);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
inline DukValue ScWidget::ToDukValue(duk_context* ctx, rct_window* w, rct_widgetindex widgetIndex)
|
||||
{
|
||||
const auto& widget = w->widgets[widgetIndex];
|
||||
auto c = w->classification;
|
||||
auto n = w->number;
|
||||
switch (widget.type)
|
||||
{
|
||||
case WWT_CHECKBOX:
|
||||
return GetObjectAsDukValue(ctx, std::make_shared<ScCheckBoxWidget>(c, n, widgetIndex));
|
||||
case WWT_SCROLL:
|
||||
return GetObjectAsDukValue(ctx, std::make_shared<ScListViewWidget>(c, n, widgetIndex));
|
||||
default:
|
||||
return GetObjectAsDukValue(ctx, std::make_shared<ScWidget>(c, n, widgetIndex));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
|
||||
@@ -177,16 +177,18 @@ namespace OpenRCT2::Scripting
|
||||
return (flags & (WF_STICK_TO_BACK | WF_STICK_TO_FRONT)) != 0;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<ScWidget>> widgets_get() const
|
||||
std::vector<DukValue> widgets_get() const
|
||||
{
|
||||
std::vector<std::shared_ptr<ScWidget>> result;
|
||||
auto ctx = GetContext()->GetScriptEngine().GetContext();
|
||||
|
||||
std::vector<DukValue> result;
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
rct_widgetindex widgetIndex = 0;
|
||||
for (auto widget = w->widgets; widget->type != WWT_LAST; widget++)
|
||||
{
|
||||
result.push_back(std::make_shared<ScWidget>(_class, _number, widgetIndex));
|
||||
result.push_back(ScWidget::ToDukValue(ctx, w, widgetIndex));
|
||||
widgetIndex++;
|
||||
}
|
||||
}
|
||||
@@ -257,18 +259,19 @@ namespace OpenRCT2::Scripting
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ScWidget> findWidget(std::string name) const
|
||||
DukValue findWidget(std::string name) const
|
||||
{
|
||||
auto ctx = GetContext()->GetScriptEngine().GetContext();
|
||||
auto w = GetWindow();
|
||||
if (w != nullptr)
|
||||
{
|
||||
auto widgetIndex = FindWidgetIndexByName(w, name);
|
||||
if (widgetIndex)
|
||||
{
|
||||
return std::make_shared<ScWidget>(_class, _number, *widgetIndex);
|
||||
return ScWidget::ToDukValue(ctx, w, *widgetIndex);
|
||||
}
|
||||
}
|
||||
return {};
|
||||
return GetObjectAsDukValue<ScWidget>(ctx, nullptr);
|
||||
}
|
||||
|
||||
void bringToFront()
|
||||
|
||||
@@ -32,6 +32,8 @@ void UiScriptExtensions::Extend(ScriptEngine& scriptEngine)
|
||||
ScUi::Register(ctx);
|
||||
ScViewport::Register(ctx);
|
||||
ScWidget::Register(ctx);
|
||||
ScCheckBoxWidget::Register(ctx);
|
||||
ScListViewWidget::Register(ctx);
|
||||
ScWindow::Register(ctx);
|
||||
|
||||
InitialiseCustomMenuItems(scriptEngine);
|
||||
|
||||
@@ -113,6 +113,20 @@ namespace OpenRCT2::Scripting
|
||||
duk_put_prop_string(_ctx, _idx, name);
|
||||
}
|
||||
|
||||
template<typename T> void Set(const char* name, const std::optional<T>& value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
EnsureObjectPushed();
|
||||
duk_push_null(_ctx);
|
||||
duk_put_prop_string(_ctx, _idx, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Set(name, *value);
|
||||
}
|
||||
}
|
||||
|
||||
DukValue Take()
|
||||
{
|
||||
EnsureObjectPushed();
|
||||
@@ -190,6 +204,8 @@ namespace OpenRCT2::Scripting
|
||||
}
|
||||
}
|
||||
|
||||
std::string ProcessString(const DukValue& value);
|
||||
|
||||
template<typename T> DukValue ToDuk(duk_context* ctx, const T& value) = delete;
|
||||
template<typename T> T FromDuk(const DukValue& s) = delete;
|
||||
|
||||
@@ -205,6 +221,17 @@ namespace OpenRCT2::Scripting
|
||||
return DukValue::take_from_stack(ctx);
|
||||
}
|
||||
|
||||
template<size_t TLen> inline DukValue ToDuk(duk_context* ctx, const char (&value)[TLen])
|
||||
{
|
||||
duk_push_string(ctx, value);
|
||||
return DukValue::take_from_stack(ctx);
|
||||
}
|
||||
|
||||
template<typename T> DukValue ToDuk(duk_context* ctx, const std::optional<T>& value)
|
||||
{
|
||||
return value ? ToDuk(ctx, *value) : ToDuk(ctx, nullptr);
|
||||
}
|
||||
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1140,6 +1140,13 @@ std::string OpenRCT2::Scripting::Stringify(const DukValue& val)
|
||||
return ExpressionStringifier::StringifyExpression(val);
|
||||
}
|
||||
|
||||
std::string OpenRCT2::Scripting::ProcessString(const DukValue& value)
|
||||
{
|
||||
if (value.type() == DukValue::Type::STRING)
|
||||
return language_convert_string(value.as_string());
|
||||
return {};
|
||||
}
|
||||
|
||||
bool OpenRCT2::Scripting::IsGameStateMutable()
|
||||
{
|
||||
// Allow single player to alter game state anywhere
|
||||
|
||||
@@ -85,6 +85,29 @@ struct ScreenCoordsXY
|
||||
}
|
||||
};
|
||||
|
||||
struct ScreenSize
|
||||
{
|
||||
int32_t width{};
|
||||
int32_t height{};
|
||||
|
||||
ScreenSize() = default;
|
||||
constexpr ScreenSize(int32_t _width, int32_t _height)
|
||||
: width(_width)
|
||||
, height(_height)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const ScreenSize& other) const
|
||||
{
|
||||
return width == other.width && height == other.height;
|
||||
}
|
||||
|
||||
bool operator!=(const ScreenSize& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Tile coordinates use 1 x/y increment per tile and 1 z increment per step.
|
||||
* Regular ('big', 'sprite') coordinates use 32 x/y increments per tile and 8 z increments per step.
|
||||
|
||||
Reference in New Issue
Block a user