From 82b1a5eb6db4d4b1797e9fb55dbaf62d3555dd6b Mon Sep 17 00:00:00 2001 From: Ted John Date: Sun, 31 Jan 2021 14:07:21 +0000 Subject: [PATCH] Convert CustomWindow into a class --- src/openrct2-ui/scripting/CustomWindow.cpp | 1416 ++++++++++---------- src/openrct2/interface/Window.cpp | 7 +- src/openrct2/interface/Window_internal.h | 3 + 3 files changed, 703 insertions(+), 723 deletions(-) diff --git a/src/openrct2-ui/scripting/CustomWindow.cpp b/src/openrct2-ui/scripting/CustomWindow.cpp index cd0683ae7a..522fb26ec5 100644 --- a/src/openrct2-ui/scripting/CustomWindow.cpp +++ b/src/openrct2-ui/scripting/CustomWindow.cpp @@ -18,6 +18,7 @@ # include # include # include +# include # include # include # include @@ -49,39 +50,6 @@ namespace OpenRCT2::Ui::Windows { WindowWidgetType::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_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); - static void window_custom_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords); - static void window_custom_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords); - 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, int32_t scrollIndex); - static void window_custom_update_viewport(rct_window* w); - - static rct_window_event_list window_custom_events([](auto& events) { - events.close = &window_custom_close; - events.mouse_up = &window_custom_mouseup; - 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; - events.scroll_mousedrag = &window_custom_scrollmousedrag; - events.scroll_mouseover = &window_custom_scrollmouseover; - events.invalidate = &window_custom_invalidate; - events.paint = &window_custom_paint; - events.scroll_paint = &window_custom_scrollpaint; - }); - struct CustomWidgetDesc { // Properties @@ -402,474 +370,755 @@ namespace OpenRCT2::Ui::Windows } }; - static rct_windownumber _nextWindowNumber; - static CustomWindowInfo& GetInfo(rct_window* w); - static rct_windownumber GetNewWindowNumber(); - static void RefreshWidgets(rct_window* w); static void InvokeEventHandler(const std::shared_ptr& owner, const DukValue& dukHandler); static void InvokeEventHandler( const std::shared_ptr& owner, const DukValue& dukHandler, const std::vector& args); - rct_window* window_custom_open(std::shared_ptr owner, DukValue dukDesc) + class CustomWindow : public rct_window { - auto desc = CustomWindowDesc::FromDukValue(dukDesc); + private: + static rct_windownumber _nextWindowNumber; - uint16_t windowFlags = WF_RESIZABLE | WF_TRANSPARENT; - - rct_window* window{}; - if (desc.X && desc.Y) + public: + void Initialise(std::shared_ptr owner, const CustomWindowDesc& desc) { - window = WindowCreate({ *desc.X, *desc.Y }, desc.Width, desc.Height, &window_custom_events, WC_CUSTOM, windowFlags); - } - else - { - window = WindowCreateAutoPos(desc.Width, desc.Height, &window_custom_events, WC_CUSTOM, windowFlags); - } + number = GetNewWindowNumber(); + custom_info = new CustomWindowInfo(owner, desc); + enabled_widgets = (1 << WIDX_CLOSE); - window->number = GetNewWindowNumber(); - window->custom_info = new CustomWindowInfo(owner, desc); - window->enabled_widgets = (1 << WIDX_CLOSE); + // Set window tab + page = desc.TabIndex.value_or(0); - // Set window tab - window->page = desc.TabIndex.value_or(0); - - // Set window colours - window->colours[0] = COLOUR_GREY; - window->colours[1] = COLOUR_GREY; - window->colours[2] = COLOUR_GREY; - auto numColours = std::min(std::size(window->colours), std::size(desc.Colours)); - for (size_t i = 0; i < numColours; i++) - { - window->colours[i] = desc.Colours[i]; - } - - if (desc.IsResizable()) - { - window->min_width = desc.MinWidth.value_or(0); - window->min_height = desc.MinHeight.value_or(0); - window->max_width = desc.MaxWidth.value_or(std::numeric_limits::max()); - window->max_height = desc.MaxHeight.value_or(std::numeric_limits::max()); - } - RefreshWidgets(window); - return window; - } - - static void window_custom_close(rct_window* w) - { - auto info = static_cast(w->custom_info); - if (info != nullptr) - { - InvokeEventHandler(info->Owner, info->Desc.OnClose); - delete info; - w->custom_info = nullptr; - } - } - - static void window_custom_change_tab(rct_window* w, size_t tabIndex) - { - const auto& info = GetInfo(w); - - w->page = static_cast(tabIndex); - w->frame_no = 0; - RefreshWidgets(w); - - w->Invalidate(); - window_event_resize_call(w); - window_event_invalidate_call(w); - WindowInitScrollWidgets(w); - w->Invalidate(); - - InvokeEventHandler(info.Owner, info.Desc.OnTabChange); - } - - static void window_custom_mouseup(rct_window* w, rct_widgetindex widgetIndex) - { - switch (widgetIndex) - { - case WIDX_CLOSE: - window_close(w); - break; - default: + // Set window colours + colours[0] = COLOUR_GREY; + colours[1] = COLOUR_GREY; + colours[2] = COLOUR_GREY; + auto numColours = std::min(std::size(colours), std::size(desc.Colours)); + for (size_t i = 0; i < numColours; i++) { - const auto& info = GetInfo(w); - if (widgetIndex >= WIDX_TAB_0 && widgetIndex < static_cast(WIDX_TAB_0 + info.Desc.Tabs.size())) + colours[i] = desc.Colours[i]; + } + + if (desc.IsResizable()) + { + min_width = desc.MinWidth.value_or(0); + min_height = desc.MinHeight.value_or(0); + max_width = desc.MaxWidth.value_or(std::numeric_limits::max()); + max_height = desc.MaxHeight.value_or(std::numeric_limits::max()); + } + RefreshWidgets(); + } + + void OnClose() override + { + auto info = static_cast(custom_info); + if (info != nullptr) + { + InvokeEventHandler(info->Owner, info->Desc.OnClose); + delete info; + custom_info = nullptr; + } + } + + void OnResize() override + { + if (width < min_width) + { + Invalidate(); + width = min_width; + } + if (height < min_height) + { + Invalidate(); + height = min_height; + } + UpdateViewport(); + } + + void OnUpdate() override + { + const auto& info = GetInfo(this); + if (info.Desc.Tabs.size() > static_cast(page)) + { + const auto& tab = info.Desc.Tabs[page]; + if (tab.imageFrameCount != 0) { - window_custom_change_tab(w, widgetIndex - WIDX_TAB_0); + frame_no++; + if (frame_no >= tab.imageFrameCount * tab.imageFrameDuration) + { + frame_no = 0; + } + widget_invalidate(this, WIDX_TAB_0 + this->page); + } + } + + InvokeEventHandler(info.Owner, info.Desc.OnUpdate); + + // Since the plugin may alter widget positions and sizes during an update event, + // we need to force an update for all list view scrollbars + rct_widgetindex widgetIndex = 0; + for (auto widget = widgets; widget->type != WindowWidgetType::Empty; widget++) + { + if (widget->type == WindowWidgetType::Scroll) + { + WidgetScrollUpdateThumbs(this, widgetIndex); + } + widgetIndex++; + } + } + + void OnPrepareDraw() override + { + widgets[WIDX_BACKGROUND].right = width - 1; + widgets[WIDX_BACKGROUND].bottom = height - 1; + widgets[WIDX_TITLE].right = width - 2; + widgets[WIDX_CLOSE].left = width - 13; + widgets[WIDX_CLOSE].right = width - 3; + widgets[WIDX_CONTENT_PANEL].right = width - 1; + widgets[WIDX_CONTENT_PANEL].bottom = height - 1; + widgets[WIDX_CLOSE].text = (colours[0] & COLOUR_FLAG_TRANSLUCENT) ? STR_CLOSE_X_WHITE : STR_CLOSE_X; + + // Having the content panel visible for transparent windows makes the borders darker than they should be + // For now just hide it if there are no tabs and the window is not resizable + auto& info = GetInfo(this); + auto canResize = (flags & WF_RESIZABLE) != 0 && (min_width != max_width || min_height != max_height); + auto numTabs = info.Desc.Tabs.size(); + if (canResize || numTabs != 0) + { + widgets[WIDX_CONTENT_PANEL].flags &= ~WIDGET_FLAGS::IS_HIDDEN; + } + else + { + widgets[WIDX_CONTENT_PANEL].flags |= WIDGET_FLAGS::IS_HIDDEN; + } + + SetPressedTab(); + + const auto& desc = info.Desc; + auto ft = Formatter::Common(); + ft.Add(desc.Title.c_str()); + + size_t scrollIndex = 0; + for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++) + { + if (widget->type == WindowWidgetType::Scroll) + { + auto& listView = info.ListViews[scrollIndex]; + auto wwidth = widget->width() + 1 - 2; + auto wheight = widget->height() + 1 - 2; + if (listView.GetScrollbars() == ScrollbarType::Horizontal + || listView.GetScrollbars() == ScrollbarType::Both) + { + wheight -= SCROLLBAR_WIDTH + 1; + } + if (listView.GetScrollbars() == ScrollbarType::Vertical || listView.GetScrollbars() == ScrollbarType::Both) + { + wwidth -= SCROLLBAR_WIDTH + 1; + } + listView.Resize({ wwidth, wheight }); + scrollIndex++; + } + } + } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + WindowDrawWidgets(this, &dpi); + DrawTabImages(dpi); + if (viewport != nullptr) + { + auto widgetIndex = GetViewportWidgetIndex(); + if (WidgetIsVisible(this, widgetIndex.value_or(false))) + { + window_draw_viewport(&dpi, this); + } + } + } + + void OnMouseUp(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_CLOSE: + window_close(this); + break; + default: + { + const auto& info = GetInfo(this); + if (widgetIndex >= WIDX_TAB_0 + && widgetIndex < static_cast(WIDX_TAB_0 + info.Desc.Tabs.size())) + { + ChangeTab(widgetIndex - WIDX_TAB_0); + break; + } + + const auto widgetDesc = info.GetCustomWidgetDesc(this, widgetIndex); + if (widgetDesc != nullptr) + { + if (widgetDesc->Type == "button") + { + InvokeEventHandler(info.Owner, widgetDesc->OnClick); + } + else if (widgetDesc->Type == "checkbox") + { + auto& widget = widgets[widgetIndex]; + widget.flags ^= WIDGET_FLAGS::IS_PRESSED; + bool isChecked = widget.flags & WIDGET_FLAGS::IS_PRESSED; + + WidgetSetCheckboxValue(this, 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; } + } + } - const auto widgetDesc = info.GetCustomWidgetDesc(w, widgetIndex); - if (widgetDesc != nullptr) + void OnMouseDown(rct_widgetindex widgetIndex) override + { + auto* widget = &widgets[widgetIndex]; + const auto& info = GetInfo(this); + const auto widgetDesc = info.GetCustomWidgetDesc(this, widgetIndex); + if (widgetDesc != nullptr) + { + if (widgetDesc->Type == "colourpicker") { - if (widgetDesc->Type == "button") + WindowDropdownShowColour(this, widget, colours[widget->colour], widgetDesc->Colour); + } + else if (widgetDesc->Type == "dropdown") + { + widget--; + auto selectedIndex = widgetDesc->SelectedIndex; + const auto& items = widgetDesc->Items; + const auto numItems = std::min(items.size(), Dropdown::ItemsMaxSize); + for (size_t i = 0; i < numItems; i++) { - InvokeEventHandler(info.Owner, widgetDesc->OnClick); + gDropdownItemsFormat[i] = selectedIndex == static_cast(i) ? STR_OPTIONS_DROPDOWN_ITEM_SELECTED + : STR_OPTIONS_DROPDOWN_ITEM; + auto sz = items[i].c_str(); + std::memcpy(&gDropdownItemsArgs[i], &sz, sizeof(const char*)); } - else if (widgetDesc->Type == "checkbox") + WindowDropdownShowTextCustomWidth( + { windowPos.x + widget->left, windowPos.y + widget->top }, widget->height() + 1, + colours[widget->colour], 0, Dropdown::Flag::StayOpen, numItems, widget->width() - 3); + } + else if (widgetDesc->Type == "spinner") + { + if (widget->text == STR_NUMERIC_DOWN) { - auto& widget = w->widgets[widgetIndex]; - widget.flags ^= WIDGET_FLAGS::IS_PRESSED; - bool isChecked = widget.flags & WIDGET_FLAGS::IS_PRESSED; - - WidgetSetCheckboxValue(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); + InvokeEventHandler(info.Owner, widgetDesc->OnDecrement); + } + else if (widget->text == STR_NUMERIC_UP) + { + InvokeEventHandler(info.Owner, widgetDesc->OnIncrement); } } - break; - } - } - } - - static void window_custom_resize(rct_window* w) - { - if (w->width < w->min_width) - { - w->Invalidate(); - w->width = w->min_width; - } - if (w->height < w->min_height) - { - w->Invalidate(); - w->height = w->min_height; - } - window_custom_update_viewport(w); - } - - static void window_custom_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) - { - const auto& info = GetInfo(w); - const auto widgetDesc = info.GetCustomWidgetDesc(w, widgetIndex); - if (widgetDesc != nullptr) - { - if (widgetDesc->Type == "colourpicker") - { - WindowDropdownShowColour(w, widget, w->colours[widget->colour], widgetDesc->Colour); - } - else if (widgetDesc->Type == "dropdown") - { - widget--; - auto selectedIndex = widgetDesc->SelectedIndex; - const auto& items = widgetDesc->Items; - const auto numItems = std::min(items.size(), Dropdown::ItemsMaxSize); - for (size_t i = 0; i < numItems; i++) + else if (widgetDesc->Type == "textbox") { - gDropdownItemsFormat[i] = selectedIndex == static_cast(i) ? STR_OPTIONS_DROPDOWN_ITEM_SELECTED - : STR_OPTIONS_DROPDOWN_ITEM; - auto sz = items[i].c_str(); - std::memcpy(&gDropdownItemsArgs[i], &sz, sizeof(const char*)); - } - WindowDropdownShowTextCustomWidth( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, - w->colours[widget->colour], 0, Dropdown::Flag::StayOpen, numItems, widget->width() - 3); - } - else if (widgetDesc->Type == "spinner") - { - if (widget->text == STR_NUMERIC_DOWN) - { - InvokeEventHandler(info.Owner, widgetDesc->OnDecrement); - } - else if (widget->text == STR_NUMERIC_UP) - { - InvokeEventHandler(info.Owner, widgetDesc->OnIncrement); + auto* text = const_cast(widgetDesc->Text.c_str()); + window_start_textbox(this, widgetIndex, STR_STRING, text, widgetDesc->MaxLength + 1); } } - else if (widgetDesc->Type == "textbox") - { - auto* text = const_cast(widgetDesc->Text.c_str()); - window_start_textbox(w, widgetIndex, STR_STRING, text, widgetDesc->MaxLength + 1); - } } - } - static void window_custom_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) - { - if (dropdownIndex == -1) - return; - - auto& info = GetInfo(w); - auto widgetDesc = info.GetCustomWidgetDesc(w, widgetIndex); - if (widgetDesc != nullptr) + void OnDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) override { - if (widgetDesc->Type == "colourpicker") - { - UpdateWidgetColour(w, widgetIndex, dropdownIndex); - } - else if (widgetDesc->Type == "dropdown") - { - UpdateWidgetSelectedIndex(w, widgetIndex - 1, dropdownIndex); - } - } - } + if (dropdownIndex == -1) + return; - 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") + auto& info = GetInfo(this); + auto widgetDesc = info.GetCustomWidgetDesc(this, widgetIndex); + if (widgetDesc != nullptr) { - UpdateWidgetText(w, widgetIndex, text); - - std::vector 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); - if (info.Desc.Tabs.size() > static_cast(w->page)) - { - const auto& tab = info.Desc.Tabs[w->page]; - if (tab.imageFrameCount != 0) - { - w->frame_no++; - if (w->frame_no >= tab.imageFrameCount * tab.imageFrameDuration) + if (widgetDesc->Type == "colourpicker") { - w->frame_no = 0; + UpdateWidgetColour(this, widgetIndex, dropdownIndex); } - widget_invalidate(w, WIDX_TAB_0 + w->page); - } - } - - InvokeEventHandler(info.Owner, info.Desc.OnUpdate); - - // Since the plugin may alter widget positions and sizes during an update event, - // we need to force an update for all list view scrollbars - rct_widgetindex widgetIndex = 0; - for (auto widget = w->widgets; widget->type != WindowWidgetType::Empty; widget++) - { - if (widget->type == WindowWidgetType::Scroll) - { - WidgetScrollUpdateThumbs(w, widgetIndex); - } - widgetIndex++; - } - } - - static void window_custom_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height) - { - auto& info = GetInfo(w); - if (scrollIndex < static_cast(info.ListViews.size())) - { - auto size = info.ListViews[scrollIndex].GetSize(); - *width = size.width; - *height = size.height; - } - } - - static void window_custom_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) - { - auto& info = GetInfo(w); - if (scrollIndex < static_cast(info.ListViews.size())) - { - info.ListViews[scrollIndex].MouseDown(screenCoords); - } - } - - static void window_custom_scrollmousedrag(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) - { - auto& info = GetInfo(w); - if (scrollIndex < static_cast(info.ListViews.size())) - { - info.ListViews[scrollIndex].MouseOver(screenCoords, true); - } - } - - static void window_custom_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) - { - auto& info = GetInfo(w); - if (scrollIndex < static_cast(info.ListViews.size())) - { - info.ListViews[scrollIndex].MouseOver(screenCoords, false); - } - } - - static void window_custom_set_pressed_tab(rct_window* w) - { - const auto& info = GetInfo(w); - auto numTabs = info.Desc.Tabs.size(); - if (numTabs != 0) - { - for (size_t i = 0; i < numTabs; i++) - { - w->pressed_widgets &= ~(1 << (WIDX_TAB_0 + i)); - } - w->pressed_widgets |= 1LL << (WIDX_TAB_0 + w->page); - } - } - - static void window_custom_invalidate(rct_window* w) - { - w->widgets[WIDX_BACKGROUND].right = w->width - 1; - w->widgets[WIDX_BACKGROUND].bottom = w->height - 1; - w->widgets[WIDX_TITLE].right = w->width - 2; - w->widgets[WIDX_CLOSE].left = w->width - 13; - w->widgets[WIDX_CLOSE].right = w->width - 3; - w->widgets[WIDX_CONTENT_PANEL].right = w->width - 1; - w->widgets[WIDX_CONTENT_PANEL].bottom = w->height - 1; - w->widgets[WIDX_CLOSE].text = (w->colours[0] & COLOUR_FLAG_TRANSLUCENT) ? STR_CLOSE_X_WHITE : STR_CLOSE_X; - - // Having the content panel visible for transparent windows makes the borders darker than they should be - // For now just hide it if there are no tabs and the window is not resizable - auto& info = GetInfo(w); - auto canResize = (w->flags & WF_RESIZABLE) != 0 && (w->min_width != w->max_width || w->min_height != w->max_height); - auto numTabs = info.Desc.Tabs.size(); - if (canResize || numTabs != 0) - { - w->widgets[WIDX_CONTENT_PANEL].flags &= ~WIDGET_FLAGS::IS_HIDDEN; - } - else - { - w->widgets[WIDX_CONTENT_PANEL].flags |= WIDGET_FLAGS::IS_HIDDEN; - } - - window_custom_set_pressed_tab(w); - - const auto& desc = info.Desc; - auto ft = Formatter::Common(); - ft.Add(desc.Title.c_str()); - - size_t scrollIndex = 0; - for (auto widget = w->widgets; widget->type != WindowWidgetType::Last; widget++) - { - if (widget->type == WindowWidgetType::Scroll) - { - auto& listView = info.ListViews[scrollIndex]; - auto width = widget->width() + 1 - 2; - auto height = widget->height() + 1 - 2; - if (listView.GetScrollbars() == ScrollbarType::Horizontal || listView.GetScrollbars() == ScrollbarType::Both) + else if (widgetDesc->Type == "dropdown") { - height -= SCROLLBAR_WIDTH + 1; + UpdateWidgetSelectedIndex(this, widgetIndex - 1, dropdownIndex); } - if (listView.GetScrollbars() == ScrollbarType::Vertical || listView.GetScrollbars() == ScrollbarType::Both) + } + } + + void OnTextInput(rct_widgetindex widgetIndex, std::string_view text) + { + auto& info = GetInfo(this); + auto widgetDesc = info.GetCustomWidgetDesc(this, widgetIndex); + if (widgetDesc != nullptr) + { + if (widgetDesc->Type == "textbox") { - width -= SCROLLBAR_WIDTH + 1; + UpdateWidgetText(this, widgetIndex, text); + + std::vector args; + auto ctx = widgetDesc->OnChange.context(); + duk_push_lstring(ctx, text.data(), text.size()); + args.push_back(DukValue::take_from_stack(ctx)); + InvokeEventHandler(info.Owner, widgetDesc->OnChange, args); } - listView.Resize({ width, height }); - scrollIndex++; } } - } - static void window_custom_draw_tab_images(rct_window* w, rct_drawpixelinfo* dpi) - { - const auto& customInfo = GetInfo(w); - const auto& tabs = customInfo.Desc.Tabs; - size_t tabIndex = 0; - for (const auto& tab : tabs) + ScreenSize OnScrollGetSize(int32_t scrollIndex) override { - auto widgetIndex = static_cast(WIDX_TAB_0 + tabIndex); - auto widget = &w->widgets[widgetIndex]; - if (WidgetIsEnabled(w, widgetIndex)) + auto& info = GetInfo(this); + if (scrollIndex < static_cast(info.ListViews.size())) { - auto leftTop = w->windowPos + tab.offset + ScreenCoordsXY{ widget->left, widget->top }; - auto image = tab.imageFrameBase; - if (static_cast(w->page) == tabIndex && tab.imageFrameDuration != 0 && tab.imageFrameCount != 0) + auto size = info.ListViews[scrollIndex].GetSize(); + return { size.width, size.height }; + } + return {}; + } + + void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + auto& info = GetInfo(this); + if (scrollIndex < static_cast(info.ListViews.size())) + { + info.ListViews[scrollIndex].MouseDown(screenCoords); + } + } + + void OnScrollMouseDrag(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + auto& info = GetInfo(this); + if (scrollIndex < static_cast(info.ListViews.size())) + { + info.ListViews[scrollIndex].MouseOver(screenCoords, true); + } + } + + void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + auto& info = GetInfo(this); + if (scrollIndex < static_cast(info.ListViews.size())) + { + info.ListViews[scrollIndex].MouseOver(screenCoords, false); + } + } + + void OnScrollDraw(int32_t scrollIndex, rct_drawpixelinfo& dpi) override + { + const auto& info = GetInfo(this); + if (scrollIndex < static_cast(info.ListViews.size())) + { + info.ListViews[scrollIndex].Paint(this, &dpi, &scrolls[scrollIndex]); + } + } + + private: + std::optional GetViewportWidgetIndex() + { + rct_widgetindex widgetIndex = 0; + for (auto widget = widgets; widget->type != WindowWidgetType::Last; widget++) + { + if (widget->type == WindowWidgetType::Viewport) { - auto frame = w->frame_no / tab.imageFrameDuration; - auto imageOffset = frame % tab.imageFrameCount; - image = image.WithIndex(image.GetIndex() + imageOffset); + return widgetIndex; } - gfx_draw_sprite(dpi, image.ToUInt32(), leftTop, image.GetTertiary()); + widgetIndex++; } - tabIndex++; + return std::nullopt; } - } - static std::optional GetViewportWidgetIndex(rct_window* w) - { - rct_widgetindex widgetIndex = 0; - for (auto widget = w->widgets; widget->type != WindowWidgetType::Last; widget++) + void UpdateViewport() { - if (widget->type == WindowWidgetType::Viewport) + auto viewportWidgetIndex = GetViewportWidgetIndex(); + if (viewportWidgetIndex) { - return widgetIndex; - } - widgetIndex++; - } - return std::nullopt; - } - - static void window_custom_paint(rct_window* w, rct_drawpixelinfo* dpi) - { - WindowDrawWidgets(w, dpi); - window_custom_draw_tab_images(w, dpi); - if (w->viewport != nullptr) - { - auto widgetIndex = GetViewportWidgetIndex(w); - if (WidgetIsVisible(w, widgetIndex.value_or(false))) - { - window_draw_viewport(dpi, w); - } - } - } - - static void window_custom_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex) - { - const auto& info = GetInfo(w); - if (scrollIndex < static_cast(info.ListViews.size())) - { - info.ListViews[scrollIndex].Paint(w, dpi, &w->scrolls[scrollIndex]); - } - } - - static void window_custom_update_viewport(rct_window* w) - { - auto viewportWidgetIndex = GetViewportWidgetIndex(w); - if (viewportWidgetIndex) - { - auto viewportWidget = &w->widgets[*viewportWidgetIndex]; - auto& customInfo = GetInfo(w); - auto widgetInfo = customInfo.GetCustomWidgetDesc(w, *viewportWidgetIndex); - if (widgetInfo != nullptr) - { - auto left = w->windowPos.x + viewportWidget->left + 1; - auto top = w->windowPos.y + viewportWidget->top + 1; - auto width = viewportWidget->width() - 1; - auto height = viewportWidget->height() - 1; - auto viewport = w->viewport; - if (viewport == nullptr) + auto viewportWidget = &widgets[*viewportWidgetIndex]; + auto& customInfo = GetInfo(this); + auto widgetInfo = customInfo.GetCustomWidgetDesc(this, *viewportWidgetIndex); + if (widgetInfo != nullptr) { - auto mapX = 0; - auto mapY = 0; - auto mapZ = 0; - viewport_create( - w, { left, top }, width, height, 0, { mapX, mapY, mapZ }, VIEWPORT_FOCUS_TYPE_COORDINATE, - SPRITE_INDEX_NULL); - w->flags |= WF_NO_SCROLLING; - w->Invalidate(); + auto left = windowPos.x + viewportWidget->left + 1; + auto top = windowPos.y + viewportWidget->top + 1; + auto wwidth = viewportWidget->width() - 1; + auto wheight = viewportWidget->height() - 1; + if (viewport == nullptr) + { + auto mapX = 0; + auto mapY = 0; + auto mapZ = 0; + viewport_create( + this, { left, top }, wwidth, wheight, 0, { mapX, mapY, mapZ }, VIEWPORT_FOCUS_TYPE_COORDINATE, + SPRITE_INDEX_NULL); + flags |= WF_NO_SCROLLING; + Invalidate(); + } + else + { + if (viewport->pos.x != left || viewport->pos.y != top || viewport->width != wwidth + || viewport->height != wheight) + { + viewport->pos.x = left; + viewport->pos.y = top; + viewport->width = wwidth; + viewport->height = wheight; + viewport->view_width = wwidth * viewport->zoom; + viewport->view_height = wheight * viewport->zoom; + Invalidate(); + } + } + } + } + } + + void ChangeTab(size_t tabIndex) + { + const auto& info = GetInfo(this); + + page = static_cast(tabIndex); + frame_no = 0; + RefreshWidgets(); + + Invalidate(); + window_event_resize_call(this); + window_event_invalidate_call(this); + WindowInitScrollWidgets(this); + Invalidate(); + + InvokeEventHandler(info.Owner, info.Desc.OnTabChange); + } + + void SetPressedTab() + { + const auto& info = GetInfo(this); + auto numTabs = info.Desc.Tabs.size(); + if (numTabs != 0) + { + for (size_t i = 0; i < numTabs; i++) + { + pressed_widgets &= ~(1ULL << (WIDX_TAB_0 + i)); + } + pressed_widgets |= 1ULL << (WIDX_TAB_0 + page); + } + } + + void DrawTabImages(rct_drawpixelinfo& dpi) + { + const auto& customInfo = GetInfo(this); + const auto& tabs = customInfo.Desc.Tabs; + size_t tabIndex = 0; + for (const auto& tab : tabs) + { + auto widgetIndex = static_cast(WIDX_TAB_0 + tabIndex); + auto widget = &widgets[widgetIndex]; + if (WidgetIsEnabled(this, widgetIndex)) + { + auto leftTop = windowPos + tab.offset + ScreenCoordsXY{ widget->left, widget->top }; + auto image = tab.imageFrameBase; + if (static_cast(page) == tabIndex && tab.imageFrameDuration != 0 && tab.imageFrameCount != 0) + { + auto frame = frame_no / tab.imageFrameDuration; + auto imageOffset = frame % tab.imageFrameCount; + image = image.WithIndex(image.GetIndex() + imageOffset); + } + gfx_draw_sprite(&dpi, image.ToUInt32(), leftTop, image.GetTertiary()); + } + tabIndex++; + } + } + + void RefreshWidgets() + { + enabled_widgets = 0; + pressed_widgets = 0; + disabled_widgets = 0; + + auto& info = GetInfo(this); + auto& widgetList = info.Widgets; + + widgetList.clear(); + info.WidgetIndexMap.clear(); + info.ListViews.clear(); + + // Add default widgets (window shim) + widgetList.insert(widgetList.begin(), std::begin(CustomDefaultWidgets), std::end(CustomDefaultWidgets)); + for (size_t i = 0; i < widgetList.size(); i++) + { + info.WidgetIndexMap.push_back(std::numeric_limits::max()); + } + enabled_widgets = 1ULL << WIDX_CLOSE; + + // Add window tabs + if (info.Desc.Tabs.size() != 0) + { + widgetList[WIDX_CONTENT_PANEL].top = 43; + } + for (size_t tabDescIndex = 0; tabDescIndex < info.Desc.Tabs.size(); tabDescIndex++) + { + rct_widget widget{}; + widget.type = WindowWidgetType::Tab; + widget.colour = 1; + widget.left = static_cast(3 + (tabDescIndex * 31)); + widget.right = widget.left + 30; + widget.top = 17; + widget.bottom = 43; + widget.image = IMAGE_TYPE_REMAP | SPR_TAB; + widget.tooltip = STR_NONE; + widgetList.push_back(widget); + info.WidgetIndexMap.push_back(std::numeric_limits::max()); + enabled_widgets |= 1ULL << (widgetList.size() - 1); + } + + // Add custom widgets + auto firstCustomWidgetIndex = widgetList.size(); + auto totalWidgets = info.Desc.Widgets.size(); + auto tabWidgetsOffset = totalWidgets; + if (info.Desc.Tabs.size() != 0) + { + totalWidgets += info.Desc.Tabs[page].Widgets.size(); + } + for (size_t widgetDescIndex = 0; widgetDescIndex < totalWidgets; widgetDescIndex++) + { + const auto& widgetDesc = widgetDescIndex < info.Desc.Widgets.size() + ? info.Desc.Widgets[widgetDescIndex] + : info.Desc.Tabs[page].Widgets[widgetDescIndex - tabWidgetsOffset]; + auto preWidgetSize = widgetList.size(); + CreateWidget(widgetList, widgetDesc); + auto numWidetsAdded = widgetList.size() - preWidgetSize; + for (size_t i = 0; i < numWidetsAdded; i++) + { + info.WidgetIndexMap.push_back(widgetDescIndex); + } + + if (widgetDesc.Type == "listview") + { + CustomListView listView(this, info.ListViews.size()); + listView.SetScrollbars(widgetDesc.Scrollbars, true); + listView.SetColumns(widgetDesc.ListViewColumns, true); + listView.SetItems(widgetDesc.ListViewItems, true); + listView.SelectedCell = widgetDesc.SelectedCell; + listView.ShowColumnHeaders = widgetDesc.ShowColumnHeaders; + listView.IsStriped = widgetDesc.IsStriped; + listView.OnClick = widgetDesc.OnClick; + listView.OnHighlight = widgetDesc.OnHighlight; + listView.CanSelect = widgetDesc.CanSelect; + info.ListViews.push_back(std::move(listView)); + } + } + + for (size_t i = firstCustomWidgetIndex; i < widgetList.size(); i++) + { + auto mask = 1ULL << i; + auto widgetFlags = widgetList[i].flags; + if (widgetFlags & WIDGET_FLAGS::IS_ENABLED) + { + enabled_widgets |= mask; + } + if (widgetFlags & WIDGET_FLAGS::IS_PRESSED) + { + pressed_widgets |= mask; + } + if (widgetFlags & WIDGET_FLAGS::IS_DISABLED) + { + disabled_widgets |= mask; + } + } + + widgetList.push_back({ WIDGETS_END }); + widgets = widgetList.data(); + + WindowInitScrollWidgets(this); + UpdateViewport(); + } + + static void CreateWidget(std::vector& widgetList, const CustomWidgetDesc& desc) + { + rct_widget widget{}; + widget.colour = 1; + widget.left = desc.X; + widget.top = desc.Y; + widget.right = desc.X + desc.Width - 1; + widget.bottom = desc.Y + desc.Height - 1; + widget.content = std::numeric_limits::max(); + widget.tooltip = STR_NONE; + if (!desc.Tooltip.empty()) + { + widget.sztooltip = const_cast(desc.Tooltip.c_str()); + widget.flags |= WIDGET_FLAGS::TOOLTIP_IS_STRING; + } + widget.flags |= WIDGET_FLAGS::IS_ENABLED; + if (desc.IsDisabled) + widget.flags |= WIDGET_FLAGS::IS_DISABLED; + if (!desc.IsVisible) + widget.flags |= WIDGET_FLAGS::IS_HIDDEN; + + if (desc.Type == "button") + { + if (desc.Image.HasValue()) + { + widget.type = desc.HasBorder ? WindowWidgetType::ImgBtn : WindowWidgetType::FlatBtn; + widget.image = desc.Image.ToUInt32(); } else { - if (viewport->pos.x != left || viewport->pos.y != top || viewport->width != width - || viewport->height != height) - { - viewport->pos.x = left; - viewport->pos.y = top; - viewport->width = width; - viewport->height = height; - viewport->view_width = width * viewport->zoom; - viewport->view_height = height * viewport->zoom; - w->Invalidate(); - } + widget.type = WindowWidgetType::Button; + widget.string = const_cast(desc.Text.c_str()); + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; } + if (desc.IsPressed) + { + widget.flags |= WIDGET_FLAGS::IS_PRESSED; + } + widgetList.push_back(widget); + } + else if (desc.Type == "checkbox") + { + widget.type = WindowWidgetType::Checkbox; + widget.string = const_cast(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 == "colourpicker") + { + widget.type = WindowWidgetType::ColourBtn; + widget.image = GetColourButtonImage(desc.Colour); + widgetList.push_back(widget); + } + else if (desc.Type == "dropdown") + { + widget.type = WindowWidgetType::DropdownMenu; + if (desc.SelectedIndex >= 0 && static_cast(desc.SelectedIndex) < desc.Items.size()) + { + widget.string = const_cast(desc.Items[desc.SelectedIndex].c_str()); + } + else + { + widget.string = const_cast(""); + } + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + widgetList.push_back(widget); + + // Add the dropdown button + widget = {}; + widget.type = WindowWidgetType::Button; + widget.colour = 1; + widget.left = desc.X + desc.Width - 12; + widget.right = desc.X + desc.Width - 2; + widget.top = desc.Y + 1; + widget.bottom = desc.Y + desc.Height - 2; + widget.text = STR_DROPDOWN_GLYPH; + widget.tooltip = STR_NONE; + widget.flags |= WIDGET_FLAGS::IS_ENABLED; + if (desc.IsDisabled) + widget.flags |= WIDGET_FLAGS::IS_DISABLED; + widgetList.push_back(widget); + } + else if (desc.Type == "groupbox") + { + widget.type = WindowWidgetType::Groupbox; + widget.string = const_cast(desc.Text.c_str()); + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + widgetList.push_back(widget); + } + else if (desc.Type == "label") + { + widget.type = WindowWidgetType::Label; + widget.string = const_cast(desc.Text.c_str()); + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + if (desc.TextAlign == TextAlignment::CENTRE) + { + widget.type = WindowWidgetType::LabelCentred; + } + widgetList.push_back(widget); + } + else if (desc.Type == "listview") + { + widget.type = WindowWidgetType::Scroll; + widget.content = 0; + if (desc.Scrollbars == ScrollbarType::Horizontal) + widget.content = SCROLL_HORIZONTAL; + else if (desc.Scrollbars == ScrollbarType::Vertical) + widget.content = SCROLL_VERTICAL; + else if (desc.Scrollbars == ScrollbarType::Both) + widget.content = SCROLL_BOTH; + widgetList.push_back(widget); + } + else if (desc.Type == "spinner") + { + widget.type = WindowWidgetType::Spinner; + widget.string = const_cast(desc.Text.c_str()); + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + widgetList.push_back(widget); + + // Add the decrement button + widget = {}; + widget.type = WindowWidgetType::Button; + widget.colour = 1; + widget.left = desc.X + desc.Width - 26; + widget.right = widget.left + 12; + widget.top = desc.Y + 1; + widget.bottom = desc.Y + desc.Height - 2; + widget.text = STR_NUMERIC_DOWN; + widget.tooltip = STR_NONE; + widget.flags |= WIDGET_FLAGS::IS_ENABLED; + if (desc.IsDisabled) + widget.flags |= WIDGET_FLAGS::IS_DISABLED; + widgetList.push_back(widget); + + // Add the increment button + widget.left = desc.X + desc.Width - 13; + widget.right = widget.left + 11; + widget.text = STR_NUMERIC_UP; + widgetList.push_back(widget); + } + else if (desc.Type == "textbox") + { + widget.type = WindowWidgetType::TextBox; + widget.string = const_cast(desc.Text.c_str()); + widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; + widgetList.push_back(widget); + } + else if (desc.Type == "viewport") + { + widget.type = WindowWidgetType::Viewport; + widget.text = STR_NONE; + widgetList.push_back(widget); } } + + static rct_windownumber GetNewWindowNumber() + { + auto result = _nextWindowNumber++; + while (window_find_by_number(WC_CUSTOM, result) != nullptr) + { + result++; + } + return result; + } + }; + + rct_window* window_custom_open(std::shared_ptr owner, DukValue dukDesc) + { + auto desc = CustomWindowDesc::FromDukValue(dukDesc); + uint16_t windowFlags = WF_RESIZABLE | WF_TRANSPARENT; + CustomWindow* window{}; + if (desc.X && desc.Y) + { + window = WindowCreate(WC_CUSTOM, { *desc.X, *desc.Y }, desc.Width, desc.Height, windowFlags); + } + else + { + window = WindowCreate(WC_CUSTOM, desc.Width, desc.Height, windowFlags); + } + if (window != nullptr) + { + window->Initialise(owner, desc); + } + return window; } static CustomWindowInfo& GetInfo(rct_window* w) @@ -877,279 +1126,6 @@ namespace OpenRCT2::Ui::Windows return *(static_cast(w->custom_info)); } - static rct_windownumber GetNewWindowNumber() - { - auto result = _nextWindowNumber++; - while (window_find_by_number(WC_CUSTOM, result) != nullptr) - { - result++; - } - return result; - } - - static void CreateWidget(std::vector& widgetList, const CustomWidgetDesc& desc) - { - rct_widget widget{}; - widget.colour = 1; - widget.left = desc.X; - widget.top = desc.Y; - widget.right = desc.X + desc.Width - 1; - widget.bottom = desc.Y + desc.Height - 1; - widget.content = std::numeric_limits::max(); - widget.tooltip = STR_NONE; - if (!desc.Tooltip.empty()) - { - widget.sztooltip = const_cast(desc.Tooltip.c_str()); - widget.flags |= WIDGET_FLAGS::TOOLTIP_IS_STRING; - } - widget.flags |= WIDGET_FLAGS::IS_ENABLED; - if (desc.IsDisabled) - widget.flags |= WIDGET_FLAGS::IS_DISABLED; - if (!desc.IsVisible) - widget.flags |= WIDGET_FLAGS::IS_HIDDEN; - - if (desc.Type == "button") - { - if (desc.Image.HasValue()) - { - widget.type = desc.HasBorder ? WindowWidgetType::ImgBtn : WindowWidgetType::FlatBtn; - widget.image = desc.Image.ToUInt32(); - } - else - { - widget.type = WindowWidgetType::Button; - widget.string = const_cast(desc.Text.c_str()); - widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; - } - if (desc.IsPressed) - { - widget.flags |= WIDGET_FLAGS::IS_PRESSED; - } - widgetList.push_back(widget); - } - else if (desc.Type == "checkbox") - { - widget.type = WindowWidgetType::Checkbox; - widget.string = const_cast(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 == "colourpicker") - { - widget.type = WindowWidgetType::ColourBtn; - widget.image = GetColourButtonImage(desc.Colour); - widgetList.push_back(widget); - } - else if (desc.Type == "dropdown") - { - widget.type = WindowWidgetType::DropdownMenu; - if (desc.SelectedIndex >= 0 && static_cast(desc.SelectedIndex) < desc.Items.size()) - { - widget.string = const_cast(desc.Items[desc.SelectedIndex].c_str()); - } - else - { - widget.string = const_cast(""); - } - widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; - widgetList.push_back(widget); - - // Add the dropdown button - widget = {}; - widget.type = WindowWidgetType::Button; - widget.colour = 1; - widget.left = desc.X + desc.Width - 12; - widget.right = desc.X + desc.Width - 2; - widget.top = desc.Y + 1; - widget.bottom = desc.Y + desc.Height - 2; - widget.text = STR_DROPDOWN_GLYPH; - widget.tooltip = STR_NONE; - widget.flags |= WIDGET_FLAGS::IS_ENABLED; - if (desc.IsDisabled) - widget.flags |= WIDGET_FLAGS::IS_DISABLED; - widgetList.push_back(widget); - } - else if (desc.Type == "groupbox") - { - widget.type = WindowWidgetType::Groupbox; - widget.string = const_cast(desc.Text.c_str()); - widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; - widgetList.push_back(widget); - } - else if (desc.Type == "label") - { - widget.type = WindowWidgetType::Label; - widget.string = const_cast(desc.Text.c_str()); - widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; - if (desc.TextAlign == TextAlignment::CENTRE) - { - widget.type = WindowWidgetType::LabelCentred; - } - widgetList.push_back(widget); - } - else if (desc.Type == "listview") - { - widget.type = WindowWidgetType::Scroll; - widget.content = 0; - if (desc.Scrollbars == ScrollbarType::Horizontal) - widget.content = SCROLL_HORIZONTAL; - else if (desc.Scrollbars == ScrollbarType::Vertical) - widget.content = SCROLL_VERTICAL; - else if (desc.Scrollbars == ScrollbarType::Both) - widget.content = SCROLL_BOTH; - widgetList.push_back(widget); - } - else if (desc.Type == "spinner") - { - widget.type = WindowWidgetType::Spinner; - widget.string = const_cast(desc.Text.c_str()); - widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; - widgetList.push_back(widget); - - // Add the decrement button - widget = {}; - widget.type = WindowWidgetType::Button; - widget.colour = 1; - widget.left = desc.X + desc.Width - 26; - widget.right = widget.left + 12; - widget.top = desc.Y + 1; - widget.bottom = desc.Y + desc.Height - 2; - widget.text = STR_NUMERIC_DOWN; - widget.tooltip = STR_NONE; - widget.flags |= WIDGET_FLAGS::IS_ENABLED; - if (desc.IsDisabled) - widget.flags |= WIDGET_FLAGS::IS_DISABLED; - widgetList.push_back(widget); - - // Add the increment button - widget.left = desc.X + desc.Width - 13; - widget.right = widget.left + 11; - widget.text = STR_NUMERIC_UP; - widgetList.push_back(widget); - } - else if (desc.Type == "textbox") - { - widget.type = WindowWidgetType::TextBox; - widget.string = const_cast(desc.Text.c_str()); - widget.flags |= WIDGET_FLAGS::TEXT_IS_STRING; - widgetList.push_back(widget); - } - else if (desc.Type == "viewport") - { - widget.type = WindowWidgetType::Viewport; - widget.text = STR_NONE; - widgetList.push_back(widget); - } - } - - static void RefreshWidgets(rct_window* w) - { - w->enabled_widgets = 0; - w->pressed_widgets = 0; - w->disabled_widgets = 0; - - auto& info = GetInfo(w); - auto& widgets = info.Widgets; - - widgets.clear(); - info.WidgetIndexMap.clear(); - info.ListViews.clear(); - - // Add default widgets (window shim) - widgets.insert(widgets.begin(), std::begin(CustomDefaultWidgets), std::end(CustomDefaultWidgets)); - for (size_t i = 0; i < widgets.size(); i++) - { - info.WidgetIndexMap.push_back(std::numeric_limits::max()); - } - w->enabled_widgets = 1ULL << WIDX_CLOSE; - - // Add window tabs - if (info.Desc.Tabs.size() != 0) - { - widgets[WIDX_CONTENT_PANEL].top = 43; - } - for (size_t tabDescIndex = 0; tabDescIndex < info.Desc.Tabs.size(); tabDescIndex++) - { - rct_widget widget{}; - widget.type = WindowWidgetType::Tab; - widget.colour = 1; - widget.left = static_cast(3 + (tabDescIndex * 31)); - widget.right = widget.left + 30; - widget.top = 17; - widget.bottom = 43; - widget.image = IMAGE_TYPE_REMAP | SPR_TAB; - widget.tooltip = STR_NONE; - widgets.push_back(widget); - info.WidgetIndexMap.push_back(std::numeric_limits::max()); - w->enabled_widgets |= 1ULL << (widgets.size() - 1); - } - - // Add custom widgets - auto firstCustomWidgetIndex = widgets.size(); - auto totalWidgets = info.Desc.Widgets.size(); - auto tabWidgetsOffset = totalWidgets; - if (info.Desc.Tabs.size() != 0) - { - totalWidgets += info.Desc.Tabs[w->page].Widgets.size(); - } - for (size_t widgetDescIndex = 0; widgetDescIndex < totalWidgets; widgetDescIndex++) - { - const auto& widgetDesc = widgetDescIndex < info.Desc.Widgets.size() - ? info.Desc.Widgets[widgetDescIndex] - : info.Desc.Tabs[w->page].Widgets[widgetDescIndex - tabWidgetsOffset]; - auto preWidgetSize = widgets.size(); - CreateWidget(widgets, widgetDesc); - auto numWidetsAdded = widgets.size() - preWidgetSize; - for (size_t i = 0; i < numWidetsAdded; i++) - { - info.WidgetIndexMap.push_back(widgetDescIndex); - } - - if (widgetDesc.Type == "listview") - { - CustomListView listView(w, info.ListViews.size()); - listView.SetScrollbars(widgetDesc.Scrollbars, true); - listView.SetColumns(widgetDesc.ListViewColumns, true); - listView.SetItems(widgetDesc.ListViewItems, true); - listView.SelectedCell = widgetDesc.SelectedCell; - listView.ShowColumnHeaders = widgetDesc.ShowColumnHeaders; - listView.IsStriped = widgetDesc.IsStriped; - listView.OnClick = widgetDesc.OnClick; - listView.OnHighlight = widgetDesc.OnHighlight; - listView.CanSelect = widgetDesc.CanSelect; - info.ListViews.push_back(std::move(listView)); - } - } - - for (size_t i = firstCustomWidgetIndex; i < widgets.size(); i++) - { - auto mask = 1ULL << i; - auto flags = widgets[i].flags; - if (flags & WIDGET_FLAGS::IS_ENABLED) - { - w->enabled_widgets |= mask; - } - if (flags & WIDGET_FLAGS::IS_PRESSED) - { - w->pressed_widgets |= mask; - } - if (flags & WIDGET_FLAGS::IS_DISABLED) - { - w->disabled_widgets |= mask; - } - } - - widgets.push_back({ WIDGETS_END }); - w->widgets = widgets.data(); - - WindowInitScrollWidgets(w); - window_custom_update_viewport(w); - } - static void InvokeEventHandler(const std::shared_ptr& owner, const DukValue& dukHandler) { std::vector args; diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index dc44f90544..207564a551 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -1530,9 +1530,10 @@ void window_event_scroll_mousedown_call(rct_window* w, int32_t scrollIndex, cons void window_event_scroll_mousedrag_call(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) { - if (w->event_handlers != nullptr) - if (w->event_handlers->scroll_mousedrag != nullptr) - w->event_handlers->scroll_mousedrag(w, scrollIndex, screenCoords); + if (w->event_handlers == nullptr) + w->OnScrollMouseDrag(scrollIndex, screenCoords); + else if (w->event_handlers->scroll_mouseover != nullptr) + w->event_handlers->scroll_mousedrag(w, scrollIndex, screenCoords); } void window_event_scroll_mouseover_call(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h index ab577334d0..7189c99c8d 100644 --- a/src/openrct2/interface/Window_internal.h +++ b/src/openrct2/interface/Window_internal.h @@ -154,6 +154,9 @@ struct rct_window { return {}; } + virtual void OnScrollMouseDrag(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) + { + } virtual void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) { }