1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

Get custom drop downs working

Co-authored-by: Hielke Morsink <hielke.morsink@gmail.com>
This commit is contained in:
Ted John
2018-03-25 23:27:19 +01:00
parent 918022da3e
commit 7047dec1d9
9 changed files with 221 additions and 50 deletions

View File

@@ -17,6 +17,7 @@
#include <openrct2/scripting/Plugin.h>
#include <openrct2-ui/interface/Widget.h>
#include <openrct2-ui/windows/Window.h>
#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<std::string> 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<Plugin> Owner;
CustomWindowDesc Desc;
std::vector<rct_widget> Widgets;
std::vector<size_t> 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<Plugin> owner, const DukValue& dukHandler);
static void InvokeEventHandler(std::shared_ptr<Plugin> owner, const DukValue& dukHandler, const std::vector<DukValue>& args);
rct_window * window_custom_open(std::shared_ptr<Plugin> 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<size_t>(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<DukValue> 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<rct_widget>& 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<size_t>::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<size_t>(widgets.size(), 64); i++)
{
if (widgets[i].flags & WIDGET_FLAGS::IS_ENABLED)
{
w->enabled_widgets |= 1ULL << i;
}
}
}
static void InvokeEventHandler(std::shared_ptr<Plugin> owner, const DukValue& dukHandler)
{
std::vector<DukValue> args;
InvokeEventHandler(owner, dukHandler, args);
}
static void InvokeEventHandler(std::shared_ptr<Plugin> owner, const DukValue& dukHandler, const std::vector<DukValue>& 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());
}
}

View File

@@ -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<sint32>(g_window_list.size());
}
std::shared_ptr<ScWindow> openWindow(DukValue desc)
@@ -76,12 +76,11 @@ namespace OpenRCT2::Scripting
std::shared_ptr<ScWindow> 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<ScWindow>(w);
}
i++;

View File

@@ -7,11 +7,11 @@
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#include <linenoise.hpp>
#include "../Context.h"
#include "../OpenRCT2.h"
#include "../platform/Platform2.h"
#include "../scripting/ScriptEngine.h"
#include "../thirdparty/linenoise.hpp"
#include "InteractiveConsole.h"
using namespace OpenRCT2;

View File

@@ -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;
}
/**

View File

@@ -21,10 +21,14 @@
#include <fstream>
#include <memory>
#include <fcntl.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef _WIN32
#else
#include <fcntl.h>
#include <sys/inotify.h>
#include <sys/types.h>
#include <unistd.h>
#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<char> 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;
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include <dukglue/dukglue.h>
#include "../interface/Console.h"
#include "../interface/InteractiveConsole.h"
namespace OpenRCT2::Scripting
{

View File

@@ -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<uint32>(-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",

View File

@@ -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());
}
}

View File

@@ -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"
#include "dukvalue.h"
#pragma warning(pop)