diff --git a/src/openrct2-ui/WindowManager.cpp b/src/openrct2-ui/WindowManager.cpp index 179b843c5a..703511e4a4 100644 --- a/src/openrct2-ui/WindowManager.cpp +++ b/src/openrct2-ui/WindowManager.cpp @@ -31,7 +31,6 @@ public: void Init() override { ThemeManagerInitialise(); - window_guest_list_init_vars(); window_new_ride_init_vars(); } diff --git a/src/openrct2-ui/interface/Window.cpp b/src/openrct2-ui/interface/Window.cpp index 3ed26793a7..f954cda263 100644 --- a/src/openrct2-ui/interface/Window.cpp +++ b/src/openrct2-ui/interface/Window.cpp @@ -86,10 +86,126 @@ static bool WindowFitsOnScreen(const ScreenCoordsXY& loc, int32_t width, int32_t return WindowFitsBetweenOthers(loc, width, height); } -rct_window* WindowCreate( - std::unique_ptr&& wp, rct_windowclass cls, const ScreenCoordsXY& pos, int32_t width, int32_t height, - uint16_t flags) +static ScreenCoordsXY ClampWindowToScreen(const ScreenCoordsXY& pos, const int32_t screenWidth, const int32_t width) { + auto screenPos = pos; + if (screenPos.x < 0) + screenPos.x = 0; + if (screenPos.x + width > screenWidth) + screenPos.x = screenWidth - width; + + return screenPos; +} + +static ScreenCoordsXY GetAutoPositionForNewWindow(int32_t width, int32_t height) +{ + auto uiContext = GetContext()->GetUiContext(); + auto screenWidth = uiContext->GetWidth(); + auto screenHeight = uiContext->GetHeight(); + + // Place window in an empty corner of the screen + const ScreenCoordsXY cornerPositions[] = { + { 0, 30 }, // topLeft + { screenWidth - width, 30 }, // topRight + { 0, screenHeight - 34 - height }, // bottomLeft + { screenWidth - width, screenHeight - 34 - height } // bottomRight + }; + + for (const auto& cornerPos : cornerPositions) + { + if (WindowFitsWithinSpace(cornerPos, width, height)) + { + return ClampWindowToScreen(cornerPos, screenWidth, width); + } + } + + // Place window next to another + for (auto& w : g_window_list) + { + if (w->flags & WF_STICK_TO_BACK) + continue; + + const ScreenCoordsXY offsets[] = { { w->width + 2, 0 }, + { -w->width - 2, 0 }, + { 0, w->height + 2 }, + { 0, -w->height - 2 }, + { w->width + 2, -w->height - 2 }, + { -w->width - 2, -w->height - 2 }, + { w->width + 2, w->height + 2 }, + { -w->width - 2, w->height + 2 } }; + + for (const auto& offset : offsets) + { + auto screenPos = w->windowPos + offset; + if (WindowFitsWithinSpace(screenPos, width, height)) + { + return ClampWindowToScreen(screenPos, screenWidth, width); + } + } + } + + // Overlap + for (auto& w : g_window_list) + { + if (w->flags & WF_STICK_TO_BACK) + continue; + + // clang-format off + const ScreenCoordsXY offsets[] = { + { w->width + 2, 0 }, + { -w->width - 2, 0 }, + { 0, w->height + 2 }, + { 0, -w->height - 2 } + }; + // clang-format on + + for (const auto& offset : offsets) + { + auto screenPos = w->windowPos + offset; + if (WindowFitsOnScreen(screenPos, width, height)) + { + return ClampWindowToScreen(screenPos, screenWidth, width); + } + } + } + + // Cascade + auto screenPos = ScreenCoordsXY{ 0, 30 }; + for (auto& w : g_window_list) + { + if (screenPos == w->windowPos) + { + screenPos.x += 5; + screenPos.y += 5; + } + } + + return ClampWindowToScreen(screenPos, screenWidth, width); +} + +static ScreenCoordsXY GetCentrePositionForNewWindow(int32_t width, int32_t height) +{ + auto uiContext = GetContext()->GetUiContext(); + auto screenWidth = uiContext->GetWidth(); + auto screenHeight = uiContext->GetHeight(); + return ScreenCoordsXY{ (screenWidth - width) / 2, std::max(TOP_TOOLBAR_HEIGHT + 1, (screenHeight - height) / 2) }; +} + +rct_window* WindowCreate( + std::unique_ptr&& wp, rct_windowclass cls, ScreenCoordsXY pos, int32_t width, int32_t height, uint32_t flags) +{ + if (flags & WF_AUTO_POSITION) + { + if (flags & WF_CENTRE_SCREEN) + { + pos = GetCentrePositionForNewWindow(width, height); + } + else + { + pos = GetAutoPositionForNewWindow(width, height); + } + } + // Check if there are any window slots left // include WINDOW_LIMIT_RESERVED for items such as the main viewport and toolbars to not appear to be counted. if (g_window_list.size() >= static_cast(gConfigGeneral.window_limit + WINDOW_LIMIT_RESERVED)) @@ -168,116 +284,25 @@ rct_window* WindowCreate( rct_window* WindowCreate( const ScreenCoordsXY& pos, int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, - uint16_t flags) + uint32_t flags) { auto w = std::make_unique(); w->event_handlers = event_handlers; return WindowCreate(std::move(w), cls, pos, width, height, flags); } -static ScreenCoordsXY ClampWindowToScreen(const ScreenCoordsXY& pos, const int32_t screenWidth, const int32_t width) -{ - auto screenPos = pos; - if (screenPos.x < 0) - screenPos.x = 0; - if (screenPos.x + width > screenWidth) - screenPos.x = screenWidth - width; - - return screenPos; -} - rct_window* WindowCreateAutoPos( - int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint16_t flags) + int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint32_t flags) { - auto uiContext = GetContext()->GetUiContext(); - auto screenWidth = uiContext->GetWidth(); - auto screenHeight = uiContext->GetHeight(); - - // Place window in an empty corner of the screen - const ScreenCoordsXY cornerPositions[] = { - { 0, 30 }, // topLeft - { screenWidth - width, 30 }, // topRight - { 0, screenHeight - 34 - height }, // bottomLeft - { screenWidth - width, screenHeight - 34 - height } // bottomRight - }; - - for (const auto& cornerPos : cornerPositions) - { - if (WindowFitsWithinSpace(cornerPos, width, height)) - return WindowCreate(ClampWindowToScreen(cornerPos, screenWidth, width), width, height, event_handlers, cls, flags); - } - - // Place window next to another - for (auto& w : g_window_list) - { - if (w->flags & WF_STICK_TO_BACK) - continue; - - const ScreenCoordsXY offsets[] = { { w->width + 2, 0 }, - { -w->width - 2, 0 }, - { 0, w->height + 2 }, - { 0, -w->height - 2 }, - { w->width + 2, -w->height - 2 }, - { -w->width - 2, -w->height - 2 }, - { w->width + 2, w->height + 2 }, - { -w->width - 2, w->height + 2 } }; - - for (const auto& offset : offsets) - { - auto screenPos = w->windowPos + offset; - if (WindowFitsWithinSpace(screenPos, width, height)) - return WindowCreate( - ClampWindowToScreen(screenPos, screenWidth, width), width, height, event_handlers, cls, flags); - } - } - - // Overlap - for (auto& w : g_window_list) - { - if (w->flags & WF_STICK_TO_BACK) - continue; - - // clang-format off - const ScreenCoordsXY offsets[] = { - { w->width + 2, 0 }, - { -w->width - 2, 0 }, - { 0, w->height + 2 }, - { 0, -w->height - 2 } - }; - // clang-format on - - for (const auto& offset : offsets) - { - auto screenPos = w->windowPos + offset; - if (WindowFitsOnScreen(screenPos, width, height)) - return WindowCreate( - ClampWindowToScreen(screenPos, screenWidth, width), width, height, event_handlers, cls, flags); - } - } - - // Cascade - auto screenPos = ScreenCoordsXY{ 0, 30 }; - for (auto& w : g_window_list) - { - if (screenPos == w->windowPos) - { - screenPos.x += 5; - screenPos.y += 5; - } - } - - return WindowCreate(ClampWindowToScreen(screenPos, screenWidth, width), width, height, event_handlers, cls, flags); + auto pos = GetAutoPositionForNewWindow(width, height); + return WindowCreate(pos, width, height, event_handlers, cls, flags); } rct_window* WindowCreateCentred( - int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint16_t flags) + int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint32_t flags) { - auto uiContext = GetContext()->GetUiContext(); - auto screenWidth = uiContext->GetWidth(); - auto screenHeight = uiContext->GetHeight(); - - auto screenPos = ScreenCoordsXY{ (screenWidth - width) / 2, std::max(TOP_TOOLBAR_HEIGHT + 1, (screenHeight - height) / 2) }; - return WindowCreate(screenPos, width, height, event_handlers, cls, flags); + auto pos = GetCentrePositionForNewWindow(width, height); + return WindowCreate(pos, width, height, event_handlers, cls, flags); } static int32_t WindowGetWidgetIndex(rct_window* w, rct_widget* widget) diff --git a/src/openrct2-ui/windows/GuestList.cpp b/src/openrct2-ui/windows/GuestList.cpp index abdc2a21de..7caf70b3a9 100644 --- a/src/openrct2-ui/windows/GuestList.cpp +++ b/src/openrct2-ui/windows/GuestList.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -27,13 +28,8 @@ static constexpr const rct_string_id WINDOW_TITLE = STR_GUESTS; static constexpr const int32_t WH = 330; static constexpr const int32_t WW = 350; -// clang-format off -enum { - PAGE_INDIVIDUAL, - PAGE_SUMMARISED -}; - -enum WINDOW_GUEST_LIST_WIDGET_IDX { +enum WINDOW_GUEST_LIST_WIDGET_IDX +{ WIDX_BACKGROUND, WIDX_TITLE, WIDX_CLOSE, @@ -50,23 +46,7 @@ enum WINDOW_GUEST_LIST_WIDGET_IDX { WIDX_GUEST_LIST }; -enum { - VIEW_ACTIONS, - VIEW_THOUGHTS, - VIEW_COUNT -}; - -static constexpr const rct_string_id filterNames[] = { - STR_GUESTS_FILTER, - STR_GUESTS_FILTER_THINKING, - STR_GUESTS_FILTER_THINKING_ABOUT, -}; - -static constexpr const rct_string_id viewNames[VIEW_COUNT] = { - STR_ACTIONS, - STR_THOUGHTS, -}; - +// clang-format off static rct_widget window_guest_list_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WW, WH), MakeWidget({ 0, 43}, {350, 287}, WindowWidgetType::Resize, WindowColour::Secondary ), // tab content panel @@ -82,868 +62,761 @@ static rct_widget window_guest_list_widgets[] = { MakeWidget({ 3, 72}, {344, 255}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_BOTH ), // guest list { WIDGETS_END }, }; - -static constexpr const uint8_t SUMMARISED_GUEST_ROW_HEIGHT = SCROLLABLE_ROW_HEIGHT + 11; -static constexpr const auto GUESTS_PER_PAGE = 2000; -static constexpr const auto GUEST_PAGE_HEIGHT = GUESTS_PER_PAGE * SCROLLABLE_ROW_HEIGHT; - -static std::vector GuestList; - -static void window_guest_list_mouseup(rct_window *w, rct_widgetindex widgetIndex); -static void window_guest_list_resize(rct_window *w); -static void window_guest_list_mousedown(rct_window *w, rct_widgetindex widgetIndex, rct_widget* widget); -static void window_guest_list_dropdown(rct_window *w, rct_widgetindex widgetIndex, int32_t dropdownIndex); -static void window_guest_list_update(rct_window *w); -static void window_guest_list_scrollgetsize(rct_window *w, int32_t scrollIndex, int32_t *width, int32_t *height); -static void window_guest_list_scrollmousedown(rct_window *w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords); -static void window_guest_list_scrollmouseover(rct_window *w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords); -static void window_guest_list_invalidate(rct_window *w); -static void window_guest_list_paint(rct_window *w, rct_drawpixelinfo *dpi); -static void window_guest_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, int32_t scrollIndex); -static void window_guest_list_textinput(rct_window *w, rct_widgetindex widgetIndex, char *text); - -static rct_window_event_list window_guest_list_events([](auto& events) -{ - events.mouse_up = &window_guest_list_mouseup; - events.resize = &window_guest_list_resize; - events.mouse_down = &window_guest_list_mousedown; - events.dropdown = &window_guest_list_dropdown; - events.update = &window_guest_list_update; - events.get_scroll_size = &window_guest_list_scrollgetsize; - events.scroll_mousedown = &window_guest_list_scrollmousedown; - events.scroll_mouseover = &window_guest_list_scrollmouseover; - events.text_input = &window_guest_list_textinput; - events.invalidate = &window_guest_list_invalidate; - events.paint = &window_guest_list_paint; - events.scroll_paint = &window_guest_list_scrollpaint; -}); // clang-format on -struct FilterArguments +class GuestListWindow final : public Window { - uint8_t args[12]{}; - - rct_string_id GetFirstStringId() +private: + enum class TabId { - rct_string_id firstStrId{}; - std::memcpy(&firstStrId, args, sizeof(firstStrId)); - return firstStrId; - } -}; -static bool operator==(const FilterArguments& l, const FilterArguments& r) -{ - return std::memcmp(l.args, r.args, sizeof(l.args)) == 0; -} -static bool operator!=(const FilterArguments& l, const FilterArguments& r) -{ - return !(l == r); -} + Individual, + Summarised + }; -static uint32_t _window_guest_list_last_find_groups_tick; -static uint32_t _window_guest_list_last_find_groups_selected_view; -static uint32_t _window_guest_list_last_find_groups_wait; - -static uint32_t _window_guest_list_highlighted_index; // 0x00F1EE10 -static int32_t _window_guest_list_selected_tab; // 0x00F1EE12 -static int32_t _window_guest_list_selected_filter; // 0x00F1EE06 -static int32_t _window_guest_list_selected_page; // 0x00F1EE07 -static uint32_t _window_guest_list_selected_view; // 0x00F1EE13 -static uint16_t _window_guest_list_num_pages; // 0x00F1EE08 -static uint32_t _window_guest_list_num_groups; // 0x00F1AF22 -static bool _window_guest_list_tracking_only; -static FilterArguments _window_guest_list_filter_arguments; - -static uint16_t _window_guest_list_groups_num_guests[240]; -static FilterArguments _window_guest_list_groups_arguments[240]; -static uint8_t _window_guest_list_groups_guest_faces[240 * 58]; -static uint8_t _window_guest_list_group_index[240]; - -static char _window_guest_list_filter_name[32]; - -static int32_t window_guest_list_is_peep_in_filter(Peep* peep); -static void window_guest_list_find_groups(); - -static FilterArguments get_arguments_from_peep(const Peep* peep); - -static bool guest_should_be_visible(Peep* peep); - -void window_guest_list_init_vars() -{ - _window_guest_list_selected_tab = 0; - _window_guest_list_selected_view = 0; - _window_guest_list_last_find_groups_tick = 0xFFFFFFFF; - _window_guest_list_selected_filter = 0xFF; - _window_guest_list_last_find_groups_wait = 0; -} - -/** - * - * rct2: 0x006992E3 - */ -rct_window* window_guest_list_open() -{ - rct_window* window; - - // Check if window is already open - window = window_bring_to_front_by_class(WC_GUEST_LIST); - if (window != nullptr) - return window; - - window = WindowCreateAutoPos(350, 330, &window_guest_list_events, WC_GUEST_LIST, WF_10 | WF_RESIZABLE); - window->widgets = window_guest_list_widgets; - window->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_PAGE_DROPDOWN) | (1 << WIDX_PAGE_DROPDOWN_BUTTON) - | (1 << WIDX_INFO_TYPE_DROPDOWN) | (1 << WIDX_INFO_TYPE_DROPDOWN_BUTTON) | (1 << WIDX_MAP) | (1 << WIDX_TRACKING) - | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_FILTER_BY_NAME); - - WindowInitScrollWidgets(window); - _window_guest_list_highlighted_index = 0xFFFF; - window->list_information_type = 0; - _window_guest_list_selected_tab = PAGE_INDIVIDUAL; - _window_guest_list_selected_filter = -1; - _window_guest_list_selected_page = 0; - _window_guest_list_num_pages = 1; - _window_guest_list_tracking_only = false; - _window_guest_list_filter_name[0] = '\0'; - window_guest_list_widgets[WIDX_TRACKING].type = WindowWidgetType::FlatBtn; - window_guest_list_widgets[WIDX_FILTER_BY_NAME].type = WindowWidgetType::FlatBtn; - window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::Empty; - window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Empty; - window->min_width = 350; - window->min_height = 330; - window->max_width = 500; - window->max_height = 450; - window_guest_list_refresh_list(); - return window; -} - -void window_guest_list_refresh_list() -{ - if (window_find_by_class(WC_GUEST_LIST) == nullptr) + enum class GuestViewType { - return; - } + Actions, + Thoughts, + }; - // Only the individual tab uses the GuestList so no point calculating it - if (_window_guest_list_selected_tab != PAGE_INDIVIDUAL) + enum class GuestFilterType { - _window_guest_list_last_find_groups_wait = 0; - _window_guest_list_last_find_groups_tick = 0; - window_guest_list_find_groups(); - return; - } + Guests, + GuestsThinking, + GuestsThinkingAbout, + }; - GuestList.clear(); - for (auto peep : EntityList(EntityListId::Peep)) + struct FilterArguments { - sprite_set_flashing(peep, false); - if (peep->OutsideOfPark) - continue; - if (_window_guest_list_selected_filter != -1) + uint8_t args[12]{}; + + rct_string_id GetFirstStringId() { - if (window_guest_list_is_peep_in_filter(peep)) - continue; - sprite_set_flashing(peep, true); + rct_string_id firstStrId{}; + std::memcpy(&firstStrId, args, sizeof(firstStrId)); + return firstStrId; } - if (!guest_should_be_visible(peep)) - continue; - GuestList.push_back(peep->sprite_index); - } - std::sort(GuestList.begin(), GuestList.end(), [](const uint16_t a, const uint16_t b) { return peep_compare(a, b) < 0; }); -} - -/** - * - * rct2: 0x006993BA - * - * @param index The number of the ride or index of the thought - */ -rct_window* window_guest_list_open_with_filter(GuestListFilterType type, int32_t index) -{ - rct_window* w = window_guest_list_open(); - - _window_guest_list_selected_page = 0; - _window_guest_list_num_pages = 1; - _window_guest_list_tracking_only = false; - _window_guest_list_filter_arguments = {}; - - Formatter ft(_window_guest_list_filter_arguments.args); - - switch (type) - { - case GuestListFilterType::GuestsOnRide: + bool operator==(const FilterArguments& other) { - auto ride = get_ride(index); - if (ride != nullptr) - { - ft.Add(ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_IN_RIDE) ? STR_IN_RIDE : STR_ON_RIDE); - ride->FormatNameTo(ft); - - _window_guest_list_selected_filter = 0; - _window_guest_list_highlighted_index = 0xFFFF; - _window_guest_list_selected_tab = 0; - _window_guest_list_selected_view = 0; - } - break; + return std::memcmp(args, other.args, sizeof(args)) == 0; } - case GuestListFilterType::GuestsInQueue: + bool operator!=(const FilterArguments& other) { - auto ride = get_ride(index); - if (ride != nullptr) - { - ft.Add(STR_QUEUING_FOR); - ride->FormatNameTo(ft); - - _window_guest_list_selected_filter = 0; - _window_guest_list_highlighted_index = 0xFFFF; - _window_guest_list_selected_tab = 0; - _window_guest_list_selected_view = 0; - } - break; + return !(*this == other); } - case GuestListFilterType::GuestsThinkingAboutRide: + }; + + struct GuestGroup + { + size_t NumGuests{}; + uint8_t Index{}; + FilterArguments Arguments; + uint8_t Faces[58]{}; + }; + + struct GuestItem + { + using CompareFunc = bool (*)(const GuestItem&, const GuestItem&); + + uint16_t Id; + char Name[256]; + }; + + static constexpr const uint8_t SUMMARISED_GUEST_ROW_HEIGHT = SCROLLABLE_ROW_HEIGHT + 11; + static constexpr const auto GUESTS_PER_PAGE = 2000; + static constexpr const auto GUEST_PAGE_HEIGHT = GUESTS_PER_PAGE * SCROLLABLE_ROW_HEIGHT; + static constexpr size_t MaxGroups = 240; + + TabId _selectedTab{}; + GuestViewType _selectedView; + bool _trackingOnly{}; + std::optional _selectedFilter; + FilterArguments _filterArguments; + std::string _filterName; + + size_t _numPages{}; + size_t _selectedPage{}; + + GuestViewType _lastFindGroupsSelectedView; + uint32_t _lastFindGroupsTick{}; + uint32_t _lastFindGroupsWait{}; + std::vector _groups; + + std::vector _guestList; + std::optional _highlightedIndex; + + uint32_t _tabAnimationIndex{}; + +public: + void OnOpen() override + { + widgets = window_guest_list_widgets; + enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_PAGE_DROPDOWN) | (1 << WIDX_PAGE_DROPDOWN_BUTTON) + | (1 << WIDX_INFO_TYPE_DROPDOWN) | (1 << WIDX_INFO_TYPE_DROPDOWN_BUTTON) | (1 << WIDX_MAP) | (1 << WIDX_TRACKING) + | (1 << WIDX_TAB_1) | (1 << WIDX_TAB_2) | (1 << WIDX_FILTER_BY_NAME); + WindowInitScrollWidgets(this); + + _selectedTab = TabId::Individual; + _numPages = 1; + widgets[WIDX_TRACKING].type = WindowWidgetType::FlatBtn; + widgets[WIDX_FILTER_BY_NAME].type = WindowWidgetType::FlatBtn; + widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::Empty; + widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Empty; + min_width = 350; + min_height = 330; + max_width = 500; + max_height = 450; + RefreshList(); + } + + void SetFilter(GuestListFilterType type, int32_t index) + { + _selectedPage = 0; + _numPages = 1; + _trackingOnly = false; + _filterArguments = {}; + + Formatter ft(_filterArguments.args); + + switch (type) { - auto ride = get_ride(index); - if (ride != nullptr) + case GuestListFilterType::GuestsOnRide: { - ft.Add(STR_NONE); - ride->FormatNameTo(ft); - - _window_guest_list_selected_filter = 1; - _window_guest_list_highlighted_index = 0xFFFF; - _window_guest_list_selected_tab = 0; - _window_guest_list_selected_view = 1; - } - break; - } - case GuestListFilterType::GuestsThinkingX: - { - ft.Add(PeepThoughts[index & 0xFF]); - - _window_guest_list_selected_filter = 1; - _window_guest_list_highlighted_index = 0xFFFF; - _window_guest_list_selected_tab = 0; - _window_guest_list_selected_view = 1; - break; - } - } - - window_guest_list_refresh_list(); - return w; -} - -/** - * - * rct2: 0x00699AAF - */ -static void window_guest_list_mouseup(rct_window* w, rct_widgetindex widgetIndex) -{ - switch (widgetIndex) - { - case WIDX_CLOSE: - window_close(w); - break; - case WIDX_MAP: - context_open_window(WC_MAP); - break; - case WIDX_TRACKING: - _window_guest_list_tracking_only = !_window_guest_list_tracking_only; - if (_window_guest_list_tracking_only) - w->pressed_widgets |= (1 << WIDX_TRACKING); - else - w->pressed_widgets &= ~(1 << WIDX_TRACKING); - w->Invalidate(); - w->scrolls[0].v_top = 0; - window_guest_list_refresh_list(); - break; - case WIDX_FILTER_BY_NAME: - if (strnlen(_window_guest_list_filter_name, sizeof(_window_guest_list_filter_name)) > 0) - { - // Unset the search filter. - _window_guest_list_filter_name[0] = '\0'; - w->pressed_widgets &= ~(1 << WIDX_FILTER_BY_NAME); - window_guest_list_refresh_list(); - } - else - { - window_text_input_open( - w, WIDX_FILTER_BY_NAME, STR_GUESTS_FILTER_BY_NAME, STR_GUESTS_ENTER_NAME_TO_SEARCH, STR_STRING, - reinterpret_cast(&_window_guest_list_filter_name), sizeof(_window_guest_list_filter_name)); - } - break; - } -} - -/** - * - * rct2: 0x00699EA3 - */ -static void window_guest_list_resize(rct_window* w) -{ - w->min_width = 350; - w->min_height = 330; - 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; - } -} - -/** - * - * rct2: 0x00699AC4 - */ -static void window_guest_list_mousedown(rct_window* w, rct_widgetindex widgetIndex, rct_widget* widget) -{ - int32_t i; - switch (widgetIndex) - { - case WIDX_TAB_1: - case WIDX_TAB_2: - if (_window_guest_list_selected_filter == -1) - if (_window_guest_list_selected_tab == widgetIndex - WIDX_TAB_1) - break; - _window_guest_list_selected_tab = widgetIndex - WIDX_TAB_1; - _window_guest_list_selected_page = 0; - _window_guest_list_num_pages = 1; - window_guest_list_widgets[WIDX_TRACKING].type = WindowWidgetType::Empty; - window_guest_list_widgets[WIDX_FILTER_BY_NAME].type = WindowWidgetType::Empty; - if (_window_guest_list_selected_tab == PAGE_INDIVIDUAL) - { - window_guest_list_widgets[WIDX_TRACKING].type = WindowWidgetType::FlatBtn; - window_guest_list_widgets[WIDX_FILTER_BY_NAME].type = WindowWidgetType::FlatBtn; - } - window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::Empty; - window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Empty; - w->list_information_type = 0; - _window_guest_list_selected_filter = -1; - w->Invalidate(); - w->scrolls[0].v_top = 0; - window_guest_list_refresh_list(); - break; - case WIDX_PAGE_DROPDOWN_BUTTON: - widget = &w->widgets[widgetIndex - 1]; - - WindowDropdownShowTextCustomWidth( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, - Dropdown::Flag::StayOpen, _window_guest_list_num_pages, widget->width() - 3); - - for (i = 0; i < _window_guest_list_num_pages; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - uint16_t* args = reinterpret_cast(&gDropdownItemsArgs[i]); - args[0] = STR_PAGE_X; - args[1] = i + 1; - } - Dropdown::SetChecked(_window_guest_list_selected_page, true); - break; - case WIDX_INFO_TYPE_DROPDOWN_BUTTON: - widget = &w->widgets[widgetIndex - 1]; - - for (i = 0; i < VIEW_COUNT; i++) - { - gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; - gDropdownItemsArgs[i] = viewNames[i]; - } - - WindowDropdownShowTextCustomWidth( - { w->windowPos.x + widget->left, w->windowPos.y + widget->top }, widget->height() + 1, w->colours[1], 0, - Dropdown::Flag::StayOpen, 2, widget->width() - 3); - - Dropdown::SetChecked(_window_guest_list_selected_view, true); - break; - } -} - -/** - * - * rct2: 0x00699AE1 - */ -static void window_guest_list_dropdown(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) -{ - switch (widgetIndex) - { - case WIDX_PAGE_DROPDOWN_BUTTON: - if (dropdownIndex == -1) - break; - _window_guest_list_selected_page = dropdownIndex; - w->Invalidate(); - break; - case WIDX_INFO_TYPE_DROPDOWN_BUTTON: - if (dropdownIndex == -1) - break; - _window_guest_list_selected_view = dropdownIndex; - w->Invalidate(); - break; - } -} - -/** - * - * rct2: 0x00699E54 - */ -static void window_guest_list_update(rct_window* w) -{ - if (_window_guest_list_last_find_groups_wait != 0) - { - _window_guest_list_last_find_groups_wait--; - } - w->list_information_type++; - if (w->list_information_type >= (_window_guest_list_selected_tab == PAGE_INDIVIDUAL ? 24 : 32)) - w->list_information_type = 0; - widget_invalidate(w, WIDX_TAB_1 + _window_guest_list_selected_tab); - gWindowMapFlashingFlags |= (1 << 0); -} - -/** - * - * rct2: 0x00699C55 - */ -static void window_guest_list_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height) -{ - int32_t y = 0; - switch (_window_guest_list_selected_tab) - { - case PAGE_INDIVIDUAL: - // Count the number of guests - y = static_cast(GuestList.size()) * SCROLLABLE_ROW_HEIGHT; - _window_guest_list_num_pages = 1 + (static_cast(GuestList.size()) - 1) / GUESTS_PER_PAGE; - if (_window_guest_list_num_pages == 0) - _window_guest_list_selected_page = 0; - else if (_window_guest_list_selected_page >= _window_guest_list_num_pages) - _window_guest_list_selected_page = _window_guest_list_num_pages - 1; - break; - case PAGE_SUMMARISED: - // Find the groups - window_guest_list_find_groups(); - y = _window_guest_list_num_groups * SUMMARISED_GUEST_ROW_HEIGHT; - break; - default: - log_error("Improper tab selected: %d, bailing out.", _window_guest_list_selected_tab); - return; - } - - y -= GUEST_PAGE_HEIGHT * _window_guest_list_selected_page; - y = std::max(0, std::min(y, GUEST_PAGE_HEIGHT)); - - if (_window_guest_list_highlighted_index != 0xFFFF) - { - _window_guest_list_highlighted_index = 0xFFFF; - w->Invalidate(); - } - - auto i = y - window_guest_list_widgets[WIDX_GUEST_LIST].bottom + window_guest_list_widgets[WIDX_GUEST_LIST].top + 21; - if (i < 0) - i = 0; - if (i < w->scrolls[0].v_top) - { - w->scrolls[0].v_top = i; - w->Invalidate(); - } - - *width = 447; - *height = y; -} - -/** - * - * rct2: 0x00699D7D - */ -static void window_guest_list_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) -{ - uint32_t i = 0; - - switch (_window_guest_list_selected_tab) - { - case PAGE_INDIVIDUAL: - i = screenCoords.y / SCROLLABLE_ROW_HEIGHT; - i += _window_guest_list_selected_page * GUESTS_PER_PAGE; - for (auto spriteIndex : GuestList) - { - if (i == 0) + auto guestRide = get_ride(index); + if (guestRide != nullptr) { - auto guest = GetEntity(spriteIndex); - if (guest != nullptr) - { - window_guest_open(guest); - } - break; + ft.Add( + ride_type_has_flag(guestRide->type, RIDE_TYPE_FLAG_IN_RIDE) ? STR_IN_RIDE : STR_ON_RIDE); + guestRide->FormatNameTo(ft); + + _selectedFilter = GuestFilterType::Guests; + _highlightedIndex = {}; + _selectedTab = TabId::Individual; + _selectedView = GuestViewType::Actions; } - i--; + break; } - break; - case PAGE_SUMMARISED: - i = screenCoords.y / SUMMARISED_GUEST_ROW_HEIGHT; - if (i < _window_guest_list_num_groups) + case GuestListFilterType::GuestsInQueue: { - _window_guest_list_filter_arguments = _window_guest_list_groups_arguments[i]; - _window_guest_list_selected_filter = _window_guest_list_selected_view; - _window_guest_list_selected_tab = PAGE_INDIVIDUAL; - window_guest_list_widgets[WIDX_TRACKING].type = WindowWidgetType::FlatBtn; - w->Invalidate(); - w->scrolls[0].v_top = 0; - window_guest_list_refresh_list(); + auto guestRide = get_ride(index); + if (guestRide != nullptr) + { + ft.Add(STR_QUEUING_FOR); + guestRide->FormatNameTo(ft); + + _selectedFilter = GuestFilterType::Guests; + _highlightedIndex = {}; + _selectedTab = TabId::Individual; + _selectedView = GuestViewType::Actions; + } + break; } - break; + case GuestListFilterType::GuestsThinkingAboutRide: + { + auto guestRide = get_ride(index); + if (guestRide != nullptr) + { + ft.Add(STR_NONE); + guestRide->FormatNameTo(ft); + + _selectedFilter = GuestFilterType::GuestsThinking; + _highlightedIndex = {}; + _selectedTab = TabId::Individual; + _selectedView = GuestViewType::Thoughts; + } + break; + } + case GuestListFilterType::GuestsThinkingX: + { + ft.Add(PeepThoughts[index & 0xFF]); + + _selectedFilter = GuestFilterType::GuestsThinking; + _highlightedIndex = {}; + _selectedTab = TabId::Individual; + _selectedView = GuestViewType::Thoughts; + break; + } + } + + RefreshList(); } -} -/** - * - * rct2: 0x00699D3B - */ -static void window_guest_list_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) -{ - uint32_t i; - - i = screenCoords.y - / (_window_guest_list_selected_tab == PAGE_INDIVIDUAL ? SCROLLABLE_ROW_HEIGHT : SUMMARISED_GUEST_ROW_HEIGHT); - i += _window_guest_list_selected_page * GUESTS_PER_PAGE; - if (i != _window_guest_list_highlighted_index) + void OnResize() override { - _window_guest_list_highlighted_index = i; - w->Invalidate(); - } -} - -/** - * - * rct2: 0x00699511 - */ -static void window_guest_list_invalidate(rct_window* w) -{ - w->pressed_widgets &= ~(1 << WIDX_TAB_1); - w->pressed_widgets &= ~(1 << WIDX_TAB_2); - w->pressed_widgets |= (1LL << (_window_guest_list_selected_tab + WIDX_TAB_1)); - - window_guest_list_widgets[WIDX_INFO_TYPE_DROPDOWN].text = viewNames[_window_guest_list_selected_view]; - window_guest_list_widgets[WIDX_MAP].type = WindowWidgetType::Empty; - if (_window_guest_list_selected_tab == PAGE_INDIVIDUAL && _window_guest_list_selected_filter != -1) - window_guest_list_widgets[WIDX_MAP].type = WindowWidgetType::FlatBtn; - - window_guest_list_widgets[WIDX_BACKGROUND].right = w->width - 1; - window_guest_list_widgets[WIDX_BACKGROUND].bottom = w->height - 1; - window_guest_list_widgets[WIDX_TAB_CONTENT_PANEL].right = w->width - 1; - window_guest_list_widgets[WIDX_TAB_CONTENT_PANEL].bottom = w->height - 1; - window_guest_list_widgets[WIDX_TITLE].right = w->width - 2; - window_guest_list_widgets[WIDX_CLOSE].left = w->width - 13; - window_guest_list_widgets[WIDX_CLOSE].right = w->width - 3; - window_guest_list_widgets[WIDX_GUEST_LIST].right = w->width - 4; - window_guest_list_widgets[WIDX_GUEST_LIST].bottom = w->height - 15; - window_guest_list_widgets[WIDX_MAP].left = 273 - 350 + w->width; - window_guest_list_widgets[WIDX_MAP].right = 296 - 350 + w->width; - window_guest_list_widgets[WIDX_FILTER_BY_NAME].left = 297 - 350 + w->width; - window_guest_list_widgets[WIDX_FILTER_BY_NAME].right = 320 - 350 + w->width; - window_guest_list_widgets[WIDX_TRACKING].left = 321 - 350 + w->width; - window_guest_list_widgets[WIDX_TRACKING].right = 344 - 350 + w->width; - - if (_window_guest_list_num_pages > 1) - { - window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::DropdownMenu; - window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Button; - auto ft = Formatter::Common(); - ft.Increment(4); - ft.Add(_window_guest_list_selected_page + 1); - } - else - { - window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::Empty; - window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Empty; - } -} - -/** - * - * rct2: 0x006995CC - */ -static void window_guest_list_paint(rct_window* w, rct_drawpixelinfo* dpi) -{ - int32_t i; - rct_string_id format; - - // Widgets - WindowDrawWidgets(w, dpi); - // Tab 1 image - i = (_window_guest_list_selected_tab == 0 ? w->list_information_type & 0x0FFFFFFFC : 0); - i += GetPeepAnimation(PeepSpriteType::Normal).base_image + 1; - i |= 0xA1600000; - gfx_draw_sprite( - dpi, i, - w->windowPos - + ScreenCoordsXY{ window_guest_list_widgets[WIDX_TAB_1].midX(), window_guest_list_widgets[WIDX_TAB_1].bottom - 6 }, - 0); - - // Tab 2 image - i = (_window_guest_list_selected_tab == 1 ? w->list_information_type / 4 : 0); - gfx_draw_sprite( - dpi, SPR_TAB_GUESTS_0 + i, - w->windowPos + ScreenCoordsXY{ window_guest_list_widgets[WIDX_TAB_2].left, window_guest_list_widgets[WIDX_TAB_2].top }, - 0); - - // Filter description - auto screenCoords = w->windowPos + ScreenCoordsXY{ 6, window_guest_list_widgets[WIDX_TAB_CONTENT_PANEL].top + 3 }; - if (_window_guest_list_selected_tab == PAGE_INDIVIDUAL) - { - if (_window_guest_list_selected_filter != -1) + min_width = 350; + min_height = 330; + if (width < min_width) { - if (_window_guest_list_filter_arguments.GetFirstStringId() != STR_NONE) + Invalidate(); + width = min_width; + } + if (height < min_height) + { + Invalidate(); + height = min_height; + } + } + + void OnUpdate() override + { + if (_lastFindGroupsWait != 0) + { + _lastFindGroupsWait--; + } + + // Current tab image animation + _tabAnimationIndex++; + if (_tabAnimationIndex >= (_selectedTab == TabId::Individual ? 24UL : 32UL)) + _tabAnimationIndex = 0; + InvalidateWidget(WIDX_TAB_1 + static_cast(_selectedTab)); + + gWindowMapFlashingFlags |= (1 << 0); + } + + void OnMouseUp(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_CLOSE: + Close(); + break; + case WIDX_MAP: + context_open_window(WC_MAP); + break; + case WIDX_TRACKING: + _trackingOnly = !_trackingOnly; + SetWidgetPressed(WIDX_TRACKING, _trackingOnly); + Invalidate(); + scrolls[0].v_top = 0; + RefreshList(); + break; + case WIDX_FILTER_BY_NAME: + if (!_filterName.empty()) + { + // Unset the search filter. + _filterName.clear(); + SetWidgetPressed(WIDX_FILTER_BY_NAME, false); + RefreshList(); + } + else + { + window_text_input_raw_open( + this, WIDX_FILTER_BY_NAME, STR_GUESTS_FILTER_BY_NAME, STR_GUESTS_ENTER_NAME_TO_SEARCH, + _filterName.c_str(), 32); + } + break; + } + } + + void OnMouseDown(rct_widgetindex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_TAB_1: + case WIDX_TAB_2: { - format = filterNames[_window_guest_list_selected_filter]; // Not sure whether the index will ever be 2 + if (_selectedFilter && _selectedTab == static_cast(widgetIndex - WIDX_TAB_1)) + break; + _selectedTab = static_cast(widgetIndex - WIDX_TAB_1); + _selectedPage = 0; + _numPages = 1; + widgets[WIDX_TRACKING].type = WindowWidgetType::Empty; + widgets[WIDX_FILTER_BY_NAME].type = WindowWidgetType::Empty; + if (_selectedTab == TabId::Individual) + { + widgets[WIDX_TRACKING].type = WindowWidgetType::FlatBtn; + widgets[WIDX_FILTER_BY_NAME].type = WindowWidgetType::FlatBtn; + } + widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::Empty; + widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Empty; + _tabAnimationIndex = 0; + _selectedFilter = {}; + Invalidate(); + scrolls[0].v_top = 0; + RefreshList(); + break; + } + case WIDX_PAGE_DROPDOWN_BUTTON: + { + auto* widget = &widgets[widgetIndex - 1]; + + WindowDropdownShowTextCustomWidth( + { windowPos.x + widget->left, windowPos.y + widget->top }, widget->height() + 1, colours[1], 0, + Dropdown::Flag::StayOpen, _numPages, widget->width() - 3); + + for (size_t i = 0; i < _numPages; i++) + { + gDropdownItemsFormat[i] = STR_DROPDOWN_MENU_LABEL; + uint16_t* args = reinterpret_cast(&gDropdownItemsArgs[i]); + args[0] = STR_PAGE_X; + args[1] = static_cast(i + 1); + } + Dropdown::SetChecked(static_cast(_selectedPage), true); + break; + } + case WIDX_INFO_TYPE_DROPDOWN_BUTTON: + { + gDropdownItemsFormat[0] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[0] = GetViewName(GuestViewType::Actions); + gDropdownItemsFormat[1] = STR_DROPDOWN_MENU_LABEL; + gDropdownItemsArgs[1] = GetViewName(GuestViewType::Thoughts); + + auto* widget = &widgets[widgetIndex - 1]; + WindowDropdownShowTextCustomWidth( + { windowPos.x + widget->left, windowPos.y + widget->top }, widget->height() + 1, colours[1], 0, + Dropdown::Flag::StayOpen, 2, widget->width() - 3); + + Dropdown::SetChecked(static_cast(_selectedView), true); + break; + } + } + } + + void OnDropdown(rct_widgetindex widgetIndex, int32_t dropdownIndex) override + { + switch (widgetIndex) + { + case WIDX_PAGE_DROPDOWN_BUTTON: + _selectedPage = dropdownIndex; + Invalidate(); + break; + case WIDX_INFO_TYPE_DROPDOWN_BUTTON: + _selectedView = static_cast(dropdownIndex); + Invalidate(); + break; + } + } + + void OnTextInput(rct_widgetindex widgetIndex, std::string_view text) override + { + if (!text.empty()) + { + _filterName = text; + SetWidgetPressed(WIDX_FILTER_BY_NAME, true); + RefreshList(); + } + } + + void OnPrepareDraw() override + { + SetWidgetPressed(WIDX_TAB_1, false); + SetWidgetPressed(WIDX_TAB_2, false); + SetWidgetPressed(WIDX_TAB_1 + static_cast(_selectedTab), true); + + widgets[WIDX_INFO_TYPE_DROPDOWN].text = GetViewName(_selectedView); + widgets[WIDX_MAP].type = WindowWidgetType::Empty; + if (_selectedTab == TabId::Individual && _selectedFilter) + widgets[WIDX_MAP].type = WindowWidgetType::FlatBtn; + + widgets[WIDX_BACKGROUND].right = width - 1; + widgets[WIDX_BACKGROUND].bottom = height - 1; + widgets[WIDX_TAB_CONTENT_PANEL].right = width - 1; + widgets[WIDX_TAB_CONTENT_PANEL].bottom = height - 1; + widgets[WIDX_TITLE].right = width - 2; + widgets[WIDX_CLOSE].left = width - 13; + widgets[WIDX_CLOSE].right = width - 3; + widgets[WIDX_GUEST_LIST].right = width - 4; + widgets[WIDX_GUEST_LIST].bottom = height - 15; + widgets[WIDX_MAP].left = 273 - 350 + width; + widgets[WIDX_MAP].right = 296 - 350 + width; + widgets[WIDX_FILTER_BY_NAME].left = 297 - 350 + width; + widgets[WIDX_FILTER_BY_NAME].right = 320 - 350 + width; + widgets[WIDX_TRACKING].left = 321 - 350 + width; + widgets[WIDX_TRACKING].right = 344 - 350 + width; + + if (_numPages > 1) + { + widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::DropdownMenu; + widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Button; + auto ft = Formatter::Common(); + ft.Increment(4); + ft.Add(_selectedPage + 1); + } + else + { + widgets[WIDX_PAGE_DROPDOWN].type = WindowWidgetType::Empty; + widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WindowWidgetType::Empty; + } + } + + void OnDraw(rct_drawpixelinfo& dpi) override + { + DrawWidgets(dpi); + DrawTabImages(dpi); + + // Filter description + rct_string_id format; + auto screenCoords = windowPos + ScreenCoordsXY{ 6, widgets[WIDX_TAB_CONTENT_PANEL].top + 3 }; + if (_selectedTab == TabId::Individual) + { + if (_selectedFilter) + { + if (_filterArguments.GetFirstStringId() != STR_NONE) + { + format = GetFilterString(*_selectedFilter); + } + else + { + format = STR_GUESTS_FILTER_THINKING_ABOUT; + } } else { - format = STR_GUESTS_FILTER_THINKING_ABOUT; + format = STR_ALL_GUESTS; } } else { - format = STR_ALL_GUESTS; + format = STR_ALL_GUESTS_SUMMARISED; } - } - else - { - format = STR_ALL_GUESTS_SUMMARISED; - } - { - Formatter ft(_window_guest_list_filter_arguments.args); - DrawTextEllipsised(dpi, screenCoords, 310, format, ft, COLOUR_BLACK); - } - - // Number of guests (list items) - if (_window_guest_list_selected_tab == PAGE_INDIVIDUAL) - { - screenCoords = w->windowPos + ScreenCoordsXY{ 4, window_guest_list_widgets[WIDX_GUEST_LIST].bottom + 2 }; - auto ft = Formatter(); - ft.Add(static_cast(GuestList.size())); - gfx_draw_string_left( - dpi, (GuestList.size() == 1 ? STR_FORMAT_NUM_GUESTS_SINGULAR : STR_FORMAT_NUM_GUESTS_PLURAL), ft.Data(), - COLOUR_BLACK, screenCoords); - } -} - -/** - * - * rct2: 0x00699701 - */ -static void window_guest_list_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex) -{ - int32_t y; - rct_string_id format; - rct_peep_thought* thought; - - // Background fill - gfx_fill_rect( - dpi, { { dpi->x, dpi->y }, { dpi->x + dpi->width - 1, dpi->y + dpi->height - 1 } }, - ColourMapA[w->colours[1]].mid_light); - switch (_window_guest_list_selected_tab) - { - case PAGE_INDIVIDUAL: { - uint32_t i = 0; - y = _window_guest_list_selected_page * -GUEST_PAGE_HEIGHT; - - // For each guest - for (auto spriteIndex : GuestList) - { - // Check if y is beyond the scroll control - if (y + SCROLLABLE_ROW_HEIGHT + 1 >= -0x7FFF && y + SCROLLABLE_ROW_HEIGHT + 1 > dpi->y && y < 0x7FFF - && y < dpi->y + dpi->height) - { - // Highlight backcolour and text colour (format) - format = STR_BLACK_STRING; - if (i == _window_guest_list_highlighted_index) - { - gfx_filter_rect(dpi, 0, y, 800, y + SCROLLABLE_ROW_HEIGHT - 1, FilterPaletteID::PaletteDarken1); - format = STR_WINDOW_COLOUR_2_STRINGID; - } - - // Guest name - auto peep = GetEntity(spriteIndex); - if (peep == nullptr) - { - continue; - } - auto ft = Formatter(); - peep->FormatNameTo(ft); - DrawTextEllipsised(dpi, { 0, y }, 113, format, ft, COLOUR_BLACK); - - switch (_window_guest_list_selected_view) - { - case VIEW_ACTIONS: - // Guest face - gfx_draw_sprite(dpi, get_peep_face_sprite_small(peep), { 118, y + 1 }, 0); - - // Tracking icon - if (peep->PeepFlags & PEEP_FLAGS_TRACKING) - gfx_draw_sprite(dpi, STR_ENTER_SELECTION_SIZE, { 112, y + 1 }, 0); - - // Action - ft = Formatter(); - peep->FormatActionTo(ft); - DrawTextEllipsised(dpi, { 133, y }, 314, format, ft, COLOUR_BLACK); - break; - case VIEW_THOUGHTS: - // For each thought - for (uint32_t j = 0; j < PEEP_MAX_THOUGHTS; j++) - { - thought = &peep->Thoughts[j]; - if (thought->type == PeepThoughtType::None) - break; - if (thought->freshness == 0) - continue; - if (thought->freshness > 5) - break; - - ft = Formatter(); - peep_thought_set_format_args(&peep->Thoughts[j], ft); - DrawTextEllipsised(dpi, { 118, y }, 329, format, ft, COLOUR_BLACK); - break; - } - break; - } - } - - // Increment list item index and y - i++; - y += SCROLLABLE_ROW_HEIGHT; - } - break; + Formatter ft(_filterArguments.args); + DrawTextEllipsised(&dpi, screenCoords, 310, format, ft, COLOUR_BLACK); } - case PAGE_SUMMARISED: - y = 0; - // For each group of guests - for (uint32_t i = 0; i < _window_guest_list_num_groups; i++) - { - // Check if y is beyond the scroll control - if (y + SUMMARISED_GUEST_ROW_HEIGHT + 1 >= dpi->y) + // Number of guests (list items) + if (_selectedTab == TabId::Individual) + { + screenCoords = windowPos + ScreenCoordsXY{ 4, widgets[WIDX_GUEST_LIST].bottom + 2 }; + auto ft = Formatter(); + ft.Add(static_cast(_guestList.size())); + gfx_draw_string_left( + &dpi, (_guestList.size() == 1 ? STR_FORMAT_NUM_GUESTS_SINGULAR : STR_FORMAT_NUM_GUESTS_PLURAL), ft.Data(), + COLOUR_BLACK, screenCoords); + } + } + + ScreenSize OnScrollGetSize(int32_t scrollIndex) override + { + int32_t y = 0; + switch (_selectedTab) + { + case TabId::Individual: + // Count the number of guests + y = static_cast(_guestList.size()) * SCROLLABLE_ROW_HEIGHT; + _numPages = (_guestList.size() + GUESTS_PER_PAGE - 1) / GUESTS_PER_PAGE; + if (_numPages == 0) + _selectedPage = 0; + else if (_selectedPage >= _numPages) + _selectedPage = _numPages - 1; + break; + case TabId::Summarised: + default: + // Find the groups + if (IsRefreshOfGroupsRequired()) { - // Check if y is beyond the scroll control - if (y >= dpi->y + dpi->height) + RefreshGroups(); + } + y = static_cast(_groups.size() * SUMMARISED_GUEST_ROW_HEIGHT); + break; + } + + y -= static_cast(GUEST_PAGE_HEIGHT * _selectedPage); + y = std::max(0, std::min(y, GUEST_PAGE_HEIGHT)); + + if (_highlightedIndex) + { + _highlightedIndex = {}; + Invalidate(); + } + + auto i = std::max(0, y - widgets[WIDX_GUEST_LIST].bottom + widgets[WIDX_GUEST_LIST].top + 21); + if (i < scrolls[0].v_top) + { + scrolls[0].v_top = i; + Invalidate(); + } + + return { 447, y }; + } + + void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + auto i = screenCoords.y / (_selectedTab == TabId::Individual ? SCROLLABLE_ROW_HEIGHT : SUMMARISED_GUEST_ROW_HEIGHT); + i += static_cast(_selectedPage * GUESTS_PER_PAGE); + if (static_cast(i) != _highlightedIndex) + { + _highlightedIndex = i; + Invalidate(); + } + } + + void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) override + { + switch (_selectedTab) + { + case TabId::Individual: + { + auto i = screenCoords.y / SCROLLABLE_ROW_HEIGHT; + i += static_cast(_selectedPage * GUESTS_PER_PAGE); + for (const auto& guestItem : _guestList) + { + if (i == 0) + { + auto guest = GetEntity(guestItem.Id); + if (guest != nullptr) + { + window_guest_open(guest); + } break; - - // Highlight backcolour and text colour (format) - format = STR_BLACK_STRING; - if (i == _window_guest_list_highlighted_index) - { - gfx_filter_rect(dpi, 0, y, 800, y + SUMMARISED_GUEST_ROW_HEIGHT, FilterPaletteID::PaletteDarken1); - format = STR_WINDOW_COLOUR_2_STRINGID; } - - // Draw guest faces - uint32_t numGuests = _window_guest_list_groups_num_guests[i]; - for (uint32_t j = 0; j < 56 && j < numGuests; j++) - gfx_draw_sprite( - dpi, _window_guest_list_groups_guest_faces[i * 56 + j] + SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY, - { static_cast(j) * 8, y + 12 }, 0); - - // Draw action - Formatter ft(_window_guest_list_groups_arguments[i].args); - DrawTextEllipsised(dpi, { 0, y }, 414, format, ft, COLOUR_BLACK); - - // Draw guest count - ft = Formatter(); - ft.Add(STR_GUESTS_COUNT_COMMA_SEP); - ft.Add(numGuests); - DrawTextBasic(dpi, { 326, y }, format, ft, COLOUR_BLACK, TextAlignment::RIGHT); + i--; } - y += SUMMARISED_GUEST_ROW_HEIGHT; + break; } - break; - } -} - -static void window_guest_list_textinput(rct_window* w, rct_widgetindex widgetIndex, char* text) -{ - if (text != nullptr && text[0] != '\0') - { - safe_strcpy(_window_guest_list_filter_name, text, sizeof(_window_guest_list_filter_name)); - w->pressed_widgets |= (1 << WIDX_FILTER_BY_NAME); - window_guest_list_refresh_list(); - } -} - -/** - * returns 0 for in filter and 1 for not in filter - * rct2: 0x0069B865 - */ -static int32_t window_guest_list_is_peep_in_filter(Peep* peep) -{ - char temp = _window_guest_list_selected_view; - _window_guest_list_selected_view = _window_guest_list_selected_filter; - auto peepArgs = get_arguments_from_peep(peep); - - _window_guest_list_selected_view = temp; - - if (_window_guest_list_filter_arguments.GetFirstStringId() == STR_NONE && _window_guest_list_selected_filter == 1) - { - Formatter(peepArgs.args).Add(STR_NONE); - } - - if (_window_guest_list_filter_arguments == peepArgs) - { - return 0; - } - return 1; -} - -/** - * Calculates a hash value (arguments) for comparing peep actions/thoughts - * rct2: 0x0069B7EA - * peep (esi) - * argument_1 (0x013CE952) gCommonFormatArgs - * argument_2 (0x013CE954) gCommonFormatArgs + 2 - */ -static FilterArguments get_arguments_from_peep(const Peep* peep) -{ - FilterArguments result; - Formatter ft(result.args); - switch (_window_guest_list_selected_view) - { - case VIEW_ACTIONS: - peep->FormatActionTo(ft); - break; - case VIEW_THOUGHTS: - { - auto thought = &peep->Thoughts[0]; - if (thought->freshness <= 5 && thought->type != PeepThoughtType::None) + case TabId::Summarised: { - peep_thought_set_format_args(thought, ft); + auto i = static_cast(screenCoords.y / SUMMARISED_GUEST_ROW_HEIGHT); + if (i < _groups.size()) + { + _filterArguments = _groups[i].Arguments; + _selectedFilter = _selectedView == GuestViewType::Actions ? GuestFilterType::Guests + : GuestFilterType::GuestsThinking; + _selectedTab = TabId::Individual; + widgets[WIDX_TRACKING].type = WindowWidgetType::FlatBtn; + Invalidate(); + scrolls[0].v_top = 0; + RefreshList(); + } + break; } - break; } } - return result; -} -/** - * - * rct2: 0x0069B5AE - */ -static void window_guest_list_find_groups() -{ - uint32_t tick256 = floor2(gScenarioTicks, 256); - if (_window_guest_list_selected_view == _window_guest_list_last_find_groups_selected_view) + void OnScrollDraw(int32_t scrollIndex, rct_drawpixelinfo& dpi) override { - if (_window_guest_list_last_find_groups_wait != 0 || _window_guest_list_last_find_groups_tick == tick256) + gfx_fill_rect( + &dpi, { { dpi.x, dpi.y }, { dpi.x + dpi.width - 1, dpi.y + dpi.height - 1 } }, ColourMapA[colours[1]].mid_light); + switch (_selectedTab) { - return; + case TabId::Individual: + DrawScrollIndividual(dpi); + break; + case TabId::Summarised: + DrawScrollSummarised(dpi); + break; } } - _window_guest_list_last_find_groups_tick = tick256; - _window_guest_list_last_find_groups_selected_view = _window_guest_list_selected_view; - _window_guest_list_last_find_groups_wait = 320; - _window_guest_list_num_groups = 0; - - // Set all guests to unassigned + void RefreshList() { + // Only the individual tab uses the GuestList so no point calculating it + if (_selectedTab != TabId::Individual) + { + RefreshGroups(); + } + else + { + _guestList.clear(); + + for (auto peep : EntityList(EntityListId::Peep)) + { + sprite_set_flashing(peep, false); + if (peep->OutsideOfPark) + continue; + if (_selectedFilter) + { + if (!IsPeepInFilter(*peep)) + continue; + sprite_set_flashing(peep, true); + } + if (!GuestShouldBeVisible(*peep)) + continue; + + auto& item = _guestList.emplace_back(); + item.Id = peep->sprite_index; + + Formatter ft; + peep->FormatNameTo(ft); + format_string(item.Name, sizeof(item.Name), STR_STRINGID, ft.Data()); + } + + std::sort(_guestList.begin(), _guestList.end(), GetGuestCompareFunc()); + } + } + +private: + void DrawTabImages(rct_drawpixelinfo& dpi) + { + // Tab 1 image + auto i = (_selectedTab == TabId::Individual ? _tabAnimationIndex & ~3 : 0); + i += GetPeepAnimation(PeepSpriteType::Normal).base_image + 1; + i |= 0xA1600000; + gfx_draw_sprite(&dpi, i, windowPos + ScreenCoordsXY{ widgets[WIDX_TAB_1].midX(), widgets[WIDX_TAB_1].bottom - 6 }, 0); + + // Tab 2 image + i = (_selectedTab == TabId::Summarised ? _tabAnimationIndex / 4 : 0); + gfx_draw_sprite( + &dpi, SPR_TAB_GUESTS_0 + i, windowPos + ScreenCoordsXY{ widgets[WIDX_TAB_2].left, widgets[WIDX_TAB_2].top }, 0); + } + + void DrawScrollIndividual(rct_drawpixelinfo& dpi) + { + size_t index = 0; + auto y = static_cast(_selectedPage) * -GUEST_PAGE_HEIGHT; + for (const auto& guestItem : _guestList) + { + // Check if y is beyond the scroll control + if (y + SCROLLABLE_ROW_HEIGHT + 1 >= -0x7FFF && y + SCROLLABLE_ROW_HEIGHT + 1 > dpi.y && y < 0x7FFF + && y < dpi.y + dpi.height) + { + // Highlight backcolour and text colour (format) + rct_string_id format = STR_BLACK_STRING; + if (index == _highlightedIndex) + { + gfx_filter_rect(&dpi, 0, y, 800, y + SCROLLABLE_ROW_HEIGHT - 1, FilterPaletteID::PaletteDarken1); + format = STR_WINDOW_COLOUR_2_STRINGID; + } + + // Guest name + auto peep = GetEntity(guestItem.Id); + if (peep == nullptr) + { + continue; + } + auto ft = Formatter(); + peep->FormatNameTo(ft); + DrawTextEllipsised(&dpi, { 0, y }, 113, format, ft, COLOUR_BLACK); + + switch (_selectedView) + { + case GuestViewType::Actions: + // Guest face + gfx_draw_sprite(&dpi, get_peep_face_sprite_small(peep), { 118, y + 1 }, 0); + + // Tracking icon + if (peep->PeepFlags & PEEP_FLAGS_TRACKING) + gfx_draw_sprite(&dpi, STR_ENTER_SELECTION_SIZE, { 112, y + 1 }, 0); + + // Action + ft = Formatter(); + peep->FormatActionTo(ft); + DrawTextEllipsised(&dpi, { 133, y }, 314, format, ft, COLOUR_BLACK); + break; + case GuestViewType::Thoughts: + // For each thought + for (const auto& thought : peep->Thoughts) + { + if (thought.type == PeepThoughtType::None) + break; + if (thought.freshness == 0) + continue; + if (thought.freshness > 5) + break; + + ft = Formatter(); + peep_thought_set_format_args(&thought, ft); + DrawTextEllipsised(&dpi, { 118, y }, 329, format, ft, COLOUR_BLACK); + break; + } + break; + } + } + y += SCROLLABLE_ROW_HEIGHT; + index++; + } + } + + void DrawScrollSummarised(rct_drawpixelinfo& dpi) + { + size_t index = 0; + auto y = 0; + for (auto& group : _groups) + { + // Check if y is beyond the scroll control + if (y + SUMMARISED_GUEST_ROW_HEIGHT + 1 >= dpi.y) + { + // Check if y is beyond the scroll control + if (y >= dpi.y + dpi.height) + break; + + // Highlight backcolour and text colour (format) + rct_string_id format = STR_BLACK_STRING; + if (index == _highlightedIndex) + { + gfx_filter_rect(&dpi, 0, y, 800, y + SUMMARISED_GUEST_ROW_HEIGHT, FilterPaletteID::PaletteDarken1); + format = STR_WINDOW_COLOUR_2_STRINGID; + } + + // Draw guest faces + for (uint32_t j = 0; j < std::size(group.Faces) && j < group.NumGuests; j++) + { + gfx_draw_sprite( + &dpi, group.Faces[j] + SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY, { static_cast(j) * 8, y + 12 }, + 0); + } + + // Draw action + Formatter ft(group.Arguments.args); + DrawTextEllipsised(&dpi, { 0, y }, 414, format, ft, COLOUR_BLACK); + + // Draw guest count + ft = Formatter(); + ft.Add(STR_GUESTS_COUNT_COMMA_SEP); + ft.Add(group.NumGuests); + DrawTextBasic(&dpi, { 326, y }, format, ft, COLOUR_BLACK, TextAlignment::RIGHT); + } + y += SUMMARISED_GUEST_ROW_HEIGHT; + index++; + } + } + + bool GuestShouldBeVisible(const Peep& peep) + { + if (_trackingOnly && !(peep.PeepFlags & PEEP_FLAGS_TRACKING)) + return false; + + if (!_filterName.empty()) + { + char name[256]{}; + + Formatter ft; + peep.FormatNameTo(ft); + format_string(name, sizeof(name), STR_STRINGID, ft.Data()); + if (strcasestr(name, _filterName.c_str()) == nullptr) + { + return false; + } + } + + return true; + } + + bool IsPeepInFilter(const Peep& peep) + { + auto guestViewType = _selectedFilter == GuestFilterType::Guests ? GuestViewType::Actions : GuestViewType::Thoughts; + auto peepArgs = GetArgumentsFromPeep(peep, guestViewType); + if (_filterArguments.GetFirstStringId() == STR_NONE && _selectedFilter == GuestFilterType::GuestsThinking) + { + Formatter(peepArgs.args).Add(STR_NONE); + } + return _filterArguments == peepArgs; + } + + bool IsRefreshOfGroupsRequired() + { + uint32_t tick256 = floor2(gScenarioTicks, 256); + if (_selectedView == _lastFindGroupsSelectedView) + { + if (_lastFindGroupsWait != 0 || _lastFindGroupsTick == tick256) + { + return false; + } + } + + return true; + } + + void RefreshGroups() + { + _lastFindGroupsTick = floor2(gScenarioTicks, 256); + _lastFindGroupsSelectedView = _selectedView; + _lastFindGroupsWait = 320; + _groups.clear(); + + // Reset all guests to unvisited for (auto peep : EntityList(EntityListId::Peep)) { if (!peep->OutsideOfPark) @@ -951,115 +824,170 @@ static void window_guest_list_find_groups() peep->flags |= SPRITE_FLAGS_PEEP_VISIBLE; } } - } - // For each guest / group - for (auto peep : EntityList(EntityListId::Peep)) - { - if (peep->OutsideOfPark || !(peep->flags & SPRITE_FLAGS_PEEP_VISIBLE)) - continue; - // New group, cap at 240 though - int32_t groupIndex = _window_guest_list_num_groups; - if (groupIndex >= 240) - break; - - _window_guest_list_num_groups++; - _window_guest_list_groups_num_guests[groupIndex] = 1; - peep->flags &= ~(SPRITE_FLAGS_PEEP_VISIBLE); - - _window_guest_list_groups_arguments[groupIndex] = get_arguments_from_peep(peep); - _window_guest_list_filter_arguments = _window_guest_list_groups_arguments[groupIndex]; - - _window_guest_list_group_index[groupIndex] = groupIndex; - auto faceIndex = groupIndex * 56; - _window_guest_list_groups_guest_faces[faceIndex++] = get_peep_face_sprite_small(peep) - - SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY; - - // Find more peeps that belong to same group - for (auto peep2 : EntityList(EntityListId::Peep)) + for (auto peep : EntityList(EntityListId::Peep)) { - if (peep2->OutsideOfPark || !(peep2->flags & SPRITE_FLAGS_PEEP_VISIBLE)) + if (peep->OutsideOfPark || !(peep->flags & SPRITE_FLAGS_PEEP_VISIBLE)) continue; + if (_groups.size() >= MaxGroups) + break; - // Get and check if in same group - auto argument12 = get_arguments_from_peep(peep2); - if (argument12 != _window_guest_list_groups_arguments[groupIndex]) - continue; + // Mark guest as visted + peep->flags &= ~(SPRITE_FLAGS_PEEP_VISIBLE); - // Assign guest - _window_guest_list_groups_num_guests[groupIndex]++; - peep2->flags &= ~(SPRITE_FLAGS_PEEP_VISIBLE); + // Create new group and push first guest + auto& group = _groups.emplace_back(); + group.Arguments = GetArgumentsFromPeep(*peep, _selectedView); + group.Index = static_cast(_groups.size() - 1); + group.Faces[group.NumGuests] = get_peep_face_sprite_small(peep) - SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY; + group.NumGuests++; - // Add face sprite, cap at 56 though - if (_window_guest_list_groups_num_guests[groupIndex] >= 56) - continue; - _window_guest_list_groups_guest_faces[faceIndex++] = get_peep_face_sprite_small(peep2) - - SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY; - } - - if (_window_guest_list_filter_arguments.GetFirstStringId() == 0) - { - _window_guest_list_num_groups--; - continue; - } - - auto curr_num_guests = _window_guest_list_groups_num_guests[groupIndex]; - int32_t swap_position = 0; - // This section places the groups in size order. - bool gotoNextPeep = false; - while (1) - { - if (swap_position >= groupIndex) + // Find more peeps that belong to same group + for (auto peep2 : EntityList(EntityListId::Peep)) { - gotoNextPeep = true; + if (peep2->OutsideOfPark || !(peep2->flags & SPRITE_FLAGS_PEEP_VISIBLE)) + continue; + + // Get and check if in same group + auto arguments = GetArgumentsFromPeep(*peep2, _selectedView); + if (arguments != group.Arguments) + continue; + + // Assign guest + peep2->flags &= ~(SPRITE_FLAGS_PEEP_VISIBLE); + + // Add face sprite if there is room + if (group.NumGuests < std::size(group.Faces)) + { + group.Faces[group.NumGuests++] = get_peep_face_sprite_small(peep2) - SPR_PEEP_SMALL_FACE_VERY_VERY_UNHAPPY; + } + + group.NumGuests++; + } + + // Remove group if empty (basically guests with no thoughts) + if (group.Arguments.GetFirstStringId() == STR_EMPTY) + { + _groups.pop_back(); + continue; + } + } + + // Sort groups by number of guests + std::sort( + _groups.begin(), _groups.end(), [](const GuestGroup& a, const GuestGroup& b) { return a.NumGuests > b.NumGuests; }); + } + + /** + * Calculates a hash value (arguments) for comparing peep actions/thoughts + */ + static FilterArguments GetArgumentsFromPeep(const Peep& peep, GuestViewType type) + { + FilterArguments result; + Formatter ft(result.args); + switch (type) + { + case GuestViewType::Actions: + peep.FormatActionTo(ft); + break; + case GuestViewType::Thoughts: + { + const auto& thought = peep.Thoughts[0]; + if (thought.type != PeepThoughtType::None && thought.freshness <= 5) + { + peep_thought_set_format_args(&thought, ft); + } break; } - if (curr_num_guests > _window_guest_list_groups_num_guests[swap_position]) - break; - swap_position++; } - if (gotoNextPeep) - { - continue; - } - - auto arguments12 = _window_guest_list_groups_arguments[groupIndex]; - auto bl = _window_guest_list_group_index[groupIndex]; - - do - { - std::swap(curr_num_guests, _window_guest_list_groups_num_guests[swap_position]); - std::swap(arguments12, _window_guest_list_groups_arguments[swap_position]); - - uint8_t temp_faces[56]; - std::memcpy(temp_faces, &(_window_guest_list_groups_guest_faces[groupIndex * 56]), 56); - std::memcpy( - &(_window_guest_list_groups_guest_faces[groupIndex * 56]), - &(_window_guest_list_groups_guest_faces[swap_position * 56]), 56); - std::memcpy(&(_window_guest_list_groups_guest_faces[swap_position * 56]), temp_faces, 56); - - std::swap(bl, _window_guest_list_group_index[swap_position]); - } while (++swap_position <= groupIndex); + return result; } -} -static bool guest_should_be_visible(Peep* peep) -{ - if (_window_guest_list_tracking_only && !(peep->PeepFlags & PEEP_FLAGS_TRACKING)) - return false; - - if (_window_guest_list_filter_name[0] != '\0') + static constexpr rct_string_id GetViewName(GuestViewType type) { - char name[256]{}; - - Formatter ft; - peep->FormatNameTo(ft); - format_string(name, sizeof(name), STR_STRINGID, ft.Data()); - if (strcasestr(name, _window_guest_list_filter_name) == nullptr) + switch (type) { - return false; + default: + case GuestViewType::Actions: + return STR_ACTIONS; + case GuestViewType::Thoughts: + return STR_THOUGHTS; } } - return true; + static constexpr rct_string_id GetFilterString(GuestFilterType type) + { + switch (type) + { + default: + case GuestFilterType::Guests: + return STR_GUESTS_FILTER; + case GuestFilterType::GuestsThinking: + return STR_GUESTS_FILTER_THINKING; + case GuestFilterType::GuestsThinkingAbout: + return STR_GUESTS_FILTER_THINKING_ABOUT; + } + } + + template static bool CompareGuestItem(const GuestItem& a, const GuestItem& b) + { + const auto* peepA = GetEntity(a.Id); + const auto* peepB = GetEntity(b.Id); + if (peepA != nullptr && peepB != nullptr) + { + // Compare types + if (peepA->AssignedPeepType != peepB->AssignedPeepType) + { + return static_cast(peepA->AssignedPeepType) < static_cast(peepB->AssignedPeepType); + } + + // Compare name + if constexpr (!TRealNames) + { + if (peepA->Name == nullptr && peepB->Name == nullptr) + { + // Simple ID comparison for when both peeps use a number or a generated name + return peepA->Id < peepB->Id; + } + } + } + return strlogicalcmp(a.Name, b.Name) < 0; + } + + static GuestItem::CompareFunc GetGuestCompareFunc() + { + return gParkFlags & PARK_FLAGS_SHOW_REAL_GUEST_NAMES ? CompareGuestItem : CompareGuestItem; + } +}; + +rct_window* window_guest_list_open() +{ + auto* window = window_bring_to_front_by_class(WC_GUEST_LIST); + if (window == nullptr) + { + window = WindowCreate(WC_GUEST_LIST, 350, 330, WF_10 | WF_RESIZABLE); + } + return window; +} + +/** + * @param index The number of the ride or index of the thought + */ +rct_window* window_guest_list_open_with_filter(GuestListFilterType type, int32_t index) +{ + auto* w = static_cast(window_guest_list_open()); + if (w != nullptr) + { + w->SetFilter(type, index); + } + return w; +} + +void window_guest_list_refresh_list() +{ + auto* w = window_find_by_class(WC_GUEST_LIST); + if (w != nullptr) + { + static_cast(w)->RefreshList(); + } } diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 673aff2dff..d7c1a067ac 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -98,7 +98,6 @@ rct_window* window_player_open(uint8_t id); rct_window* window_new_campaign_open(int16_t campaignType); rct_window* window_install_track_open(const utf8* path); -void window_guest_list_init_vars(); void window_guest_list_refresh_list(); rct_window* window_guest_list_open(); rct_window* window_guest_list_open_with_filter(GuestListFilterType type, int32_t index); diff --git a/src/openrct2/interface/Window.cpp b/src/openrct2/interface/Window.cpp index e3545fae0d..e5d99854c7 100644 --- a/src/openrct2/interface/Window.cpp +++ b/src/openrct2/interface/Window.cpp @@ -1419,9 +1419,16 @@ void window_event_mouse_down_call(rct_window* w, rct_widgetindex widgetIndex) void window_event_dropdown_call(rct_window* w, rct_widgetindex widgetIndex, int32_t dropdownIndex) { if (w->event_handlers == nullptr) - w->OnDropdown(widgetIndex, dropdownIndex); + { + if (dropdownIndex != -1) + { + w->OnDropdown(widgetIndex, dropdownIndex); + } + } else if (w->event_handlers->dropdown != nullptr) + { w->event_handlers->dropdown(w, widgetIndex, dropdownIndex); + } } void window_event_unknown_05_call(rct_window* w) @@ -1497,16 +1504,26 @@ void window_event_unknown_0E_call(rct_window* w) void window_get_scroll_size(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height) { - if (w->event_handlers != nullptr) - if (w->event_handlers->get_scroll_size != nullptr) - w->event_handlers->get_scroll_size(w, scrollIndex, width, height); + if (w->event_handlers == nullptr) + { + auto size = w->OnScrollGetSize(scrollIndex); + if (width != nullptr) + *width = size.width; + if (height != nullptr) + *height = size.height; + } + else if (w->event_handlers->get_scroll_size != nullptr) + { + w->event_handlers->get_scroll_size(w, scrollIndex, width, height); + } } void window_event_scroll_mousedown_call(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) { - if (w->event_handlers != nullptr) - if (w->event_handlers->scroll_mousedown != nullptr) - w->event_handlers->scroll_mousedown(w, scrollIndex, screenCoords); + if (w->event_handlers == nullptr) + w->OnScrollMouseDown(scrollIndex, screenCoords); + else if (w->event_handlers->scroll_mousedown != nullptr) + w->event_handlers->scroll_mousedown(w, scrollIndex, screenCoords); } void window_event_scroll_mousedrag_call(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) @@ -1518,9 +1535,10 @@ void window_event_scroll_mousedrag_call(rct_window* w, int32_t scrollIndex, cons void window_event_scroll_mouseover_call(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) { - if (w->event_handlers != nullptr) - if (w->event_handlers->scroll_mouseover != nullptr) - w->event_handlers->scroll_mouseover(w, scrollIndex, screenCoords); + if (w->event_handlers == nullptr) + w->OnScrollMouseOver(scrollIndex, screenCoords); + else if (w->event_handlers->scroll_mouseover != nullptr) + w->event_handlers->scroll_mouseover(w, scrollIndex, screenCoords); } void window_event_textinput_call(rct_window* w, rct_widgetindex widgetIndex, char* text) @@ -1602,9 +1620,10 @@ void window_event_paint_call(rct_window* w, rct_drawpixelinfo* dpi) void window_event_scroll_paint_call(rct_window* w, rct_drawpixelinfo* dpi, int32_t scrollIndex) { - if (w->event_handlers != nullptr) - if (w->event_handlers->scroll_paint != nullptr) - w->event_handlers->scroll_paint(w, dpi, scrollIndex); + if (w->event_handlers == nullptr) + w->OnScrollDraw(scrollIndex, *dpi); + else if (w->event_handlers->scroll_paint != nullptr) + w->event_handlers->scroll_paint(w, dpi, scrollIndex); } /** diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 55db8ea851..f7996ceb51 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -364,7 +364,11 @@ enum WINDOW_FLAGS WF_WHITE_BORDER_ONE = (1 << 12), WF_WHITE_BORDER_MASK = (1 << 12) | (1 << 13), - WF_NO_SNAPPING = (1 << 15) + WF_NO_SNAPPING = (1 << 15), + + // Create only flags + WF_AUTO_POSITION = (1 << 16), + WF_CENTRE_SCREEN = (1 << 17), }; enum SCROLL_FLAGS @@ -673,21 +677,25 @@ void window_update_all(); void window_set_window_limit(int32_t value); rct_window* WindowCreate( - std::unique_ptr&& w, rct_windowclass cls, const ScreenCoordsXY& pos, int32_t width, int32_t height, - uint16_t flags); + std::unique_ptr&& w, rct_windowclass cls, ScreenCoordsXY pos, int32_t width, int32_t height, uint32_t flags); template::value>::type* = nullptr> -T* WindowCreate(rct_windowclass cls, const ScreenCoordsXY& pos, int32_t width, int32_t height, uint16_t flags = 0) +T* WindowCreate(rct_windowclass cls, const ScreenCoordsXY& pos, int32_t width, int32_t height, uint32_t flags = 0) { return static_cast(WindowCreate(std::make_unique(), cls, pos, width, height, flags)); } +template::value>::type* = nullptr> +T* WindowCreate(rct_windowclass cls, int32_t width, int32_t height, uint32_t flags = 0) +{ + return static_cast(WindowCreate(std::make_unique(), cls, {}, width, height, flags | WF_AUTO_POSITION)); +} rct_window* WindowCreate( const ScreenCoordsXY& pos, int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, - uint16_t flags); + uint32_t flags); rct_window* WindowCreateAutoPos( - int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint16_t flags); + int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint32_t flags); rct_window* WindowCreateCentred( - int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint16_t flags); + int32_t width, int32_t height, rct_window_event_list* event_handlers, rct_windowclass cls, uint32_t flags); void window_close(rct_window* window); void window_close_by_class(rct_windowclass cls); diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h index 479bf4e7e8..c16ac13584 100644 --- a/src/openrct2/interface/Window_internal.h +++ b/src/openrct2/interface/Window_internal.h @@ -119,6 +119,9 @@ struct rct_window virtual void OnClose() { } + virtual void OnResize() + { + } virtual void OnUpdate() { } @@ -144,6 +147,19 @@ struct rct_window virtual void OnTextInput(rct_widgetindex widgetIndex, std::string_view text) { } + virtual ScreenSize OnScrollGetSize(int32_t scrollIndex) + { + return {}; + } + virtual void OnScrollMouseOver(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnScrollMouseDown(int32_t scrollIndex, const ScreenCoordsXY& screenCoords) + { + } + virtual void OnScrollDraw(int32_t scrollIndex, rct_drawpixelinfo& dpi) + { + } }; #ifdef __WARN_SUGGEST_FINAL_METHODS__