Add text box widget

This commit is contained in:
Ted John 2021-01-23 14:28:07 +00:00
parent be350f7e2e
commit c0d8786af8
7 changed files with 127 additions and 4 deletions

View File

@ -18,6 +18,7 @@
- Feature: [#13613] Add single-rail roller coaster (Rocky Mountain Construction Raptor).
- Feature: [#13614] Add terrain surfaces from RollerCoaster Tycoon 1.
- Feature: [#13675] [Plugin] Add context.setInterval and context.setTimeout.
- Feature: [#13927] [Plugin] Add isVisible and text box widget.
- Change: [#13346] [Plugin] Renamed FootpathScenery to FootpathAddition, fix typos.
- Fix: [#4605, #11912] Water palettes are not updated properly when selected in Object Selection.
- Fix: [#9631, #10716] Banners drawing glitches when there are more than 32 on the screen at once.

View File

@ -1,5 +1,5 @@
/*****************************************************************************
* Copyright (c) 2014-2020 OpenRCT2 developers
* Copyright (c) 2014-2021 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
@ -1861,7 +1861,7 @@ declare global {
* Represents the type of a widget, e.g. button or label.
*/
type WidgetType =
"button" | "checkbox" | "colourpicker" | "dropdown" | "groupbox" | "label" | "listview" | "spinner" | "viewport";
"button" | "checkbox" | "colourpicker" | "dropdown" | "groupbox" | "label" | "listview" | "spinner" | "textbox" | "viewport";
interface Widget {
type: WidgetType;
@ -1956,6 +1956,12 @@ declare global {
onIncrement: () => void;
}
interface TextBoxWidget extends Widget {
text: string;
maxLength: number;
onChange: (text: string) => void;
}
interface ViewportWidget extends Widget {
viewport: Viewport
}

View File

@ -54,6 +54,7 @@ namespace OpenRCT2::Ui::Windows
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, int32_t dropdownIndex);
static void window_custom_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text);
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);
@ -70,6 +71,7 @@ namespace OpenRCT2::Ui::Windows
events.resize = &window_custom_resize;
events.mouse_down = &window_custom_mousedown;
events.dropdown = &window_custom_dropdown;
events.text_input = &window_custom_textinput;
events.update = &window_custom_update;
events.get_scroll_size = &window_custom_scrollgetsize;
events.scroll_mousedown = &window_custom_scrollmousedown;
@ -98,6 +100,7 @@ namespace OpenRCT2::Ui::Windows
std::vector<ListViewColumn> ListViewColumns;
ScrollbarType Scrollbars{};
int32_t SelectedIndex{};
int32_t MaxLength{};
std::optional<RowColumn> SelectedCell;
bool IsChecked{};
bool IsDisabled{};
@ -194,6 +197,12 @@ namespace OpenRCT2::Ui::Windows
result.OnIncrement = desc["onIncrement"];
result.OnDecrement = desc["onDecrement"];
}
else if (result.Type == "textbox")
{
result.Text = ProcessString(desc["text"]);
result.MaxLength = AsOrDefault(desc["maxLength"], 32);
result.OnChange = desc["onChange"];
}
result.HasBorder = AsOrDefault(desc["border"], result.HasBorder);
return result;
}
@ -554,6 +563,11 @@ namespace OpenRCT2::Ui::Windows
InvokeEventHandler(info.Owner, widgetDesc->OnIncrement);
}
}
else if (widgetDesc->Type == "textbox")
{
auto* text = const_cast<char*>(widgetDesc->Text.c_str());
window_start_textbox(w, widgetIndex, STR_STRING, text, widgetDesc->MaxLength + 1);
}
}
}
@ -577,6 +591,28 @@ namespace OpenRCT2::Ui::Windows
}
}
static void window_custom_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text)
{
if (text == nullptr)
return;
auto& info = GetInfo(w);
auto widgetDesc = info.GetCustomWidgetDesc(w, widgetIndex);
if (widgetDesc != nullptr)
{
if (widgetDesc->Type == "textbox")
{
UpdateWidgetText(w, widgetIndex, text);
std::vector<DukValue> args;
auto ctx = widgetDesc->OnChange.context();
duk_push_string(ctx, text);
args.push_back(DukValue::take_from_stack(ctx));
InvokeEventHandler(info.Owner, widgetDesc->OnChange, args);
}
}
}
static void window_custom_update(rct_window* w)
{
const auto& info = GetInfo(w);
@ -961,6 +997,13 @@ namespace OpenRCT2::Ui::Windows
widget.text = STR_NUMERIC_UP;
widgetList.push_back(widget);
}
else if (desc.Type == "textbox")
{
widget.type = WindowWidgetType::TextBox;
widget.string = const_cast<utf8*>(desc.Text.c_str());
widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING;
widgetList.push_back(widget);
}
else if (desc.Type == "viewport")
{
widget.type = WindowWidgetType::Viewport;
@ -1327,6 +1370,33 @@ namespace OpenRCT2::Ui::Windows
return nullptr;
}
int32_t GetWidgetMaxLength(rct_window* w, rct_widgetindex widgetIndex)
{
if (w->custom_info != nullptr)
{
auto& customInfo = GetInfo(w);
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(w, widgetIndex);
if (customWidgetInfo != nullptr)
{
return customWidgetInfo->MaxLength;
}
}
return 0;
}
void SetWidgetMaxLength(rct_window* w, rct_widgetindex widgetIndex, int32_t value)
{
if (w->custom_info != nullptr)
{
auto& customInfo = GetInfo(w);
auto customWidgetInfo = customInfo.GetCustomWidgetDesc(w, widgetIndex);
if (customWidgetInfo != nullptr)
{
customWidgetInfo->MaxLength = value;
}
}
}
} // namespace OpenRCT2::Ui::Windows
#endif

View File

@ -34,6 +34,8 @@ namespace OpenRCT2::Ui::Windows
std::string GetWidgetName(rct_window* w, rct_widgetindex widgetIndex);
void SetWidgetName(rct_window* w, rct_widgetindex widgetIndex, std::string_view name);
CustomListView* GetCustomListView(rct_window* w, rct_widgetindex widgetIndex);
int32_t GetWidgetMaxLength(rct_window* w, rct_widgetindex widgetIndex);
void SetWidgetMaxLength(rct_window* w, rct_widgetindex widgetIndex, int32_t value);
} // namespace OpenRCT2::Ui::Windows
#endif

View File

@ -832,6 +832,41 @@ namespace OpenRCT2::Scripting
}
};
class ScTextBoxWidget : public ScWidget
{
public:
ScTextBoxWidget(rct_windowclass c, rct_windownumber n, rct_widgetindex widgetIndex)
: ScWidget(c, n, widgetIndex)
{
}
static void Register(duk_context* ctx)
{
dukglue_set_base_class<ScWidget, ScTextBoxWidget>(ctx);
dukglue_register_property(ctx, &ScTextBoxWidget::maxLength_get, &ScTextBoxWidget::maxLength_set, "maxLength");
}
private:
int32_t maxLength_get() const
{
auto w = GetWindow();
if (w != nullptr && IsCustomWindow())
{
return OpenRCT2::Ui::Windows::GetWidgetMaxLength(w, _widgetIndex);
}
return 0;
}
void maxLength_set(int32_t value)
{
auto w = GetWindow();
if (w != nullptr && IsCustomWindow())
{
OpenRCT2::Ui::Windows::SetWidgetMaxLength(w, _widgetIndex, value);
}
}
};
inline DukValue ScWidget::ToDukValue(duk_context* ctx, rct_window* w, rct_widgetindex widgetIndex)
{
const auto& widget = w->widgets[widgetIndex];
@ -851,6 +886,8 @@ namespace OpenRCT2::Scripting
return GetObjectAsDukValue(ctx, std::make_shared<ScDropdownWidget>(c, n, widgetIndex));
case WindowWidgetType::Scroll:
return GetObjectAsDukValue(ctx, std::make_shared<ScListViewWidget>(c, n, widgetIndex));
case WindowWidgetType::TextBox:
return GetObjectAsDukValue(ctx, std::make_shared<ScTextBoxWidget>(c, n, widgetIndex));
default:
return GetObjectAsDukValue(ctx, std::make_shared<ScWidget>(c, n, widgetIndex));
}

View File

@ -37,6 +37,7 @@ void UiScriptExtensions::Extend(ScriptEngine& scriptEngine)
ScCheckBoxWidget::Register(ctx);
ScDropdownWidget::Register(ctx);
ScListViewWidget::Register(ctx);
ScTextBoxWidget::Register(ctx);
ScWindow::Register(ctx);
InitialiseCustomMenuItems(scriptEngine);

View File

@ -2003,12 +2003,18 @@ void window_cancel_textbox()
if (gUsingWidgetTextBox)
{
rct_window* w = window_find_by_number(gCurrentTextBox.window.classification, gCurrentTextBox.window.number);
window_event_textinput_call(w, gCurrentTextBox.widget_index, nullptr);
if (w != nullptr)
{
window_event_textinput_call(w, gCurrentTextBox.widget_index, nullptr);
}
gCurrentTextBox.window.classification = WC_NULL;
gCurrentTextBox.window.number = 0;
context_stop_text_input();
gUsingWidgetTextBox = false;
widget_invalidate(w, gCurrentTextBox.widget_index);
if (w != nullptr)
{
widget_invalidate(w, gCurrentTextBox.widget_index);
}
gCurrentTextBox.widget_index = static_cast<uint16_t>(WindowWidgetType::Last);
}
}