OpenTTD Source 20250312-master-gcdcc6b491d
town_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 "town.h"
12#include "viewport_func.h"
13#include "error.h"
14#include "gui.h"
15#include "house.h"
16#include "newgrf_cargo.h"
17#include "newgrf_house.h"
18#include "newgrf_text.h"
19#include "picker_gui.h"
20#include "command_func.h"
21#include "company_func.h"
22#include "company_base.h"
23#include "company_gui.h"
24#include "network/network.h"
25#include "string_func.h"
26#include "strings_func.h"
27#include "sound_func.h"
28#include "tilehighlight_func.h"
29#include "sortlist_type.h"
30#include "road_cmd.h"
31#include "landscape.h"
32#include "querystring_gui.h"
33#include "window_func.h"
34#include "townname_func.h"
35#include "core/backup_type.hpp"
37#include "genworld.h"
38#include "fios.h"
39#include "stringfilter_type.h"
40#include "dropdown_func.h"
41#include "town_kdtree.h"
42#include "town_cmd.h"
43#include "timer/timer.h"
45#include "timer/timer_window.h"
46#include "zoom_func.h"
47#include "hotkeys.h"
48
49#include "widgets/town_widget.h"
50
51#include "table/strings.h"
52
53#include <sstream>
54
55#include "safeguards.h"
56
57TownKdtree _town_local_authority_kdtree{};
58
60
61static constexpr NWidgetPart _nested_town_authority_widgets[] = {
63 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
64 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TA_CAPTION),
65 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TA_ZONE_BUTTON), SetMinimalSize(50, 0), SetStringTip(STR_LOCAL_AUTHORITY_ZONE, STR_LOCAL_AUTHORITY_ZONE_TOOLTIP),
66 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
67 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
68 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
70 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_RATING_INFO), SetMinimalSize(317, 92), SetResize(1, 1), EndContainer(),
71 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_COMMAND_LIST), SetMinimalSize(317, 52), SetResize(1, 0), SetToolTip(STR_LOCAL_AUTHORITY_ACTIONS_TOOLTIP), EndContainer(),
72 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TA_ACTION_INFO), SetMinimalSize(317, 52), SetResize(1, 0), EndContainer(),
74 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TA_EXECUTE), SetMinimalSize(317, 12), SetResize(1, 0), SetFill(1, 0), SetStringTip(STR_LOCAL_AUTHORITY_DO_IT_BUTTON, STR_LOCAL_AUTHORITY_DO_IT_TOOLTIP),
75 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
77};
78
81private:
82 Town *town = nullptr;
83 TownAction sel_action = TownAction::End;
87 std::array<StringID, to_underlying(TownAction::End)> action_tooltips{};
88
91
100 int GetNthSetBit(int n)
101 {
102 if (n >= 0) {
103 for (uint i : SetBitIterator(this->enabled_actions.base())) {
104 n--;
105 if (n < 0) return i;
106 }
107 }
108 return -1;
109 }
110
117 {
118 TownActions enabled{};
119 enabled.Set();
120
124 if (!_settings_game.economy.bribe) enabled.Reset(TownAction::Bribe);
125
126 return enabled;
127 }
128
129public:
131 {
132 this->town = Town::Get(window_number);
134
141 this->action_tooltips[5] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_NEW_BUILDINGS;
143 this->action_tooltips[7] = STR_LOCAL_AUTHORITY_ACTION_TOOLTIP_BRIBE;
144
145 this->InitNested(window_number);
146 }
147
148 void OnInit() override
149 {
150 this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
151 this->exclusive_size = GetSpriteSize(SPR_EXCLUSIVE_TRANSPORT);
152 }
153
154 void OnPaint() override
155 {
159
161 this->SetWidgetDisabledState(WID_TA_EXECUTE, (this->sel_action == TownAction::End) || !this->available_actions.Test(this->sel_action));
162
163 this->DrawWidgets();
164 if (!this->IsShaded())
165 {
166 this->DrawRatings();
167 this->DrawActions();
168 }
169 }
170
171 StringID GetRatingString(int rating) const
172 {
173 if (rating > RATING_EXCELLENT) return STR_CARGO_RATING_OUTSTANDING;
174 if (rating > RATING_VERYGOOD) return STR_CARGO_RATING_EXCELLENT;
175 if (rating > RATING_GOOD) return STR_CARGO_RATING_VERY_GOOD;
176 if (rating > RATING_MEDIOCRE) return STR_CARGO_RATING_GOOD;
177 if (rating > RATING_POOR) return STR_CARGO_RATING_MEDIOCRE;
178 if (rating > RATING_VERYPOOR) return STR_CARGO_RATING_POOR;
179 if (rating > RATING_APPALLING) return STR_CARGO_RATING_VERY_POOR;
181 }
182
185 {
186 Rect r = this->GetWidget<NWidgetBase>(WID_TA_RATING_INFO)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
187
189 int icon_y_offset = (this->resize.step_height - this->icon_size.height) / 2;
190 int exclusive_y_offset = (this->resize.step_height - this->exclusive_size.height) / 2;
191
193 r.top += this->resize.step_height;
194
195 bool rtl = _current_text_dir == TD_RTL;
196 Rect icon = r.WithWidth(this->icon_size.width, rtl);
198 Rect text = r.Indent(this->icon_size.width + WidgetDimensions::scaled.hsep_normal + this->exclusive_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
199
200 /* Draw list of companies */
201 for (const Company *c : Company::Iterate()) {
202 if ((this->town->have_ratings.Test(c->index) || this->town->exclusivity == c->index)) {
203 DrawCompanyIcon(c->index, icon.left, text.top + icon_y_offset);
204
205 if (this->town->exclusivity == c->index) {
206 DrawSprite(SPR_EXCLUSIVE_TRANSPORT, COMPANY_SPRITE_COLOUR(c->index), exclusive.left, text.top + exclusive_y_offset);
207 }
208
209 int rating = this->town->ratings[c->index];
210 DrawString(text.left, text.right, text.top + text_y_offset, GetString(STR_LOCAL_AUTHORITY_COMPANY_RATING, c->index, c->index, GetRatingString(rating)));
211 text.top += this->resize.step_height;
212 }
213 }
214
215 text.bottom = text.top - 1;
216 if (text.bottom > r.bottom) {
217 /* If the company list is too big to fit, mark ourself dirty and draw again. */
218 ResizeWindow(this, 0, text.bottom - r.bottom, false);
219 }
220 }
221
224 {
225 Rect r = this->GetWidget<NWidgetBase>(WID_TA_COMMAND_LIST)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
226
229
230 /* Draw list of actions */
231 for (TownAction i = {}; i != TownAction::End; ++i) {
232 /* Don't show actions if disabled in settings. */
233 if (!this->enabled_actions.Test(i)) continue;
234
235 /* Set colour of action based on ability to execute and if selected. */
237 if (this->available_actions.Test(i)) action_colour = TC_ORANGE;
238 if (this->sel_action == i) action_colour = TC_WHITE;
239
242 }
243 }
244
245 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
246 {
248
249 return this->Window::GetWidgetString(widget, stringid);
250 }
251
252 void DrawWidget(const Rect &r, WidgetID widget) const override
253 {
254 switch (widget) {
256 if (this->sel_action != TownAction::End) {
257 Money action_cost = _price[PR_TOWN_ACTION] * GetTownActionCost(this->sel_action) >> 8;
259
261 GetString(this->action_tooltips[to_underlying(this->sel_action)], action_cost),
262 affordable ? TC_YELLOW : TC_RED);
263 }
264 break;
265 }
266 }
267
269 {
270 switch (widget) {
271 case WID_TA_ACTION_INFO: {
272 assert(size.width > padding.width && size.height > padding.height);
273 Dimension d = {0, 0};
274 for (TownAction i = {}; i != TownAction::End; ++i) {
275 Money price = _price[PR_TOWN_ACTION] * GetTownActionCost(i) >> 8;
276 d = maxdim(d, GetStringMultiLineBoundingBox(GetString(this->action_tooltips[to_underlying(i)], price), size));
277 }
278 d.width += padding.width;
279 d.height += padding.height;
280 size = maxdim(size, d);
281 break;
282 }
283
285 size.height = (to_underlying(TownAction::End) + 1) * GetCharacterHeight(FS_NORMAL) + padding.height;
287 for (TownAction i = {}; i != TownAction::End; ++i) {
288 size.width = std::max(size.width, GetStringBoundingBox(STR_LOCAL_AUTHORITY_ACTION_SMALL_ADVERTISING_CAMPAIGN + to_underlying(i)).width + padding.width);
289 }
290 size.width += padding.width;
291 break;
292
295 size.height = 9 * resize.height + padding.height;
296 break;
297 }
298 }
299
300 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
301 {
302 switch (widget) {
303 case WID_TA_ZONE_BUTTON: {
304 bool new_show_state = !this->town->show_zone;
305 TownID index = this->town->index;
306
307 new_show_state ? _town_local_authority_kdtree.Insert(index) : _town_local_authority_kdtree.Remove(index);
308
309 this->town->show_zone = new_show_state;
312 break;
313 }
314
315 case WID_TA_COMMAND_LIST: {
317
318 y = GetNthSetBit(y);
319 if (y >= 0) {
320 this->sel_action = static_cast<TownAction>(y);
321 this->SetDirty();
322 }
323
324 /* When double-clicking, continue */
325 if (click_count == 1 || y < 0 || !this->available_actions.Test(this->sel_action)) break;
326 [[fallthrough]];
327 }
328
329 case WID_TA_EXECUTE:
330 Command<CMD_DO_TOWN_ACTION>::Post(STR_ERROR_CAN_T_DO_THIS, this->town->xy, static_cast<TownID>(this->window_number), this->sel_action);
331 break;
332 }
333 }
334
336 IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
337 this->SetDirty();
338 }};
339
340 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
341 {
342 if (!gui_scope) return;
343
344 this->enabled_actions = this->GetEnabledActions();
345 if (!this->enabled_actions.Test(this->sel_action)) {
346 this->sel_action = TownAction::End;
347 }
348 }
349};
350
351static WindowDesc _town_authority_desc(
352 WDP_AUTO, "view_town_authority", 317, 222,
354 {},
355 _nested_town_authority_widgets
356);
357
358static void ShowTownAuthorityWindow(uint town)
359{
360 AllocateWindowDescFront<TownAuthorityWindow>(_town_authority_desc, town);
361}
362
363
364/* Town view window. */
366private:
367 Town *town = nullptr;
368
369public:
370 static const int WID_TV_HEIGHT_NORMAL = 150;
371
373 {
374 this->CreateNestedTree();
375
376 this->town = Town::Get(window_number);
378
379 this->FinishInitNested(window_number);
380
383 nvp->InitializeViewport(this, this->town->xy, ScaleZoomGUI(ZOOM_LVL_TOWN));
384
385 /* disable renaming town in network games if you are not the server */
387 }
388
389 void Close([[maybe_unused]] int data = 0) override
390 {
392 this->Window::Close();
393 }
394
395 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
396 {
397 if (widget == WID_TV_CAPTION) return GetString(STR_TOWN_VIEW_TOWN_CAPTION, this->town->index);
398
399 return this->Window::GetWidgetString(widget, stringid);
400 }
401
402 void OnPaint() override
403 {
404 extern const Town *_viewport_highlight_town;
405 this->SetWidgetLoweredState(WID_TV_CATCHMENT, _viewport_highlight_town == this->town);
406
407 this->DrawWidgets();
408 }
409
410 void DrawWidget(const Rect &r, WidgetID widget) const override
411 {
412 if (widget != WID_TV_INFO) return;
413
414 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
415
416 DrawString(tr, GetString(STR_TOWN_VIEW_POPULATION_HOUSES, this->town->cache.population, this->town->cache.num_houses));
418
420
421 for (auto tpe : {TPE_PASSENGERS, TPE_MAIL}) {
423 CargoType cargo_type = cs->Index();
424 DrawString(tr, GetString(str_last_period, 1ULL << cargo_type, this->town->supplied[cargo_type].old_act, this->town->supplied[cargo_type].old_max));
426 }
427 }
428
429 bool first = true;
430 for (int i = TAE_BEGIN; i < TAE_END; i++) {
431 if (this->town->goal[i] == 0) continue;
432 if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue;
433 if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue;
434
435 if (first) {
438 first = false;
439 }
440
441 bool rtl = _current_text_dir == TD_RTL;
442
444 assert(cargo != nullptr);
445
446 StringID string;
447
448 if (this->town->goal[i] == TOWN_GROWTH_DESERT || this->town->goal[i] == TOWN_GROWTH_WINTER) {
449 /* For 'original' gameplay, don't show the amount required (you need 1 or more ..) */
451 if (this->town->received[i].old_act == 0) {
453
454 if (this->town->goal[i] == TOWN_GROWTH_WINTER && TileHeight(this->town->xy) < GetSnowLine()) {
456 }
457 }
458
459 DrawString(tr.Indent(20, rtl), GetString(string, cargo->name));
460 } else {
462 if (this->town->received[i].old_act < this->town->goal[i]) {
464 }
465 DrawString(tr.Indent(20, rtl), GetString(string, cargo->Index(), this->town->received[i].old_act, cargo->Index(), this->town->goal[i]));
466 }
468 }
469
470 if (HasBit(this->town->flags, TOWN_IS_GROWING)) {
473 } else {
476 }
477
478 /* only show the town noise, if the noise option is activated. */
480 DrawString(tr, GetString(STR_TOWN_VIEW_NOISE_IN_TOWN, this->town->noise_reached, this->town->MaxTownNoise()));
482 }
483
484 if (!this->town->text.empty()) {
485 tr.top = DrawStringMultiLine(tr, this->town->text.GetDecodedString(), TC_BLACK);
486 }
487 }
488
489 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
490 {
491 switch (widget) {
492 case WID_TV_CENTER_VIEW: // scroll to location
493 if (_ctrl_pressed) {
494 ShowExtraViewportWindow(this->town->xy);
495 } else {
496 ScrollMainWindowToTile(this->town->xy);
497 }
498 break;
499
500 case WID_TV_SHOW_AUTHORITY: // town authority
501 ShowTownAuthorityWindow(this->window_number);
502 break;
503
504 case WID_TV_CHANGE_NAME: // rename
506 break;
507
508 case WID_TV_CATCHMENT:
510 break;
511
512 case WID_TV_EXPAND: { // expand town - only available on Scenario editor
514 break;
515 }
516
517 case WID_TV_DELETE: // delete town - only available on Scenario editor
519 break;
520 }
521 }
522
524 {
525 switch (widget) {
526 case WID_TV_INFO:
527 size.height = GetDesiredInfoHeight(size.width) + padding.height;
528 break;
529 }
530 }
531
537 {
539
540 bool first = true;
541 for (int i = TAE_BEGIN; i < TAE_END; i++) {
542 if (this->town->goal[i] == 0) continue;
543 if (this->town->goal[i] == TOWN_GROWTH_WINTER && (TileHeight(this->town->xy) < LowestSnowLine() || this->town->cache.population <= 90)) continue;
544 if (this->town->goal[i] == TOWN_GROWTH_DESERT && (GetTropicZone(this->town->xy) != TROPICZONE_DESERT || this->town->cache.population <= 60)) continue;
545
546 if (first) {
548 first = false;
549 }
551 }
553
555
556 if (!this->town->text.empty()) {
558 }
559
560 return aimed_height;
561 }
562
563 void ResizeWindowAsNeeded()
564 {
567 if (aimed_height > nwid_info->current_y || (aimed_height < nwid_info->current_y && nwid_info->current_y > nwid_info->smallest_y)) {
568 this->ReInit();
569 }
570 }
571
572 void OnResize() override
573 {
574 if (this->viewport != nullptr) {
576 nvp->UpdateViewportCoordinates(this);
577
578 ScrollWindowToTile(this->town->xy, this, true); // Re-center viewport.
579 }
580 }
581
582 void OnMouseWheel(int wheel) override
583 {
585 DoZoomInOutWindow(wheel < 0 ? ZOOM_IN : ZOOM_OUT, this);
586 }
587 }
588
594 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
595 {
596 if (!gui_scope) return;
597 /* Called when setting station noise or required cargoes have changed, in order to resize the window */
598 this->SetDirty(); // refresh display for current size. This will allow to avoid glitches when downgrading
599 this->ResizeWindowAsNeeded();
600 }
601
602 void OnQueryTextFinished(std::optional<std::string> str) override
603 {
604 if (!str.has_value()) return;
605
607 }
608
609 IntervalTimer<TimerGameCalendar> daily_interval = {{TimerGameCalendar::DAY, TimerGameCalendar::Priority::NONE}, [this](auto) {
610 /* Refresh after possible snowline change */
611 this->SetDirty();
612 }};
613};
614
615static constexpr NWidgetPart _nested_town_game_view_widgets[] = {
617 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
618 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
619 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION),
620 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetSpriteTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
621 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
622 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
623 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
624 EndContainer(),
625 NWidget(WWT_PANEL, COLOUR_BROWN),
626 NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
627 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 0), SetResize(1, 1),
628 EndContainer(),
629 EndContainer(),
630 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
632 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_SHOW_AUTHORITY), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_LOCAL_AUTHORITY_BUTTON, STR_TOWN_VIEW_LOCAL_AUTHORITY_TOOLTIP),
633 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
634 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
635 EndContainer(),
636};
637
638static WindowDesc _town_game_view_desc(
639 WDP_AUTO, "view_town", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL,
641 {},
642 _nested_town_game_view_widgets
643);
644
645static constexpr NWidgetPart _nested_town_editor_view_widgets[] = {
647 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
648 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CHANGE_NAME), SetAspect(WidgetDimensions::ASPECT_RENAME), SetSpriteTip(SPR_RENAME, STR_TOWN_VIEW_RENAME_TOOLTIP),
649 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TV_CAPTION), SetStringTip(STR_TOWN_VIEW_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
650 NWidget(WWT_PUSHIMGBTN, COLOUR_BROWN, WID_TV_CENTER_VIEW), SetAspect(WidgetDimensions::ASPECT_LOCATION), SetSpriteTip(SPR_GOTO_LOCATION, STR_TOWN_VIEW_CENTER_TOOLTIP),
651 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
652 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
653 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
654 EndContainer(),
655 NWidget(WWT_PANEL, COLOUR_BROWN),
656 NWidget(WWT_INSET, COLOUR_BROWN), SetPadding(2, 2, 2, 2),
657 NWidget(NWID_VIEWPORT, INVALID_COLOUR, WID_TV_VIEWPORT), SetMinimalSize(254, 86), SetFill(1, 1), SetResize(1, 1),
658 EndContainer(),
659 EndContainer(),
660 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TV_INFO), SetMinimalSize(260, 32), SetResize(1, 0), SetFill(1, 0), EndContainer(),
662 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_EXPAND), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_EXPAND_BUTTON, STR_TOWN_VIEW_EXPAND_TOOLTIP),
663 NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_TV_DELETE), SetMinimalSize(80, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_TOWN_VIEW_DELETE_BUTTON, STR_TOWN_VIEW_DELETE_TOOLTIP),
664 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TV_CATCHMENT), SetMinimalSize(40, 12), SetFill(1, 1), SetResize(1, 0), SetStringTip(STR_BUTTON_CATCHMENT, STR_TOOLTIP_CATCHMENT),
665 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
666 EndContainer(),
667};
668
669static WindowDesc _town_editor_view_desc(
670 WDP_AUTO, "view_town_scen", 260, TownViewWindow::WID_TV_HEIGHT_NORMAL,
672 {},
673 _nested_town_editor_view_widgets
674);
675
676void ShowTownViewWindow(TownID town)
677{
678 if (_game_mode == GM_EDITOR) {
679 AllocateWindowDescFront<TownViewWindow>(_town_editor_view_desc, town);
680 } else {
681 AllocateWindowDescFront<TownViewWindow>(_town_game_view_desc, town);
682 }
683}
684
685static constexpr NWidgetPart _nested_town_directory_widgets[] = {
687 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
688 NWidget(WWT_CAPTION, COLOUR_BROWN, WID_TD_CAPTION),
689 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
690 NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
691 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
692 EndContainer(),
696 NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_TD_SORT_ORDER), SetStringTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
697 NWidget(WWT_DROPDOWN, COLOUR_BROWN, WID_TD_SORT_CRITERIA), SetToolTip(STR_TOOLTIP_SORT_CRITERIA),
698 NWidget(WWT_EDITBOX, COLOUR_BROWN, WID_TD_FILTER), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
699 EndContainer(),
700 NWidget(WWT_PANEL, COLOUR_BROWN, WID_TD_LIST), SetToolTip(STR_TOWN_DIRECTORY_LIST_TOOLTIP),
702 NWidget(WWT_PANEL, COLOUR_BROWN),
703 NWidget(WWT_TEXT, INVALID_COLOUR, WID_TD_WORLD_POPULATION), SetPadding(2, 0, 2, 2), SetFill(1, 0), SetResize(1, 0),
704 EndContainer(),
705 EndContainer(),
708 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
709 EndContainer(),
710 EndContainer(),
711};
712
717
720private:
721 /* Runtime saved values */
722 static Listing last_sorting;
723
724 /* Constants for sorting towns */
725 static inline const StringID sorter_names[] = {
729 };
730 static const std::initializer_list<GUITownList::SortFunction * const> sorter_funcs;
731
734
735 GUITownList towns{TownDirectoryWindow::last_sorting.order};
736
737 Scrollbar *vscroll = nullptr;
738
739 void BuildSortTownList()
740 {
741 if (this->towns.NeedRebuild()) {
742 this->towns.clear();
743 this->towns.reserve(Town::GetNumItems());
744
745 for (const Town *t : Town::Iterate()) {
746 if (this->string_filter.IsEmpty()) {
747 this->towns.push_back(t);
748 continue;
749 }
751 this->string_filter.AddLine(t->GetCachedName());
752 if (this->string_filter.GetState()) this->towns.push_back(t);
753 }
754
755 this->towns.RebuildDone();
756 this->vscroll->SetCount(this->towns.size()); // Update scrollbar as well.
757 }
758 /* Always sort the towns. */
759 this->towns.Sort();
760 this->SetWidgetDirty(WID_TD_LIST); // Force repaint of the displayed towns.
761 }
762
764 static bool TownNameSorter(const Town * const &a, const Town * const &b, const bool &)
765 {
766 return StrNaturalCompare(a->GetCachedName(), b->GetCachedName()) < 0; // Sort by name (natural sorting).
767 }
768
770 static bool TownPopulationSorter(const Town * const &a, const Town * const &b, const bool &order)
771 {
775 return a_population < b_population;
776 }
777
779 static bool TownRatingSorter(const Town * const &a, const Town * const &b, const bool &order)
780 {
781 bool before = !order; // Value to get 'a' before 'b'.
782
783 /* Towns without rating are always after towns with rating. */
788 if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b, order);
789 return a_rating < b_rating;
790 }
791 return before;
792 }
793 if (b->have_ratings.Test(_local_company)) return !before;
794
795 /* Sort unrated towns always on ascending town name. */
796 if (before) return TownDirectoryWindow::TownNameSorter(a, b, order);
797 return TownDirectoryWindow::TownNameSorter(b, a, order);
798 }
799
800public:
802 {
803 this->CreateNestedTree();
804
805 this->vscroll = this->GetScrollbar(WID_TD_SCROLLBAR);
806
807 this->towns.SetListing(this->last_sorting);
809 this->towns.ForceRebuild();
810 this->BuildSortTownList();
811
812 this->FinishInitNested(0);
813
815 this->townname_editbox.cancel_button = QueryString::ACTION_CLEAR;
816 }
817
818 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
819 {
820 switch (widget) {
821 case WID_TD_CAPTION:
823
826
828 return GetString(TownDirectoryWindow::sorter_names[this->towns.SortType()]);
829
830 default:
831 return this->Window::GetWidgetString(widget, stringid);
832 }
833 }
834
840 static std::string GetTownString(const Town *t, uint64_t population)
841 {
843 }
844
845 void DrawWidget(const Rect &r, WidgetID widget) const override
846 {
847 switch (widget) {
849 this->DrawSortButtonState(widget, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
850 break;
851
852 case WID_TD_LIST: {
853 Rect tr = r.Shrink(WidgetDimensions::scaled.framerect);
854 if (this->towns.empty()) { // No towns available.
856 break;
857 }
858
859 /* At least one town available. */
860 bool rtl = _current_text_dir == TD_RTL;
861 Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD);
862 int icon_x = tr.WithWidth(icon_size.width, rtl).left;
863 tr = tr.Indent(icon_size.width + WidgetDimensions::scaled.hsep_normal, rtl);
864
865 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->towns);
866 for (auto it = first; it != last; ++it) {
867 const Town *t = *it;
868 assert(t->xy != INVALID_TILE);
869
870 /* Draw rating icon. */
871 if (_game_mode == GM_EDITOR || !t->have_ratings.Test(_local_company)) {
872 DrawSprite(SPR_TOWN_RATING_NA, PAL_NONE, icon_x, tr.top + (this->resize.step_height - icon_size.height) / 2);
873 } else {
874 SpriteID icon = SPR_TOWN_RATING_APALLING;
875 if (t->ratings[_local_company] > RATING_VERYPOOR) icon = SPR_TOWN_RATING_MEDIOCRE;
876 if (t->ratings[_local_company] > RATING_GOOD) icon = SPR_TOWN_RATING_GOOD;
877 DrawSprite(icon, PAL_NONE, icon_x, tr.top + (this->resize.step_height - icon_size.height) / 2);
878 }
879
880 DrawString(tr.left, tr.right, tr.top + (this->resize.step_height - GetCharacterHeight(FS_NORMAL)) / 2, GetTownString(t, t->cache.population));
881
882 tr.top += this->resize.step_height;
883 }
884 break;
885 }
886 }
887 }
888
890 {
891 switch (widget) {
892 case WID_TD_SORT_ORDER: {
894 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
895 d.height += padding.height;
896 size = maxdim(size, d);
897 break;
898 }
900 Dimension d = GetStringListBoundingBox(TownDirectoryWindow::sorter_names);
901 d.width += padding.width;
902 d.height += padding.height;
903 size = maxdim(size, d);
904 break;
905 }
906 case WID_TD_LIST: {
908 uint64_t max_value = GetParamMaxDigits(8);
909 for (uint i = 0; i < this->towns.size(); i++) {
910 const Town *t = this->towns[i];
911
912 assert(t != nullptr);
913
914 d = maxdim(d, GetStringBoundingBox(GetTownString(t, max_value)));
915 }
916 Dimension icon_size = GetSpriteSize(SPR_TOWN_RATING_GOOD);
917 d.width += icon_size.width + 2;
918 d.height = std::max(d.height, icon_size.height);
919 resize.height = d.height;
920 d.height *= 5;
921 d.width += padding.width;
922 d.height += padding.height;
923 size = maxdim(size, d);
924 break;
925 }
928 d.width += padding.width;
929 d.height += padding.height;
930 size = maxdim(size, d);
931 break;
932 }
933 }
934 }
935
936 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
937 {
938 switch (widget) {
939 case WID_TD_SORT_ORDER: // Click on sort order button
940 if (this->towns.SortType() != 2) { // A different sort than by rating.
941 this->towns.ToggleSortOrder();
942 this->last_sorting = this->towns.GetListing(); // Store new sorting order.
943 } else {
944 /* Some parts are always sorted ascending on name. */
945 this->last_sorting.order = !this->last_sorting.order;
946 this->towns.SetListing(this->last_sorting);
947 this->towns.ForceResort();
948 this->towns.Sort();
949 }
950 this->SetDirty();
951 break;
952
953 case WID_TD_SORT_CRITERIA: // Click on sort criteria dropdown
954 ShowDropDownMenu(this, TownDirectoryWindow::sorter_names, this->towns.SortType(), WID_TD_SORT_CRITERIA, 0, 0);
955 break;
956
957 case WID_TD_LIST: { // Click on Town Matrix
958 auto it = this->vscroll->GetScrolledItemFromWidget(this->towns, pt.y, this, WID_TD_LIST, WidgetDimensions::scaled.framerect.top);
959 if (it == this->towns.end()) return; // click out of town bounds
960
961 const Town *t = *it;
962 assert(t != nullptr);
963 if (_ctrl_pressed) {
965 } else {
967 }
968 break;
969 }
970 }
971 }
972
973 void OnDropdownSelect(WidgetID widget, int index) override
974 {
975 if (widget != WID_TD_SORT_CRITERIA) return;
976
977 if (this->towns.SortType() != index) {
978 this->towns.SetSortType(index);
979 this->last_sorting = this->towns.GetListing(); // Store new sorting order.
980 this->BuildSortTownList();
981 }
982 }
983
984 void OnPaint() override
985 {
986 if (this->towns.NeedRebuild()) this->BuildSortTownList();
987 this->DrawWidgets();
988 }
989
991 IntervalTimer<TimerWindow> rebuild_interval = {std::chrono::seconds(3), [this](auto) {
992 this->BuildSortTownList();
993 this->SetDirty();
994 }};
995
996 void OnResize() override
997 {
998 this->vscroll->SetCapacityFromWidget(this, WID_TD_LIST, WidgetDimensions::scaled.framerect.Vertical());
999 }
1000
1002 {
1003 if (wid == WID_TD_FILTER) {
1004 this->string_filter.SetFilterTerm(this->townname_editbox.text.GetText());
1005 this->InvalidateData(TDIWD_FORCE_REBUILD);
1006 }
1007 }
1008
1014 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1015 {
1016 switch (data) {
1017 case TDIWD_FORCE_REBUILD:
1018 /* This needs to be done in command-scope to enforce rebuilding before resorting invalid data */
1019 this->towns.ForceRebuild();
1020 break;
1021
1022 case TDIWD_POPULATION_CHANGE:
1023 if (this->towns.SortType() == 1) this->towns.ForceResort();
1024 break;
1025
1026 default:
1027 this->towns.ForceResort();
1028 }
1029 }
1030
1032 {
1033 switch (hotkey) {
1036 SetFocusedWindow(this); // The user has asked to give focus to the text box, so make sure this window is focused.
1037 break;
1038 default:
1039 return ES_NOT_HANDLED;
1040 }
1041 return ES_HANDLED;
1042 }
1043
1044 static inline HotkeyList hotkeys {"towndirectory", {
1045 Hotkey('F', "focus_filter_box", TDHK_FOCUS_FILTER_BOX),
1046 }};
1047};
1048
1049Listing TownDirectoryWindow::last_sorting = {false, 0};
1050
1052const std::initializer_list<GUITownList::SortFunction * const> TownDirectoryWindow::sorter_funcs = {
1053 &TownNameSorter,
1054 &TownPopulationSorter,
1055 &TownRatingSorter,
1056};
1057
1058static WindowDesc _town_directory_desc(
1059 WDP_AUTO, "list_towns", 208, 202,
1061 {},
1062 _nested_town_directory_widgets,
1063 &TownDirectoryWindow::hotkeys
1064);
1065
1066void ShowTownDirectory()
1067{
1069 new TownDirectoryWindow(_town_directory_desc);
1070}
1071
1072void CcFoundTown(Commands, const CommandCost &result, TileIndex tile)
1073{
1074 if (result.Failed()) return;
1075
1076 if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile);
1078}
1079
1080void CcFoundRandomTown(Commands, const CommandCost &result, Money, TownID town_id)
1081{
1082 if (result.Succeeded()) ScrollMainWindowToTile(Town::Get(town_id)->xy);
1083}
1084
1085static constexpr NWidgetPart _nested_found_town_widgets[] = {
1087 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1088 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_FOUND_TOWN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1089 NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
1090 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
1091 EndContainer(),
1092 /* Construct new town(s) buttons. */
1093 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
1095 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_NEW_TOWN), SetStringTip(STR_FOUND_TOWN_NEW_TOWN_BUTTON, STR_FOUND_TOWN_NEW_TOWN_TOOLTIP), SetFill(1, 0),
1098 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_RANDOM_TOWN), SetStringTip(STR_FOUND_TOWN_RANDOM_TOWN_BUTTON, STR_FOUND_TOWN_RANDOM_TOWN_TOOLTIP), SetFill(1, 0),
1099 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_MANY_RANDOM_TOWNS), SetStringTip(STR_FOUND_TOWN_MANY_RANDOM_TOWNS, STR_FOUND_TOWN_RANDOM_TOWNS_TOOLTIP), SetFill(1, 0),
1100 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_LOAD_FROM_FILE), SetStringTip(STR_FOUND_TOWN_LOAD_FROM_FILE, STR_FOUND_TOWN_LOAD_FROM_FILE_TOOLTIP), SetFill(1, 0),
1101 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_EXPAND_ALL_TOWNS), SetStringTip(STR_FOUND_TOWN_EXPAND_ALL_TOWNS, STR_FOUND_TOWN_EXPAND_ALL_TOWNS_TOOLTIP), SetFill(1, 0),
1102 EndContainer(),
1103 EndContainer(),
1104
1105 /* Town name selection. */
1106 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_NAME_TITLE),
1107 NWidget(WWT_EDITBOX, COLOUR_GREY, WID_TF_TOWN_NAME_EDITBOX), SetStringTip(STR_FOUND_TOWN_NAME_EDITOR_TITLE, STR_FOUND_TOWN_NAME_EDITOR_TOOLTIP), SetFill(1, 0),
1108 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_TF_TOWN_NAME_RANDOM), SetStringTip(STR_FOUND_TOWN_NAME_RANDOM_BUTTON, STR_FOUND_TOWN_NAME_RANDOM_TOOLTIP), SetFill(1, 0),
1109
1110 /* Town size selection. */
1111 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_TITLE),
1114 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_SMALL), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_SMALL_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1115 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_MEDIUM), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_MEDIUM_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1116 EndContainer(),
1118 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_TF_SIZE_SEL),
1119 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_LARGE), SetStringTip(STR_FOUND_TOWN_INITIAL_SIZE_LARGE_BUTTON, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1120 EndContainer(),
1121 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_SIZE_RANDOM), SetStringTip(STR_FOUND_TOWN_SIZE_RANDOM, STR_FOUND_TOWN_INITIAL_SIZE_TOOLTIP), SetFill(1, 0),
1122 EndContainer(),
1123 EndContainer(),
1124 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_CITY), SetStringTip(STR_FOUND_TOWN_CITY, STR_FOUND_TOWN_CITY_TOOLTIP), SetFill(1, 0),
1125
1126 /* Town roads selection. */
1129 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_FOUND_TOWN_ROAD_LAYOUT),
1132 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_ORIGINAL), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_ORIGINAL, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1133 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_BETTER), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_BETTER_ROADS, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1134 EndContainer(),
1136 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID2), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_2X2_GRID, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1137 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_GRID3), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_3X3_GRID, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1138 EndContainer(),
1139 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_TF_LAYOUT_RANDOM), SetStringTip(STR_FOUND_TOWN_SELECT_LAYOUT_RANDOM, STR_FOUND_TOWN_SELECT_LAYOUT_TOOLTIP), SetFill(1, 0),
1140 EndContainer(),
1141 EndContainer(),
1142 EndContainer(),
1143 EndContainer(),
1144 EndContainer(),
1145};
1146
1149private:
1152 bool city = false;
1154 bool townnamevalid = false;
1157
1158public:
1160 Window(desc),
1163 params(_settings_game.game_creation.town_name)
1164 {
1165 this->InitNested(window_number);
1167 this->RandomTownName();
1168 this->UpdateButtons(true);
1169 }
1170
1171 void OnInit() override
1172 {
1173 if (_game_mode == GM_EDITOR) return;
1174
1176 this->GetWidget<NWidgetStacked>(WID_TF_SIZE_SEL)->SetDisplayedPlane(SZSP_VERTICAL);
1179 } else {
1180 this->GetWidget<NWidgetStacked>(WID_TF_ROAD_LAYOUT_SEL)->SetDisplayedPlane(0);
1181 }
1182 }
1183
1184 void RandomTownName()
1185 {
1186 this->townnamevalid = GenerateTownName(_interactive_random, &this->townnameparts);
1187
1188 if (!this->townnamevalid) {
1189 this->townname_editbox.text.DeleteAll();
1190 } else {
1191 this->townname_editbox.text.Assign(GetTownName(&this->params, this->townnameparts));
1192 }
1194
1196 }
1197
1198 void UpdateButtons(bool check_availability)
1199 {
1200 if (check_availability && _game_mode != GM_EDITOR) {
1202 this->ReInit();
1203 }
1204
1205 for (WidgetID i = WID_TF_SIZE_SMALL; i <= WID_TF_SIZE_RANDOM; i++) {
1206 this->SetWidgetLoweredState(i, i == WID_TF_SIZE_SMALL + this->town_size);
1207 }
1208
1209 this->SetWidgetLoweredState(WID_TF_CITY, this->city);
1210
1213 }
1214
1215 this->SetDirty();
1216 }
1217
1218 template <typename Tcallback>
1219 void ExecuteFoundTownCommand(TileIndex tile, bool random, StringID errstr, Tcallback cc)
1220 {
1221 std::string name;
1222
1223 if (!this->townnamevalid) {
1224 name = this->townname_editbox.text.GetText();
1225 } else {
1226 /* If user changed the name, send it */
1227 std::string original_name = GetTownName(&this->params, this->townnameparts);
1228 if (original_name != this->townname_editbox.text.GetText()) name = this->townname_editbox.text.GetText();
1229 }
1230
1231 bool success = Command<CMD_FOUND_TOWN>::Post(errstr, cc,
1232 tile, this->town_size, this->city, this->town_layout, random, townnameparts, name);
1233
1234 /* Rerandomise name, if success and no cost-estimation. */
1235 if (success && !_shift_pressed) this->RandomTownName();
1236 }
1237
1238 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1239 {
1240 switch (widget) {
1241 case WID_TF_NEW_TOWN:
1242 HandlePlacePushButton(this, WID_TF_NEW_TOWN, SPR_CURSOR_TOWN, HT_RECT);
1243 break;
1244
1245 case WID_TF_RANDOM_TOWN:
1246 this->ExecuteFoundTownCommand(TileIndex{}, true, STR_ERROR_CAN_T_GENERATE_TOWN, CcFoundRandomTown);
1247 break;
1248
1250 this->RandomTownName();
1252 break;
1253
1257 if (!GenerateTowns(this->town_layout)) {
1259 }
1261 old_generating_world.Restore();
1262 break;
1263 }
1264
1267 break;
1268
1270 for (Town *t : Town::Iterate()) {
1272 }
1273 break;
1274
1276 this->town_size = (TownSize)(widget - WID_TF_SIZE_SMALL);
1277 this->UpdateButtons(false);
1278 break;
1279
1280 case WID_TF_CITY:
1281 this->city ^= true;
1282 this->SetWidgetLoweredState(WID_TF_CITY, this->city);
1283 this->SetDirty();
1284 break;
1285
1288 this->town_layout = (TownLayout)(widget - WID_TF_LAYOUT_ORIGINAL);
1289
1290 /* If we are in the editor, sync the settings of the current game to the chosen layout,
1291 * so that importing towns from file uses the selected layout. */
1292 if (_game_mode == GM_EDITOR) _settings_game.economy.town_layout = this->town_layout;
1293
1294 this->UpdateButtons(false);
1295 break;
1296 }
1297 }
1298
1300 {
1301 this->ExecuteFoundTownCommand(tile, false, STR_ERROR_CAN_T_FOUND_TOWN_HERE, CcFoundTown);
1302 }
1303
1304 void OnPlaceObjectAbort() override
1305 {
1306 this->RaiseButtons();
1307 this->UpdateButtons(false);
1308 }
1309
1315 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1316 {
1317 if (!gui_scope) return;
1318 this->UpdateButtons(true);
1319 }
1320};
1321
1322static WindowDesc _found_town_desc(
1323 WDP_AUTO, "build_town", 160, 162,
1326 _nested_found_town_widgets
1327);
1328
1329void ShowFoundTownWindow()
1330{
1331 if (_game_mode != GM_EDITOR && !Company::IsValidID(_local_company)) return;
1332 AllocateWindowDescFront<FoundTownWindow>(_found_town_desc, 0);
1333}
1334
1335void InitializeTownGui()
1336{
1337 _town_local_authority_kdtree.Clear();
1338}
1339
1348void DrawNewHouseTileInGUI(int x, int y, const HouseSpec *spec, HouseID house_id, int view)
1349{
1350 HouseResolverObject object(house_id, INVALID_TILE, nullptr, CBID_NO_CALLBACK, 0, 0, true, view);
1351 const SpriteGroup *group = object.Resolve();
1352 if (group == nullptr || group->type != SGT_TILELAYOUT) return;
1353
1354 uint8_t stage = TOWN_HOUSE_COMPLETED;
1355 const DrawTileSprites *dts = reinterpret_cast<const TileLayoutSpriteGroup *>(group)->ProcessRegisters(&stage);
1356
1357 PaletteID palette = GENERAL_SPRITE_COLOUR(spec->random_colour[0]);
1359 uint16_t callback = GetHouseCallback(CBID_HOUSE_COLOUR, 0, 0, house_id, nullptr, INVALID_TILE, true, view);
1360 if (callback != CALLBACK_FAILED) {
1361 /* If bit 14 is set, we should use a 2cc colour map, else use the callback value. */
1362 palette = HasBit(callback, 14) ? GB(callback, 0, 8) + SPR_2CCMAP_BASE : callback;
1363 }
1364 }
1365
1366 SpriteID image = dts->ground.sprite;
1367 PaletteID pal = dts->ground.pal;
1368
1369 if (HasBit(image, SPRITE_MODIFIER_CUSTOM_SPRITE)) image += stage;
1370 if (HasBit(pal, SPRITE_MODIFIER_CUSTOM_SPRITE)) pal += stage;
1371
1372 if (GB(image, 0, SPRITE_WIDTH) != 0) {
1373 DrawSprite(image, GroundSpritePaletteTransform(image, pal, palette), x, y);
1374 }
1375
1376 DrawNewGRFTileSeqInGUI(x, y, dts, stage, palette);
1377}
1378
1386void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
1387{
1388 auto draw = [](int x, int y, HouseID house_id, int view) {
1389 if (house_id >= NEW_HOUSE_OFFSET) {
1390 /* Houses don't necessarily need new graphics. If they don't have a
1391 * spritegroup associated with them, then the sprite for the substitute
1392 * house id is drawn instead. */
1393 const HouseSpec *spec = HouseSpec::Get(house_id);
1394 if (spec->grf_prop.GetSpriteGroup() != nullptr) {
1395 DrawNewHouseTileInGUI(x, y, spec, house_id, view);
1396 return;
1397 } else {
1398 house_id = HouseSpec::Get(house_id)->grf_prop.subst_id;
1399 }
1400 }
1401
1402 /* Retrieve data from the draw town tile struct */
1403 const DrawBuildingsTileStruct &dcts = GetTownDrawTileData()[house_id << 4 | view << 2 | TOWN_HOUSE_COMPLETED];
1404 DrawSprite(dcts.ground.sprite, dcts.ground.pal, x, y);
1405
1406 /* Add a house on top of the ground? */
1407 if (dcts.building.sprite != 0) {
1408 Point pt = RemapCoords(dcts.subtile_x, dcts.subtile_y, 0);
1409 DrawSprite(dcts.building.sprite, dcts.building.pal, x + UnScaleGUI(pt.x), y + UnScaleGUI(pt.y));
1410 }
1411 };
1412
1413 /* Houses can have 1x1, 1x2, 2x1 and 2x2 layouts which are individual HouseIDs. For the GUI we need
1414 * draw all of the tiles with appropriate positions. */
1415 int x_delta = ScaleGUITrad(TILE_PIXELS);
1416 int y_delta = ScaleGUITrad(TILE_PIXELS / 2);
1417
1418 const HouseSpec *hs = HouseSpec::Get(house_id);
1419 if (hs->building_flags.Test(BuildingFlag::Size2x2)) {
1420 draw(x, y - y_delta - y_delta, house_id, view); // North corner.
1421 draw(x + x_delta, y - y_delta, house_id + 1, view); // West corner.
1422 draw(x - x_delta, y - y_delta, house_id + 2, view); // East corner.
1423 draw(x, y, house_id + 3, view); // South corner.
1424 } else if (hs->building_flags.Test(BuildingFlag::Size2x1)) {
1425 draw(x + x_delta / 2, y - y_delta, house_id, view); // North east tile.
1426 draw(x - x_delta / 2, y, house_id + 1, view); // South west tile.
1427 } else if (hs->building_flags.Test(BuildingFlag::Size1x2)) {
1428 draw(x - x_delta / 2, y - y_delta, house_id, view); // North west tile.
1429 draw(x + x_delta / 2, y, house_id + 1, view); // South east tile.
1430 } else {
1431 draw(x, y, house_id, view);
1432 }
1433}
1434
1441{
1442 uint16_t callback_res = GetHouseCallback(CBID_HOUSE_CUSTOM_NAME, 1, 0, hs->Index(), nullptr, INVALID_TILE, true);
1443 if (callback_res != CALLBACK_FAILED && callback_res != 0x400) {
1444 if (callback_res > 0x400) {
1446 } else {
1447 StringID new_name = GetGRFStringID(hs->grf_prop.grffile->grfid, GRFSTR_MISC_GRF_TEXT + callback_res);
1448 if (new_name != STR_NULL && new_name != STR_UNDEFINED) {
1449 return new_name;
1450 }
1451 }
1452 }
1453
1454 return hs->building_name;
1455}
1456
1458public:
1459 HousePickerCallbacks() : PickerCallbacks("fav_houses") {}
1460
1465 {
1467 case LandscapeType::Temperate: this->climate_mask = HZ_TEMP; break;
1468 case LandscapeType::Arctic: this->climate_mask = HZ_SUBARTC_ABOVE | HZ_SUBARTC_BELOW; break;
1469 case LandscapeType::Tropic: this->climate_mask = HZ_SUBTROPIC; break;
1470 case LandscapeType::Toyland: this->climate_mask = HZ_TOYLND; break;
1471 default: NOT_REACHED();
1472 }
1473
1474 /* In some cases, not all 'classes' (house zones) have distinct houses, so we need to disable those.
1475 * As we need to check all types, and this cannot change with the picker window open, pre-calculate it.
1476 * This loop calls GetTypeName() instead of directly checking properties so that there is no discrepancy. */
1477 this->class_mask = 0;
1478
1479 int num_classes = this->GetClassCount();
1480 for (int cls_id = 0; cls_id < num_classes; ++cls_id) {
1481 int num_types = this->GetTypeCount(cls_id);
1482 for (int id = 0; id < num_types; ++id) {
1483 if (this->GetTypeName(cls_id, id) != INVALID_STRING_ID) {
1484 SetBit(this->class_mask, cls_id);
1485 break;
1486 }
1487 }
1488 }
1489 }
1490
1491 HouseZones climate_mask{};
1492 uint8_t class_mask = 0;
1493
1494 static inline int sel_class;
1495 static inline int sel_type;
1496 static inline int sel_view;
1497
1498 /* Houses do not have classes like NewGRFClass. We'll make up fake classes based on town zone
1499 * availability instead. */
1500 static inline const std::array<StringID, HZB_END> zone_names = {
1501 STR_HOUSE_PICKER_CLASS_ZONE1,
1502 STR_HOUSE_PICKER_CLASS_ZONE2,
1503 STR_HOUSE_PICKER_CLASS_ZONE3,
1504 STR_HOUSE_PICKER_CLASS_ZONE4,
1505 STR_HOUSE_PICKER_CLASS_ZONE5,
1506 };
1507
1508 GrfSpecFeature GetFeature() const override { return GSF_HOUSES; }
1509
1510 StringID GetClassTooltip() const override { return STR_PICKER_HOUSE_CLASS_TOOLTIP; }
1511 StringID GetTypeTooltip() const override { return STR_PICKER_HOUSE_TYPE_TOOLTIP; }
1512 bool IsActive() const override { return true; }
1513
1514 bool HasClassChoice() const override { return true; }
1515 int GetClassCount() const override { return static_cast<int>(zone_names.size()); }
1516
1517 void Close([[maybe_unused]] int data) override { ResetObjectToPlace(); }
1518
1519 int GetSelectedClass() const override { return HousePickerCallbacks::sel_class; }
1520 void SetSelectedClass(int cls_id) const override { HousePickerCallbacks::sel_class = cls_id; }
1521
1522 StringID GetClassName(int id) const override
1523 {
1524 if (id >= GetClassCount()) return INVALID_STRING_ID;
1525 if (!HasBit(this->class_mask, id)) return INVALID_STRING_ID;
1526 return zone_names[id];
1527 }
1528
1529 int GetTypeCount(int cls_id) const override
1530 {
1531 if (cls_id < GetClassCount()) return static_cast<int>(HouseSpec::Specs().size());
1532 return 0;
1533 }
1534
1535 PickerItem GetPickerItem(int cls_id, int id) const override
1536 {
1537 const auto *spec = HouseSpec::Get(id);
1538 if (!spec->grf_prop.HasGrfFile()) return {0, spec->Index(), cls_id, id};
1539 return {spec->grf_prop.grfid, spec->grf_prop.local_id, cls_id, id};
1540 }
1541
1542 int GetSelectedType() const override { return sel_type; }
1543 void SetSelectedType(int id) const override { sel_type = id; }
1544
1545 StringID GetTypeName(int cls_id, int id) const override
1546 {
1547 const HouseSpec *spec = HouseSpec::Get(id);
1548 if (spec == nullptr) return INVALID_STRING_ID;
1549 if (!spec->enabled) return INVALID_STRING_ID;
1550 if ((spec->building_availability & climate_mask) == 0) return INVALID_STRING_ID;
1551 if (!HasBit(spec->building_availability, cls_id)) return INVALID_STRING_ID;
1552 for (int i = 0; i < cls_id; i++) {
1553 /* Don't include if it's already included in an earlier zone. */
1554 if (HasBit(spec->building_availability, i)) return INVALID_STRING_ID;
1555 }
1556
1557 return GetHouseName(spec);
1558 }
1559
1560 std::span<const BadgeID> GetTypeBadges(int cls_id, int id) const override
1561 {
1562 const auto *spec = HouseSpec::Get(id);
1563 if (spec == nullptr) return {};
1564 if (!spec->enabled) return {};
1565 if ((spec->building_availability & climate_mask) == 0) return {};
1566 if (!HasBit(spec->building_availability, cls_id)) return {};
1567 for (int i = 0; i < cls_id; i++) {
1568 /* Don't include if it's already included in an earlier zone. */
1569 if (HasBit(spec->building_availability, i)) return {};
1570 }
1571
1572 return spec->badges;
1573 }
1574
1575 bool IsTypeAvailable(int, int id) const override
1576 {
1577 const HouseSpec *hs = HouseSpec::Get(id);
1578 return hs->enabled;
1579 }
1580
1581 void DrawType(int x, int y, int, int id) const override
1582 {
1584 }
1585
1586 void FillUsedItems(std::set<PickerItem> &items) override
1587 {
1588 auto id_count = GetBuildingHouseIDCounts();
1589 for (auto it = id_count.begin(); it != id_count.end(); ++it) {
1590 if (*it == 0) continue;
1591 HouseID house = static_cast<HouseID>(std::distance(id_count.begin(), it));
1592 const HouseSpec *hs = HouseSpec::Get(house);
1593 int class_index = FindFirstBit(hs->building_availability & HZ_ZONALL);
1594 items.insert({0, house, class_index, house});
1595 }
1596 }
1597
1598 std::set<PickerItem> UpdateSavedItems(const std::set<PickerItem> &src) override
1599 {
1600 if (src.empty()) return src;
1601
1602 const auto &specs = HouseSpec::Specs();
1603 std::set<PickerItem> dst;
1604 for (const auto &item : src) {
1605 if (item.grfid == 0) {
1606 dst.insert(item);
1607 } else {
1608 /* Search for spec by grfid and local index. */
1609 auto it = std::ranges::find_if(specs, [&item](const HouseSpec &spec) { return spec.grf_prop.grfid == item.grfid && spec.grf_prop.local_id == item.local_id; });
1610 if (it == specs.end()) {
1611 /* Not preset, hide from UI. */
1612 dst.insert({item.grfid, item.local_id, -1, -1});
1613 } else {
1614 int class_index = FindFirstBit(it->building_availability & HZ_ZONALL);
1615 dst.insert( {item.grfid, item.local_id, class_index, it->Index()});
1616 }
1617 }
1618 }
1619
1620 return dst;
1621 }
1622
1623 static HousePickerCallbacks instance;
1624};
1625/* static */ HousePickerCallbacks HousePickerCallbacks::instance;
1626
1632static CargoTypes GetProducedCargoOfHouse(const HouseSpec *hs)
1633{
1634 CargoTypes produced{};
1636 for (uint i = 0; i < 256; i++) {
1637 uint16_t callback = GetHouseCallback(CBID_HOUSE_PRODUCE_CARGO, i, 0, hs->Index(), nullptr, INVALID_TILE, true);
1638
1639 if (callback == CALLBACK_FAILED || callback == CALLBACK_HOUSEPRODCARGO_END) break;
1640
1641 CargoType cargo = GetCargoTranslation(GB(callback, 8, 7), hs->grf_prop.grffile);
1642 if (!IsValidCargoType(cargo)) continue;
1643
1644 uint amt = GB(callback, 0, 8);
1645 if (amt == 0) continue;
1646
1647 SetBit(produced, cargo);
1648 }
1649 } else {
1650 /* Cargo is not controlled by NewGRF, town production effect is used instead. */
1651 for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_PASSENGERS]) SetBit(produced, cs->Index());
1652 for (const CargoSpec *cs : CargoSpec::town_production_cargoes[TPE_MAIL]) SetBit(produced, cs->Index());
1653 }
1654 return produced;
1655}
1656
1658 std::string house_info{};
1659 bool house_protected = false;
1660
1661 BuildHouseWindow(WindowDesc &desc, Window *parent) : PickerWindow(desc, parent, 0, HousePickerCallbacks::instance)
1662 {
1663 HousePickerCallbacks::instance.SetClimateMask();
1664 this->ConstructWindow();
1665 }
1666
1667 void UpdateSelectSize(const HouseSpec *spec)
1668 {
1669 if (spec == nullptr) {
1670 SetTileSelectSize(1, 1);
1672 } else {
1673 SetObjectToPlaceWnd(SPR_CURSOR_TOWN, PAL_NONE, HT_RECT | HT_DIAGONAL, this);
1674 if (spec->building_flags.Test(BuildingFlag::Size2x2)) {
1675 SetTileSelectSize(2, 2);
1676 } else if (spec->building_flags.Test(BuildingFlag::Size2x1)) {
1677 SetTileSelectSize(2, 1);
1678 } else if (spec->building_flags.Test(BuildingFlag::Size1x2)) {
1679 SetTileSelectSize(1, 2);
1680 } else if (spec->building_flags.Test(BuildingFlag::Size1x1)) {
1681 SetTileSelectSize(1, 1);
1682 }
1683 }
1684 }
1685
1692 static std::string GetHouseYear(TimerGameCalendar::Year min_year, TimerGameCalendar::Year max_year)
1693 {
1694 if (min_year == CalendarTime::MIN_YEAR) {
1695 if (max_year == CalendarTime::MAX_YEAR) {
1697 }
1698 return GetString(STR_HOUSE_PICKER_YEARS_UNTIL, max_year);
1699 }
1700 if (max_year == CalendarTime::MAX_YEAR) {
1701 return GetString(STR_HOUSE_PICKER_YEARS_FROM, min_year);
1702 }
1703 return GetString(STR_HOUSE_PICKER_YEARS, min_year, max_year);
1704 }
1705
1711 static std::string GetHouseInformation(const HouseSpec *hs)
1712 {
1713 std::stringstream line;
1714
1716 line << "\n";
1717
1719 line << "\n";
1720
1721 line << GetHouseYear(hs->min_year, hs->max_year);
1722 line << "\n";
1723
1724 uint8_t size = 0;
1725 if (hs->building_flags.Test(BuildingFlag::Size1x1)) size = 0x11;
1726 if (hs->building_flags.Test(BuildingFlag::Size2x1)) size = 0x21;
1727 if (hs->building_flags.Test(BuildingFlag::Size1x2)) size = 0x12;
1728 if (hs->building_flags.Test(BuildingFlag::Size2x2)) size = 0x22;
1729 line << GetString(STR_HOUSE_PICKER_SIZE, GB(size, 0, 4), GB(size, 4, 4));
1730
1732 if (cargo_string.has_value()) {
1733 line << "\n";
1734 line << *cargo_string;
1735 }
1736
1737 CargoTypes produced = GetProducedCargoOfHouse(hs);
1738 if (produced != 0) {
1739 line << "\n";
1740 line << GetString(STR_HOUSE_PICKER_CARGO_PRODUCED, produced);
1741 }
1742
1743 return line.str();
1744 }
1745
1746 void OnInit() override
1747 {
1748 this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !this->house_protected);
1749 this->SetWidgetLoweredState(WID_BH_PROTECT_ON, this->house_protected);
1750
1751 this->PickerWindow::OnInit();
1752 }
1753
1754 void DrawWidget(const Rect &r, WidgetID widget) const override
1755 {
1756 if (widget == WID_BH_INFO) {
1757 if (!this->house_info.empty()) DrawStringMultiLine(r, this->house_info);
1758 } else {
1759 this->PickerWindow::DrawWidget(r, widget);
1760 }
1761 }
1762
1763 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1764 {
1765 switch (widget) {
1766 case WID_BH_PROTECT_OFF:
1767 case WID_BH_PROTECT_ON:
1768 this->house_protected = (widget == WID_BH_PROTECT_ON);
1769 this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !this->house_protected);
1770 this->SetWidgetLoweredState(WID_BH_PROTECT_ON, this->house_protected);
1771
1773 this->SetDirty();
1774 break;
1775
1776 default:
1777 this->PickerWindow::OnClick(pt, widget, click_count);
1778 break;
1779 }
1780 }
1781
1782 void OnInvalidateData(int data = 0, bool gui_scope = true) override
1783 {
1785 if (!gui_scope) return;
1786
1788
1789 PickerInvalidations pi(data);
1790 if (pi.Test(PickerInvalidation::Position)) {
1791 UpdateSelectSize(spec);
1792 this->house_info = GetHouseInformation(spec);
1793 }
1794
1795 /* If house spec already has the protected flag, handle it automatically and disable the buttons. */
1797 if (hasflag) this->house_protected = true;
1798
1799 this->SetWidgetLoweredState(WID_BH_PROTECT_OFF, !this->house_protected);
1800 this->SetWidgetLoweredState(WID_BH_PROTECT_ON, this->house_protected);
1801
1804 }
1805
1807 {
1809 Command<CMD_PLACE_HOUSE>::Post(STR_ERROR_CAN_T_BUILD_HOUSE, CcPlaySound_CONSTRUCTION_OTHER, tile, spec->Index(), this->house_protected);
1810 }
1811
1812 IntervalTimer<TimerWindow> view_refresh_interval = {std::chrono::milliseconds(2500), [this](auto) {
1813 /* There are four different 'views' that are random based on house tile position. As this is not
1814 * user-controllable, instead we automatically cycle through them. */
1816 this->SetDirty();
1817 }};
1818
1819 static inline HotkeyList hotkeys{"buildhouse", {
1820 Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX),
1821 }};
1822};
1823
1827 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1828 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_HOUSE_PICKER_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1829 NWidget(WWT_SHADEBOX, COLOUR_DARK_GREEN),
1830 NWidget(WWT_DEFSIZEBOX, COLOUR_DARK_GREEN),
1831 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
1832 EndContainer(),
1836 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
1838 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BH_INFO), SetFill(1, 1), SetMinimalTextLines(10, 0),
1839 NWidget(WWT_LABEL, INVALID_COLOUR), SetStringTip(STR_HOUSE_PICKER_PROTECT_TITLE, STR_NULL), SetFill(1, 0),
1841 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BH_PROTECT_OFF), SetMinimalSize(60, 12), SetStringTip(STR_HOUSE_PICKER_PROTECT_OFF, STR_HOUSE_PICKER_PROTECT_TOOLTIP),
1842 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BH_PROTECT_ON), SetMinimalSize(60, 12), SetStringTip(STR_HOUSE_PICKER_PROTECT_ON, STR_HOUSE_PICKER_PROTECT_TOOLTIP),
1843 EndContainer(),
1844 EndContainer(),
1845 EndContainer(),
1846
1847 EndContainer(),
1849 EndContainer(),
1850};
1851
1852static WindowDesc _build_house_desc(
1853 WDP_AUTO, "build_house", 0, 0,
1857 &BuildHouseWindow::hotkeys
1858);
1859
1860void ShowBuildHousePicker(Window *parent)
1861{
1862 if (BringWindowToFrontById(WC_BUILD_HOUSE, 0)) return;
1863 new BuildHouseWindow(_build_house_desc, parent);
1864}
Class for backupping variables and making sure they are restored later.
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint8_t FindFirstBit(T x)
Search the first set bit in a value.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
Definition cargo_type.h:23
bool IsValidCargoType(CargoType t)
Test whether cargo type is not INVALID_CARGO.
Definition cargo_type.h:106
std::optional< std::string > BuildCargoAcceptanceString(const CargoArray &acceptance, StringID label)
Build comma-separated cargo acceptance string.
@ TPE_PASSENGERS
Cargo behaves passenger-like for production.
Definition cargotype.h:37
@ TPE_MAIL
Cargo behaves mail-like for production.
Definition cargotype.h:38
TownAcceptanceEffect
Town growth effect when delivering cargo.
Definition cargotype.h:22
@ TAE_END
End of town effects.
Definition cargotype.h:30
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
constexpr Timpl & Set()
Set all bits.
Common return value for all commands.
bool Succeeded() const
Did this command succeed?
bool Failed() const
Did this command fail?
std::string GetDecodedString() const
Decode the encoded string.
Definition strings.cpp:219
List template of 'things' T to sort in a GUI.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetListing(Listing l)
Import sort conditions.
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.
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
PickerItem GetPickerItem(int cls_id, int id) const override
Get data about an item.
bool IsActive() const override
Should picker class/type selection be enabled?
void SetClimateMask()
Set climate mask for filtering buildings from current landscape.
void SetSelectedClass(int cls_id) const override
Set the selected class.
StringID GetClassTooltip() const override
Get the tooltip string for the class list.
std::span< const BadgeID > GetTypeBadges(int cls_id, int id) const override
Get the item of a type.
void DrawType(int x, int y, int, int id) const override
Draw preview image of an item.
static int sel_view
Currently selected 'view'. This is not controllable as its based on random data.
int GetClassCount() const override
Get the number of classes.
void FillUsedItems(std::set< PickerItem > &items) override
Fill a set with all items that are used by the current player.
static int sel_type
Currently selected HouseID.
int GetSelectedClass() const override
Get the index of the selected class.
std::set< PickerItem > UpdateSavedItems(const std::set< PickerItem > &src) override
Update link between grfid/localidx and class_index/index in saved items.
StringID GetTypeTooltip() const override
Get the tooltip string for the type grid.
void SetSelectedType(int id) const override
Set the selected type.
StringID GetTypeName(int cls_id, int id) const override
Get the item of a type.
int GetSelectedType() const override
Get the selected type.
bool IsTypeAvailable(int, int id) const override
Test if an item is currently buildable.
bool HasClassChoice() const override
Are there multiple classes to chose from?
uint8_t class_mask
Mask of available 'classes'.
int GetTypeCount(int cls_id) const override
Get the number of types in a class.
StringID GetClassName(int id) const override
Get the name of a class.
static int sel_class
Currently selected 'class'.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
K-dimensional tree, specialised for 2-dimensional space.
Definition kdtree.hpp:35
void Insert(const T &element)
Insert a single element in the tree.
Definition kdtree.hpp:398
void Remove(const T &element)
Remove a single element from the tree, if it exists.
Definition kdtree.hpp:417
void Clear()
Clear the tree.
Definition kdtree.hpp:377
Baseclass for nested widgets.
Nested widget to display a viewport in a window.
void UpdateViewportCoordinates(Window *w)
Update the position and size of the viewport (after eg a resize).
Definition widget.cpp:2424
void InitializeViewport(Window *w, std::variant< TileIndex, VehicleID > focus, ZoomLevel zoom)
Initialize the viewport of the window.
Definition widget.cpp:2415
Class for PickerClassWindow to collect information and retain state.
Definition picker_gui.h:38
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
@ Position
Update scroll positions.
@ PCWHK_FOCUS_FILTER_BOX
Focus the edit box for editing the filter string.
Definition picker_gui.h:194
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnInit() override
Notification that the nested widget tree gets initialized.
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
size_type GetCount() const
Gets the number of elements in the list.
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static constexpr TimerGame< struct Calendar >::Year MIN_YEAR
The absolute minimum year in OTTD.
static constexpr TimerGame< struct Calendar >::Year MAX_YEAR
MAX_YEAR, nicely rounded value of the number of years that can be encoded in a single 32 bits date,...
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
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 vsep_normal
Normal vertical spacing.
Definition window_gui.h:58
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:94
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
Functions related to commands.
@ Execute
execute the given command
Commands
List of commands.
Definition of stuff that is very close to a company, like the company struct itself.
void DrawCompanyIcon(CompanyID c, int x, int y)
Draw the icon of a company.
Money GetAvailableMoney(CompanyID company)
Get the amount of money that a company has available, or INT64_MAX if there is no such valid company.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Functions related to companies.
GUI Functions related to companies.
void ShowDropDownMenu(Window *w, std::span< const StringID > strings, int selected, WidgetID button, uint32_t disabled_mask, uint32_t hidden_mask, uint width)
Show a dropdown menu window near a widget of the parent window.
Definition dropdown.cpp:441
Functions related to the drop down widget.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23)
Definition enum_type.hpp:17
Functions related to errors.
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition error.h:24
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCost &cc)
Display an error message in a window.
@ SLO_LOAD
File is being loaded.
Definition fileio_type.h:55
@ FT_TOWN_DATA
town data file
Definition fileio_type.h:21
Declarations for savegames operations.
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
Definition fios_gui.cpp:984
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:77
bool _generating_world
Whether we are generating the map or not.
Definition genworld.cpp:72
Functions related to world/map generation.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:705
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:923
bool _shift_pressed
Is Shift pressed?
Definition gfx.cpp:39
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:852
Dimension GetStringListBoundingBox(std::span< const StringID > list, FontSize fontsize)
Get maximum dimension of a list of strings.
Definition gfx.cpp:890
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
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
Dimension GetStringMultiLineBoundingBox(StringID str, const Dimension &suggestion)
Calculate string bounding box for multi-line strings.
Definition gfx.cpp:741
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:775
uint32_t SpriteID
The number of a sprite, without mapping bits and colourtables.
Definition gfx_type.h:17
@ FS_NORMAL
Index of the normal font in the font tables.
Definition gfx_type.h:243
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:294
@ TC_NO_SHADE
Do not add shading to this text colour.
Definition gfx_type.h:318
constexpr NWidgetPart NWidgetFunction(NWidgetFunctionType *func_ptr)
Obtain a nested widget (sub)tree from an external source.
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 SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around 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.
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
uint8_t LowestSnowLine()
Get the lowest possible snow line height, either variable or static.
uint8_t GetSnowLine()
Get the current snow line, either variable or static.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition window.cpp:943
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1500
GUI functions that shouldn't be here.
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
Hotkey related functions.
definition of HouseSpec and accessors
@ BuildingIsProtected
towns and AI will not remove this house, while human players will be able to
static const HouseID NEW_HOUSE_OFFSET
Offset for new houses.
Definition house.h:28
static const uint8_t TOWN_HOUSE_COMPLETED
Simple value that indicates the house has reached the final stage of construction.
Definition house.h:25
HouseZones
Definition house.h:68
@ HZ_SUBARTC_BELOW
13 2000 can appear in sub-arctic climate below the snow line
Definition house.h:78
@ HZ_ZONALL
1F This is just to englobe all above types at once
Definition house.h:75
@ HZ_TEMP
12 1000 can appear in temperate climate
Definition house.h:77
@ HZ_TOYLND
15 8000 can appear in toyland climate
Definition house.h:80
@ HZ_SUBTROPIC
14 4000 can appear in subtropical climate
Definition house.h:79
@ HZ_SUBARTC_ABOVE
11 800 can appear in sub-arctic climate above the snow line
Definition house.h:76
uint16_t HouseID
OpenTTD ID of house types.
Definition house_type.h:13
Functions related to OTTD's landscape.
Point RemapCoords(int x, int y, int z)
Map 3D world or tile coordinate to equivalent 2D coordinate as used in the viewports and smallmap.
Definition landscape.h:79
bool DoZoomInOutWindow(ZoomStateChange how, Window *w)
Zooms a viewport in a window in or out.
Definition main_gui.cpp:93
bool HandlePlacePushButton(Window *w, WidgetID widget, CursorID cursor, HighLightStyle mode)
This code is shared for the majority of the pushbuttons.
Definition main_gui.cpp:63
constexpr int RoundDivSU(int a, uint b)
Computes round(a / b) for signed a and unsigned b.
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.
bool _networking
are we in networking mode?
Definition network.cpp:65
bool _network_server
network-server is active
Definition network.cpp:66
Basic functions/variables used all over the place.
GrfSpecFeature
Definition newgrf.h:68
@ CBID_HOUSE_COLOUR
Called to determine the colour of a town building.
@ CBID_NO_CALLBACK
Set when using the callback resolve system, but not to resolve a callback.
@ CBID_HOUSE_CUSTOM_NAME
Called on the Get Tile Description for an house tile.
@ CBID_HOUSE_PRODUCE_CARGO
Called to determine how much cargo a town building produces.
static const uint CALLBACK_FAILED
Different values for Callback result evaluations.
@ ProduceCargo
custom cargo production
@ Colour
decide the colour of the building
static const uint CALLBACK_HOUSEPRODCARGO_END
Sentinel indicating that the loop for CBID_HOUSE_PRODUCE_CARGO has ended.
CargoType GetCargoTranslation(uint8_t cargo, const GRFFile *grffile, bool usebit)
Translate a GRF-local cargo slot/bitnum into a CargoType.
Cargo support for NewGRFs.
void ErrorUnknownCallbackResult(uint32_t grfid, uint16_t cbid, uint16_t cb_res)
Record that a NewGRF returned an unknown/invalid callback result.
std::span< const uint > GetBuildingHouseIDCounts()
Get read-only span of total HouseID building counts.
Functions related to NewGRF houses.
StringID GetGRFStringID(uint32_t grfid, GRFStringID stringid)
Returns the index for this stringid associated with its grfID.
Header of Action 04 "universal holder" structure and functions.
static constexpr GRFStringID GRFSTR_MISC_GRF_TEXT
Miscellaneous GRF text range.
void UpdateOSKOriginalText(const Window *parent, WidgetID button)
Updates the original text of the OSK so when the 'parent' changes the original and you press on cance...
Definition osk_gui.cpp:412
std::unique_ptr< NWidgetBase > MakePickerClassWidgets()
Create nested widgets for the class picker widgets.
std::unique_ptr< NWidgetBase > MakePickerTypeWidgets()
Create nested widgets for the type picker widgets.
Functions/types etc.
Base for the GUIs that have an edit box in them.
Randomizer _interactive_random
Random used everywhere else, where it does not (directly) influence the game state.
void UpdateNearestTownForRoadTiles(bool invalidate)
Updates cached nearest town for all road tiles.
Road related functions.
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:58
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:57
@ SWS_OFF
Scroll wheel has no effect.
Base types for having sorted lists in GUIs.
Functions related to sound.
@ SND_15_BEEP
19 == 0x13 GUI button click
Definition sound_type.h:66
@ SND_1F_CONSTRUCTION_OTHER
29 == 0x1D Construction: other (non-water, non-rail, non-bridge)
Definition sound_type.h:76
void DrawNewGRFTileSeqInGUI(int x, int y, const DrawTileSprites *dts, uint32_t stage, PaletteID default_palette)
Draw NewGRF object in GUI.
Definition sprite.h:139
PaletteID GroundSpritePaletteTransform(SpriteID image, PaletteID pal, PaletteID default_pal)
Applies PALETTE_MODIFIER_COLOUR to a palette entry of a ground sprite.
Definition sprite.h:174
static constexpr uint8_t SPRITE_MODIFIER_CUSTOM_SPRITE
these masks change the colours of the palette for a sprite.
Definition sprites.h:1549
static constexpr uint8_t SPRITE_WIDTH
number of bits for the sprite number
Definition sprites.h:1539
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
Searching and filtering using a stringterm.
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
uint64_t GetParamMaxDigits(uint count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:230
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
@ TD_RTL
Text is written right-to-left by default.
static const int MAX_CHAR_LENGTH
Max. length of UTF-8 encoded unicode character.
Class to backup a specific variable and restore it later.
void Restore()
Restore the variable.
static std::string GetHouseYear(TimerGameCalendar::Year min_year, TimerGameCalendar::Year max_year)
Get a date range string for house availability year.
void OnPlaceObject(Point pt, TileIndex tile) override
The user clicked some place on the map when a tile highlight mode has been set.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
static std::string GetHouseInformation(const HouseSpec *hs)
Get information string for a house.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInit() override
Notification that the nested widget tree gets initialized.
Specification of a cargo type.
Definition cargotype.h:74
CargoType Index() const
Determines index of this cargospec.
Definition cargotype.h:108
StringID name
Name of this type of cargo.
Definition cargotype.h:91
static std::array< std::vector< const CargoSpec * >, NUM_TPE > town_production_cargoes
List of cargo specs for each Town Product Effect.
Definition cargotype.h:27
SoundSettings sound
sound effect settings
GUISettings gui
settings related to the GUI
Dimensions (a width and height) of a rectangle in 2D.
This structure is the same for both Industries and Houses.
Definition sprite.h:76
Ground palette sprite of a tile, together with its sprite layout.
Definition sprite.h:46
PalSpriteID ground
Palette and sprite for the ground.
Definition sprite.h:47
bool bribe
enable bribing the local authority
TownFounding found_town
town founding.
bool exclusive_rights
allow buying exclusive rights
TownLayout town_layout
select town layout,
bool station_noise_level
build new airports when the town noise level is still within accepted limits
bool fund_buildings
allow funding new buildings
bool fund_roads
allow funding local road reconstruction
const struct SpriteGroup * GetSpriteGroup(size_t index=0) const
Get the SpriteGroup at the specified index.
Found a town window class.
uint32_t townnameparts
Generated town name.
TownLayout town_layout
Selected town layout.
void OnPlaceObject(Point pt, TileIndex tile) override
The user clicked some place on the map when a tile highlight mode has been set.
QueryString townname_editbox
Townname editbox.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void OnInit() override
Notification that the nested widget tree gets initialized.
TownSize town_size
Selected town size.
bool townnamevalid
Is generated town name valid?
TownNameParams params
Town name parameters.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
bool city
Are we building a city?
const struct GRFFile * grffile
grf file that introduced this entity
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
bool persistent_buildingtools
keep the building tools active after usage
uint8_t scrollwheel_scrolling
scrolling using the scroll wheel?
LandscapeType landscape
the landscape we're currently in
EconomySettings economy
settings to change the economy
GameCreationSettings game_creation
settings used during the creation of a game (map)
List of hotkeys for a window.
Definition hotkeys.h:37
All data for a single hotkey.
Definition hotkeys.h:21
Resolver object to be used for houses (feature 07 spritegroups).
bool enabled
the house is available to build (true by default, but can be disabled by newgrf)
Definition house.h:106
static HouseSpec * Get(size_t house_id)
Get the spec for a house ID.
BuildingFlags building_flags
some flags that describe the house (size, stadium etc...)
Definition house.h:104
TimerGameCalendar::Year max_year
last year it can be built
Definition house.h:96
HouseCallbackMasks callback_mask
Bitmask of house callbacks that have to be called.
Definition house.h:110
uint8_t population
population (Zero on other tiles in multi tile house.)
Definition house.h:97
HouseExtraFlags extra_flags
some more flags
Definition house.h:113
TimerGameCalendar::Year min_year
introduction year of the house
Definition house.h:95
HouseID Index() const
Gets the index of this spec.
StringID building_name
building name
Definition house.h:99
GRFFileProps grf_prop
Properties related the the grf file.
Definition house.h:109
Colours random_colour[4]
4 "random" colours
Definition house.h:111
HouseZones building_availability
where can it be built (climates, zones)
Definition house.h:105
static std::vector< HouseSpec > & Specs()
Get a reference to all HouseSpecs.
Data structure describing how to show the list (what sort direction and criteria).
bool order
Ascending/descending.
Partial widget specification to allow NWidgets to be written nested.
SpriteID sprite
The 'real' sprite.
Definition gfx_type.h:23
PaletteID pal
The palette (use PAL_NONE) if not needed)
Definition gfx_type.h:24
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.
static size_t GetNumItems()
Returns number of valid items in the pool.
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.
Data stored about a string that can be modified in the GUI.
int cancel_button
Widget button of parent window to simulate when pressing CANCEL in OSK.
static const int ACTION_CLEAR
Clear editbox.
constexpr uint Horizontal() const
Get total horizontal 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 Indent(int indent, bool end) const
Copy Rect and indent it from its position.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:213
Iterable ensemble of each set bit in a value.
bool click_beep
Beep on a random selection of buttons.
bool confirm
Play sound effect on successful constructions or other actions.
virtual const SpriteGroup * Resolve(ResolverObject &object) const
Base sprite group resolver.
String filter and state.
bool IsEmpty() const
Check whether any filter words were entered.
void SetFilterTerm(std::string_view str)
Set the term to filter on.
void ResetState()
Reset the matching state to process a new item.
void AddLine(const char *str)
Pass another text line from the current item to the filter.
bool GetState() const
Get the matching state of the current item.
void DeleteAll()
Delete every character in the textbuffer.
Definition textbuf.cpp:112
void Assign(const std::string_view text)
Copy a string into the textbuffer.
Definition textbuf.cpp:422
const char * GetText() const
Get the current text.
Definition textbuf.cpp:286
Action 2 sprite layout for houses, industry tiles, objects and airport tiles.
Town authority window.
Definition town_gui.cpp:80
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition town_gui.cpp:340
void DrawActions()
Draws the contents of the actions panel.
Definition town_gui.cpp:223
Dimension icon_size
Dimensions of company icon.
Definition town_gui.cpp:89
void OnInit() override
Notification that the nested widget tree gets initialized.
Definition town_gui.cpp:148
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition town_gui.cpp:252
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.
Definition town_gui.cpp:268
Town * town
Town being displayed.
Definition town_gui.cpp:82
TownActions enabled_actions
Actions that are enabled in settings.
Definition town_gui.cpp:85
TownAction sel_action
Currently selected town action, TownAction::End means no action selected.
Definition town_gui.cpp:83
TownActions available_actions
Actions that are available to execute for the current company.
Definition town_gui.cpp:86
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition town_gui.cpp:300
void DrawRatings()
Draw the contents of the ratings panel.
Definition town_gui.cpp:184
int GetNthSetBit(int n)
Get the position of the Nth set bit.
Definition town_gui.cpp:100
Dimension exclusive_size
Dimensions of exclusive icon.
Definition town_gui.cpp:90
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition town_gui.cpp:245
IntervalTimer< TimerWindow > redraw_interval
Redraw the whole window on a regular interval.
Definition town_gui.cpp:336
static TownActions GetEnabledActions()
Gets all town authority actions enabled in settings.
Definition town_gui.cpp:116
void OnPaint() override
The window must be repainted.
Definition town_gui.cpp:154
TownActions displayed_actions_on_previous_painting
Actions that were available on the previous call to OnPaint()
Definition town_gui.cpp:84
uint32_t population
Current population of people.
Definition town.h:42
Town directory window class.
Definition town_gui.cpp:719
static const std::initializer_list< GUITownList::SortFunction *const > sorter_funcs
Available town directory sorting functions.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition town_gui.cpp:845
static bool TownPopulationSorter(const Town *const &a, const Town *const &b, const bool &order)
Sort by population (default descending, as big towns are of the most interest).
Definition town_gui.cpp:770
IntervalTimer< TimerWindow > rebuild_interval
Redraw the whole window on a regular interval.
Definition town_gui.cpp:991
void OnDropdownSelect(WidgetID widget, int index) override
A dropdown option associated to this window has been selected.
Definition town_gui.cpp:973
QueryString townname_editbox
Filter editbox.
Definition town_gui.cpp:733
void OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
static bool TownRatingSorter(const Town *const &a, const Town *const &b, const bool &order)
Sort by town rating.
Definition town_gui.cpp:779
void OnResize() override
Called after the window got resized.
Definition town_gui.cpp:996
StringFilter string_filter
Filter for towns.
Definition town_gui.cpp:732
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
EventState OnHotkey(int hotkey) override
A hotkey has been pressed.
void OnPaint() override
The window must be repainted.
Definition town_gui.cpp:984
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition town_gui.cpp:936
static std::string GetTownString(const Town *t, uint64_t population)
Get the string to draw the town name.
Definition town_gui.cpp:840
static bool TownNameSorter(const Town *const &a, const Town *const &b, const bool &)
Sort by town name.
Definition town_gui.cpp:764
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.
Definition town_gui.cpp:889
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition town_gui.cpp:818
Struct holding parameters used to generate town name.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition town_gui.cpp:489
Town * town
Town displayed by the window.
Definition town_gui.cpp:367
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition town_gui.cpp:594
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.
Definition town_gui.cpp:523
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition town_gui.cpp:410
uint GetDesiredInfoHeight(int width) const
Gets the desired height for the information panel.
Definition town_gui.cpp:536
void OnMouseWheel(int wheel) override
The mouse wheel has been turned.
Definition town_gui.cpp:582
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition town_gui.cpp:395
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition town_gui.cpp:389
void OnPaint() override
The window must be repainted.
Definition town_gui.cpp:402
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
Definition town_gui.cpp:602
void OnResize() override
Called after the window got resized.
Definition town_gui.cpp:572
Town data structure.
Definition town.h:52
EncodedString text
General text with additional information.
Definition town.h:81
bool larger_town
if this is a larger town and should grow more quickly
Definition town.h:99
ReferenceThroughBaseContainer< std::array< int16_t, MAX_COMPANIES > > ratings
ratings of each company for this town
Definition town.h:75
TileIndex xy
town center tile
Definition town.h:53
uint8_t fund_buildings_months
fund buildings program in action?
Definition town.h:96
uint16_t noise_reached
level of noise that all the airports are generating
Definition town.h:66
uint8_t flags
See TownFlags.
Definition town.h:64
TownCache cache
Container for all cacheable data.
Definition town.h:55
CompanyID exclusivity
which company has exclusivity
Definition town.h:73
std::array< TransportedCargoStat< uint32_t >, NUM_CARGO > supplied
Cargo statistics about supplied cargo.
Definition town.h:77
bool show_zone
NOSAVE: mark town to show the local authority zone in the viewports.
Definition town.h:102
CompanyMask have_ratings
which companies have a rating
Definition town.h:71
uint16_t growth_rate
town growth rate
Definition town.h:94
std::array< TransportedCargoStat< uint16_t >, NUM_TAE > received
Cargo statistics about received cargotypes.
Definition town.h:78
std::array< uint32_t, NUM_TAE > goal
Amount of cargo required for the town to grow.
Definition town.h:79
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
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:955
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1050
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
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:321
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:744
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3164
Window * parent
Parent window.
Definition window_gui.h:329
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
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1726
ViewportData * viewport
Pointer to viewport data, if present.
Definition window_gui.h:319
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:483
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition window_gui.h:492
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition window.cpp:528
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:442
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:558
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
Definition window.cpp:210
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:973
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1749
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
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
AllWindows< false > Iterate
Iterate all windows in whatever order is easiest.
Definition window_gui.h:923
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
@ EnableDefault
enable the 'Default' button ("\0" is returned)
@ LengthIsInChars
the length of the string is counted in characters
TropicZone GetTropicZone(Tile tile)
Get the tropic zone.
Definition tile_map.h:238
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
Definition tile_map.h:29
static const uint TILE_PIXELS
Pixel distance between tile columns/rows in ZOOM_BASE.
Definition tile_type.h:17
@ TROPICZONE_DESERT
Tile is desert.
Definition tile_type.h:78
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_DIAGONAL
Also allow 'diagonal rectangles'. Only usable in combination with HT_RECT or HT_POINT.
@ HT_RECT
rectangle (stations, depots, ...)
Definition of Interval and OneShot timers.
Definition of the game-calendar-timer.
Definition of the Window system.
Base of the town class.
static const uint TOWN_GROWTH_WINTER
The town only needs this cargo in the winter (any amount)
Definition town.h:31
TownActions GetMaskOfTownActions(CompanyID cid, const Town *t)
Get a list of available town authority actions.
const CargoSpec * FindFirstCargoWithTownAcceptanceEffect(TownAcceptanceEffect effect)
Determines the first cargo with a certain town effect.
static const uint TOWN_GROWTH_DESERT
The town needs the cargo for growth when on desert (any amount)
Definition town.h:32
@ TOWN_IS_GROWING
Conditions for town growth are met. Grow according to Town::growth_rate.
Definition town.h:194
uint32_t GetWorldPopulation()
Get the total population, the sum of all towns in the world.
Definition town_cmd.cpp:462
CargoArray GetAcceptedCargoOfHouse(const HouseSpec *hs)
Get accepted cargo of a house prototype.
Definition town_cmd.cpp:858
uint8_t GetTownActionCost(TownAction action)
Get cost factors for a TownAction.
TownAction
Town actions of a company.
Definition town.h:210
@ RoadRebuild
Rebuild the roads.
@ Bribe
Try to bribe the council.
@ BuyRights
Buy exclusive transport rights.
@ FundBuildings
Fund new buildings.
bool GenerateTowns(TownLayout layout)
Generate a number of towns with a given layout.
Command definitions related to towns.
TownDirectoryHotkeys
Enum referring to the Hotkeys in the town directory window.
Definition town_gui.cpp:714
@ TDHK_FOCUS_FILTER_BOX
Focus the filter box.
Definition town_gui.cpp:715
static constexpr NWidgetPart _nested_build_house_widgets[]
Nested widget definition for the build NewGRF rail waypoint window.
void DrawHouseInGUI(int x, int y, HouseID house_id, int view)
Draw a house that does not exist.
void DrawNewHouseTileInGUI(int x, int y, const HouseSpec *spec, HouseID house_id, int view)
Draw representation of a house tile for GUI purposes.
static StringID GetHouseName(const HouseSpec *hs)
Get name for a prototype house.
static CargoTypes GetProducedCargoOfHouse(const HouseSpec *hs)
Get the cargo types produced by a house.
Declarations for accessing the k-d tree of towns.
TownLayout
Town Layouts.
Definition town_type.h:81
@ TF_CUSTOM_LAYOUT
Allowed, with custom town layout.
Definition town_type.h:99
TownSize
Supported initial town sizes.
Definition town_type.h:21
@ TSZ_MEDIUM
Medium town.
Definition town_type.h:23
static const uint MAX_LENGTH_TOWN_NAME_CHARS
The maximum length of a town name in characters including '\0'.
Definition town_type.h:111
Types related to the town widgets.
@ WID_TA_EXECUTE
Do-it button.
Definition town_widget.h:32
@ WID_TA_ACTION_INFO
Additional information about the action.
Definition town_widget.h:31
@ WID_TA_RATING_INFO
Overview with ratings for each company.
Definition town_widget.h:28
@ WID_TA_CAPTION
Caption of window.
Definition town_widget.h:26
@ WID_TA_ZONE_BUTTON
Turn on/off showing local authority zone.
Definition town_widget.h:27
@ WID_TA_COMMAND_LIST
List of commands for the player.
Definition town_widget.h:29
@ WID_TV_VIEWPORT
View of the center of the town.
Definition town_widget.h:38
@ WID_TV_INFO
General information about the town.
Definition town_widget.h:39
@ WID_TV_EXPAND
Expand this town (scenario editor only).
Definition town_widget.h:44
@ WID_TV_CATCHMENT
Toggle catchment area highlight.
Definition town_widget.h:43
@ WID_TV_SHOW_AUTHORITY
Show the town authority window.
Definition town_widget.h:41
@ WID_TV_CHANGE_NAME
Change the name of this town.
Definition town_widget.h:42
@ WID_TV_CENTER_VIEW
Center the main view on this town.
Definition town_widget.h:40
@ WID_TV_DELETE
Delete this town (scenario editor only).
Definition town_widget.h:45
@ WID_TV_CAPTION
Caption of window.
Definition town_widget.h:37
@ WID_TF_LAYOUT_RANDOM
Selection for a randomly chosen town layout.
Definition town_widget.h:69
@ WID_TF_LOAD_FROM_FILE
Load town data from file.
Definition town_widget.h:54
@ WID_TF_SIZE_SEL
Container of town size buttons.
Definition town_widget.h:58
@ WID_TF_SIZE_LARGE
Selection for a large town.
Definition town_widget.h:61
@ WID_TF_NEW_TOWN
Create a new town.
Definition town_widget.h:50
@ WID_TF_EXPAND_ALL_TOWNS
Make all towns grow slightly.
Definition town_widget.h:55
@ WID_TF_MANY_RANDOM_TOWNS
Randomly place many towns.
Definition town_widget.h:53
@ WID_TF_SIZE_SMALL
Selection for a small town.
Definition town_widget.h:59
@ WID_TF_LAYOUT_GRID2
Selection for the 2x2 grid town layout.
Definition town_widget.h:67
@ WID_TF_LAYOUT_ORIGINAL
Selection for the original town layout.
Definition town_widget.h:65
@ WID_TF_SIZE_RANDOM
Selection for a randomly sized town.
Definition town_widget.h:62
@ WID_TF_TOWN_NAME_EDITBOX
Editor for the town name.
Definition town_widget.h:56
@ WID_TF_TOWN_ACTION_SEL
Container of town action buttons.
Definition town_widget.h:51
@ WID_TF_SIZE_MEDIUM
Selection for a medium town.
Definition town_widget.h:60
@ WID_TF_CITY
Selection for the town's city state.
Definition town_widget.h:63
@ WID_TF_RANDOM_TOWN
Randomly place a town.
Definition town_widget.h:52
@ WID_TF_LAYOUT_BETTER
Selection for the better town layout.
Definition town_widget.h:66
@ WID_TF_ROAD_LAYOUT_SEL
Container of town road layout buttons.
Definition town_widget.h:64
@ WID_TF_LAYOUT_GRID3
Selection for the 3x3 grid town layout.
Definition town_widget.h:68
@ WID_TF_TOWN_NAME_RANDOM
Generate a random town name.
Definition town_widget.h:57
@ WID_TD_LIST
List of towns.
Definition town_widget.h:19
@ WID_TD_CAPTION
Caption of the window.
Definition town_widget.h:15
@ WID_TD_FILTER
Filter of name.
Definition town_widget.h:18
@ WID_TD_SORT_ORDER
Direction of sort dropdown.
Definition town_widget.h:16
@ WID_TD_WORLD_POPULATION
The world's population.
Definition town_widget.h:21
@ WID_TD_SCROLLBAR
Scrollbar for the town list.
Definition town_widget.h:20
@ WID_TD_SORT_CRITERIA
Criteria of sort dropdown.
Definition town_widget.h:17
@ WID_BH_PROTECT_OFF
Button to protect the next house built.
Definition town_widget.h:75
@ WID_BH_PROTECT_ON
Button to not protect the next house built.
Definition town_widget.h:76
@ WID_BH_INFO
Information panel of selected house.
Definition town_widget.h:74
bool GenerateTownName(Randomizer &randomizer, uint32_t *townnameparts, TownNames *town_names)
Generates valid town name.
Definition townname.cpp:136
Town name generator stuff.
bool ScrollWindowToTile(TileIndex tile, Window *w, bool instant)
Scrolls the viewport in a window to a given location.
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
void SetViewportCatchmentTown(const Town *t, bool sel)
Select or deselect town for coverage area highlight.
const Town * _viewport_highlight_town
Currently selected town for coverage area highlight.
Functions related to (drawing on) viewports.
@ ZOOM_IN
Zoom in (get more detailed view).
@ ZOOM_OUT
Zoom out (get helicopter view).
static RectPadding ScaleGUITrad(const RectPadding &r)
Scale a RectPadding to GUI zoom level.
Definition widget.cpp:48
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_INSET
Pressed (inset) panel, most commonly used as combo box text area.
Definition widget_type.h:41
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ WWT_LABEL
Centered label.
Definition widget_type.h:47
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:61
@ 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_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_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ 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
@ NWID_VIEWPORT
Nested widget containing a viewport.
Definition widget_type.h:72
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:60
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:48
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:70
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ SZSP_VERTICAL
Display plane with zero size horizontally, and filling and resizing vertically.
@ EqualSize
Containers should keep all their (resizing) children equally large.
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition window.cpp:2025
void SetFocusedWindow(Window *w)
Set the window that has the focus.
Definition window.cpp:419
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition window.cpp:1226
Window functions not directly related to making/drawing windows.
@ Construction
This window is used for construction; close it whenever changing company.
@ DisableVpScroll
Window does not do autoscroll,.
@ SBS_DOWN
Sort ascending.
Definition window_gui.h:219
@ SBS_UP
Sort descending.
Definition window_gui.h:220
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:145
int WidgetID
Widget ID.
Definition window_type.h:20
EventState
State of handling an event.
@ ES_HANDLED
The passed event is handled.
@ ES_NOT_HANDLED
The passed event is not handled.
@ WC_TOWN_AUTHORITY
Town authority; Window numbers:
@ WC_FOUND_TOWN
Found a town; Window numbers:
@ WC_BUILD_HOUSE
Build house; Window numbers:
@ WC_BUILD_TOOLBAR
Build toolbar; Window numbers:
Definition window_type.h:75
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_TOWN_VIEW
Town view; Window numbers:
@ WC_TOWN_DIRECTORY
Town directory; Window numbers:
Functions related to zooming.
ZoomLevel ScaleZoomGUI(ZoomLevel value)
Scale zoom level relative to GUI zoom.
Definition zoom_func.h:87
int UnScaleGUI(int value)
Short-hand to apply GUI zoom level.
Definition zoom_func.h:77
@ ZOOM_LVL_TOWN
Default zoom level for the town view.
Definition zoom_type.h:31