Codechange: Use std::map to provide indexed widget access.

This removes the need to determine the biggest widget index and replaces C-style memory handling.
This commit is contained in:
Peter Nelson 2023-10-16 11:13:36 +01:00 committed by Peter Nelson
parent a12f426d69
commit b86182ab84
16 changed files with 147 additions and 209 deletions

View File

@ -107,11 +107,9 @@ struct GraphLegendWindow : Window {
/** /**
* Construct a vertical list of buttons, one for each company. * Construct a vertical list of buttons, one for each company.
* @param biggest_index Storage for collecting the biggest index used in the returned tree.
* @return Panel with company buttons. * @return Panel with company buttons.
* @post \c *biggest_index contains the largest used index in the tree.
*/ */
static NWidgetBase *MakeNWidgetCompanyLines(int *biggest_index) static NWidgetBase *MakeNWidgetCompanyLines()
{ {
NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE); NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE);
vert->SetPadding(2, 2, 2, 2); vert->SetPadding(2, 2, 2, 2);
@ -125,7 +123,6 @@ static NWidgetBase *MakeNWidgetCompanyLines(int *biggest_index)
panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP); panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP);
vert->Add(panel); vert->Add(panel);
} }
*biggest_index = WID_GL_LAST_COMPANY;
return vert; return vert;
} }
@ -1338,11 +1335,9 @@ CompanyID PerformanceRatingDetailWindow::company = INVALID_COMPANY;
/** /**
* Make a vertical list of panels for outputting score details. * Make a vertical list of panels for outputting score details.
* @param biggest_index Storage for collecting the biggest index used in the returned tree.
* @return Panel with performance details. * @return Panel with performance details.
* @post \c *biggest_index contains the largest used index in the tree.
*/ */
static NWidgetBase *MakePerformanceDetailPanels(int *biggest_index) static NWidgetBase *MakePerformanceDetailPanels()
{ {
const StringID performance_tips[] = { const StringID performance_tips[] = {
STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP, STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP,
@ -1366,14 +1361,13 @@ static NWidgetBase *MakePerformanceDetailPanels(int *biggest_index)
panel->SetDataTip(0x0, performance_tips[widnum - WID_PRD_SCORE_FIRST]); panel->SetDataTip(0x0, performance_tips[widnum - WID_PRD_SCORE_FIRST]);
vert->Add(panel); vert->Add(panel);
} }
*biggest_index = WID_PRD_SCORE_LAST;
return vert; return vert;
} }
/** Make a number of rows with buttons for each company for the performance rating detail window. */ /** Make a number of rows with buttons for each company for the performance rating detail window. */
NWidgetBase *MakeCompanyButtonRowsGraphGUI(int *biggest_index) NWidgetBase *MakeCompanyButtonRowsGraphGUI()
{ {
return MakeCompanyButtonRows(biggest_index, WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST, COLOUR_BROWN, 8, STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP); return MakeCompanyButtonRows(WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST, COLOUR_BROWN, 8, STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP);
} }
static const NWidgetPart _nested_performance_rating_detail_widgets[] = { static const NWidgetPart _nested_performance_rating_detail_widgets[] = {

View File

@ -454,12 +454,12 @@ void LinkGraphOverlay::SetCompanyMask(CompanyMask company_mask)
} }
/** Make a number of rows with buttons for each company for the linkgraph legend window. */ /** Make a number of rows with buttons for each company for the linkgraph legend window. */
NWidgetBase *MakeCompanyButtonRowsLinkGraphGUI(int *biggest_index) NWidgetBase *MakeCompanyButtonRowsLinkGraphGUI()
{ {
return MakeCompanyButtonRows(biggest_index, WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST, COLOUR_GREY, 3, STR_NULL); return MakeCompanyButtonRows(WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST, COLOUR_GREY, 3, STR_NULL);
} }
NWidgetBase *MakeSaturationLegendLinkGraphGUI(int *biggest_index) NWidgetBase *MakeSaturationLegendLinkGraphGUI()
{ {
NWidgetVertical *panel = new NWidgetVertical(NC_EQUALSIZE); NWidgetVertical *panel = new NWidgetVertical(NC_EQUALSIZE);
for (uint i = 0; i < lengthof(LinkGraphOverlay::LINK_COLOURS[0]); ++i) { for (uint i = 0; i < lengthof(LinkGraphOverlay::LINK_COLOURS[0]); ++i) {
@ -470,11 +470,10 @@ NWidgetBase *MakeSaturationLegendLinkGraphGUI(int *biggest_index)
wid->SetResize(0, 0); wid->SetResize(0, 0);
panel->Add(wid); panel->Add(wid);
} }
*biggest_index = WID_LGL_SATURATION_LAST;
return panel; return panel;
} }
NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index) NWidgetBase *MakeCargoesLegendLinkGraphGUI()
{ {
uint num_cargo = static_cast<uint>(_sorted_cargo_specs.size()); uint num_cargo = static_cast<uint>(_sorted_cargo_specs.size());
static const uint ENTRIES_PER_COL = 5; static const uint ENTRIES_PER_COL = 5;
@ -503,7 +502,6 @@ NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index)
} }
/* If there are no cargo specs defined, then col won't have been created so don't add it. */ /* If there are no cargo specs defined, then col won't have been created so don't add it. */
if (col != nullptr) panel->Add(col); if (col != nullptr) panel->Add(col);
*biggest_index = WID_LGL_CARGO_LAST;
return panel; return panel;
} }

View File

@ -855,9 +855,8 @@ GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = {
&NGameSearchFilter &NGameSearchFilter
}; };
static NWidgetBase *MakeResizableHeader(int *biggest_index) static NWidgetBase *MakeResizableHeader()
{ {
*biggest_index = std::max<int>(*biggest_index, WID_NG_INFO);
return new NWidgetServerListHeader(); return new NWidgetServerListHeader();
} }

View File

@ -1937,16 +1937,11 @@ static const NWidgetPart _nested_newgrf_infopanel_widgets[] = {
}; };
/** Construct nested container widget for managing the lists and the info panel of the NewGRF GUI. */ /** Construct nested container widget for managing the lists and the info panel of the NewGRF GUI. */
NWidgetBase* NewGRFDisplay(int *biggest_index) NWidgetBase* NewGRFDisplay()
{ {
NWidgetBase *avs = MakeNWidgets(std::begin(_nested_newgrf_availables_widgets), std::end(_nested_newgrf_availables_widgets), biggest_index, nullptr); NWidgetBase *avs = MakeNWidgets(std::begin(_nested_newgrf_availables_widgets), std::end(_nested_newgrf_availables_widgets), nullptr);
NWidgetBase *acs = MakeNWidgets(std::begin(_nested_newgrf_actives_widgets), std::end(_nested_newgrf_actives_widgets), nullptr);
int biggest2; NWidgetBase *inf = MakeNWidgets(std::begin(_nested_newgrf_infopanel_widgets), std::end(_nested_newgrf_infopanel_widgets), nullptr);
NWidgetBase *acs = MakeNWidgets(std::begin(_nested_newgrf_actives_widgets), std::end(_nested_newgrf_actives_widgets), &biggest2, nullptr);
*biggest_index = std::max(*biggest_index, biggest2);
NWidgetBase *inf = MakeNWidgets(std::begin(_nested_newgrf_infopanel_widgets), std::end(_nested_newgrf_infopanel_widgets), &biggest2, nullptr);
*biggest_index = std::max(*biggest_index, biggest2);
return new NWidgetNewGRFDisplay(avs, acs, inf); return new NWidgetNewGRFDisplay(avs, acs, inf);
} }

View File

@ -220,10 +220,9 @@ static const int KEY_PADDING = 6; // Vertical padding for remaining key rows
* @param widtype Widget type of the key. Must be either \c NWID_SPACER for an invisible key, or a \c WWT_* widget. * @param widtype Widget type of the key. Must be either \c NWID_SPACER for an invisible key, or a \c WWT_* widget.
* @param widnum Widget number of the key. * @param widnum Widget number of the key.
* @param widdata Data value of the key widget. * @param widdata Data value of the key widget.
* @param biggest_index Collected biggest widget index so far.
* @note Key width is measured in 1/2 keys to allow for 1/2 key shifting between rows. * @note Key width is measured in 1/2 keys to allow for 1/2 key shifting between rows.
*/ */
static void AddKey(NWidgetHorizontal *hor, int pad_y, int num_half, WidgetType widtype, int widnum, uint16_t widdata, int *biggest_index) static void AddKey(NWidgetHorizontal *hor, int pad_y, int num_half, WidgetType widtype, int widnum, uint16_t widdata)
{ {
int key_width = HALF_KEY_WIDTH + (INTER_KEY_SPACE + HALF_KEY_WIDTH) * (num_half - 1); int key_width = HALF_KEY_WIDTH + (INTER_KEY_SPACE + HALF_KEY_WIDTH) * (num_half - 1);
@ -243,80 +242,78 @@ static void AddKey(NWidgetHorizontal *hor, int pad_y, int num_half, WidgetType w
leaf->SetMinimalTextLines(1, pad_y, FS_NORMAL); leaf->SetMinimalTextLines(1, pad_y, FS_NORMAL);
hor->Add(leaf); hor->Add(leaf);
} }
*biggest_index = std::max(*biggest_index, widnum);
} }
/** Construct the top row keys (cancel, ok, backspace). */ /** Construct the top row keys (cancel, ok, backspace). */
static NWidgetBase *MakeTopKeys(int *biggest_index) static NWidgetBase *MakeTopKeys()
{ {
NWidgetHorizontal *hor = new NWidgetHorizontal(); NWidgetHorizontal *hor = new NWidgetHorizontal();
AddKey(hor, TOP_KEY_PADDING, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL, biggest_index); AddKey(hor, TOP_KEY_PADDING, 6 * 2, WWT_TEXTBTN, WID_OSK_CANCEL, STR_BUTTON_CANCEL);
AddKey(hor, TOP_KEY_PADDING, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK, biggest_index); AddKey(hor, TOP_KEY_PADDING, 6 * 2, WWT_TEXTBTN, WID_OSK_OK, STR_BUTTON_OK );
AddKey(hor, TOP_KEY_PADDING, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE, biggest_index); AddKey(hor, TOP_KEY_PADDING, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE);
return hor; return hor;
} }
/** Construct the row containing the digit keys. */ /** Construct the row containing the digit keys. */
static NWidgetBase *MakeNumberKeys(int *biggest_index) static NWidgetBase *MakeNumberKeys()
{ {
NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
for (int widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) { for (int widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) {
AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0);
} }
return hor; return hor;
} }
/** Construct the qwerty row keys. */ /** Construct the qwerty row keys. */
static NWidgetBase *MakeQwertyKeys(int *biggest_index) static NWidgetBase *MakeQwertyKeys()
{ {
NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
AddKey(hor, KEY_PADDING, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL, biggest_index); AddKey(hor, KEY_PADDING, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL);
for (int widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) { for (int widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) {
AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0);
} }
AddKey(hor, KEY_PADDING, 1, NWID_SPACER, 0, 0, biggest_index); AddKey(hor, KEY_PADDING, 1, NWID_SPACER, 0, 0);
return hor; return hor;
} }
/** Construct the asdfg row keys. */ /** Construct the asdfg row keys. */
static NWidgetBase *MakeAsdfgKeys(int *biggest_index) static NWidgetBase *MakeAsdfgKeys()
{ {
NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
AddKey(hor, KEY_PADDING, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS, biggest_index); AddKey(hor, KEY_PADDING, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS);
for (int widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) { for (int widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) {
AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0);
} }
return hor; return hor;
} }
/** Construct the zxcvb row keys. */ /** Construct the zxcvb row keys. */
static NWidgetBase *MakeZxcvbKeys(int *biggest_index) static NWidgetBase *MakeZxcvbKeys()
{ {
NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
AddKey(hor, KEY_PADDING, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT, biggest_index); AddKey(hor, KEY_PADDING, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT);
for (int widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) { for (int widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) {
AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0);
} }
AddKey(hor, KEY_PADDING, 1, NWID_SPACER, 0, 0, biggest_index); AddKey(hor, KEY_PADDING, 1, NWID_SPACER, 0, 0);
return hor; return hor;
} }
/** Construct the spacebar row keys. */ /** Construct the spacebar row keys. */
static NWidgetBase *MakeSpacebarKeys(int *biggest_index) static NWidgetBase *MakeSpacebarKeys()
{ {
NWidgetHorizontal *hor = new NWidgetHorizontal(); NWidgetHorizontal *hor = new NWidgetHorizontal();
AddKey(hor, KEY_PADDING, 8, NWID_SPACER, 0, 0, biggest_index); AddKey(hor, KEY_PADDING, 8, NWID_SPACER, 0, 0);
AddKey(hor, KEY_PADDING, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); AddKey(hor, KEY_PADDING, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY);
AddKey(hor, KEY_PADDING, 3, NWID_SPACER, 0, 0, biggest_index); AddKey(hor, KEY_PADDING, 3, NWID_SPACER, 0, 0);
AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT, biggest_index); AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT);
AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT, biggest_index); AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT);
return hor; return hor;
} }

View File

@ -1229,9 +1229,9 @@ struct ScriptDebugWindow : public Window {
}; };
/** Make a number of rows with buttons for each company for the Script debug window. */ /** Make a number of rows with buttons for each company for the Script debug window. */
NWidgetBase *MakeCompanyButtonRowsScriptDebug(int *biggest_index) NWidgetBase *MakeCompanyButtonRowsScriptDebug()
{ {
return MakeCompanyButtonRows(biggest_index, WID_SCRD_COMPANY_BUTTON_START, WID_SCRD_COMPANY_BUTTON_END, COLOUR_GREY, 8, STR_AI_DEBUG_SELECT_AI_TOOLTIP); return MakeCompanyButtonRows(WID_SCRD_COMPANY_BUTTON_START, WID_SCRD_COMPANY_BUTTON_END, COLOUR_GREY, 8, STR_AI_DEBUG_SELECT_AI_TOOLTIP);
} }
/** Widgets for the Script debug window. */ /** Widgets for the Script debug window. */

View File

@ -1942,12 +1942,12 @@ static const NWidgetPart _nested_smallmap_bar[] = {
EndContainer(), EndContainer(),
}; };
static NWidgetBase *SmallMapDisplay(int *biggest_index) static NWidgetBase *SmallMapDisplay()
{ {
NWidgetContainer *map_display = new NWidgetSmallmapDisplay; NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
MakeNWidgets(std::begin(_nested_smallmap_display), std::end(_nested_smallmap_display), biggest_index, map_display); MakeNWidgets(std::begin(_nested_smallmap_display), std::end(_nested_smallmap_display), map_display);
MakeNWidgets(std::begin(_nested_smallmap_bar), std::end(_nested_smallmap_bar), biggest_index, map_display); MakeNWidgets(std::begin(_nested_smallmap_bar), std::end(_nested_smallmap_bar), map_display);
return map_display; return map_display;
} }

View File

@ -714,10 +714,9 @@ const StringID CompanyStationsWindow::sorter_names[] = {
/** /**
* Make a horizontal row of cargo buttons, starting at widget #WID_STL_CARGOSTART. * Make a horizontal row of cargo buttons, starting at widget #WID_STL_CARGOSTART.
* @param biggest_index Pointer to store biggest used widget number of the buttons.
* @return Horizontal row. * @return Horizontal row.
*/ */
static NWidgetBase *CargoWidgets(int *biggest_index) static NWidgetBase *CargoWidgets()
{ {
NWidgetHorizontal *container = new NWidgetHorizontal(); NWidgetHorizontal *container = new NWidgetHorizontal();
@ -730,7 +729,6 @@ static NWidgetBase *CargoWidgets(int *biggest_index)
panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE); panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
container->Add(panel); container->Add(panel);
} }
*biggest_index = WID_STL_CARGOSTART + static_cast<int>(_sorted_standard_cargo_specs.size());
return container; return container;
} }

View File

@ -646,9 +646,9 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
void OnTimeout() override void OnTimeout() override
{ {
for (uint i = WID_ETT_START; i < this->nested_array_size; i++) { for (const auto &pair : this->widget_lookup) {
if (i == WID_ETT_BUTTONS_START) i = WID_ETT_BUTTONS_END; // skip the buttons if (pair.first < WID_ETT_START || (pair.first >= WID_ETT_BUTTONS_START && pair.first < WID_ETT_BUTTONS_END)) continue; // skip the buttons
this->RaiseWidgetWhenLowered(i); this->RaiseWidgetWhenLowered(pair.first);
} }
} }

View File

@ -89,11 +89,10 @@ TEST_CASE_METHOD(WindowDescTestsFixture, "WindowDesc - NWidgetPart validity")
INFO(fmt::format("{}:{}", window_desc->file, window_desc->line)); INFO(fmt::format("{}:{}", window_desc->file, window_desc->line));
int biggest_index = -1;
NWidgetStacked *shade_select = nullptr; NWidgetStacked *shade_select = nullptr;
NWidgetBase *root = nullptr; NWidgetBase *root = nullptr;
REQUIRE_NOTHROW(root = MakeWindowNWidgetTree(window_desc->nwid_begin, window_desc->nwid_end, &biggest_index, &shade_select)); REQUIRE_NOTHROW(root = MakeWindowNWidgetTree(window_desc->nwid_begin, window_desc->nwid_end, &shade_select));
CHECK((root != nullptr)); CHECK((root != nullptr));
delete root; delete root;
} }

View File

@ -2120,7 +2120,7 @@ struct MainToolbarWindow : Window {
}}; }};
}; };
static NWidgetBase *MakeMainToolbar(int *biggest_index) static NWidgetBase *MakeMainToolbar()
{ {
/** Sprites to use for the different toolbar buttons */ /** Sprites to use for the different toolbar buttons */
static const SpriteID toolbar_button_sprites[] = { static const SpriteID toolbar_button_sprites[] = {
@ -2174,7 +2174,6 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index)
hor->Add(leaf); hor->Add(leaf);
} }
*biggest_index = std::max<int>(*biggest_index, WID_TN_SWITCH_BAR);
return hor; return hor;
} }
@ -2513,9 +2512,9 @@ static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR), NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
}; };
static NWidgetBase *MakeScenarioToolbar(int *biggest_index) static NWidgetBase *MakeScenarioToolbar()
{ {
return MakeNWidgets(std::begin(_nested_toolb_scen_inner_widgets), std::end(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer()); return MakeNWidgets(std::begin(_nested_toolb_scen_inner_widgets), std::end(_nested_toolb_scen_inner_widgets), new NWidgetScenarioToolbarContainer());
} }
static const NWidgetPart _nested_toolb_scen_widgets[] = { static const NWidgetPart _nested_toolb_scen_widgets[] = {

View File

@ -256,7 +256,7 @@ public:
* get producing the correct result than dynamically building the widgets is. * get producing the correct result than dynamically building the widgets is.
* @see NWidgetFunctionType * @see NWidgetFunctionType
*/ */
static NWidgetBase *MakeTreeTypeButtons(int *biggest_index) static NWidgetBase *MakeTreeTypeButtons()
{ {
const byte type_base = _tree_base_by_landscape[_settings_game.game_creation.landscape]; const byte type_base = _tree_base_by_landscape[_settings_game.game_creation.landscape];
const byte type_count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; const byte type_count = _tree_count_by_landscape[_settings_game.game_creation.landscape];
@ -278,7 +278,6 @@ static NWidgetBase *MakeTreeTypeButtons(int *biggest_index)
NWidgetBackground *button = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_BUTTON_FIRST + cur_type); NWidgetBackground *button = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_BUTTON_FIRST + cur_type);
button->SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP); button->SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP);
hstack->Add(button); hstack->Add(button);
*biggest_index = WID_BT_TYPE_BUTTON_FIRST + cur_type;
cur_type++; cur_type++;
} }
} }

View File

@ -877,9 +877,9 @@ void Window::DrawWidgets() const
if (this->flags & WF_HIGHLIGHTED) { if (this->flags & WF_HIGHLIGHTED) {
extern bool _window_highlight_colour; extern bool _window_highlight_colour;
for (uint i = 0; i < this->nested_array_size; i++) { for (const auto &pair : this->widget_lookup) {
const NWidgetBase *widget = this->GetWidget<NWidgetBase>(i); const NWidgetBase *widget = pair.second;
if (widget == nullptr || !widget->IsHighlighted()) continue; if (!widget->IsHighlighted()) continue;
Rect outer = widget->GetCurrentRect(); Rect outer = widget->GetCurrentRect();
Rect inner = outer.Shrink(WidgetDimensions::scaled.bevel).Expand(1); Rect inner = outer.Shrink(WidgetDimensions::scaled.bevel).Expand(1);
@ -903,7 +903,7 @@ void Window::DrawSortButtonState(int widget, SortButtonState state) const
{ {
if (state == SBS_OFF) return; if (state == SBS_OFF) return;
assert(this->widget_lookup != nullptr); assert(!this->widget_lookup.empty());
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect(); Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect();
/* Sort button uses the same sprites as vertical scrollbar */ /* Sort button uses the same sprites as vertical scrollbar */
@ -1023,10 +1023,9 @@ NWidgetBase::NWidgetBase(WidgetType tp) : ZeroedMemoryAllocator()
*/ */
/** /**
* @fn void NWidgetBase::FillWidgetLookup(NWidgetBase **widget_lookup, uint length) * @fn void NWidgetBase::FillWidgetLookup(WidgetLookup &widget_lookup)
* Fill the Window::widget_lookup array with pointers to nested widgets in the tree. * Fill the Window::widget_lookup with pointers to nested widgets in the tree.
* @param array Base pointer of the array. * @param widget_lookup The WidgetLookup.
* @param length Length of the array.
*/ */
/** /**
@ -1276,9 +1275,9 @@ void NWidgetCore::SetAlignment(StringAlignment align)
this->align = align; this->align = align;
} }
void NWidgetCore::FillWidgetLookup(NWidgetBase **widget_lookup, uint length) void NWidgetCore::FillWidgetLookup(WidgetLookup &widget_lookup)
{ {
if (this->index >= 0 && (uint)(this->index) < length) widget_lookup[this->index] = this; if (this->index >= 0) widget_lookup[this->index] = this;
} }
NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y) NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y)
@ -1345,10 +1344,10 @@ void NWidgetContainer::Add(NWidgetBase *wid)
} }
} }
void NWidgetContainer::FillWidgetLookup(NWidgetBase **widget_lookup, uint length) void NWidgetContainer::FillWidgetLookup(WidgetLookup &widget_lookup)
{ {
for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
child_wid->FillWidgetLookup(widget_lookup, length); child_wid->FillWidgetLookup(widget_lookup);
} }
} }
@ -1452,10 +1451,10 @@ void NWidgetStacked::AssignSizePosition(SizingType sizing, int x, int y, uint gi
} }
} }
void NWidgetStacked::FillWidgetLookup(NWidgetBase **widget_lookup, uint length) void NWidgetStacked::FillWidgetLookup(WidgetLookup &widget_lookup)
{ {
if (this->index >= 0 && (uint)(this->index) < length) widget_lookup[this->index] = this; if (this->index >= 0) widget_lookup[this->index] = this;
NWidgetContainer::FillWidgetLookup(widget_lookup, length); NWidgetContainer::FillWidgetLookup(widget_lookup);
} }
void NWidgetStacked::Draw(const Window *w) void NWidgetStacked::Draw(const Window *w)
@ -1564,7 +1563,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w)
this->resize_y = 1; // smallest common child resize step. this->resize_y = 1; // smallest common child resize step.
this->gaps = 0; this->gaps = 0;
/* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ /* 1a. Forward call, collect longest/widest child length. */
uint longest = 0; // Longest child found. uint longest = 0; // Longest child found.
uint max_vert_fill = 0; // Biggest vertical fill step. uint max_vert_fill = 0; // Biggest vertical fill step.
for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
@ -1756,7 +1755,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w)
this->resize_y = 0; // smallest non-zero child widget resize step. this->resize_y = 0; // smallest non-zero child widget resize step.
this->gaps = 0; this->gaps = 0;
/* 1a. Forward call, collect biggest nested array index, and longest/widest child length. */ /* 1a. Forward call, collect longest/widest child length. */
uint highest = 0; // Highest child found. uint highest = 0; // Highest child found.
uint max_hor_fill = 0; // Biggest horizontal fill step. uint max_hor_fill = 0; // Biggest horizontal fill step.
for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
@ -1925,7 +1924,7 @@ void NWidgetSpacer::SetupSmallestSize(Window *)
this->smallest_y = this->min_y; this->smallest_y = this->min_y;
} }
void NWidgetSpacer::FillWidgetLookup(NWidgetBase **, uint) void NWidgetSpacer::FillWidgetLookup(WidgetLookup &)
{ {
} }
@ -2065,10 +2064,10 @@ void NWidgetMatrix::AssignSizePosition(SizingType, int x, int y, uint given_widt
this->SetCount(this->count); this->SetCount(this->count);
} }
void NWidgetMatrix::FillWidgetLookup(NWidgetBase **widget_lookup, uint length) void NWidgetMatrix::FillWidgetLookup(WidgetLookup &widget_lookup)
{ {
if (this->index >= 0 && (uint)(this->index) < length) widget_lookup[this->index] = this; if (this->index >= 0) widget_lookup[this->index] = this;
NWidgetContainer::FillWidgetLookup(widget_lookup, length); NWidgetContainer::FillWidgetLookup(widget_lookup);
} }
NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y)
@ -2185,7 +2184,7 @@ void NWidgetMatrix::GetScrollOffsets(int &start_x, int &start_y, int &base_offs_
* Constructor parent nested widgets. * Constructor parent nested widgets.
* @param tp Type of parent widget. * @param tp Type of parent widget.
* @param colour Colour of the parent widget. * @param colour Colour of the parent widget.
* @param index Index in the widget array used by the window system. * @param index Index of the widget.
* @param child Child container widget (if supplied). If not supplied, a * @param child Child container widget (if supplied). If not supplied, a
* vertical container will be inserted while adding the first * vertical container will be inserted while adding the first
* child widget. * child widget.
@ -2335,10 +2334,10 @@ void NWidgetBackground::AssignSizePosition(SizingType sizing, int x, int y, uint
} }
} }
void NWidgetBackground::FillWidgetLookup(NWidgetBase **widget_lookup, uint length) void NWidgetBackground::FillWidgetLookup(WidgetLookup &widget_lookup)
{ {
if (this->index >= 0 && (uint)(this->index) < length) widget_lookup[this->index] = this; if (this->index >= 0) widget_lookup[this->index] = this;
if (this->child != nullptr) this->child->FillWidgetLookup(widget_lookup, length); if (this->child != nullptr) this->child->FillWidgetLookup(widget_lookup);
} }
void NWidgetBackground::Draw(const Window *w) void NWidgetBackground::Draw(const Window *w)
@ -2556,7 +2555,7 @@ void Scrollbar::SetCapacityFromWidget(Window *w, int widget, int padding)
* Scrollbar widget. * Scrollbar widget.
* @param tp Scrollbar type. (horizontal/vertical) * @param tp Scrollbar type. (horizontal/vertical)
* @param colour Colour of the scrollbar. * @param colour Colour of the scrollbar.
* @param index Index in the widget array used by the window system. * @param index Index of the widget.
*/ */
NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR) NWidgetScrollbar::NWidgetScrollbar(WidgetType tp, Colours colour, int index) : NWidgetCore(tp, colour, 1, 1, 0x0, STR_NULL), Scrollbar(tp != NWID_HSCROLLBAR)
{ {
@ -2680,7 +2679,7 @@ Dimension NWidgetLeaf::dropdown_dimension = {0, 0};
* Nested leaf widget. * Nested leaf widget.
* @param tp Type of leaf widget. * @param tp Type of leaf widget.
* @param colour Colour of the leaf widget. * @param colour Colour of the leaf widget.
* @param index Index in the widget array used by the window system. * @param index Index of the widget.
* @param data Data of the widget. * @param data Data of the widget.
* @param tip Tooltip of the widget. * @param tip Tooltip of the widget.
*/ */
@ -3110,11 +3109,9 @@ bool NWidgetLeaf::ButtonHit(const Point &pt)
* @param nwid_end Pointer to ending of nested widget parts. * @param nwid_end Pointer to ending of nested widget parts.
* @param dest Address of pointer to use for returning the composed widget. * @param dest Address of pointer to use for returning the composed widget.
* @param fill_dest Fill the composed widget with child widgets. * @param fill_dest Fill the composed widget with child widgets.
* @param biggest_index Pointer to biggest nested widget index in the tree encountered so far.
* @return Pointer to remaining nested widget parts. * @return Pointer to remaining nested widget parts.
* @pre \c biggest_index != nullptr.
*/ */
static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetBase **dest, bool *fill_dest, int *biggest_index) static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetBase **dest, bool *fill_dest)
{ {
*dest = nullptr; *dest = nullptr;
*fill_dest = false; *fill_dest = false;
@ -3143,7 +3140,6 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
case WWT_FRAME: case WWT_FRAME:
if (*dest != nullptr) return nwid_begin; if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetBackground(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index); *dest = new NWidgetBackground(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index);
*biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index);
*fill_dest = true; *fill_dest = true;
break; break;
@ -3160,16 +3156,12 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
*fill_dest = true; *fill_dest = true;
nwm->SetIndex(nwid_begin->u.widget.index); nwm->SetIndex(nwid_begin->u.widget.index);
nwm->SetColour(nwid_begin->u.widget.colour); nwm->SetColour(nwid_begin->u.widget.colour);
*biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index);
break; break;
} }
case WPT_FUNCTION: { case WPT_FUNCTION: {
if (*dest != nullptr) return nwid_begin; if (*dest != nullptr) return nwid_begin;
/* Ensure proper functioning even when the called code simply writes its largest index. */ *dest = nwid_begin->u.func_ptr();
int biggest = -1;
*dest = nwid_begin->u.func_ptr(&biggest);
*biggest_index = std::max(*biggest_index, biggest);
*fill_dest = false; *fill_dest = false;
break; break;
} }
@ -3267,14 +3259,12 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
case NWID_VIEWPORT: case NWID_VIEWPORT:
if (*dest != nullptr) return nwid_begin; if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetViewport(nwid_begin->u.widget.index); *dest = new NWidgetViewport(nwid_begin->u.widget.index);
*biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index);
break; break;
case NWID_HSCROLLBAR: case NWID_HSCROLLBAR:
case NWID_VSCROLLBAR: case NWID_VSCROLLBAR:
if (*dest != nullptr) return nwid_begin; if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetScrollbar(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index); *dest = new NWidgetScrollbar(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index);
*biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index);
break; break;
case NWID_SELECTION: { case NWID_SELECTION: {
@ -3283,7 +3273,6 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
*dest = nws; *dest = nws;
*fill_dest = true; *fill_dest = true;
nws->SetIndex(nwid_begin->u.widget.index); nws->SetIndex(nwid_begin->u.widget.index);
*biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index);
break; break;
} }
@ -3291,7 +3280,6 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
if (*dest != nullptr) return nwid_begin; if (*dest != nullptr) return nwid_begin;
assert((nwid_begin->type & WWT_MASK) < WWT_LAST || (nwid_begin->type & WWT_MASK) == NWID_BUTTON_DROPDOWN); assert((nwid_begin->type & WWT_MASK) < WWT_LAST || (nwid_begin->type & WWT_MASK) == NWID_BUTTON_DROPDOWN);
*dest = new NWidgetLeaf(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index, 0x0, STR_NULL); *dest = new NWidgetLeaf(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index, 0x0, STR_NULL);
*biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index);
break; break;
} }
nwid_begin++; nwid_begin++;
@ -3316,11 +3304,9 @@ bool IsContainerWidgetType(WidgetType tp)
* @param nwid_begin Pointer to beginning of nested widget parts. * @param nwid_begin Pointer to beginning of nested widget parts.
* @param nwid_end Pointer to ending of nested widget parts. * @param nwid_end Pointer to ending of nested widget parts.
* @param parent Pointer or container to use for storing the child widgets (*parent == nullptr or *parent == container or background widget). * @param parent Pointer or container to use for storing the child widgets (*parent == nullptr or *parent == container or background widget).
* @param biggest_index Pointer to biggest nested widget index in the tree.
* @return Pointer to remaining nested widget parts. * @return Pointer to remaining nested widget parts.
* @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used.
*/ */
static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetBase **parent, int *biggest_index) static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetBase **parent)
{ {
/* If *parent == nullptr, only the first widget is read and returned. Otherwise, *parent must point to either /* If *parent == nullptr, only the first widget is read and returned. Otherwise, *parent must point to either
* a #NWidgetContainer or a #NWidgetBackground object, and parts are added as much as possible. */ * a #NWidgetContainer or a #NWidgetBackground object, and parts are added as much as possible. */
@ -3331,7 +3317,7 @@ static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NW
for (;;) { for (;;) {
NWidgetBase *sub_widget = nullptr; NWidgetBase *sub_widget = nullptr;
bool fill_sub = false; bool fill_sub = false;
nwid_begin = MakeNWidget(nwid_begin, nwid_end, &sub_widget, &fill_sub, biggest_index); nwid_begin = MakeNWidget(nwid_begin, nwid_end, &sub_widget, &fill_sub);
/* Break out of loop when end reached */ /* Break out of loop when end reached */
if (sub_widget == nullptr) break; if (sub_widget == nullptr) break;
@ -3339,7 +3325,7 @@ static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NW
/* If sub-widget is a container, recursively fill that container. */ /* If sub-widget is a container, recursively fill that container. */
if (fill_sub && IsContainerWidgetType(sub_widget->type)) { if (fill_sub && IsContainerWidgetType(sub_widget->type)) {
NWidgetBase *sub_ptr = sub_widget; NWidgetBase *sub_ptr = sub_widget;
nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &sub_ptr, biggest_index); nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &sub_ptr);
} }
/* Add sub_widget to parent container if available, otherwise return the widget to the caller. */ /* Add sub_widget to parent container if available, otherwise return the widget to the caller. */
@ -3362,19 +3348,15 @@ static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NW
* Construct a nested widget tree from an array of parts. * Construct a nested widget tree from an array of parts.
* @param nwid_begin Pointer to beginning of nested widget parts. * @param nwid_begin Pointer to beginning of nested widget parts.
* @param nwid_end Pointer to ending of nested widget parts. * @param nwid_end Pointer to ending of nested widget parts.
* @param biggest_index Pointer to biggest nested widget index collected in the tree.
* @param container Container to add the nested widgets to. In case it is nullptr a vertical container is used. * @param container Container to add the nested widgets to. In case it is nullptr a vertical container is used.
* @return Root of the nested widget tree, a vertical container containing the entire GUI. * @return Root of the nested widget tree, a vertical container containing the entire GUI.
* @ingroup NestedWidgetParts * @ingroup NestedWidgetParts
* @pre \c biggest_index != nullptr
* @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used.
*/ */
NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetContainer *container) NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetContainer *container)
{ {
*biggest_index = -1;
if (container == nullptr) container = new NWidgetVertical(); if (container == nullptr) container = new NWidgetVertical();
NWidgetBase *cont_ptr = container; NWidgetBase *cont_ptr = container;
[[maybe_unused]] const NWidgetPart *nwid_part = MakeWidgetTree(nwid_begin, nwid_end, &cont_ptr, biggest_index); [[maybe_unused]] const NWidgetPart *nwid_part = MakeWidgetTree(nwid_begin, nwid_end, &cont_ptr);
#ifdef WITH_ASSERT #ifdef WITH_ASSERT
if (unlikely(nwid_part != nwid_end)) throw std::runtime_error("Did not consume all NWidgetParts"); if (unlikely(nwid_part != nwid_end)) throw std::runtime_error("Did not consume all NWidgetParts");
#endif #endif
@ -3387,20 +3369,15 @@ NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart
* container with a caption widget) and has a shade box widget. * container with a caption widget) and has a shade box widget.
* @param nwid_begin Pointer to beginning of nested widget parts. * @param nwid_begin Pointer to beginning of nested widget parts.
* @param nwid_end Pointer to ending of nested widget parts. * @param nwid_end Pointer to ending of nested widget parts.
* @param biggest_index Pointer to biggest nested widget index collected in the tree.
* @param[out] shade_select Pointer to the inserted shade selection widget (\c nullptr if not unserted). * @param[out] shade_select Pointer to the inserted shade selection widget (\c nullptr if not unserted).
* @return Root of the nested widget tree, a vertical container containing the entire GUI. * @return Root of the nested widget tree, a vertical container containing the entire GUI.
* @ingroup NestedWidgetParts * @ingroup NestedWidgetParts
* @pre \c biggest_index != nullptr
* @post \c *biggest_index contains the largest widget index of the tree and \c -1 if no index is used.
*/ */
NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetStacked **shade_select) NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetStacked **shade_select)
{ {
*biggest_index = -1;
/* Read the first widget recursively from the array. */ /* Read the first widget recursively from the array. */
NWidgetBase *nwid = nullptr; NWidgetBase *nwid = nullptr;
nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &nwid, biggest_index); nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &nwid);
assert(nwid != nullptr); assert(nwid != nullptr);
NWidgetContainer *root = new NWidgetVertical; NWidgetContainer *root = new NWidgetVertical;
@ -3425,25 +3402,21 @@ NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWi
} }
/* Load the remaining parts into 'body'. */ /* Load the remaining parts into 'body'. */
int biggest2 = -1; MakeNWidgets(nwid_begin, nwid_end, body);
MakeNWidgets(nwid_begin, nwid_end, &biggest2, body);
*biggest_index = std::max(*biggest_index, biggest2);
return root; return root;
} }
/** /**
* Make a number of rows with button-like graphics, for enabling/disabling each company. * Make a number of rows with button-like graphics, for enabling/disabling each company.
* @param biggest_index Storage for collecting the biggest index used in the returned tree.
* @param widget_first The first widget index to use. * @param widget_first The first widget index to use.
* @param widget_last The last widget index to use. * @param widget_last The last widget index to use.
* @param colour The colour in which to draw the button. * @param colour The colour in which to draw the button.
* @param max_length Maximal number of company buttons in one row. * @param max_length Maximal number of company buttons in one row.
* @param button_tooltip The tooltip-string of every button. * @param button_tooltip The tooltip-string of every button.
* @return Panel with rows of company buttons. * @return Panel with rows of company buttons.
* @post \c *biggest_index contains the largest used index in the tree.
*/ */
NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, Colours button_colour, int max_length, StringID button_tooltip) NWidgetBase *MakeCompanyButtonRows(int widget_first, int widget_last, Colours button_colour, int max_length, StringID button_tooltip)
{ {
assert(max_length >= 1); assert(max_length >= 1);
NWidgetVertical *vert = nullptr; // Storage for all rows. NWidgetVertical *vert = nullptr; // Storage for all rows.
@ -3475,7 +3448,6 @@ NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int wid
hor->Add(panel); hor->Add(panel);
hor_length++; hor_length++;
} }
*biggest_index = widget_last;
if (vert == nullptr) return hor; // All buttons fit in a single row. if (vert == nullptr) return hor; // All buttons fit in a single row.
if (hor_length > 0 && hor_length < max_length) { if (hor_length > 0 && hor_length < max_length) {

View File

@ -47,7 +47,7 @@ enum ResizeWidgetValues {
*/ */
enum WidgetType { enum WidgetType {
/* Window widget types. */ /* Window widget types. */
WWT_EMPTY, ///< Empty widget, place holder to reserve space in widget array WWT_EMPTY, ///< Empty widget, place holder to reserve space in widget tree.
WWT_PANEL, ///< Simple depressed panel WWT_PANEL, ///< Simple depressed panel
WWT_INSET, ///< Pressed (inset) panel, most commonly used as combo box _text_ area WWT_INSET, ///< Pressed (inset) panel, most commonly used as combo box _text_ area
@ -122,6 +122,9 @@ enum SizingType {
class NWidgetCore; class NWidgetCore;
class Scrollbar; class Scrollbar;
/** Lookup between widget IDs and NWidget objects. */
using WidgetLookup = std::map<int, class NWidgetBase *>;
/** /**
* Baseclass for nested widgets. * Baseclass for nested widgets.
* @invariant After initialization, \f$current\_x = smallest\_x + n * resize\_x, for n \geq 0\f$. * @invariant After initialization, \f$current\_x = smallest\_x + n * resize\_x, for n \geq 0\f$.
@ -136,7 +139,7 @@ public:
virtual void SetupSmallestSize(Window *w) = 0; virtual void SetupSmallestSize(Window *w) = 0;
virtual void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) = 0; virtual void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) = 0;
virtual void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) = 0; virtual void FillWidgetLookup(WidgetLookup &widget_lookup) = 0;
virtual NWidgetCore *GetWidgetFromPos(int x, int y) = 0; virtual NWidgetCore *GetWidgetFromPos(int x, int y) = 0;
virtual NWidgetBase *GetWidgetOfType(WidgetType tp); virtual NWidgetBase *GetWidgetOfType(WidgetType tp);
@ -337,7 +340,7 @@ public:
inline void SetDisabled(bool disabled); inline void SetDisabled(bool disabled);
inline bool IsDisabled() const; inline bool IsDisabled() const;
void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) override; void FillWidgetLookup(WidgetLookup &widget_lookup) override;
NWidgetCore *GetWidgetFromPos(int x, int y) override; NWidgetCore *GetWidgetFromPos(int x, int y) override;
bool IsHighlighted() const override; bool IsHighlighted() const override;
TextColour GetHighlightColour() const override; TextColour GetHighlightColour() const override;
@ -345,7 +348,7 @@ public:
NWidgetDisplay disp_flags; ///< Flags that affect display and interaction with the widget. NWidgetDisplay disp_flags; ///< Flags that affect display and interaction with the widget.
Colours colour; ///< Colour of this widget. Colours colour; ///< Colour of this widget.
int index; ///< Index of the nested widget in the widget array of the window (\c -1 means 'not used'). int index; ///< Index of the nested widget (\c -1 means 'not used').
uint32_t widget_data; ///< Data of the widget. @see Widget::data uint32_t widget_data; ///< Data of the widget. @see Widget::data
StringID tool_tip; ///< Tooltip of the widget. @see Widget::tootips StringID tool_tip; ///< Tooltip of the widget. @see Widget::tootips
int scrollbar_index; ///< Index of an attached scrollbar. int scrollbar_index; ///< Index of an attached scrollbar.
@ -419,7 +422,7 @@ public:
void AdjustPaddingForZoom() override; void AdjustPaddingForZoom() override;
void Add(NWidgetBase *wid); void Add(NWidgetBase *wid);
void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) override; void FillWidgetLookup(WidgetLookup &widget_lookup) override;
void Draw(const Window *w) override; void Draw(const Window *w) override;
NWidgetCore *GetWidgetFromPos(int x, int y) override; NWidgetCore *GetWidgetFromPos(int x, int y) override;
@ -462,7 +465,7 @@ public:
void AdjustPaddingForZoom() override; void AdjustPaddingForZoom() override;
void SetupSmallestSize(Window *w) override; void SetupSmallestSize(Window *w) override;
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override;
void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) override; void FillWidgetLookup(WidgetLookup &widget_lookup) override;
void Draw(const Window *w) override; void Draw(const Window *w) override;
NWidgetCore *GetWidgetFromPos(int x, int y) override; NWidgetCore *GetWidgetFromPos(int x, int y) override;
@ -564,7 +567,7 @@ public:
void SetupSmallestSize(Window *w) override; void SetupSmallestSize(Window *w) override;
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override;
void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) override; void FillWidgetLookup(WidgetLookup &widget_lookup) override;
NWidgetCore *GetWidgetFromPos(int x, int y) override; NWidgetCore *GetWidgetFromPos(int x, int y) override;
void Draw(const Window *w) override; void Draw(const Window *w) override;
@ -593,7 +596,7 @@ public:
NWidgetSpacer(int width, int height); NWidgetSpacer(int width, int height);
void SetupSmallestSize(Window *w) override; void SetupSmallestSize(Window *w) override;
void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) override; void FillWidgetLookup(WidgetLookup &widget_lookup) override;
void Draw(const Window *w) override; void Draw(const Window *w) override;
void SetDirty(const Window *w) const override; void SetDirty(const Window *w) const override;
@ -617,7 +620,7 @@ public:
void SetupSmallestSize(Window *w) override; void SetupSmallestSize(Window *w) override;
void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override; void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override;
void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) override; void FillWidgetLookup(WidgetLookup &widget_lookup) override;
void Draw(const Window *w) override; void Draw(const Window *w) override;
NWidgetCore *GetWidgetFromPos(int x, int y) override; NWidgetCore *GetWidgetFromPos(int x, int y) override;
@ -955,7 +958,7 @@ struct NWidgetPartDataTip {
*/ */
struct NWidgetPartWidget { struct NWidgetPartWidget {
Colours colour; ///< Widget colour. Colours colour; ///< Widget colour.
int16_t index; ///< Widget index in the widget array. int16_t index; ///< Index of the widget.
}; };
/** /**
@ -1002,11 +1005,9 @@ struct NWidgetPartAlignment {
/** /**
* Pointer to function returning a nested widget. * Pointer to function returning a nested widget.
* @param biggest_index Pointer to storage for collecting the biggest index used in the nested widget.
* @return Nested widget (tree). * @return Nested widget (tree).
* @post \c *biggest_index must contain the value of the biggest index in the returned tree.
*/ */
typedef NWidgetBase *NWidgetFunctionType(int *biggest_index); typedef NWidgetBase *NWidgetFunctionType();
/** /**
* Partial widget specification to allow NWidgets to be written nested. * Partial widget specification to allow NWidgets to be written nested.
@ -1282,7 +1283,7 @@ static inline NWidgetPart SetScrollbar(int index)
* Widget part function for starting a new 'real' widget. * Widget part function for starting a new 'real' widget.
* @param tp Type of the new nested widget. * @param tp Type of the new nested widget.
* @param col Colour of the new widget. * @param col Colour of the new widget.
* @param idx Index of the widget in the widget array. * @param idx Index of the widget.
* @note with #WWT_PANEL, #WWT_FRAME, #WWT_INSET, a new container is started. * @note with #WWT_PANEL, #WWT_FRAME, #WWT_INSET, a new container is started.
* Child widgets must have a index bigger than the parent index. * Child widgets must have a index bigger than the parent index.
* @ingroup NestedWidgetParts * @ingroup NestedWidgetParts
@ -1330,10 +1331,10 @@ static inline NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
} }
bool IsContainerWidgetType(WidgetType tp); bool IsContainerWidgetType(WidgetType tp);
NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetContainer *container); NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetContainer *container);
NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetStacked **shade_select); NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetStacked **shade_select);
NWidgetBase *MakeCompanyButtonRows(int *biggest_index, int widget_first, int widget_last, Colours button_colour, int max_length, StringID button_tooltip); NWidgetBase *MakeCompanyButtonRows(int widget_first, int widget_last, Colours button_colour, int max_length, StringID button_tooltip);
void SetupWidgetDimensions(); void SetupWidgetDimensions();

View File

@ -224,10 +224,8 @@ int Window::GetRowFromWidget(int clickpos, int widget, int padding, int line_hei
*/ */
void Window::DisableAllWidgetHighlight() void Window::DisableAllWidgetHighlight()
{ {
for (uint i = 0; i < this->nested_array_size; i++) { for (auto &pair : this->widget_lookup) {
NWidgetBase *nwid = this->GetWidget<NWidgetBase>(i); NWidgetBase *nwid = pair.second;
if (nwid == nullptr) continue;
if (nwid->IsHighlighted()) { if (nwid->IsHighlighted()) {
nwid->SetHighlighted(TC_INVALID); nwid->SetHighlighted(TC_INVALID);
nwid->SetDirty(this); nwid->SetDirty(this);
@ -244,8 +242,6 @@ void Window::DisableAllWidgetHighlight()
*/ */
void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour) void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour)
{ {
assert(widget_index < this->nested_array_size);
NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index); NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
if (nwid == nullptr) return; if (nwid == nullptr) return;
@ -258,9 +254,8 @@ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour
} else { } else {
/* If we disable a highlight, check all widgets if anyone still has a highlight */ /* If we disable a highlight, check all widgets if anyone still has a highlight */
bool valid = false; bool valid = false;
for (uint i = 0; i < this->nested_array_size; i++) { for (const auto &pair : this->widget_lookup) {
nwid = this->GetWidget<NWidgetBase>(i); nwid = pair.second;
if (nwid == nullptr) continue;
if (!nwid->IsHighlighted()) continue; if (!nwid->IsHighlighted()) continue;
valid = true; valid = true;
@ -277,8 +272,6 @@ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour
*/ */
bool Window::IsWidgetHighlighted(byte widget_index) const bool Window::IsWidgetHighlighted(byte widget_index) const
{ {
assert(widget_index < this->nested_array_size);
const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index); const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(widget_index);
if (nwid == nullptr) return false; if (nwid == nullptr) return false;
@ -493,18 +486,19 @@ void Window::UnfocusFocusedWidget()
*/ */
bool Window::SetFocusedWidget(int widget_index) bool Window::SetFocusedWidget(int widget_index)
{ {
/* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ NWidgetCore *widget = this->GetWidget<NWidgetCore>(widget_index);
if ((uint)widget_index >= this->nested_array_size) return false; assert(widget != nullptr); /* Setting focus to a non-existing widget is a bad idea. */
assert(this->widget_lookup[widget_index] != nullptr); // Setting focus to a non-existing widget is a bad idea.
if (this->nested_focus != nullptr) { if (this->nested_focus != nullptr) {
if (this->GetWidget<NWidgetCore>(widget_index) == this->nested_focus) return false; /* Do nothing if widget_index is already focused. */
if (widget == this->nested_focus) return false;
/* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */ /* Repaint the widget that lost focus. A focused edit box may else leave the caret on the screen. */
this->nested_focus->SetDirty(this); this->nested_focus->SetDirty(this);
if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus();
} }
this->nested_focus = this->GetWidget<NWidgetCore>(widget_index);
this->nested_focus = widget;
if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxGainedFocus(); if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxGainedFocus();
return true; return true;
} }
@ -531,21 +525,23 @@ void Window::OnFocusLost(bool)
*/ */
void Window::RaiseButtons(bool autoraise) void Window::RaiseButtons(bool autoraise)
{ {
for (uint i = 0; i < this->nested_array_size; i++) { for (auto &pair : this->widget_lookup) {
if (this->widget_lookup[i] == nullptr) continue; WidgetType type = pair.second->type;
WidgetType type = this->widget_lookup[i]->type; NWidgetCore *wid = dynamic_cast<NWidgetCore *>(pair.second);
if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) &&
(!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && wid->IsLowered()) {
this->RaiseWidget(i); wid->SetLowered(false);
this->SetWidgetDirty(i); wid->SetDirty(this);
} }
} }
/* Special widgets without widget index */ /* Special widgets without widget index */
NWidgetCore *wid = this->nested_root != nullptr ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : nullptr; {
if (wid != nullptr) { NWidgetCore *wid = this->nested_root != nullptr ? dynamic_cast<NWidgetCore *>(this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX)) : nullptr;
wid->SetLowered(false); if (wid != nullptr) {
wid->SetDirty(this); wid->SetLowered(false);
wid->SetDirty(this);
}
} }
} }
@ -556,9 +552,10 @@ void Window::RaiseButtons(bool autoraise)
void Window::SetWidgetDirty(byte widget_index) const void Window::SetWidgetDirty(byte widget_index) const
{ {
/* Sometimes this function is called before the window is even fully initialized */ /* Sometimes this function is called before the window is even fully initialized */
if (this->widget_lookup == nullptr) return; auto it = this->widget_lookup.find(widget_index);
if (it == std::end(this->widget_lookup)) return;
this->widget_lookup[widget_index]->SetDirty(this); it->second->SetDirty(this);
} }
/** /**
@ -635,7 +632,7 @@ static void DispatchLeftClickEvent(Window *w, int x, int y, int click_count)
/* Clicked on a widget that is not disabled. /* Clicked on a widget that is not disabled.
* So unless the clicked widget is the caption bar, change focus to this widget. * So unless the clicked widget is the caption bar, change focus to this widget.
* Exception: In the OSK we always want the editbox to stay focused. */ * Exception: In the OSK we always want the editbox to stay focused. */
if (widget_type != WWT_CAPTION && w->window_class != WC_OSK) { if (widget_index >= 0 && widget_type != WWT_CAPTION && w->window_class != WC_OSK) {
/* focused_widget_changed is 'now' only true if the window this widget /* focused_widget_changed is 'now' only true if the window this widget
* is in gained focus. In that case it must remain true, also if the * is in gained focus. In that case it must remain true, also if the
* local widget focus did not change. As such it's the logical-or of * local widget focus did not change. As such it's the logical-or of
@ -1091,8 +1088,6 @@ Window::~Window()
assert(*this->z_position == nullptr); assert(*this->z_position == nullptr);
if (this->viewport != nullptr) DeleteWindowViewport(this); if (this->viewport != nullptr) DeleteWindowViewport(this);
free(this->widget_lookup); // Contents is released through deletion of #nested_root.
delete this->nested_root; delete this->nested_root;
} }
@ -1729,12 +1724,8 @@ static Point LocalGetWindowPlacement(const WindowDesc *desc, int16_t sm_width, i
*/ */
void Window::CreateNestedTree() void Window::CreateNestedTree()
{ {
int biggest_index = -1; this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_begin, this->window_desc->nwid_end, &this->shade_select);
this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_begin, this->window_desc->nwid_end, &biggest_index, &this->shade_select); this->nested_root->FillWidgetLookup(this->widget_lookup);
this->nested_array_size = (uint)(biggest_index + 1);
this->widget_lookup = CallocT<NWidgetBase *>(this->nested_array_size);
this->nested_root->FillWidgetLookup(this->widget_lookup, this->nested_array_size);
} }
/** /**
@ -1840,9 +1831,9 @@ static void DecreaseWindowCounters()
for (Window *w : Window::Iterate()) { for (Window *w : Window::Iterate()) {
if (_scroller_click_timeout == 0) { if (_scroller_click_timeout == 0) {
/* Unclick scrollbar buttons if they are pressed. */ /* Unclick scrollbar buttons if they are pressed. */
for (uint i = 0; i < w->nested_array_size; i++) { for (auto &pair : w->widget_lookup) {
NWidgetBase *nwid = w->widget_lookup[i]; NWidgetBase *nwid = pair.second;
if (nwid != nullptr && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { if (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR) {
NWidgetScrollbar *sb = static_cast<NWidgetScrollbar*>(nwid); NWidgetScrollbar *sb = static_cast<NWidgetScrollbar*>(nwid);
if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) {
sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN);
@ -3155,8 +3146,8 @@ void Window::ProcessHighlightedInvalidations()
{ {
if ((this->flags & WF_HIGHLIGHTED) == 0) return; if ((this->flags & WF_HIGHLIGHTED) == 0) return;
for (uint i = 0; i < this->nested_array_size; i++) { for (const auto &pair : this->widget_lookup) {
if (this->IsWidgetHighlighted(i)) this->SetWidgetDirty(i); if (pair.second->IsHighlighted()) pair.second->SetDirty(this);
} }
} }

View File

@ -260,8 +260,7 @@ public:
const NWidgetCore *nested_focus; ///< Currently focused nested widget, or \c nullptr if no nested widget has focus. const NWidgetCore *nested_focus; ///< Currently focused nested widget, or \c nullptr if no nested widget has focus.
std::map<int, QueryString*> querystrings; ///< QueryString associated to WWT_EDITBOX widgets. std::map<int, QueryString*> querystrings; ///< QueryString associated to WWT_EDITBOX widgets.
NWidgetBase *nested_root; ///< Root of the nested tree. NWidgetBase *nested_root; ///< Root of the nested tree.
NWidgetBase **widget_lookup; ///< Array of pointers into the tree. Do not access directly, use #Window::GetWidget() instead. WidgetLookup widget_lookup; ///< Indexed access to the nested widget tree. Do not access directly, use #Window::GetWidget() instead.
uint nested_array_size; ///< Size of the nested array.
NWidgetStacked *shade_select; ///< Selection widget (#NWID_SELECTION) to use for shading the window. If \c nullptr, window cannot shade. NWidgetStacked *shade_select; ///< Selection widget (#NWID_SELECTION) to use for shading the window. If \c nullptr, window cannot shade.
Dimension unshaded_size; ///< Last known unshaded size (only valid while shaded). Dimension unshaded_size; ///< Last known unshaded size (only valid while shaded).
@ -328,8 +327,7 @@ public:
*/ */
inline void SetWidgetDisabledState(byte widget_index, bool disab_stat) inline void SetWidgetDisabledState(byte widget_index, bool disab_stat)
{ {
assert(widget_index < this->nested_array_size); this->GetWidget<NWidgetCore>(widget_index)->SetDisabled(disab_stat);
if (this->widget_lookup[widget_index] != nullptr) this->GetWidget<NWidgetCore>(widget_index)->SetDisabled(disab_stat);
} }
/** /**
@ -357,7 +355,6 @@ public:
*/ */
inline bool IsWidgetDisabled(byte widget_index) const inline bool IsWidgetDisabled(byte widget_index) const
{ {
assert(widget_index < this->nested_array_size);
return this->GetWidget<NWidgetCore>(widget_index)->IsDisabled(); return this->GetWidget<NWidgetCore>(widget_index)->IsDisabled();
} }
@ -389,7 +386,6 @@ public:
*/ */
inline void SetWidgetLoweredState(byte widget_index, bool lowered_stat) inline void SetWidgetLoweredState(byte widget_index, bool lowered_stat)
{ {
assert(widget_index < this->nested_array_size);
this->GetWidget<NWidgetCore>(widget_index)->SetLowered(lowered_stat); this->GetWidget<NWidgetCore>(widget_index)->SetLowered(lowered_stat);
} }
@ -399,7 +395,6 @@ public:
*/ */
inline void ToggleWidgetLoweredState(byte widget_index) inline void ToggleWidgetLoweredState(byte widget_index)
{ {
assert(widget_index < this->nested_array_size);
bool lowered_state = this->GetWidget<NWidgetCore>(widget_index)->IsLowered(); bool lowered_state = this->GetWidget<NWidgetCore>(widget_index)->IsLowered();
this->GetWidget<NWidgetCore>(widget_index)->SetLowered(!lowered_state); this->GetWidget<NWidgetCore>(widget_index)->SetLowered(!lowered_state);
} }
@ -441,7 +436,6 @@ public:
*/ */
inline bool IsWidgetLowered(byte widget_index) const inline bool IsWidgetLowered(byte widget_index) const
{ {
assert(widget_index < this->nested_array_size);
return this->GetWidget<NWidgetCore>(widget_index)->IsLowered(); return this->GetWidget<NWidgetCore>(widget_index)->IsLowered();
} }
@ -894,8 +888,9 @@ inline bool AllEqual(It begin, It end, Pred pred)
template <class NWID> template <class NWID>
inline NWID *Window::GetWidget(uint widnum) inline NWID *Window::GetWidget(uint widnum)
{ {
if (widnum >= this->nested_array_size || this->widget_lookup[widnum] == nullptr) return nullptr; auto it = this->widget_lookup.find(widnum);
NWID *nwid = dynamic_cast<NWID *>(this->widget_lookup[widnum]); if (it == std::end(this->widget_lookup)) return nullptr;
NWID *nwid = dynamic_cast<NWID *>(it->second);
assert(nwid != nullptr); assert(nwid != nullptr);
return nwid; return nwid;
} }
@ -904,8 +899,9 @@ inline NWID *Window::GetWidget(uint widnum)
template <> template <>
inline const NWidgetBase *Window::GetWidget<NWidgetBase>(uint widnum) const inline const NWidgetBase *Window::GetWidget<NWidgetBase>(uint widnum) const
{ {
if (widnum >= this->nested_array_size) return nullptr; auto it = this->widget_lookup.find(widnum);
return this->widget_lookup[widnum]; if (it == std::end(this->widget_lookup)) return nullptr;
return it->second;
} }
/** /**