# HG changeset patch # User Peter Nelson # Date 2023-10-16 10:13:36 # Node ID b17bd3a7c49f9a95aa243b875cb096ff39a4f3e8 # Parent 2ccb2f8f699f736f22e42937bc1049a423cb0178 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. diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -107,11 +107,9 @@ struct GraphLegendWindow : Window { /** * 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. - * @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); vert->SetPadding(2, 2, 2, 2); @@ -125,7 +123,6 @@ static NWidgetBase *MakeNWidgetCompanyLi panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP); vert->Add(panel); } - *biggest_index = WID_GL_LAST_COMPANY; return vert; } @@ -1338,11 +1335,9 @@ CompanyID PerformanceRatingDetailWindow: /** * 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. - * @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[] = { STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP, @@ -1366,14 +1361,13 @@ static NWidgetBase *MakePerformanceDetai panel->SetDataTip(0x0, performance_tips[widnum - WID_PRD_SCORE_FIRST]); vert->Add(panel); } - *biggest_index = WID_PRD_SCORE_LAST; return vert; } /** 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[] = { diff --git a/src/linkgraph/linkgraph_gui.cpp b/src/linkgraph/linkgraph_gui.cpp --- a/src/linkgraph/linkgraph_gui.cpp +++ b/src/linkgraph/linkgraph_gui.cpp @@ -454,12 +454,12 @@ void LinkGraphOverlay::SetCompanyMask(Co } /** 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); for (uint i = 0; i < lengthof(LinkGraphOverlay::LINK_COLOURS[0]); ++i) { @@ -470,11 +470,10 @@ NWidgetBase *MakeSaturationLegendLinkGra wid->SetResize(0, 0); panel->Add(wid); } - *biggest_index = WID_LGL_SATURATION_LAST; return panel; } -NWidgetBase *MakeCargoesLegendLinkGraphGUI(int *biggest_index) +NWidgetBase *MakeCargoesLegendLinkGraphGUI() { uint num_cargo = static_cast(_sorted_cargo_specs.size()); static const uint ENTRIES_PER_COL = 5; @@ -503,7 +502,6 @@ NWidgetBase *MakeCargoesLegendLinkGraphG } /* 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); - *biggest_index = WID_LGL_CARGO_LAST; return panel; } diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -855,9 +855,8 @@ GUIGameServerList::FilterFunction * cons &NGameSearchFilter }; -static NWidgetBase *MakeResizableHeader(int *biggest_index) +static NWidgetBase *MakeResizableHeader() { - *biggest_index = std::max(*biggest_index, WID_NG_INFO); return new NWidgetServerListHeader(); } diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -1937,16 +1937,11 @@ static const NWidgetPart _nested_newgrf_ }; /** 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); - - int biggest2; - 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); + 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); + NWidgetBase *inf = MakeNWidgets(std::begin(_nested_newgrf_infopanel_widgets), std::end(_nested_newgrf_infopanel_widgets), nullptr); return new NWidgetNewGRFDisplay(avs, acs, inf); } diff --git a/src/osk_gui.cpp b/src/osk_gui.cpp --- a/src/osk_gui.cpp +++ b/src/osk_gui.cpp @@ -220,10 +220,9 @@ static const int KEY_PADDING = 6; // * @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 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. */ -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); @@ -243,80 +242,78 @@ static void AddKey(NWidgetHorizontal *ho leaf->SetMinimalTextLines(1, pad_y, FS_NORMAL); hor->Add(leaf); } - - *biggest_index = std::max(*biggest_index, widnum); } /** Construct the top row keys (cancel, ok, backspace). */ -static NWidgetBase *MakeTopKeys(int *biggest_index) +static NWidgetBase *MakeTopKeys() { 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_OK, STR_BUTTON_OK, biggest_index); - AddKey(hor, TOP_KEY_PADDING, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE, 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 ); + AddKey(hor, TOP_KEY_PADDING, 2 * 2, WWT_PUSHIMGBTN, WID_OSK_BACKSPACE, SPR_OSK_BACKSPACE); return hor; } /** Construct the row containing the digit keys. */ -static NWidgetBase *MakeNumberKeys(int *biggest_index) +static NWidgetBase *MakeNumberKeys() { NWidgetHorizontal *hor = new NWidgetHorizontalLTR(); 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; } /** Construct the qwerty row keys. */ -static NWidgetBase *MakeQwertyKeys(int *biggest_index) +static NWidgetBase *MakeQwertyKeys() { 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++) { - 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; } /** Construct the asdfg row keys. */ -static NWidgetBase *MakeAsdfgKeys(int *biggest_index) +static NWidgetBase *MakeAsdfgKeys() { 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++) { - AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0, biggest_index); + AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0); } return hor; } /** Construct the zxcvb row keys. */ -static NWidgetBase *MakeZxcvbKeys(int *biggest_index) +static NWidgetBase *MakeZxcvbKeys() { 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++) { - 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; } /** Construct the spacebar row keys. */ -static NWidgetBase *MakeSpacebarKeys(int *biggest_index) +static NWidgetBase *MakeSpacebarKeys() { NWidgetHorizontal *hor = new NWidgetHorizontal(); - AddKey(hor, KEY_PADDING, 8, NWID_SPACER, 0, 0, biggest_index); - AddKey(hor, KEY_PADDING, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY, biggest_index); - AddKey(hor, KEY_PADDING, 3, NWID_SPACER, 0, 0, biggest_index); - AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_LEFT, SPR_OSK_LEFT, biggest_index); - AddKey(hor, KEY_PADDING, 2, WWT_PUSHIMGBTN, WID_OSK_RIGHT, SPR_OSK_RIGHT, biggest_index); + AddKey(hor, KEY_PADDING, 8, NWID_SPACER, 0, 0); + AddKey(hor, KEY_PADDING, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY); + AddKey(hor, KEY_PADDING, 3, NWID_SPACER, 0, 0); + 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); return hor; } diff --git a/src/script/script_gui.cpp b/src/script/script_gui.cpp --- a/src/script/script_gui.cpp +++ b/src/script/script_gui.cpp @@ -1229,9 +1229,9 @@ struct ScriptDebugWindow : public 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. */ diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1942,12 +1942,12 @@ static const NWidgetPart _nested_smallma EndContainer(), }; -static NWidgetBase *SmallMapDisplay(int *biggest_index) +static NWidgetBase *SmallMapDisplay() { 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_bar), std::end(_nested_smallmap_bar), 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), map_display); return map_display; } diff --git a/src/station_gui.cpp b/src/station_gui.cpp --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -714,10 +714,9 @@ const StringID CompanyStationsWindow::so /** * 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. */ -static NWidgetBase *CargoWidgets(int *biggest_index) +static NWidgetBase *CargoWidgets() { NWidgetHorizontal *container = new NWidgetHorizontal(); @@ -730,7 +729,6 @@ static NWidgetBase *CargoWidgets(int *bi panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE); container->Add(panel); } - *biggest_index = WID_STL_CARGOSTART + static_cast(_sorted_standard_cargo_specs.size()); return container; } diff --git a/src/terraform_gui.cpp b/src/terraform_gui.cpp --- a/src/terraform_gui.cpp +++ b/src/terraform_gui.cpp @@ -646,9 +646,9 @@ struct ScenarioEditorLandscapeGeneration void OnTimeout() override { - for (uint i = WID_ETT_START; i < this->nested_array_size; i++) { - if (i == WID_ETT_BUTTONS_START) i = WID_ETT_BUTTONS_END; // skip the buttons - this->RaiseWidgetWhenLowered(i); + for (const auto &pair : this->widget_lookup) { + if (pair.first < WID_ETT_START || (pair.first >= WID_ETT_BUTTONS_START && pair.first < WID_ETT_BUTTONS_END)) continue; // skip the buttons + this->RaiseWidgetWhenLowered(pair.first); } } diff --git a/src/tests/test_window_desc.cpp b/src/tests/test_window_desc.cpp --- a/src/tests/test_window_desc.cpp +++ b/src/tests/test_window_desc.cpp @@ -89,11 +89,10 @@ TEST_CASE_METHOD(WindowDescTestsFixture, INFO(fmt::format("{}:{}", window_desc->file, window_desc->line)); - int biggest_index = -1; NWidgetStacked *shade_select = 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)); delete root; } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -2120,7 +2120,7 @@ struct MainToolbarWindow : Window { }}; }; -static NWidgetBase *MakeMainToolbar(int *biggest_index) +static NWidgetBase *MakeMainToolbar() { /** Sprites to use for the different toolbar buttons */ static const SpriteID toolbar_button_sprites[] = { @@ -2174,7 +2174,6 @@ static NWidgetBase *MakeMainToolbar(int hor->Add(leaf); } - *biggest_index = std::max(*biggest_index, WID_TN_SWITCH_BAR); return hor; } @@ -2513,9 +2512,9 @@ static const NWidgetPart _nested_toolb_s 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[] = { diff --git a/src/tree_gui.cpp b/src/tree_gui.cpp --- a/src/tree_gui.cpp +++ b/src/tree_gui.cpp @@ -256,7 +256,7 @@ public: * get producing the correct result than dynamically building the widgets is. * @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_count = _tree_count_by_landscape[_settings_game.game_creation.landscape]; @@ -278,7 +278,6 @@ static NWidgetBase *MakeTreeTypeButtons( NWidgetBackground *button = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_BUTTON_FIRST + cur_type); button->SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP); hstack->Add(button); - *biggest_index = WID_BT_TYPE_BUTTON_FIRST + cur_type; cur_type++; } } diff --git a/src/widget.cpp b/src/widget.cpp --- a/src/widget.cpp +++ b/src/widget.cpp @@ -877,9 +877,9 @@ void Window::DrawWidgets() const if (this->flags & WF_HIGHLIGHTED) { extern bool _window_highlight_colour; - for (uint i = 0; i < this->nested_array_size; i++) { - const NWidgetBase *widget = this->GetWidget(i); - if (widget == nullptr || !widget->IsHighlighted()) continue; + for (const auto &pair : this->widget_lookup) { + const NWidgetBase *widget = pair.second; + if (!widget->IsHighlighted()) continue; Rect outer = widget->GetCurrentRect(); Rect inner = outer.Shrink(WidgetDimensions::scaled.bevel).Expand(1); @@ -903,7 +903,7 @@ void Window::DrawSortButtonState(int wid { if (state == SBS_OFF) return; - assert(this->widget_lookup != nullptr); + assert(!this->widget_lookup.empty()); Rect r = this->GetWidget(widget)->GetCurrentRect(); /* Sort button uses the same sprites as vertical scrollbar */ @@ -1023,10 +1023,9 @@ NWidgetBase::NWidgetBase(WidgetType tp) */ /** - * @fn void NWidgetBase::FillWidgetLookup(NWidgetBase **widget_lookup, uint length) - * Fill the Window::widget_lookup array with pointers to nested widgets in the tree. - * @param array Base pointer of the array. - * @param length Length of the array. + * @fn void NWidgetBase::FillWidgetLookup(WidgetLookup &widget_lookup) + * Fill the Window::widget_lookup with pointers to nested widgets in the tree. + * @param widget_lookup The WidgetLookup. */ /** @@ -1276,9 +1275,9 @@ void NWidgetCore::SetAlignment(StringAli 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) @@ -1345,10 +1344,10 @@ void NWidgetContainer::Add(NWidgetBase * } } -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) { - child_wid->FillWidgetLookup(widget_lookup, length); + child_wid->FillWidgetLookup(widget_lookup); } } @@ -1452,10 +1451,10 @@ void NWidgetStacked::AssignSizePosition( } } -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; - NWidgetContainer::FillWidgetLookup(widget_lookup, length); + if (this->index >= 0) widget_lookup[this->index] = this; + NWidgetContainer::FillWidgetLookup(widget_lookup); } void NWidgetStacked::Draw(const Window *w) @@ -1564,7 +1563,7 @@ void NWidgetHorizontal::SetupSmallestSiz this->resize_y = 1; // smallest common child resize step. 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 max_vert_fill = 0; // Biggest vertical fill step. for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { @@ -1756,7 +1755,7 @@ void NWidgetVertical::SetupSmallestSize( this->resize_y = 0; // smallest non-zero child widget resize step. 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 max_hor_fill = 0; // Biggest horizontal fill step. for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { @@ -1925,7 +1924,7 @@ void NWidgetSpacer::SetupSmallestSize(Wi this->smallest_y = this->min_y; } -void NWidgetSpacer::FillWidgetLookup(NWidgetBase **, uint) +void NWidgetSpacer::FillWidgetLookup(WidgetLookup &) { } @@ -2065,10 +2064,10 @@ void NWidgetMatrix::AssignSizePosition(S 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; - NWidgetContainer::FillWidgetLookup(widget_lookup, length); + if (this->index >= 0) widget_lookup[this->index] = this; + NWidgetContainer::FillWidgetLookup(widget_lookup); } NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) @@ -2185,7 +2184,7 @@ void NWidgetMatrix::GetScrollOffsets(int * Constructor parent nested widgets. * @param tp Type of 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 * vertical container will be inserted while adding the first * child widget. @@ -2335,10 +2334,10 @@ void NWidgetBackground::AssignSizePositi } } -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->child != nullptr) this->child->FillWidgetLookup(widget_lookup, length); + if (this->index >= 0) widget_lookup[this->index] = this; + if (this->child != nullptr) this->child->FillWidgetLookup(widget_lookup); } void NWidgetBackground::Draw(const Window *w) @@ -2556,7 +2555,7 @@ void Scrollbar::SetCapacityFromWidget(Wi * Scrollbar widget. * @param tp Scrollbar type. (horizontal/vertical) * @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) { @@ -2680,7 +2679,7 @@ Dimension NWidgetLeaf::dropdown_dimensio * Nested leaf widget. * @param tp Type of 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 tip Tooltip of the widget. */ @@ -3110,11 +3109,9 @@ bool NWidgetLeaf::ButtonHit(const Point * @param nwid_end Pointer to ending of nested widget parts. * @param dest Address of pointer to use for returning the composed widget. * @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. - * @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; *fill_dest = false; @@ -3143,7 +3140,6 @@ static const NWidgetPart *MakeNWidget(co case WWT_FRAME: if (*dest != nullptr) return nwid_begin; *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; break; @@ -3160,16 +3156,12 @@ static const NWidgetPart *MakeNWidget(co *fill_dest = true; nwm->SetIndex(nwid_begin->u.widget.index); nwm->SetColour(nwid_begin->u.widget.colour); - *biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index); break; } case WPT_FUNCTION: { if (*dest != nullptr) return nwid_begin; - /* Ensure proper functioning even when the called code simply writes its largest index. */ - int biggest = -1; - *dest = nwid_begin->u.func_ptr(&biggest); - *biggest_index = std::max(*biggest_index, biggest); + *dest = nwid_begin->u.func_ptr(); *fill_dest = false; break; } @@ -3267,14 +3259,12 @@ static const NWidgetPart *MakeNWidget(co case NWID_VIEWPORT: if (*dest != nullptr) return nwid_begin; *dest = new NWidgetViewport(nwid_begin->u.widget.index); - *biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index); break; case NWID_HSCROLLBAR: case NWID_VSCROLLBAR: if (*dest != nullptr) return nwid_begin; *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; case NWID_SELECTION: { @@ -3283,7 +3273,6 @@ static const NWidgetPart *MakeNWidget(co *dest = nws; *fill_dest = true; nws->SetIndex(nwid_begin->u.widget.index); - *biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index); break; } @@ -3291,7 +3280,6 @@ static const NWidgetPart *MakeNWidget(co if (*dest != nullptr) return nwid_begin; 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); - *biggest_index = std::max(*biggest_index, (int)nwid_begin->u.widget.index); break; } nwid_begin++; @@ -3316,11 +3304,9 @@ bool IsContainerWidgetType(WidgetType tp * @param nwid_begin Pointer to beginning 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 biggest_index Pointer to biggest nested widget index in the tree. * @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 * a #NWidgetContainer or a #NWidgetBackground object, and parts are added as much as possible. */ @@ -3331,7 +3317,7 @@ static const NWidgetPart *MakeWidgetTree for (;;) { NWidgetBase *sub_widget = nullptr; 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 */ if (sub_widget == nullptr) break; @@ -3339,7 +3325,7 @@ static const NWidgetPart *MakeWidgetTree /* If sub-widget is a container, recursively fill that container. */ if (fill_sub && IsContainerWidgetType(sub_widget->type)) { 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. */ @@ -3362,19 +3348,15 @@ static const NWidgetPart *MakeWidgetTree * Construct a nested widget tree from an array of parts. * @param nwid_begin Pointer to beginning 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. * @return Root of the nested widget tree, a vertical container containing the entire GUI. * @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(); 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 if (unlikely(nwid_part != nwid_end)) throw std::runtime_error("Did not consume all NWidgetParts"); #endif @@ -3387,20 +3369,15 @@ NWidgetContainer *MakeNWidgets(const NWi * container with a caption widget) and has a shade box widget. * @param nwid_begin Pointer to beginning 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). * @return Root of the nested widget tree, a vertical container containing the entire GUI. * @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. */ NWidgetBase *nwid = nullptr; - nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &nwid, biggest_index); + nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &nwid); assert(nwid != nullptr); NWidgetContainer *root = new NWidgetVertical; @@ -3425,25 +3402,21 @@ NWidgetContainer *MakeWindowNWidgetTree( } /* Load the remaining parts into 'body'. */ - int biggest2 = -1; - MakeNWidgets(nwid_begin, nwid_end, &biggest2, body); - - *biggest_index = std::max(*biggest_index, biggest2); + MakeNWidgets(nwid_begin, nwid_end, body); + return root; } /** * 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_last The last widget index to use. * @param colour The colour in which to draw the button. * @param max_length Maximal number of company buttons in one row. * @param button_tooltip The tooltip-string of every button. * @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); NWidgetVertical *vert = nullptr; // Storage for all rows. @@ -3475,7 +3448,6 @@ NWidgetBase *MakeCompanyButtonRows(int * hor->Add(panel); hor_length++; } - *biggest_index = widget_last; if (vert == nullptr) return hor; // All buttons fit in a single row. if (hor_length > 0 && hor_length < max_length) { diff --git a/src/widget_type.h b/src/widget_type.h --- a/src/widget_type.h +++ b/src/widget_type.h @@ -47,7 +47,7 @@ enum ResizeWidgetValues { */ enum WidgetType { /* 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_INSET, ///< Pressed (inset) panel, most commonly used as combo box _text_ area @@ -122,6 +122,9 @@ enum SizingType { class NWidgetCore; class Scrollbar; +/** Lookup between widget IDs and NWidget objects. */ +using WidgetLookup = std::map; + /** * Baseclass for nested widgets. * @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 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 NWidgetBase *GetWidgetOfType(WidgetType tp); @@ -337,7 +340,7 @@ public: inline void SetDisabled(bool disabled); 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; bool IsHighlighted() const override; TextColour GetHighlightColour() const override; @@ -345,7 +348,7 @@ public: NWidgetDisplay disp_flags; ///< Flags that affect display and interaction with the 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 StringID tool_tip; ///< Tooltip of the widget. @see Widget::tootips int scrollbar_index; ///< Index of an attached scrollbar. @@ -419,7 +422,7 @@ public: void AdjustPaddingForZoom() override; void Add(NWidgetBase *wid); - void FillWidgetLookup(NWidgetBase **widget_lookup, uint length) override; + void FillWidgetLookup(WidgetLookup &widget_lookup) override; void Draw(const Window *w) override; NWidgetCore *GetWidgetFromPos(int x, int y) override; @@ -462,7 +465,7 @@ public: void AdjustPaddingForZoom() override; void SetupSmallestSize(Window *w) 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; NWidgetCore *GetWidgetFromPos(int x, int y) override; @@ -564,7 +567,7 @@ public: void SetupSmallestSize(Window *w) 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; void Draw(const Window *w) override; @@ -593,7 +596,7 @@ public: NWidgetSpacer(int width, int height); 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 SetDirty(const Window *w) const override; @@ -617,7 +620,7 @@ public: void SetupSmallestSize(Window *w) 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; NWidgetCore *GetWidgetFromPos(int x, int y) override; @@ -955,7 +958,7 @@ struct NWidgetPartDataTip { */ struct NWidgetPartWidget { 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. - * @param biggest_index Pointer to storage for collecting the biggest index used in the nested widget. * @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. @@ -1282,7 +1283,7 @@ static inline NWidgetPart SetScrollbar(i * Widget part function for starting a new 'real' widget. * @param tp Type of the new nested 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. * Child widgets must have a index bigger than the parent index. * @ingroup NestedWidgetParts @@ -1330,10 +1331,10 @@ static inline NWidgetPart NWidgetFunctio } bool IsContainerWidgetType(WidgetType tp); -NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetContainer *container); -NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, int *biggest_index, NWidgetStacked **shade_select); +NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetContainer *container); +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(); diff --git a/src/window.cpp b/src/window.cpp --- a/src/window.cpp +++ b/src/window.cpp @@ -224,10 +224,8 @@ int Window::GetRowFromWidget(int clickpo */ void Window::DisableAllWidgetHighlight() { - for (uint i = 0; i < this->nested_array_size; i++) { - NWidgetBase *nwid = this->GetWidget(i); - if (nwid == nullptr) continue; - + for (auto &pair : this->widget_lookup) { + NWidgetBase *nwid = pair.second; if (nwid->IsHighlighted()) { nwid->SetHighlighted(TC_INVALID); nwid->SetDirty(this); @@ -244,8 +242,6 @@ void Window::DisableAllWidgetHighlight() */ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour) { - assert(widget_index < this->nested_array_size); - NWidgetBase *nwid = this->GetWidget(widget_index); if (nwid == nullptr) return; @@ -258,9 +254,8 @@ void Window::SetWidgetHighlight(byte wid } else { /* If we disable a highlight, check all widgets if anyone still has a highlight */ bool valid = false; - for (uint i = 0; i < this->nested_array_size; i++) { - nwid = this->GetWidget(i); - if (nwid == nullptr) continue; + for (const auto &pair : this->widget_lookup) { + nwid = pair.second; if (!nwid->IsHighlighted()) continue; valid = true; @@ -277,8 +272,6 @@ void Window::SetWidgetHighlight(byte wid */ bool Window::IsWidgetHighlighted(byte widget_index) const { - assert(widget_index < this->nested_array_size); - const NWidgetBase *nwid = this->GetWidget(widget_index); if (nwid == nullptr) return false; @@ -493,18 +486,19 @@ void Window::UnfocusFocusedWidget() */ bool Window::SetFocusedWidget(int widget_index) { - /* Do nothing if widget_index is already focused, or if it wasn't a valid widget. */ - if ((uint)widget_index >= this->nested_array_size) return false; - - assert(this->widget_lookup[widget_index] != nullptr); // Setting focus to a non-existing widget is a bad idea. + NWidgetCore *widget = this->GetWidget(widget_index); + assert(widget != nullptr); /* Setting focus to a non-existing widget is a bad idea. */ + if (this->nested_focus != nullptr) { - if (this->GetWidget(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. */ this->nested_focus->SetDirty(this); if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxLostFocus(); } - this->nested_focus = this->GetWidget(widget_index); + + this->nested_focus = widget; if (this->nested_focus->type == WWT_EDITBOX) VideoDriver::GetInstance()->EditBoxGainedFocus(); return true; } @@ -531,21 +525,23 @@ void Window::OnFocusLost(bool) */ void Window::RaiseButtons(bool autoraise) { - for (uint i = 0; i < this->nested_array_size; i++) { - if (this->widget_lookup[i] == nullptr) continue; - WidgetType type = this->widget_lookup[i]->type; + for (auto &pair : this->widget_lookup) { + WidgetType type = pair.second->type; + NWidgetCore *wid = dynamic_cast(pair.second); if (((type & ~WWB_PUSHBUTTON) < WWT_LAST || type == NWID_PUSHBUTTON_DROPDOWN) && - (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && this->IsWidgetLowered(i)) { - this->RaiseWidget(i); - this->SetWidgetDirty(i); + (!autoraise || (type & WWB_PUSHBUTTON) || type == WWT_EDITBOX) && wid->IsLowered()) { + wid->SetLowered(false); + wid->SetDirty(this); } } /* Special widgets without widget index */ - NWidgetCore *wid = this->nested_root != nullptr ? (NWidgetCore*)this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX) : nullptr; - if (wid != nullptr) { - wid->SetLowered(false); - wid->SetDirty(this); + { + NWidgetCore *wid = this->nested_root != nullptr ? dynamic_cast(this->nested_root->GetWidgetOfType(WWT_DEFSIZEBOX)) : nullptr; + if (wid != nullptr) { + wid->SetLowered(false); + wid->SetDirty(this); + } } } @@ -556,9 +552,10 @@ void Window::RaiseButtons(bool autoraise void Window::SetWidgetDirty(byte widget_index) const { /* Sometimes this function is called before the window is even fully initialized */ - if (this->widget_lookup == nullptr) return; - - this->widget_lookup[widget_index]->SetDirty(this); + auto it = this->widget_lookup.find(widget_index); + if (it == std::end(this->widget_lookup)) return; + + it->second->SetDirty(this); } /** @@ -635,7 +632,7 @@ static void DispatchLeftClickEvent(Windo /* Clicked on a widget that is not disabled. * 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. */ - 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 * 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 @@ -1091,8 +1088,6 @@ Window::~Window() assert(*this->z_position == nullptr); if (this->viewport != nullptr) DeleteWindowViewport(this); - - free(this->widget_lookup); // Contents is released through deletion of #nested_root. delete this->nested_root; } @@ -1729,12 +1724,8 @@ static Point LocalGetWindowPlacement(con */ void Window::CreateNestedTree() { - int biggest_index = -1; - this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_begin, this->window_desc->nwid_end, &biggest_index, &this->shade_select); - this->nested_array_size = (uint)(biggest_index + 1); - - this->widget_lookup = CallocT(this->nested_array_size); - this->nested_root->FillWidgetLookup(this->widget_lookup, this->nested_array_size); + this->nested_root = MakeWindowNWidgetTree(this->window_desc->nwid_begin, this->window_desc->nwid_end, &this->shade_select); + this->nested_root->FillWidgetLookup(this->widget_lookup); } /** @@ -1840,9 +1831,9 @@ static void DecreaseWindowCounters() for (Window *w : Window::Iterate()) { if (_scroller_click_timeout == 0) { /* Unclick scrollbar buttons if they are pressed. */ - for (uint i = 0; i < w->nested_array_size; i++) { - NWidgetBase *nwid = w->widget_lookup[i]; - if (nwid != nullptr && (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR)) { + for (auto &pair : w->widget_lookup) { + NWidgetBase *nwid = pair.second; + if (nwid->type == NWID_HSCROLLBAR || nwid->type == NWID_VSCROLLBAR) { NWidgetScrollbar *sb = static_cast(nwid); if (sb->disp_flags & (ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN)) { sb->disp_flags &= ~(ND_SCROLLBAR_UP | ND_SCROLLBAR_DOWN); @@ -3155,8 +3146,8 @@ void Window::ProcessHighlightedInvalidat { if ((this->flags & WF_HIGHLIGHTED) == 0) return; - for (uint i = 0; i < this->nested_array_size; i++) { - if (this->IsWidgetHighlighted(i)) this->SetWidgetDirty(i); + for (const auto &pair : this->widget_lookup) { + if (pair.second->IsHighlighted()) pair.second->SetDirty(this); } } diff --git a/src/window_gui.h b/src/window_gui.h --- a/src/window_gui.h +++ b/src/window_gui.h @@ -260,8 +260,7 @@ public: const NWidgetCore *nested_focus; ///< Currently focused nested widget, or \c nullptr if no nested widget has focus. std::map querystrings; ///< QueryString associated to WWT_EDITBOX widgets. 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. - uint nested_array_size; ///< Size of the nested array. + WidgetLookup widget_lookup; ///< Indexed access to the nested widget tree. Do not access directly, use #Window::GetWidget() instead. 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). @@ -328,8 +327,7 @@ public: */ inline void SetWidgetDisabledState(byte widget_index, bool disab_stat) { - assert(widget_index < this->nested_array_size); - if (this->widget_lookup[widget_index] != nullptr) this->GetWidget(widget_index)->SetDisabled(disab_stat); + this->GetWidget(widget_index)->SetDisabled(disab_stat); } /** @@ -357,7 +355,6 @@ public: */ inline bool IsWidgetDisabled(byte widget_index) const { - assert(widget_index < this->nested_array_size); return this->GetWidget(widget_index)->IsDisabled(); } @@ -389,7 +386,6 @@ public: */ inline void SetWidgetLoweredState(byte widget_index, bool lowered_stat) { - assert(widget_index < this->nested_array_size); this->GetWidget(widget_index)->SetLowered(lowered_stat); } @@ -399,7 +395,6 @@ public: */ inline void ToggleWidgetLoweredState(byte widget_index) { - assert(widget_index < this->nested_array_size); bool lowered_state = this->GetWidget(widget_index)->IsLowered(); this->GetWidget(widget_index)->SetLowered(!lowered_state); } @@ -441,7 +436,6 @@ public: */ inline bool IsWidgetLowered(byte widget_index) const { - assert(widget_index < this->nested_array_size); return this->GetWidget(widget_index)->IsLowered(); } @@ -894,8 +888,9 @@ inline bool AllEqual(It begin, It end, P template inline NWID *Window::GetWidget(uint widnum) { - if (widnum >= this->nested_array_size || this->widget_lookup[widnum] == nullptr) return nullptr; - NWID *nwid = dynamic_cast(this->widget_lookup[widnum]); + auto it = this->widget_lookup.find(widnum); + if (it == std::end(this->widget_lookup)) return nullptr; + NWID *nwid = dynamic_cast(it->second); assert(nwid != nullptr); return nwid; } @@ -904,8 +899,9 @@ inline NWID *Window::GetWidget(uint widn template <> inline const NWidgetBase *Window::GetWidget(uint widnum) const { - if (widnum >= this->nested_array_size) return nullptr; - return this->widget_lookup[widnum]; + auto it = this->widget_lookup.find(widnum); + if (it == std::end(this->widget_lookup)) return nullptr; + return it->second; } /**