From af340cbf34d44bfa4bf6f5d5bbbf0d9e956fa186 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 20 Feb 2022 19:27:43 +0000 Subject: [PATCH] Add API for toolbox menu items --- distribution/openrct2.d.ts | 8 +++ src/openrct2-ui/scripting/CustomMenu.cpp | 1 - src/openrct2-ui/scripting/CustomMenu.h | 11 ++- src/openrct2-ui/scripting/ScUi.hpp | 17 ++++- src/openrct2-ui/windows/TitleMenu.cpp | 91 ++++++++++++++++++++---- src/openrct2-ui/windows/TopToolbar.cpp | 24 +++++-- 6 files changed, 131 insertions(+), 21 deletions(-) diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index a372e15268..fbf5bc9d95 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -2124,6 +2124,14 @@ declare global { registerMenuItem(text: string, callback: () => void): void; + /** + * Registers a new item in the toolbox menu on the title screen. + * Only available to intransient plugins. + * @param text The menu item text. + * @param callback The function to call when the menu item is clicked. + */ + registerToolboxMenuItem(text: string, callback: () => void): void; + registerShortcut(desc: ShortcutDesc): void; } diff --git a/src/openrct2-ui/scripting/CustomMenu.cpp b/src/openrct2-ui/scripting/CustomMenu.cpp index 4faf3389dd..b84633fc7b 100644 --- a/src/openrct2-ui/scripting/CustomMenu.cpp +++ b/src/openrct2-ui/scripting/CustomMenu.cpp @@ -279,7 +279,6 @@ namespace OpenRCT2::Scripting duk_error(scriptEngine.GetContext(), DUK_ERR_ERROR, "Invalid parameters."); } } - } // namespace OpenRCT2::Scripting #endif diff --git a/src/openrct2-ui/scripting/CustomMenu.h b/src/openrct2-ui/scripting/CustomMenu.h index 83e15749da..b34d33638f 100644 --- a/src/openrct2-ui/scripting/CustomMenu.h +++ b/src/openrct2-ui/scripting/CustomMenu.h @@ -23,15 +23,24 @@ enum class CursorID : uint8_t; namespace OpenRCT2::Scripting { + enum class CustomToolbarMenuItemKind + { + Standard, + Toolbox, + }; + class CustomToolbarMenuItem { public: std::shared_ptr Owner; + CustomToolbarMenuItemKind Kind; std::string Text; DukValue Callback; - CustomToolbarMenuItem(std::shared_ptr owner, const std::string& text, DukValue callback) + CustomToolbarMenuItem( + std::shared_ptr owner, CustomToolbarMenuItemKind kind, const std::string& text, DukValue callback) : Owner(owner) + , Kind(kind) , Text(text) , Callback(callback) { diff --git a/src/openrct2-ui/scripting/ScUi.hpp b/src/openrct2-ui/scripting/ScUi.hpp index 5f8a55c85a..17050d24cc 100644 --- a/src/openrct2-ui/scripting/ScUi.hpp +++ b/src/openrct2-ui/scripting/ScUi.hpp @@ -313,7 +313,21 @@ namespace OpenRCT2::Scripting { auto& execInfo = _scriptEngine.GetExecInfo(); auto owner = execInfo.GetCurrentPlugin(); - CustomMenuItems.emplace_back(owner, text, callback); + CustomMenuItems.emplace_back(owner, CustomToolbarMenuItemKind::Standard, text, callback); + } + + void registerToolboxMenuItem(const std::string& text, DukValue callback) + { + auto& execInfo = _scriptEngine.GetExecInfo(); + auto owner = execInfo.GetCurrentPlugin(); + if (owner->GetMetadata().Type == PluginType::Intransient) + { + CustomMenuItems.emplace_back(owner, CustomToolbarMenuItemKind::Toolbox, text, callback); + } + else + { + duk_error(_scriptEngine.GetContext(), DUK_ERR_ERROR, "Plugin must be intransient."); + } } void registerShortcut(DukValue desc) @@ -364,6 +378,7 @@ namespace OpenRCT2::Scripting dukglue_register_method(ctx, &ScUi::showScenarioSelect, "showScenarioSelect"); dukglue_register_method(ctx, &ScUi::activateTool, "activateTool"); dukglue_register_method(ctx, &ScUi::registerMenuItem, "registerMenuItem"); + dukglue_register_method(ctx, &ScUi::registerToolboxMenuItem, "registerToolboxMenuItem"); dukglue_register_method(ctx, &ScUi::registerShortcut, "registerShortcut"); } diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp index 8698db5f15..1cc73987f0 100644 --- a/src/openrct2-ui/windows/TitleMenu.cpp +++ b/src/openrct2-ui/windows/TitleMenu.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,16 @@ enum { WIDX_NEW_VERSION, }; +enum +{ + DDIDX_SCENARIO_EDITOR, + DDIDX_CONVERT_SAVED_GAME, + DDIDX_TRACK_DESIGNER, + DDIDX_TRACK_MANAGER, + DDIDX_OPEN_CONTENT_FOLDER, + DDIDX_CUSTOM_BEGIN = 6, +}; + static ScreenRect _filterRect; static constexpr ScreenSize MenuButtonDims = { 82, 82 }; static constexpr ScreenSize UpdateButtonDims = { MenuButtonDims.width * 4, 28 }; @@ -167,36 +178,89 @@ static void WindowTitleMenuMousedown(rct_window* w, rct_widgetindex widgetIndex, { if (widgetIndex == WIDX_GAME_TOOLS) { - gDropdownItems[0].Format = STR_SCENARIO_EDITOR; - gDropdownItems[1].Format = STR_CONVERT_SAVED_GAME_TO_SCENARIO; - gDropdownItems[2].Format = STR_ROLLER_COASTER_DESIGNER; - gDropdownItems[3].Format = STR_TRACK_DESIGNS_MANAGER; - gDropdownItems[4].Format = STR_OPEN_USER_CONTENT_FOLDER; + int32_t i = 0; + gDropdownItems[i++].Format = STR_SCENARIO_EDITOR; + gDropdownItems[i++].Format = STR_CONVERT_SAVED_GAME_TO_SCENARIO; + gDropdownItems[i++].Format = STR_ROLLER_COASTER_DESIGNER; + gDropdownItems[i++].Format = STR_TRACK_DESIGNS_MANAGER; + gDropdownItems[i++].Format = STR_OPEN_USER_CONTENT_FOLDER; + +#ifdef ENABLE_SCRIPTING + auto hasCustomItems = false; + const auto& customMenuItems = OpenRCT2::Scripting::CustomMenuItems; + if (!customMenuItems.empty()) + { + for (const auto& item : customMenuItems) + { + if (item.Kind == OpenRCT2::Scripting::CustomToolbarMenuItemKind::Toolbox) + { + // Add seperator + if (!hasCustomItems) + { + hasCustomItems = true; + gDropdownItems[i++].Format = STR_EMPTY; + } + + gDropdownItems[i].Format = STR_STRING; + auto sz = item.Text.c_str(); + std::memcpy(&gDropdownItems[i].Args, &sz, sizeof(const char*)); + i++; + } + } + } +#endif + + int32_t yOffset = 0; + if (i > 5) + { + yOffset = -(widget->height() + 5 + (i * 12)); + } + WindowDropdownShowText( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, TRANSLUCENT(w->colours[0]), - Dropdown::Flag::StayOpen, 5); + { w->windowPos.x + widget->left, w->windowPos.y + widget->top + yOffset }, widget->height() + 1, + TRANSLUCENT(w->colours[0]), Dropdown::Flag::StayOpen, i); } } +static void InvokeCustomToolboxMenuItem(size_t index) +{ +#ifdef ENABLE_SCRIPTING + const auto& customMenuItems = OpenRCT2::Scripting::CustomMenuItems; + size_t i = 0; + for (const auto& item : customMenuItems) + { + if (item.Kind == OpenRCT2::Scripting::CustomToolbarMenuItemKind::Toolbox) + { + if (i == index) + { + item.Invoke(); + break; + } + i++; + } + } +#endif +} + static void WindowTitleMenuDropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) { if (widgetIndex == WIDX_GAME_TOOLS) { switch (dropdownIndex) { - case 0: + case DDIDX_SCENARIO_EDITOR: Editor::Load(); break; - case 1: + case DDIDX_CONVERT_SAVED_GAME: Editor::ConvertSaveToScenario(); break; - case 2: + case DDIDX_TRACK_DESIGNER: Editor::LoadTrackDesigner(); break; - case 3: + case DDIDX_TRACK_MANAGER: Editor::LoadTrackManager(); break; - case 4: + case DDIDX_OPEN_CONTENT_FOLDER: { auto context = OpenRCT2::GetContext(); auto env = context->GetPlatformEnvironment(); @@ -204,6 +268,9 @@ static void WindowTitleMenuDropdown(rct_window* w, rct_widgetindex widgetIndex, uiContext->OpenFolder(env->GetDirectoryPath(OpenRCT2::DIRBASE::USER)); break; } + default: + InvokeCustomToolboxMenuItem(dropdownIndex - DDIDX_CUSTOM_BEGIN); + break; } } } diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 02bdfe8490..117071df2f 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -3315,10 +3315,13 @@ static void TopToolbarInitMapMenu(rct_window* w, rct_widget* widget) gDropdownItems[i++].Format = STR_EMPTY; for (const auto& item : customMenuItems) { - gDropdownItems[i].Format = STR_STRING; - auto sz = item.Text.c_str(); - std::memcpy(&gDropdownItems[i].Args, &sz, sizeof(const char*)); - i++; + if (item.Kind == OpenRCT2::Scripting::CustomToolbarMenuItemKind::Standard) + { + gDropdownItems[i].Format = STR_STRING; + auto sz = item.Text.c_str(); + std::memcpy(&gDropdownItems[i].Args, &sz, sizeof(const char*)); + i++; + } } } #endif @@ -3356,9 +3359,18 @@ static void TopToolbarMapMenuDropdown(int16_t dropdownIndex) #ifdef ENABLE_SCRIPTING const auto& customMenuItems = OpenRCT2::Scripting::CustomMenuItems; auto customIndex = static_cast(dropdownIndex - customStartIndex); - if (customMenuItems.size() > customIndex) + size_t i = 0; + for (const auto& item : customMenuItems) { - customMenuItems[customIndex].Invoke(); + if (item.Kind == OpenRCT2::Scripting::CustomToolbarMenuItemKind::Standard) + { + if (i == customIndex) + { + item.Invoke(); + break; + } + i++; + } } #endif }