OpenTTD Source 20260311-master-g511d3794ce
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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"
25#include "company_base.h"
26#include "company_gui.h"
27#include "gui.h"
28#include "group_cmd.h"
29#include "group_gui.h"
30#include "vehicle_cmd.h"
31#include "gfx_func.h"
32
34
35#include "table/sprites.h"
36#include "table/strings.h"
37
38#include "safeguards.h"
39
40static constexpr std::initializer_list<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),
49 /* left part */
54 NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_GROUP), SetMatrixDataTip(1, 0, STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP),
58 NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_INFO), SetFill(1, 1), SetMinimalTextLines(3, WidgetDimensions::unscaled.framerect.Vertical()), EndContainer(),
61 SetToolTip(STR_GROUP_CREATE_TOOLTIP),
63 SetToolTip(STR_GROUP_DELETE_TOOLTIP),
65 SetToolTip(STR_GROUP_RENAME_TOOLTIP),
67 SetToolTip(STR_GROUP_LIVERY_TOOLTIP),
68 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), EndContainer(),
70 SetToolTip(STR_GROUP_REPLACE_PROTECTION_TOOLTIP),
73 /* right part */
77 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_GL_GROUP_BY_ORDER), SetFill(1, 1), SetMinimalSize(0, 12), SetStringTip(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), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
81 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetToolTip(STR_TOOLTIP_GROUP_ORDER),
82 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetToolTip(STR_TOOLTIP_SORT_CRITERIA),
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), SetToolTip(STR_TOOLTIP_FILTER_CRITERIA),
88 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(0, 1), SetResize(1, 0), EndContainer(),
96 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(),
99 SetToolTip(STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP),
100 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetResize(1, 0), EndContainer(),
102 SetStringTip(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 SetSpriteTip(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 SetSpriteTip(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
113static void SortGUIGroupList(std::vector<GUIGroupListItem> &list)
114{
115 /* Sort the groups by their name */
116 std::array<std::pair<const Group *, std::string>, 2> last_group{};
117
118 std::ranges::sort(list, [&last_group](const GUIGroupListItem &a, const GUIGroupListItem &b) -> bool {
119 if (a.group != last_group[0].first) {
120 last_group[0] = {a.group, GetString(STR_GROUP_NAME, a.group->index)};
121 }
122
123 if (b.group != last_group[1].first) {
124 last_group[1] = {b.group, GetString(STR_GROUP_NAME, b.group->index)};
125 }
126
127 int r = StrNaturalCompare(last_group[0].second, last_group[1].second); // Sort by name (natural sorting).
128 if (r == 0) return a.group->number < b.group->number;
129 return r < 0;
130 });
131}
132
140static void GuiGroupListAddChildren(GUIGroupList &list, GUIGroupListItem &item, bool fold, uint8_t indent = 1)
141{
142 if (fold && item.group->folded) {
143 Group::Get(item.group->index)->folded = !item.group->children.empty();
144 return;
145 }
146
147 if (item.group->children.empty()) return;
148
149 std::vector<GUIGroupListItem> sublist;
150 for (const GroupID &group : item.group->children) {
151 sublist.emplace_back(Group::Get(group), indent);
152 }
153 SortGUIGroupList(sublist);
154
155 for (const GUIGroupListItem &subitem : sublist) {
156 GuiGroupListAddChildren(list, list.emplace_back(subitem), fold, indent + 1);
157 }
158}
159
167void BuildGuiGroupList(GUIGroupList &list, bool fold, Owner owner, VehicleType veh_type)
168{
169 /* Make a temporary list of parent groups */
170 std::vector<GUIGroupListItem> sublist;
171 for (const Group *g : Group::Iterate()) {
172 if (g->parent != GroupID::Invalid()) continue;
173 if (g->owner != owner) continue;
174 if (g->vehicle_type != veh_type) continue;
175 sublist.emplace_back(g, 0);
176 }
177 SortGUIGroupList(sublist);
178
179 /* Now add each parent group, and its children if necessary, to the list. */
180 for (auto &item : sublist) {
181 GuiGroupListAddChildren(list, list.emplace_back(item), fold);
182 }
183
184 if (list.empty()) return;
185
186 /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
187 uint16_t level_mask = 0;
188 for (auto it = std::rbegin(list); std::next(it) != std::rend(list); ++it) {
189 auto next_it = std::next(it);
190 AssignBit(level_mask, it->indent, it->indent <= next_it->indent);
191 next_it->level_mask = level_mask;
192 }
193}
194
207
208class VehicleGroupWindow : public BaseVehicleListWindow {
209private:
210 GroupID group_sel = GroupID::Invalid();
211 GroupID group_rename = GroupID::Invalid();
212 GroupID group_over = GroupID::Invalid();
213 GroupID group_confirm = GroupID::Invalid();
214 GUIGroupList groups{};
216 Scrollbar *group_sb = nullptr;
217
218 std::array<Dimension, VGC_END> column_size{};
219 std::array<Rect, VGC_END> column_rects{};
220 bool last_overlay_state = false;
221
228 {
229 if (!this->groups.NeedRebuild()) return;
230
231 this->groups.clear();
232
233 BuildGuiGroupList(this->groups, true, owner, this->vli.vtype);
234
235 this->groups.RebuildDone();
236 }
237
243 {
244 this->column_size[VGC_FOLD] = maxdim(GetScaledSpriteSize(SPR_CIRCLE_FOLDED), GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED));
245 this->tiny_step_height = this->column_size[VGC_FOLD].height;
246
247 this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype));
248 this->column_size[VGC_NAME].width = std::max(170u, this->column_size[VGC_NAME].width) + WidgetDimensions::scaled.hsep_indent;
249 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NAME].height);
250
251 this->column_size[VGC_PROTECT] = GetScaledSpriteSize(SPR_GROUP_REPLACE_PROTECT);
252 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROTECT].height);
253
254 this->column_size[VGC_AUTOREPLACE] = GetScaledSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
255 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height);
256
257 this->column_size[VGC_PROFIT].width = 0;
258 this->column_size[VGC_PROFIT].height = 0;
259 static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT};
260 for (const auto &profit_sprite : profit_sprites) {
261 Dimension d = GetScaledSpriteSize(profit_sprite);
262 this->column_size[VGC_PROFIT] = maxdim(this->column_size[VGC_PROFIT], d);
263 }
264 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROFIT].height);
265
266 int num_vehicle = GetGroupNumVehicle(this->vli.company, ALL_GROUP, this->vli.vtype);
267 uint64_t max_value = GetParamMaxValue(num_vehicle, 3, FS_SMALL);
268 this->column_size[VGC_NUMBER] = GetStringBoundingBox(GetString(STR_GROUP_COUNT_WITH_SUBGROUP, max_value, max_value));
269 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NUMBER].height);
270
271 this->tiny_step_height += WidgetDimensions::scaled.framerect.Vertical();
272
273 return WidgetDimensions::scaled.framerect.left +
274 this->column_size[VGC_FOLD].width + WidgetDimensions::scaled.hsep_normal +
275 this->column_size[VGC_NAME].width + WidgetDimensions::scaled.hsep_wide +
276 this->column_size[VGC_PROTECT].width + WidgetDimensions::scaled.hsep_normal +
277 this->column_size[VGC_AUTOREPLACE].width + WidgetDimensions::scaled.hsep_normal +
278 this->column_size[VGC_PROFIT].width + WidgetDimensions::scaled.hsep_normal +
279 this->column_size[VGC_NUMBER].width +
280 WidgetDimensions::scaled.framerect.right;
281 }
282
287 {
288 bool rtl = _current_text_dir == TD_RTL;
289 Rect r = this->GetWidget<NWidgetCore>(WID_GL_LIST_GROUP)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
290
291 /* Place columns before VGC_NAME from start to end. */
292 for (VehicleGroupColumns lc{}; lc != VGC_NAME; ++lc) {
293 this->column_rects[lc] = r.WithWidth(this->column_size[lc].width, rtl);
294 r = r.Indent(this->column_size[lc].width + WidgetDimensions::scaled.hsep_normal, rtl);
295 }
296 /* Place columns after VGC_NAME from end to start. */
297 for (VehicleGroupColumns lc{VGC_END - 1}; lc != VGC_NAME; --lc) {
298 this->column_rects[lc] = r.WithWidth(this->column_size[lc].width, !rtl);
299 r = r.Indent(this->column_size[lc].width + WidgetDimensions::scaled.hsep_normal, !rtl);
300 }
301 /* Name column fills remaining space. */
302 this->column_rects[VGC_NAME] = r;
303 }
304
310 std::string GetGroupNameString(GroupID g_id) const
311 {
312 if (IsAllGroupID(g_id)) return GetString(STR_GROUP_ALL_TRAINS + this->vli.vtype);
313 if (IsDefaultGroupID(g_id)) return GetString(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype);
314 return GetString(STR_GROUP_NAME, g_id);
315 }
316
323 {
324 uint num_vehicle_min_age = GetGroupNumVehicleMinAge(this->vli.company, g_id, this->vli.vtype);
325 if (num_vehicle_min_age == 0) return SPR_PROFIT_NA;
326
327 Money profit_last_year_min_age = GetGroupProfitLastYearMinAge(this->vli.company, g_id, this->vli.vtype);
328 if (profit_last_year_min_age < 0) return SPR_PROFIT_NEGATIVE;
329 if (profit_last_year_min_age < VEHICLE_PROFIT_THRESHOLD * num_vehicle_min_age) return SPR_PROFIT_SOME;
330 return SPR_PROFIT_LOT;
331 }
332
342 void DrawGroupInfo(Rect r, GroupID g_id, uint16_t level_mask = 0, uint8_t indent = 0, bool protection = false, bool has_children = false) const
343 {
344 /* Highlight the group if a vehicle is dragged over it */
345 if (g_id == this->group_over) {
346 GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(COLOUR_GREY, SHADE_LIGHTEST));
347 }
348
349 if (g_id == NEW_GROUP) return;
350
351 /* draw the selected group in white, else we draw it in black */
352 TextColour colour = g_id == this->vli.ToGroupID() ? TC_WHITE : TC_BLACK;
353 const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype);
354 bool rtl = _current_text_dir == TD_RTL;
355
356 const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
357 const int level_width = rtl ? -WidgetDimensions::scaled.hsep_indent : WidgetDimensions::scaled.hsep_indent;
358 const PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
359
360 r = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
361 if (indent > 0) {
362 /* Draw tree continuation lines. */
363 int tx = (rtl ? r.right : r.left) + offset;
364 for (uint lvl = 1; lvl <= indent; ++lvl) {
365 if (HasBit(level_mask, lvl)) GfxDrawLine(tx, r.top, tx, r.bottom, linecolour, WidgetDimensions::scaled.fullbevel.top);
366 if (lvl < indent) tx += level_width;
367 }
368 /* Draw our node in the tree. */
369 int ycentre = CentreBounds(r.top, r.bottom, WidgetDimensions::scaled.fullbevel.top);
370 if (!HasBit(level_mask, indent)) GfxDrawLine(tx, r.top, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
371 GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
372 }
373
374 /* draw fold / unfold button */
375 if (has_children) {
376 DrawSpriteIgnorePadding(Group::Get(g_id)->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, r.WithX(this->column_rects[VGC_FOLD]).Translate(indent * level_width, 0), SA_CENTER);
377 }
378
379 /* draw group name */
380 DrawString(r.WithX(this->column_rects[VGC_NAME]).Indent(indent * WidgetDimensions::scaled.hsep_indent, rtl).CentreToHeight(this->column_size[VGC_NAME].height), this->GetGroupNameString(g_id), colour);
381
382 /* draw autoreplace protection */
383 if (protection) {
384 DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, r.WithX(this->column_rects[VGC_PROTECT]), SA_CENTER);
385 }
386
387 /* draw autoreplace status */
388 if (stats.autoreplace_defined) {
389 DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_ACTIVE, stats.autoreplace_finished ? PALETTE_CRASH : PAL_NONE, r.WithX(this->column_rects[VGC_AUTOREPLACE]), SA_CENTER);
390 }
391
392 /* draw the profit icon */
393 DrawSpriteIgnorePadding(this->GetGroupProfitSpriteID(g_id), PAL_NONE, r.WithX(this->column_rects[VGC_PROFIT]), SA_CENTER);
394
395 /* draw the number of vehicles of the group */
396 int num_vehicle_with_subgroups = GetGroupNumVehicle(this->vli.company, g_id, this->vli.vtype);
397 int num_vehicle = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype).num_vehicle;
398 if (IsAllGroupID(g_id) || IsDefaultGroupID(g_id) || num_vehicle_with_subgroups == num_vehicle) {
399 DrawString(r.WithX(this->column_rects[VGC_NUMBER]).CentreToHeight(this->column_size[VGC_NUMBER].height), GetString(STR_JUST_COMMA, num_vehicle), colour, SA_RIGHT | SA_FORCE, false, FS_SMALL);
400 } else {
401 DrawString(r.WithX(this->column_rects[VGC_NUMBER]).CentreToHeight(this->column_size[VGC_NUMBER].height), GetString(STR_GROUP_COUNT_WITH_SUBGROUP, num_vehicle, num_vehicle_with_subgroups - num_vehicle), colour, SA_RIGHT | SA_FORCE);
402 }
403 }
404
409 {
410 if (this->group_over == GroupID::Invalid()) return;
411
412 if (IsAllGroupID(this->group_over)) {
414 } else if (IsDefaultGroupID(this->group_over)) {
416 } else {
418 }
419 }
420
421public:
423 {
424 this->CreateNestedTree();
425
426 this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR);
427 this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR);
428
429 this->vli.SetIndex(ALL_GROUP);
430
431 this->groups.ForceRebuild();
432 this->groups.NeedResort();
433 this->BuildGroupList(vli.company);
434 this->group_sb->SetCount(this->groups.size());
435
436 this->GetWidget<NWidgetCore>(WID_GL_CAPTION)->SetString(STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype);
437 this->GetWidget<NWidgetCore>(WID_GL_LIST_VEHICLE)->SetToolTip(STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype);
438
439 this->GetWidget<NWidgetCore>(WID_GL_CREATE_GROUP)->SetSprite(SPR_GROUP_CREATE_TRAIN + this->vli.vtype);
440 this->GetWidget<NWidgetCore>(WID_GL_RENAME_GROUP)->SetSprite(SPR_GROUP_RENAME_TRAIN + this->vli.vtype);
441 this->GetWidget<NWidgetCore>(WID_GL_DELETE_GROUP)->SetSprite(SPR_GROUP_DELETE_TRAIN + this->vli.vtype);
442 this->GetWidget<NWidgetCore>(WID_GL_LIVERY_GROUP)->SetSprite(SPR_GROUP_LIVERY_TRAIN + this->vli.vtype);
443 this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->SetSprite(SPR_GROUP_REPLACE_OFF_TRAIN + this->vli.vtype);
444
445 this->FinishInitNested(window_number);
446 this->owner = vli.company;
447
448 this->BuildVehicleList();
449 this->SortVehicleList();
450 }
451
454 {
455 *this->sorting = this->vehgroups.GetListing();
456 }
457
458 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
459 {
460 switch (widget) {
462 size.width = this->ComputeGroupInfoSize();
463 fill.height = resize.height = this->tiny_step_height;
464 break;
465
468 size.width = this->ComputeGroupInfoSize();
469 size.height = this->tiny_step_height;
470 break;
471
472 case WID_GL_INFO: {
473 uint left_side = 0;
474 for (const StringID &label : {STR_GROUP_PROFIT_THIS_PERIOD, STR_GROUP_PROFIT_THIS_YEAR, STR_GROUP_PROFIT_LAST_PERIOD, STR_GROUP_PROFIT_LAST_YEAR, STR_GROUP_OCCUPANCY}) {
475 left_side = std::max(left_side, GetStringBoundingBox(label).width);
476 }
477
478 /* Guestimate that 12 digits is reasonable*/
479 uint right_side = std::max(
480 GetStringBoundingBox(GetString(STR_GROUP_OCCUPANCY_VALUE, GetParamMaxDigits(3))).width,
481 GetStringBoundingBox(GetString(STR_JUST_CURRENCY_LONG, GetParamMaxDigits(12))).width
482 );
483
484 size.width = left_side + WidgetDimensions::scaled.hsep_wide + right_side + padding.width;
485 break;
486 }
487
490 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
491 d.height += padding.height;
492 size = maxdim(size, d);
493 break;
494 }
495
497 this->ComputeGroupInfoSize();
498 fill.height = resize.height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height);
499 size.height = 4 * resize.height;
500 break;
501
503 size.width = GetStringListWidth(this->vehicle_group_by_names) + padding.width;
504 break;
505
507 size.width = GetStringListWidth(this->vehicle_group_none_sorter_names_calendar);
508 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_none_sorter_names_wallclock));
509 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_calendar));
510 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_wallclock));
511 size.width += padding.width;
512 break;
513
515 size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList(true)).width + padding.width);
516 break;
517
519 Dimension d = this->GetActionDropdownSize(true, true, true);
520 d.height += padding.height;
521 d.width += padding.width;
522 size = maxdim(size, d);
523 break;
524 }
525 }
526 }
527
533 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
534 {
535 if (data == 0) {
536 /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
537 this->vehgroups.ForceRebuild();
538 this->groups.ForceRebuild();
539 } else {
540 this->vehgroups.ForceResort();
541 this->groups.ForceResort();
542 }
543
544 /* Process ID-invalidation in command-scope as well */
545 if (this->group_rename != GroupID::Invalid() && !Group::IsValidID(this->group_rename)) {
547 this->group_rename = GroupID::Invalid();
548 }
549
550 GroupID group = this->vli.ToGroupID();
551 if (!(IsAllGroupID(group) || IsDefaultGroupID(group) || Group::IsValidID(group))) {
552 this->vli.SetIndex(ALL_GROUP);
554 }
555 this->SetDirty();
556 }
557
558 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
559 {
560 switch (widget) {
562 return GetString(this->GetCargoFilterLabel(this->cargo_filter_criteria));
563
565 return GetString(STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype);
566
567 case WID_GL_CAPTION:
568 /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption
569 * We list all vehicles or ungrouped vehicles */
570 if (IsDefaultGroupID(this->vli.ToGroupID()) || IsAllGroupID(this->vli.ToGroupID())) {
571 return GetString(stringid, STR_COMPANY_NAME, this->vli.company, this->vehicles.size(), this->vehicles.size());
572 } else {
573 uint num_vehicle = GetGroupNumVehicle(this->vli.company, this->vli.ToGroupID(), this->vli.vtype);
574
575 return GetString(stringid, STR_GROUP_NAME, this->vli.ToGroupID(), num_vehicle, num_vehicle);
576 }
577
578 default:
579 return this->Window::GetWidgetString(widget, stringid);
580 }
581 }
582
583 void OnPaint() override
584 {
585 /* If we select the all vehicles, this->list will contain all vehicles of the owner
586 * else this->list will contain all vehicles which belong to the selected group */
587 this->BuildVehicleList();
588 this->SortVehicleList();
589
590 this->BuildGroupList(this->owner);
591
592 this->group_sb->SetCount(this->groups.size());
593 this->vscroll->SetCount(this->vehgroups.size());
594
595 /* The drop down menu is out, *but* it may not be used, retract it. */
596 if (this->vehicles.empty() && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) {
599 }
600
601 /* Disable all lists management button when the list is empty */
602 this->SetWidgetsDisabledState(this->vehicles.empty() || _local_company != this->vli.company,
606
607 /* Disable the group specific function when we select the default group or all vehicles */
608 GroupID group = this->vli.ToGroupID();
609 this->SetWidgetsDisabledState(IsDefaultGroupID(group) || IsAllGroupID(group) || _local_company != this->vli.company,
614
615 /* Disable remaining buttons for non-local companies
616 * Needed while changing _local_company, eg. by cheats
617 * All procedures (eg. move vehicle to another group)
618 * verify, whether you are the owner of the vehicle,
619 * so it doesn't have to be disabled
620 */
624
625 /* If not a default group and the group has replace protection, show an enabled replace sprite. */
626 uint16_t protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN;
627 if (!IsDefaultGroupID(group) && !IsAllGroupID(group) && Group::Get(group)->flags.Test(GroupFlag::ReplaceProtection)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN;
628 this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->SetSprite(protect_sprite + this->vli.vtype);
629
630 /* Set text of "group by" dropdown widget. */
631 this->GetWidget<NWidgetCore>(WID_GL_GROUP_BY_DROPDOWN)->SetString(std::data(this->vehicle_group_by_names)[this->grouping]);
632
633 /* Set text of "sort by" dropdown widget. */
634 this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->SetString(this->GetVehicleSorterNames()[this->vehgroups.SortType()]);
635
636 this->DrawWidgets();
637 }
638
639 void DrawWidget(const Rect &r, WidgetID widget) const override
640 {
641 switch (widget) {
644 break;
645
648 break;
649
650 case WID_GL_INFO: {
651 Money this_year = 0;
652 Money last_year = 0;
653 uint64_t occupancy = 0;
654
655 for (const Vehicle * const v : this->vehicles) {
656 assert(v->owner == this->owner);
657
658 this_year += v->GetDisplayProfitThisYear();
659 last_year += v->GetDisplayProfitLastYear();
660 occupancy += v->trip_occupancy;
661 }
662
663 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
664
665 DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_GROUP_PROFIT_THIS_PERIOD : STR_GROUP_PROFIT_THIS_YEAR, TC_BLACK);
666 DrawString(tr, GetString(STR_JUST_CURRENCY_LONG, this_year), TC_BLACK, SA_RIGHT);
667
668 tr.top += GetCharacterHeight(FS_NORMAL);
669 DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_GROUP_PROFIT_LAST_PERIOD : STR_GROUP_PROFIT_LAST_YEAR, TC_BLACK);
670 DrawString(tr, GetString(STR_JUST_CURRENCY_LONG, last_year), TC_BLACK, SA_RIGHT);
671
672 tr.top += GetCharacterHeight(FS_NORMAL);
673 DrawString(tr, STR_GROUP_OCCUPANCY, TC_BLACK);
674 const size_t vehicle_count = this->vehicles.size();
675 if (vehicle_count > 0) {
676 DrawString(tr, GetString(STR_GROUP_OCCUPANCY_VALUE, occupancy / vehicle_count), TC_BLACK, SA_RIGHT);
677 }
678
679 break;
680 }
681
682 case WID_GL_LIST_GROUP: {
683 Rect row = r.WithHeight(this->tiny_step_height);
684
685 auto [first, last] = this->group_sb->GetVisibleRangeIterators(this->groups);
686 for (auto it = first; it != last; ++it) {
687 const Group *g = it->group;
688 assert(g->owner == this->owner);
689
690 DrawGroupInfo(row, g->index, it->level_mask, it->indent, g->flags.Test(GroupFlag::ReplaceProtection), g->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent));
691 row = row.Translate(0, this->tiny_step_height);
692 }
693 if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.size()) {
695 }
696 break;
697 }
698
700 this->DrawSortButtonState(WID_GL_SORT_BY_ORDER, this->vehgroups.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
701 break;
702
704 if (this->vli.ToGroupID() != ALL_GROUP && this->grouping == GB_NONE) {
705 /* Mark vehicles which are in sub-groups (only if we are not using shared order coalescing) */
706 Rect mr = r.WithHeight(this->resize.step_height);
707 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->vehgroups);
708 for (auto it = first; it != last; ++it) {
709 const Vehicle *v = it->GetSingleVehicle();
710 if (v->group_id != this->vli.ToGroupID()) {
712 }
713 mr = mr.Translate(0, this->resize.step_height);
714 }
715 }
716
717 this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r);
718 break;
719 }
720 }
721
722 static void DeleteGroupCallback(Window *win, bool confirmed)
723 {
724 if (confirmed) {
726 w->vli.SetIndex(ALL_GROUP);
727 Command<Commands::DeleteGroup>::Post(STR_ERROR_GROUP_CAN_T_DELETE, w->group_confirm);
728 }
729 }
730
731 void OnMouseLoop() override
732 {
733 if (last_overlay_state != ShowCargoIconOverlay()) {
734 last_overlay_state = ShowCargoIconOverlay();
735 this->SetDirty();
736 }
737 }
738
739 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
740 {
741 switch (widget) {
742 case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending
743 this->vehgroups.ToggleSortOrder();
744 this->SetDirty();
745 break;
746
747 case WID_GL_GROUP_BY_DROPDOWN: // Select grouping option dropdown menu
748 ShowDropDownMenu(this, this->vehicle_group_by_names, this->grouping, WID_GL_GROUP_BY_DROPDOWN, 0, 0);
749 return;
750
751 case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu
752 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));
753 return;
754
755 case WID_GL_FILTER_BY_CARGO: { // Select filtering criteria dropdown menu
756 static std::string cargo_filter;
757 ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria, widget, 0, DropDownOption::Filterable, &cargo_filter);
758 break;
759 }
760
761 case WID_GL_ALL_VEHICLES: // All vehicles button
762 if (!IsAllGroupID(this->vli.ToGroupID())) {
763 this->vli.SetIndex(ALL_GROUP);
764 this->vehgroups.ForceRebuild();
765 this->SetDirty();
766 }
767 break;
768
769 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button
770 if (!IsDefaultGroupID(this->vli.ToGroupID())) {
771 this->vli.SetIndex(DEFAULT_GROUP);
772 this->vehgroups.ForceRebuild();
773 this->SetDirty();
774 }
775 break;
776
777 case WID_GL_LIST_GROUP: { // Matrix Group
778 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
779 if (it == this->groups.end()) return;
780
781 if (it->group->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)) {
782 /* The group has children, check if the user clicked the fold / unfold button. */
783 bool rtl = _current_text_dir == TD_RTL;
784 Rect r = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
785 r = r.Indent(it->indent * WidgetDimensions::scaled.hsep_indent, rtl).WithWidth(this->column_size[VGC_FOLD].width, rtl);
786 if (click_count > 1 || r.Contains(pt)) {
787
788 GroupID g = this->vli.ToGroupID();
789 if (!IsAllGroupID(g) && !IsDefaultGroupID(g)) {
790 do {
791 g = Group::Get(g)->parent;
792 if (g == it->group->index) {
793 this->vli.SetIndex(g);
794 break;
795 }
796 } while (g != GroupID::Invalid());
797 }
798
799 Group::Get(it->group->index)->folded = !it->group->folded;
800 this->groups.ForceRebuild();
801
802 this->SetDirty();
803 break;
804 }
805 }
806
807 this->vli.SetIndex(it->group->index);
808 this->group_sel = it->group->index;
809
811
812 this->vehgroups.ForceRebuild();
813 this->SetDirty();
814 break;
815 }
816
817 case WID_GL_LIST_VEHICLE: { // Matrix Vehicle
818 auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
819 if (it == this->vehgroups.end()) return; // click out of list bound
820
821 const GUIVehicleGroup &vehgroup = *it;
822
823 const Vehicle *v = nullptr;
824
825 switch (this->grouping) {
826 case GB_NONE: {
827 const Vehicle *v2 = vehgroup.GetSingleVehicle();
828 if (VehicleClicked(v2)) break;
829 v = v2;
830 break;
831 }
832
833 case GB_SHARED_ORDERS: {
834 assert(vehgroup.NumVehicles() > 0);
835 v = vehgroup.vehicles_begin[0];
836 /*
837 * No VehicleClicked(v) support for now, because don't want
838 * to enable any contextual actions except perhaps clicking/ctrl-clicking to clone orders.
839 */
840 break;
841 }
842
843 default:
844 NOT_REACHED();
845 }
846 if (v) {
847 if (_ctrl_pressed && this->grouping == GB_SHARED_ORDERS) {
848 ShowOrdersWindow(v);
849 } else {
850 this->vehicle_sel = v->index;
851
852 if (_ctrl_pressed && this->grouping == GB_NONE) {
853 /*
854 * It only makes sense to select a group if not using shared orders
855 * since two vehicles sharing orders can be from different groups.
856 */
857 this->SelectGroup(v->group_id);
858 }
859
862 _cursor.vehchain = true;
863
864 this->SetDirty();
865 }
866 }
867
868 break;
869 }
870
871 case WID_GL_CREATE_GROUP: { // Create a new group
872 Command<Commands::CreateGroup>::Post(STR_ERROR_GROUP_CAN_T_CREATE, CcCreateGroup, this->vli.vtype, this->vli.ToGroupID());
873 break;
874 }
875
876 case WID_GL_DELETE_GROUP: { // Delete the selected group
877 this->group_confirm = this->vli.ToGroupID();
878 ShowQuery(
879 GetEncodedString(STR_QUERY_GROUP_DELETE_CAPTION),
880 GetEncodedString(STR_GROUP_DELETE_QUERY_TEXT),
881 this, DeleteGroupCallback);
882 break;
883 }
884
885 case WID_GL_RENAME_GROUP: // Rename the selected roup
886 this->ShowRenameGroupWindow(this->vli.ToGroupID(), false);
887 break;
888
889 case WID_GL_LIVERY_GROUP: // Set group livery
890 ShowCompanyLiveryWindow(this->owner, this->vli.ToGroupID());
891 break;
892
894 ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype);
895 break;
896
898 ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.ToGroupID()), IsDefaultGroupID(this->vli.ToGroupID())), -1, WID_GL_MANAGE_VEHICLES_DROPDOWN);
899 break;
900 }
901
902 case WID_GL_START_ALL:
903 case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list
904 Command<Commands::MassStartStop>::Post(TileIndex{}, widget == WID_GL_START_ALL, true, this->vli);
905 break;
906 }
907
909 const Group *g = Group::GetIfValid(this->vli.ToGroupID());
910 if (g != nullptr) {
911 Command<Commands::SetGroupFlag>::Post(this->vli.ToGroupID(), GroupFlag::ReplaceProtection, !g->flags.Test(GroupFlag::ReplaceProtection), _ctrl_pressed);
912 }
913 break;
914 }
915 }
916 }
917
918 void OnDragDrop_Group(Point pt, WidgetID widget)
919 {
920 const Group *g = Group::Get(this->group_sel);
921
922 switch (widget) {
923 case WID_GL_ALL_VEHICLES: // All vehicles
924 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
925 if (g->parent != GroupID::Invalid()) {
926 Command<Commands::AlterGroup>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, GroupID::Invalid(), {});
927 }
928
929 this->group_sel = GroupID::Invalid();
930 this->group_over = GroupID::Invalid();
931 this->SetDirty();
932 break;
933
934 case WID_GL_LIST_GROUP: { // Matrix group
935 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
936 GroupID new_g = it == this->groups.end() ? GroupID::Invalid() : it->group->index;
937
938 if (this->group_sel != new_g && g->parent != new_g) {
939 Command<Commands::AlterGroup>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, new_g, {});
940 }
941
942 this->group_sel = GroupID::Invalid();
943 this->group_over = GroupID::Invalid();
944 this->SetDirty();
945 break;
946 }
947 }
948 }
949
950 void OnDragDrop_Vehicle(Point pt, WidgetID widget)
951 {
952 switch (widget) {
953 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
954 Command<Commands::AddVehicleToGroup>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, DEFAULT_GROUP, this->vehicle_sel, _ctrl_pressed || this->grouping == GB_SHARED_ORDERS, VehicleListIdentifier{});
955
956 this->vehicle_sel = VehicleID::Invalid();
957 this->group_over = GroupID::Invalid();
958
959 this->SetDirty();
960 break;
961
962 case WID_GL_LIST_GROUP: { // Matrix group
963 const VehicleID vindex = this->vehicle_sel;
964 this->vehicle_sel = VehicleID::Invalid();
965 this->group_over = GroupID::Invalid();
966 this->SetDirty();
967
968 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
969 GroupID new_g = it == this->groups.end() ? NEW_GROUP : it->group->index;
970
971 Command<Commands::AddVehicleToGroup>::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{});
972 break;
973 }
974
975 case WID_GL_LIST_VEHICLE: { // Matrix vehicle
976 const VehicleID vindex = this->vehicle_sel;
977 this->vehicle_sel = VehicleID::Invalid();
978 this->group_over = GroupID::Invalid();
979 this->SetDirty();
980
981 auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
982 if (it == this->vehgroups.end()) return; // click out of list bound
983
984 const GUIVehicleGroup &vehgroup = *it;
985 switch (this->grouping) {
986 case GB_NONE: {
987 const Vehicle *v = vehgroup.GetSingleVehicle();
988 if (!VehicleClicked(v) && vindex == v->index) {
990 }
991 break;
992 }
993
994 case GB_SHARED_ORDERS: {
995 if (!VehicleClicked(vehgroup)) {
996 const Vehicle *v = vehgroup.vehicles_begin[0];
997 if (vindex == v->index) {
998 if (vehgroup.NumVehicles() == 1) {
1000 } else {
1001 ShowVehicleListWindow(v);
1002 }
1003 }
1004 }
1005 break;
1006 }
1007
1008 default:
1009 NOT_REACHED();
1010 }
1011 break;
1012 }
1013 }
1014 }
1015
1016 void OnDragDrop(Point pt, WidgetID widget) override
1017 {
1018 if (this->vehicle_sel != VehicleID::Invalid()) OnDragDrop_Vehicle(pt, widget);
1019 if (this->group_sel != GroupID::Invalid()) OnDragDrop_Group(pt, widget);
1020
1021 _cursor.vehchain = false;
1022 }
1023
1024 void OnQueryTextFinished(std::optional<std::string> str) override
1025 {
1026 if (str.has_value()) Command<Commands::AlterGroup>::Post(STR_ERROR_GROUP_CAN_T_RENAME, AlterGroupMode::Rename, this->group_rename, GroupID::Invalid(), *str);
1027 this->group_rename = GroupID::Invalid();
1028 }
1029
1030 void OnResize() override
1031 {
1032 this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP);
1033 this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE);
1034 this->UpdateColumnRects();
1035 }
1036
1037 void OnDropdownSelect(WidgetID widget, int index, int) override
1038 {
1039 switch (widget) {
1041 this->UpdateVehicleGroupBy(static_cast<GroupBy>(index));
1042 break;
1043
1045 this->vehgroups.SetSortType(index);
1046 break;
1047
1048 case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria
1049 this->SetCargoFilter(index);
1050 break;
1051
1053 assert(!this->vehicles.empty());
1054
1055 switch (index) {
1056 case ADI_REPLACE: // Replace window
1057 ShowReplaceGroupVehicleWindow(this->vli.ToGroupID(), this->vli.vtype);
1058 break;
1059 case ADI_SERVICE: // Send for servicing
1060 case ADI_DEPOT: { // Send to Depots
1061 Command<Commands::SendVehicleToDepot>::Post(GetCmdSendToDepotMsg(this->vli.vtype), VehicleID::Invalid(), (index == ADI_SERVICE ? DepotCommandFlag::Service : DepotCommandFlags{}) | DepotCommandFlag::MassSend, this->vli);
1062 break;
1063 }
1064
1065 case ADI_CREATE_GROUP: // Create group
1066 Command<Commands::AddVehicleToGroup>::Post(CcAddVehicleNewGroup, NEW_GROUP, VehicleID::Invalid(), false, this->vli);
1067 break;
1068
1069 case ADI_ADD_SHARED: // Add shared Vehicles
1070 assert(Group::IsValidID(this->vli.ToGroupID()));
1071
1072 Command<Commands::AddSharedVehiclesToGroup>::Post(STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE, this->vli.ToGroupID(), this->vli.vtype);
1073 break;
1074 case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group
1075 assert(Group::IsValidID(this->vli.ToGroupID()));
1076
1077 Command<Commands::RemoveAllVehiclesGroup>::Post(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES, this->vli.ToGroupID());
1078 break;
1079 default: NOT_REACHED();
1080 }
1081 break;
1082
1083 default: NOT_REACHED();
1084 }
1085
1086 this->SetDirty();
1087 }
1088
1089 void OnGameTick() override
1090 {
1091 if (this->groups.NeedResort() || this->vehgroups.NeedResort()) {
1092 this->SetDirty();
1093 }
1094 }
1095
1096 void OnPlaceObjectAbort() override
1097 {
1098 /* abort drag & drop */
1099 this->vehicle_sel = VehicleID::Invalid();
1101 this->group_sel = GroupID::Invalid();
1102 this->group_over = GroupID::Invalid();
1104 }
1105
1106 void OnMouseDrag(Point pt, WidgetID widget) override
1107 {
1108 if (this->vehicle_sel == VehicleID::Invalid() && this->group_sel == GroupID::Invalid()) return;
1109
1110 /* A vehicle is dragged over... */
1111 GroupID new_group_over = GroupID::Invalid();
1112 switch (widget) {
1113 case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group.
1114 new_group_over = DEFAULT_GROUP;
1115 break;
1116
1117 case WID_GL_LIST_GROUP: { // ... the list of custom groups.
1118 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
1119 new_group_over = it == this->groups.end() ? NEW_GROUP : it->group->index;
1120 break;
1121 }
1122 }
1123
1124 /* Do not highlight when dragging over the current group */
1125 if (this->vehicle_sel != VehicleID::Invalid()) {
1126 if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = GroupID::Invalid();
1127 } else if (this->group_sel != GroupID::Invalid()) {
1128 if (this->group_sel == new_group_over || Group::Get(this->group_sel)->parent == new_group_over) new_group_over = GroupID::Invalid();
1129 }
1130
1131 /* Mark widgets as dirty if the group changed. */
1132 if (new_group_over != this->group_over) {
1134 this->group_over = new_group_over;
1136 }
1137 }
1138
1139 void ShowRenameGroupWindow(GroupID group, bool empty)
1140 {
1141 assert(Group::IsValidID(group));
1142 this->group_rename = group;
1143
1144 /* Show empty query for new groups */
1145 std::string str;
1146 if (!empty) str = GetString(STR_GROUP_NAME, group);
1147
1149 }
1150
1157 {
1158 if (this->vehicle_sel == vehicle) ResetObjectToPlace();
1159 }
1160
1166 void SelectGroup(const GroupID g_id)
1167 {
1168 if (g_id == GroupID::Invalid() || g_id == this->vli.ToGroupID()) return;
1169
1170 this->vli.SetIndex(g_id);
1171 if (g_id != ALL_GROUP && g_id != DEFAULT_GROUP) {
1172 const Group *g = Group::Get(g_id);
1173
1174 auto found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
1175 if (found == std::end(this->groups)) {
1176 /* The group's branch is maybe collapsed, so try to expand it. */
1177 for (auto pg = Group::GetIfValid(g->parent); pg != nullptr; pg = Group::GetIfValid(pg->parent)) {
1178 pg->folded = false;
1179 }
1180 this->groups.ForceRebuild();
1181 this->BuildGroupList(this->owner);
1182 this->group_sb->SetCount(this->groups.size());
1183 found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
1184 }
1185 if (found != std::end(this->groups)) this->group_sb->ScrollTowards(std::distance(std::begin(this->groups), found));
1186 }
1187 this->vehgroups.ForceRebuild();
1188 this->SetDirty();
1189 }
1190
1191};
1192
1193static WindowDesc _vehicle_group_desc[] = {
1194 {
1195 WDP_AUTO, "list_groups_train", 525, 246,
1197 {},
1198 _nested_group_widgets
1199 },
1200 {
1201 WDP_AUTO, "list_groups_roadveh", 460, 246,
1203 {},
1204 _nested_group_widgets
1205 },
1206 {
1207 WDP_AUTO, "list_groups_ship", 460, 246,
1209 {},
1210 _nested_group_widgets
1211 },
1212 {
1213 WDP_AUTO, "list_groups_aircraft", 460, 246,
1215 {},
1216 _nested_group_widgets
1217 },
1218};
1219
1227template <bool Tneed_existing_window>
1228static void ShowCompanyGroupInternal(CompanyID company, VehicleType vehicle_type, GroupID group)
1229{
1230 if (!Company::IsValidID(company)) return;
1231
1232 assert(vehicle_type < std::size(_vehicle_group_desc));
1233 VehicleListIdentifier vli(VL_GROUP_LIST, vehicle_type, company);
1235 if (w != nullptr) w->SelectGroup(group);
1236}
1237
1244void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group)
1245{
1246 ShowCompanyGroupInternal<false>(company, vehicle_type, group);
1247}
1248
1257
1265{
1266 return dynamic_cast<VehicleGroupWindow *>(FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).ToWindowNumber()));
1267}
1268
1274static void CcCreateGroup(GroupID gid, VehicleType veh_type)
1275{
1277 if (w != nullptr) w->ShowRenameGroupWindow(gid, true);
1278}
1279
1287void CcCreateGroup(Commands, const CommandCost &result, GroupID new_group, VehicleType vt, GroupID)
1288{
1289 if (result.Failed()) return;
1290
1291 assert(vt <= VEH_AIRCRAFT);
1292 CcCreateGroup(new_group, vt);
1293}
1294
1300void CcAddVehicleNewGroup(Commands, const CommandCost &result, GroupID new_group, GroupID, VehicleID, bool, const VehicleListIdentifier &)
1301{
1302 if (result.Failed()) return;
1303
1304 const Group *g = Group::Get(new_group);
1305 CcCreateGroup(new_group, g->vehicle_type);
1306}
1307
1313{
1314 /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either
1315 * If that is the case, we can skip looping though the windows and save time
1316 */
1317 if (_special_mouse_mode != WSM_DRAGDROP) return;
1318
1320 if (w != nullptr) w->UnselectVehicle(v->index);
1321}
void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype)
Show the autoreplace configuration window for a particular group.
Functions related to the autoreplace GUIs.
constexpr T AssignBit(T &x, const uint8_t y, bool value)
Assigns a bit in a variable.
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Common return value for all commands.
bool Failed() const
Did this command fail?
void RebuildDone()
Notify the sortlist that the rebuild is done.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
Scrollbar data structure.
void SetCount(size_t num)
Sets the number of elements in the list.
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.
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:2504
void ScrollTowards(size_type position)
Scroll towards the given position; if the item is visible nothing happens, otherwise it will be shown...
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
size_type GetPosition() const
Gets the position of the first visible element in the list.
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
SpriteID GetGroupProfitSpriteID(GroupID g_id) const
Get the profit sprite ID to draw for the given group.
void UnselectVehicle(VehicleID vehicle)
Tests whether a given vehicle is selected in the window, and unselects it if necessary.
void DirtyHighlightedGroupWidget()
Mark the widget containing the currently highlighted group as dirty.
GroupID group_sel
Selected group (for drag/drop).
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnDragDrop(Point pt, WidgetID widget) override
A dragged 'object' has been released.
GroupID group_rename
Group being renamed, GroupID::Invalid() if none.
void OnMouseDrag(Point pt, WidgetID widget) override
An 'object' is being dragged at the provided position, highlight the target if possible.
void BuildGroupList(Owner owner)
(Re)Build the group list.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
uint tiny_step_height
Step height for the group list.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
~VehicleGroupWindow()
Save the last sorting state.
void OnResize() override
Called after the window got resized.
void OnGameTick() override
Called once per (game) tick.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void UpdateColumnRects()
Update precalculated column rects for drawing group information.
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
GroupID group_confirm
Group awaiting delete confirmation.
std::string GetGroupNameString(GroupID g_id) const
Get the string to draw for the given group.
std::array< Dimension, VGC_END > column_size
Size of the columns in the group list.
GUIGroupList groups
List of groups.
GroupID group_over
Group over which a vehicle is dragged, GroupID::Invalid() if none.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
uint ComputeGroupInfoSize()
Compute tiny_step_height and column_size.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnMouseLoop() override
Called for every mouse loop run, which is at least once per (game) tick.
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
void DrawGroupInfo(Rect r, 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.
void SelectGroup(const GroupID g_id)
Selects the specified group in the list.
void OnPaint() override
The window must be repainted.
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
Functions related to commands.
Commands
List of commands.
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.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
GUI Functions related to companies.
void ShowDropDownMenu(Window *w, std::span< const StringID > strings, int selected, WidgetID button, uint32_t disabled_mask, uint32_t hidden_mask, uint width, DropDownOptions options, std::string *const persistent_filter_text)
Show a dropdown menu window near a widget of the parent window.
Definition dropdown.cpp:627
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
Definition dropdown.cpp:545
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options, std::string *const persistent_filter_text)
Show a drop down list.
Definition dropdown.cpp:585
Functions related to the drop down widget.
@ Filterable
Set if the dropdown is filterable.
#define DECLARE_INCREMENT_DECREMENT_OPERATORS(enum_type)
For some enums it is useful to have pre/post increment/decrement operators.
Definition enum_type.hpp:86
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:87
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:900
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:669
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
uint GetStringListWidth(std::span< const StringID > list, FontSize fontsize)
Get maximum width of a list of strings.
Definition gfx.cpp:924
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:116
Functions related to the gfx engine.
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:70
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ FS_SMALL
Index of the small font in the font tables.
Definition gfx_type.h:250
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:390
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:400
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:346
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...
@ ReplaceProtection
If set, the global autoreplace has no effect on the group.
Definition group.h:68
bool IsAllGroupID(GroupID id_g)
Checks if a GroupID stands for all vehicles of a company.
Definition group.h:104
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.
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...
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Command definitions related to engine groups.
@ Rename
Change group name.
Definition group_cmd.h:24
@ SetParent
Change group parent.
Definition group_cmd.h:25
void SetDirty() const
Mark entire window as dirty (in need of re-paint).
Definition window.cpp:980
void BuildGuiGroupList(GUIGroupList &list, bool fold, Owner owner, VehicleType veh_type)
Build GUI group list, a sorted hierarchical list of groups for owner and vehicle type.
VehicleGroupColumns
Columns in the group list.
@ VGC_AUTOREPLACE
Autoreplace active icon.
@ VGC_PROTECT
Autoreplace protect icon.
@ VGC_PROFIT
Profit icon.
@ VGC_NAME
Group name.
@ VGC_NUMBER
Number of vehicles in the group.
@ VGC_FOLD
Fold / Unfold button.
void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group)
Show the group window for the given company and vehicle type.
void DeleteGroupHighlightOfVehicle(const Vehicle *v)
Removes the highlight of a vehicle in a group window.
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.
static VehicleGroupWindow * FindVehicleGroupWindow(VehicleType vt, Owner owner)
Finds a group list window determined by vehicle type and owner.
static void ShowCompanyGroupInternal(CompanyID company, VehicleType vehicle_type, GroupID group)
Show the group window for the given company and vehicle type.
static void GuiGroupListAddChildren(GUIGroupList &list, GUIGroupListItem &item, bool fold, uint8_t indent=1)
Add children to GUI group list to build a hierarchical tree.
void ShowCompanyGroupForVehicle(const Vehicle *v)
Show the group window for the given vehicle.
static void CcCreateGroup(GroupID gid, VehicleType veh_type)
Opens a 'Rename group' window for newly created group.
Functions/definitions that have something to do with groups.
static constexpr GroupID DEFAULT_GROUP
Ungrouped vehicles are in this group.
Definition group_type.h:18
static constexpr GroupID ALL_GROUP
All vehicles are in this group.
Definition group_type.h:17
static constexpr GroupID NEW_GROUP
Sentinel for a to-be-created group.
Definition group_type.h:16
static const uint MAX_LENGTH_GROUP_NAME_CHARS
The maximum length of a group name in characters including '\0'.
Definition group_type.h:20
Types related to the group widgets.
@ WID_GL_LIST_GROUP
List of the groups.
@ WID_GL_STOP_ALL
Stop all button.
@ WID_GL_REPLACE_PROTECTION
Replace protection button.
@ WID_GL_MANAGE_VEHICLES_DROPDOWN
Manage vehicles dropdown list.
@ WID_GL_GROUP_BY_ORDER
Group order.
@ WID_GL_SORT_BY_ORDER
Sort order.
@ WID_GL_GROUP_BY_DROPDOWN
Group by dropdown list.
@ WID_GL_CAPTION
Caption of the window.
@ WID_GL_START_ALL
Start all button.
@ WID_GL_ALL_VEHICLES
All vehicles entry.
@ WID_GL_DELETE_GROUP
Delete group button.
@ WID_GL_AVAILABLE_VEHICLES
Available vehicles.
@ WID_GL_RENAME_GROUP
Rename group button.
@ WID_GL_LIST_VEHICLE_SCROLLBAR
Scrollbar for the list.
@ WID_GL_LIVERY_GROUP
Group livery button.
@ WID_GL_SORT_BY_DROPDOWN
Sort by dropdown list.
@ WID_GL_LIST_VEHICLE
List of the vehicles.
@ WID_GL_FILTER_BY_CARGO
Filter vehicles by cargo type.
@ WID_GL_CREATE_GROUP
Create group button.
@ WID_GL_LIST_GROUP_SCROLLBAR
Scrollbar for the list.
@ WID_GL_INFO
Group info.
@ WID_GL_DEFAULT_VEHICLES
Default vehicles entry.
GUI functions that shouldn't be here.
#define Point
Macro that prevents name conflicts between included headers.
void ShowQuery(EncodedString &&caption, EncodedString &&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...
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
@ Vehicle
Vehicle news item. (new engine available).
Definition news_type.h:81
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:393
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:1619
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition sprites.h:1404
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:429
Functions related to low-level strings.
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:236
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:218
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
void SetCargoFilter(CargoType cargo_type)
Set cargo filter for the vehicle group list.
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.
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.
CargoType cargo_filter_criteria
Selected cargo filter index.
VehicleType type
Type of vehicle.
T y
Y coordinate.
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:25
uint16_t num_vehicle
Number of vehicles.
Definition group.h:29
bool autoreplace_defined
Are any autoreplace rules set?
Definition group.h:31
static GroupStatistics & Get(CompanyID company, GroupID id_g, VehicleType type)
Returns the GroupStatistics for a specific group.
Definition group_cmd.cpp:82
bool autoreplace_finished
Have all autoreplacement finished?
Definition group.h:32
Group data.
Definition group.h:74
GroupFlags flags
Group flags.
Definition group.h:79
GroupID parent
Parent group.
Definition group.h:86
VehicleType vehicle_type
Vehicle type of the group.
Definition group.h:77
bool folded
NOSAVE: Is this group folded in the group view?
Definition group.h:84
uint16_t number
Per-company group number.
Definition group.h:87
Owner owner
Group Owner.
Definition group.h:76
FlatSet< GroupID > children
NOSAVE: child groups belonging to this group.
Definition group.h:83
Colour for pixel/line drawing.
Definition gfx_type.h:405
static Pool::IterateWrapper< Group > Iterate(size_t from=0)
static Group * Get(auto index)
static bool IsValidID(auto index)
static Group * GetIfValid(auto index)
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
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 Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect CentreToHeight(int height) const
Centre a vertical dimension within this Rect.
Rect WithX(int new_left, int new_right) const
Create a new Rect, replacing the left and right coordiates.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
bool Contains(const Point &pt) const
Test if a point falls inside this Rect.
The information about a vehicle list.
Definition vehiclelist.h:32
CompanyID company
The company associated with this list.
Definition vehiclelist.h:35
WindowNumber ToWindowNumber() const
Pack a VehicleListIdentifier in 32 bits so it can be used as unique WindowNumber.
VehicleType vtype
The vehicle type associated with this list.
Definition vehiclelist.h:34
Vehicle data structure.
GroupID group_id
Index of group Pool array.
Owner owner
Which company owns the vehicle?
High level window description.
Definition window_gui.h:168
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:274
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:817
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1822
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:768
Window * parent
Parent window.
Definition window_gui.h:329
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:470
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:570
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:518
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:800
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1089
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:516
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1812
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:990
WindowFlags flags
Window flags.
Definition window_gui.h:301
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:327
int height
Height of the window (number of pixels down in y direction).
Definition window_gui.h:313
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
Stuff related to the text buffer GUI.
@ EnableDefault
enable the 'Default' button ("\0" is returned)
Definition textbuf_gui.h:20
@ LengthIsInChars
the length of the string is counted in characters
Definition textbuf_gui.h:21
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
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...
@ 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.
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, ...
PoolID< uint32_t, struct VehicleIDTag, 0xFF000, 0xFFFFF > VehicleID
The type all our vehicle IDs have.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_TRAIN
Train vehicle type.
@ 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).
@ VL_GROUP_LIST
Index is the group.
Definition vehiclelist.h:27
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX).
Definition widget_type.h:57
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX).
Definition widget_type.h:55
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window).
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX).
Definition widget_type.h:56
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
@ EqualSize
Containers should keep all their (resizing) children equally large.
@ BigFirst
Allocate space to biggest resize first.
void CloseWindowByClass(WindowClass cls, int data)
Close all windows of a given class.
Definition window.cpp:1222
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition window.cpp:96
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1166
Window functions not directly related to making/drawing windows.
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:219
@ SBS_UP
Sort descending.
Definition window_gui.h:220
@ WSM_DRAGDROP
Drag&drop an object.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_ROADVEH_LIST
Road vehicle list; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50
@ WC_SHIPS_LIST
Ships list; Window numbers:
@ WC_TRAINS_LIST
Trains list; Window numbers:
@ WC_DROPDOWN_MENU
Drop down menu; Window numbers:
@ WC_QUERY_STRING
Query string window; Window numbers:
@ WC_AIRCRAFT_LIST
Aircraft list; Window numbers: