OpenTTD Source 20250312-master-gcdcc6b491d
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"
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
35
36#include "table/sprites.h"
37
38#include "safeguards.h"
39
40static 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),
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
121static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, bool fold, GroupID parent = GroupID::Invalid(), 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
156void 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 last_group[0] = {a.group, GetString(STR_GROUP_NAME, a.group->index)};
174 }
175
176 if (b.group != last_group[1].first) {
177 last_group[1] = {b.group, GetString(STR_GROUP_NAME, b.group->index)};
178 }
179
180 int r = StrNaturalCompare(last_group[0].second, last_group[1].second); // Sort by name (natural sorting).
181 if (r == 0) return a.group->number < b.group->number;
182 return r < 0;
183 });
184
185 GuiGroupListAddChildren(dst, list, fold, GroupID::Invalid(), 0);
186}
187
189private:
190 /* Columns in the group list */
201
202 GroupID group_sel = GroupID::Invalid();
203 GroupID group_rename = GroupID::Invalid();
204 GroupID group_over = GroupID::Invalid();
205 GroupID group_confirm = GroupID::Invalid();
208 Scrollbar *group_sb = nullptr;
209
210 std::array<Dimension, VGC_END> column_size{};
211 bool last_overlay_state = false;
212
219 {
220 if (!this->groups.NeedRebuild()) return;
221
222 this->groups.clear();
223
224 BuildGuiGroupList(this->groups, true, owner, this->vli.vtype);
225
226 this->groups.RebuildDone();
227 }
228
234 {
235 this->column_size[VGC_FOLD] = maxdim(GetSpriteSize(SPR_CIRCLE_FOLDED), GetSpriteSize(SPR_CIRCLE_UNFOLDED));
236 this->tiny_step_height = this->column_size[VGC_FOLD].height;
237
239 this->column_size[VGC_NAME].width = std::max(170u, this->column_size[VGC_NAME].width) + WidgetDimensions::scaled.hsep_indent;
240 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NAME].height);
241
242 this->column_size[VGC_PROTECT] = GetSpriteSize(SPR_GROUP_REPLACE_PROTECT);
243 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROTECT].height);
244
245 this->column_size[VGC_AUTOREPLACE] = GetSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
246 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height);
247
248 this->column_size[VGC_PROFIT].width = 0;
249 this->column_size[VGC_PROFIT].height = 0;
250 static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT};
251 for (const auto &profit_sprite : profit_sprites) {
254 }
255 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROFIT].height);
256
257 int num_vehicle = GetGroupNumVehicle(this->vli.company, ALL_GROUP, this->vli.vtype);
258 uint64_t max_value = GetParamMaxValue(num_vehicle, 3, FS_SMALL);
260 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NUMBER].height);
261
262 this->tiny_step_height += WidgetDimensions::scaled.framerect.Vertical();
263
270 this->column_size[VGC_NUMBER].width +
272 }
273
284 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
285 {
286 /* Highlight the group if a vehicle is dragged over it */
287 if (g_id == this->group_over) {
288 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));
289 }
290
291 if (g_id == NEW_GROUP) return;
292
293 /* draw the selected group in white, else we draw it in black */
294 TextColour colour = g_id == this->vli.ToGroupID() ? TC_WHITE : TC_BLACK;
295 const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype);
296 bool rtl = _current_text_dir == TD_RTL;
297
298 const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
300 const int linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
301
302 if (indent > 0) {
303 /* Draw tree continuation lines. */
304 int tx = (rtl ? right - WidgetDimensions::scaled.framerect.right : left + WidgetDimensions::scaled.framerect.left) + offset;
305 for (uint lvl = 1; lvl <= indent; ++lvl) {
306 if (HasBit(level_mask, lvl)) GfxDrawLine(tx, y, tx, y + this->tiny_step_height - 1, linecolour, WidgetDimensions::scaled.fullbevel.top);
307 if (lvl < indent) tx += level_width;
308 }
309 /* Draw our node in the tree. */
310 int ycentre = y + this->tiny_step_height / 2 - 1;
311 if (!HasBit(level_mask, indent)) GfxDrawLine(tx, y, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
312 GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
313 }
314
315 /* draw fold / unfold button */
316 int x = rtl ? right - WidgetDimensions::scaled.framerect.right - this->column_size[VGC_FOLD].width + 1 : left + WidgetDimensions::scaled.framerect.left;
317 if (has_children) {
318 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);
319 }
320
321 /* draw group name */
322 std::string str;
323 if (IsAllGroupID(g_id)) {
325 } else if (IsDefaultGroupID(g_id)) {
327 } else {
329 }
331 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, std::move(str), colour);
332
333 /* draw autoreplace protection */
335 if (protection) DrawSprite(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROTECT].height) / 2);
336
337 /* draw autoreplace status */
339 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);
340
341 /* draw the profit icon */
344 uint num_vehicle_min_age = GetGroupNumVehicleMinAge(this->vli.company, g_id, this->vli.vtype);
345 Money profit_last_year_min_age = GetGroupProfitLastYearMinAge(this->vli.company, g_id, this->vli.vtype);
346 if (num_vehicle_min_age == 0) {
347 spr = SPR_PROFIT_NA;
348 } else if (profit_last_year_min_age < 0) {
349 spr = SPR_PROFIT_NEGATIVE;
350 } else if (profit_last_year_min_age < VEHICLE_PROFIT_THRESHOLD * num_vehicle_min_age) {
351 spr = SPR_PROFIT_SOME;
352 } else {
353 spr = SPR_PROFIT_LOT;
354 }
355 DrawSprite(spr, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROFIT].height) / 2);
356
357 /* draw the number of vehicles of the group */
359 int num_vehicle_with_subgroups = GetGroupNumVehicle(this->vli.company, g_id, this->vli.vtype);
360 int num_vehicle = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype).num_vehicle;
361 if (IsAllGroupID(g_id) || IsDefaultGroupID(g_id) || num_vehicle_with_subgroups == num_vehicle) {
362 DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, GetString(STR_JUST_COMMA, num_vehicle), colour, SA_RIGHT | SA_FORCE, false, FS_SMALL);
363 } else {
364 DrawString(x, x + this->column_size[VGC_NUMBER].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NUMBER].height) / 2, GetString(STR_GROUP_COUNT_WITH_SUBGROUP, num_vehicle, num_vehicle_with_subgroups - num_vehicle), colour, SA_RIGHT | SA_FORCE);
365 }
366 }
367
372 {
373 if (this->group_over == GroupID::Invalid()) return;
374
375 if (IsAllGroupID(this->group_over)) {
377 } else if (IsDefaultGroupID(this->group_over)) {
379 } else {
381 }
382 }
383
384public:
386 {
387 this->CreateNestedTree();
388
389 this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR);
390 this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR);
391
392 this->vli.SetIndex(ALL_GROUP);
393
394 this->groups.ForceRebuild();
395 this->groups.NeedResort();
396 this->BuildGroupList(vli.company);
397 this->group_sb->SetCount(this->groups.size());
398
401
402 this->GetWidget<NWidgetCore>(WID_GL_CREATE_GROUP)->SetSprite(SPR_GROUP_CREATE_TRAIN + this->vli.vtype);
403 this->GetWidget<NWidgetCore>(WID_GL_RENAME_GROUP)->SetSprite(SPR_GROUP_RENAME_TRAIN + this->vli.vtype);
404 this->GetWidget<NWidgetCore>(WID_GL_DELETE_GROUP)->SetSprite(SPR_GROUP_DELETE_TRAIN + this->vli.vtype);
405 this->GetWidget<NWidgetCore>(WID_GL_LIVERY_GROUP)->SetSprite(SPR_GROUP_LIVERY_TRAIN + this->vli.vtype);
406 this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->SetSprite(SPR_GROUP_REPLACE_OFF_TRAIN + this->vli.vtype);
407
408 this->FinishInitNested(window_number);
409 this->owner = vli.company;
410
411 this->BuildVehicleList();
412 this->SortVehicleList();
413 }
414
416 {
417 *this->sorting = this->vehgroups.GetListing();
418 }
419
421 {
422 switch (widget) {
424 size.width = this->ComputeGroupInfoSize();
425 resize.height = this->tiny_step_height;
426 fill.height = this->tiny_step_height;
427 break;
428
431 size.width = this->ComputeGroupInfoSize();
432 size.height = this->tiny_step_height;
433 break;
434
437 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
438 d.height += padding.height;
439 size = maxdim(size, d);
440 break;
441 }
442
444 this->ComputeGroupInfoSize();
445 resize.height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height);
446 size.height = 4 * resize.height;
447 break;
448
450 size.width = GetStringListWidth(this->vehicle_group_by_names) + padding.width;
451 break;
452
454 size.width = GetStringListWidth(this->vehicle_group_none_sorter_names_calendar);
455 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_none_sorter_names_wallclock));
456 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_calendar));
457 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_wallclock));
458 size.width += padding.width;
459 break;
460
462 size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList(true)).width + padding.width);
463 break;
464
466 Dimension d = this->GetActionDropdownSize(true, true, true);
467 d.height += padding.height;
468 d.width += padding.width;
469 size = maxdim(size, d);
470 break;
471 }
472 }
473 }
474
480 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
481 {
482 if (data == 0) {
483 /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
484 this->vehgroups.ForceRebuild();
485 this->groups.ForceRebuild();
486 } else {
487 this->vehgroups.ForceResort();
488 this->groups.ForceResort();
489 }
490
491 /* Process ID-invalidation in command-scope as well */
492 if (this->group_rename != GroupID::Invalid() && !Group::IsValidID(this->group_rename)) {
494 this->group_rename = GroupID::Invalid();
495 }
496
497 GroupID group = this->vli.ToGroupID();
498 if (!(IsAllGroupID(group) || IsDefaultGroupID(group) || Group::IsValidID(group))) {
499 this->vli.SetIndex(ALL_GROUP);
501 }
502 this->SetDirty();
503 }
504
505 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
506 {
507 switch (widget) {
509 return GetString(this->GetCargoFilterLabel(this->cargo_filter_criteria));
510
513
514 case WID_GL_CAPTION:
515 /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption
516 * We list all vehicles or ungrouped vehicles */
517 if (IsDefaultGroupID(this->vli.ToGroupID()) || IsAllGroupID(this->vli.ToGroupID())) {
518 return GetString(stringid, STR_COMPANY_NAME, this->vli.company, this->vehicles.size(), this->vehicles.size());
519 } else {
520 uint num_vehicle = GetGroupNumVehicle(this->vli.company, this->vli.ToGroupID(), this->vli.vtype);
521
522 return GetString(stringid, STR_GROUP_NAME, this->vli.ToGroupID(), num_vehicle, num_vehicle);
523 }
524
525 default:
526 return this->Window::GetWidgetString(widget, stringid);
527 }
528 }
529
530 void OnPaint() override
531 {
532 /* If we select the all vehicles, this->list will contain all vehicles of the owner
533 * else this->list will contain all vehicles which belong to the selected group */
534 this->BuildVehicleList();
535 this->SortVehicleList();
536
537 this->BuildGroupList(this->owner);
538
539 this->group_sb->SetCount(this->groups.size());
540 this->vscroll->SetCount(this->vehgroups.size());
541
542 /* The drop down menu is out, *but* it may not be used, retract it. */
543 if (this->vehicles.empty() && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) {
546 }
547
548 /* Disable all lists management button when the list is empty */
549 this->SetWidgetsDisabledState(this->vehicles.empty() || _local_company != this->vli.company,
553
554 /* Disable the group specific function when we select the default group or all vehicles */
555 GroupID group = this->vli.ToGroupID();
556 this->SetWidgetsDisabledState(IsDefaultGroupID(group) || IsAllGroupID(group) || _local_company != this->vli.company,
561
562 /* Disable remaining buttons for non-local companies
563 * Needed while changing _local_company, eg. by cheats
564 * All procedures (eg. move vehicle to another group)
565 * verify, whether you are the owner of the vehicle,
566 * so it doesn't have to be disabled
567 */
571
572 /* If not a default group and the group has replace protection, show an enabled replace sprite. */
573 uint16_t protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN;
574 if (!IsDefaultGroupID(group) && !IsAllGroupID(group) && Group::Get(group)->flags.Test(GroupFlag::ReplaceProtection)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN;
575 this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->SetSprite(protect_sprite + this->vli.vtype);
576
577 /* Set text of "group by" dropdown widget. */
578 this->GetWidget<NWidgetCore>(WID_GL_GROUP_BY_DROPDOWN)->SetString(std::data(this->vehicle_group_by_names)[this->grouping]);
579
580 /* Set text of "sort by" dropdown widget. */
581 this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->SetString(this->GetVehicleSorterNames()[this->vehgroups.SortType()]);
582
583 this->DrawWidgets();
584 }
585
586 void DrawWidget(const Rect &r, WidgetID widget) const override
587 {
588 switch (widget) {
590 DrawGroupInfo(r.top, r.left, r.right, ALL_GROUP);
591 break;
592
594 DrawGroupInfo(r.top, r.left, r.right, DEFAULT_GROUP);
595 break;
596
597 case WID_GL_INFO: {
598 Money this_year = 0;
599 Money last_year = 0;
601
602 for (const Vehicle * const v : this->vehicles) {
603 assert(v->owner == this->owner);
604
605 this_year += v->GetDisplayProfitThisYear();
606 last_year += v->GetDisplayProfitLastYear();
607 occupancy += v->trip_occupancy;
608 }
609
610 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
611
614
618
621 const size_t vehicle_count = this->vehicles.size();
622 if (vehicle_count > 0) {
624 }
625
626 break;
627 }
628
629 case WID_GL_LIST_GROUP: {
630 int y1 = r.top;
631 auto [first, last] = this->group_sb->GetVisibleRangeIterators(this->groups);
632 for (auto it = first; it != last; ++it) {
633 const Group *g = it->group;
634
635 assert(g->owner == this->owner);
636
637 DrawGroupInfo(y1, r.left, r.right, 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));
638
639 y1 += this->tiny_step_height;
640 }
641 if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.size()) {
642 DrawGroupInfo(y1, r.left, r.right, NEW_GROUP);
643 }
644 break;
645 }
646
649 break;
650
652 if (this->vli.ToGroupID() != ALL_GROUP && this->grouping == GB_NONE) {
653 /* Mark vehicles which are in sub-groups (only if we are not using shared order coalescing) */
655 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->vehgroups);
656 for (auto it = first; it != last; ++it) {
657 const Vehicle *v = it->GetSingleVehicle();
658 if (v->group_id != this->vli.ToGroupID()) {
660 }
661 mr = mr.Translate(0, this->resize.step_height);
662 }
663 }
664
665 this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r);
666 break;
667 }
668 }
669
670 static void DeleteGroupCallback(Window *win, bool confirmed)
671 {
672 if (confirmed) {
674 w->vli.SetIndex(ALL_GROUP);
676 }
677 }
678
679 void OnMouseLoop() override
680 {
681 if (last_overlay_state != ShowCargoIconOverlay()) {
682 last_overlay_state = ShowCargoIconOverlay();
683 this->SetDirty();
684 }
685 }
686
687 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
688 {
689 switch (widget) {
690 case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending
692 this->SetDirty();
693 break;
694
695 case WID_GL_GROUP_BY_DROPDOWN: // Select grouping option dropdown menu
696 ShowDropDownMenu(this, this->vehicle_group_by_names, this->grouping, WID_GL_GROUP_BY_DROPDOWN, 0, 0);
697 return;
698
699 case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu
700 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));
701 return;
702
703 case WID_GL_FILTER_BY_CARGO: // Select filtering criteria dropdown menu
704 ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria, widget);
705 break;
706
707 case WID_GL_ALL_VEHICLES: // All vehicles button
708 if (!IsAllGroupID(this->vli.ToGroupID())) {
709 this->vli.SetIndex(ALL_GROUP);
710 this->vehgroups.ForceRebuild();
711 this->SetDirty();
712 }
713 break;
714
715 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button
716 if (!IsDefaultGroupID(this->vli.ToGroupID())) {
717 this->vli.SetIndex(DEFAULT_GROUP);
718 this->vehgroups.ForceRebuild();
719 this->SetDirty();
720 }
721 break;
722
723 case WID_GL_LIST_GROUP: { // Matrix Group
724 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
725 if (it == this->groups.end()) return;
726
727 if (it->group->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)) {
728 /* The group has children, check if the user clicked the fold / unfold button. */
730 int x = _current_text_dir == TD_RTL ?
733 if (click_count > 1 || (pt.x >= x && pt.x < (int)(x + this->column_size[VGC_FOLD].width))) {
734
735 GroupID g = this->vli.ToGroupID();
736 if (!IsAllGroupID(g) && !IsDefaultGroupID(g)) {
737 do {
738 g = Group::Get(g)->parent;
739 if (g == it->group->index) {
740 this->vli.SetIndex(g);
741 break;
742 }
743 } while (g != GroupID::Invalid());
744 }
745
746 Group::Get(it->group->index)->folded = !it->group->folded;
747 this->groups.ForceRebuild();
748
749 this->SetDirty();
750 break;
751 }
752 }
753
754 this->vli.SetIndex(it->group->index);
755 this->group_sel = it->group->index;
756
758
759 this->vehgroups.ForceRebuild();
760 this->SetDirty();
761 break;
762 }
763
764 case WID_GL_LIST_VEHICLE: { // Matrix Vehicle
765 auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
766 if (it == this->vehgroups.end()) return; // click out of list bound
767
768 const GUIVehicleGroup &vehgroup = *it;
769
770 const Vehicle *v = nullptr;
771
772 switch (this->grouping) {
773 case GB_NONE: {
774 const Vehicle *v2 = vehgroup.GetSingleVehicle();
775 if (VehicleClicked(v2)) break;
776 v = v2;
777 break;
778 }
779
780 case GB_SHARED_ORDERS: {
781 assert(vehgroup.NumVehicles() > 0);
782 v = vehgroup.vehicles_begin[0];
783 /*
784 * No VehicleClicked(v) support for now, because don't want
785 * to enable any contextual actions except perhaps clicking/ctrl-clicking to clone orders.
786 */
787 break;
788 }
789
790 default:
791 NOT_REACHED();
792 }
793 if (v) {
794 if (_ctrl_pressed && this->grouping == GB_SHARED_ORDERS) {
795 ShowOrdersWindow(v);
796 } else {
797 this->vehicle_sel = v->index;
798
799 if (_ctrl_pressed && this->grouping == GB_NONE) {
800 /*
801 * It only makes sense to select a group if not using shared orders
802 * since two vehicles sharing orders can be from different groups.
803 */
804 this->SelectGroup(v->group_id);
805 }
806
809 _cursor.vehchain = true;
810
811 this->SetDirty();
812 }
813 }
814
815 break;
816 }
817
818 case WID_GL_CREATE_GROUP: { // Create a new group
820 break;
821 }
822
823 case WID_GL_DELETE_GROUP: { // Delete the selected group
824 this->group_confirm = this->vli.ToGroupID();
825 ShowQuery(
828 this, DeleteGroupCallback);
829 break;
830 }
831
832 case WID_GL_RENAME_GROUP: // Rename the selected roup
833 this->ShowRenameGroupWindow(this->vli.ToGroupID(), false);
834 break;
835
836 case WID_GL_LIVERY_GROUP: // Set group livery
837 ShowCompanyLiveryWindow(this->owner, this->vli.ToGroupID());
838 break;
839
841 ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype);
842 break;
843
845 ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.ToGroupID()), IsDefaultGroupID(this->vli.ToGroupID())), -1, WID_GL_MANAGE_VEHICLES_DROPDOWN);
846 break;
847 }
848
849 case WID_GL_START_ALL:
850 case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list
852 break;
853 }
854
856 const Group *g = Group::GetIfValid(this->vli.ToGroupID());
857 if (g != nullptr) {
859 }
860 break;
861 }
862 }
863 }
864
865 void OnDragDrop_Group(Point pt, WidgetID widget)
866 {
867 const Group *g = Group::Get(this->group_sel);
868
869 switch (widget) {
870 case WID_GL_ALL_VEHICLES: // All vehicles
871 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
872 if (g->parent != GroupID::Invalid()) {
874 }
875
876 this->group_sel = GroupID::Invalid();
877 this->group_over = GroupID::Invalid();
878 this->SetDirty();
879 break;
880
881 case WID_GL_LIST_GROUP: { // Matrix group
882 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
883 GroupID new_g = it == this->groups.end() ? GroupID::Invalid() : it->group->index;
884
885 if (this->group_sel != new_g && g->parent != new_g) {
887 }
888
889 this->group_sel = GroupID::Invalid();
890 this->group_over = GroupID::Invalid();
891 this->SetDirty();
892 break;
893 }
894 }
895 }
896
897 void OnDragDrop_Vehicle(Point pt, WidgetID widget)
898 {
899 switch (widget) {
900 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
902
903 this->vehicle_sel = VehicleID::Invalid();
904 this->group_over = GroupID::Invalid();
905
906 this->SetDirty();
907 break;
908
909 case WID_GL_LIST_GROUP: { // Matrix group
910 const VehicleID vindex = this->vehicle_sel;
911 this->vehicle_sel = VehicleID::Invalid();
912 this->group_over = GroupID::Invalid();
913 this->SetDirty();
914
915 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
916 GroupID new_g = it == this->groups.end() ? NEW_GROUP : it->group->index;
917
919 break;
920 }
921
922 case WID_GL_LIST_VEHICLE: { // Matrix vehicle
923 const VehicleID vindex = this->vehicle_sel;
924 this->vehicle_sel = VehicleID::Invalid();
925 this->group_over = GroupID::Invalid();
926 this->SetDirty();
927
928 auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
929 if (it == this->vehgroups.end()) return; // click out of list bound
930
931 const GUIVehicleGroup &vehgroup = *it;
932 switch (this->grouping) {
933 case GB_NONE: {
934 const Vehicle *v = vehgroup.GetSingleVehicle();
935 if (!VehicleClicked(v) && vindex == v->index) {
937 }
938 break;
939 }
940
941 case GB_SHARED_ORDERS: {
942 if (!VehicleClicked(vehgroup)) {
943 const Vehicle *v = vehgroup.vehicles_begin[0];
944 if (vindex == v->index) {
945 if (vehgroup.NumVehicles() == 1) {
947 } else {
948 ShowVehicleListWindow(v);
949 }
950 }
951 }
952 break;
953 }
954
955 default:
956 NOT_REACHED();
957 }
958 break;
959 }
960 }
961 }
962
963 void OnDragDrop(Point pt, WidgetID widget) override
964 {
965 if (this->vehicle_sel != VehicleID::Invalid()) OnDragDrop_Vehicle(pt, widget);
966 if (this->group_sel != GroupID::Invalid()) OnDragDrop_Group(pt, widget);
967
968 _cursor.vehchain = false;
969 }
970
971 void OnQueryTextFinished(std::optional<std::string> str) override
972 {
973 if (str.has_value()) Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_RENAME, AlterGroupMode::Rename, this->group_rename, GroupID::Invalid(), *str);
974 this->group_rename = GroupID::Invalid();
975 }
976
977 void OnResize() override
978 {
979 this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP);
980 this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE);
981 }
982
983 void OnDropdownSelect(WidgetID widget, int index) override
984 {
985 switch (widget) {
987 this->UpdateVehicleGroupBy(static_cast<GroupBy>(index));
988 break;
989
991 this->vehgroups.SetSortType(index);
992 break;
993
994 case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria
995 this->SetCargoFilter(index);
996 break;
997
999 assert(!this->vehicles.empty());
1000
1001 switch (index) {
1002 case ADI_REPLACE: // Replace window
1003 ShowReplaceGroupVehicleWindow(this->vli.ToGroupID(), this->vli.vtype);
1004 break;
1005 case ADI_SERVICE: // Send for servicing
1006 case ADI_DEPOT: { // Send to Depots
1007 Command<CMD_SEND_VEHICLE_TO_DEPOT>::Post(GetCmdSendToDepotMsg(this->vli.vtype), VehicleID::Invalid(), (index == ADI_SERVICE ? DepotCommandFlag::Service : DepotCommandFlags{}) | DepotCommandFlag::MassSend, this->vli);
1008 break;
1009 }
1010
1011 case ADI_CREATE_GROUP: // Create group
1012 Command<CMD_ADD_VEHICLE_GROUP>::Post(CcAddVehicleNewGroup, NEW_GROUP, VehicleID::Invalid(), false, this->vli);
1013 break;
1014
1015 case ADI_ADD_SHARED: // Add shared Vehicles
1016 assert(Group::IsValidID(this->vli.ToGroupID()));
1017
1019 break;
1020 case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group
1021 assert(Group::IsValidID(this->vli.ToGroupID()));
1022
1024 break;
1025 default: NOT_REACHED();
1026 }
1027 break;
1028
1029 default: NOT_REACHED();
1030 }
1031
1032 this->SetDirty();
1033 }
1034
1035 void OnGameTick() override
1036 {
1037 if (this->groups.NeedResort() || this->vehgroups.NeedResort()) {
1038 this->SetDirty();
1039 }
1040 }
1041
1042 void OnPlaceObjectAbort() override
1043 {
1044 /* abort drag & drop */
1045 this->vehicle_sel = VehicleID::Invalid();
1047 this->group_sel = GroupID::Invalid();
1048 this->group_over = GroupID::Invalid();
1050 }
1051
1052 void OnMouseDrag(Point pt, WidgetID widget) override
1053 {
1054 if (this->vehicle_sel == VehicleID::Invalid() && this->group_sel == GroupID::Invalid()) return;
1055
1056 /* A vehicle is dragged over... */
1057 GroupID new_group_over = GroupID::Invalid();
1058 switch (widget) {
1059 case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group.
1061 break;
1062
1063 case WID_GL_LIST_GROUP: { // ... the list of custom groups.
1064 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
1065 new_group_over = it == this->groups.end() ? NEW_GROUP : it->group->index;
1066 break;
1067 }
1068 }
1069
1070 /* Do not highlight when dragging over the current group */
1071 if (this->vehicle_sel != VehicleID::Invalid()) {
1072 if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = GroupID::Invalid();
1073 } else if (this->group_sel != GroupID::Invalid()) {
1074 if (this->group_sel == new_group_over || Group::Get(this->group_sel)->parent == new_group_over) new_group_over = GroupID::Invalid();
1075 }
1076
1077 /* Mark widgets as dirty if the group changed. */
1078 if (new_group_over != this->group_over) {
1080 this->group_over = new_group_over;
1082 }
1083 }
1084
1085 void ShowRenameGroupWindow(GroupID group, bool empty)
1086 {
1087 assert(Group::IsValidID(group));
1088 this->group_rename = group;
1089
1090 /* Show empty query for new groups */
1091 std::string str;
1092 if (!empty) str = GetString(STR_GROUP_NAME, group);
1093
1095 }
1096
1103 {
1104 if (this->vehicle_sel == vehicle) ResetObjectToPlace();
1105 }
1106
1113 {
1114 if (g_id == GroupID::Invalid() || g_id == this->vli.ToGroupID()) return;
1115
1116 this->vli.SetIndex(g_id);
1117 if (g_id != ALL_GROUP && g_id != DEFAULT_GROUP) {
1118 const Group *g = Group::Get(g_id);
1119
1120 auto found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
1121 if (found == std::end(this->groups)) {
1122 /* The group's branch is maybe collapsed, so try to expand it. */
1123 for (auto pg = Group::GetIfValid(g->parent); pg != nullptr; pg = Group::GetIfValid(pg->parent)) {
1124 pg->folded = false;
1125 }
1126 this->groups.ForceRebuild();
1127 this->BuildGroupList(this->owner);
1128 this->group_sb->SetCount(this->groups.size());
1129 found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
1130 }
1131 if (found != std::end(this->groups)) this->group_sb->ScrollTowards(std::distance(std::begin(this->groups), found));
1132 }
1133 this->vehgroups.ForceRebuild();
1134 this->SetDirty();
1135 }
1136
1137};
1138
1139static WindowDesc _vehicle_group_desc[] = {
1140 {
1141 WDP_AUTO, "list_groups_train", 525, 246,
1143 {},
1144 _nested_group_widgets
1145 },
1146 {
1147 WDP_AUTO, "list_groups_roadveh", 460, 246,
1149 {},
1150 _nested_group_widgets
1151 },
1152 {
1153 WDP_AUTO, "list_groups_ship", 460, 246,
1155 {},
1156 _nested_group_widgets
1157 },
1158 {
1159 WDP_AUTO, "list_groups_aircraft", 460, 246,
1161 {},
1162 _nested_group_widgets
1163 },
1164};
1165
1173template <bool Tneed_existing_window>
1174static void ShowCompanyGroupInternal(CompanyID company, VehicleType vehicle_type, GroupID group)
1175{
1176 if (!Company::IsValidID(company)) return;
1177
1178 assert(vehicle_type < std::size(_vehicle_group_desc));
1179 VehicleListIdentifier vli(VL_GROUP_LIST, vehicle_type, company);
1180 VehicleGroupWindow *w = AllocateWindowDescFront<VehicleGroupWindow, Tneed_existing_window>(_vehicle_group_desc[vehicle_type], vli.ToWindowNumber(), vli);
1181 if (w != nullptr) w->SelectGroup(group);
1182}
1183
1190void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group)
1191{
1192 ShowCompanyGroupInternal<false>(company, vehicle_type, group);
1193}
1194
1200{
1201 ShowCompanyGroupInternal<true>(v->owner, v->type, v->group_id);
1202}
1203
1211{
1212 return dynamic_cast<VehicleGroupWindow *>(FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).ToWindowNumber()));
1213}
1214
1219static void CcCreateGroup(GroupID gid, VehicleType veh_type)
1220{
1222 if (w != nullptr) w->ShowRenameGroupWindow(gid, true);
1223}
1224
1232void CcCreateGroup(Commands, const CommandCost &result, GroupID new_group, VehicleType vt, GroupID)
1233{
1234 if (result.Failed()) return;
1235
1236 assert(vt <= VEH_AIRCRAFT);
1237 CcCreateGroup(new_group, vt);
1238}
1239
1246{
1247 if (result.Failed()) return;
1248
1249 const Group *g = Group::Get(new_group);
1250 CcCreateGroup(new_group, g->vehicle_type);
1251}
1252
1258{
1259 /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either
1260 * If that is the case, we can skip looping though the windows and save time
1261 */
1262 if (_special_mouse_mode != WSM_DRAGDROP) return;
1263
1265 if (w != nullptr) w->UnselectVehicle(v->index);
1266}
void ShowReplaceGroupVehicleWindow(GroupID id_g, VehicleType vehicletype)
Show the autoreplace configuration window for a particular group.
Functions related to the autoreplace GUIs.
debug_inline constexpr 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.
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?
Enum-as-bit-set wrapper.
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.
int pos_x
Horizontal position of top-left corner of the widget in the window.
Base class for a 'real' widget.
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:2521
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.
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.
void OnResize() override
Called after the window got resized.
void OnGameTick() override
Called once per (game) tick.
@ VGC_PROFIT
Profit icon.
@ VGC_AUTOREPLACE
Autoreplace active icon.
@ VGC_FOLD
Fold / Unfold button.
@ VGC_NAME
Group name.
@ VGC_PROTECT
Autoreplace protect icon.
@ VGC_NUMBER
Number of vehicles in the group.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
GroupID group_confirm
Group awaiting delete confirmation.
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 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.
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) override
A dropdown option associated to this window has been selected.
void SelectGroup(const GroupID g_id)
Selects the specified group in the list.
void OnPaint() override
The window must be repainted.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:29
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:94
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
int hsep_indent
Width of indentation for tree layouts.
Definition window_gui.h:63
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.
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:923
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:852
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:658
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:875
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:115
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:989
Functions related to the gfx engine.
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:244
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:377
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:387
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:294
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:333
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.
bool IsAllGroupID(GroupID id_g)
Checks if a GroupID stands for all vehicles of a company.
Definition group.h:101
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 NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
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 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.
@ SetParent
Change group parent.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:943
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.
static void GuiGroupListAddChildren(GUIGroupList &dst, const GUIGroupList &src, bool fold, GroupID parent=GroupID::Invalid(), uint8_t indent=0)
Add children to GUI group list to build a hierarchical tree.
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.
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.
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.
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.
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.
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:387
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:1609
static const CursorID SPR_CURSOR_MOUSE
Cursor sprite numbers.
Definition sprites.h:1394
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:607
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:248
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:426
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
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.
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.
CargoType cargo_filter_criteria
Selected cargo filter index.
VehicleType type
Type of vehicle.
bool vehchain
vehicle chain is dragged
Definition gfx_type.h:149
Dimensions (a width and height) of a rectangle in 2D.
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
Group data.
Definition group.h:72
GroupFlags flags
Group flags.
Definition group.h:77
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
uint16_t number
Per-company group number.
Definition group.h:84
Owner owner
Group Owner.
Definition group.h:74
Partial widget specification to allow NWidgets to be written nested.
Coordinates of a point in 2D.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
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.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:213
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:793
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1736
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:744
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:554
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:502
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:776
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1038
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:1726
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
int left
x position of left edge of the window
Definition window_gui.h:310
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:973
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:311
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)
@ LengthIsInChars
the length of the string is counted in characters
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).
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, ...
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:65
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:45
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:49
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:54
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:51
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:75
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:67
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:59
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:58
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:55
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:60
@ 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:1155
SpecialMouseMode _special_mouse_mode
Mode of the mouse.
Definition window.cpp:93
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1101
Window functions not directly related to making/drawing windows.
@ 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:145
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:47
@ 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: