Fix #14756: Invalidate nested focus before widget container is cleared. (#14809)

This commit is contained in:
Cyprian Klimaszewski
2025-12-06 18:52:44 +01:00
committed by dP
parent 8978e029cf
commit a8f0d5a3ad
6 changed files with 38 additions and 11 deletions

View File

@@ -1348,8 +1348,7 @@ struct BuildVehicleWindow : Window {
// CM calls this in constructor // CM calls this in constructor
// this->SetCargoFilterArray(); // this->SetCargoFilterArray();
auto container = this->GetWidget<NWidgetContainer>(WID_BV_BADGE_FILTER); this->badge_filters = AddBadgeDropdownFilters(this, WID_BV_BADGE_FILTER, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
this->badge_filters = AddBadgeDropdownFilters(*container, WID_BV_BADGE_FILTER, COLOUR_GREY, static_cast<GrfSpecFeature>(GSF_TRAINS + this->vehicle_type));
this->widget_lookup.clear(); this->widget_lookup.clear();
this->nested_root->FillWidgetLookup(this->widget_lookup); this->nested_root->FillWidgetLookup(this->widget_lookup);

View File

@@ -21,6 +21,7 @@
#include "strings_func.h" #include "strings_func.h"
#include "timer/timer_game_calendar.h" #include "timer/timer_game_calendar.h"
#include "window_gui.h" #include "window_gui.h"
#include "window_type.h"
#include "zoom_func.h" #include "zoom_func.h"
#include "table/strings.h" #include "table/strings.h"
@@ -550,15 +551,17 @@ DropDownList NWidgetBadgeFilter::GetDropDownList(PaletteID palette) const
/** /**
* Add badge drop down filter widgets. * 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 widget Widget index to apply to first filter.
* @param colour Background colour of widgets. * @param colour Background colour of widgets.
* @param feature GRF feature for filters. * @param feature GRF feature for filters.
* @return First and last widget indexes of filter widgets. * @return First and last widget indexes of filter widgets.
*/ */
std::pair<WidgetID, WidgetID> AddBadgeDropdownFilters(NWidgetContainer &container, WidgetID widget, Colours colour, GrfSpecFeature feature) std::pair<WidgetID, WidgetID> AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature)
{ {
container.Clear(); auto container = window->GetWidget<NWidgetContainer>(container_id);
container->Clear(window);
WidgetID first = ++widget; WidgetID first = ++widget;
/* Get list of classes used by feature. */ /* Get list of classes used by feature. */
@@ -568,7 +571,7 @@ std::pair<WidgetID, WidgetID> AddBadgeDropdownFilters(NWidgetContainer &containe
const auto [config, _] = GetBadgeClassConfigItem(feature, GetClassBadge(class_index)->label); const auto [config, _] = GetBadgeClassConfigItem(feature, GetClassBadge(class_index)->label);
if (!config.show_filter) continue; if (!config.show_filter) continue;
container.Add(std::make_unique<NWidgetBadgeFilter>(colour, widget, feature, class_index)); container->Add(std::make_unique<NWidgetBadgeFilter>(colour, widget, feature, class_index));
++widget; ++widget;
} }

View File

@@ -57,7 +57,7 @@ std::unique_ptr<DropDownListItem> MakeDropDownListBadgeIconItem(const std::share
DropDownList BuildBadgeClassConfigurationList(const class GUIBadgeClasses &badge_class, uint columns, std::span<const StringID> column_separators, Colours bg_colour); DropDownList BuildBadgeClassConfigurationList(const class GUIBadgeClasses &badge_class, uint columns, std::span<const StringID> column_separators, Colours bg_colour);
bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result, BadgeFilterChoices &choices); bool HandleBadgeConfigurationDropDownClick(GrfSpecFeature feature, uint columns, int result, int click_result, BadgeFilterChoices &choices);
std::pair<WidgetID, WidgetID> AddBadgeDropdownFilters(NWidgetContainer &container, WidgetID widget, Colours colour, GrfSpecFeature feature); std::pair<WidgetID, WidgetID> AddBadgeDropdownFilters(Window *window, WidgetID container_id, WidgetID widget, Colours colour, GrfSpecFeature feature);
class NWidgetBadgeFilter : public NWidgetLeaf { class NWidgetBadgeFilter : public NWidgetLeaf {
public: public:

View File

@@ -251,9 +251,7 @@ void PickerWindow::ConstructWindow()
void PickerWindow::OnInit() void PickerWindow::OnInit()
{ {
this->badge_classes = GUIBadgeClasses(this->callbacks.GetFeature()); this->badge_classes = GUIBadgeClasses(this->callbacks.GetFeature());
this->badge_filters = AddBadgeDropdownFilters(this, WID_PW_BADGE_FILTER, WID_PW_BADGE_FILTER, COLOUR_DARK_GREEN, this->callbacks.GetFeature());
auto container = this->GetWidget<NWidgetContainer>(WID_PW_BADGE_FILTER);
this->badge_filters = AddBadgeDropdownFilters(*container, WID_PW_BADGE_FILTER, COLOUR_DARK_GREEN, this->callbacks.GetFeature());
this->widget_lookup.clear(); this->widget_lookup.clear();
this->nested_root->FillWidgetLookup(this->widget_lookup); this->nested_root->FillWidgetLookup(this->widget_lookup);

View File

@@ -3562,3 +3562,20 @@ std::unique_ptr<NWidgetBase> MakeCompanyButtonRows(WidgetID widget_first, Widget
if (hor != nullptr) vert->Add(std::move(hor)); if (hor != nullptr) vert->Add(std::move(hor));
return vert; 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();
}
}
}
}

View File

@@ -504,7 +504,17 @@ public:
inline bool IsEmpty() { return this->children.empty(); } inline bool IsEmpty() { return this->children.empty(); }
NWidgetBase *GetWidgetOfType(WidgetType tp) override; 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: protected:
std::vector<std::unique_ptr<NWidgetBase>> children{}; ///< Child widgets in container. std::vector<std::unique_ptr<NWidgetBase>> children{}; ///< Child widgets in container.