Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
#include "vehicle_func.h"
|
||||
#include "autoreplace_gui.h"
|
||||
#include "company_func.h"
|
||||
#include "widgets/dropdown_func.h"
|
||||
#include "dropdown_func.h"
|
||||
#include "tilehighlight_func.h"
|
||||
#include "vehicle_gui_base.h"
|
||||
#include "core/geometry_func.hpp"
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "company_gui.h"
|
||||
#include "gui.h"
|
||||
#include "group_cmd.h"
|
||||
#include "group_gui.h"
|
||||
#include "vehicle_cmd.h"
|
||||
#include "gfx_func.h"
|
||||
|
||||
@@ -38,8 +39,6 @@
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
typedef GUIList<const Group*> GUIGroupList;
|
||||
|
||||
static constexpr NWidgetPart _nested_group_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL), // Window header
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
@@ -76,19 +75,19 @@ static constexpr NWidgetPart _nested_group_widgets[] = {
|
||||
/* right part */
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(NWID_VERTICAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GL_GROUP_BY_ORDER), SetFill(1, 1), SetMinimalSize(0, 12), SetDataTip(STR_STATION_VIEW_GROUP, STR_TOOLTIP_GROUP_ORDER),
|
||||
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_GL_SORT_BY_ORDER), SetFill(1, 1), SetMinimalSize(0, 12), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetFill(1, 0), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetFill(1, 0), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
|
||||
NWidget(NWID_VERTICAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
|
||||
EndContainer(),
|
||||
NWidget(NWID_VERTICAL),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(),
|
||||
NWidget(NWID_VERTICAL, NC_EQUALSIZE),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalTextLines(1, WidgetDimensions::unscaled.framerect.Vertical()), SetFill(0, 1), SetResize(1, 0), EndContainer(),
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_FILTER_BY_CARGO), SetMinimalSize(0, 12), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), EndContainer(),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_FILTER_BY_CARGO), SetMinimalSize(0, 12), SetFill(0, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(0, 1), SetResize(1, 0), EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
EndContainer(),
|
||||
@@ -103,9 +102,9 @@ static constexpr NWidgetPart _nested_group_widgets[] = {
|
||||
NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetResize(1, 0), EndContainer(),
|
||||
NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12),
|
||||
SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetMinimalSize(12, 12),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG),
|
||||
SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetMinimalSize(12, 12),
|
||||
NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG),
|
||||
SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP),
|
||||
NWidget(WWT_RESIZEBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
@@ -113,6 +112,83 @@ static constexpr NWidgetPart _nested_group_widgets[] = {
|
||||
EndContainer(),
|
||||
};
|
||||
|
||||
/**
|
||||
* Add children to GUI group list to build a hierarchical tree.
|
||||
* @param dst Destination list.
|
||||
* @param src Source list.
|
||||
* @param fold Whether to handle group folding/hiding.
|
||||
* @param parent Current tree parent (set by self with recursion).
|
||||
* @param indent Current tree indentation level (set by self with recursion).
|
||||
*/
|
||||
static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, bool fold, GroupID parent = INVALID_GROUP, uint8_t indent = 0)
|
||||
{
|
||||
for (const auto &item : src) {
|
||||
if (item.group->parent != parent) continue;
|
||||
|
||||
dst.emplace_back(item.group, indent);
|
||||
|
||||
if (fold && item.group->folded) {
|
||||
/* Test if this group has children at all. If not, the folded flag should be cleared to avoid lingering unfold buttons in the list. */
|
||||
GroupID groupid = item.group->index;
|
||||
bool has_children = std::any_of(src.begin(), src.end(), [groupid](const auto &child) { return child.group->parent == groupid; });
|
||||
Group::Get(item.group->index)->folded = has_children;
|
||||
} else {
|
||||
GuiGroupListAddChildren(dst, src, fold, item.group->index, 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);
|
||||
AssignBit(level_mask, it->indent, it->indent <= next_it->indent);
|
||||
next_it->level_mask = level_mask;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build GUI group list, a sorted hierarchical list of groups for owner and vehicle type.
|
||||
* @param dst Destination list, owned by the caller.
|
||||
* @param fold Whether to handle group folding/hiding.
|
||||
* @param owner Owner of groups.
|
||||
* @param veh_type Vehicle type of groups.
|
||||
*/
|
||||
void BuildGuiGroupList(GUIGroupList &dst, bool fold, Owner owner, VehicleType veh_type)
|
||||
{
|
||||
GUIGroupList list;
|
||||
|
||||
for (const Group *g : Group::Iterate()) {
|
||||
if (g->owner == owner && g->vehicle_type == veh_type) {
|
||||
list.emplace_back(g, 0);
|
||||
}
|
||||
}
|
||||
|
||||
list.ForceResort();
|
||||
|
||||
/* Sort the groups by their name */
|
||||
std::array<std::pair<const Group *, std::string>, 2> last_group{};
|
||||
|
||||
list.Sort([&last_group](const GUIGroupListItem &a, const GUIGroupListItem &b) -> bool {
|
||||
if (a.group != last_group[0].first) {
|
||||
SetDParam(0, a.group->index);
|
||||
last_group[0] = {a.group, GetString(STR_GROUP_NAME)};
|
||||
}
|
||||
|
||||
if (b.group != last_group[1].first) {
|
||||
SetDParam(0, b.group->index);
|
||||
last_group[1] = {b.group, GetString(STR_GROUP_NAME)};
|
||||
}
|
||||
|
||||
int r = StrNaturalCompare(last_group[0].second, last_group[1].second); // Sort by name (natural sorting).
|
||||
if (r == 0) return a.group->number < b.group->number;
|
||||
return r < 0;
|
||||
});
|
||||
|
||||
GuiGroupListAddChildren(dst, list, fold, INVALID_GROUP, 0);
|
||||
}
|
||||
|
||||
class VehicleGroupWindow : public BaseVehicleListWindow {
|
||||
private:
|
||||
/* Columns in the group list */
|
||||
@@ -135,26 +211,8 @@ private:
|
||||
uint tiny_step_height; ///< Step height for the group list
|
||||
Scrollbar *group_sb;
|
||||
|
||||
std::vector<int> indents; ///< Indentation levels
|
||||
|
||||
Dimension column_size[VGC_END]; ///< Size of the columns in the group list.
|
||||
|
||||
void AddChildren(GUIGroupList &source, GroupID parent, int indent)
|
||||
{
|
||||
for (const Group *g : source) {
|
||||
if (g->parent != parent) continue;
|
||||
this->groups.push_back(g);
|
||||
this->indents.push_back(indent);
|
||||
if (g->folded) {
|
||||
/* Test if this group has children at all. If not, the folded flag should be cleared to avoid lingering unfold buttons in the list. */
|
||||
bool has_children = std::any_of(source.begin(), source.end(), [g](const Group *child){ return child->parent == g->index; });
|
||||
Group::Get(g->index)->folded = has_children;
|
||||
} else {
|
||||
AddChildren(source, g->index, indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (Re)Build the group list.
|
||||
*
|
||||
@@ -165,42 +223,9 @@ private:
|
||||
if (!this->groups.NeedRebuild()) return;
|
||||
|
||||
this->groups.clear();
|
||||
this->indents.clear();
|
||||
|
||||
GUIGroupList list;
|
||||
BuildGuiGroupList(this->groups, true, owner, this->vli.vtype);
|
||||
|
||||
for (const Group *g : Group::Iterate()) {
|
||||
if (g->owner == owner && g->vehicle_type == this->vli.vtype) {
|
||||
list.push_back(g);
|
||||
}
|
||||
}
|
||||
|
||||
list.ForceResort();
|
||||
|
||||
/* Sort the groups by their name */
|
||||
const Group *last_group[2] = { nullptr, nullptr };
|
||||
std::string last_name[2] = { {}, {} };
|
||||
list.Sort([&](const Group * const &a, const Group * const &b) {
|
||||
if (a != last_group[0]) {
|
||||
last_group[0] = a;
|
||||
SetDParam(0, a->index);
|
||||
last_name[0] = GetString(STR_GROUP_NAME);
|
||||
}
|
||||
|
||||
if (b != last_group[1]) {
|
||||
last_group[1] = b;
|
||||
SetDParam(0, b->index);
|
||||
last_name[1] = GetString(STR_GROUP_NAME);
|
||||
}
|
||||
|
||||
int r = StrNaturalCompare(last_name[0], last_name[1]); // Sort by name (natural sorting).
|
||||
if (r == 0) return a->index < b->index;
|
||||
return r < 0;
|
||||
});
|
||||
|
||||
AddChildren(list, INVALID_GROUP, 0);
|
||||
|
||||
this->groups.shrink_to_fit();
|
||||
this->groups.RebuildDone();
|
||||
}
|
||||
|
||||
@@ -226,8 +251,8 @@ private:
|
||||
this->column_size[VGC_PROFIT].width = 0;
|
||||
this->column_size[VGC_PROFIT].height = 0;
|
||||
static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT};
|
||||
for (uint i = 0; i < lengthof(profit_sprites); i++) {
|
||||
Dimension d = GetSpriteSize(profit_sprites[i]);
|
||||
for (const auto &profit_sprite : profit_sprites) {
|
||||
Dimension d = GetSpriteSize(profit_sprite);
|
||||
this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d);
|
||||
}
|
||||
this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROFIT].height);
|
||||
@@ -260,11 +285,11 @@ private:
|
||||
* @param protection Whether autoreplace protection is set.
|
||||
* @param has_children Whether the group has children and should have a fold / unfold button.
|
||||
*/
|
||||
void DrawGroupInfo(int y, int left, int right, GroupID g_id, int indent = 0, bool protection = false, bool has_children = false) const
|
||||
void DrawGroupInfo(int y, int left, int right, GroupID g_id, uint16_t level_mask = 0, uint8_t indent = 0, bool protection = false, bool has_children = false) const
|
||||
{
|
||||
/* Highlight the group if a vehicle is dragged over it */
|
||||
if (g_id == this->group_over) {
|
||||
GfxFillRect(left + WidgetDimensions::scaled.bevel.left, y + WidgetDimensions::scaled.framerect.top, right - WidgetDimensions::scaled.bevel.right, y + this->tiny_step_height - 1 - WidgetDimensions::scaled.framerect.bottom, _colour_gradient[COLOUR_GREY][7]);
|
||||
GfxFillRect(left + WidgetDimensions::scaled.bevel.left, y + WidgetDimensions::scaled.framerect.top, right - WidgetDimensions::scaled.bevel.right, y + this->tiny_step_height - 1 - WidgetDimensions::scaled.framerect.bottom, GetColourGradient(COLOUR_GREY, SHADE_LIGHTEST));
|
||||
}
|
||||
|
||||
if (g_id == NEW_GROUP) return;
|
||||
@@ -274,10 +299,27 @@ private:
|
||||
const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype);
|
||||
bool rtl = _current_text_dir == TD_RTL;
|
||||
|
||||
const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
|
||||
const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
|
||||
const int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
|
||||
|
||||
if (indent > 0) {
|
||||
/* Draw tree continuation lines. */
|
||||
int tx = (rtl ? right - WidgetDimensions::scaled.framerect.right : left + WidgetDimensions::scaled.framerect.left) + offset;
|
||||
for (uint lvl = 1; lvl <= indent; ++lvl) {
|
||||
if (HasBit(level_mask, lvl)) GfxDrawLine(tx, y, tx, y + this->tiny_step_height - 1, linecolour, WidgetDimensions::scaled.fullbevel.top);
|
||||
if (lvl < indent) tx += level_width;
|
||||
}
|
||||
/* Draw our node in the tree. */
|
||||
int ycentre = y + this->tiny_step_height / 2 - 1;
|
||||
if (!HasBit(level_mask, indent)) GfxDrawLine(tx, y, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
|
||||
GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
|
||||
}
|
||||
|
||||
/* draw fold / unfold button */
|
||||
int x = rtl ? right - WidgetDimensions::scaled.framerect.right - this->column_size[VGC_FOLD].width + 1 : left + WidgetDimensions::scaled.framerect.left;
|
||||
if (has_children) {
|
||||
DrawSprite(Group::Get(g_id)->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, rtl ? x - indent : x + indent, y + (this->tiny_step_height - this->column_size[VGC_FOLD].height) / 2);
|
||||
DrawSprite(Group::Get(g_id)->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, x + indent * level_width, y + (this->tiny_step_height - this->column_size[VGC_FOLD].height) / 2);
|
||||
}
|
||||
|
||||
/* draw group name */
|
||||
@@ -291,7 +333,7 @@ private:
|
||||
str = STR_GROUP_NAME;
|
||||
}
|
||||
x = rtl ? x - WidgetDimensions::scaled.hsep_normal - this->column_size[VGC_NAME].width : x + WidgetDimensions::scaled.hsep_normal + this->column_size[VGC_FOLD].width;
|
||||
DrawString(x + (rtl ? 0 : indent), x + this->column_size[VGC_NAME].width - 1 - (rtl ? indent : 0), y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour);
|
||||
DrawString(x + (rtl ? 0 : indent * WidgetDimensions::scaled.hsep_indent), x + this->column_size[VGC_NAME].width - 1 - (rtl ? indent * WidgetDimensions::scaled.hsep_indent : 0), y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour);
|
||||
|
||||
/* draw autoreplace protection */
|
||||
x = rtl ? x - WidgetDimensions::scaled.hsep_wide - this->column_size[VGC_PROTECT].width : x + WidgetDimensions::scaled.hsep_wide + this->column_size[VGC_NAME].width;
|
||||
@@ -348,7 +390,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
VehicleGroupWindow(WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number)
|
||||
VehicleGroupWindow(WindowDesc &desc, WindowNumber window_number) : BaseVehicleListWindow(desc, window_number)
|
||||
{
|
||||
this->CreateNestedTree();
|
||||
|
||||
@@ -386,56 +428,56 @@ public:
|
||||
*this->sorting = this->vehgroups.GetListing();
|
||||
}
|
||||
|
||||
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_GL_LIST_GROUP:
|
||||
size->width = this->ComputeGroupInfoSize();
|
||||
resize->height = this->tiny_step_height;
|
||||
fill->height = this->tiny_step_height;
|
||||
size.width = this->ComputeGroupInfoSize();
|
||||
resize.height = this->tiny_step_height;
|
||||
fill.height = this->tiny_step_height;
|
||||
break;
|
||||
|
||||
case WID_GL_ALL_VEHICLES:
|
||||
case WID_GL_DEFAULT_VEHICLES:
|
||||
size->width = this->ComputeGroupInfoSize();
|
||||
size->height = this->tiny_step_height;
|
||||
size.width = this->ComputeGroupInfoSize();
|
||||
size.height = this->tiny_step_height;
|
||||
break;
|
||||
|
||||
case WID_GL_SORT_BY_ORDER: {
|
||||
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_GL_LIST_VEHICLE:
|
||||
this->ComputeGroupInfoSize();
|
||||
resize->height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height);
|
||||
size->height = 4 * resize->height;
|
||||
resize.height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height);
|
||||
size.height = 4 * resize.height;
|
||||
break;
|
||||
|
||||
case WID_GL_GROUP_BY_DROPDOWN:
|
||||
size->width = GetStringListWidth(this->vehicle_group_by_names) + padding.width;
|
||||
size.width = GetStringListWidth(this->vehicle_group_by_names) + padding.width;
|
||||
break;
|
||||
|
||||
case WID_GL_SORT_BY_DROPDOWN:
|
||||
size->width = GetStringListWidth(this->vehicle_group_none_sorter_names_calendar);
|
||||
size->width = std::max(size->width, GetStringListWidth(this->vehicle_group_none_sorter_names_wallclock));
|
||||
size->width = std::max(size->width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_calendar));
|
||||
size->width = std::max(size->width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_wallclock));
|
||||
size->width += padding.width;
|
||||
size.width = GetStringListWidth(this->vehicle_group_none_sorter_names_calendar);
|
||||
size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_none_sorter_names_wallclock));
|
||||
size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_calendar));
|
||||
size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_wallclock));
|
||||
size.width += padding.width;
|
||||
break;
|
||||
|
||||
case WID_GL_FILTER_BY_CARGO:
|
||||
size->width = std::max(size->width, GetDropDownListDimension(this->BuildCargoDropDownList(true)).width + padding.width);
|
||||
size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList(true)).width + padding.width);
|
||||
break;
|
||||
|
||||
case WID_GL_MANAGE_VEHICLES_DROPDOWN: {
|
||||
Dimension d = this->GetActionDropdownSize(true, true, true);
|
||||
d.height += padding.height;
|
||||
d.width += padding.width;
|
||||
*size = maxdim(*size, d);
|
||||
size = maxdim(size, d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -548,7 +590,7 @@ public:
|
||||
this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype;
|
||||
|
||||
/* Set text of "group by" dropdown widget. */
|
||||
this->GetWidget<NWidgetCore>(WID_GL_GROUP_BY_DROPDOWN)->widget_data = this->vehicle_group_by_names[this->grouping];
|
||||
this->GetWidget<NWidgetCore>(WID_GL_GROUP_BY_DROPDOWN)->widget_data = std::data(this->vehicle_group_by_names)[this->grouping];
|
||||
|
||||
/* Set text of "sort by" dropdown widget. */
|
||||
this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->GetVehicleSorterNames()[this->vehgroups.SortType()];
|
||||
@@ -604,13 +646,13 @@ public:
|
||||
|
||||
case WID_GL_LIST_GROUP: {
|
||||
int y1 = r.top;
|
||||
size_t max = std::min<size_t>(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.size());
|
||||
for (size_t i = this->group_sb->GetPosition(); i < max; ++i) {
|
||||
const Group *g = this->groups[i];
|
||||
auto [first, last] = this->group_sb->GetVisibleRangeIterators(this->groups);
|
||||
for (auto it = first; it != last; ++it) {
|
||||
const Group *g = it->group;
|
||||
|
||||
assert(g->owner == this->owner);
|
||||
|
||||
DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i] * WidgetDimensions::scaled.hsep_indent, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (i + 1 < this->groups.size() && indents[i + 1] > this->indents[i]));
|
||||
DrawGroupInfo(y1, r.left, r.right, g->index, it->level_mask, it->indent, HasBit(g->flags, GroupFlags::GF_REPLACE_PROTECTION), g->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent));
|
||||
|
||||
y1 += this->tiny_step_height;
|
||||
}
|
||||
@@ -628,11 +670,11 @@ public:
|
||||
if (this->vli.index != ALL_GROUP && this->grouping == GB_NONE) {
|
||||
/* Mark vehicles which are in sub-groups (only if we are not using shared order coalescing) */
|
||||
Rect mr = r.WithHeight(this->resize.step_height);
|
||||
size_t max = std::min<size_t>(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehgroups.size());
|
||||
for (size_t i = this->vscroll->GetPosition(); i < max; ++i) {
|
||||
const Vehicle *v = this->vehgroups[i].GetSingleVehicle();
|
||||
auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->vehgroups);
|
||||
for (auto it = first; it != last; ++it) {
|
||||
const Vehicle *v = it->GetSingleVehicle();
|
||||
if (v->group_id != this->vli.index) {
|
||||
GfxFillRect(mr.Shrink(WidgetDimensions::scaled.bevel), _colour_gradient[COLOUR_GREY][3], FILLRECT_CHECKER);
|
||||
GfxFillRect(mr.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(COLOUR_GREY, SHADE_DARK), FILLRECT_CHECKER);
|
||||
}
|
||||
mr = mr.Translate(0, this->resize.step_height);
|
||||
}
|
||||
@@ -652,6 +694,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool last_overlay_state;
|
||||
void OnMouseLoop() override
|
||||
{
|
||||
if (last_overlay_state != ShowCargoIconOverlay()) {
|
||||
last_overlay_state = ShowCargoIconOverlay();
|
||||
this->SetDirty();
|
||||
}
|
||||
}
|
||||
|
||||
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
|
||||
{
|
||||
switch (widget) {
|
||||
@@ -692,27 +743,26 @@ public:
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
if (it == this->groups.end()) return;
|
||||
|
||||
size_t id_g = it - this->groups.begin();
|
||||
if ((*it)->folded || (id_g + 1 < this->groups.size() && this->indents[id_g + 1] > this->indents[id_g])) {
|
||||
if (it->group->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)) {
|
||||
/* The group has children, check if the user clicked the fold / unfold button. */
|
||||
NWidgetCore *group_display = this->GetWidget<NWidgetCore>(widget);
|
||||
int x = _current_text_dir == TD_RTL ?
|
||||
group_display->pos_x + group_display->current_x - WidgetDimensions::scaled.framerect.right - this->indents[id_g] * WidgetDimensions::scaled.hsep_indent - this->column_size[VGC_FOLD].width :
|
||||
group_display->pos_x + WidgetDimensions::scaled.framerect.left + this->indents[id_g] * WidgetDimensions::scaled.hsep_indent;
|
||||
group_display->pos_x + group_display->current_x - WidgetDimensions::scaled.framerect.right - it->indent * WidgetDimensions::scaled.hsep_indent - this->column_size[VGC_FOLD].width :
|
||||
group_display->pos_x + WidgetDimensions::scaled.framerect.left + it->indent * WidgetDimensions::scaled.hsep_indent;
|
||||
if (click_count > 1 || (pt.x >= x && pt.x < (int)(x + this->column_size[VGC_FOLD].width))) {
|
||||
|
||||
GroupID g = this->vli.index;
|
||||
if (!IsAllGroupID(g) && !IsDefaultGroupID(g)) {
|
||||
do {
|
||||
g = Group::Get(g)->parent;
|
||||
if (g == groups[id_g]->index) {
|
||||
if (g == it->group->index) {
|
||||
this->vli.index = g;
|
||||
break;
|
||||
}
|
||||
} while (g != INVALID_GROUP);
|
||||
}
|
||||
|
||||
Group::Get(groups[id_g]->index)->folded = !groups[id_g]->folded;
|
||||
Group::Get(it->group->index)->folded = !it->group->folded;
|
||||
this->groups.ForceRebuild();
|
||||
|
||||
this->SetDirty();
|
||||
@@ -720,7 +770,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
this->group_sel = this->vli.index = this->groups[id_g]->index;
|
||||
this->group_sel = this->vli.index = it->group->index;
|
||||
|
||||
SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this, CM_DDSP_GROUP);
|
||||
|
||||
@@ -807,7 +857,7 @@ public:
|
||||
break;
|
||||
|
||||
case WID_GL_MANAGE_VEHICLES_DROPDOWN: {
|
||||
ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index), IsDefaultGroupID(this->vli.index)), 0, WID_GL_MANAGE_VEHICLES_DROPDOWN);
|
||||
ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index), IsDefaultGroupID(this->vli.index)), -1, WID_GL_MANAGE_VEHICLES_DROPDOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -845,7 +895,7 @@ public:
|
||||
|
||||
case WID_GL_LIST_GROUP: { // Matrix group
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = it == this->groups.end() ? INVALID_GROUP : (*it)->index;
|
||||
GroupID new_g = it == this->groups.end() ? INVALID_GROUP : it->group->index;
|
||||
|
||||
if (this->group_sel != new_g && g->parent != new_g) {
|
||||
Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, new_g, {});
|
||||
@@ -878,7 +928,7 @@ public:
|
||||
this->SetDirty();
|
||||
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
GroupID new_g = it == this->groups.end() ? NEW_GROUP : (*it)->index;
|
||||
GroupID new_g = it == this->groups.end() ? NEW_GROUP : it->group->index;
|
||||
|
||||
Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr, new_g, vindex, citymania::_fn_mod || this->grouping == GB_SHARED_ORDERS, VehicleListIdentifier{});
|
||||
break;
|
||||
@@ -933,9 +983,9 @@ public:
|
||||
_cursor.vehchain = false;
|
||||
}
|
||||
|
||||
void OnQueryTextFinished(char *str) override
|
||||
void OnQueryTextFinished(std::optional<std::string> str) override
|
||||
{
|
||||
if (str != nullptr) Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_RENAME, AlterGroupMode::Rename, this->group_rename, 0, str);
|
||||
if (str.has_value()) Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_RENAME, AlterGroupMode::Rename, this->group_rename, 0, *str);
|
||||
this->group_rename = INVALID_GROUP;
|
||||
}
|
||||
|
||||
@@ -1027,7 +1077,7 @@ public:
|
||||
|
||||
case WID_GL_LIST_GROUP: { // ... the list of custom groups.
|
||||
auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
|
||||
new_group_over = it == this->groups.end() ? NEW_GROUP : (*it)->index;
|
||||
new_group_over = it == this->groups.end() ? NEW_GROUP : it->group->index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1082,18 +1132,19 @@ public:
|
||||
this->vli.index = g_id;
|
||||
if (g_id != ALL_GROUP && g_id != DEFAULT_GROUP) {
|
||||
const Group *g = Group::Get(g_id);
|
||||
int id_g = find_index(this->groups, g);
|
||||
// The group's branch is maybe collapsed, so try to expand it
|
||||
if (id_g == -1) {
|
||||
|
||||
auto found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
|
||||
if (found == std::end(this->groups)) {
|
||||
/* The group's branch is maybe collapsed, so try to expand it. */
|
||||
for (auto pg = Group::GetIfValid(g->parent); pg != nullptr; pg = Group::GetIfValid(pg->parent)) {
|
||||
pg->folded = false;
|
||||
}
|
||||
this->groups.ForceRebuild();
|
||||
this->BuildGroupList(this->owner);
|
||||
this->group_sb->SetCount(this->groups.size());
|
||||
id_g = find_index(this->groups, g);
|
||||
found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
|
||||
}
|
||||
this->group_sb->ScrollTowards(id_g);
|
||||
if (found != std::end(this->groups)) this->group_sb->ScrollTowards(std::distance(std::begin(this->groups), found));
|
||||
}
|
||||
this->vehgroups.ForceRebuild();
|
||||
this->SetDirty();
|
||||
@@ -1102,18 +1153,18 @@ public:
|
||||
};
|
||||
|
||||
|
||||
static WindowDesc _other_group_desc(__FILE__, __LINE__,
|
||||
static WindowDesc _other_group_desc(
|
||||
WDP_AUTO, "list_groups", 460, 246,
|
||||
WC_INVALID, WC_NONE,
|
||||
0,
|
||||
std::begin(_nested_group_widgets), std::end(_nested_group_widgets)
|
||||
_nested_group_widgets
|
||||
);
|
||||
|
||||
static WindowDesc _train_group_desc(__FILE__, __LINE__,
|
||||
static WindowDesc _train_group_desc(
|
||||
WDP_AUTO, "list_groups_train", 525, 246,
|
||||
WC_TRAINS_LIST, WC_NONE,
|
||||
0,
|
||||
std::begin(_nested_group_widgets), std::end(_nested_group_widgets)
|
||||
_nested_group_widgets
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -1123,17 +1174,17 @@ static WindowDesc _train_group_desc(__FILE__, __LINE__,
|
||||
* @param group The group to be selected. Defaults to INVALID_GROUP.
|
||||
* @param need_existing_window Whether the existing window is needed. Defaults to false.
|
||||
*/
|
||||
void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group = INVALID_GROUP, bool need_existing_window = false)
|
||||
void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group, bool need_existing_window)
|
||||
{
|
||||
if (!Company::IsValidID(company)) return;
|
||||
|
||||
const WindowNumber num = VehicleListIdentifier(VL_GROUP_LIST, vehicle_type, company).Pack();
|
||||
VehicleGroupWindow *w;
|
||||
if (vehicle_type == VEH_TRAIN) {
|
||||
w = AllocateWindowDescFront<VehicleGroupWindow>(&_train_group_desc, num, need_existing_window);
|
||||
w = AllocateWindowDescFront<VehicleGroupWindow>(_train_group_desc, num, need_existing_window);
|
||||
} else {
|
||||
_other_group_desc.cls = GetWindowClassForVehicleType(vehicle_type);
|
||||
w = AllocateWindowDescFront<VehicleGroupWindow>(&_other_group_desc, num, need_existing_window);
|
||||
w = AllocateWindowDescFront<VehicleGroupWindow>(_other_group_desc, num, need_existing_window);
|
||||
}
|
||||
if (w != nullptr) w->SelectGroup(group);
|
||||
}
|
||||
@@ -1155,7 +1206,7 @@ void ShowCompanyGroupForVehicle(const Vehicle *v)
|
||||
*/
|
||||
static inline VehicleGroupWindow *FindVehicleGroupWindow(VehicleType vt, Owner owner)
|
||||
{
|
||||
return (VehicleGroupWindow *)FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).Pack());
|
||||
return dynamic_cast<VehicleGroupWindow *>(FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).Pack()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user