From da98ef63d37b97a12a22dacb5efcafda6c085600 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 15 Feb 2020 15:07:10 +0000 Subject: [PATCH] Implement checkboxes and disabling widgets --- distribution/openrct2.d.ts | 9 ++- src/openrct2-ui/interface/Widget.cpp | 39 +++++++------ src/openrct2-ui/scripting/CustomWindow.cpp | 66 ++++++++++++++++++++-- src/openrct2-ui/scripting/ScWidget.hpp | 42 ++++++++++++++ src/openrct2/interface/Window.h | 2 + 5 files changed, 136 insertions(+), 22 deletions(-) diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index bf3058ba13..5d3dc92d81 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -326,7 +326,7 @@ export interface Park { * Represents the type of a widget, e.g. button or label. */ export type WidgetType = - "button" | "dropdown" | "groupbox" | "label" | "tabview" | "viewport"; + "button" | "checkbox" | "dropdown" | "groupbox" | "label" | "tabview" | "viewport"; export interface Widget { type: WidgetType; @@ -334,6 +334,7 @@ export interface Widget { y: number; width: number; height: number; + isDisabled: boolean; } export interface ButtonWidget extends Widget { @@ -341,6 +342,12 @@ export interface ButtonWidget extends Widget { onClick: () => void; } +export interface CheckboxWidget extends Widget { + text: string; + isChecked: number; + onChanged: (isChecked: boolean) => void; +} + export interface DropdownWidget extends Widget { items: string[]; selectedIndex: number; diff --git a/src/openrct2-ui/interface/Widget.cpp b/src/openrct2-ui/interface/Widget.cpp index 78f2d7311e..a4bc08c884 100644 --- a/src/openrct2-ui/interface/Widget.cpp +++ b/src/openrct2-ui/interface/Widget.cpp @@ -438,6 +438,26 @@ static void widget_text_inset(rct_drawpixelinfo* dpi, rct_window* w, rct_widgeti widget_text(dpi, w, widgetIndex); } +static std::pair widget_get_stringid_and_args(const rct_widget* widget) +{ + auto stringId = widget->text; + void* formatArgs = gCommonFormatArgs; + if (widget->flags & WIDGET_FLAGS::TEXT_IS_STRING) + { + if (widget->string == nullptr || widget->string[0] == '\0') + { + stringId = STR_NONE; + formatArgs = nullptr; + } + else + { + stringId = STR_STRING; + formatArgs = (void*)&widget->string; + } + } + return std::make_pair(stringId, formatArgs); +} + /** * * rct2: 0x006EB535 @@ -455,21 +475,7 @@ static void widget_groupbox_draw(rct_drawpixelinfo* dpi, rct_window* w, rct_widg int32_t textRight = l; // Text - auto stringId = widget->text; - void* formatArgs = gCommonFormatArgs; - if (widget->flags & WIDGET_FLAGS::TEXT_IS_STRING) - { - if (widget->string == nullptr || widget->string[0] == '\0') - { - stringId = STR_NONE; - formatArgs = nullptr; - } - else - { - stringId = STR_STRING; - formatArgs = &widget->string; - } - } + auto [stringId, formatArgs] = widget_get_stringid_and_args(widget); if (stringId != STR_NONE) { uint8_t colour = w->colours[widget->colour] & 0x7F; @@ -639,7 +645,8 @@ static void widget_checkbox_draw(rct_drawpixelinfo* dpi, rct_window* w, rct_widg if (widget->text == STR_NONE) return; - gfx_draw_string_left_centred(dpi, widget->text, gCommonFormatArgs, colour, l + 14, yMid); + auto [stringId, formatArgs] = widget_get_stringid_and_args(widget); + gfx_draw_string_left_centred(dpi, stringId, formatArgs, colour, l + 14, yMid); } /** diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp index 80834e61cb..ceb7e3b292 100644 --- a/src/openrct2-ui/scripting/CustomWindow.cpp +++ b/src/openrct2-ui/scripting/CustomWindow.cpp @@ -91,11 +91,20 @@ namespace OpenRCT2::Ui::Windows std::string Text; std::vector Items; int32_t SelectedIndex{}; + bool IsChecked{}; + bool IsDisabled{}; // Event handlers DukValue OnClick; DukValue OnChange; + static std::string ProcessString(const DukValue& value) + { + if (value.type() == DukValue::Type::STRING) + return ProcessString(value.as_string()); + return {}; + } + static std::string ProcessString(const std::string_view& s) { std::string result; @@ -124,22 +133,32 @@ namespace OpenRCT2::Ui::Windows result.Height = desc["height"].as_int(); if (result.Type == "button") { - result.Text = desc["text"].as_string(); + result.Text = ProcessString(desc["text"]); result.OnClick = desc["onClick"]; } + else if (result.Type == "checkbox") + { + result.Text = ProcessString(desc["text"]); + auto dukIsChecked = desc["isChecked"]; + if (dukIsChecked.type() == DukValue::Type::BOOLEAN) + { + result.IsChecked = dukIsChecked.as_bool(); + } + result.OnChange = desc["onChange"]; + } else if (result.Type == "dropdown") { auto dukItems = desc["items"].as_array(); for (const auto& dukItem : dukItems) { - result.Items.push_back(dukItem.as_string()); + result.Items.push_back(ProcessString(dukItem)); } result.SelectedIndex = desc["selectedIndex"].as_int(); result.OnChange = desc["onChange"]; } else if (result.Type == "groupbox" || result.Type == "label") { - result.Text = ProcessString(desc["text"].as_string()); + result.Text = ProcessString(desc["text"]); } return result; } @@ -312,6 +331,20 @@ namespace OpenRCT2::Ui::Windows { InvokeEventHandler(info.Owner, widgetDesc->OnClick); } + else if (widgetDesc->Type == "checkbox") + { + auto& widget = w->widgets[widgetIndex]; + widget.flags ^= WIDGET_FLAGS::IS_PRESSED; + bool isChecked = widget.flags & WIDGET_FLAGS::IS_PRESSED; + + widget_set_checkbox_value(w, widgetIndex, isChecked); + + std::vector args; + auto ctx = widgetDesc->OnChange.context(); + duk_push_boolean(ctx, isChecked); + args.push_back(DukValue::take_from_stack(ctx)); + InvokeEventHandler(info.Owner, widgetDesc->OnChange, args); + } } break; } @@ -429,6 +462,8 @@ namespace OpenRCT2::Ui::Windows widget.bottom = desc.Y + desc.Height; widget.tooltip = STR_NONE; widget.flags = WIDGET_FLAGS::IS_ENABLED; + if (desc.IsDisabled) + widget.flags |= WIDGET_FLAGS::IS_DISABLED; if (desc.Type == "button") { @@ -437,6 +472,17 @@ namespace OpenRCT2::Ui::Windows widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; widgetList.push_back(widget); } + else if (desc.Type == "checkbox") + { + widget.type = WWT_CHECKBOX; + widget.string = (utf8*)desc.Text.c_str(); + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + if (desc.IsChecked) + { + widget.flags |= WIDGET_FLAGS::IS_PRESSED; + } + widgetList.push_back(widget); + } else if (desc.Type == "dropdown") { widget.type = WWT_DROPDOWN; @@ -510,9 +556,19 @@ namespace OpenRCT2::Ui::Windows 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) + auto mask = 1ULL << i; + auto flags = widgets[i].flags; + if (flags & WIDGET_FLAGS::IS_ENABLED) { - w->enabled_widgets |= 1ULL << i; + w->enabled_widgets |= mask; + } + if (flags & WIDGET_FLAGS::IS_PRESSED) + { + w->pressed_widgets |= mask; + } + if (flags & WIDGET_FLAGS::IS_DISABLED) + { + w->disabled_widgets |= mask; } } } diff --git a/src/openrct2-ui/scripting/ScWidget.hpp b/src/openrct2-ui/scripting/ScWidget.hpp index d06141fbf4..afec19de5a 100644 --- a/src/openrct2-ui/scripting/ScWidget.hpp +++ b/src/openrct2-ui/scripting/ScWidget.hpp @@ -163,6 +163,46 @@ namespace OpenRCT2::Scripting } } + bool isDisabled_get() + { + auto w = GetWindow(); + if (w != nullptr) + { + return widget_is_disabled(w, _widgetIndex); + } + return false; + } + void isDisabled_set(bool value) + { + auto w = GetWindow(); + if (w != nullptr) + { + auto mask = 1ULL << _widgetIndex; + if (value) + w->disabled_widgets |= mask; + else + w->disabled_widgets &= ~mask; + } + } + + bool isChecked_get() + { + auto w = GetWindow(); + if (w != nullptr) + { + return widget_is_pressed(w, _widgetIndex); + } + return false; + } + void isChecked_set(bool value) + { + auto w = GetWindow(); + if (w != nullptr) + { + widget_set_checkbox_value(w, _widgetIndex, value ? 1 : 0); + } + } + std::string text_get() { if (IsCustomWindow()) @@ -193,9 +233,11 @@ namespace OpenRCT2::Scripting dukglue_register_property(ctx, &y_get, &y_set, "y"); dukglue_register_property(ctx, &width_get, &width_set, "width"); dukglue_register_property(ctx, &height_get, &height_set, "height"); + dukglue_register_property(ctx, &isDisabled_get, &isDisabled_set, "isDisabled"); // No so common dukglue_register_property(ctx, &text_get, &text_set, "text"); + dukglue_register_property(ctx, &isChecked_get, &isChecked_set, "isChecked"); } private: diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index fa3ddbedf6..8b3704afb0 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -69,6 +69,8 @@ namespace WIDGET_FLAGS { const WidgetFlags TEXT_IS_STRING = 1 << 0; const WidgetFlags IS_ENABLED = 1 << 1; + const WidgetFlags IS_PRESSED = 1 << 2; + const WidgetFlags IS_DISABLED = 1 << 3; } // namespace WIDGET_FLAGS /**