From 9a3934ae233cd7e61d578862c7963bec09c0197e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sat, 30 Dec 2023 07:36:21 +0000 Subject: [PATCH] Codechange: Use vector/unique_ptr inside widget containers. This replaces a C-style double-linked-list which required all widgets to have next/prev pointers, and removes the need for manual pointer management. --- src/network/network_gui.cpp | 35 ++++++--- src/smallmap_gui.cpp | 10 ++- src/toolbar_gui.cpp | 34 +++++---- src/widget.cpp | 143 ++++++++++++------------------------ src/widget_type.h | 11 +-- 5 files changed, 98 insertions(+), 135 deletions(-) diff --git a/src/network/network_gui.cpp b/src/network/network_gui.cpp index bef7637ef4..0ce4e55be2 100644 --- a/src/network/network_gui.cpp +++ b/src/network/network_gui.cpp @@ -115,18 +115,18 @@ public: this->resize_y = 0; // We never resize in this direction /* First initialise some variables... */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->SetupSmallestSize(w); this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical()); } /* ... then in a second pass make sure the 'current' sizes are set. Won't change for most widgets. */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->current_x = child_wid->smallest_x; child_wid->current_y = this->smallest_y; } - this->smallest_x = this->head->smallest_x + this->tail->smallest_x; // First and last are always shown, rest not + this->smallest_x = this->children.front()->smallest_x + this->children.back()->smallest_x; // First and last are always shown, rest not } void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override @@ -138,27 +138,38 @@ public: this->current_x = given_width; this->current_y = given_height; - given_width -= this->tail->smallest_x; + given_width -= this->children.back()->smallest_x; /* The first and last widget are always visible, determine which other should be visible */ - for (NWidgetBase *child_wid = this->head->next; child_wid->next != nullptr; child_wid = child_wid->next) { - if (given_width > ScaleGUITrad(MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER) + child_wid->smallest_x && child_wid->prev->current_x != 0) { - given_width -= child_wid->smallest_x; - child_wid->current_x = child_wid->smallest_x; /* Make visible. */ - } else { - child_wid->current_x = 0; /* Make invisible. */ + if (this->children.size() > 2) { + auto first = std::next(std::begin(this->children)); + auto last = std::prev(std::end(this->children)); + for (auto it = first; it != last; ++it) { + auto &child_wid = *it; + if (given_width > ScaleGUITrad(MINIMUM_NAME_WIDTH_BEFORE_NEW_HEADER) + child_wid->smallest_x && (*std::prev(it))->current_x != 0) { + given_width -= child_wid->smallest_x; + child_wid->current_x = child_wid->smallest_x; /* Make visible. */ + } else { + child_wid->current_x = 0; /* Make invisible. */ + } } } /* All remaining space goes to the first (name) widget */ - this->head->current_x = given_width; + this->children.front()->current_x = given_width; /* Now assign the widgets to their rightful place */ uint position = 0; // Place to put next child relative to origin of the container. - for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != nullptr; child_wid = rtl ? child_wid->prev : child_wid->next) { + auto assign_position = [&](const std::unique_ptr &child_wid) { if (child_wid->current_x != 0) { child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl); position += child_wid->current_x; } + }; + + if (rtl) { + std::for_each(std::rbegin(this->children), std::rend(this->children), assign_position); + } else { + std::for_each(std::begin(this->children), std::end(this->children), assign_position); } } }; diff --git a/src/smallmap_gui.cpp b/src/smallmap_gui.cpp index 85012d66c1..a91760f646 100644 --- a/src/smallmap_gui.cpp +++ b/src/smallmap_gui.cpp @@ -1852,8 +1852,9 @@ public: void SetupSmallestSize(Window *w) override { - NWidgetBase *display = this->head; - NWidgetBase *bar = display->next; + assert(this->children.size() == 2); + NWidgetBase *display = this->children.front().get(); + NWidgetBase *bar = this->children.back().get(); display->SetupSmallestSize(w); bar->SetupSmallestSize(w); @@ -1875,8 +1876,9 @@ public: this->current_x = given_width; this->current_y = given_height; - NWidgetBase *display = this->head; - NWidgetBase *bar = display->next; + assert(this->children.size() == 2); + NWidgetBase *display = this->children.front().get(); + NWidgetBase *bar = this->children.back().get(); if (sizing == ST_SMALLEST) { this->smallest_x = given_width; diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 2b3f12417a..396932196a 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1347,7 +1347,7 @@ public: uint nbuttons = 0; /* First initialise some variables... */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->SetupSmallestSize(w); this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical()); if (this->IsButton(child_wid->type)) { @@ -1359,7 +1359,7 @@ public: } /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->current_y = this->smallest_y; if (!this->IsButton(child_wid->type)) { child_wid->current_x = child_wid->smallest_x; @@ -1381,12 +1381,13 @@ public: uint arrangable_count, button_count, spacer_count; const WidgetID *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count); - /* Create us ourselves a quick lookup table */ - NWidgetBase *widgets[WID_TN_END]; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { - child_wid->current_x = 0; /* Hide widget, it will be revealed in the next step. */ - if (child_wid->type == NWID_SPACER) continue; - widgets[((NWidgetCore*)child_wid)->index] = child_wid; + /* Create us ourselves a quick lookup table from WidgetID to slot. */ + std::map lookup; + for (auto it = std::begin(this->children); it != std::end(this->children); ++it) { + NWidgetBase *nwid = it->get(); + nwid->current_x = 0; /* Hide widget, it will be revealed in the next step. */ + if (nwid->type == NWID_SPACER) continue; + lookup[dynamic_cast(nwid)->index] = std::distance(this->children.begin(), it); } /* Now assign the widgets to their rightful place */ @@ -1397,12 +1398,13 @@ public: uint button_i = 0; /* Index into the arrangement indices. The macro lastof cannot be used here! */ - const WidgetID *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement; + const WidgetID *slotp = rtl ? &arrangement[arrangable_count - 1] : arrangement; for (uint i = 0; i < arrangable_count; i++) { - NWidgetBase *child_wid = widgets[*cur_wid]; - /* If we have to give space to the spacers, do that */ - if (spacer_space != 0) { - NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev; + uint slot = lookup[*slotp]; + auto &child_wid = this->children[slot]; + /* If we have space to give to the spacers, do that. */ + if (spacer_space > 0 && slot > 0 && slot < this->children.size() - 1) { + const auto &possible_spacer = this->children[slot + (rtl ? 1 : -1)]; if (possible_spacer != nullptr && possible_spacer->type == NWID_SPACER) { uint add = spacer_space / (spacer_count - spacer_i); position += add; @@ -1423,9 +1425,9 @@ public: position += child_wid->current_x; if (rtl) { - cur_wid--; + slotp--; } else { - cur_wid++; + slotp++; } } } @@ -1783,7 +1785,7 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { /* Find the size of panel_widths */ uint i = 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue; assert(i < lengthof(this->panel_widths)); diff --git a/src/widget.cpp b/src/widget.cpp index 151a6d40cb..fa5791dbb4 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -1275,30 +1275,10 @@ NWidgetCore *NWidgetCore::GetWidgetFromPos(int x, int y) return (IsInsideBS(x, this->pos_x, this->current_x) && IsInsideBS(y, this->pos_y, this->current_y)) ? this : nullptr; } -/** - * Constructor container baseclass. - * @param tp Type of the container. - */ -NWidgetContainer::NWidgetContainer(WidgetType tp) : NWidgetBase(tp) -{ - this->head = nullptr; - this->tail = nullptr; -} - -NWidgetContainer::~NWidgetContainer() -{ - while (this->head != nullptr) { - NWidgetBase *wid = this->head->next; - delete this->head; - this->head = wid; - } - this->tail = nullptr; -} - NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) { if (this->type == tp) return this; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { NWidgetBase *nwid = child_wid->GetWidgetOfType(tp); if (nwid != nullptr) return nwid; } @@ -1307,7 +1287,7 @@ NWidgetBase *NWidgetContainer::GetWidgetOfType(WidgetType tp) void NWidgetContainer::AdjustPaddingForZoom() { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->AdjustPaddingForZoom(); } NWidgetBase::AdjustPaddingForZoom(); @@ -1321,31 +1301,19 @@ void NWidgetContainer::Add(NWidgetBase *wid) { assert(wid != nullptr); wid->parent = this; - assert(wid->next == nullptr && wid->prev == nullptr); - - if (this->head == nullptr) { - this->head = wid; - this->tail = wid; - } else { - assert(this->tail != nullptr); - assert(this->tail->next == nullptr); - - this->tail->next = wid; - wid->prev = this->tail; - this->tail = wid; - } + this->children.emplace_back(wid); } void NWidgetContainer::FillWidgetLookup(WidgetLookup &widget_lookup) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->FillWidgetLookup(widget_lookup); } } void NWidgetContainer::Draw(const Window *w) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->Draw(w); } @@ -1356,7 +1324,7 @@ NWidgetCore *NWidgetContainer::GetWidgetFromPos(int x, int y) { if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y); if (nwid != nullptr) return nwid; } @@ -1372,7 +1340,7 @@ NWidgetStacked::NWidgetStacked(WidgetID index) : NWidgetContainer(NWID_SELECTION void NWidgetStacked::AdjustPaddingForZoom() { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { child_wid->AdjustPaddingForZoom(); } NWidgetContainer::AdjustPaddingForZoom(); @@ -1401,11 +1369,11 @@ void NWidgetStacked::SetupSmallestSize(Window *w) /* First sweep, recurse down and compute minimal size and filling. */ this->smallest_x = 0; this->smallest_y = 0; - this->fill_x = (this->head != nullptr) ? 1 : 0; - this->fill_y = (this->head != nullptr) ? 1 : 0; - this->resize_x = (this->head != nullptr) ? 1 : 0; - this->resize_y = (this->head != nullptr) ? 1 : 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + this->fill_x = this->IsEmpty() ? 0 : 1; + this->fill_y = this->IsEmpty() ? 0 : 1; + this->resize_x = this->IsEmpty() ? 0 : 1; + this->resize_y = this->IsEmpty() ? 0 : 1; + for (const auto &child_wid : this->children) { child_wid->SetupSmallestSize(w); this->smallest_x = std::max(this->smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal()); @@ -1424,7 +1392,7 @@ void NWidgetStacked::AssignSizePosition(SizingType sizing, int x, int y, uint gi if (this->shown_plane >= SZSP_BEGIN) return; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint hor_step = (sizing == ST_SMALLEST) ? 1 : child_wid->GetHorizontalStepSize(sizing); uint child_width = ComputeMaxSize(child_wid->smallest_x, given_width - child_wid->padding.Horizontal(), hor_step); uint child_pos_x = (rtl ? child_wid->padding.right : child_wid->padding.left); @@ -1447,16 +1415,9 @@ void NWidgetStacked::Draw(const Window *w) { if (this->shown_plane >= SZSP_BEGIN) return; - int plane = 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; plane++, child_wid = child_wid->next) { - if (plane == this->shown_plane) { - child_wid->Draw(w); - DrawOutline(w, this); - return; - } - } - - NOT_REACHED(); + assert(static_cast(this->shown_plane) < this->children.size()); + this->children[shown_plane]->Draw(w); + DrawOutline(w, this); } NWidgetCore *NWidgetStacked::GetWidgetFromPos(int x, int y) @@ -1464,13 +1425,9 @@ NWidgetCore *NWidgetStacked::GetWidgetFromPos(int x, int y) if (this->shown_plane >= SZSP_BEGIN) return nullptr; if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr; - int plane = 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; plane++, child_wid = child_wid->next) { - if (plane == this->shown_plane) { - return child_wid->GetWidgetFromPos(x, y); - } - } - return nullptr; + + if (static_cast(this->shown_plane) >= this->children.size()) return nullptr; + return this->children[shown_plane]->GetWidgetFromPos(x, y); } /** @@ -1552,7 +1509,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w) /* 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) { + for (const auto &child_wid : this->children) { child_wid->SetupSmallestSize(w); longest = std::max(longest, child_wid->smallest_x); max_vert_fill = std::max(max_vert_fill, child_wid->GetVerticalStepSize(ST_SMALLEST)); @@ -1564,7 +1521,7 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w) [[maybe_unused]] uint max_smallest = this->smallest_y + 3 * max_vert_fill; // Upper limit to computing smallest height. uint cur_height = this->smallest_y; for (;;) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint step_size = child_wid->GetVerticalStepSize(ST_SMALLEST); uint child_height = child_wid->smallest_y + child_wid->padding.Vertical(); if (step_size > 1 && child_height < cur_height) { // Small step sizes or already fitting children are not interesting. @@ -1581,12 +1538,12 @@ void NWidgetHorizontal::SetupSmallestSize(Window *w) } /* 2. For containers that must maintain equal width, extend child minimal size. */ if (this->flags & NC_EQUALSIZE) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { if (child_wid->fill_x == 1) child_wid->smallest_x = longest; } } /* 3. Compute smallest, fill, and resize values of the container. */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { this->smallest_x += child_wid->smallest_x + child_wid->padding.Horizontal(); if (child_wid->fill_x > 0) { if (this->fill_x == 0 || this->fill_x > child_wid->fill_x) this->fill_x = child_wid->fill_x; @@ -1609,7 +1566,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint /* Compute additional width given to us. */ uint additional_length = given_width - (this->pip_pre + this->gaps * this->pip_inter + this->pip_post); - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { if (child_wid->smallest_x != 0 || child_wid->fill_x != 0) additional_length -= child_wid->smallest_x + child_wid->padding.Horizontal(); } @@ -1631,7 +1588,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint */ int num_changing_childs = 0; // Number of children that can change size. uint biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step > 0) { if (!(flags & NC_BIGFIRST)) num_changing_childs++; @@ -1646,7 +1603,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint /* First.5 loop: count how many children are of the biggest step size. */ if ((flags & NC_BIGFIRST) && biggest_stepsize > 0) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step == biggest_stepsize) { num_changing_childs++; @@ -1657,7 +1614,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint /* Second loop: Allocate the additional horizontal space over the resizing children, starting with the biggest resize steps. */ while (biggest_stepsize > 0) { uint next_biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step > biggest_stepsize) continue; // Already done if (hor_step == biggest_stepsize) { @@ -1674,7 +1631,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint if (num_changing_childs == 0 && (flags & NC_BIGFIRST) && biggest_stepsize > 0) { /* Second.5 loop: count how many children are of the updated biggest step size. */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint hor_step = child_wid->GetHorizontalStepSize(sizing); if (hor_step == biggest_stepsize) { num_changing_childs++; @@ -1699,8 +1656,7 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint /* Third loop: Compute position and call the child. */ uint position = rtl ? this->current_x - pre : pre; // Place to put next child relative to origin of the container. - NWidgetBase *child_wid = this->head; - while (child_wid != nullptr) { + for (const auto &child_wid : this->children) { uint child_width = child_wid->current_x; uint child_x = x + (rtl ? position - child_width - child_wid->padding.left : position + child_wid->padding.left); uint child_y = y + child_wid->padding.top; @@ -1710,8 +1666,6 @@ void NWidgetHorizontal::AssignSizePosition(SizingType sizing, int x, int y, uint uint padded_child_width = child_width + child_wid->padding.Horizontal() + inter; position = rtl ? position - padded_child_width : position + padded_child_width; } - - child_wid = child_wid->next; } } @@ -1744,7 +1698,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w) /* 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) { + for (const auto &child_wid : this->children) { child_wid->SetupSmallestSize(w); highest = std::max(highest, child_wid->smallest_y); max_hor_fill = std::max(max_hor_fill, child_wid->GetHorizontalStepSize(ST_SMALLEST)); @@ -1756,7 +1710,7 @@ void NWidgetVertical::SetupSmallestSize(Window *w) [[maybe_unused]] uint max_smallest = this->smallest_x + 3 * max_hor_fill; // Upper limit to computing smallest height. uint cur_width = this->smallest_x; for (;;) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint step_size = child_wid->GetHorizontalStepSize(ST_SMALLEST); uint child_width = child_wid->smallest_x + child_wid->padding.Horizontal(); if (step_size > 1 && child_width < cur_width) { // Small step sizes or already fitting children are not interesting. @@ -1773,12 +1727,12 @@ void NWidgetVertical::SetupSmallestSize(Window *w) } /* 2. For containers that must maintain equal width, extend children minimal size. */ if (this->flags & NC_EQUALSIZE) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { if (child_wid->fill_y == 1) child_wid->smallest_y = highest; } } /* 3. Compute smallest, fill, and resize values of the container. */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { this->smallest_y += child_wid->smallest_y + child_wid->padding.Vertical(); if (child_wid->fill_y > 0) { if (this->fill_y == 0 || this->fill_y > child_wid->fill_y) this->fill_y = child_wid->fill_y; @@ -1801,7 +1755,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g /* Compute additional height given to us. */ uint additional_length = given_height - (this->pip_pre + this->gaps * this->pip_inter + this->pip_post); - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { if (child_wid->smallest_y != 0 || child_wid->fill_y != 0) additional_length -= child_wid->smallest_y + child_wid->padding.Vertical(); } @@ -1814,7 +1768,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g /* First loop: Find biggest stepsize, find number of children that want a piece of the pie, handle horizontal size for all children, handle vertical size for non-resizing child. */ int num_changing_childs = 0; // Number of children that can change size. uint biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step > 0) { if (!(flags & NC_BIGFIRST)) num_changing_childs++; @@ -1829,7 +1783,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g /* First.5 loop: count how many children are of the biggest step size. */ if ((this->flags & NC_BIGFIRST) && biggest_stepsize > 0) { - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step == biggest_stepsize) { num_changing_childs++; @@ -1840,7 +1794,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g /* Second loop: Allocate the additional vertical space over the resizing children, starting with the biggest resize steps. */ while (biggest_stepsize > 0) { uint next_biggest_stepsize = 0; - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step > biggest_stepsize) continue; // Already done if (vert_step == biggest_stepsize) { @@ -1857,7 +1811,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g if (num_changing_childs == 0 && (flags & NC_BIGFIRST) && biggest_stepsize > 0) { /* Second.5 loop: count how many children are of the updated biggest step size. */ - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint vert_step = child_wid->GetVerticalStepSize(sizing); if (vert_step == biggest_stepsize) { num_changing_childs++; @@ -1882,7 +1836,7 @@ void NWidgetVertical::AssignSizePosition(SizingType sizing, int x, int y, uint g /* Third loop: Compute position and call the child. */ uint position = pre; // Place to put next child relative to origin of the container. - for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) { + for (const auto &child_wid : this->children) { uint child_x = x + (rtl ? child_wid->padding.right : child_wid->padding.left); uint child_height = child_wid->current_y; @@ -1974,7 +1928,7 @@ void NWidgetMatrix::SetCount(int count) * Then multiply that by the height of a widget, and add the pre * and post spacing "offsets". */ count = CeilDiv(count, this->sb->IsVertical() ? this->widgets_x : this->widgets_y); - count *= (this->sb->IsVertical() ? this->head->smallest_y : this->head->smallest_x) + this->pip_inter; + count *= (this->sb->IsVertical() ? this->children.front()->smallest_y : this->children.front()->smallest_x) + this->pip_inter; if (count > 0) count -= this->pip_inter; // We counted an inter too much in the multiplication above count += this->pip_pre + this->pip_post; this->sb->SetCount(count); @@ -2002,15 +1956,14 @@ int NWidgetMatrix::GetCurrentElement() const void NWidgetMatrix::SetupSmallestSize(Window *w) { - assert(this->head != nullptr); - assert(this->head->next == nullptr); + assert(this->children.size() == 1); - this->head->SetupSmallestSize(w); + this->children.front()->SetupSmallestSize(w); Dimension padding = { (uint)this->pip_pre + this->pip_post, (uint)this->pip_pre + this->pip_post}; - Dimension size = {this->head->smallest_x + padding.width, this->head->smallest_y + padding.height}; + Dimension size = {this->children.front()->smallest_x + padding.width, this->children.front()->smallest_y + padding.height}; Dimension fill = {0, 0}; - Dimension resize = {this->pip_inter + this->head->smallest_x, this->pip_inter + this->head->smallest_y}; + Dimension resize = {this->pip_inter + this->children.front()->smallest_x, this->pip_inter + this->children.front()->smallest_y}; if (this->index >= 0) w->UpdateWidgetSize(this->index, &size, padding, &fill, &resize); @@ -2032,8 +1985,8 @@ void NWidgetMatrix::AssignSizePosition(SizingType, int x, int y, uint given_widt this->current_y = given_height; /* Determine the size of the widgets, and the number of visible widgets on each of the axis. */ - this->widget_w = this->head->smallest_x + this->pip_inter; - this->widget_h = this->head->smallest_y + this->pip_inter; + this->widget_w = this->children.front()->smallest_x + this->pip_inter; + this->widget_h = this->children.front()->smallest_y + this->pip_inter; /* Account for the pip_inter is between widgets, so we need to account for that when * the division assumes pip_inter is used for all widgets. */ @@ -2072,7 +2025,7 @@ NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) this->current_element = (widget_row + start_y) * this->widgets_x + start_x + widget_col; if (this->current_element >= this->count) return nullptr; - NWidgetCore *child = dynamic_cast(this->head); + NWidgetCore *child = dynamic_cast(this->children.front().get()); assert(child != nullptr); child->AssignSizePosition(ST_RESIZE, this->pos_x + (rtl ? this->pip_post - widget_col * this->widget_w : this->pip_pre + widget_col * this->widget_w) + base_offs_x, @@ -2096,7 +2049,7 @@ NWidgetCore *NWidgetMatrix::GetWidgetFromPos(int x, int y) AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi); /* Get the appropriate offsets so we can draw the right widgets. */ - NWidgetCore *child = dynamic_cast(this->head); + NWidgetCore *child = dynamic_cast(this->children.front().get()); assert(child != nullptr); int start_x, start_y, base_offs_x, base_offs_y; this->GetScrollOffsets(start_x, start_y, base_offs_x, base_offs_y); diff --git a/src/widget_type.h b/src/widget_type.h index 9c2620cad6..375ed88291 100644 --- a/src/widget_type.h +++ b/src/widget_type.h @@ -235,9 +235,6 @@ public: int pos_x; ///< Horizontal position of top-left corner of the widget in the window. int pos_y; ///< Vertical position of top-left corner of the widget in the window. - NWidgetBase *next; ///< Pointer to next widget in container. Managed by parent container widget. - NWidgetBase *prev; ///< Pointer to previous widget in container. Managed by parent container widget. - RectPadding padding; ///< Padding added to the widget. Managed by parent container widget. (parent container may swap left and right for RTL) RectPadding uz_padding; ///< Unscaled padding, for resize calculation. @@ -446,8 +443,7 @@ inline bool NWidgetCore::IsDisabled() const */ class NWidgetContainer : public NWidgetBase { public: - NWidgetContainer(WidgetType tp); - ~NWidgetContainer(); + NWidgetContainer(WidgetType tp) : NWidgetBase(tp) { } void AdjustPaddingForZoom() override; void Add(NWidgetBase *wid); @@ -457,13 +453,12 @@ public: NWidgetCore *GetWidgetFromPos(int x, int y) override; /** Return whether the container is empty. */ - inline bool IsEmpty() { return head == nullptr; } + inline bool IsEmpty() { return this->children.empty(); } NWidgetBase *GetWidgetOfType(WidgetType tp) override; protected: - NWidgetBase *head; ///< Pointer to first widget in container. - NWidgetBase *tail; ///< Pointer to last widget in container. + std::vector> children; ///< Child widgets in contaier. }; /** Display planes with zero size for #NWidgetStacked. */