OpenTTD Source 20251019-master-g9f7f314f81
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#include "table/strings.h"
38
39#include "safeguards.h"
40
41static constexpr NWidgetPart _nested_group_widgets[] = {
42 NWidget(NWID_HORIZONTAL), // Window header
43 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
44 NWidget(WWT_CAPTION, COLOUR_GREY, WID_GL_CAPTION),
45 NWidget(WWT_SHADEBOX, COLOUR_GREY),
46 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
47 NWidget(WWT_STICKYBOX, COLOUR_GREY),
50 /* left part */
55 NWidget(WWT_MATRIX, COLOUR_GREY, WID_GL_LIST_GROUP), SetMatrixDataTip(1, 0, STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP),
59 NWidget(WWT_PANEL, COLOUR_GREY, WID_GL_INFO), SetFill(1, 1), SetMinimalTextLines(3, WidgetDimensions::unscaled.framerect.Vertical()), EndContainer(),
62 SetToolTip(STR_GROUP_CREATE_TOOLTIP),
64 SetToolTip(STR_GROUP_DELETE_TOOLTIP),
66 SetToolTip(STR_GROUP_RENAME_TOOLTIP),
68 SetToolTip(STR_GROUP_LIVERY_TOOLTIP),
69 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 0), EndContainer(),
71 SetToolTip(STR_GROUP_REPLACE_PROTECTION_TOOLTIP),
74 /* right part */
78 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),
79 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),
82 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_GROUP_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetToolTip(STR_TOOLTIP_GROUP_ORDER),
83 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_SORT_BY_DROPDOWN), SetFill(1, 1), SetMinimalSize(0, 12), SetToolTip(STR_TOOLTIP_SORT_CRITERIA),
86 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalTextLines(1, WidgetDimensions::unscaled.framerect.Vertical()), SetFill(0, 1), SetResize(1, 0), EndContainer(),
88 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_GL_FILTER_BY_CARGO), SetMinimalSize(0, 12), SetFill(0, 1), SetToolTip(STR_TOOLTIP_FILTER_CRITERIA),
89 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(0, 1), SetResize(1, 0), EndContainer(),
97 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(1, 0), SetFill(1, 1), SetResize(1, 0), EndContainer(),
100 SetToolTip(STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP),
101 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetFill(1, 0), SetResize(1, 0), EndContainer(),
103 SetStringTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP),
104 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_STOP_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG),
105 SetSpriteTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP),
106 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_GL_START_ALL), SetAspect(WidgetDimensions::ASPECT_VEHICLE_FLAG),
107 SetSpriteTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP),
108 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
109 EndContainer(),
110 EndContainer(),
111 EndContainer(),
112};
113
114static void SortGUIGroupList(std::vector<GUIGroupListItem> &list)
115{
116 /* Sort the groups by their name */
117 std::array<std::pair<const Group *, std::string>, 2> last_group{};
118
119 std::ranges::sort(list, [&last_group](const GUIGroupListItem &a, const GUIGroupListItem &b) -> bool {
120 if (a.group != last_group[0].first) {
121 last_group[0] = {a.group, GetString(STR_GROUP_NAME, a.group->index)};
122 }
123
124 if (b.group != last_group[1].first) {
125 last_group[1] = {b.group, GetString(STR_GROUP_NAME, b.group->index)};
126 }
127
128 int r = StrNaturalCompare(last_group[0].second, last_group[1].second); // Sort by name (natural sorting).
129 if (r == 0) return a.group->number < b.group->number;
130 return r < 0;
131 });
132}
133
141static void GuiGroupListAddChildren(GUIGroupList &list, GUIGroupListItem &item, bool fold, uint8_t indent = 1)
142{
143 if (fold && item.group->folded) {
144 Group::Get(item.group->index)->folded = !item.group->children.empty();
145 return;
146 }
147
148 if (item.group->children.empty()) return;
149
150 std::vector<GUIGroupListItem> sublist;
151 for (const GroupID &group : item.group->children) {
152 sublist.emplace_back(Group::Get(group), indent);
153 }
154 SortGUIGroupList(sublist);
155
156 for (const GUIGroupListItem &subitem : sublist) {
157 GuiGroupListAddChildren(list, list.emplace_back(subitem), fold, indent + 1);
158 }
159}
160
168void BuildGuiGroupList(GUIGroupList &list, bool fold, Owner owner, VehicleType veh_type)
169{
170 /* Make a temporary list of parent groups */
171 std::vector<GUIGroupListItem> sublist;
172 for (const Group *g : Group::Iterate()) {
173 if (g->parent != GroupID::Invalid()) continue;
174 if (g->owner != owner) continue;
175 if (g->vehicle_type != veh_type) continue;
176 sublist.emplace_back(g, 0);
177 }
178 SortGUIGroupList(sublist);
179
180 /* Now add each parent group, and its children if necessary, to the list. */
181 for (auto &item : sublist) {
182 GuiGroupListAddChildren(list, list.emplace_back(item), fold);
183 }
184
185 if (list.empty()) return;
186
187 /* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
188 uint16_t level_mask = 0;
189 for (auto it = std::rbegin(list); std::next(it) != std::rend(list); ++it) {
190 auto next_it = std::next(it);
191 AssignBit(level_mask, it->indent, it->indent <= next_it->indent);
192 next_it->level_mask = level_mask;
193 }
194}
195
197private:
198 /* Columns in the group list */
209
210 GroupID group_sel = GroupID::Invalid();
211 GroupID group_rename = GroupID::Invalid();
212 GroupID group_over = GroupID::Invalid();
213 GroupID group_confirm = GroupID::Invalid();
216 Scrollbar *group_sb = nullptr;
217
218 std::array<Dimension, VGC_END> column_size{};
219 bool last_overlay_state = false;
220
227 {
228 if (!this->groups.NeedRebuild()) return;
229
230 this->groups.clear();
231
232 BuildGuiGroupList(this->groups, true, owner, this->vli.vtype);
233
234 this->groups.RebuildDone();
235 }
236
242 {
243 this->column_size[VGC_FOLD] = maxdim(GetScaledSpriteSize(SPR_CIRCLE_FOLDED), GetScaledSpriteSize(SPR_CIRCLE_UNFOLDED));
244 this->tiny_step_height = this->column_size[VGC_FOLD].height;
245
246 this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype));
247 this->column_size[VGC_NAME].width = std::max(170u, this->column_size[VGC_NAME].width) + WidgetDimensions::scaled.hsep_indent;
248 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NAME].height);
249
250 this->column_size[VGC_PROTECT] = GetScaledSpriteSize(SPR_GROUP_REPLACE_PROTECT);
251 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROTECT].height);
252
253 this->column_size[VGC_AUTOREPLACE] = GetScaledSpriteSize(SPR_GROUP_REPLACE_ACTIVE);
254 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_AUTOREPLACE].height);
255
256 this->column_size[VGC_PROFIT].width = 0;
257 this->column_size[VGC_PROFIT].height = 0;
258 static const SpriteID profit_sprites[] = {SPR_PROFIT_NA, SPR_PROFIT_NEGATIVE, SPR_PROFIT_SOME, SPR_PROFIT_LOT};
259 for (const auto &profit_sprite : profit_sprites) {
260 Dimension d = GetScaledSpriteSize(profit_sprite);
262 }
263 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_PROFIT].height);
264
265 int num_vehicle = GetGroupNumVehicle(this->vli.company, ALL_GROUP, this->vli.vtype);
266 uint64_t max_value = GetParamMaxValue(num_vehicle, 3, FS_SMALL);
267 this->column_size[VGC_NUMBER] = GetStringBoundingBox(GetString(STR_GROUP_COUNT_WITH_SUBGROUP, max_value, max_value));
268 this->tiny_step_height = std::max(this->tiny_step_height, this->column_size[VGC_NUMBER].height);
269
270 this->tiny_step_height += WidgetDimensions::scaled.framerect.Vertical();
271
278 this->column_size[VGC_NUMBER].width +
280 }
281
290 void DrawGroupInfo(Rect r, GroupID g_id, uint16_t level_mask = 0, uint8_t indent = 0, bool protection = false, bool has_children = false) const
291 {
292 /* Highlight the group if a vehicle is dragged over it */
293 if (g_id == this->group_over) {
294 GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(COLOUR_GREY, SHADE_LIGHTEST));
295 }
296
297 if (g_id == NEW_GROUP) return;
298
299 /* draw the selected group in white, else we draw it in black */
300 TextColour colour = g_id == this->vli.ToGroupID() ? TC_WHITE : TC_BLACK;
301 const GroupStatistics &stats = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype);
302 bool rtl = _current_text_dir == TD_RTL;
303
304 const int offset = (rtl ? -(int)this->column_size[VGC_FOLD].width : (int)this->column_size[VGC_FOLD].width) / 2;
306 const PixelColour linecolour = GetColourGradient(COLOUR_ORANGE, SHADE_NORMAL);
307
308 r = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
309 if (indent > 0) {
310 /* Draw tree continuation lines. */
311 int tx = (rtl ? r.right : r.left) + offset;
312 for (uint lvl = 1; lvl <= indent; ++lvl) {
313 if (HasBit(level_mask, lvl)) GfxDrawLine(tx, r.top, tx, r.bottom, linecolour, WidgetDimensions::scaled.fullbevel.top);
314 if (lvl < indent) tx += level_width;
315 }
316 /* Draw our node in the tree. */
317 int ycentre = CentreBounds(r.top, r.bottom, WidgetDimensions::scaled.fullbevel.top);
318 if (!HasBit(level_mask, indent)) GfxDrawLine(tx, r.top, tx, ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
319 GfxDrawLine(tx, ycentre, tx + offset - (rtl ? -1 : 1), ycentre, linecolour, WidgetDimensions::scaled.fullbevel.top);
320 }
321
322 /* draw fold / unfold button */
323 r = r.Indent(indent * WidgetDimensions::scaled.hsep_indent, rtl);
324 if (has_children) {
325 DrawSpriteIgnorePadding(Group::Get(g_id)->folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED, PAL_NONE, r.WithWidth(this->column_size[VGC_FOLD].width, rtl), SA_CENTER);
326 }
327
328 /* Group name text column shrinks to fit available space. */
329 int text_width = this->column_size[VGC_NAME].width - indent * WidgetDimensions::scaled.hsep_indent;
330
331 /* draw group name */
332 std::string str;
333 if (IsAllGroupID(g_id)) {
334 str = GetString(STR_GROUP_ALL_TRAINS + this->vli.vtype);
335 } else if (IsDefaultGroupID(g_id)) {
336 str = GetString(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype);
337 } else {
338 str = GetString(STR_GROUP_NAME, g_id);
339 }
340 r = r.Indent(this->column_size[VGC_FOLD].width + WidgetDimensions::scaled.hsep_normal, rtl);
341 DrawString(r.WithWidth(text_width, rtl).CentreToHeight(this->column_size[VGC_NAME].height), std::move(str), colour);
342
343 /* draw autoreplace protection */
344 r = r.Indent(text_width + WidgetDimensions::scaled.hsep_wide, rtl);
345 if (protection) {
346 DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, r.WithWidth(this->column_size[VGC_PROTECT].width, rtl), SA_CENTER);
347 }
348
349 /* draw autoreplace status */
350 r = r.Indent(this->column_size[VGC_PROTECT].width + WidgetDimensions::scaled.hsep_normal, rtl);
351 if (stats.autoreplace_defined) {
352 DrawSpriteIgnorePadding(SPR_GROUP_REPLACE_ACTIVE, stats.autoreplace_finished ? PALETTE_CRASH : PAL_NONE, r.WithWidth(this->column_size[VGC_AUTOREPLACE].width, rtl), SA_CENTER);
353 }
354
355 /* draw the profit icon */
356 SpriteID spr;
357 uint num_vehicle_min_age = GetGroupNumVehicleMinAge(this->vli.company, g_id, this->vli.vtype);
358 Money profit_last_year_min_age = GetGroupProfitLastYearMinAge(this->vli.company, g_id, this->vli.vtype);
359 if (num_vehicle_min_age == 0) {
360 spr = SPR_PROFIT_NA;
361 } else if (profit_last_year_min_age < 0) {
362 spr = SPR_PROFIT_NEGATIVE;
363 } else if (profit_last_year_min_age < VEHICLE_PROFIT_THRESHOLD * num_vehicle_min_age) {
364 spr = SPR_PROFIT_SOME;
365 } else {
366 spr = SPR_PROFIT_LOT;
367 }
368
369 r = r.Indent(this->column_size[VGC_AUTOREPLACE].width + WidgetDimensions::scaled.hsep_normal, rtl);
370 DrawSpriteIgnorePadding(spr, PAL_NONE, r.WithWidth(this->column_size[VGC_PROFIT].width, rtl), SA_CENTER);
371
372 /* draw the number of vehicles of the group */
373 r = r.Indent(this->column_size[VGC_PROFIT].width + WidgetDimensions::scaled.hsep_normal, rtl);
374 int num_vehicle_with_subgroups = GetGroupNumVehicle(this->vli.company, g_id, this->vli.vtype);
375 int num_vehicle = GroupStatistics::Get(this->vli.company, g_id, this->vli.vtype).num_vehicle;
376 if (IsAllGroupID(g_id) || IsDefaultGroupID(g_id) || num_vehicle_with_subgroups == num_vehicle) {
377 DrawString(r.CentreToHeight(this->column_size[VGC_NUMBER].height), GetString(STR_JUST_COMMA, num_vehicle), colour, SA_RIGHT | SA_FORCE, false, FS_SMALL);
378 } else {
379 DrawString(r.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);
380 }
381 }
382
387 {
388 if (this->group_over == GroupID::Invalid()) return;
389
390 if (IsAllGroupID(this->group_over)) {
392 } else if (IsDefaultGroupID(this->group_over)) {
394 } else {
396 }
397 }
398
399public:
401 {
402 this->CreateNestedTree();
403
404 this->vscroll = this->GetScrollbar(WID_GL_LIST_VEHICLE_SCROLLBAR);
405 this->group_sb = this->GetScrollbar(WID_GL_LIST_GROUP_SCROLLBAR);
406
407 this->vli.SetIndex(ALL_GROUP);
408
409 this->groups.ForceRebuild();
410 this->groups.NeedResort();
411 this->BuildGroupList(vli.company);
412 this->group_sb->SetCount(this->groups.size());
413
414 this->GetWidget<NWidgetCore>(WID_GL_CAPTION)->SetString(STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype);
415 this->GetWidget<NWidgetCore>(WID_GL_LIST_VEHICLE)->SetToolTip(STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype);
416
417 this->GetWidget<NWidgetCore>(WID_GL_CREATE_GROUP)->SetSprite(SPR_GROUP_CREATE_TRAIN + this->vli.vtype);
418 this->GetWidget<NWidgetCore>(WID_GL_RENAME_GROUP)->SetSprite(SPR_GROUP_RENAME_TRAIN + this->vli.vtype);
419 this->GetWidget<NWidgetCore>(WID_GL_DELETE_GROUP)->SetSprite(SPR_GROUP_DELETE_TRAIN + this->vli.vtype);
420 this->GetWidget<NWidgetCore>(WID_GL_LIVERY_GROUP)->SetSprite(SPR_GROUP_LIVERY_TRAIN + this->vli.vtype);
421 this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->SetSprite(SPR_GROUP_REPLACE_OFF_TRAIN + this->vli.vtype);
422
423 this->FinishInitNested(window_number);
424 this->owner = vli.company;
425
426 this->BuildVehicleList();
427 this->SortVehicleList();
428 }
429
431 {
432 *this->sorting = this->vehgroups.GetListing();
433 }
434
435 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
436 {
437 switch (widget) {
439 size.width = this->ComputeGroupInfoSize();
440 fill.height = resize.height = this->tiny_step_height;
441 break;
442
445 size.width = this->ComputeGroupInfoSize();
446 size.height = this->tiny_step_height;
447 break;
448
450 Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->GetString());
451 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
452 d.height += padding.height;
453 size = maxdim(size, d);
454 break;
455 }
456
458 this->ComputeGroupInfoSize();
459 fill.height = resize.height = GetVehicleListHeight(this->vli.vtype, this->tiny_step_height);
460 size.height = 4 * resize.height;
461 break;
462
464 size.width = GetStringListWidth(this->vehicle_group_by_names) + padding.width;
465 break;
466
468 size.width = GetStringListWidth(this->vehicle_group_none_sorter_names_calendar);
469 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_none_sorter_names_wallclock));
470 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_calendar));
471 size.width = std::max(size.width, GetStringListWidth(this->vehicle_group_shared_orders_sorter_names_wallclock));
472 size.width += padding.width;
473 break;
474
476 size.width = std::max(size.width, GetDropDownListDimension(this->BuildCargoDropDownList(true)).width + padding.width);
477 break;
478
480 Dimension d = this->GetActionDropdownSize(true, true, true);
481 d.height += padding.height;
482 d.width += padding.width;
483 size = maxdim(size, d);
484 break;
485 }
486 }
487 }
488
494 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
495 {
496 if (data == 0) {
497 /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
498 this->vehgroups.ForceRebuild();
499 this->groups.ForceRebuild();
500 } else {
501 this->vehgroups.ForceResort();
502 this->groups.ForceResort();
503 }
504
505 /* Process ID-invalidation in command-scope as well */
506 if (this->group_rename != GroupID::Invalid() && !Group::IsValidID(this->group_rename)) {
508 this->group_rename = GroupID::Invalid();
509 }
510
511 GroupID group = this->vli.ToGroupID();
512 if (!(IsAllGroupID(group) || IsDefaultGroupID(group) || Group::IsValidID(group))) {
513 this->vli.SetIndex(ALL_GROUP);
515 }
516 this->SetDirty();
517 }
518
519 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
520 {
521 switch (widget) {
523 return GetString(this->GetCargoFilterLabel(this->cargo_filter_criteria));
524
526 return GetString(STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vli.vtype);
527
528 case WID_GL_CAPTION:
529 /* If selected_group == DEFAULT_GROUP || ALL_GROUP, draw the standard caption
530 * We list all vehicles or ungrouped vehicles */
531 if (IsDefaultGroupID(this->vli.ToGroupID()) || IsAllGroupID(this->vli.ToGroupID())) {
532 return GetString(stringid, STR_COMPANY_NAME, this->vli.company, this->vehicles.size(), this->vehicles.size());
533 } else {
534 uint num_vehicle = GetGroupNumVehicle(this->vli.company, this->vli.ToGroupID(), this->vli.vtype);
535
536 return GetString(stringid, STR_GROUP_NAME, this->vli.ToGroupID(), num_vehicle, num_vehicle);
537 }
538
539 default:
540 return this->Window::GetWidgetString(widget, stringid);
541 }
542 }
543
544 void OnPaint() override
545 {
546 /* If we select the all vehicles, this->list will contain all vehicles of the owner
547 * else this->list will contain all vehicles which belong to the selected group */
548 this->BuildVehicleList();
549 this->SortVehicleList();
550
551 this->BuildGroupList(this->owner);
552
553 this->group_sb->SetCount(this->groups.size());
554 this->vscroll->SetCount(this->vehgroups.size());
555
556 /* The drop down menu is out, *but* it may not be used, retract it. */
557 if (this->vehicles.empty() && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) {
560 }
561
562 /* Disable all lists management button when the list is empty */
563 this->SetWidgetsDisabledState(this->vehicles.empty() || _local_company != this->vli.company,
567
568 /* Disable the group specific function when we select the default group or all vehicles */
569 GroupID group = this->vli.ToGroupID();
570 this->SetWidgetsDisabledState(IsDefaultGroupID(group) || IsAllGroupID(group) || _local_company != this->vli.company,
575
576 /* Disable remaining buttons for non-local companies
577 * Needed while changing _local_company, eg. by cheats
578 * All procedures (eg. move vehicle to another group)
579 * verify, whether you are the owner of the vehicle,
580 * so it doesn't have to be disabled
581 */
585
586 /* If not a default group and the group has replace protection, show an enabled replace sprite. */
587 uint16_t protect_sprite = SPR_GROUP_REPLACE_OFF_TRAIN;
588 if (!IsDefaultGroupID(group) && !IsAllGroupID(group) && Group::Get(group)->flags.Test(GroupFlag::ReplaceProtection)) protect_sprite = SPR_GROUP_REPLACE_ON_TRAIN;
589 this->GetWidget<NWidgetCore>(WID_GL_REPLACE_PROTECTION)->SetSprite(protect_sprite + this->vli.vtype);
590
591 /* Set text of "group by" dropdown widget. */
592 this->GetWidget<NWidgetCore>(WID_GL_GROUP_BY_DROPDOWN)->SetString(std::data(this->vehicle_group_by_names)[this->grouping]);
593
594 /* Set text of "sort by" dropdown widget. */
595 this->GetWidget<NWidgetCore>(WID_GL_SORT_BY_DROPDOWN)->SetString(this->GetVehicleSorterNames()[this->vehgroups.SortType()]);
596
597 this->DrawWidgets();
598 }
599
600 void DrawWidget(const Rect &r, WidgetID widget) const override
601 {
602 switch (widget) {
605 break;
606
609 break;
610
611 case WID_GL_INFO: {
612 Money this_year = 0;
613 Money last_year = 0;
614 uint64_t occupancy = 0;
615
616 for (const Vehicle * const v : this->vehicles) {
617 assert(v->owner == this->owner);
618
619 this_year += v->GetDisplayProfitThisYear();
620 last_year += v->GetDisplayProfitLastYear();
621 occupancy += v->trip_occupancy;
622 }
623
624 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
625
626 DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_GROUP_PROFIT_THIS_PERIOD : STR_GROUP_PROFIT_THIS_YEAR, TC_BLACK);
627 DrawString(tr, GetString(STR_JUST_CURRENCY_LONG, this_year), TC_BLACK, SA_RIGHT);
628
629 tr.top += GetCharacterHeight(FS_NORMAL);
630 DrawString(tr, TimerGameEconomy::UsingWallclockUnits() ? STR_GROUP_PROFIT_LAST_PERIOD : STR_GROUP_PROFIT_LAST_YEAR, TC_BLACK);
631 DrawString(tr, GetString(STR_JUST_CURRENCY_LONG, last_year), TC_BLACK, SA_RIGHT);
632
633 tr.top += GetCharacterHeight(FS_NORMAL);
634 DrawString(tr, STR_GROUP_OCCUPANCY, TC_BLACK);
635 const size_t vehicle_count = this->vehicles.size();
636 if (vehicle_count > 0) {
637 DrawString(tr, GetString(STR_GROUP_OCCUPANCY_VALUE, occupancy / vehicle_count), TC_BLACK, SA_RIGHT);
638 }
639
640 break;
641 }
642
643 case WID_GL_LIST_GROUP: {
644 Rect row = r.WithHeight(this->tiny_step_height);
645
646 auto [first, last] = this->group_sb->GetVisibleRangeIterators(this->groups);
647 for (auto it = first; it != last; ++it) {
648 const Group *g = it->group;
649 assert(g->owner == this->owner);
650
651 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));
652 row = row.Translate(0, this->tiny_step_height);
653 }
654 if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.size()) {
656 }
657 break;
658 }
659
662 break;
663
665 if (this->vli.ToGroupID() != ALL_GROUP && this->grouping == GB_NONE) {
666 /* Mark vehicles which are in sub-groups (only if we are not using shared order coalescing) */
667 Rect mr = r.WithHeight(this->resize.step_height);
668 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->vehgroups);
669 for (auto it = first; it != last; ++it) {
670 const Vehicle *v = it->GetSingleVehicle();
671 if (v->group_id != this->vli.ToGroupID()) {
673 }
674 mr = mr.Translate(0, this->resize.step_height);
675 }
676 }
677
678 this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r);
679 break;
680 }
681 }
682
683 static void DeleteGroupCallback(Window *win, bool confirmed)
684 {
685 if (confirmed) {
687 w->vli.SetIndex(ALL_GROUP);
688 Command<CMD_DELETE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_DELETE, w->group_confirm);
689 }
690 }
691
692 void OnMouseLoop() override
693 {
694 if (last_overlay_state != ShowCargoIconOverlay()) {
695 last_overlay_state = ShowCargoIconOverlay();
696 this->SetDirty();
697 }
698 }
699
700 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
701 {
702 switch (widget) {
703 case WID_GL_SORT_BY_ORDER: // Flip sorting method ascending/descending
705 this->SetDirty();
706 break;
707
708 case WID_GL_GROUP_BY_DROPDOWN: // Select grouping option dropdown menu
709 ShowDropDownMenu(this, this->vehicle_group_by_names, this->grouping, WID_GL_GROUP_BY_DROPDOWN, 0, 0);
710 return;
711
712 case WID_GL_SORT_BY_DROPDOWN: // Select sorting criteria dropdown menu
713 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));
714 return;
715
716 case WID_GL_FILTER_BY_CARGO: // Select filtering criteria dropdown menu
717 ShowDropDownList(this, this->BuildCargoDropDownList(false), this->cargo_filter_criteria, widget);
718 break;
719
720 case WID_GL_ALL_VEHICLES: // All vehicles button
721 if (!IsAllGroupID(this->vli.ToGroupID())) {
722 this->vli.SetIndex(ALL_GROUP);
723 this->vehgroups.ForceRebuild();
724 this->SetDirty();
725 }
726 break;
727
728 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles button
729 if (!IsDefaultGroupID(this->vli.ToGroupID())) {
730 this->vli.SetIndex(DEFAULT_GROUP);
731 this->vehgroups.ForceRebuild();
732 this->SetDirty();
733 }
734 break;
735
736 case WID_GL_LIST_GROUP: { // Matrix Group
737 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
738 if (it == this->groups.end()) return;
739
740 if (it->group->folded || (std::next(it) != std::end(this->groups) && std::next(it)->indent > it->indent)) {
741 /* The group has children, check if the user clicked the fold / unfold button. */
742 bool rtl = _current_text_dir == TD_RTL;
743 Rect r = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
744 r = r.Indent(it->indent * WidgetDimensions::scaled.hsep_indent, rtl).WithWidth(this->column_size[VGC_FOLD].width, rtl);
745 if (click_count > 1 || r.Contains(pt)) {
746
747 GroupID g = this->vli.ToGroupID();
748 if (!IsAllGroupID(g) && !IsDefaultGroupID(g)) {
749 do {
750 g = Group::Get(g)->parent;
751 if (g == it->group->index) {
752 this->vli.SetIndex(g);
753 break;
754 }
755 } while (g != GroupID::Invalid());
756 }
757
758 Group::Get(it->group->index)->folded = !it->group->folded;
759 this->groups.ForceRebuild();
760
761 this->SetDirty();
762 break;
763 }
764 }
765
766 this->vli.SetIndex(it->group->index);
767 this->group_sel = it->group->index;
768
770
771 this->vehgroups.ForceRebuild();
772 this->SetDirty();
773 break;
774 }
775
776 case WID_GL_LIST_VEHICLE: { // Matrix Vehicle
777 auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
778 if (it == this->vehgroups.end()) return; // click out of list bound
779
780 const GUIVehicleGroup &vehgroup = *it;
781
782 const Vehicle *v = nullptr;
783
784 switch (this->grouping) {
785 case GB_NONE: {
786 const Vehicle *v2 = vehgroup.GetSingleVehicle();
787 if (VehicleClicked(v2)) break;
788 v = v2;
789 break;
790 }
791
792 case GB_SHARED_ORDERS: {
793 assert(vehgroup.NumVehicles() > 0);
794 v = vehgroup.vehicles_begin[0];
795 /*
796 * No VehicleClicked(v) support for now, because don't want
797 * to enable any contextual actions except perhaps clicking/ctrl-clicking to clone orders.
798 */
799 break;
800 }
801
802 default:
803 NOT_REACHED();
804 }
805 if (v) {
806 if (_ctrl_pressed && this->grouping == GB_SHARED_ORDERS) {
807 ShowOrdersWindow(v);
808 } else {
809 this->vehicle_sel = v->index;
810
811 if (_ctrl_pressed && this->grouping == GB_NONE) {
812 /*
813 * It only makes sense to select a group if not using shared orders
814 * since two vehicles sharing orders can be from different groups.
815 */
816 this->SelectGroup(v->group_id);
817 }
818
821 _cursor.vehchain = true;
822
823 this->SetDirty();
824 }
825 }
826
827 break;
828 }
829
830 case WID_GL_CREATE_GROUP: { // Create a new group
831 Command<CMD_CREATE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_CREATE, CcCreateGroup, this->vli.vtype, this->vli.ToGroupID());
832 break;
833 }
834
835 case WID_GL_DELETE_GROUP: { // Delete the selected group
836 this->group_confirm = this->vli.ToGroupID();
837 ShowQuery(
838 GetEncodedString(STR_QUERY_GROUP_DELETE_CAPTION),
839 GetEncodedString(STR_GROUP_DELETE_QUERY_TEXT),
840 this, DeleteGroupCallback);
841 break;
842 }
843
844 case WID_GL_RENAME_GROUP: // Rename the selected roup
845 this->ShowRenameGroupWindow(this->vli.ToGroupID(), false);
846 break;
847
848 case WID_GL_LIVERY_GROUP: // Set group livery
849 ShowCompanyLiveryWindow(this->owner, this->vli.ToGroupID());
850 break;
851
853 ShowBuildVehicleWindow(INVALID_TILE, this->vli.vtype);
854 break;
855
857 ShowDropDownList(this, this->BuildActionDropdownList(true, Group::IsValidID(this->vli.ToGroupID()), IsDefaultGroupID(this->vli.ToGroupID())), -1, WID_GL_MANAGE_VEHICLES_DROPDOWN);
858 break;
859 }
860
861 case WID_GL_START_ALL:
862 case WID_GL_STOP_ALL: { // Start/stop all vehicles of the list
864 break;
865 }
866
868 const Group *g = Group::GetIfValid(this->vli.ToGroupID());
869 if (g != nullptr) {
871 }
872 break;
873 }
874 }
875 }
876
877 void OnDragDrop_Group(Point pt, WidgetID widget)
878 {
879 const Group *g = Group::Get(this->group_sel);
880
881 switch (widget) {
882 case WID_GL_ALL_VEHICLES: // All vehicles
883 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
884 if (g->parent != GroupID::Invalid()) {
885 Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, GroupID::Invalid(), {});
886 }
887
888 this->group_sel = GroupID::Invalid();
889 this->group_over = GroupID::Invalid();
890 this->SetDirty();
891 break;
892
893 case WID_GL_LIST_GROUP: { // Matrix group
894 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
895 GroupID new_g = it == this->groups.end() ? GroupID::Invalid() : it->group->index;
896
897 if (this->group_sel != new_g && g->parent != new_g) {
898 Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_SET_PARENT, AlterGroupMode::SetParent, this->group_sel, new_g, {});
899 }
900
901 this->group_sel = GroupID::Invalid();
902 this->group_over = GroupID::Invalid();
903 this->SetDirty();
904 break;
905 }
906 }
907 }
908
909 void OnDragDrop_Vehicle(Point pt, WidgetID widget)
910 {
911 switch (widget) {
912 case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
913 Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, DEFAULT_GROUP, this->vehicle_sel, _ctrl_pressed || this->grouping == GB_SHARED_ORDERS, VehicleListIdentifier{});
914
915 this->vehicle_sel = VehicleID::Invalid();
916 this->group_over = GroupID::Invalid();
917
918 this->SetDirty();
919 break;
920
921 case WID_GL_LIST_GROUP: { // Matrix group
922 const VehicleID vindex = this->vehicle_sel;
923 this->vehicle_sel = VehicleID::Invalid();
924 this->group_over = GroupID::Invalid();
925 this->SetDirty();
926
927 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
928 GroupID new_g = it == this->groups.end() ? NEW_GROUP : it->group->index;
929
930 Command<CMD_ADD_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE, new_g == NEW_GROUP ? CcAddVehicleNewGroup : nullptr, new_g, vindex, _ctrl_pressed || this->grouping == GB_SHARED_ORDERS, VehicleListIdentifier{});
931 break;
932 }
933
934 case WID_GL_LIST_VEHICLE: { // Matrix vehicle
935 const VehicleID vindex = this->vehicle_sel;
936 this->vehicle_sel = VehicleID::Invalid();
937 this->group_over = GroupID::Invalid();
938 this->SetDirty();
939
940 auto it = this->vscroll->GetScrolledItemFromWidget(this->vehgroups, pt.y, this, WID_GL_LIST_VEHICLE);
941 if (it == this->vehgroups.end()) return; // click out of list bound
942
943 const GUIVehicleGroup &vehgroup = *it;
944 switch (this->grouping) {
945 case GB_NONE: {
946 const Vehicle *v = vehgroup.GetSingleVehicle();
947 if (!VehicleClicked(v) && vindex == v->index) {
949 }
950 break;
951 }
952
953 case GB_SHARED_ORDERS: {
954 if (!VehicleClicked(vehgroup)) {
955 const Vehicle *v = vehgroup.vehicles_begin[0];
956 if (vindex == v->index) {
957 if (vehgroup.NumVehicles() == 1) {
959 } else {
960 ShowVehicleListWindow(v);
961 }
962 }
963 }
964 break;
965 }
966
967 default:
968 NOT_REACHED();
969 }
970 break;
971 }
972 }
973 }
974
975 void OnDragDrop(Point pt, WidgetID widget) override
976 {
977 if (this->vehicle_sel != VehicleID::Invalid()) OnDragDrop_Vehicle(pt, widget);
978 if (this->group_sel != GroupID::Invalid()) OnDragDrop_Group(pt, widget);
979
980 _cursor.vehchain = false;
981 }
982
983 void OnQueryTextFinished(std::optional<std::string> str) override
984 {
985 if (str.has_value()) Command<CMD_ALTER_GROUP>::Post(STR_ERROR_GROUP_CAN_T_RENAME, AlterGroupMode::Rename, this->group_rename, GroupID::Invalid(), *str);
986 this->group_rename = GroupID::Invalid();
987 }
988
989 void OnResize() override
990 {
991 this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP);
992 this->vscroll->SetCapacityFromWidget(this, WID_GL_LIST_VEHICLE);
993 }
994
995 void OnDropdownSelect(WidgetID widget, int index, int) override
996 {
997 switch (widget) {
999 this->UpdateVehicleGroupBy(static_cast<GroupBy>(index));
1000 break;
1001
1003 this->vehgroups.SetSortType(index);
1004 break;
1005
1006 case WID_GL_FILTER_BY_CARGO: // Select a cargo filter criteria
1007 this->SetCargoFilter(index);
1008 break;
1009
1011 assert(!this->vehicles.empty());
1012
1013 switch (index) {
1014 case ADI_REPLACE: // Replace window
1015 ShowReplaceGroupVehicleWindow(this->vli.ToGroupID(), this->vli.vtype);
1016 break;
1017 case ADI_SERVICE: // Send for servicing
1018 case ADI_DEPOT: { // Send to Depots
1019 Command<CMD_SEND_VEHICLE_TO_DEPOT>::Post(GetCmdSendToDepotMsg(this->vli.vtype), VehicleID::Invalid(), (index == ADI_SERVICE ? DepotCommandFlag::Service : DepotCommandFlags{}) | DepotCommandFlag::MassSend, this->vli);
1020 break;
1021 }
1022
1023 case ADI_CREATE_GROUP: // Create group
1024 Command<CMD_ADD_VEHICLE_GROUP>::Post(CcAddVehicleNewGroup, NEW_GROUP, VehicleID::Invalid(), false, this->vli);
1025 break;
1026
1027 case ADI_ADD_SHARED: // Add shared Vehicles
1028 assert(Group::IsValidID(this->vli.ToGroupID()));
1029
1030 Command<CMD_ADD_SHARED_VEHICLE_GROUP>::Post(STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE, this->vli.ToGroupID(), this->vli.vtype);
1031 break;
1032 case ADI_REMOVE_ALL: // Remove all Vehicles from the selected group
1033 assert(Group::IsValidID(this->vli.ToGroupID()));
1034
1035 Command<CMD_REMOVE_ALL_VEHICLES_GROUP>::Post(STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES, this->vli.ToGroupID());
1036 break;
1037 default: NOT_REACHED();
1038 }
1039 break;
1040
1041 default: NOT_REACHED();
1042 }
1043
1044 this->SetDirty();
1045 }
1046
1047 void OnGameTick() override
1048 {
1049 if (this->groups.NeedResort() || this->vehgroups.NeedResort()) {
1050 this->SetDirty();
1051 }
1052 }
1053
1054 void OnPlaceObjectAbort() override
1055 {
1056 /* abort drag & drop */
1057 this->vehicle_sel = VehicleID::Invalid();
1059 this->group_sel = GroupID::Invalid();
1060 this->group_over = GroupID::Invalid();
1062 }
1063
1064 void OnMouseDrag(Point pt, WidgetID widget) override
1065 {
1066 if (this->vehicle_sel == VehicleID::Invalid() && this->group_sel == GroupID::Invalid()) return;
1067
1068 /* A vehicle is dragged over... */
1069 GroupID new_group_over = GroupID::Invalid();
1070 switch (widget) {
1071 case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group.
1072 new_group_over = DEFAULT_GROUP;
1073 break;
1074
1075 case WID_GL_LIST_GROUP: { // ... the list of custom groups.
1076 auto it = this->group_sb->GetScrolledItemFromWidget(this->groups, pt.y, this, WID_GL_LIST_GROUP);
1077 new_group_over = it == this->groups.end() ? NEW_GROUP : it->group->index;
1078 break;
1079 }
1080 }
1081
1082 /* Do not highlight when dragging over the current group */
1083 if (this->vehicle_sel != VehicleID::Invalid()) {
1084 if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = GroupID::Invalid();
1085 } else if (this->group_sel != GroupID::Invalid()) {
1086 if (this->group_sel == new_group_over || Group::Get(this->group_sel)->parent == new_group_over) new_group_over = GroupID::Invalid();
1087 }
1088
1089 /* Mark widgets as dirty if the group changed. */
1090 if (new_group_over != this->group_over) {
1092 this->group_over = new_group_over;
1094 }
1095 }
1096
1097 void ShowRenameGroupWindow(GroupID group, bool empty)
1098 {
1099 assert(Group::IsValidID(group));
1100 this->group_rename = group;
1101
1102 /* Show empty query for new groups */
1103 std::string str;
1104 if (!empty) str = GetString(STR_GROUP_NAME, group);
1105
1107 }
1108
1115 {
1116 if (this->vehicle_sel == vehicle) ResetObjectToPlace();
1117 }
1118
1124 void SelectGroup(const GroupID g_id)
1125 {
1126 if (g_id == GroupID::Invalid() || g_id == this->vli.ToGroupID()) return;
1127
1128 this->vli.SetIndex(g_id);
1129 if (g_id != ALL_GROUP && g_id != DEFAULT_GROUP) {
1130 const Group *g = Group::Get(g_id);
1131
1132 auto found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
1133 if (found == std::end(this->groups)) {
1134 /* The group's branch is maybe collapsed, so try to expand it. */
1135 for (auto pg = Group::GetIfValid(g->parent); pg != nullptr; pg = Group::GetIfValid(pg->parent)) {
1136 pg->folded = false;
1137 }
1138 this->groups.ForceRebuild();
1139 this->BuildGroupList(this->owner);
1140 this->group_sb->SetCount(this->groups.size());
1141 found = std::ranges::find(this->groups, g, &GUIGroupListItem::group);
1142 }
1143 if (found != std::end(this->groups)) this->group_sb->ScrollTowards(std::distance(std::begin(this->groups), found));
1144 }
1145 this->vehgroups.ForceRebuild();
1146 this->SetDirty();
1147 }
1148
1149};
1150
1151static WindowDesc _vehicle_group_desc[] = {
1152 {
1153 WDP_AUTO, "list_groups_train", 525, 246,
1155 {},
1156 _nested_group_widgets
1157 },
1158 {
1159 WDP_AUTO, "list_groups_roadveh", 460, 246,
1161 {},
1162 _nested_group_widgets
1163 },
1164 {
1165 WDP_AUTO, "list_groups_ship", 460, 246,
1167 {},
1168 _nested_group_widgets
1169 },
1170 {
1171 WDP_AUTO, "list_groups_aircraft", 460, 246,
1173 {},
1174 _nested_group_widgets
1175 },
1176};
1177
1185template <bool Tneed_existing_window>
1186static void ShowCompanyGroupInternal(CompanyID company, VehicleType vehicle_type, GroupID group)
1187{
1188 if (!Company::IsValidID(company)) return;
1189
1190 assert(vehicle_type < std::size(_vehicle_group_desc));
1191 VehicleListIdentifier vli(VL_GROUP_LIST, vehicle_type, company);
1192 VehicleGroupWindow *w = AllocateWindowDescFront<VehicleGroupWindow, Tneed_existing_window>(_vehicle_group_desc[vehicle_type], vli.ToWindowNumber(), vli);
1193 if (w != nullptr) w->SelectGroup(group);
1194}
1195
1202void ShowCompanyGroup(CompanyID company, VehicleType vehicle_type, GroupID group)
1203{
1204 ShowCompanyGroupInternal<false>(company, vehicle_type, group);
1205}
1206
1212{
1213 ShowCompanyGroupInternal<true>(v->owner, v->type, v->group_id);
1214}
1215
1223{
1224 return dynamic_cast<VehicleGroupWindow *>(FindWindowById(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, owner).ToWindowNumber()));
1225}
1226
1231static void CcCreateGroup(GroupID gid, VehicleType veh_type)
1232{
1234 if (w != nullptr) w->ShowRenameGroupWindow(gid, true);
1235}
1236
1244void CcCreateGroup(Commands, const CommandCost &result, GroupID new_group, VehicleType vt, GroupID)
1245{
1246 if (result.Failed()) return;
1247
1248 assert(vt <= VEH_AIRCRAFT);
1249 CcCreateGroup(new_group, vt);
1250}
1251
1258{
1259 if (result.Failed()) return;
1260
1261 const Group *g = Group::Get(new_group);
1262 CcCreateGroup(new_group, g->vehicle_type);
1263}
1264
1270{
1271 /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any group windows either
1272 * If that is the case, we can skip looping though the windows and save time
1273 */
1274 if (_special_mouse_mode != WSM_DRAGDROP) return;
1275
1277 if (w != nullptr) w->UnselectVehicle(v->index);
1278}
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.
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.
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:2499
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 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.
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:30
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
RectPadding fullbevel
Always-scaled bevel thickness.
Definition window_gui.h:39
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
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:455
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:415
Dimension GetDropDownListDimension(const DropDownList &list)
Determine width and height required to fully display a DropDownList.
Definition dropdown.cpp:374
Functions related to the drop down widget.
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:895
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:666
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:918
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:68
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.
bool IsAllGroupID(GroupID id_g)
Checks if a GroupID stands for all vehicles of a company.
Definition group.h:103
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.
@ SetParent
Change group parent.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:966
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.
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.
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.
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
Definition palette.cpp:388
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:428
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
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.
T y
Y coordinate.
bool vehchain
vehicle chain is dragged
Definition gfx_type.h:150
Dimensions (a width and height) of a rectangle in 2D.
VehicleList::const_iterator vehicles_begin
Pointer to beginning element of this vehicle group.
Statistics and caches on the vehicles in a group.
Definition group.h: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:73
bool autoreplace_finished
Have all autoreplacement finished?
Definition group.h:32
Group data.
Definition group.h:73
GroupFlags flags
Group flags.
Definition group.h:78
GroupID parent
Parent group.
Definition group.h:85
VehicleType vehicle_type
Vehicle type of the group.
Definition group.h:76
bool folded
NOSAVE: Is this group folded in the group view?
Definition group.h:83
uint16_t number
Per-company group number.
Definition group.h:86
Owner owner
Group Owner.
Definition group.h:75
FlatSet< GroupID > children
NOSAVE: child groups belonging to this group.
Definition group.h:82
Partial widget specification to allow NWidgets to be written nested.
Colour for pixel/line drawing.
Definition gfx_type.h:405
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 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 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.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:212
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:167
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:273
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:815
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1789
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:766
Window * parent
Parent window.
Definition window_gui.h:328
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:469
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:556
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:504
void DrawSortButtonState(WidgetID widget, SortButtonState state) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:798
void CloseChildWindows(WindowClass wc=WC_INVALID) const
Close all children a window might have in a head-recursive manner.
Definition window.cpp:1075
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:515
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1779
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:316
WindowFlags flags
Window flags.
Definition window_gui.h:300
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:313
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
Stuff related to the text buffer GUI.
@ 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:67
@ 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:58
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:51
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:53
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:77
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:69
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:61
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:60
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:57
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:62
@ 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:1205
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:1151
Window functions not directly related to making/drawing windows.
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:218
@ SBS_UP
Sort descending.
Definition window_gui.h:219
@ 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: