OpenTTD Source  20241120-master-g6d3adc6169
group_gui.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #include "stdafx.h"
11 #include "textbuf_gui.h"
12 #include "command_func.h"
13 #include "vehicle_gui.h"
14 #include "vehicle_base.h"
15 #include "string_func.h"
16 #include "strings_func.h"
17 #include "window_func.h"
18 #include "vehicle_func.h"
19 #include "autoreplace_gui.h"
20 #include "company_func.h"
21 #include "dropdown_func.h"
22 #include "tilehighlight_func.h"
23 #include "vehicle_gui_base.h"
24 #include "core/geometry_func.hpp"
25 #include "core/container_func.hpp"
26 #include "company_base.h"
27 #include "company_gui.h"
28 #include "gui.h"
29 #include "group_cmd.h"
30 #include "group_gui.h"
31 #include "vehicle_cmd.h"
32 #include "gfx_func.h"
33 
34 #include "widgets/group_widget.h"
35 
36 #include "table/sprites.h"
37 
38 #include "safeguards.h"
39 
40 static constexpr NWidgetPart _nested_group_widgets[] = {
41  NWidget(NWID_HORIZONTAL), // Window header
42  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
43  NWidget(WWT_CAPTION, COLOUR_GREY, WID_GL_CAPTION),
44  NWidget(WWT_SHADEBOX, COLOUR_GREY),
45  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
46  NWidget(WWT_STICKYBOX, COLOUR_GREY),
47  EndContainer(),
49  /* left part */
51  NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_ALL_VEHICLES), SetFill(1, 0), EndContainer(),
54  NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_GROUP), SetMatrixDataTip(1, 0, STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP),
57  EndContainer(),
58  NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_INFO), SetFill(1, 1), SetMinimalTextLines(3, WidgetDimensions::unscaled.framerect.Vertical()), EndContainer(),
61  SetDataTip(SPR_GROUP_CREATE_TRAIN, STR_GROUP_CREATE_TOOLTIP),
63  SetDataTip(SPR_GROUP_DELETE_TRAIN, STR_GROUP_DELETE_TOOLTIP),
65  SetDataTip(SPR_GROUP_RENAME_TRAIN, STR_GROUP_RENAME_TOOLTIP),
67  SetDataTip(SPR_GROUP_LIVERY_TRAIN, STR_GROUP_LIVERY_TOOLTIP),
68  NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), EndContainer(),
70  SetDataTip(SPR_GROUP_REPLACE_OFF_TRAIN, STR_GROUP_REPLACE_PROTECTION_TOOLTIP),
71  EndContainer(),
72  EndContainer(),
73  /* right part */
77  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),
78  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),
79  EndContainer(),
81  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_GROUP_ORDER),
82  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIA),
83  EndContainer(),
85  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalTextLines(1, WidgetDimensions::unscaled.framerect.Vertical()), SetFill(0, 1), SetResize(1, 0), EndContainer(),
87  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_FILTER_BY_CARGO), SetMinimalSize(0, 12), SetFill(0, 1), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
88  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(0, 1), SetResize(1, 0), EndContainer(),
89  EndContainer(),
90  EndContainer(),
91  EndContainer(),
95  EndContainer(),
96  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(),
99  SetDataTip(STR_JUST_STRING, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP),
100  NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetResize(1, 0), EndContainer(),
102  SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP),
103  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG),
104  SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP),
105  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG),
106  SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP),
107  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
108  EndContainer(),
109  EndContainer(),
110  EndContainer(),
111 };
112 
121 static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, bool fold, GroupID parent = INVALID_GROUP, uint8_t indent = 0)
122 {
123  for (const auto &item : src) {
124  if (item.group->parent != parent) continue;
125 
126  dst.emplace_back(item.group, indent);
127 
128  if (fold && item.group->folded) {
129  /* Test if this group has children at all. If not, the folded flag should be cleared to avoid lingering unfold buttons in the list. */
130  GroupID groupid = item.group->index;
131  bool has_children = std::any_of(src.begin(), src.end(), [groupid](const auto &child) { return child.group->parent == groupid; });
132  Group::Get(item.group->index)->folded = has_children;
133  } else {
134  GuiGroupListAddChildren(dst, src, fold, item.group->index, indent + 1);
135  }
136  }
137 
138  if (indent > 0 || dst.empty()) return;
139 
140  /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
141  uint16_t level_mask = 0;
142  for (auto it = std::rbegin(dst); std::next(it) != std::rend(dst); ++it) {
143  auto next_it = std::next(it);
144  AssignBit(level_mask, it->indent, it->indent <= next_it->indent);
145  next_it->level_mask = level_mask;
146  }
147 }
148 
156 void BuildGuiGroupList(GUIGroupList &dst, bool fold, Owner owner, VehicleType veh_type)
157 {
158  GUIGroupList list;
159 
160  for (const Group *g : Group::Iterate()) {
161  if (g->owner == owner && g->vehicle_type == veh_type) {
162  list.emplace_back(g, 0);
163  }
164  }
165 
166  list.ForceResort();
167 
168  /* Sort the groups by their name */
169  std::array<std::pair<const Group *, std::string>, 2> last_group{};
170 
171  list.Sort([&last_group](const GUIGroupListItem &a, const GUIGroupListItem &b) -> bool {
172  if (a.group != last_group[0].first) {
173  SetDParam(0, a.group->index);
174  last_group[0] = {a.group, GetString(STR_GROUP_NAME)};
175  }
176 
177  if (b.group != last_group[1].first) {
178  SetDParam(0, b.group->index);
179  last_group[1] = {b.group, GetString(STR_GROUP_NAME)};
180  }
181 
182  int r = StrNaturalCompare(last_group[0].second, last_group[1].second); // Sort by name (natural sorting).
183  if (r == 0) return a.group->number < b.group->number;
184  return r < 0;
185  });
186 
187  GuiGroupListAddChildren(dst, list, fold, INVALID_GROUP, 0);
188 }
189 
191 private:
192  /* Columns in the group list */
193  enum ListColumns {
200 
201  VGC_END
202  };
203 
210  Scrollbar *group_sb;
211 
213 
220  {
221  if (!this->groups.NeedRebuild()) return;
222 
223  this->groups.clear();
224 
225  BuildGuiGroupList(this->groups, true, owner, this->vli.vtype);
226 
227  this->groups.RebuildDone();
228  }
229 
235  {
236  this->column_size[VGC_FOLD] = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED));
237  this->tiny_step_height = this->column_size[VGC_FOLD].height;
238 
239  this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype));
240  this->column_size[VGC_NAME].width = std::max(170u, this->column_size[VGC_NAME].width) + WidgetDimensions::scaled.hsep_indent;
241  this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NAME].height);
242 
243  this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT);
244  this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROTECT].height);
245 
246  this->column_size[VGC_AUTOREPLACE] = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
247  this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height);
248 
249  this->column_size[VGC_PROFIT].width = 0;
250  this->column_size[VGC_PROFIT].height = 0;
251  static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT};
252  for (const auto &profit_sprite : profit_sprites) {
253  Dimension d = GetSpriteSize(profit_sprite);
254  this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d);
255  }
256  this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROFIT].height);
257 
258  int num_vehicle = GetGroupNumVehicle(this->vli.company, ALL_GROUP, this->vli.vtype);
259  SetDParamMaxValue(0, num_vehicle, 3, FS_SMALL);
260  SetDParamMaxValue(1, num_vehicle, 3, FS_SMALL);
261  this->column_size[VGC_NUMBER] = GetStringBoundingBox(STR_GROUP_COUNT_WITH_SUBGROUP);
262  this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NUMBER].height);
263 
264  this->tiny_step_height += WidgetDimensions::scaled.framerect.Vertical();
265 
266  return WidgetDimensions::scaled.framerect.left +
267  this->column_size[VGC_FOLD].width + WidgetDimensions::scaled.hsep_normal +
268  this->column_size[VGC_NAME].width + WidgetDimensions::scaled.hsep_wide +
269  this->column_size[VGC_PROTECT].width + WidgetDimensions::scaled.hsep_normal +
270  this->column_size[VGC_AUTOREPLACE].width + WidgetDimensions::scaled.hsep_normal +
271  this->column_size[VGC_PROFIT].width + WidgetDimensions::scaled.hsep_normal +
272  this->column_size[VGC_NUMBER].width +
274  }
275 
286  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
287  {
288  /* Highlight the group if a vehicle is dragged over it */
289  if (g_id == this->group_over) {
290  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));
291  }
292 
293  if (g_id == NEW_GROUP) return;
294 
295  /* draw the selected group in white, else we draw it in black */
296  TextColour colour = g_id == this->vli.index ? TC_WHITE : TC_BLACK;
297  const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype);
298  bool rtl = _current_text_dir == TD_RTL;
299 
300  const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
302  const int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
303 
304  if (indent > 0) {
305  /* Draw tree continuation lines. */
306  int tx = (rtl ? right - WidgetDimensions::scaled.framerect.right : left + WidgetDimensions::scaled.framerect.left) + offset;
307  for (uint lvl = 1; lvl <= indent; ++lvl) {
308  if (HasBit(level_mask, lvl)) GfxDrawLine(tx, y, tx, y + this->tiny_step_height - 1, linecolour, WidgetDimensions::scaled.fullbevel.top);
309  if (lvl < indent) tx += level_width;
310  }
311  /* Draw our node in the tree. */
312  int ycentre = y + this->tiny_step_height / 2 - 1;
313  if (!HasBit(level_mask, indent)) GfxDrawLine(tx, y, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
314  GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
315  }
316 
317  /* draw fold / unfold button */
318  int x = rtl ? right - WidgetDimensions::scaled.framerect.right - this->column_size[VGC_FOLD].width + 1 : left + WidgetDimensions::scaled.framerect.left;
319  if (has_children) {
320  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);
321  }
322 
323  /* draw group name */
324  StringID str;
325  if (IsAllGroupID(g_id)) {
326  str = STR_GROUP_ALL_TRAINS + this->vli.vtype;
327  } else if (IsDefaultGroupID(g_id)) {
328  str = STR_GROUP_DEFAULT_TRAINS + this->vli.vtype;
329  } else {
330  SetDParam(0, g_id);
331  str = STR_GROUP_NAME;
332  }
333  x = rtl ? x - WidgetDimensions::scaled.hsep_normal - this->column_size[VGC_NAME].width : x + WidgetDimensions::scaled.hsep_normal + this->column_size[VGC_FOLD].width;
334  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);
335 
336  /* draw autoreplace protection */
337  x = rtl ? x - WidgetDimensions::scaled.hsep_wide - this->column_size[VGC_PROTECT].width : x + WidgetDimensions::scaled.hsep_wide + this->column_size[VGC_NAME].width;
338  if (protection) DrawSprite(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROTECT].height) / 2);
339 
340  /* draw autoreplace status */
341  x = rtl ? x - WidgetDimensions::scaled.hsep_normal - this->column_size[VGC_AUTOREPLACE].width : x + WidgetDimensions::scaled.hsep_normal + this->column_size[VGC_PROTECT].width;
342  if (stats.autoreplace_defined) DrawSprite(SPR_GROUP_REPLACE_ACTIVE, stats.autoreplace_finished ? PALETTE_CRASH : PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_AUTOREPLACE].height) / 2);
343 
344  /* draw the profit icon */
345  x = rtl ? x - WidgetDimensions::scaled.hsep_normal - this->column_size[VGC_PROFIT].width : x + WidgetDimensions::scaled.hsep_normal + this->column_size[VGC_AUTOREPLACE].width;
346  SpriteID spr;
347  uint num_vehicle_min_age = GetGroupNumVehicleMinAge(this->vli.company, g_id, this->vli.vtype);
348  Money profit_last_year_min_age = GetGroupProfitLastYearMinAge(this->vli.company, g_id, this->vli.vtype);
349  if (num_vehicle_min_age == 0) {
350  spr = SPR_PROFIT_NA;
351  } else if (profit_last_year_min_age < 0) {
352  spr = SPR_PROFIT_NEGATIVE;
353  } else if (profit_last_year_min_age < VEHICLE_PROFIT_THRESHOLD * num_vehicle_min_age) {
354  spr = SPR_PROFIT_SOME;
355  } else {
356  spr = SPR_PROFIT_LOT;
357  }
358  DrawSprite(spr, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROFIT].height) / 2);
359 
360  /* draw the number of vehicles of the group */
361  x = rtl ? x - WidgetDimensions::scaled.hsep_normal - this->column_size[VGC_NUMBER].width : x + WidgetDimensions::scaled.hsep_normal + this->column_size[VGC_PROFIT].width;
362  int num_vehicle_with_subgroups = GetGroupNumVehicle(this->vli.company, g_id, this->vli.vtype);
363  int num_vehicle = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype).num_vehicle;
364  if (IsAllGroupID(g_id) || IsDefaultGroupID(g_id) || num_vehicle_with_subgroups == num_vehicle) {
365  SetDParam(0, num_vehicle);
366  DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_JUST_COMMA, colour, SA_RIGHT | SA_FORCE, false, FS_SMALL);
367  } else {
368  SetDParam(0, num_vehicle);
369  SetDParam(1, num_vehicle_with_subgroups - num_vehicle);
370  DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, STR_GROUP_COUNT_WITH_SUBGROUP, colour, SA_RIGHT | SA_FORCE);
371  }
372  }
373 
378  {
379  if (this->group_over == INVALID_GROUP) return;
380 
381  if (IsAllGroupID(this->group_over)) {
383  } else if (IsDefaultGroupID(this->group_over)) {
385  } else {
387  }
388  }
389 
390 public:
392  {
393  this->CreateNestedTree();
394 
395  this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR);
396  this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR);
397 
398  this->vli.index = ALL_GROUP;
399  this->group_sel = INVALID_GROUP;
400  this->group_rename = INVALID_GROUP;
401  this->group_over = INVALID_GROUP;
402 
403  this->groups.ForceRebuild();
404  this->groups.NeedResort();
405  this->BuildGroupList(vli.company);
406  this->group_sb->SetCount(this->groups.size());
407 
408  this->GetWidget<NWidgetCore>(WID_GL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype;
409  this->GetWidget<NWidgetCore>(WID_GL_LIST_VEHICLE)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype;
410 
411  this->GetWidget<NWidgetCore>(WID_GL_CREATE_GROUP)->widget_data += this->vli.vtype;
412  this->GetWidget<NWidgetCore>(WID_GL_RENAME_GROUP)->widget_data += this->vli.vtype;
413  this->GetWidget<NWidgetCore>(WID_GL_DELETE_GROUP)->widget_data += this->vli.vtype;
414  this->GetWidget<NWidgetCore>(WID_GL_LIVERY_GROUP)->widget_data += this->vli.vtype;
415  this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->widget_data += this->vli.vtype;
416 
417  this->FinishInitNested(window_number);
418  this->owner = vli.company;
419 
420  this->BuildVehicleList();
421  this->SortVehicleList();
422  }
423 
425  {
426  *this->sorting = this->vehgroups.GetListing();
427  }
428 
429  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
430  {
431  switch (widget) {
432  case WID_GL_LIST_GROUP:
433  size.width = this->ComputeGroupInfoSize();
434  resize.height = this->tiny_step_height;
435  fill.height = this->tiny_step_height;
436  break;
437 
438  case WID_GL_ALL_VEHICLES:
440  size.width = this->ComputeGroupInfoSize();
441  size.height = this->tiny_step_height;
442  break;
443 
444  case WID_GL_SORT_BY_ORDER: {
445  Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
446  d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
447  d.height += padding.height;
448  size = maxdim(size, d);
449  break;
450  }
451 
452  case WID_GL_LIST_VEHICLE:
453  this->ComputeGroupInfoSize();
454  resize.height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height);
455  size.height = 4 * resize.height;
456  break;
457 
459  size.width = GetStringListWidth(this->vehicle_group_by_names) + padding.width;
460  break;
461 
463  size.width = GetStringListWidth(this->vehicle_group_none_sorter_names_calendar);
464  size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_none_sorter_names_wallclock));
465  size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_calendar));
466  size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_wallclock));
467  size.width += padding.width;
468  break;
469 
471  size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList(true)).width + padding.width);
472  break;
473 
475  Dimension d = this->GetActionDropdownSize(true, true, true);
476  d.height += padding.height;
477  d.width += padding.width;
478  size = maxdim(size, d);
479  break;
480  }
481  }
482  }
483 
489  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
490  {
491  if (data == 0) {
492  /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
493  this->vehgroups.ForceRebuild();
494  this->groups.ForceRebuild();
495  } else {
496  this->vehgroups.ForceResort();
497  this->groups.ForceResort();
498  }
499 
500  /* Process ID-invalidation in command-scope as well */
501  if (this->group_rename != INVALID_GROUP && !Group::IsValidID(this->group_rename)) {
503  this->group_rename = INVALID_GROUP;
504  }
505 
506  if (!(IsAllGroupID(this->vli.index) || IsDefaultGroupID(this->vli.index) || Group::IsValidID(this->vli.index))) {
507  this->vli.index = ALL_GROUP;
509  }
510  this->SetDirty();
511  }
512 
513  void SetStringParameters(WidgetID widget) const override
514  {
515  switch (widget) {
517  SetDParam(0, this->GetCargoFilterLabel(this->cargo_filter_criteria));
518  break;
519 
521  SetDParam(0, STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype);
522  break;
523 
524  case WID_GL_CAPTION:
525  /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption
526  * We list all vehicles or ungrouped vehicles */
527  if (IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index)) {
528  SetDParam(0, STR_COMPANY_NAME);
529  SetDParam(1, this->vli.company);
530  SetDParam(2, this->vehicles.size());
531  SetDParam(3, this->vehicles.size());
532  } else {
533  uint num_vehicle = GetGroupNumVehicle(this->vli.company, this->vli.index, this->vli.vtype);
534 
535  SetDParam(0, STR_GROUP_NAME);
536  SetDParam(1, this->vli.index);
537  SetDParam(2, num_vehicle);
538  SetDParam(3, num_vehicle);
539  }
540  break;
541  }
542  }
543 
544  void OnPaint() override
545  {
546  /* If we select the all vehicles, this->list will contain all vehicles of the owner
547  * else this->list will contain all vehicles which belong to the selected group */
548  this->BuildVehicleList();
549  this->SortVehicleList();
550 
551  this->BuildGroupList(this->owner);
552 
553  this->group_sb->SetCount(this->groups.size());
554  this->vscroll->SetCount(this->vehgroups.size());
555 
556  /* The drop down menu is out, *but* it may not be used, retract it. */
557  if (this->vehicles.empty() && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) {
560  }
561 
562  /* Disable all lists management button when the list is empty */
563  this->SetWidgetsDisabledState(this->vehicles.empty() || _local_company != this->vli.company,
567 
568  /* Disable the group specific function when we select the default group or all vehicles */
569  this->SetWidgetsDisabledState(IsDefaultGroupID(this->vli.index) || IsAllGroupID(this->vli.index) || _local_company != this->vli.company,
574 
575  /* Disable remaining buttons for non-local companies
576  * Needed while changing _local_company, eg. by cheats
577  * All procedures (eg. move vehicle to another group)
578  * verify, whether you are the owner of the vehicle,
579  * so it doesn't have to be disabled
580  */
584 
585  /* If not a default group and the group has replace protection, show an enabled replace sprite. */
586  uint16_t protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN;
587  if (!IsDefaultGroupID(this->vli.index) && !IsAllGroupID(this->vli.index) && HasBit(Group::Get(this->vli.index)->flags, GroupFlags::GF_REPLACE_PROTECTION)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN;
588  this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->widget_data = protect_sprite + this->vli.vtype;
589 
590  /* Set text of "group by" dropdown widget. */
591  this->GetWidget<NWidgetCore>(WID_GL_GROUP_BY_DROPDOWN)->widget_data = std::data(this->vehicle_group_by_names)[this->grouping];
592 
593  /* Set text of "sort by" dropdown widget. */
594  this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->widget_data = this->GetVehicleSorterNames()[this->vehgroups.SortType()];
595 
596  this->DrawWidgets();
597  }
598 
599  void DrawWidget(const Rect &r, WidgetID widget) const override
600  {
601  switch (widget) {
602  case WID_GL_ALL_VEHICLES:
603  DrawGroupInfo(r.top, r.left, r.right, ALL_GROUP);
604  break;
605 
607  DrawGroupInfo(r.top, r.left, r.right, DEFAULT_GROUP);
608  break;
609 
610  case WID_GL_INFO: {
611  Money this_year = 0;
612  Money last_year = 0;
613  uint64_t occupancy = 0;
614 
615  for (const Vehicle * const v : this->vehicles) {
616  assert(v->owner == this->owner);
617 
618  this_year += v->GetDisplayProfitThisYear();
619  last_year += v->GetDisplayProfitLastYear();
620  occupancy += v->trip_occupancy;
621  }
622 
623  Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
624 
625  DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_GROUP_PROFIT_THIS_PERIOD : STR_GROUP_PROFIT_THIS_YEAR, TC_BLACK);
626  SetDParam(0, this_year);
627  DrawString(tr, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT);
628 
629  tr.top += GetCharacterHeight(FS_NORMAL);
630  DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_GROUP_PROFIT_LAST_PERIOD : STR_GROUP_PROFIT_LAST_YEAR, TC_BLACK);
631  SetDParam(0, last_year);
632  DrawString(tr, STR_JUST_CURRENCY_LONG, TC_BLACK, SA_RIGHT);
633 
634  tr.top += GetCharacterHeight(FS_NORMAL);
635  DrawString(tr, STR_GROUP_OCCUPANCY, TC_BLACK);
636  const size_t vehicle_count = this->vehicles.size();
637  if (vehicle_count > 0) {
638  SetDParam(0, occupancy / vehicle_count);
639  DrawString(tr, STR_GROUP_OCCUPANCY_VALUE, TC_BLACK, SA_RIGHT);
640  }
641 
642  break;
643  }
644 
645  case WID_GL_LIST_GROUP: {
646  int y1 = r.top;
647  auto [first, last] = this->group_sb->GetVisibleRangeIterators(this->groups);
648  for (auto it = first; it != last; ++it) {
649  const Group *g = it->group;
650 
651  assert(g->owner == this->owner);
652 
653  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));
654 
655  y1 += this->tiny_step_height;
656  }
657  if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.size()) {
658  DrawGroupInfo(y1, r.left, r.right, NEW_GROUP);
659  }
660  break;
661  }
662 
665  break;
666 
667  case WID_GL_LIST_VEHICLE:
668  if (this->vli.index != ALL_GROUP && this->grouping == GB_NONE) {
669  /* Mark vehicles which are in sub-groups (only if we are not using shared order coalescing) */
670  Rect mr = r.WithHeight(this->resize.step_height);
671  auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->vehgroups);
672  for (auto it = first; it != last; ++it) {
673  const Vehicle *v = it->GetSingleVehicle();
674  if (v->group_id != this->vli.index) {
676  }
677  mr = mr.Translate(0, this->resize.step_height);
678  }
679  }
680 
681  this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r);
682  break;
683  }
684  }
685 
686  static void DeleteGroupCallback(Window *win, bool confirmed)
687  {
688  if (confirmed) {
690  w->vli.index = ALL_GROUP;
691  Command<CMD_DELETE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_DELETE, w->group_confirm);
692  }
693  }
694 
695  bool last_overlay_state;
696  void OnMouseLoop() override
697  {
698  if (last_overlay_state != ShowCargoIconOverlay()) {
699  last_overlay_state = ShowCargoIconOverlay();
700  this->SetDirty();
701  }
702  }
703 
704  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
705  {
706  switch (widget) {
707  case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending
708  this->vehgroups.ToggleSortOrder();
709  this->SetDirty();
710  break;
711 
712  case WID_GL_GROUP_BY_DROPDOWN: // Select grouping option dropdown menu
713  ShowDropDownMenu(this, this->vehicle_group_by_names, this->grouping, WID_GL_GROUP_BY_DROPDOWN, 0, 0);
714  return;
715 
716  case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu
717  ShowDropDownMenu(this, this->GetVehicleSorterNames(), this->vehgroups.SortType(), WID_GL_SORT_BY_DROPDOWN, 0, (this->vli.vtype == VEH_TRAIN || this->vli.vtype == VEH_ROAD) ? 0 : (1 << 10));
718  return;
719 
720  case WID_GL_FILTER_BY_CARGO: // Select filtering criteria dropdown menu
721  ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria, widget);
722  break;
723 
724  case WID_GL_ALL_VEHICLES: // All vehicles button
725  if (!IsAllGroupID(this->vli.index)) {
726  this->vli.index = ALL_GROUP;
727  this->vehgroups.ForceRebuild();
728  this->SetDirty();
729  }
730  break;
731 
732  case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button
733  if (!IsDefaultGroupID(this->vli.index)) {
734  this->vli.index = DEFAULT_GROUP;
735  this->vehgroups.ForceRebuild();
736  this->SetDirty();
737  }
738  break;
739 
740  case WID_GL_LIST_GROUP: { // Matrix Group
741  auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
742  if (it == this->groups.end()) return;
743 
744  if (it->group->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)) {
745  /* The group has children, check if the user clicked the fold / unfold button. */
746  NWidgetCore *group_display = this->GetWidget<NWidgetCore>(widget);
747  int x = _current_text_dir == TD_RTL ?
748  group_display->pos_x + group_display->current_x - WidgetDimensions::scaled.framerect.right - it->indent * WidgetDimensions::scaled.hsep_indent - this->column_size[VGC_FOLD].width :
749  group_display->pos_x + WidgetDimensions::scaled.framerect.left + it->indent * WidgetDimensions::scaled.hsep_indent;
750  if (click_count > 1 || (pt.x >= x && pt.x < (int)(x + this->column_size[VGC_FOLD].width))) {
751 
752  GroupID g = this->vli.index;
753  if (!IsAllGroupID(g) && !IsDefaultGroupID(g)) {
754  do {
755  g = Group::Get(g)->parent;
756  if (g == it->group->index) {
757  this->vli.index = g;
758  break;
759  }
760  } while (g != INVALID_GROUP);
761  }
762 
763  Group::Get(it->group->index)->folded = !it->group->folded;
764  this->groups.ForceRebuild();
765 
766  this->SetDirty();
767  break;
768  }
769  }
770 
771  this->group_sel = this->vli.index = it->group->index;
772 
773  SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
774 
775  this->vehgroups.ForceRebuild();
776  this->SetDirty();
777  break;
778  }
779 
780  case WID_GL_LIST_VEHICLE: { // Matrix Vehicle
781  auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
782  if (it == this->vehgroups.end()) return; // click out of list bound
783 
784  const GUIVehicleGroup &vehgroup = *it;
785 
786  const Vehicle *v = nullptr;
787 
788  switch (this->grouping) {
789  case GB_NONE: {
790  const Vehicle *v2 = vehgroup.GetSingleVehicle();
791  if (VehicleClicked(v2)) break;
792  v = v2;
793  break;
794  }
795 
796  case GB_SHARED_ORDERS: {
797  assert(vehgroup.NumVehicles() > 0);
798  v = vehgroup.vehicles_begin[0];
799  /*
800  * No VehicleClicked(v) support for now, because don't want
801  * to enable any contextual actions except perhaps clicking/ctrl-clicking to clone orders.
802  */
803  break;
804  }
805 
806  default:
807  NOT_REACHED();
808  }
809  if (v) {
810  if (_ctrl_pressed && this->grouping == GB_SHARED_ORDERS) {
811  ShowOrdersWindow(v);
812  } else {
813  this->vehicle_sel = v->index;
814 
815  if (_ctrl_pressed && this->grouping == GB_NONE) {
816  /*
817  * It only makes sense to select a group if not using shared orders
818  * since two vehicles sharing orders can be from different groups.
819  */
820  this->SelectGroup(v->group_id);
821  }
822 
823  SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
825  _cursor.vehchain = true;
826 
827  this->SetDirty();
828  }
829  }
830 
831  break;
832  }
833 
834  case WID_GL_CREATE_GROUP: { // Create a new group
835  Command<CMD_CREATE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_CREATE, CcCreateGroup, this->vli.vtype, this->vli.index);
836  break;
837  }
838 
839  case WID_GL_DELETE_GROUP: { // Delete the selected group
840  this->group_confirm = this->vli.index;
841  ShowQuery(STR_QUERY_GROUP_DELETE_CAPTION, STR_GROUP_DELETE_QUERY_TEXT, this, DeleteGroupCallback);
842  break;
843  }
844 
845  case WID_GL_RENAME_GROUP: // Rename the selected roup
846  this->ShowRenameGroupWindow(this->vli.index, false);
847  break;
848 
849  case WID_GL_LIVERY_GROUP: // Set group livery
850  ShowCompanyLiveryWindow(this->owner, this->vli.index);
851  break;
852 
854  ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype);
855  break;
856 
858  ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.index), IsDefaultGroupID(this->vli.index)), -1, WID_GL_MANAGE_VEHICLES_DROPDOWN);
859  break;
860  }
861 
862  case WID_GL_START_ALL:
863  case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list
864  Command<CMD_MASS_START_STOP>::Post(0, widget == WID_GL_START_ALL, true, this->vli);
865  break;
866  }
867 
869  const Group *g = Group::GetIfValid(this->vli.index);
870  if (g != nullptr) {
872  }
873  break;
874  }
875  }
876  }
877 
878  void OnDragDrop_Group(Point pt, WidgetID widget)
879  {
880  const Group *g = Group::Get(this->group_sel);
881 
882  switch (widget) {
883  case WID_GL_ALL_VEHICLES: // All vehicles
884  case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
885  if (g->parent != INVALID_GROUP) {
886  Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, INVALID_GROUP, {});
887  }
888 
889  this->group_sel = INVALID_GROUP;
890  this->group_over = INVALID_GROUP;
891  this->SetDirty();
892  break;
893 
894  case WID_GL_LIST_GROUP: { // Matrix group
895  auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
896  GroupID new_g = it == this->groups.end() ? INVALID_GROUP : it->group->index;
897 
898  if (this->group_sel != new_g && g->parent != new_g) {
899  Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, new_g, {});
900  }
901 
902  this->group_sel = INVALID_GROUP;
903  this->group_over = INVALID_GROUP;
904  this->SetDirty();
905  break;
906  }
907  }
908  }
909 
910  void OnDragDrop_Vehicle(Point pt, WidgetID widget)
911  {
912  switch (widget) {
913  case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
914  Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, DEFAULT_GROUP, this->vehicle_sel, _ctrl_pressed || this->grouping == GB_SHARED_ORDERS, VehicleListIdentifier{});
915 
917  this->group_over = INVALID_GROUP;
918 
919  this->SetDirty();
920  break;
921 
922  case WID_GL_LIST_GROUP: { // Matrix group
923  const VehicleID vindex = this->vehicle_sel;
924  this->vehicle_sel = INVALID_VEHICLE;
925  this->group_over = INVALID_GROUP;
926  this->SetDirty();
927 
928  auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
929  GroupID new_g = it == this->groups.end() ? NEW_GROUP : it->group->index;
930 
931  Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr, new_g, vindex, _ctrl_pressed || this->grouping == GB_SHARED_ORDERS, VehicleListIdentifier{});
932  break;
933  }
934 
935  case WID_GL_LIST_VEHICLE: { // Matrix vehicle
936  const VehicleID vindex = this->vehicle_sel;
937  this->vehicle_sel = INVALID_VEHICLE;
938  this->group_over = INVALID_GROUP;
939  this->SetDirty();
940 
941  auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
942  if (it == this->vehgroups.end()) return; // click out of list bound
943 
944  const GUIVehicleGroup &vehgroup = *it;
945  switch (this->grouping) {
946  case GB_NONE: {
947  const Vehicle *v = vehgroup.GetSingleVehicle();
948  if (!VehicleClicked(v) && vindex == v->index) {
950  }
951  break;
952  }
953 
954  case GB_SHARED_ORDERS: {
955  if (!VehicleClicked(vehgroup)) {
956  const Vehicle *v = vehgroup.vehicles_begin[0];
957  if (vindex == v->index) {
958  if (vehgroup.NumVehicles() == 1) {
960  } else {
961  ShowVehicleListWindow(v);
962  }
963  }
964  }
965  break;
966  }
967 
968  default:
969  NOT_REACHED();
970  }
971  break;
972  }
973  }
974  }
975 
976  void OnDragDrop(Point pt, WidgetID widget) override
977  {
978  if (this->vehicle_sel != INVALID_VEHICLE) OnDragDrop_Vehicle(pt, widget);
979  if (this->group_sel != INVALID_GROUP) OnDragDrop_Group(pt, widget);
980 
981  _cursor.vehchain = false;
982  }
983 
984  void OnQueryTextFinished(std::optional<std::string> str) override
985  {
986  if (str.has_value()) Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_RENAME, AlterGroupMode::Rename, this->group_rename, 0, *str);
987  this->group_rename = INVALID_GROUP;
988  }
989 
990  void OnResize() override
991  {
992  this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP);
993  this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE);
994  }
995 
996  void OnDropdownSelect(WidgetID widget, int index) override
997  {
998  switch (widget) {
1000  this->UpdateVehicleGroupBy(static_cast<GroupBy>(index));
1001  break;
1002 
1004  this->vehgroups.SetSortType(index);
1005  break;
1006 
1007  case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria
1008  this->SetCargoFilter(index);
1009  break;
1010 
1012  assert(!this->vehicles.empty());
1013 
1014  switch (index) {
1015  case ADI_REPLACE: // Replace window
1016  ShowReplaceGroupVehicleWindow(this->vli.index, this->vli.vtype);
1017  break;
1018  case ADI_SERVICE: // Send for servicing
1019  case ADI_DEPOT: { // Send to Depots
1020  Command<CMD_SEND_VEHICLE_TO_DEPOT>::Post(GetCmdSendToDepotMsg(this->vli.vtype), 0, DepotCommand::MassSend | (index == ADI_SERVICE ? DepotCommand::Service : DepotCommand::None), this->vli);
1021  break;
1022  }
1023 
1024  case ADI_CREATE_GROUP: // Create group
1026  break;
1027 
1028  case ADI_ADD_SHARED: // Add shared Vehicles
1029  assert(Group::IsValidID(this->vli.index));
1030 
1031  Command<CMD_ADD_SHARED_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE, this->vli.index, this->vli.vtype);
1032  break;
1033  case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group
1034  assert(Group::IsValidID(this->vli.index));
1035 
1036  Command<CMD_REMOVE_ALL_VEHICLES_GROUP>::Post(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES, this->vli.index);
1037  break;
1038  default: NOT_REACHED();
1039  }
1040  break;
1041 
1042  default: NOT_REACHED();
1043  }
1044 
1045  this->SetDirty();
1046  }
1047 
1048  void OnGameTick() override
1049  {
1050  if (this->groups.NeedResort() || this->vehgroups.NeedResort()) {
1051  this->SetDirty();
1052  }
1053  }
1054 
1055  void OnPlaceObjectAbort() override
1056  {
1057  /* abort drag & drop */
1058  this->vehicle_sel = INVALID_VEHICLE;
1060  this->group_sel = INVALID_GROUP;
1061  this->group_over = INVALID_GROUP;
1063  }
1064 
1065  void OnMouseDrag(Point pt, WidgetID widget) override
1066  {
1067  if (this->vehicle_sel == INVALID_VEHICLE && this->group_sel == INVALID_GROUP) return;
1068 
1069  /* A vehicle is dragged over... */
1070  GroupID new_group_over = INVALID_GROUP;
1071  switch (widget) {
1072  case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group.
1073  new_group_over = DEFAULT_GROUP;
1074  break;
1075 
1076  case WID_GL_LIST_GROUP: { // ... the list of custom groups.
1077  auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
1078  new_group_over = it == this->groups.end() ? NEW_GROUP : it->group->index;
1079  break;
1080  }
1081  }
1082 
1083  /* Do not highlight when dragging over the current group */
1084  if (this->vehicle_sel != INVALID_VEHICLE) {
1085  if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = INVALID_GROUP;
1086  } else if (this->group_sel != INVALID_GROUP) {
1087  if (this->group_sel == new_group_over || Group::Get(this->group_sel)->parent == new_group_over) new_group_over = INVALID_GROUP;
1088  }
1089 
1090  /* Mark widgets as dirty if the group changed. */
1091  if (new_group_over != this->group_over) {
1093  this->group_over = new_group_over;
1095  }
1096  }
1097 
1098  void ShowRenameGroupWindow(GroupID group, bool empty)
1099  {
1100  assert(Group::IsValidID(group));
1101  this->group_rename = group;
1102  /* Show empty query for new groups */
1103  StringID str = STR_EMPTY;
1104  if (!empty) {
1105  SetDParam(0, group);
1106  str = STR_GROUP_NAME;
1107  }
1109  }
1110 
1117  {
1118  if (this->vehicle_sel == vehicle) ResetObjectToPlace();
1119  }
1120 
1126  void SelectGroup(const GroupID g_id)
1127  {
1128  if (g_id == INVALID_GROUP || g_id == this->vli.index) return;
1129 
1130  this->vli.index = g_id;
1131  if (g_id != ALL_GROUP && g_id != DEFAULT_GROUP) {
1132  const Group *g = Group::Get(g_id);
1133 
1134  auto found = std::find_if(std::begin(this->groups), std::end(this->groups), [g](const auto &item) { return item.group == g; });
1135  if (found == std::end(this->groups)) {
1136  /* The group's branch is maybe collapsed, so try to expand it. */
1137  for (auto pg = Group::GetIfValid(g->parent); pg != nullptr; pg = Group::GetIfValid(pg->parent)) {
1138  pg->folded = false;
1139  }
1140  this->groups.ForceRebuild();
1141  this->BuildGroupList(this->owner);
1142  this->group_sb->SetCount(this->groups.size());
1143  found = std::find_if(std::begin(this->groups), std::end(this->groups), [g](const auto &item) { return item.group == g; });
1144  }
1145  if (found != std::end(this->groups)) this->group_sb->ScrollTowards(std::distance(std::begin(this->groups), found));
1146  }
1147  this->vehgroups.ForceRebuild();
1148  this->SetDirty();
1149  }
1150 
1151 };
1152 
1153 
1154 static WindowDesc _other_group_desc(
1155  WDP_AUTO, "list_groups", 460, 246,
1157  0,
1158  _nested_group_widgets
1159 );
1160 
1161 static WindowDesc _train_group_desc(
1162  WDP_AUTO, "list_groups_train", 525, 246,
1164  0,
1165  _nested_group_widgets
1166 );
1167 
1175 void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group, bool need_existing_window)
1176 {
1177  if (!Company::IsValidID(company)) return;
1178 
1179  const WindowNumber num = VehicleListIdentifier(VL_GROUP_LIST, vehicle_type, company).Pack();
1180  VehicleGroupWindow *w;
1181  if (vehicle_type == VEH_TRAIN) {
1182  w = AllocateWindowDescFront<VehicleGroupWindow>(_train_group_desc, num, need_existing_window);
1183  } else {
1184  _other_group_desc.cls = GetWindowClassForVehicleType(vehicle_type);
1185  w = AllocateWindowDescFront<VehicleGroupWindow>(_other_group_desc, num, need_existing_window);
1186  }
1187  if (w != nullptr) w->SelectGroup(group);
1188 }
1189 
1195 {
1196  ShowCompanyGroup(v->owner, v->type, v->group_id, true);
1197 }
1198 
1206 {
1207  return dynamic_cast<VehicleGroupWindow *>(FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).Pack()));
1208 }
1209 
1214 static void CcCreateGroup(GroupID gid, VehicleType veh_type)
1215 {
1217  if (w != nullptr) w->ShowRenameGroupWindow(gid, true);
1218 }
1219 
1227 void CcCreateGroup(Commands, const CommandCost &result, GroupID new_group, VehicleType vt, GroupID)
1228 {
1229  if (result.Failed()) return;
1230 
1231  assert(vt <= VEH_AIRCRAFT);
1232  CcCreateGroup(new_group, vt);
1233 }
1234 
1241 {
1242  if (result.Failed()) return;
1243 
1244  const Group *g = Group::Get(new_group);
1245  CcCreateGroup(new_group, g->vehicle_type);
1246 }
1247 
1253 {
1254  /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either
1255  * If that is the case, we can skip looping though the windows and save time
1256  */
1257  if (_special_mouse_mode != WSM_DRAGDROP) return;
1258 
1260  if (w != nullptr) w->UnselectVehicle(v->index);
1261 }
void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype)
Show the autoreplace configuration window for a particular group.
Functions related to the autoreplace GUIs.
constexpr debug_inline bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
Common return value for all commands.
Definition: command_type.h:23
bool Failed() const
Did this command fail?
Definition: command_type.h:171
void RebuildDone()
Notify the sortlist that the rebuild is done.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
Listing GetListing() const
Export current sort conditions.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:243
int pos_x
Horizontal position of top-left corner of the widget in the window.
Definition: widget_type.h:248
Base class for a 'real' widget.
Definition: widget_type.h:370
Scrollbar data structure.
Definition: widget_type.h:694
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
Definition: widget_type.h:879
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition: widget.cpp:2394
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
Definition: widget_type.h:841
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Definition: widget_type.h:860
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:740
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Definition: group_gui.cpp:489
void UnselectVehicle(VehicleID vehicle)
Tests whether a given vehicle is selected in the window, and unselects it if necessary.
Definition: group_gui.cpp:1116
void DirtyHighlightedGroupWidget()
Mark the widget containing the currently highlighted group as dirty.
Definition: group_gui.cpp:377
GroupID group_sel
Selected group (for drag/drop)
Definition: group_gui.cpp:204
GroupID group_rename
Group being renamed, INVALID_GROUP if none.
Definition: group_gui.cpp:205
void BuildGroupList(Owner owner)
(Re)Build the group list.
Definition: group_gui.cpp:219
uint tiny_step_height
Step height for the group list.
Definition: group_gui.cpp:209
void OnResize() override
Called after the window got resized.
Definition: group_gui.cpp:990
void OnGameTick() override
Called once per (game) tick.
Definition: group_gui.cpp:1048
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
Definition: group_gui.cpp:1055
Dimension column_size[VGC_END]
Size of the columns in the group list.
Definition: group_gui.cpp:212
GroupID group_confirm
Group awaiting delete confirmation.
Definition: group_gui.cpp:207
GUIGroupList groups
List of groups.
Definition: group_gui.cpp:208
GroupID group_over
Group over which a vehicle is dragged, INVALID_GROUP if none.
Definition: group_gui.cpp:206
uint ComputeGroupInfoSize()
Compute tiny_step_height and column_size.
Definition: group_gui.cpp:234
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
Draw a row in the group list.
Definition: group_gui.cpp:286
@ VGC_PROFIT
Profit icon.
Definition: group_gui.cpp:198
@ VGC_AUTOREPLACE
Autoreplace active icon.
Definition: group_gui.cpp:197
@ VGC_FOLD
Fold / Unfold button.
Definition: group_gui.cpp:194
@ VGC_NAME
Group name.
Definition: group_gui.cpp:195
@ VGC_PROTECT
Autoreplace protect icon.
Definition: group_gui.cpp:196
@ VGC_NUMBER
Number of vehicles in the group.
Definition: group_gui.cpp:199
void OnMouseLoop() override
Called for every mouse loop run, which is at least once per (game) tick.
Definition: group_gui.cpp:696
void SelectGroup(const GroupID g_id)
Selects the specified group in the list.
Definition: group_gui.cpp:1126
void OnPaint() override
The window must be repainted.
Definition: group_gui.cpp:544
RectPadding framerect
Standard padding inside many panels.
Definition: window_gui.h:42
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
int hsep_wide
Wide horizontal spacing.
Definition: window_gui.h:64
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
int hsep_normal
Normal horizontal spacing.
Definition: window_gui.h:63
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition: window_gui.h:40
int hsep_indent
Width of identation for tree layouts.
Definition: window_gui.h:65
Functions related to commands.
Commands
List of commands.
Definition: command_type.h:187
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
Functions related to companies.
GUI Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
Some simple functions to help with accessing containers.
void ShowDropDownMenu(Window *w, std::span< const StringID > strings, int selected, WidgetID button, uint32_t disabled_mask, uint32_t hidden_mask, uint width)
Show a dropdown menu window near a widget of the parent window.
Definition: dropdown.cpp:441
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition: dropdown.cpp:404
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
Definition: dropdown.cpp:363
Functions related to the drop down widget.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition: fontcache.cpp:77
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition: gfx.cpp:851
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition: gfx.cpp:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:38
uint GetStringListWidth(std::span< const StringID > list, FontSize fontsize)
Get maximum width of a list of strings.
Definition: gfx.cpp:874
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition: gfx.cpp:114
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition: gfx.cpp:988
Functions related to the gfx engine.
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition: gfx_type.h:18
@ SA_RIGHT
Right align the text (must be a single bit).
Definition: gfx_type.h:345
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition: gfx_type.h:355
@ FS_SMALL
Index of the small font in the font tables.
Definition: gfx_type.h:210
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:260
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition: gfx_type.h:299
Money GetGroupProfitLastYearMinAge(CompanyID company, GroupID id_g, VehicleType type)
Get last year's profit of vehicles above minimum age for the group with GroupID id_g and its sub-grou...
Definition: group_cmd.cpp:851
@ GF_REPLACE_PROTECTION
If set to true, the global autoreplace has no effect on the group.
Definition: group.h:66
bool IsAllGroupID(GroupID id_g)
Checks if a GroupID stands for all vehicles of a company.
Definition: group.h:100
uint GetGroupNumVehicle(CompanyID company, GroupID id_g, VehicleType type)
Get the number of vehicles in the group with GroupID id_g and its sub-groups.
Definition: group_cmd.cpp:817
uint GetGroupNumVehicleMinAge(CompanyID company, GroupID id_g, VehicleType type)
Get the number of vehicles above profit minimum age in the group with GroupID id_g and its sub-groups...
Definition: group_cmd.cpp:834
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition: widget_type.h:1181
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1284
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1137
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
Definition: widget_type.h:1214
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
Definition: widget_type.h:1149
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlags::ResizeX)
Widget part function for setting the aspect ratio.
Definition: widget_type.h:1295
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
Command definitions related to engine groups.
@ Rename
Change group name.
@ SetParent
Change group parent.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:940
void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group, bool need_existing_window)
Show the group window for the given company and vehicle type.
Definition: group_gui.cpp:1175
void DeleteGroupHighlightOfVehicle(const Vehicle *v)
Removes the highlight of a vehicle in a group window.
Definition: group_gui.cpp:1252
void CcAddVehicleNewGroup(Commands, const CommandCost &result, GroupID new_group, GroupID, VehicleID, bool, const VehicleListIdentifier &)
Open rename window after adding a vehicle to a new group via drag and drop.
Definition: group_gui.cpp:1240
static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, bool fold, GroupID parent=INVALID_GROUP, uint8_t indent=0)
Add children to GUI group list to build a hierarchical tree.
Definition: group_gui.cpp:121
static VehicleGroupWindow * FindVehicleGroupWindow(VehicleType vt, Owner owner)
Finds a group list window determined by vehicle type and owner.
Definition: group_gui.cpp:1205
void ShowCompanyGroupForVehicle(const Vehicle *v)
Show the group window for the given vehicle.
Definition: group_gui.cpp:1194
static void CcCreateGroup(GroupID gid, VehicleType veh_type)
Opens a 'Rename group' window for newly created group.
Definition: group_gui.cpp:1214
void BuildGuiGroupList(GUIGroupList &dst, bool fold, Owner owner, VehicleType veh_type)
Build GUI group list, a sorted hierarchical list of groups for owner and vehicle type.
Definition: group_gui.cpp:156
Functions/definitions that have something to do with groups.
uint16_t GroupID
Type for all group identifiers.
Definition: group_type.h:13
static const GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition: group_type.h:17
static const GroupID NEW_GROUP
Sentinel for a to-be-created group.
Definition: group_type.h:15
static const uint MAX_LENGTH_GROUP_NAME_CHARS
The maximum length of a group name in characters including '\0'.
Definition: group_type.h:20
static const GroupID INVALID_GROUP
Sentinel for invalid groups.
Definition: group_type.h:18
static const GroupID ALL_GROUP
All vehicles are in this group.
Definition: group_type.h:16
Types related to the group widgets.
@ WID_GL_LIST_GROUP
List of the groups.
Definition: group_widget.h:30
@ WID_GL_STOP_ALL
Stop all button.
Definition: group_widget.h:25
@ WID_GL_REPLACE_PROTECTION
Replace protection button.
Definition: group_widget.h:36
@ WID_GL_MANAGE_VEHICLES_DROPDOWN
Manage vehicles dropdown list.
Definition: group_widget.h:24
@ WID_GL_GROUP_BY_ORDER
Group order.
Definition: group_widget.h:16
@ WID_GL_SORT_BY_ORDER
Sort order.
Definition: group_widget.h:18
@ WID_GL_GROUP_BY_DROPDOWN
Group by dropdown list.
Definition: group_widget.h:17
@ WID_GL_CAPTION
Caption of the window.
Definition: group_widget.h:15
@ WID_GL_START_ALL
Start all button.
Definition: group_widget.h:26
@ WID_GL_ALL_VEHICLES
All vehicles entry.
Definition: group_widget.h:28
@ WID_GL_DELETE_GROUP
Delete group button.
Definition: group_widget.h:33
@ WID_GL_AVAILABLE_VEHICLES
Available vehicles.
Definition: group_widget.h:23
@ WID_GL_RENAME_GROUP
Rename group button.
Definition: group_widget.h:34
@ WID_GL_LIST_VEHICLE_SCROLLBAR
Scrollbar for the list.
Definition: group_widget.h:22
@ WID_GL_LIVERY_GROUP
Group livery button.
Definition: group_widget.h:35
@ WID_GL_SORT_BY_DROPDOWN
Sort by dropdown list.
Definition: group_widget.h:19
@ WID_GL_LIST_VEHICLE
List of the vehicles.
Definition: group_widget.h:21
@ WID_GL_FILTER_BY_CARGO
Filter vehicles by cargo type.
Definition: group_widget.h:20
@ WID_GL_CREATE_GROUP
Create group button.
Definition: group_widget.h:32
@ WID_GL_LIST_GROUP_SCROLLBAR
Scrollbar for the list.
Definition: group_widget.h:31
@ WID_GL_INFO
Group info.
Definition: group_widget.h:37
@ WID_GL_DEFAULT_VEHICLES
Default vehicles entry.
Definition: group_widget.h:29
GUI functions that shouldn't be here.
void ShowQuery(StringID caption, StringID message, Window *parent, QueryCallbackProc *callback, bool focus)
Show a confirmation window with standard 'yes' and 'no' buttons The window is aligned to the centre o...
Definition: misc_gui.cpp:1223
void ShowQueryString(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1079
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition: palette.cpp:314
A number of safeguards to prevent using unsafe methods.
This file contains all sprite-related enums and defines.
static const PaletteID PALETTE_CRASH
Recolour sprite greying of crashed vehicles.
Definition: sprites.h:1605
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition: sprites.h:1390
Definition of base types and functions in a cross-platform compatible way.
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
Definition: string.cpp:589
Functions related to low-level strings.
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition: string_type.h:25
void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:127
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:56
Functions related to OTTD's strings.
@ TD_RTL
Text is written right-to-left by default.
Definition: strings_type.h:24
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
CargoID cargo_filter_criteria
Selected cargo filter index.
VehicleListIdentifier vli
Identifier of the vehicle list we want to currently show.
void DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const
Draw all the vehicle list items.
VehicleID vehicle_sel
Selected vehicle.
Listing * sorting
Pointer to the vehicle type related sorting.
void SetCargoFilter(uint8_t index)
Set cargo filter for the vehicle group list.
GroupBy grouping
How we want to group the list.
Dimension GetActionDropdownSize(bool show_autoreplace, bool show_group, bool show_create)
Compute the size for the Action dropdown.
DropDownList BuildActionDropdownList(bool show_autoreplace, bool show_group, bool show_create)
Display the Action dropdown window.
VehicleList vehicles
List of vehicles. This is the buffer for vehgroups to point into; if this is structurally modified,...
GUIVehicleGroupList vehgroups
List of (groups of) vehicles. This stores iterators of vehicles, and should be rebuilt if vehicles is...
DropDownList BuildCargoDropDownList(bool full) const
Build drop down list for cargo filter selection.
VehicleType type
Type of vehicle.
Definition: vehicle_type.h:51
bool vehchain
vehicle chain is dragged
Definition: gfx_type.h:150
Dimensions (a width and height) of a rectangle in 2D.
VehicleList::const_iterator vehicles_begin
Pointer to beginning element of this vehicle group.
Statistics and caches on the vehicles in a group.
Definition: group.h:24
uint16_t num_vehicle
Number of vehicles.
Definition: group.h:28
bool autoreplace_defined
Are any autoreplace rules set?
Definition: group.h:30
static GroupStatistics & Get(CompanyID company, GroupID id_g, VehicleType type)
Returns the GroupStatistics for a specific group.
Definition: group_cmd.cpp:63
bool autoreplace_finished
Have all autoreplacement finished?
Definition: group.h:31
Group data.
Definition: group.h:72
GroupID parent
Parent group.
Definition: group.h:83
VehicleType vehicle_type
Vehicle type of the group.
Definition: group.h:75
bool folded
NOSAVE: Is this group folded in the group view?
Definition: group.h:81
Owner owner
Group Owner.
Definition: group.h:74
uint8_t flags
Group flags.
Definition: group.h:77
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1075
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static Titem * GetIfValid(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:350
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
The information about a vehicle list.
Definition: vehiclelist.h:28
CompanyID company
The company associated with this list.
Definition: vehiclelist.h:31
uint32_t Pack() const
Pack a VehicleListIdentifier in a single uint32.
Definition: vehiclelist.cpp:23
VehicleType vtype
The vehicle type associated with this list.
Definition: vehiclelist.h:30
uint32_t index
A vehicle list type specific index.
Definition: vehiclelist.h:32
Vehicle data structure.
Definition: vehicle_base.h:244
GroupID group_id
Index of group Pool array.
Definition: vehicle_base.h:366
Owner owner
Which company owns the vehicle?
Definition: vehicle_base.h:309
High level window description.
Definition: window_gui.h:159
WindowClass cls
Class of the window,.
Definition: window_gui.h:170
Data structure for an opened window.
Definition: window_gui.h:273
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition: widget.cpp:780
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1733
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
Window * parent
Parent window.
Definition: window_gui.h:328
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition: window_gui.h:475
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:551
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition: widget.cpp:763
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition: window.cpp:1035
ResizeInfo resize
Resize information.
Definition: window_gui.h:314
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition: window_gui.h:521
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1723
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition: window_gui.h:316
int left
x position of left edge of the window
Definition: window_gui.h:309
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:314
int height
Height of the window (number of pixels down in y direction)
Definition: window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition: window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition: window_gui.h:302
Stuff related to the text buffer GUI.
@ QSF_ENABLE_DEFAULT
enable the 'Default' button ("\0" is returned)
Definition: textbuf_gui.h:21
@ QSF_LEN_IN_CHARS
the length of the string is counted in characters
Definition: textbuf_gui.h:22
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:95
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
Definition: viewport.cpp:3498
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
Definition: viewport.cpp:3435
@ HT_DRAG
dragging items in the depot windows
Base class for all vehicles.
Command definitions for vehicles.
Functions related to vehicles.
static const Money VEHICLE_PROFIT_THRESHOLD
Threshold for a vehicle to be considered making good profit.
Definition: vehicle_func.h:29
void ShowVehicleViewWindow(const Vehicle *v)
Shows the vehicle view window of the given vehicle.
bool VehicleClicked(const Vehicle *v)
Dispatch a "vehicle selected" event if any window waits for it.
uint GetVehicleListHeight(VehicleType type, uint divisor)
Get the height of a vehicle in the vehicle list GUIs.
void SetMouseCursorVehicle(const Vehicle *v, EngineImageType image_type)
Set the mouse cursor to look like a vehicle.
bool ShowCargoIconOverlay()
Test if cargo icon overlays should be drawn.
Functions related to the vehicle's GUIs.
WindowClass GetWindowClassForVehicleType(VehicleType vt)
Get WindowClass for vehicle list of given vehicle type.
Definition: vehicle_gui.h:97
Functions/classes shared between the different vehicle list GUIs.
@ EIT_IN_LIST
Vehicle drawn in vehicle list, group list, ...
Definition: vehicle_type.h:82
VehicleType
Available vehicle types.
Definition: vehicle_type.h:21
@ VEH_ROAD
Road vehicle type.
Definition: vehicle_type.h:25
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition: vehicle_type.h:27
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
uint32_t VehicleID
The type all our vehicle IDs have.
Definition: vehicle_type.h:16
static const VehicleID INVALID_VEHICLE
Constant representing a non-existing vehicle.
Definition: vehicle_type.h:54
@ None
No special flags.
@ MassSend
Tells that it's a mass send to depot command (type in VLW flag)
@ Service
The vehicle will leave the depot right after arrival (service only)
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:524
@ NC_BIGFIRST
Value of the NCB_BIGFIRST flag.
Definition: widget_type.h:525
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:112
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
Definition: widget_type.h:113
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_TEXTBTN
(Toggle) Button with text
Definition: widget_type.h:55
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
@ WWT_MATRIX
Grid of rows and columns.
Definition: widget_type.h:59
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:84
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:69
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:65
@ WWT_DROPDOWN
Drop down list.
Definition: widget_type.h:70
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1098
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition: window.cpp:1152
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition: window.cpp:93
Window functions not directly related to making/drawing windows.
@ WSM_DRAGDROP
Drag&drop an object.
Definition: window_gui.h:1041
@ SBS_DOWN
Sort ascending.
Definition: window_gui.h:220
@ SBS_UP
Sort descending.
Definition: window_gui.h:221
@ WDP_AUTO
Find a place automatically.
Definition: window_gui.h:147
int WidgetID
Widget ID.
Definition: window_type.h:18
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:737
@ WC_INVALID
Invalid window.
Definition: window_type.h:724
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_TRAINS_LIST
Trains list; Window numbers:
Definition: window_type.h:308
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
Definition: window_type.h:156
@ WC_QUERY_STRING
Query string window; Window numbers:
Definition: window_type.h:123