1
0
Fork 0

Compare commits

...

3 Commits

Author SHA1 Message Date
Peter Nelson 934545a674
Fix: Calculation of initial engine age was inaccurate. (#11660)
Engine age in months was calculated as the difference in days / 32, instead of the actually difference in months. This would result in engines being artificially younger if a game was started at a later date.
2023-12-31 15:47:32 +00:00
Peter Nelson 7124b4eef1 Codechange: Use std::unique_ptr for all NWidgets. 2023-12-31 15:33:56 +00:00
Peter Nelson 9a3934ae23 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.
2023-12-31 15:33:56 +00:00
18 changed files with 308 additions and 351 deletions

View File

@ -675,7 +675,7 @@ void SetYearEngineAgingStops()
* @param aging_date The date used for age calculations.
* @param seed Random seed.
*/
void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t seed)
void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed)
{
const EngineInfo *ei = &e->info;
@ -699,7 +699,11 @@ void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t se
* Note: TTDP uses fixed 1922 */
e->intro_date = ei->base_intro <= TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year + 2, 0, 1) ? ei->base_intro : (TimerGameCalendar::Date)GB(r, 0, 9) + ei->base_intro;
if (e->intro_date <= TimerGameCalendar::date) {
e->age = (aging_date - e->intro_date).base() >> 5;
TimerGameCalendar::YearMonthDay intro_ymd = TimerGameCalendar::ConvertDateToYMD(e->intro_date);
int aging_months = aging_ymd.year.base() * 12 + aging_ymd.month;
int intro_months = intro_ymd.year.base() * 12 + intro_ymd.month;
if (intro_ymd.day > 1) intro_months++; // Engines are introduced at the first month start at/after intro date.
e->age = aging_months - intro_months;
e->company_avail = MAX_UVALUE(CompanyMask);
e->flags |= ENGINE_AVAILABLE;
}
@ -756,10 +760,11 @@ void StartupEngines()
{
/* Aging of vehicles stops, so account for that when starting late */
const TimerGameCalendar::Date aging_date = std::min(TimerGameCalendar::date, TimerGameCalendar::ConvertYMDToDate(_year_engine_aging_stops, 0, 1));
TimerGameCalendar::YearMonthDay aging_ymd = TimerGameCalendar::ConvertDateToYMD(aging_date);
uint32_t seed = Random();
for (Engine *e : Engine::Iterate()) {
StartupOneEngine(e, aging_date, seed);
StartupOneEngine(e, aging_ymd, seed);
}
for (Engine *e : Engine::Iterate()) {
CalcEngineReliability(e, false);

View File

@ -27,7 +27,7 @@ bool IsEngineBuildable(EngineID engine, VehicleType type, CompanyID company);
bool IsEngineRefittable(EngineID engine);
void SetYearEngineAgingStops();
void CalcEngineReliability(Engine *e, bool new_month);
void StartupOneEngine(Engine *e, TimerGameCalendar::Date aging_date, uint32_t seed);
void StartupOneEngine(Engine *e, const TimerGameCalendar::YearMonthDay &aging_ymd, uint32_t seed);
uint GetTotalCapacityOfArticulatedParts(EngineID engine);

View File

@ -109,19 +109,19 @@ struct GraphLegendWindow : Window {
* Construct a vertical list of buttons, one for each company.
* @return Panel with company buttons.
*/
static NWidgetBase *MakeNWidgetCompanyLines()
static std::unique_ptr<NWidgetBase> MakeNWidgetCompanyLines()
{
NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE);
auto vert = std::make_unique<NWidgetVertical>(NC_EQUALSIZE);
vert->SetPadding(2, 2, 2, 2);
uint sprite_height = GetSpriteSize(SPR_COMPANY_ICON, nullptr, ZOOM_LVL_OUT_4X).height;
for (WidgetID widnum = WID_GL_FIRST_COMPANY; widnum <= WID_GL_LAST_COMPANY; widnum++) {
NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_BROWN, widnum);
auto panel = std::make_unique<NWidgetBackground>(WWT_PANEL, COLOUR_BROWN, widnum);
panel->SetMinimalSize(246, sprite_height + WidgetDimensions::unscaled.framerect.Vertical());
panel->SetMinimalTextLines(1, WidgetDimensions::unscaled.framerect.Vertical(), FS_NORMAL);
panel->SetFill(1, 1);
panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP);
vert->Add(panel);
vert->Add(std::move(panel));
}
return vert;
}
@ -1337,7 +1337,7 @@ CompanyID PerformanceRatingDetailWindow::company = INVALID_COMPANY;
* Make a vertical list of panels for outputting score details.
* @return Panel with performance details.
*/
static NWidgetBase *MakePerformanceDetailPanels()
static std::unique_ptr<NWidgetBase> MakePerformanceDetailPanels()
{
const StringID performance_tips[] = {
STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP,
@ -1354,18 +1354,18 @@ static NWidgetBase *MakePerformanceDetailPanels()
static_assert(lengthof(performance_tips) == SCORE_END - SCORE_BEGIN);
NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE);
auto vert = std::make_unique<NWidgetVertical>(NC_EQUALSIZE);
for (WidgetID widnum = WID_PRD_SCORE_FIRST; widnum <= WID_PRD_SCORE_LAST; widnum++) {
NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_BROWN, widnum);
auto panel = std::make_unique<NWidgetBackground>(WWT_PANEL, COLOUR_BROWN, widnum);
panel->SetFill(1, 1);
panel->SetDataTip(0x0, performance_tips[widnum - WID_PRD_SCORE_FIRST]);
vert->Add(panel);
vert->Add(std::move(panel));
}
return vert;
}
/** Make a number of rows with buttons for each company for the performance rating detail window. */
NWidgetBase *MakeCompanyButtonRowsGraphGUI()
std::unique_ptr<NWidgetBase> MakeCompanyButtonRowsGraphGUI()
{
return MakeCompanyButtonRows(WID_PRD_COMPANY_FIRST, WID_PRD_COMPANY_LAST, COLOUR_BROWN, 8, STR_PERFORMANCE_DETAIL_SELECT_COMPANY_TOOLTIP);
}

View File

@ -454,54 +454,54 @@ void LinkGraphOverlay::SetCompanyMask(CompanyMask company_mask)
}
/** Make a number of rows with buttons for each company for the linkgraph legend window. */
NWidgetBase *MakeCompanyButtonRowsLinkGraphGUI()
std::unique_ptr<NWidgetBase> MakeCompanyButtonRowsLinkGraphGUI()
{
return MakeCompanyButtonRows(WID_LGL_COMPANY_FIRST, WID_LGL_COMPANY_LAST, COLOUR_GREY, 3, STR_NULL);
}
NWidgetBase *MakeSaturationLegendLinkGraphGUI()
std::unique_ptr<NWidgetBase> MakeSaturationLegendLinkGraphGUI()
{
NWidgetVertical *panel = new NWidgetVertical(NC_EQUALSIZE);
auto panel = std::make_unique<NWidgetVertical>(NC_EQUALSIZE);
for (uint i = 0; i < lengthof(LinkGraphOverlay::LINK_COLOURS[0]); ++i) {
NWidgetBackground * wid = new NWidgetBackground(WWT_PANEL, COLOUR_DARK_GREEN, i + WID_LGL_SATURATION_FIRST);
auto wid = std::make_unique<NWidgetBackground>(WWT_PANEL, COLOUR_DARK_GREEN, i + WID_LGL_SATURATION_FIRST);
wid->SetMinimalSize(50, 0);
wid->SetMinimalTextLines(1, 0, FS_SMALL);
wid->SetFill(1, 1);
wid->SetResize(0, 0);
panel->Add(wid);
panel->Add(std::move(wid));
}
return panel;
}
NWidgetBase *MakeCargoesLegendLinkGraphGUI()
std::unique_ptr<NWidgetBase> MakeCargoesLegendLinkGraphGUI()
{
uint num_cargo = static_cast<uint>(_sorted_cargo_specs.size());
static const uint ENTRIES_PER_COL = 5;
NWidgetHorizontal *panel = new NWidgetHorizontal(NC_EQUALSIZE);
NWidgetVertical *col = nullptr;
auto panel = std::make_unique<NWidgetHorizontal>(NC_EQUALSIZE);
std::unique_ptr<NWidgetVertical> col = nullptr;
for (uint i = 0; i < num_cargo; ++i) {
if (i % ENTRIES_PER_COL == 0) {
if (col != nullptr) panel->Add(col);
col = new NWidgetVertical(NC_EQUALSIZE);
if (col != nullptr) panel->Add(std::move(col));
col = std::make_unique<NWidgetVertical>(NC_EQUALSIZE);
}
NWidgetBackground * wid = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, i + WID_LGL_CARGO_FIRST);
auto wid = std::make_unique<NWidgetBackground>(WWT_PANEL, COLOUR_GREY, i + WID_LGL_CARGO_FIRST);
wid->SetMinimalSize(25, 0);
wid->SetMinimalTextLines(1, 0, FS_SMALL);
wid->SetFill(1, 1);
wid->SetResize(0, 0);
col->Add(wid);
col->Add(std::move(wid));
}
/* Fill up last row */
for (uint i = num_cargo; i < Ceil(num_cargo, ENTRIES_PER_COL); ++i) {
NWidgetSpacer *spc = new NWidgetSpacer(25, 0);
auto spc = std::make_unique<NWidgetSpacer>(25, 0);
spc->SetMinimalTextLines(1, 0, FS_SMALL);
spc->SetFill(1, 1);
spc->SetResize(0, 0);
col->Add(spc);
col->Add(std::move(spc));
}
/* If there are no cargo specs defined, then col won't have been created so don't add it. */
if (col != nullptr) panel->Add(col);
if (col != nullptr) panel->Add(std::move(col));
return panel;
}

View File

@ -89,21 +89,21 @@ class NWidgetServerListHeader : public NWidgetContainer {
public:
NWidgetServerListHeader() : NWidgetContainer(NWID_HORIZONTAL)
{
NWidgetLeaf *leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
auto leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME, STR_NETWORK_SERVER_LIST_GAME_NAME_TOOLTIP);
leaf->SetResize(1, 0);
leaf->SetFill(1, 0);
this->Add(leaf);
this->Add(std::move(leaf));
this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
this->Add(new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP));
this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_CLIENTS, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION, STR_NETWORK_SERVER_LIST_CLIENTS_CAPTION_TOOLTIP));
this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_MAPSIZE, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION, STR_NETWORK_SERVER_LIST_MAP_SIZE_CAPTION_TOOLTIP));
this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_DATE, STR_NETWORK_SERVER_LIST_DATE_CAPTION, STR_NETWORK_SERVER_LIST_DATE_CAPTION_TOOLTIP));
this->Add(std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_YEARS, STR_NETWORK_SERVER_LIST_YEARS_CAPTION, STR_NETWORK_SERVER_LIST_YEARS_CAPTION_TOOLTIP));
leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
leaf = std::make_unique<NWidgetLeaf>(WWT_PUSHTXTBTN, COLOUR_WHITE, WID_NG_INFO, STR_EMPTY, STR_NETWORK_SERVER_LIST_INFO_ICONS_TOOLTIP);
leaf->SetMinimalSize(14 + GetSpriteSize(SPR_LOCK, nullptr, ZOOM_LVL_OUT_4X).width
+ GetSpriteSize(SPR_BLOT, nullptr, ZOOM_LVL_OUT_4X).width, 12);
leaf->SetFill(0, 1);
this->Add(leaf);
this->Add(std::move(leaf));
}
void SetupSmallestSize(Window *w) override
@ -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<NWidgetBase> &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);
}
}
};
@ -855,9 +866,9 @@ GUIGameServerList::FilterFunction * const NetworkGameWindow::filter_funcs[] = {
&NGameSearchFilter
};
static NWidgetBase *MakeResizableHeader()
static std::unique_ptr<NWidgetBase> MakeResizableHeader()
{
return new NWidgetServerListHeader();
return std::make_unique<NWidgetServerListHeader>();
}
static const NWidgetPart _nested_network_game_widgets[] = {

View File

@ -1600,27 +1600,22 @@ NewGRFWindow::GUIGRFConfigList::FilterFunction * const NewGRFWindow::filter_func
* - two column mode, put the #acs and the #avs underneath each other and the #inf next to it, or
* - three column mode, put the #avs, #acs, and #inf each in its own column.
*/
class NWidgetNewGRFDisplay : public NWidgetContainer {
class NWidgetNewGRFDisplay : public NWidgetBase {
public:
static const uint MAX_EXTRA_INFO_WIDTH; ///< Maximal additional width given to the panel.
static const uint MIN_EXTRA_FOR_3_COLUMNS; ///< Minimal additional width needed before switching to 3 columns.
NWidgetBase *avs; ///< Widget with the available grfs list and buttons.
NWidgetBase *acs; ///< Widget with the active grfs list and buttons.
NWidgetBase *inf; ///< Info panel.
std::unique_ptr<NWidgetBase> avs; ///< Widget with the available grfs list and buttons.
std::unique_ptr<NWidgetBase> acs; ///< Widget with the active grfs list and buttons.
std::unique_ptr<NWidgetBase> inf; ///< Info panel.
bool editable; ///< Editable status of the parent NewGRF window (if \c false, drop all widgets that make the window editable).
NWidgetNewGRFDisplay(NWidgetBase *avs, NWidgetBase *acs, NWidgetBase *inf) : NWidgetContainer(NWID_HORIZONTAL)
NWidgetNewGRFDisplay(std::unique_ptr<NWidgetBase> &&avs, std::unique_ptr<NWidgetBase> &&acs, std::unique_ptr<NWidgetBase> &&inf) : NWidgetBase(NWID_CUSTOM)
, avs(std::move(avs))
, acs(std::move(acs))
, inf(std::move(inf))
, editable(true) // Temporary setting, 'real' value is set in SetupSmallestSize().
{
this->avs = avs;
this->acs = acs;
this->inf = inf;
this->Add(this->avs);
this->Add(this->acs);
this->Add(this->inf);
this->editable = true; // Temporary setting, 'real' value is set in SetupSmallestSize().
}
void SetupSmallestSize(Window *w) override
@ -1785,6 +1780,13 @@ public:
}
}
void FillWidgetLookup(WidgetLookup &widget_lookup) override
{
this->avs->FillWidgetLookup(widget_lookup);
this->acs->FillWidgetLookup(widget_lookup);
this->inf->FillWidgetLookup(widget_lookup);
}
NWidgetCore *GetWidgetFromPos(int x, int y) override
{
if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
@ -1937,13 +1939,13 @@ 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()
std::unique_ptr<NWidgetBase> NewGRFDisplay()
{
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);
std::unique_ptr<NWidgetBase> avs = MakeNWidgets(std::begin(_nested_newgrf_availables_widgets), std::end(_nested_newgrf_availables_widgets), nullptr);
std::unique_ptr<NWidgetBase> acs = MakeNWidgets(std::begin(_nested_newgrf_actives_widgets), std::end(_nested_newgrf_actives_widgets), nullptr);
std::unique_ptr<NWidgetBase> inf = MakeNWidgets(std::begin(_nested_newgrf_infopanel_widgets), std::end(_nested_newgrf_infopanel_widgets), nullptr);
return new NWidgetNewGRFDisplay(avs, acs, inf);
return std::make_unique<NWidgetNewGRFDisplay>(std::move(avs), std::move(acs), std::move(inf));
}
/* Widget definition of the manage newgrfs window */

View File

@ -222,32 +222,32 @@ static const int KEY_PADDING = 6; // Vertical padding for remaining key rows
* @param widdata Data value of the key widget.
* @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, WidgetID widnum, uint16_t widdata)
static void AddKey(std::unique_ptr<NWidgetHorizontal> &hor, int pad_y, int num_half, WidgetType widtype, WidgetID widnum, uint16_t widdata)
{
int key_width = HALF_KEY_WIDTH + (INTER_KEY_SPACE + HALF_KEY_WIDTH) * (num_half - 1);
if (widtype == NWID_SPACER) {
if (!hor->IsEmpty()) key_width += INTER_KEY_SPACE;
NWidgetSpacer *spc = new NWidgetSpacer(key_width, 0);
auto spc = std::make_unique<NWidgetSpacer>(key_width, 0);
spc->SetMinimalTextLines(1, pad_y, FS_NORMAL);
hor->Add(spc);
hor->Add(std::move(spc));
} else {
if (!hor->IsEmpty()) {
NWidgetSpacer *spc = new NWidgetSpacer(INTER_KEY_SPACE, 0);
auto spc = std::make_unique<NWidgetSpacer>(INTER_KEY_SPACE, 0);
spc->SetMinimalTextLines(1, pad_y, FS_NORMAL);
hor->Add(spc);
hor->Add(std::move(spc));
}
NWidgetLeaf *leaf = new NWidgetLeaf(widtype, COLOUR_GREY, widnum, widdata, STR_NULL);
auto leaf = std::make_unique<NWidgetLeaf>(widtype, COLOUR_GREY, widnum, widdata, STR_NULL);
leaf->SetMinimalSize(key_width, 0);
leaf->SetMinimalTextLines(1, pad_y, FS_NORMAL);
hor->Add(leaf);
hor->Add(std::move(leaf));
}
}
/** Construct the top row keys (cancel, ok, backspace). */
static NWidgetBase *MakeTopKeys()
static std::unique_ptr<NWidgetBase> MakeTopKeys()
{
NWidgetHorizontal *hor = new NWidgetHorizontal();
auto hor = std::make_unique<NWidgetHorizontal>();
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 );
@ -256,9 +256,9 @@ static NWidgetBase *MakeTopKeys()
}
/** Construct the row containing the digit keys. */
static NWidgetBase *MakeNumberKeys()
static std::unique_ptr<NWidgetBase> MakeNumberKeys()
{
NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
std::unique_ptr<NWidgetHorizontal> hor = std::make_unique<NWidgetHorizontalLTR>();
for (WidgetID widnum = WID_OSK_NUMBERS_FIRST; widnum <= WID_OSK_NUMBERS_LAST; widnum++) {
AddKey(hor, KEY_PADDING, 2, WWT_PUSHBTN, widnum, 0x0);
@ -267,9 +267,9 @@ static NWidgetBase *MakeNumberKeys()
}
/** Construct the qwerty row keys. */
static NWidgetBase *MakeQwertyKeys()
static std::unique_ptr<NWidgetBase> MakeQwertyKeys()
{
NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
std::unique_ptr<NWidgetHorizontal> hor = std::make_unique<NWidgetHorizontalLTR>();
AddKey(hor, KEY_PADDING, 3, WWT_PUSHIMGBTN, WID_OSK_SPECIAL, SPR_OSK_SPECIAL);
for (WidgetID widnum = WID_OSK_QWERTY_FIRST; widnum <= WID_OSK_QWERTY_LAST; widnum++) {
@ -280,9 +280,9 @@ static NWidgetBase *MakeQwertyKeys()
}
/** Construct the asdfg row keys. */
static NWidgetBase *MakeAsdfgKeys()
static std::unique_ptr<NWidgetBase> MakeAsdfgKeys()
{
NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
std::unique_ptr<NWidgetHorizontal> hor = std::make_unique<NWidgetHorizontalLTR>();
AddKey(hor, KEY_PADDING, 4, WWT_IMGBTN, WID_OSK_CAPS, SPR_OSK_CAPS);
for (WidgetID widnum = WID_OSK_ASDFG_FIRST; widnum <= WID_OSK_ASDFG_LAST; widnum++) {
@ -292,9 +292,9 @@ static NWidgetBase *MakeAsdfgKeys()
}
/** Construct the zxcvb row keys. */
static NWidgetBase *MakeZxcvbKeys()
static std::unique_ptr<NWidgetBase> MakeZxcvbKeys()
{
NWidgetHorizontal *hor = new NWidgetHorizontalLTR();
std::unique_ptr<NWidgetHorizontal> hor = std::make_unique<NWidgetHorizontalLTR>();
AddKey(hor, KEY_PADDING, 3, WWT_IMGBTN, WID_OSK_SHIFT, SPR_OSK_SHIFT);
for (WidgetID widnum = WID_OSK_ZXCVB_FIRST; widnum <= WID_OSK_ZXCVB_LAST; widnum++) {
@ -305,9 +305,9 @@ static NWidgetBase *MakeZxcvbKeys()
}
/** Construct the spacebar row keys. */
static NWidgetBase *MakeSpacebarKeys()
static std::unique_ptr<NWidgetBase> MakeSpacebarKeys()
{
NWidgetHorizontal *hor = new NWidgetHorizontal();
auto hor = std::make_unique<NWidgetHorizontal>();
AddKey(hor, KEY_PADDING, 8, NWID_SPACER, 0, 0);
AddKey(hor, KEY_PADDING, 13, WWT_PUSHTXTBTN, WID_OSK_SPACE, STR_EMPTY);

View File

@ -399,6 +399,7 @@ static bool FixTTOEngines()
}
TimerGameCalendar::Date aging_date = std::min(TimerGameCalendar::date + CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR, TimerGameCalendar::ConvertYMDToDate(2050, 0, 1));
TimerGameCalendar::YearMonthDay aging_ymd = TimerGameCalendar::ConvertDateToYMD(aging_date);
for (EngineID i = 0; i < 256; i++) {
int oi = ttd_to_tto[i];
@ -407,7 +408,7 @@ static bool FixTTOEngines()
if (oi == 255) {
/* Default engine is used */
TimerGameCalendar::date += CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
StartupOneEngine(e, aging_date, 0);
StartupOneEngine(e, aging_ymd, 0);
CalcEngineReliability(e, false);
e->intro_date -= CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;
TimerGameCalendar::date -= CalendarTime::DAYS_TILL_ORIGINAL_BASE_YEAR;

View File

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

View File

@ -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;
@ -1942,12 +1944,12 @@ static const NWidgetPart _nested_smallmap_bar[] = {
EndContainer(),
};
static NWidgetBase *SmallMapDisplay()
static std::unique_ptr<NWidgetBase> SmallMapDisplay()
{
NWidgetContainer *map_display = new NWidgetSmallmapDisplay;
std::unique_ptr<NWidgetBase> map_display = std::make_unique<NWidgetSmallmapDisplay>();
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);
map_display = MakeNWidgets(std::begin(_nested_smallmap_display), std::end(_nested_smallmap_display), std::move(map_display));
map_display = MakeNWidgets(std::begin(_nested_smallmap_bar), std::end(_nested_smallmap_bar), std::move(map_display));
return map_display;
}

View File

@ -716,18 +716,18 @@ const StringID CompanyStationsWindow::sorter_names[] = {
* Make a horizontal row of cargo buttons, starting at widget #WID_STL_CARGOSTART.
* @return Horizontal row.
*/
static NWidgetBase *CargoWidgets()
static std::unique_ptr<NWidgetBase> CargoWidgets()
{
NWidgetHorizontal *container = new NWidgetHorizontal();
auto container = std::make_unique<NWidgetHorizontal>();
for (uint i = 0; i < _sorted_standard_cargo_specs.size(); i++) {
NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
auto panel = std::make_unique<NWidgetBackground>(WWT_PANEL, COLOUR_GREY, WID_STL_CARGOSTART + i);
panel->SetMinimalSize(14, 0);
panel->SetMinimalTextLines(1, 0, FS_NORMAL);
panel->SetResize(0, 0);
panel->SetFill(0, 1);
panel->SetDataTip(0, STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE);
container->Add(panel);
container->Add(std::move(panel));
}
return container;
}

View File

@ -90,9 +90,8 @@ TEST_CASE_METHOD(WindowDescTestsFixture, "WindowDesc - NWidgetPart validity")
INFO(fmt::format("{}:{}", window_desc->file, window_desc->line));
NWidgetStacked *shade_select = nullptr;
NWidgetBase *root = nullptr;
std::unique_ptr<NWidgetBase> root = nullptr;
REQUIRE_NOTHROW(root = MakeWindowNWidgetTree(window_desc->nwid_begin, window_desc->nwid_end, &shade_select));
CHECK((root != nullptr));
delete root;
}

View File

@ -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<WidgetID, uint> 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<NWidgetCore *>(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));
@ -2120,7 +2122,7 @@ struct MainToolbarWindow : Window {
}};
};
static NWidgetBase *MakeMainToolbar()
static std::unique_ptr<NWidgetBase> MakeMainToolbar()
{
/** Sprites to use for the different toolbar buttons */
static const SpriteID toolbar_button_sprites[] = {
@ -2157,7 +2159,7 @@ static NWidgetBase *MakeMainToolbar()
SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
};
NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
auto hor = std::make_unique<NWidgetMainToolbarContainer>();
for (WidgetID i = 0; i < WID_TN_END; i++) {
switch (i) {
case WID_TN_SMALL_MAP:
@ -2166,12 +2168,12 @@ static NWidgetBase *MakeMainToolbar()
case WID_TN_ZOOM_IN:
case WID_TN_BUILDING_TOOLS_START:
case WID_TN_MUSIC_SOUND:
hor->Add(new NWidgetSpacer(0, 0));
hor->Add(std::make_unique<NWidgetSpacer>(0, 0));
break;
}
NWidgetLeaf *leaf = new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i);
auto leaf = std::make_unique<NWidgetLeaf>(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i);
leaf->SetMinimalSize(20, 20);
hor->Add(leaf);
hor->Add(std::move(leaf));
}
return hor;
@ -2512,9 +2514,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()
static std::unique_ptr<NWidgetBase> MakeScenarioToolbar()
{
return MakeNWidgets(std::begin(_nested_toolb_scen_inner_widgets), std::end(_nested_toolb_scen_inner_widgets), new NWidgetScenarioToolbarContainer());
return MakeNWidgets(std::begin(_nested_toolb_scen_inner_widgets), std::end(_nested_toolb_scen_inner_widgets), std::make_unique<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()
static std::unique_ptr<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];
@ -266,20 +266,20 @@ static NWidgetBase *MakeTreeTypeButtons()
const int num_rows = CeilDiv(type_count, num_columns);
byte cur_type = type_base;
NWidgetVertical *vstack = new NWidgetVertical(NC_EQUALSIZE);
auto vstack = std::make_unique<NWidgetVertical>(NC_EQUALSIZE);
vstack->SetPIP(0, 1, 0);
for (int row = 0; row < num_rows; row++) {
NWidgetHorizontal *hstack = new NWidgetHorizontal(NC_EQUALSIZE);
auto hstack = std::make_unique<NWidgetHorizontal>(NC_EQUALSIZE);
hstack->SetPIP(0, 1, 0);
vstack->Add(hstack);
for (int col = 0; col < num_columns; col++) {
if (cur_type > type_base + type_count) break;
NWidgetBackground *button = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_BUTTON_FIRST + cur_type);
auto button = std::make_unique<NWidgetBackground>(WWT_PANEL, COLOUR_GREY, WID_BT_TYPE_BUTTON_FIRST + cur_type);
button->SetDataTip(0x0, STR_PLANT_TREE_TOOLTIP);
hstack->Add(button);
hstack->Add(std::move(button));
cur_type++;
}
vstack->Add(std::move(hstack));
}
return vstack;

View File

@ -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();
@ -1317,35 +1297,23 @@ void NWidgetContainer::AdjustPaddingForZoom()
* Append widget \a wid to container.
* @param wid Widget to append.
*/
void NWidgetContainer::Add(NWidgetBase *wid)
void NWidgetContainer::Add(std::unique_ptr<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.push_back(std::move(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<size_t>(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<size_t>(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<NWidgetCore *>(this->head);
NWidgetCore *child = dynamic_cast<NWidgetCore *>(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<NWidgetCore *>(this->head);
NWidgetCore *child = dynamic_cast<NWidgetCore *>(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);
@ -2168,19 +2121,14 @@ void NWidgetMatrix::GetScrollOffsets(int &start_x, int &start_y, int &base_offs_
* vertical container will be inserted while adding the first
* child widget.
*/
NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, WidgetID index, NWidgetPIPContainer *child) : NWidgetCore(tp, colour, index, 1, 1, 0x0, STR_NULL)
NWidgetBackground::NWidgetBackground(WidgetType tp, Colours colour, WidgetID index, std::unique_ptr<NWidgetPIPContainer> &&child) : NWidgetCore(tp, colour, index, 1, 1, 0x0, STR_NULL)
{
assert(tp == WWT_PANEL || tp == WWT_INSET || tp == WWT_FRAME);
this->child = child;
this->child = std::move(child);
if (this->child != nullptr) this->child->parent = this;
this->SetAlignment(SA_TOP | SA_LEFT);
}
NWidgetBackground::~NWidgetBackground()
{
if (this->child != nullptr) delete this->child;
}
/**
* Add a child to the parent.
* @param nwid Nested widget to add to the background widget.
@ -2188,13 +2136,13 @@ NWidgetBackground::~NWidgetBackground()
* Unless a child container has been given in the constructor, a parent behaves as a vertical container.
* You can add several children to it, and they are put underneath each other.
*/
void NWidgetBackground::Add(NWidgetBase *nwid)
void NWidgetBackground::Add(std::unique_ptr<NWidgetBase> &&nwid)
{
if (this->child == nullptr) {
this->child = new NWidgetVertical();
this->child = std::make_unique<NWidgetVertical>();
}
nwid->parent = this->child;
this->child->Add(nwid);
nwid->parent = this->child.get();
this->child->Add(std::move(nwid));
}
/**
@ -2210,7 +2158,7 @@ void NWidgetBackground::Add(NWidgetBase *nwid)
void NWidgetBackground::SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_post)
{
if (this->child == nullptr) {
this->child = new NWidgetVertical();
this->child = std::make_unique<NWidgetVertical>();
}
this->child->parent = this;
this->child->SetPIP(pip_pre, pip_inter, pip_post);
@ -2229,7 +2177,7 @@ void NWidgetBackground::SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_p
void NWidgetBackground::SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post)
{
if (this->child == nullptr) {
this->child = new NWidgetVertical();
this->child = std::make_unique<NWidgetVertical>();
}
this->child->parent = this;
this->child->SetPIPRatio(pip_ratio_pre, pip_ratio_inter, pip_ratio_post);
@ -3090,60 +3038,60 @@ bool NWidgetLeaf::ButtonHit(const Point &pt)
* @param fill_dest Fill the composed widget with child widgets.
* @return Pointer to remaining nested widget parts.
*/
static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetBase **dest, bool *fill_dest)
static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, std::unique_ptr<NWidgetBase> &dest, bool *fill_dest)
{
*dest = nullptr;
dest = nullptr;
*fill_dest = false;
while (nwid_begin < nwid_end) {
switch (nwid_begin->type) {
case NWID_SPACER:
if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetSpacer(0, 0);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetSpacer>(0, 0);
break;
case NWID_HORIZONTAL:
if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetHorizontal(nwid_begin->u.cont_flags);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetHorizontal>(nwid_begin->u.cont_flags);
*fill_dest = true;
break;
case NWID_HORIZONTAL_LTR:
if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetHorizontalLTR(nwid_begin->u.cont_flags);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetHorizontalLTR>(nwid_begin->u.cont_flags);
*fill_dest = true;
break;
case WWT_PANEL:
case WWT_INSET:
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);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetBackground>(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index);
*fill_dest = true;
break;
case NWID_VERTICAL:
if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetVertical(nwid_begin->u.cont_flags);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetVertical>(nwid_begin->u.cont_flags);
*fill_dest = true;
break;
case NWID_MATRIX: {
if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetMatrix(nwid_begin->u.widget.colour, nwid_begin->u.widget.index);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetMatrix>(nwid_begin->u.widget.colour, nwid_begin->u.widget.index);
*fill_dest = true;
break;
}
case WPT_FUNCTION: {
if (*dest != nullptr) return nwid_begin;
*dest = nwid_begin->u.func_ptr();
if (dest != nullptr) return nwid_begin;
dest = nwid_begin->u.func_ptr();
*fill_dest = false;
break;
}
case WPT_RESIZE: {
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(dest.get());
if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_RESIZE requires NWidgetResizeBase");
assert(nwid_begin->u.xy.x >= 0 && nwid_begin->u.xy.y >= 0);
nwrb->SetResize(nwid_begin->u.xy.x, nwid_begin->u.xy.y);
@ -3151,7 +3099,7 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
}
case WPT_MINSIZE: {
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(dest.get());
if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_MINSIZE requires NWidgetResizeBase");
assert(nwid_begin->u.xy.x >= 0 && nwid_begin->u.xy.y >= 0);
nwrb->SetMinimalSize(nwid_begin->u.xy.x, nwid_begin->u.xy.y);
@ -3159,7 +3107,7 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
}
case WPT_MINTEXTLINES: {
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(dest.get());
if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_MINTEXTLINES requires NWidgetResizeBase");
assert(nwid_begin->u.text_lines.size >= FS_BEGIN && nwid_begin->u.text_lines.size < FS_END);
nwrb->SetMinimalTextLines(nwid_begin->u.text_lines.lines, nwid_begin->u.text_lines.spacing, nwid_begin->u.text_lines.size);
@ -3167,28 +3115,28 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
}
case WPT_TEXTSTYLE: {
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(dest.get());
if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_TEXTSTYLE requires NWidgetCore");
nwc->SetTextStyle(nwid_begin->u.text_style.colour, nwid_begin->u.text_style.size);
break;
}
case WPT_ALIGNMENT: {
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(dest.get());
if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_ALIGNMENT requires NWidgetCore");
nwc->SetAlignment(nwid_begin->u.align.align);
break;
}
case WPT_FILL: {
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(*dest);
NWidgetResizeBase *nwrb = dynamic_cast<NWidgetResizeBase *>(dest.get());
if (unlikely(nwrb == nullptr)) throw std::runtime_error("WPT_FILL requires NWidgetResizeBase");
nwrb->SetFill(nwid_begin->u.xy.x, nwid_begin->u.xy.y);
break;
}
case WPT_DATATIP: {
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(dest.get());
if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_DATATIP requires NWidgetCore");
nwc->widget_data = nwid_begin->u.data_tip.data;
nwc->tool_tip = nwid_begin->u.data_tip.tooltip;
@ -3196,15 +3144,15 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
}
case WPT_PADDING:
if (unlikely(*dest == nullptr)) throw std::runtime_error("WPT_PADDING requires NWidgetBase");
(*dest)->SetPadding(nwid_begin->u.padding);
if (unlikely(dest == nullptr)) throw std::runtime_error("WPT_PADDING requires NWidgetBase");
dest->SetPadding(nwid_begin->u.padding);
break;
case WPT_PIPSPACE: {
NWidgetPIPContainer *nwc = dynamic_cast<NWidgetPIPContainer *>(*dest);
NWidgetPIPContainer *nwc = dynamic_cast<NWidgetPIPContainer *>(dest.get());
if (nwc != nullptr) nwc->SetPIP(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post);
NWidgetBackground *nwb = dynamic_cast<NWidgetBackground *>(*dest);
NWidgetBackground *nwb = dynamic_cast<NWidgetBackground *>(dest.get());
if (nwb != nullptr) nwb->SetPIP(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post);
if (unlikely(nwc == nullptr && nwb == nullptr)) throw std::runtime_error("WPT_PIPSPACE requires NWidgetPIPContainer or NWidgetBackground");
@ -3212,10 +3160,10 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
}
case WPT_PIPRATIO: {
NWidgetPIPContainer *nwc = dynamic_cast<NWidgetPIPContainer *>(*dest);
NWidgetPIPContainer *nwc = dynamic_cast<NWidgetPIPContainer *>(dest.get());
if (nwc != nullptr) nwc->SetPIPRatio(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post);
NWidgetBackground *nwb = dynamic_cast<NWidgetBackground *>(*dest);
NWidgetBackground *nwb = dynamic_cast<NWidgetBackground *>(dest.get());
if (nwb != nullptr) nwb->SetPIPRatio(nwid_begin->u.pip.pre, nwid_begin->u.pip.inter, nwid_begin->u.pip.post);
if (unlikely(nwc == nullptr && nwb == nullptr)) throw std::runtime_error("WPT_PIPRATIO requires NWidgetPIPContainer or NWidgetBackground");
@ -3223,7 +3171,7 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
}
case WPT_SCROLLBAR: {
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(*dest);
NWidgetCore *nwc = dynamic_cast<NWidgetCore *>(dest.get());
if (unlikely(nwc == nullptr)) throw std::runtime_error("WPT_SCROLLBAR requires NWidgetCore");
nwc->scrollbar_index = nwid_begin->u.widget.index;
break;
@ -3233,27 +3181,27 @@ static const NWidgetPart *MakeNWidget(const NWidgetPart *nwid_begin, const NWidg
return nwid_begin;
case NWID_VIEWPORT:
if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetViewport(nwid_begin->u.widget.index);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetViewport>(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);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetScrollbar>(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index);
break;
case NWID_SELECTION: {
if (*dest != nullptr) return nwid_begin;
*dest = new NWidgetStacked(nwid_begin->u.widget.index);
if (dest != nullptr) return nwid_begin;
dest = std::make_unique<NWidgetStacked>(nwid_begin->u.widget.index);
*fill_dest = true;
break;
}
default:
if (*dest != nullptr) return nwid_begin;
if (dest != nullptr) return nwid_begin;
assert((nwid_begin->type & WWT_MASK) < WWT_LAST || (nwid_begin->type & WWT_MASK) == NWID_BUTTON_DROPDOWN);
*dest = new NWidgetLeaf(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index, 0x0, STR_NULL);
dest = std::make_unique<NWidgetLeaf>(nwid_begin->type, nwid_begin->u.widget.colour, nwid_begin->u.widget.index, 0x0, STR_NULL);
break;
}
nwid_begin++;
@ -3280,33 +3228,32 @@ bool IsContainerWidgetType(WidgetType tp)
* @param parent Pointer or container to use for storing the child widgets (*parent == nullptr or *parent == container or background widget).
* @return Pointer to remaining nested widget parts.
*/
static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetBase **parent)
static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, std::unique_ptr<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. */
NWidgetContainer *nwid_cont = dynamic_cast<NWidgetContainer *>(*parent);
NWidgetBackground *nwid_parent = dynamic_cast<NWidgetBackground *>(*parent);
assert(*parent == nullptr || (nwid_cont != nullptr && nwid_parent == nullptr) || (nwid_cont == nullptr && nwid_parent != nullptr));
NWidgetContainer *nwid_cont = dynamic_cast<NWidgetContainer *>(parent.get());
NWidgetBackground *nwid_parent = dynamic_cast<NWidgetBackground *>(parent.get());
assert(parent == nullptr || (nwid_cont != nullptr && nwid_parent == nullptr) || (nwid_cont == nullptr && nwid_parent != nullptr));
for (;;) {
NWidgetBase *sub_widget = nullptr;
std::unique_ptr<NWidgetBase> sub_widget = nullptr;
bool fill_sub = false;
nwid_begin = MakeNWidget(nwid_begin, nwid_end, &sub_widget, &fill_sub);
nwid_begin = MakeNWidget(nwid_begin, nwid_end, sub_widget, &fill_sub);
/* Break out of loop when end reached */
if (sub_widget == nullptr) break;
/* 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);
nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, sub_widget);
}
/* Add sub_widget to parent container if available, otherwise return the widget to the caller. */
if (nwid_cont != nullptr) nwid_cont->Add(sub_widget);
if (nwid_parent != nullptr) nwid_parent->Add(sub_widget);
if (nwid_cont != nullptr) nwid_cont->Add(std::move(sub_widget));
if (nwid_parent != nullptr) nwid_parent->Add(std::move(sub_widget));
if (nwid_cont == nullptr && nwid_parent == nullptr) {
*parent = sub_widget;
parent = std::move(sub_widget);
return nwid_begin;
}
}
@ -3326,15 +3273,14 @@ static const NWidgetPart *MakeWidgetTree(const NWidgetPart *nwid_begin, const NW
* @return Root of the nested widget tree, a vertical container containing the entire GUI.
* @ingroup NestedWidgetParts
*/
NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetContainer *container)
std::unique_ptr<NWidgetBase> MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, std::unique_ptr<NWidgetBase> &&container)
{
if (container == nullptr) container = new NWidgetVertical();
NWidgetBase *cont_ptr = container;
[[maybe_unused]] const NWidgetPart *nwid_part = MakeWidgetTree(nwid_begin, nwid_end, &cont_ptr);
if (container == nullptr) container = std::make_unique<NWidgetVertical>();
[[maybe_unused]] const NWidgetPart *nwid_part = MakeWidgetTree(nwid_begin, nwid_end, container);
#ifdef WITH_ASSERT
if (unlikely(nwid_part != nwid_end)) throw std::runtime_error("Did not consume all NWidgetParts");
#endif
return container;
return std::move(container);
}
/**
@ -3347,38 +3293,33 @@ NWidgetContainer *MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart
* @return Root of the nested widget tree, a vertical container containing the entire GUI.
* @ingroup NestedWidgetParts
*/
NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetStacked **shade_select)
std::unique_ptr<NWidgetBase> MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetStacked **shade_select)
{
*shade_select = nullptr;
/* Read the first widget recursively from the array. */
NWidgetBase *nwid = nullptr;
nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, &nwid);
std::unique_ptr<NWidgetBase> nwid = nullptr;
nwid_begin = MakeWidgetTree(nwid_begin, nwid_end, nwid);
assert(nwid != nullptr);
NWidgetContainer *root = new NWidgetVertical;
root->Add(nwid);
if (nwid_begin == nwid_end) { // There is no body at all.
*shade_select = nullptr;
NWidgetHorizontal *hor_cont = dynamic_cast<NWidgetHorizontal *>(nwid.get());
auto root = std::make_unique<NWidgetVertical>();
root->Add(std::move(nwid));
if (nwid_begin == nwid_end) return root; // There is no body at all.
if (hor_cont != nullptr && hor_cont->GetWidgetOfType(WWT_CAPTION) != nullptr && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != nullptr) {
/* If the first widget has a title bar and a shade box, silently add a shade selection widget in the tree. */
auto shade_stack = std::make_unique<NWidgetStacked>(-1);
*shade_select = shade_stack.get();
/* Load the remaining parts into the shade stack. */
shade_stack->Add(MakeNWidgets(nwid_begin, nwid_end, std::make_unique<NWidgetVertical>()));
root->Add(std::move(shade_stack));
return root;
}
/* If the first widget looks like a titlebar, treat it as such.
* If it has a shading box, silently add a shade selection widget in the tree. */
NWidgetHorizontal *hor_cont = dynamic_cast<NWidgetHorizontal *>(nwid);
NWidgetContainer *body;
if (hor_cont != nullptr && hor_cont->GetWidgetOfType(WWT_CAPTION) != nullptr && hor_cont->GetWidgetOfType(WWT_SHADEBOX) != nullptr) {
*shade_select = new NWidgetStacked(-1);
root->Add(*shade_select);
body = new NWidgetVertical;
(*shade_select)->Add(body);
} else {
*shade_select = nullptr;
body = root;
}
/* Load the remaining parts into 'body'. */
MakeNWidgets(nwid_begin, nwid_end, body);
return root;
/* Load the remaining parts into 'root'. */
return MakeNWidgets(nwid_begin, nwid_end, std::move(root));
}
/**
@ -3390,11 +3331,11 @@ NWidgetContainer *MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWi
* @param button_tooltip The tooltip-string of every button.
* @return Panel with rows of company buttons.
*/
NWidgetBase *MakeCompanyButtonRows(WidgetID widget_first, WidgetID widget_last, Colours button_colour, int max_length, StringID button_tooltip)
std::unique_ptr<NWidgetBase> MakeCompanyButtonRows(WidgetID widget_first, WidgetID widget_last, Colours button_colour, int max_length, StringID button_tooltip)
{
assert(max_length >= 1);
NWidgetVertical *vert = nullptr; // Storage for all rows.
NWidgetHorizontal *hor = nullptr; // Storage for buttons in one row.
std::unique_ptr<NWidgetVertical> vert = nullptr; // Storage for all rows.
std::unique_ptr<NWidgetHorizontal> hor = nullptr; // Storage for buttons in one row.
int hor_length = 0;
Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON, nullptr, ZOOM_LVL_OUT_4X);
@ -3404,33 +3345,33 @@ NWidgetBase *MakeCompanyButtonRows(WidgetID widget_first, WidgetID widget_last,
for (WidgetID widnum = widget_first; widnum <= widget_last; widnum++) {
/* Ensure there is room in 'hor' for another button. */
if (hor_length == max_length) {
if (vert == nullptr) vert = new NWidgetVertical();
vert->Add(hor);
if (vert == nullptr) vert = std::make_unique<NWidgetVertical>();
vert->Add(std::move(hor));
hor = nullptr;
hor_length = 0;
}
if (hor == nullptr) {
hor = new NWidgetHorizontal();
hor = std::make_unique<NWidgetHorizontal>();
hor_length = 0;
}
NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, button_colour, widnum);
auto panel = std::make_unique<NWidgetBackground>(WWT_PANEL, button_colour, widnum);
panel->SetMinimalSize(sprite_size.width, sprite_size.height);
panel->SetFill(1, 1);
panel->SetResize(1, 0);
panel->SetDataTip(0x0, button_tooltip);
hor->Add(panel);
hor->Add(std::move(panel));
hor_length++;
}
if (vert == nullptr) return hor; // All buttons fit in a single row.
if (hor_length > 0 && hor_length < max_length) {
/* Last row is partial, add a spacer at the end to force all buttons to the left. */
NWidgetSpacer *spc = new NWidgetSpacer(sprite_size.width, sprite_size.height);
auto spc = std::make_unique<NWidgetSpacer>(sprite_size.width, sprite_size.height);
spc->SetFill(1, 1);
spc->SetResize(1, 0);
hor->Add(spc);
hor->Add(std::move(spc));
}
if (hor != nullptr) vert->Add(hor);
if (hor != nullptr) vert->Add(std::move(hor));
return vert;
}

View File

@ -84,6 +84,7 @@ enum WidgetType {
NWID_BUTTON_DROPDOWN, ///< Button with a drop-down.
NWID_HSCROLLBAR, ///< Horizontal scrollbar
NWID_VSCROLLBAR, ///< Vertical scrollbar
NWID_CUSTOM, ///< General Custom widget.
/* Nested widget part types. */
WPT_RESIZE, ///< Widget part for specifying resizing.
@ -235,9 +236,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,24 +444,22 @@ 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);
void Add(std::unique_ptr<NWidgetBase> &&wid);
void FillWidgetLookup(WidgetLookup &widget_lookup) override;
void Draw(const Window *w) override;
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<std::unique_ptr<NWidgetBase>> children; ///< Child widgets in contaier.
};
/** Display planes with zero size for #NWidgetStacked. */
@ -636,10 +632,9 @@ public:
*/
class NWidgetBackground : public NWidgetCore {
public:
NWidgetBackground(WidgetType tp, Colours colour, WidgetID index, NWidgetPIPContainer *child = nullptr);
~NWidgetBackground();
NWidgetBackground(WidgetType tp, Colours colour, WidgetID index, std::unique_ptr<NWidgetPIPContainer> &&child = nullptr);
void Add(NWidgetBase *nwid);
void Add(std::unique_ptr<NWidgetBase> &&nwid);
void SetPIP(uint8_t pip_pre, uint8_t pip_inter, uint8_t pip_post);
void SetPIPRatio(uint8_t pip_ratio_pre, uint8_t pip_ratio_inter, uint8_t pip_ratio_post);
@ -654,7 +649,7 @@ public:
NWidgetBase *GetWidgetOfType(WidgetType tp) override;
private:
NWidgetPIPContainer *child; ///< Child widget.
std::unique_ptr<NWidgetPIPContainer> child; ///< Child widget.
};
/**
@ -1034,7 +1029,7 @@ struct NWidgetPartAlignment {
* Pointer to function returning a nested widget.
* @return Nested widget (tree).
*/
typedef NWidgetBase *NWidgetFunctionType();
typedef std::unique_ptr<NWidgetBase> NWidgetFunctionType();
/**
* Partial widget specification to allow NWidgets to be written nested.
@ -1358,10 +1353,10 @@ static inline NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
}
bool IsContainerWidgetType(WidgetType tp);
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);
std::unique_ptr<NWidgetBase> MakeNWidgets(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, std::unique_ptr<NWidgetBase> &&container);
std::unique_ptr<NWidgetBase> MakeWindowNWidgetTree(const NWidgetPart *nwid_begin, const NWidgetPart *nwid_end, NWidgetStacked **shade_select);
NWidgetBase *MakeCompanyButtonRows(WidgetID widget_first, WidgetID widget_last, Colours button_colour, int max_length, StringID button_tooltip);
std::unique_ptr<NWidgetBase> MakeCompanyButtonRows(WidgetID widget_first, WidgetID widget_last, Colours button_colour, int max_length, StringID button_tooltip);
void SetupWidgetDimensions();

View File

@ -1088,7 +1088,6 @@ Window::~Window()
assert(*this->z_position == nullptr);
if (this->viewport != nullptr) DeleteWindowViewport(this);
delete this->nested_root;
}
/**

View File

@ -259,7 +259,7 @@ public:
ViewportData *viewport; ///< Pointer to viewport data, if present.
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.
std::unique_ptr<NWidgetBase> nested_root; ///< Root of the nested tree.
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).