From 7047dec1d95e809e1b831716c11a1c2d6530edcc Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 25 Mar 2018 23:27:19 +0100 Subject: [PATCH] Get custom drop downs working Co-authored-by: Hielke Morsink --- src/openrct2-ui/scripting/CustomWindow.cpp | 219 +++++++++++++++++---- src/openrct2-ui/scripting/ScUi.hpp | 7 +- src/openrct2/interface/StdInOutConsole.cpp | 2 +- src/openrct2/interface/Window.h | 3 +- src/openrct2/scripting/Plugin.cpp | 21 +- src/openrct2/scripting/ScConsole.hpp | 2 +- src/openrct2/scripting/ScPark.hpp | 4 +- src/openrct2/scripting/ScTile.hpp | 4 +- src/openrct2/thirdparty/dukglue/dukglue.h | 9 +- 9 files changed, 221 insertions(+), 50 deletions(-) diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp index 3d4a67f6a1..1bfd2de279 100644 --- a/src/openrct2-ui/scripting/CustomWindow.cpp +++ b/src/openrct2-ui/scripting/CustomWindow.cpp @@ -17,6 +17,7 @@ #include #include #include +#include "../interface/Dropdown.h" #include "ScUi.hpp" #include "ScWindow.hpp" @@ -41,21 +42,21 @@ namespace OpenRCT2::Ui::Windows { WWT_RESIZE, 1, 0, 0, 14, 0, 0xFFFFFFFF, STR_NONE }, // content panel }; - static void window_custom_close(rct_window *w); - static void window_custom_mouseup(rct_window *w, rct_widgetindex widgetIndex); - static void window_custom_resize(rct_window *w); - static void window_custom_scrollgetsize(rct_window *w, sint32 scrollIndex, sint32 *width, sint32 *height); - 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, sint32 scrollIndex); + static void window_custom_close(rct_window * w); + static void window_custom_mouseup(rct_window * w, rct_widgetindex widgetIndex); + 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, sint32 dropdownIndex); + static void window_custom_invalidate(rct_window * w); + static void window_custom_paint(rct_window * w, rct_drawpixelinfo * dpi); static rct_window_event_list window_custom_events = { window_custom_close, window_custom_mouseup, window_custom_resize, - nullptr, - nullptr, + window_custom_mousedown, + window_custom_dropdown, nullptr, nullptr, nullptr, @@ -85,14 +86,17 @@ namespace OpenRCT2::Ui::Windows { // Properties std::string Type; - sint32 X; - sint32 Y; - sint32 Width; - sint32 Height; + sint32 X{}; + sint32 Y{}; + sint32 Width{}; + sint32 Height{}; std::string Text; + std::vector Items; + sint32 SelectedIndex{}; // Event handlers DukValue OnClick; + DukValue OnChange; static CustomWidgetDesc FromDukValue(DukValue desc) { @@ -102,8 +106,21 @@ namespace OpenRCT2::Ui::Windows result.Y = desc["y"].as_int(); result.Width = desc["width"].as_int(); result.Height = desc["height"].as_int(); - result.Text = desc["text"].as_string(); - result.OnClick = desc["onClick"]; + if (result.Type == "button") + { + result.Text = desc["text"].as_string(); + result.OnClick = desc["onClick"]; + } + else if (result.Type == "dropdown") + { + auto dukItems = desc["items"].as_array(); + for (const auto& dukItem : dukItems) + { + result.Items.push_back(dukItem.as_string()); + } + result.SelectedIndex = desc["selectedIndex"].as_int(); + result.OnChange = desc["onChange"]; + } return result; } }; @@ -173,6 +190,7 @@ namespace OpenRCT2::Ui::Windows std::shared_ptr Owner; CustomWindowDesc Desc; std::vector Widgets; + std::vector WidgetIndexMap; CustomWindowInfo( rct_windowclass cls, @@ -187,6 +205,19 @@ namespace OpenRCT2::Ui::Windows } CustomWindowInfo(const CustomWindowInfo&) = delete; + + const CustomWidgetDesc * GetCustomWidgetDesc(size_t widgetIndex) const + { + if (widgetIndex < WidgetIndexMap.size()) + { + auto widgetDescIndex = WidgetIndexMap[widgetIndex]; + if (widgetDescIndex < Desc.Widgets.size()) + { + return &Desc.Widgets[widgetDescIndex]; + } + } + return nullptr; + } }; static rct_windownumber _nextWindowNumber; @@ -195,6 +226,7 @@ namespace OpenRCT2::Ui::Windows static rct_windownumber GetNewWindowNumber(); static void RefreshWidgets(rct_window * w); static void InvokeEventHandler(std::shared_ptr owner, const DukValue& dukHandler); + static void InvokeEventHandler(std::shared_ptr owner, const DukValue& dukHandler, const std::vector& args); rct_window * window_custom_open(std::shared_ptr owner, DukValue dukDesc) { @@ -261,8 +293,14 @@ namespace OpenRCT2::Ui::Windows default: { const auto& info = GetInfo(w); - const auto& widgetDesc = info.Desc.Widgets[widgetIndex - WIDX_CUSTOM_BEGIN]; - InvokeEventHandler(info.Owner, widgetDesc.OnClick); + const auto widgetDesc = info.GetCustomWidgetDesc(widgetIndex); + if (widgetDesc != nullptr) + { + if (widgetDesc->Type == "button") + { + InvokeEventHandler(info.Owner, widgetDesc->OnClick); + } + } break; } } @@ -286,6 +324,61 @@ namespace OpenRCT2::Ui::Windows } } + 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); + if (widgetDesc != nullptr) + { + if (widgetDesc->Type == "dropdown") + { + widget--; + const auto& items = widgetDesc->Items; + const auto numItems = std::min(items.size(), DROPDOWN_ITEMS_MAX_SIZE); + for (size_t i = 0; i < numItems; i++) + { + gDropdownItemsFormat[i] = STR_STRING; + set_format_arg_on((uint8*)&gDropdownItemsArgs[i], 0, const char *, items[i].c_str()); + } + window_dropdown_show_text_custom_width( + w->x + widget->left, + w->y + widget->top, + widget->bottom - widget->top + 1, + w->colours[widget->colour], + 0, + DROPDOWN_FLAG_STAY_OPEN, + numItems, + widget->right - widget->left - 3); + } + } + } + + static void window_custom_dropdown(rct_window * w, rct_widgetindex widgetIndex, sint32 dropdownIndex) + { + if (dropdownIndex == -1) + return; + + const auto& info = GetInfo(w); + const auto widgetDesc = info.GetCustomWidgetDesc(widgetIndex); + if (widgetDesc != nullptr) + { + if (widgetDesc->Type == "dropdown") + { + if (dropdownIndex >= 0 && (size_t)dropdownIndex < widgetDesc->Items.size()) + { + std::vector args; + auto ctx = widgetDesc->OnChange.context(); + duk_push_int(ctx, dropdownIndex); + args.push_back(DukValue::take_from_stack(ctx)); + InvokeEventHandler(info.Owner, widgetDesc->OnChange, args); + + auto& widget = w->widgets[widgetIndex - 1]; + widget.string = (utf8*)widgetDesc->Items[dropdownIndex].c_str(); + } + } + } + } + static void window_custom_invalidate(rct_window * w) { w->widgets[WIDX_BACKGROUND].right = w->width - 1; @@ -320,6 +413,49 @@ namespace OpenRCT2::Ui::Windows return result; } + static void CreateWidget(std::vector& widgetList, const CustomWidgetDesc &desc) + { + rct_widget widget{}; + widget.colour = 1; + widget.left = desc.X; + widget.top = desc.Y; + widget.right = desc.X + desc.Width; + widget.bottom = desc.Y + desc.Height; + widget.tooltip = STR_NONE; + widget.flags = WIDGET_FLAGS::IS_ENABLED; + + if (desc.Type == "button") + { + widget.type = WWT_BUTTON; + widget.string = (utf8*)desc.Text.c_str(); + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + widgetList.push_back(widget); + } + else if (desc.Type == "dropdown") + { + widget.type = WWT_DROPDOWN; + if (desc.SelectedIndex >= 0 && (size_t)desc.SelectedIndex < desc.Items.size()) + { + widget.string = (utf8*)desc.Items[desc.SelectedIndex].c_str(); + } + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + widgetList.push_back(widget); + + // Add the dropdown button + widget = {}; + widget.type = WWT_BUTTON; + widget.colour = 1; + widget.left = desc.X + desc.Width - 11; + widget.right = desc.X + desc.Width - 1; + widget.top = desc.Y + 1; + widget.bottom = desc.Y + desc.Height - 1; + widget.text = STR_DROPDOWN_GLYPH; + widget.tooltip = STR_NONE; + widget.flags |= WIDGET_FLAGS::IS_ENABLED; + widgetList.push_back(widget); + } + } + static void RefreshWidgets(rct_window * w) { auto& info = GetInfo(w); @@ -329,34 +465,45 @@ namespace OpenRCT2::Ui::Windows // Add default widgets (window shim) widgets.insert(widgets.begin(), std::begin(CustomDefaultWidgets), std::end(CustomDefaultWidgets)); - w->enabled_widgets = 1ULL << WIDX_CLOSE; + for (size_t i = 0; i < widgets.size(); i++) + { + info.WidgetIndexMap.push_back(std::numeric_limits::max()); + } // Add custom widgets - for (const auto& widgetDesc : info.Desc.Widgets) + for (size_t widgetDescIndex = 0; widgetDescIndex < info.Desc.Widgets.size(); widgetDescIndex++) { - rct_widget widget{}; - widget.type = WWT_BUTTON; - widget.left = widgetDesc.X; - widget.top = widgetDesc.Y; - widget.right = widgetDesc.X + widgetDesc.Width; - widget.bottom = widgetDesc.Y + widgetDesc.Height; - widget.string = (utf8*)widgetDesc.Text.c_str(); - widget.tooltip = STR_NONE; - widget.flags = WIDGET_FLAGS::TEXT_IS_STRING; - widgets.push_back(widget); - - auto widgetIndex = widgets.size() - 1; - if (widgetIndex < 64) + const auto& widgetDesc = info.Desc.Widgets[widgetDescIndex]; + auto preWidgetSize = widgets.size(); + CreateWidget(widgets, widgetDesc); + auto numWidetsAdded = widgets.size() - preWidgetSize; + for (size_t i = 0; i < numWidetsAdded; i++) { - w->enabled_widgets |= 1ULL << widgetIndex; + 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(widgets.size(), 64); i++) + { + if (widgets[i].flags & WIDGET_FLAGS::IS_ENABLED) + { + w->enabled_widgets |= 1ULL << i; + } + } } static void InvokeEventHandler(std::shared_ptr owner, const DukValue& dukHandler) + { + std::vector args; + InvokeEventHandler(owner, dukHandler, args); + } + + static void InvokeEventHandler(std::shared_ptr owner, const DukValue& dukHandler, const std::vector& args) { if (dukHandler.is_function()) { @@ -365,7 +512,11 @@ namespace OpenRCT2::Ui::Windows { ScriptExecutionInfo::PluginScope scope(execInfo, owner); dukHandler.push(); - duk_pcall(dukHandler.context(), 0); + for (const auto& arg : args) + { + arg.push(); + } + duk_pcall(dukHandler.context(), (duk_idx_t)args.size()); duk_pop(dukHandler.context()); } } diff --git a/src/openrct2-ui/scripting/ScUi.hpp b/src/openrct2-ui/scripting/ScUi.hpp index 04862be3f5..28e9852c2a 100644 --- a/src/openrct2-ui/scripting/ScUi.hpp +++ b/src/openrct2-ui/scripting/ScUi.hpp @@ -34,7 +34,7 @@ namespace OpenRCT2::Scripting sint32 height_get() { return context_get_height(); } sint32 windows_get() { - return gWindowNextSlot - g_window_list; + return static_cast(g_window_list.size()); } std::shared_ptr openWindow(DukValue desc) @@ -76,12 +76,11 @@ namespace OpenRCT2::Scripting std::shared_ptr getWindow(sint32 index) { - auto windowEnd = gWindowNextSlot; - auto i = 0; - for (auto w = g_window_list; w < windowEnd; w++) + for (sint32 i = 0; i < g_window_list.size(); i++) { if (i == index) { + auto w = g_window_list[i].get(); return std::make_shared(w); } i++; diff --git a/src/openrct2/interface/StdInOutConsole.cpp b/src/openrct2/interface/StdInOutConsole.cpp index 9491b00cd7..c4338d98bb 100644 --- a/src/openrct2/interface/StdInOutConsole.cpp +++ b/src/openrct2/interface/StdInOutConsole.cpp @@ -7,11 +7,11 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include #include "../Context.h" #include "../OpenRCT2.h" #include "../platform/Platform2.h" #include "../scripting/ScriptEngine.h" -#include "../thirdparty/linenoise.hpp" #include "InteractiveConsole.h" using namespace OpenRCT2; diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 63a6ec4912..5f6e6c36b6 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -67,7 +67,8 @@ extern widget_identifier gCurrentTextBox; using WidgetFlags = uint32; namespace WIDGET_FLAGS { - const uint32 TEXT_IS_STRING = 1 << 0; + const WidgetFlags TEXT_IS_STRING = 1 << 0; + const WidgetFlags IS_ENABLED = 1 << 1; } /** diff --git a/src/openrct2/scripting/Plugin.cpp b/src/openrct2/scripting/Plugin.cpp index ce482f3267..6b55cda62e 100644 --- a/src/openrct2/scripting/Plugin.cpp +++ b/src/openrct2/scripting/Plugin.cpp @@ -21,10 +21,14 @@ #include #include -#include -#include -#include -#include +#ifdef _WIN32 + +#else + #include + #include + #include + #include +#endif using namespace OpenRCT2::Scripting; @@ -95,6 +99,8 @@ void Plugin::Update() void Plugin::EnableHotReload() { +#ifdef _WIN32 +#else auto fd = inotify_init(); if (fd >= 0) { @@ -114,12 +120,15 @@ void Plugin::EnableHotReload() close(fd); } } +#endif } bool Plugin::ShouldHotReload() { if (_hotReloadEnabled) { +#ifdef _WIN32 +#else std::vector eventData; eventData.resize(1024); @@ -134,6 +143,7 @@ bool Plugin::ShouldHotReload() } offset += sizeof(inotify_event) + e->len; } +#endif } return false; } @@ -142,8 +152,11 @@ void Plugin::DisableHotReload() { if (_hotReloadEnabled) { +#ifdef _WIN32 +#else inotify_rm_watch(_hotReloadData.FileDesc, _hotReloadData.WatchDesc); close(_hotReloadData.FileDesc); +#endif _hotReloadData = HotReloadData(); _hotReloadEnabled = false; } diff --git a/src/openrct2/scripting/ScConsole.hpp b/src/openrct2/scripting/ScConsole.hpp index 10f5916de9..b3c908b697 100644 --- a/src/openrct2/scripting/ScConsole.hpp +++ b/src/openrct2/scripting/ScConsole.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include "../interface/Console.h" +#include "../interface/InteractiveConsole.h" namespace OpenRCT2::Scripting { diff --git a/src/openrct2/scripting/ScPark.hpp b/src/openrct2/scripting/ScPark.hpp index 3bbab2db7d..656904179a 100644 --- a/src/openrct2/scripting/ScPark.hpp +++ b/src/openrct2/scripting/ScPark.hpp @@ -61,7 +61,7 @@ namespace OpenRCT2::Scripting type = GetParkMessageType(message["type"].as_string()); text = message["text"].as_string(); } - news_item_add_to_queue_raw(type, text.c_str(), -1); + news_item_add_to_queue_raw(type, text.c_str(), static_cast(-1)); } catch (const std::exception&) { @@ -80,7 +80,7 @@ namespace OpenRCT2::Scripting private: uint8 GetParkMessageType(const std::string& key) { - static constexpr auto keys = { + static auto keys = { "attraction", "peep_on_attraction", "peep", diff --git a/src/openrct2/scripting/ScTile.hpp b/src/openrct2/scripting/ScTile.hpp index a3d96a5fdc..c53062b412 100644 --- a/src/openrct2/scripting/ScTile.hpp +++ b/src/openrct2/scripting/ScTile.hpp @@ -20,7 +20,7 @@ namespace OpenRCT2::Scripting std::string type_get() { - if (tile_element_get_type(_element) == TILE_ELEMENT_TYPE_PATH) + if (_element->GetType() == TILE_ELEMENT_TYPE_PATH) { return "footpath"; } @@ -65,7 +65,7 @@ namespace OpenRCT2::Scripting { _count++; } - while (!tile_element_is_last_for_tile(element++)); + while (!(element++)->IsLastForTile()); } } diff --git a/src/openrct2/thirdparty/dukglue/dukglue.h b/src/openrct2/thirdparty/dukglue/dukglue.h index 1b62f7b9d4..1e305e91cb 100644 --- a/src/openrct2/thirdparty/dukglue/dukglue.h +++ b/src/openrct2/thirdparty/dukglue/dukglue.h @@ -1,7 +1,14 @@ #pragma once +#pragma warning(push) +#pragma warning(disable : 4267) // conversion from a to b, possible loss of data +#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4702) // unreachable code + #include "register_function.h" #include "register_class.h" #include "register_property.h" #include "public_util.h" -#include "dukvalue.h" \ No newline at end of file +#include "dukvalue.h" + +#pragma warning(pop)