Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2025-05-14 18:41:13 +05:00
994 changed files with 38753 additions and 34512 deletions
+144 -121
View File
@@ -26,7 +26,8 @@
#include "window_func.h"
#include "timer/timer_game_calendar.h"
#include "vehicle_func.h"
#include "widgets/dropdown_func.h"
#include "dropdown_type.h"
#include "dropdown_func.h"
#include "engine_gui.h"
#include "cargotype.h"
#include "core/geometry_func.hpp"
@@ -98,7 +99,7 @@ static constexpr NWidgetPart _nested_build_vehicle_widgets[] = {
bool _engine_sort_direction; ///< \c false = descending, \c true = ascending.
byte _engine_sort_last_criteria[] = {0, 0, 0, 0}; ///< Last set sort criteria, for each vehicle type.
uint8_t _engine_sort_last_criteria[] = {0, 0, 0, 0}; ///< Last set sort criteria, for each vehicle type.
bool _engine_sort_last_order[] = {false, false, false, false}; ///< Last set direction of the sort order, for each vehicle type.
bool _engine_sort_show_hidden_engines[] = {false, false, false, false}; ///< Last set 'show hidden engines' setting for each vehicle type.
static CargoID _engine_sort_last_cargo_criteria[] = {CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY, CargoFilterCriteria::CF_ANY}; ///< Last set filter criteria, for each vehicle type.
@@ -486,7 +487,7 @@ EngList_SortTypeFunction * const _engine_sort_functions[][11] = {{
}};
/** Dropdown menu strings for the vehicle sort criteria. */
const StringID _engine_sort_listing[][12] = {{
const std::initializer_list<const StringID> _engine_sort_listing[] = {{
/* Trains */
STR_SORT_BY_ENGINE_ID,
STR_SORT_BY_COST,
@@ -499,7 +500,6 @@ const StringID _engine_sort_listing[][12] = {{
STR_SORT_BY_POWER_VS_RUNNING_COST,
STR_SORT_BY_RELIABILITY,
STR_SORT_BY_CARGO_CAPACITY,
INVALID_STRING_ID
}, {
/* Road vehicles */
STR_SORT_BY_ENGINE_ID,
@@ -513,7 +513,6 @@ const StringID _engine_sort_listing[][12] = {{
STR_SORT_BY_POWER_VS_RUNNING_COST,
STR_SORT_BY_RELIABILITY,
STR_SORT_BY_CARGO_CAPACITY,
INVALID_STRING_ID
}, {
/* Ships */
STR_SORT_BY_ENGINE_ID,
@@ -524,7 +523,6 @@ const StringID _engine_sort_listing[][12] = {{
STR_SORT_BY_RUNNING_COST,
STR_SORT_BY_RELIABILITY,
STR_SORT_BY_CARGO_CAPACITY,
INVALID_STRING_ID
}, {
/* Aircraft */
STR_SORT_BY_ENGINE_ID,
@@ -536,11 +534,10 @@ const StringID _engine_sort_listing[][12] = {{
STR_SORT_BY_RELIABILITY,
STR_SORT_BY_CARGO_CAPACITY,
STR_SORT_BY_RANGE,
INVALID_STRING_ID
}};
/** Filters vehicles by cargo and engine (in case of rail vehicle). */
static bool CDECL CargoAndEngineFilter(const GUIEngineListItem *item, const CargoID cid)
static bool CargoAndEngineFilter(const GUIEngineListItem *item, const CargoID cid)
{
if (cid == CargoFilterCriteria::CF_ANY) {
return true;
@@ -552,7 +549,7 @@ static bool CDECL CargoAndEngineFilter(const GUIEngineListItem *item, const Carg
}
}
static GUIEngineList::FilterFunction * const _filter_funcs[] = {
static GUIEngineList::FilterFunction * const _engine_filter_funcs[] = {
&CargoAndEngineFilter,
};
@@ -1008,18 +1005,16 @@ int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number,
* @param type Type of vehicle (VEH_*)
* @param r The Rect of the list
* @param eng_list What engines to draw
* @param min where to start in the list
* @param max where in the list to end
* @param sb Scrollbar of list.
* @param selected_id what engine to highlight as selected, if any
* @param show_count Whether to show the amount of engines or not
* @param selected_group the group to list the engines of
*/
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, uint16_t min, uint16_t max, EngineID selected_id, bool show_count, GroupID selected_group)
void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_list, const Scrollbar &sb, EngineID selected_id, bool show_count, GroupID selected_group)
{
static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
/* Obligatory sanity checks! */
assert(max <= eng_list.size());
auto [first, last] = sb.GetVisibleRangeIterators(eng_list);
bool rtl = _current_text_dir == TD_RTL;
int step_size = GetEngineListHeight(type);
@@ -1027,7 +1022,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
int sprite_right = GetVehicleImageCellSize(type, EIT_PURCHASE).extend_right;
int sprite_width = sprite_left + sprite_right;
int circle_width = std::max(GetScaledSpriteSize(SPR_CIRCLE_FOLDED).width, GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED).width);
int linecolour = _colour_gradient[COLOUR_ORANGE][4];
int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
Rect ir = r.WithHeight(step_size).Shrink(WidgetDimensions::scaled.matrix);
int sprite_y_offset = ScaleSpriteTrad(sprite_y_offsets[type]) + ir.Height() / 2;
@@ -1038,9 +1033,8 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
replace_icon = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
uint biggest_num_engines = 0;
for (auto i = min; i < max; i++) {
const auto &item = eng_list[i];
const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
for (auto it = first; it != last; ++it) {
const uint num_engines = GetGroupNumEngines(_local_company, selected_group, it->engine_id);
biggest_num_engines = std::max(biggest_num_engines, num_engines);
}
@@ -1057,13 +1051,31 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
int small_text_y_offset = ir.Height() - GetCharacterHeight(FS_SMALL);
int replace_icon_y_offset = (ir.Height() - replace_icon.height) / 2;
const int offset = (rtl ? -circle_width : circle_width) / 2;
const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
int y = ir.top;
for (; min < max; min++, y += step_size) {
const auto &item = eng_list[min];
for (auto it = first; it != last; ++it) {
const auto &item = *it;
uint indent = item.indent * WidgetDimensions::scaled.hsep_indent;
bool has_variants = (item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None;
bool is_folded = (item.flags & EngineDisplayFlags::IsFolded) != EngineDisplayFlags::None;
bool shaded = (item.flags & EngineDisplayFlags::Shaded) != EngineDisplayFlags::None;
bool has_variants = HasFlag(item.flags, EngineDisplayFlags::HasVariants);
bool is_folded = HasFlag(item.flags, EngineDisplayFlags::IsFolded);
bool shaded = HasFlag(item.flags, EngineDisplayFlags::Shaded);
if (item.indent > 0) {
/* Draw tree continuation lines. */
int tx = (rtl ? ir.right : ir.left) + offset;
int ty = y - WidgetDimensions::scaled.matrix.top;
for (uint lvl = 1; lvl <= item.indent; ++lvl) {
if (HasBit(item.level_mask, lvl)) GfxDrawLine(tx, ty, tx, ty + step_size - 1, linecolour, WidgetDimensions::scaled.fullbevel.top);
if (lvl < item.indent) tx += level_width;
}
/* Draw our node in the tree. */
int ycentre = y + normal_text_y_offset + GetCharacterHeight(FS_NORMAL) / 2 - 1;
if (!HasBit(item.level_mask, item.indent)) GfxDrawLine(tx, ty, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
}
/* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
const uint num_engines = GetGroupNumEngines(_local_company, selected_group, item.engine_id);
@@ -1091,14 +1103,7 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
Rect fr = ir.Indent(indent, rtl).WithWidth(circle_width, rtl);
DrawSpriteIgnorePadding(is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, {fr.left, y, fr.right, y + ir.Height() - 1}, SA_CENTER);
}
if (indent > 0) {
/* Draw tree lines */
Rect fr = ir.Indent(indent - WidgetDimensions::scaled.hsep_indent, rtl).WithWidth(circle_width, rtl);
int ycenter = y + normal_text_y_offset + GetCharacterHeight(FS_NORMAL) / 2;
bool continues = (min + 1U) < eng_list.size() && eng_list[min + 1].indent == item.indent;
GfxDrawLine(fr.left + circle_width / 2, y - WidgetDimensions::scaled.matrix.top, fr.left + circle_width / 2, continues ? y - WidgetDimensions::scaled.matrix.top + step_size - 1 : ycenter, linecolour, WidgetDimensions::scaled.fullbevel.top);
GfxDrawLine(fr.left + circle_width / 2, ycenter, fr.right, ycenter, linecolour, WidgetDimensions::scaled.fullbevel.top);
}
y += step_size;
}
}
@@ -1125,6 +1130,44 @@ void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selecte
ShowDropDownMenu(w, _engine_sort_listing[vehicle_type], selected, button, 0, hidden_mask);
}
/**
* Add children to GUI engine list to build a hierarchical tree.
* @param dst Destination list.
* @param src Source list.
* @param parent Current tree parent (set by self with recursion).
* @param indent Current tree indentation level (set by self with recursion).
*/
void GUIEngineListAddChildren(GUIEngineList &dst, const GUIEngineList &src, EngineID parent, uint8_t indent)
{
for (const auto &item : src) {
if (item.variant_id != parent || item.engine_id == parent) continue;
const Engine *e = Engine::Get(item.engine_id);
EngineDisplayFlags flags = item.flags;
if (e->display_last_variant != INVALID_ENGINE) flags &= ~EngineDisplayFlags::Shaded;
dst.emplace_back(e->display_last_variant == INVALID_ENGINE ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent);
/* Add variants if not folded */
if (HasFlag(item.flags, EngineDisplayFlags::HasVariants) && !HasFlag(item.flags, EngineDisplayFlags::IsFolded)) {
/* Add this engine again as a child */
if (!HasFlag(item.flags, EngineDisplayFlags::Shaded)) {
dst.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags::None, indent + 1);
}
GUIEngineListAddChildren(dst, src, item.engine_id, indent + 1);
}
}
if (indent > 0 || dst.empty()) return;
/* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
uint16_t level_mask = 0;
for (auto it = std::rbegin(dst); std::next(it) != std::rend(dst); ++it) {
auto next_it = std::next(it);
SB(level_mask, it->indent, 1, it->indent <= next_it->indent);
next_it->level_mask = level_mask;
}
}
/** Enum referring to the Hotkeys in the build vehicle window */
enum BuildVehicleHotkeys {
BVHK_FOCUS_FILTER_BOX, ///< Focus the edit box for editing the filter string
@@ -1138,7 +1181,7 @@ struct BuildVehicleWindow : Window {
RoadType roadtype; ///< Road type to show, or #INVALID_ROADTYPE.
} filter; ///< Filter to apply.
bool descending_sort_order; ///< Sort direction, @see _engine_sort_direction
byte sort_criteria; ///< Current sort criterium.
uint8_t sort_criteria; ///< Current sort criterium.
bool show_hidden_engines; ///< State of the 'show hidden engines' button.
bool listview_mode; ///< If set, only display the available vehicles and do not show a 'build' button.
EngineID sel_engine; ///< Currently selected engine, or #INVALID_ENGINE
@@ -1169,28 +1212,7 @@ struct BuildVehicleWindow : Window {
}
}
void AddChildren(const GUIEngineList &source, EngineID parent, int indent)
{
for (const auto &item : source) {
if (item.variant_id != parent || item.engine_id == parent) continue;
const Engine *e = Engine::Get(item.engine_id);
EngineDisplayFlags flags = item.flags;
if (e->display_last_variant != INVALID_ENGINE) flags &= ~EngineDisplayFlags::Shaded;
this->eng_list.emplace_back(e->display_last_variant == INVALID_ENGINE ? item.engine_id : e->display_last_variant, item.engine_id, flags, indent);
/* Add variants if not folded */
if ((item.flags & (EngineDisplayFlags::HasVariants | EngineDisplayFlags::IsFolded)) == EngineDisplayFlags::HasVariants) {
/* Add this engine again as a child */
if ((item.flags & EngineDisplayFlags::Shaded) == EngineDisplayFlags::None) {
this->eng_list.emplace_back(item.engine_id, item.engine_id, EngineDisplayFlags::None, indent + 1);
}
AddChildren(source, item.engine_id, indent + 1);
}
}
}
BuildVehicleWindow(WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc), vehicle_editbox(MAX_LENGTH_VEHICLE_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_VEHICLE_NAME_CHARS)
BuildVehicleWindow(WindowDesc &desc, TileIndex tile, VehicleType type) : Window(desc), vehicle_editbox(MAX_LENGTH_VEHICLE_NAME_CHARS * MAX_CHAR_LENGTH, MAX_LENGTH_VEHICLE_NAME_CHARS)
{
this->vehicle_type = type;
this->listview_mode = tile == INVALID_TILE;
@@ -1248,7 +1270,7 @@ struct BuildVehicleWindow : Window {
/* Select the first unshaded engine in the list as default when opening the window */
EngineID engine = INVALID_ENGINE;
auto it = std::find_if(this->eng_list.begin(), this->eng_list.end(), [&](GUIEngineListItem &item){ return (item.flags & EngineDisplayFlags::Shaded) == EngineDisplayFlags::None; });
auto it = std::ranges::find_if(this->eng_list, [&](GUIEngineListItem &item) { return !HasFlag(item.flags, EngineDisplayFlags::Shaded); });
if (it != this->eng_list.end()) engine = it->engine_id;
this->SelectEngine(engine);
}
@@ -1300,7 +1322,7 @@ struct BuildVehicleWindow : Window {
this->cargo_filter_criteria = _engine_sort_last_cargo_criteria[this->vehicle_type];
if (this->cargo_filter_criteria < NUM_CARGO && !HasBit(_standard_cargo_mask, this->cargo_filter_criteria)) this->cargo_filter_criteria = CargoFilterCriteria::CF_ANY;
this->eng_list.SetFilterFuncs(_filter_funcs);
this->eng_list.SetFilterFuncs(_engine_filter_funcs);
this->eng_list.SetFilterState(this->cargo_filter_criteria != CargoFilterCriteria::CF_ANY);
}
@@ -1347,7 +1369,7 @@ struct BuildVehicleWindow : Window {
if (0 == this->eng_list.size()) { // no engine passed through the filter, invalidate the previously selected engine
// CM this->SelectEngine(INVALID_ENGINE);
return INVALID_ENGINE;
} else if (std::find(this->eng_list.begin(), this->eng_list.end(), this->sel_engine) == this->eng_list.end()) { // previously selected engine didn't pass the filter, select the first engine of the list
} else if (std::ranges::find(this->eng_list, this->sel_engine, &GUIEngineListItem::engine_id) == this->eng_list.end()) { // previously selected engine didn't pass the filter, select the first engine of the list
// CM this->SelectEngine(this->eng_list[0].engine_id);
return this->eng_list[0].engine_id;
}
@@ -1431,7 +1453,7 @@ struct BuildVehicleWindow : Window {
/* ensure primary engine of variant group is in list */
for (const auto &variant : variants) {
if (std::find(list.begin(), list.end(), variant) == list.end()) {
if (std::ranges::find(list, variant, &GUIEngineListItem::engine_id) == list.end()) {
const Engine *e = Engine::Get(variant);
list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlags::Shaded, 0);
if (e->u.rail.railveh_type != RAILVEH_WAGON) num_engines++;
@@ -1571,8 +1593,7 @@ struct BuildVehicleWindow : Window {
default: NOT_REACHED();
case VEH_TRAIN:
sel_id = this->GenerateBuildTrainList(list); // CM
AddChildren(list, INVALID_ENGINE, 0);
this->eng_list.shrink_to_fit();
GUIEngineListAddChildren(this->eng_list, list);
this->eng_list.RebuildDone();
return sel_id; // CM
case VEH_ROAD:
@@ -1599,7 +1620,7 @@ struct BuildVehicleWindow : Window {
}
for (const auto &variant : variants) {
if (std::find(this->eng_list.begin(), this->eng_list.end(), variant) == this->eng_list.end()) {
if (std::ranges::find(this->eng_list, variant, &GUIEngineListItem::engine_id) == this->eng_list.end()) {
const Engine *e = Engine::Get(variant);
this->eng_list.emplace_back(variant, e->info.variant_id, e->display_flags | EngineDisplayFlags::Shaded, 0);
}
@@ -1609,8 +1630,7 @@ struct BuildVehicleWindow : Window {
EngList_Sort(this->eng_list, _engine_sort_functions[this->vehicle_type][this->sort_criteria]);
this->eng_list.swap(list);
AddChildren(list, INVALID_ENGINE, 0);
this->eng_list.shrink_to_fit();
GUIEngineListAddChildren(this->eng_list, list, INVALID_ENGINE, 0);
this->eng_list.RebuildDone();
return sel_id; // CM
@@ -1621,25 +1641,54 @@ struct BuildVehicleWindow : Window {
DropDownList list;
/* Add item for disabling filtering. */
list.push_back(std::make_unique<DropDownListStringItem>(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY, false));
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ANY), CargoFilterCriteria::CF_ANY));
/* Specific filters for trains. */
if (this->vehicle_type == VEH_TRAIN) {
/* Add item for locomotives only in case of trains. */
list.push_back(std::make_unique<DropDownListStringItem>(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ENGINES), CargoFilterCriteria::CF_ENGINES, false));
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_ENGINES), CargoFilterCriteria::CF_ENGINES));
/* Add item for vehicles not carrying anything, e.g. train engines.
* This could also be useful for eyecandy vehicles of other types, but is likely too confusing for joe, */
list.push_back(std::make_unique<DropDownListStringItem>(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE, false));
list.push_back(MakeDropDownListStringItem(this->GetCargoFilterLabel(CargoFilterCriteria::CF_NONE), CargoFilterCriteria::CF_NONE));
}
/* Add cargos */
Dimension d = GetLargestCargoIconSize();
for (const CargoSpec *cs : _sorted_standard_cargo_specs) {
list.push_back(std::make_unique<DropDownListIconItem>(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index(), false));
list.push_back(MakeDropDownListIconItem(d, cs->GetCargoIcon(), PAL_NONE, cs->name, cs->Index()));
}
return list;
}
void BuildVehicle()
{
EngineID sel_eng = this->sel_engine;
if (sel_eng == INVALID_ENGINE) return;
CargoID cargo = this->cargo_filter_criteria;
if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
if (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) {
Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, this->window_number, sel_eng, true, cargo, INVALID_CLIENT_ID);
} else {
Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, this->window_number, sel_eng, true, cargo, INVALID_CLIENT_ID);
}
/* Update last used variant in hierarchy and refresh if necessary. */
bool refresh = false;
EngineID parent = sel_eng;
while (parent != INVALID_ENGINE) {
Engine *e = Engine::Get(parent);
refresh |= (e->display_last_variant != sel_eng);
e->display_last_variant = sel_eng;
parent = e->info.variant_id;
}
if (refresh) {
InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
}
}
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
@@ -1664,7 +1713,7 @@ struct BuildVehicleWindow : Window {
if (it != this->eng_list.end()) {
const auto &item = *it;
const Rect r = this->GetWidget<NWidgetBase>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.matrix).WithWidth(WidgetDimensions::scaled.hsep_indent * (item.indent + 1), _current_text_dir == TD_RTL);
if ((item.flags & EngineDisplayFlags::HasVariants) != EngineDisplayFlags::None && IsInsideMM(r.left, r.right, pt.x)) {
if (HasFlag(item.flags, EngineDisplayFlags::HasVariants) && IsInsideMM(r.left, r.right, pt.x)) {
/* toggle folded flag on engine */
assert(item.variant_id != INVALID_ENGINE);
Engine *engine = Engine::Get(item.variant_id);
@@ -1674,7 +1723,7 @@ struct BuildVehicleWindow : Window {
InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
return;
}
if ((item.flags & EngineDisplayFlags::Shaded) == EngineDisplayFlags::None) e = item.engine_id;
if (!HasFlag(item.flags, EngineDisplayFlags::Shaded)) e = item.engine_id;
}
this->SelectEngine(e);
this->SetDirty();
@@ -1702,34 +1751,9 @@ struct BuildVehicleWindow : Window {
break;
}
case WID_BV_BUILD: {
EngineID sel_eng = this->sel_engine;
if (sel_eng != INVALID_ENGINE) {
CargoID cargo = this->cargo_filter_criteria;
if (cargo == CargoFilterCriteria::CF_ANY || cargo == CargoFilterCriteria::CF_ENGINES || cargo == CargoFilterCriteria::CF_NONE) cargo = INVALID_CARGO;
if (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) {
Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildWagon, this->window_number, sel_eng, true, cargo, INVALID_CLIENT_ID);
} else {
Command<CMD_BUILD_VEHICLE>::Post(GetCmdBuildVehMsg(this->vehicle_type), CcBuildPrimaryVehicle, this->window_number, sel_eng, true, cargo, INVALID_CLIENT_ID);
}
/* Update last used variant in hierarchy and refresh if necessary. */
bool refresh = false;
EngineID parent = sel_eng;
while (parent != INVALID_ENGINE) {
Engine *e = Engine::Get(parent);
refresh |= (e->display_last_variant != sel_eng);
e->display_last_variant = sel_eng;
parent = e->info.variant_id;
}
if (refresh) {
InvalidateWindowData(WC_REPLACE_VEHICLE, this->vehicle_type, 0); // Update the autoreplace window
InvalidateWindowClassesData(WC_BUILD_VEHICLE); // The build windows needs updating as well
return;
}
}
case WID_BV_BUILD:
this->BuildVehicle();
break;
}
case WID_BV_RENAME: {
EngineID sel_eng = this->sel_engine;
@@ -1777,7 +1801,7 @@ struct BuildVehicleWindow : Window {
break;
case WID_BV_SORT_DROPDOWN:
SetDParam(0, _engine_sort_listing[this->vehicle_type][this->sort_criteria]);
SetDParam(0, std::data(_engine_sort_listing[this->vehicle_type])[this->sort_criteria]);
break;
case WID_BV_CARGO_FILTER_DROPDOWN:
@@ -1800,43 +1824,43 @@ struct BuildVehicleWindow : Window {
}
}
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
{
switch (widget) {
case WID_BV_LIST:
resize->height = GetEngineListHeight(this->vehicle_type);
size->height = 3 * resize->height;
size->width = std::max(size->width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165) + padding.width;
resize.height = GetEngineListHeight(this->vehicle_type);
size.height = 3 * resize.height;
size.width = std::max(size.width, GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_left + GetVehicleImageCellSize(this->vehicle_type, EIT_PURCHASE).extend_right + 165) + padding.width;
break;
case WID_BV_PANEL:
size->height = GetCharacterHeight(FS_NORMAL) * this->details_height + padding.height;
size.height = GetCharacterHeight(FS_NORMAL) * this->details_height + padding.height;
break;
case WID_BV_SORT_ASCENDING_DESCENDING: {
Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
d.height += padding.height;
*size = maxdim(*size, d);
size = maxdim(size, d);
break;
}
case WID_BV_CARGO_FILTER_DROPDOWN:
size->width = std::max(size->width, GetDropDownListDimension(this->BuildCargoDropDownList()).width + padding.width);
size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList()).width + padding.width);
break;
case WID_BV_BUILD:
*size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
*size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
size->width += padding.width;
size->height += padding.height;
size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + this->vehicle_type);
size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_BUY_REFIT_VEHICLE_BUTTON + this->vehicle_type));
size.width += padding.width;
size.height += padding.height;
break;
case WID_BV_SHOW_HIDE:
*size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
*size = maxdim(*size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
size->width += padding.width;
size->height += padding.height;
size = GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_HIDE_TOGGLE_BUTTON + this->vehicle_type);
size = maxdim(size, GetStringBoundingBox(STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON + this->vehicle_type));
size.width += padding.width;
size.height += padding.height;
break;
}
}
@@ -1849,8 +1873,7 @@ struct BuildVehicleWindow : Window {
this->vehicle_type,
r,
this->eng_list,
this->vscroll->GetPosition(),
static_cast<uint16_t>(std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.size())),
*this->vscroll,
this->sel_engine,
false,
DEFAULT_GROUP
@@ -1891,7 +1914,7 @@ struct BuildVehicleWindow : Window {
int needed_height = this->details_height;
/* Draw details panels. */
if (this->sel_engine != INVALID_ENGINE) {
const Rect r = this->GetWidget<NWidgetBase>(WID_BV_PANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, WidgetDimensions::scaled.framerect);
const Rect r = this->GetWidget<NWidgetBase>(WID_BV_PANEL)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
int text_end = DrawVehiclePurchaseInfo(r.left, r.right, r.top, this->sel_engine, this->te);
needed_height = std::max(needed_height, (text_end - r.top) / GetCharacterHeight(FS_NORMAL));
}
@@ -1904,11 +1927,11 @@ struct BuildVehicleWindow : Window {
}
}
void OnQueryTextFinished(char *str) override
void OnQueryTextFinished(std::optional<std::string> str) override
{
if (str == nullptr) return;
if (!str.has_value()) return;
Command<CMD_RENAME_ENGINE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, this->rename_engine, str);
Command<CMD_RENAME_ENGINE>::Post(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type, this->rename_engine, *str);
}
void OnDropdownSelect(WidgetID widget, int index) override
@@ -1976,11 +1999,11 @@ struct BuildVehicleWindow : Window {
}};
};
static WindowDesc _build_vehicle_desc(__FILE__, __LINE__,
static WindowDesc _build_vehicle_desc(
WDP_AUTO, "build_vehicle", 240, 268,
WC_BUILD_VEHICLE, WC_NONE,
WDF_CONSTRUCTION,
std::begin(_nested_build_vehicle_widgets), std::end(_nested_build_vehicle_widgets),
_nested_build_vehicle_widgets,
&BuildVehicleWindow::hotkeys
);
@@ -1996,5 +2019,5 @@ void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
CloseWindowById(WC_BUILD_VEHICLE, num);
new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
new BuildVehicleWindow(_build_vehicle_desc, tile, type);
}