Implement checkboxes and disabling widgets

This commit is contained in:
Ted John 2020-02-15 15:07:10 +00:00
parent a9a67a7a7e
commit da98ef63d3
5 changed files with 136 additions and 22 deletions

View file

@ -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;

View file

@ -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<rct_string_id, void*> 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);
}
/**

View file

@ -91,11 +91,20 @@ namespace OpenRCT2::Ui::Windows
std::string Text;
std::vector<std::string> 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<DukValue> 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<size_t>(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;
}
}
}

View file

@ -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:

View file

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