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.
* @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 *MakeNWidgetCompanyLines(int *biggest_index)
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::company = INVALID_COMPANY;
/**
* 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 *MakePerformanceDetailPanels(int *biggest_index)
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[] = {

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. */
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 *MakeSaturationLegendLinkGraphGUI(int *biggest_index)
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<uint>(_sorted_cargo_specs.size());
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 (col != nullptr) panel->Add(col);
*biggest_index = WID_LGL_CARGO_LAST;
return panel;
}

View File

@ -855,9 +855,8 @@ GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = {
&NGameSearchFilter
};
static NWidgetBase *MakeResizableHeader(int *biggest_index)
static NWidgetBase *MakeResizableHeader()
{
*biggest_index = std::max<int>(*biggest_index, WID_NG_INFO);
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. */
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);
}

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 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 *hor, int pad_y, int num_half, WidgetType w
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;
}

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. */
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. */

View File

@ -1942,12 +1942,12 @@ static const NWidgetPart _nested_smallmap_bar[] = {
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;
}

View File

@ -714,10 +714,9 @@ const StringID CompanyStationsWindow::sorter_names[] = {
/**
* 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 *biggest_index)
panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
container->Add(panel);
}
*biggest_index = WID_STL_CARGOSTART + static_cast<int>(_sorted_standard_cargo_specs.size());
return container;
}

View File

@ -646,9 +646,9 @@ struct ScenarioEditorLandscapeGenerationWindow : Window {
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);
}
}

View File

@ -89,11 +89,10 @@ TEST_CASE_METHOD(WindowDescTestsFixture, "WindowDesc - NWidgetPart validity")
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;
}

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 */
static const SpriteID toolbar_button_sprites[] = {
@ -2174,7 +2174,6 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index)
hor->Add(leaf);
}
*biggest_index = std::max<int>(*biggest_index, WID_TN_SWITCH_BAR);
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),
};
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[] = {

View File

@ -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(int *biggest_index)
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++;
}
}

View File

@ -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<NWidgetBase>(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 widget, SortButtonState state) const
{
if (state == SBS_OFF) return;
assert(this->widget_lookup != nullptr);
assert(!this->widget_lookup.empty());
Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect();
/* 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)
* 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(StringAlignment 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)
@ -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) {
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;
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::SetupSmallestSize(Window *w)
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(Window *w)
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(Window *)
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);
}
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 &start_x, int &start_y, int &base_offs_
* 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::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->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(Window *w, int widget, int padding)
* 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_dimension = {0, 0};
* 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 &pt)
* @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(const NWidgetPart *nwid_begin, const NWidg
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(const NWidgetPart *nwid_begin, const NWidg
*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(const NWidgetPart *nwid_begin, const NWidg
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(const NWidgetPart *nwid_begin, const NWidg
*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(const NWidgetPart *nwid_begin, const NWidg
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(const NWidgetPart *nwid_begin, const NW
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(const NWidgetPart *nwid_begin, const NW
/* 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(const NWidgetPart *nwid_begin, const NW
* 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 NWidgetPart *nwid_begin, const NWidgetPart
* 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(const NWidgetPart *nwid_begin, const NWi
}
/* Load the remaining parts into 'body'. */
int biggest2 = -1;
MakeNWidgets(nwid_begin, nwid_end, &biggest2, body);
MakeNWidgets(nwid_begin, nwid_end, body);
*biggest_index = std::max(*biggest_index, biggest2);
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 *biggest_index, int widget_first, int wid
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) {

View File

@ -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<int, class NWidgetBase *>;
/**
* 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(int index)
* 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 NWidgetFunction(NWidgetFunctionType *func_ptr)
}
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();

View File

@ -224,10 +224,8 @@ int Window::GetRowFromWidget(int clickpos, int widget, int padding, int line_hei
*/
void Window::DisableAllWidgetHighlight()
{
for (uint i = 0; i < this->nested_array_size; i++) {
NWidgetBase *nwid = this->GetWidget<NWidgetBase>(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<NWidgetBase>(widget_index);
if (nwid == nullptr) return;
@ -258,9 +254,8 @@ void Window::SetWidgetHighlight(byte widget_index, TextColour highlighted_colour
} 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<NWidgetBase>(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 widget_index, TextColour highlighted_colour
*/
bool Window::IsWidgetHighlighted(byte widget_index) const
{
assert(widget_index < this->nested_array_size);
const NWidgetBase *nwid = this->GetWidget<NWidgetBase>(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;
NWidgetCore *widget = this->GetWidget<NWidgetCore>(widget_index);
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->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. */
this->nested_focus->SetDirty(this);
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();
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<NWidgetCore *>(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<NWidgetCore *>(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;
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.
* 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(const WindowDesc *desc, int16_t sm_width, i
*/
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<NWidgetBase *>(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<NWidgetScrollbar*>(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::ProcessHighlightedInvalidations()
{
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);
}
}

View File

@ -260,8 +260,7 @@ public:
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.
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<NWidgetCore>(widget_index)->SetDisabled(disab_stat);
this->GetWidget<NWidgetCore>(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<NWidgetCore>(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<NWidgetCore>(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<NWidgetCore>(widget_index)->IsLowered();
this->GetWidget<NWidgetCore>(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<NWidgetCore>(widget_index)->IsLowered();
}
@ -894,8 +888,9 @@ inline bool AllEqual(It begin, It end, Pred pred)
template <class NWID>
inline NWID *Window::GetWidget(uint widnum)
{
if (widnum >= this->nested_array_size || this->widget_lookup[widnum] == nullptr) return nullptr;
NWID *nwid = dynamic_cast<NWID *>(this->widget_lookup[widnum]);
auto it = this->widget_lookup.find(widnum);
if (it == std::end(this->widget_lookup)) return nullptr;
NWID *nwid = dynamic_cast<NWID *>(it->second);
assert(nwid != nullptr);
return nwid;
}
@ -904,8 +899,9 @@ inline NWID *Window::GetWidget(uint widnum)
template <>
inline const NWidgetBase *Window::GetWidget<NWidgetBase>(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;
}
/**