diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index 7f1c169bcb..988652654f 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -1089,14 +1089,19 @@ declare global { type ListViewItem = string[]; + interface RowColumn { + row: number; + column: number; + } + interface ListView extends Widget { scroll?: ScrollType; isStriped?: boolean; showColumnHeaders?: boolean; columns?: ListViewColumn[]; items?: string[] | ListViewItem[]; - selectedIndex?: number; - highlightedIndex?: number; + selectedCell?: RowColumn; + readonly highlightedCell?: RowColumn; canSelect?: boolean; onHighlight: (item: number, column: number) => void; diff --git a/src/openrct2-ui/scripting/CustomListView.cpp b/src/openrct2-ui/scripting/CustomListView.cpp index 5d8b02610d..c4df956ce0 100644 --- a/src/openrct2-ui/scripting/CustomListView.cpp +++ b/src/openrct2-ui/scripting/CustomListView.cpp @@ -85,6 +85,28 @@ namespace OpenRCT2::Scripting } return result; } + + template<> std::optional FromDuk(const DukValue& d) + { + if (d.type() == DukValue::Type::OBJECT) + { + auto dukRow = d["row"]; + auto dukColumn = d["column"]; + if (dukRow.type() == DukValue::Type::NUMBER && dukColumn.type() == DukValue::Type::NUMBER) + { + return RowColumn(dukRow.as_int(), dukColumn.as_int()); + } + } + return std::nullopt; + } + + template<> DukValue ToDuk(duk_context* ctx, const RowColumn& value) + { + DukObject obj(ctx); + obj.Set("row", value.Row); + obj.Set("column", value.Column); + return obj.Take(); + } } // namespace OpenRCT2::Scripting void CustomListView::SetItems(const std::vector& items) diff --git a/src/openrct2-ui/scripting/CustomListView.h b/src/openrct2-ui/scripting/CustomListView.h index dda7c69825..729d21a7ba 100644 --- a/src/openrct2-ui/scripting/CustomListView.h +++ b/src/openrct2-ui/scripting/CustomListView.h @@ -149,6 +149,8 @@ namespace OpenRCT2::Scripting template<> std::optional FromDuk(const DukValue& d); template<> ListViewColumn FromDuk(const DukValue& d); template<> ListViewItem FromDuk(const DukValue& d); + template<> std::optional FromDuk(const DukValue& d); + template<> DukValue ToDuk(duk_context* ctx, const RowColumn& value); } // namespace OpenRCT2::Scripting #endif diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp index 992d0d8c7c..0b1fa7b928 100644 --- a/src/openrct2-ui/scripting/CustomWindow.cpp +++ b/src/openrct2-ui/scripting/CustomWindow.cpp @@ -1106,11 +1106,11 @@ namespace OpenRCT2::Ui::Windows { if (w->custom_info != nullptr) { - auto& customInfo = GetInfo(w); + auto& info = GetInfo(w); auto scrollIndex = window_get_scroll_data_index(w, widgetIndex); if (scrollIndex < static_cast(info.ListViews.size())) { - return &customInfo.ListViews[scrollIndex]; + return &info.ListViews[scrollIndex]; } } return nullptr; diff --git a/src/openrct2-ui/scripting/ScWidget.hpp b/src/openrct2-ui/scripting/ScWidget.hpp index 26987c71d0..85912da76b 100644 --- a/src/openrct2-ui/scripting/ScWidget.hpp +++ b/src/openrct2-ui/scripting/ScWidget.hpp @@ -40,7 +40,7 @@ namespace OpenRCT2::Scripting { } - static DukValue ToDuk(duk_context* ctx, rct_window* w, rct_widgetindex widgetIndex); + static DukValue ToDukValue(duk_context* ctx, rct_window* w, rct_widgetindex widgetIndex); private: std::string type_get() const @@ -347,6 +347,9 @@ namespace OpenRCT2::Scripting { dukglue_set_base_class(ctx); dukglue_register_property(ctx, &ScListViewWidget::isStriped_get, &ScListViewWidget::isStriped_set, "isStriped"); + dukglue_register_property(ctx, &ScListViewWidget::highlightedCell_get, nullptr, "highlightedCell"); + dukglue_register_property( + ctx, &ScListViewWidget::selectedCell_get, &ScListViewWidget::selectedCell_set, "selectedCell"); } private: @@ -369,6 +372,37 @@ namespace OpenRCT2::Scripting } } + 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>(value); + } + } + CustomListView* GetListView() const { auto w = GetWindow(); @@ -380,7 +414,7 @@ namespace OpenRCT2::Scripting } }; - inline DukValue ScWidget::ToDuk(duk_context* ctx, rct_window* w, rct_widgetindex widgetIndex) + inline DukValue ScWidget::ToDukValue(duk_context* ctx, rct_window* w, rct_widgetindex widgetIndex) { const auto& widget = w->widgets[widgetIndex]; auto c = w->classification; diff --git a/src/openrct2-ui/scripting/ScWindow.hpp b/src/openrct2-ui/scripting/ScWindow.hpp index 1f2dd412db..106b82281b 100644 --- a/src/openrct2-ui/scripting/ScWindow.hpp +++ b/src/openrct2-ui/scripting/ScWindow.hpp @@ -188,7 +188,7 @@ namespace OpenRCT2::Scripting rct_widgetindex widgetIndex = 0; for (auto widget = w->widgets; widget->type != WWT_LAST; widget++) { - result.push_back(ScWidget::ToDuk(ctx, w, widgetIndex)); + result.push_back(ScWidget::ToDukValue(ctx, w, widgetIndex)); widgetIndex++; } } @@ -268,7 +268,7 @@ namespace OpenRCT2::Scripting auto widgetIndex = FindWidgetIndexByName(w, name); if (widgetIndex) { - return ScWidget::ToDuk(ctx, w, *widgetIndex); + return ScWidget::ToDukValue(ctx, w, *widgetIndex); } } return GetObjectAsDukValue(ctx, nullptr); diff --git a/src/openrct2/scripting/Duktape.hpp b/src/openrct2/scripting/Duktape.hpp index 02ec125821..c36849ac4d 100644 --- a/src/openrct2/scripting/Duktape.hpp +++ b/src/openrct2/scripting/Duktape.hpp @@ -194,6 +194,15 @@ namespace OpenRCT2::Scripting template DukValue ToDuk(duk_context* ctx, const T& value) = delete; template T FromDuk(const DukValue& s) = delete; + template<> inline DukValue ToDuk(duk_context* ctx, const std::nullptr_t&) + { + duk_push_null(ctx); + return DukValue::take_from_stack(ctx); + } + template DukValue ToDuk(duk_context* ctx, const std::optional& value) + { + return value ? ToDuk(ctx, *value) : ToDuk(ctx, nullptr); + } template<> inline DukValue ToDuk(duk_context* ctx, const std::nullptr_t&) {