From abf8438a1bf433a3876e39a7530a250976416e7e Mon Sep 17 00:00:00 2001 From: Cyprian Klimaszewski <111280526+Rito13@users.noreply.github.com> Date: Sat, 6 Dec 2025 18:52:44 +0100 Subject: [PATCH] Fix #14756: Invalidate nested focus before widget container is cleared. (#14809) --- src/build_vehicle_gui.cpp | 3 +-- src/newgrf_badge_gui.cpp | 11 +++++++---- src/newgrf_badge_gui.h | 2 +- src/picker_gui.cpp | 4 +--- src/widget.cpp | 17 +++++++++++++++++ src/widget_type.h | 12 +++++++++++- 6 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/build_vehicle_gui.cpp b/src/build_vehicle_gui.cpp index d8912bc89c..00cc734ee1 100644 --- a/src/build_vehicle_gui.cpp +++ b/src/build_vehicle_gui.cpp @@ -1334,8 +1334,7 @@ struct BuildVehicleWindow : Window { this->badge_classes = GUIBadgeClasses(static_cast(GSF_TRAINS + this->vehicle_type)); this->SetCargoFilterArray(); - auto container = this->GetWidget(WID_BV_BADGE_FILTER); - this->badge_filters = AddBadgeDropdownFilters(*container, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast(GSF_TRAINS + this->vehicle_type)); + this->badge_filters = AddBadgeDropdownFilters(this, WID_BV_BADGE_FILTER, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast(GSF_TRAINS + this->vehicle_type)); this->widget_lookup.clear(); this->nested_root->FillWidgetLookup(this->widget_lookup); diff --git a/src/newgrf_badge_gui.cpp b/src/newgrf_badge_gui.cpp index c2d0dba8f2..f2cf6f45ca 100644 --- a/src/newgrf_badge_gui.cpp +++ b/src/newgrf_badge_gui.cpp @@ -21,6 +21,7 @@ #include "strings_func.h" #include "timer/timer_game_calendar.h" #include "window_gui.h" +#include "window_type.h" #include "zoom_func.h" #include "table/strings.h" @@ -550,15 +551,17 @@ DropDownList NWidgetBadgeFilter::GetDropDownList(PaletteID palette) const /** * Add badge drop down filter widgets. - * @param container Container widget to hold filter widgets. + * @param window Window that holds the container. + * @param container Container widget index to hold filter widgets. * @param widget Widget index to apply to first filter. * @param colour Background colour of widgets. * @param feature GRF feature for filters. * @return First and last widget indexes of filter widgets. */ -std::pair AddBadgeDropdownFilters(NWidgetContainer &container, WidgetID widget, Colours colour, GrfSpecFeature feature) +std::pair AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature) { - container.Clear(); + auto container = window->GetWidget(container_id); + container->Clear(window); WidgetID first = ++widget; /* Get list of classes used by feature. */ @@ -568,7 +571,7 @@ std::pair AddBadgeDropdownFilters(NWidgetContainer &containe const auto [config, _] = GetBadgeClassConfigItem(feature, GetClassBadge(class_index)->label); if (!config.show_filter) continue; - container.Add(std::make_unique(colour, widget, feature, class_index)); + container->Add(std::make_unique(colour, widget, feature, class_index)); ++widget; } diff --git a/src/newgrf_badge_gui.h b/src/newgrf_badge_gui.h index 868cdf86d6..2ac8ba66a2 100644 --- a/src/newgrf_badge_gui.h +++ b/src/newgrf_badge_gui.h @@ -57,7 +57,7 @@ std::unique_ptr MakeDropDownListBadgeIconItem(const std::share DropDownList BuildBadgeClassConfigurationList(const class GUIBadgeClasses &badge_class, uint columns, std::span column_separators, Colours bg_colour); bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result, BadgeFilterChoices &choices); -std::pair AddBadgeDropdownFilters(NWidgetContainer &container, WidgetID widget, Colours colour, GrfSpecFeature feature); +std::pair AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature); class NWidgetBadgeFilter : public NWidgetLeaf { public: diff --git a/src/picker_gui.cpp b/src/picker_gui.cpp index a594b7c37b..7a85be0d0a 100644 --- a/src/picker_gui.cpp +++ b/src/picker_gui.cpp @@ -251,9 +251,7 @@ void PickerWindow::ConstructWindow() void PickerWindow::OnInit() { this->badge_classes = GUIBadgeClasses(this->callbacks.GetFeature()); - - auto container = this->GetWidget(WID_PW_BADGE_FILTER); - this->badge_filters = AddBadgeDropdownFilters(*container, WID_PW_BADGE_FILTER, COLOUR_DARK_GREEN, this->callbacks.GetFeature()); + this->badge_filters = AddBadgeDropdownFilters(this, WID_PW_BADGE_FILTER, WID_PW_BADGE_FILTER, COLOUR_DARK_GREEN, this->callbacks.GetFeature()); this->widget_lookup.clear(); this->nested_root->FillWidgetLookup(this->widget_lookup); diff --git a/src/widget.cpp b/src/widget.cpp index b99da3d4bf..bb0c5d2a09 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -3476,3 +3476,20 @@ std::unique_ptr MakeCompanyButtonRows(WidgetID widget_first, Widget if (hor != nullptr) vert->Add(std::move(hor)); return vert; } + +/** + * Unfocuses the focused widget of the window, + * if the focused widget is contained inside the container. + * @param parent_window Window which contains this container. + */ +void NWidgetContainer::UnfocusWidgets(Window *parent_window) +{ + assert(parent_window != nullptr); + if (parent_window->nested_focus != nullptr) { + for (auto &widget : this->children) { + if (parent_window->nested_focus == widget.get()) { + parent_window->UnfocusFocusedWidget(); + } + } + } +} diff --git a/src/widget_type.h b/src/widget_type.h index 072d56365e..12deb5ff4e 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -484,7 +484,17 @@ public: inline bool IsEmpty() { return this->children.empty(); } NWidgetBase *GetWidgetOfType(WidgetType tp) override; - void Clear() { this->children.clear(); } + void UnfocusWidgets(Window *parent_window); + + /** + * Clears the container, deleting all widgets that were contained. + * @param parent_window Window that contains the container. + */ + inline void Clear(Window *parent_window) + { + this->UnfocusWidgets(parent_window); + this->children.clear(); + } protected: std::vector> children{}; ///< Child widgets in container.