OpenTTD Source 20260820-master-g39da062c0c
fios_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
12#include "error.h"
13#include "gui.h"
14#include "gfx_func.h"
15#include "command_func.h"
16#include "network/network.h"
18#include "strings_func.h"
19#include "string_func.h"
20#include "fileio_func.h"
21#include "fios.h"
22#include "window_func.h"
23#include "tilehighlight_func.h"
24#include "querystring_gui.h"
25#include "engine_func.h"
26#include "landscape_type.h"
27#include "genworld.h"
30#include "gamelog.h"
31#include "stringfilter_type.h"
32#include "misc_cmd.h"
33#include "gamelog_internal.h"
34
35#include "widgets/fios_widget.h"
36
37#include "table/sprites.h"
38#include "table/strings.h"
39
40#include "safeguards.h"
41
43
44static bool _fios_path_changed;
45static bool _savegame_sort_dirty;
46
48enum class SavegameSorter : uint8_t {
51};
52
54static bool _savegame_sorter_ascending = false;
55
57bool FiosItemSorter(const FiosItem &a, const FiosItem &b)
58{
59 switch (_savegame_sorter) {
64 default:
65 NOT_REACHED();
66 }
67}
68
73{
74 this->checkable = false;
76 this->error_msg.clear();
77
78 this->map_size_x = this->map_size_y = 256; // Default for old savegames which do not store mapsize.
79 this->current_date = CalendarTime::MIN_DATE;
80 this->landscape = {};
81 this->starting_year = {};
82
83 companies.clear();
84
85 this->gamelog.Reset();
86
88}
89
91static constexpr std::initializer_list<NWidgetPart> _nested_load_dialog_widgets = {
97 /* Current directory and free space */
100
102 /* Left side : filter box and available files */
104 /* Filter box with label */
107 SetPIP(WidgetDimensions::unscaled.frametext.left, WidgetDimensions::unscaled.frametext.right, 0),
108 NWidget(WWT_TEXT, Colours::Invalid), SetFill(0, 1), SetStringTip(STR_SAVELOAD_FILTER_TITLE),
110 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
111 EndContainer(),
112 EndContainer(),
113 /* Sort buttons */
116 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYNAME), SetStringTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
117 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYDATE), SetStringTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
118 EndContainer(),
119 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SL_HOME_BUTTON), SetAspect(1), SetSpriteTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON_TOOLTIP),
120 EndContainer(),
121 /* Files */
125 SetToolTip(STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR),
126 EndContainer(),
127 EndContainer(),
129 EndContainer(),
130 /* Online Content button */
133 SetStringTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
134 EndContainer(),
135 EndContainer(),
136
137 /* Right side : game details */
140 EndContainer(),
141 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_MISSING_NEWGRFS), SetStringTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
144 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_NEWGRF_INFO), SetStringTip(STR_MAPGEN_NEWGRF_SETTINGS, STR_MAPGEN_NEWGRF_SETTINGS_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
145 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_LOAD_BUTTON), SetStringTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
146 EndContainer(),
148 EndContainer(),
149 EndContainer(),
150 EndContainer(),
151};
152
154static constexpr std::initializer_list<NWidgetPart> _nested_load_heightmap_dialog_widgets = {
159 EndContainer(),
160 /* Current directory and free space */
162 EndContainer(),
163
164 /* Filter box with label */
167 SetPIP(WidgetDimensions::unscaled.frametext.left, WidgetDimensions::unscaled.frametext.right, 0),
168 NWidget(WWT_TEXT, Colours::Invalid), SetFill(0, 1), SetStringTip(STR_SAVELOAD_FILTER_TITLE),
170 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
171 EndContainer(),
172 EndContainer(),
173 /* Sort Buttons */
176 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYNAME), SetStringTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
177 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYDATE), SetStringTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
178 EndContainer(),
179 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SL_HOME_BUTTON), SetAspect(1), SetSpriteTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON_TOOLTIP),
180 EndContainer(),
181 /* Files */
185 SetToolTip(STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR),
186 EndContainer(),
187 EndContainer(),
189 EndContainer(),
190 /* Online Content and Load button */
193 SetStringTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
195 SetStringTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP),
197 EndContainer(),
198};
199
201static constexpr std::initializer_list<NWidgetPart> _nested_load_town_data_dialog_widgets = {
206 EndContainer(),
207 /* Current directory and free space */
209
210 /* Filter box with label */
213 SetPIP(WidgetDimensions::unscaled.frametext.left, WidgetDimensions::unscaled.frametext.right, 0),
214 NWidget(WWT_TEXT, Colours::Invalid), SetFill(0, 1), SetStringTip(STR_SAVELOAD_FILTER_TITLE),
215 NWidget(WWT_EDITBOX, Colours::Grey, WID_SL_FILTER), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
216 EndContainer(),
217 EndContainer(),
218 /* Sort Buttons */
221 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYNAME), SetStringTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
222 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYDATE), SetStringTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
223 EndContainer(),
224 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SL_HOME_BUTTON), SetAspect(1), SetSpriteTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON_TOOLTIP),
225 EndContainer(),
226 /* Files */
230 SetToolTip(STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(),
231 EndContainer(),
233 EndContainer(),
234 /* Load button */
237 SetStringTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_TOWN_DATA_TOOLTIP),
239 EndContainer(),
240};
241
243static constexpr std::initializer_list<NWidgetPart> _nested_save_dialog_widgets = {
248 EndContainer(),
249 /* Current directory and free space */
251 EndContainer(),
252
254 /* Left side : filter box and available files */
256 /* Filter box with label */
259 SetPIP(WidgetDimensions::unscaled.frametext.left, WidgetDimensions::unscaled.frametext.right, 0),
260 NWidget(WWT_TEXT, Colours::Invalid), SetFill(0, 1), SetStringTip(STR_SAVELOAD_FILTER_TITLE),
262 SetStringTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
263 EndContainer(),
264 EndContainer(),
265 /* Sort buttons */
268 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYNAME), SetStringTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
269 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SORT_BYDATE), SetStringTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
270 EndContainer(),
271 NWidget(WWT_PUSHIMGBTN, Colours::Grey, WID_SL_HOME_BUTTON), SetAspect(1), SetSpriteTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON_TOOLTIP),
272 EndContainer(),
273 /* Files */
277 SetToolTip(STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR),
278 EndContainer(),
279 EndContainer(),
281 EndContainer(),
284 SetStringTip(STR_SAVELOAD_OSKTITLE, STR_SAVELOAD_EDITBOX_TOOLTIP),
285 EndContainer(),
286 /* New directory/delete/save buttons */
288 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_NEW_DIRECTORY), SetStringTip(STR_SAVELOAD_NEW_DIRECTORY_BUTTON, STR_SAVELOAD_NEW_DIRECTORY_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
289 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_DELETE_SELECTION), SetStringTip(STR_SAVELOAD_DELETE_BUTTON, STR_SAVELOAD_DELETE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
290 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SL_SAVE_GAME), SetStringTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
291 EndContainer(),
292 EndContainer(),
293
294 /* Right side : game details */
297 EndContainer(),
300 EndContainer(),
302 EndContainer(),
303 EndContainer(),
304 EndContainer(),
305};
306
309 TextColour::LightBrown, // DetailedFileType::OldGameFile
310 TextColour::Orange, // DetailedFileType::GameFile
311 TextColour::Yellow, // DetailedFileType::HeightmapBmp
312 TextColour::Orange, // DetailedFileType::HeightmapPng
313 TextColour::LightBrown, // DetailedFileType::TownDataJson
314 TextColour::LightBlue, // DetailedFileType::FiosDrive
315 TextColour::DarkGreen, // DetailedFileType::FiosParent
316 TextColour::DarkGreen, // DetailedFileType::FiosDirectory
317 TextColour::Orange, // DetailedFileType::FiosDirect
318};
319
324static void SortSaveGameList(FileList &file_list)
325{
326 size_t sort_start = 0;
327 size_t sort_end = 0;
328
329 /* Directories are always above the files (FIOS_TYPE_DIR)
330 * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
331 * Only sort savegames/scenarios, not directories
332 */
333 for (const auto &item : file_list) {
334 switch (item.type.detailed) {
335 case DetailedFileType::FiosDirectory: sort_start++; break;
336 case DetailedFileType::FiosParent: sort_start++; break;
337 case DetailedFileType::FiosDrive: sort_end++; break;
338 default: break;
339 }
340 }
341
342 std::sort(file_list.begin() + sort_start, file_list.end() - sort_end, FiosItemSorter);
343}
344
345struct SaveLoadWindow : public Window {
346private:
347 static const uint EDITBOX_MAX_SIZE = 50;
348 static const uint MAX_DIRECTORY_NAME_CHARS = 64;
349
355 const FiosItem *selected = nullptr;
356 const FiosItem *highlighted = nullptr;
357 Scrollbar *vscroll = nullptr;
358
361 std::vector<FiosItem *> display_list{};
362
363 static void SaveGameConfirmationCallback(Window *, bool confirmed)
364 {
365 /* File name has already been written to _file_to_saveload */
366 if (confirmed) _switch_mode = SwitchMode::SaveGame;
367 }
368
369 static void SaveHeightmapConfirmationCallback(Window *, bool confirmed)
370 {
371 /* File name has already been written to _file_to_saveload */
373 }
374
375 static void DeleteFileConfirmationCallback(Window *window, bool confirmed)
376 {
377 auto *save_load_window = static_cast<SaveLoadWindow*>(window);
378
379 assert(save_load_window->selected != nullptr);
380
381 if (confirmed) {
382 if (!FioRemove(save_load_window->selected->name)) {
383 ShowErrorMessage(GetEncodedString(STR_ERROR_UNABLE_TO_DELETE_FILE), {}, WarningLevel::Error);
384 } else {
385 save_load_window->InvalidateData(SLIWD_RESCAN_FILES);
386 /* Reset file name to current date on successful delete */
387 if (save_load_window->abstract_filetype == AbstractFileType::Savegame) save_load_window->GenerateFileName();
388 }
389 }
390 }
391
398 static std::optional<StringID> GetDirectoryNameError(const std::string &name)
399 {
400 assert(!name.empty());
401
402 /* Reject path and drive separators, which would turn the name into a path. */
403 if (name.find_first_of("/\\:") != std::string::npos) return STR_ERROR_DIRECTORY_ILLEGAL_NAME;
404 /* Reject a leading dot. This covers the current and parent directory entries and hidden names the list would never show. */
405 if (name.front() == '.') return STR_ERROR_DIRECTORY_LEADING_DOT;
406
407 return std::nullopt;
408 }
409
414 void ShowNewDirectoryQuery(std::string_view initial_name = {})
415 {
416 /* An unchanged name would otherwise be treated as cancel, so the AcceptUnchanged flag lets the pre-filled name be resubmitted to try again. */
418 initial_name,
419 STR_SAVELOAD_NEW_DIRECTORY_QUERY_CAPTION,
421 this,
424 }
425
432 void HandleNewDirectoryRequest(const std::string &query_text)
433 {
434 /* CS_ALPHANUMERAL allows spaces, so trim them before validating. */
435 const std::string name{StrTrimView(query_text, " ")};
436
437 /* An empty name is treated as a cancel, the same as other query dialogs. */
438 if (name.empty()) return;
439
440 if (auto error = GetDirectoryNameError(name); error.has_value()) {
441 this->ShowNewDirectoryQuery(name);
442 ShowErrorMessage(GetEncodedString(STR_ERROR_CANNOT_CREATE_DIRECTORY), GetEncodedString(*error), WarningLevel::Error);
443 return;
444 }
445
446 switch (FiosCreateDirectory(name)) {
449 break;
451 this->ShowNewDirectoryQuery(name);
452 ShowErrorMessage(GetEncodedString(STR_ERROR_CANNOT_CREATE_DIRECTORY), GetEncodedString(STR_ERROR_DIRECTORY_NAME_IN_USE), WarningLevel::Error);
453 break;
455 ShowErrorMessage(GetEncodedString(STR_ERROR_CANNOT_CREATE_DIRECTORY), GetEncodedString(STR_ERROR_DIRECTORY_PERMISSION_DENIED), WarningLevel::Error);
456 break;
458 ShowErrorMessage(GetEncodedString(STR_ERROR_CANNOT_CREATE_DIRECTORY), {}, WarningLevel::Error);
459 break;
460 }
461 }
462
463public:
464
467 {
468 this->filename_editbox.text.Assign(GenerateDefaultSaveName());
469 }
470
473 {
474 assert(this->fop == SaveLoadOperation::Save || this->fop == SaveLoadOperation::Load);
475
476 /* For saving, construct an initial file name. */
477 if (this->fop == SaveLoadOperation::Save) {
478 switch (this->abstract_filetype) {
480 this->GenerateFileName();
481 break;
482
485 this->filename_editbox.text.Assign("UNNAMED");
486 break;
487
488 default:
489 /* It's not currently possible to save town data. */
490 NOT_REACHED();
491 }
492 }
494 this->filename_editbox.ok_button = WID_SL_SAVE_GAME;
495
496 this->CreateNestedTree();
499 }
500
501 /* Select caption string of the window. */
502 StringID caption_string;
503 switch (this->abstract_filetype) {
505 caption_string = (this->fop == SaveLoadOperation::Save) ? STR_SAVELOAD_SAVE_CAPTION : STR_SAVELOAD_LOAD_CAPTION;
506 break;
507
509 caption_string = (this->fop == SaveLoadOperation::Save) ? STR_SAVELOAD_SAVE_SCENARIO : STR_SAVELOAD_LOAD_SCENARIO;
510 break;
511
513 caption_string = (this->fop == SaveLoadOperation::Save) ? STR_SAVELOAD_SAVE_HEIGHTMAP : STR_SAVELOAD_LOAD_HEIGHTMAP;
514 break;
515
517 caption_string = STR_SAVELOAD_LOAD_TOWN_DATA; // It's not currently possible to save town data.
518 break;
519
520 default:
521 NOT_REACHED();
522 }
523 this->GetWidget<NWidgetCore>(WID_SL_CAPTION)->SetString(caption_string);
524
525 this->vscroll = this->GetScrollbar(WID_SL_SCROLLBAR);
526 this->FinishInitNested(0);
527
530 this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
531
532 /* pause is only used in single-player, non-editor mode, non-menu mode. It
533 * will be unpaused in the WE_DESTROY event handler. */
534 if (_game_mode != GameMode::Menu && !_networking && _game_mode != GameMode::Editor) {
535 Command<Commands::Pause>::Post(PauseMode::SaveLoad, true);
536 }
537 SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WindowClass::MainWindow, 0);
538
540
542
543 /* Select the initial directory. */
544 o_dir.type = FIOS_TYPE_DIRECT;
545 switch (this->abstract_filetype) {
547 o_dir.name = FioFindDirectory(Subdirectory::Save);
548 break;
549
551 o_dir.name = FioFindDirectory(Subdirectory::Scenario);
552 break;
553
556 o_dir.name = FioFindDirectory(Subdirectory::Heightmap);
557 break;
558
559 default:
560 o_dir.name = _personal_dir;
561 }
562
563 switch (this->fop) {
565 /* Focus the edit box by default in the save window */
567 break;
568
569 default:
571 }
572 }
573
574 void Close([[maybe_unused]] int data = 0) override
575 {
576 /* pause is only used in single-player, non-editor mode, non menu mode */
577 if (!_networking && _game_mode != GameMode::Editor && _game_mode != GameMode::Menu) {
578 Command<Commands::Pause>::Post(PauseMode::SaveLoad, false);
579 }
580 this->Window::Close();
581 }
582
583 void DrawWidget(const Rect &r, WidgetID widget) const override
584 {
585 switch (widget) {
590 }
591 break;
592
593 case WID_SL_BACKGROUND: {
594 static std::string path;
595 static std::optional<uint64_t> free_space = std::nullopt;
596
597 if (_fios_path_changed) {
598 path = FiosGetCurrentPath();
599 free_space = FiosGetDiskFreeSpace(path);
600 _fios_path_changed = false;
601 }
602
603 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
604
605 if (free_space.has_value()) {
606 DrawString(ir.left, ir.right, ir.top + GetCharacterHeight(FontSize::Normal), GetString(STR_SAVELOAD_BYTES_FREE, free_space.value()));
607 } else {
608 DrawString(ir.left, ir.right, ir.top + GetCharacterHeight(FontSize::Normal), STR_ERROR_UNABLE_TO_READ_DRIVE);
609 }
610 DrawString(ir.left, ir.right, ir.top, path, TextColour::Black);
611 break;
612 }
613
615 const Rect br = r.Shrink(WidgetDimensions::scaled.bevel);
617
618 Rect tr = r.Shrink(WidgetDimensions::scaled.inset).WithHeight(this->resize.step_height);
619 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->display_list);
620 for (auto it = first; it != last; ++it) {
621 const FiosItem *item = *it;
622
623 if (item == this->selected) {
625 } else if (item == this->highlighted) {
627 }
628 DrawString(tr, item->title.GetDecodedString(), _fios_colours[item->type.detailed]);
629 tr = tr.Translate(0, this->resize.step_height);
630 }
631 break;
632 }
633
634 case WID_SL_DETAILS:
635 this->DrawDetails(r);
636 break;
637 }
638 }
639
640 void DrawDetails(const Rect &r) const
641 {
642 /* Header panel */
643 int HEADER_HEIGHT = GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.frametext.Vertical();
644
645 Rect hr = r.WithHeight(HEADER_HEIGHT).Shrink(WidgetDimensions::scaled.frametext);
646 Rect tr = r.Shrink(WidgetDimensions::scaled.frametext);
647 tr.top += HEADER_HEIGHT;
648
649 /* Create the nice lighter rectangle at the details top */
651 DrawString(hr.left, hr.right, hr.top, STR_SAVELOAD_DETAIL_CAPTION, TextColour::FromString, AlignmentH::Centre);
652
653 if (this->selected == nullptr) return;
654
655 /* Details panel */
656 tr.bottom -= GetCharacterHeight(FontSize::Normal) - 1;
657 if (tr.top > tr.bottom) return;
658
659 if (!_load_check_data.checkable) {
660 /* Old savegame, no information available */
661 DrawString(tr, STR_SAVELOAD_DETAIL_NOT_AVAILABLE);
664 /* Incompatible / broken savegame */
666 } else {
667 /* Mapsize */
668 DrawString(tr, GetString(STR_NETWORK_SERVER_LIST_MAP_SIZE, _load_check_data.map_size_x, _load_check_data.map_size_y));
670 if (tr.top > tr.bottom) return;
671
672 /* Climate */
673 if (to_underlying(_load_check_data.landscape) < NUM_LANDSCAPE) {
674 DrawString(tr, GetString(STR_NETWORK_SERVER_LIST_LANDSCAPE, STR_CLIMATE_TEMPERATE_LANDSCAPE + to_underlying(_load_check_data.landscape)));
676 }
677
679 if (tr.top > tr.bottom) return;
680
681 /* Start date (if available) */
683 DrawString(tr, GetString(STR_NETWORK_SERVER_LIST_START_DATE, TimerGameCalendar::ConvertYMDToDate(_load_check_data.starting_year, 0, 1)));
685 }
686 if (tr.top > tr.bottom) return;
687
688 /* Hide current date for scenarios */
690 /* Current date */
691 DrawString(tr, GetString(STR_NETWORK_SERVER_LIST_CURRENT_DATE, _load_check_data.current_date));
693 }
694
695 /* Hide the NewGRF stuff when saving. We also hide the button. */
698 if (tr.top > tr.bottom) return;
699
700 /* NewGrf compatibility */
701 DrawString(tr, GetString(STR_SAVELOAD_DETAIL_GRFSTATUS, _load_check_data.grfconfig.empty() ? STR_NEWGRF_LIST_NONE : STR_NEWGRF_LIST_ALL_FOUND + to_underlying(_load_check_data.grf_compatibility)));
703 }
704 if (tr.top > tr.bottom) return;
705
706 /* Hide the company stuff for scenarios */
709 if (tr.top > tr.bottom) return;
710
711 /* Companies / AIs */
712 for (auto &pair : _load_check_data.companies) {
713 const CompanyProperties &c = *pair.second;
714 if (c.name.empty()) {
715 AutoRestoreBackup landscape_backup(_settings_game.game_creation.landscape, _load_check_data.landscape);
716 DrawString(tr, GetString(STR_SAVELOAD_DETAIL_COMPANY_INDEX, pair.first + 1, c.name_1, c.name_2));
717 } else {
718 DrawString(tr, GetString(STR_SAVELOAD_DETAIL_COMPANY_INDEX, pair.first + 1, STR_JUST_RAW_STRING, c.name));
719 }
720
722 if (tr.top > tr.bottom) break;
723 }
724 }
725 }
726 }
727
728 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
729 {
730 switch (widget) {
732 size.height = 2 * GetCharacterHeight(FontSize::Normal) + padding.height;
733 break;
734
736 fill.height = resize.height = GetCharacterHeight(FontSize::Normal);
737 size.height = resize.height * 10 + padding.height;
738 break;
740 case WID_SL_SORT_BYDATE: {
742 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
743 d.height += padding.height;
744 size = maxdim(size, d);
745 break;
746 }
747 }
748 }
749
750 void OnPaint() override
751 {
752 if (_savegame_sort_dirty) {
753 _savegame_sort_dirty = false;
754 SortSaveGameList(this->fios_items);
756 }
757
758 this->DrawWidgets();
759 }
760
761 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
762 {
763 switch (widget) {
764 case WID_SL_SORT_BYNAME: // Sort save games by name
767 _savegame_sort_dirty = true;
768 this->SetDirty();
769 break;
770
771 case WID_SL_SORT_BYDATE: // Sort save games by date
774 _savegame_sort_dirty = true;
775 this->SetDirty();
776 break;
777
778 case WID_SL_HOME_BUTTON: // OpenTTD 'button', jumps to OpenTTD directory
781 break;
782
783 case WID_SL_LOAD_BUTTON: {
784 if (this->selected == nullptr || _load_check_data.HasErrors()) break;
785
786 _file_to_saveload.Set(*this->selected);
787
788 if (this->abstract_filetype == AbstractFileType::Heightmap) {
789 this->Close();
791 } else if (this->abstract_filetype == AbstractFileType::TownData) {
792 this->Close();
793 LoadTownData();
794 } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GRFListCompatibility::NotFound || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) {
797 this->Close();
798 }
799 break;
800 }
801
803 if (_load_check_data.HasNewGrfs()) {
804 ShowNewGRFSettings(false, false, false, _load_check_data.grfconfig);
805 }
806 break;
807
809 if (!_network_available) {
810 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WarningLevel::Error);
811 } else if (_load_check_data.HasNewGrfs()) {
813 }
814 break;
815
816 case WID_SL_DRIVES_DIRECTORIES_LIST: { // Click the listbox
817 auto it = this->vscroll->GetScrolledItemFromWidget(this->display_list, pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WidgetDimensions::scaled.inset.top);
818 if (it == this->display_list.end()) return;
819
820 /* Get the corresponding non-filtered out item from the list */
821 const FiosItem *file = *it;
822
823 if (FiosBrowseTo(file)) {
824 /* Changed directory, need refresh. */
826 break;
827 }
828
829 if (click_count == 1) {
830 if (this->selected != file) {
831 this->selected = file;
832 _load_check_data.Clear();
833
834 if (file->type.detailed == DetailedFileType::GameFile) {
835 /* Other detailed file types cannot be checked before. */
837 }
838
840 }
841 if (this->fop == SaveLoadOperation::Save) {
842 /* Copy clicked name to editbox */
843 this->filename_editbox.text.Assign(file->title.GetDecodedString());
845 }
846 } else if (!_load_check_data.HasErrors()) {
847 this->selected = file;
848 if (this->fop == SaveLoadOperation::Load) {
849 if (this->abstract_filetype == AbstractFileType::Savegame || this->abstract_filetype == AbstractFileType::Scenario || this->abstract_filetype == AbstractFileType::TownData) {
850 this->OnClick(pt, WID_SL_LOAD_BUTTON, 1);
851 } else {
852 assert(this->abstract_filetype == AbstractFileType::Heightmap);
853 _file_to_saveload.Set(*file);
854
855 this->Close();
857 }
858 }
859 }
860 break;
861 }
862
864 if (!_network_available) {
865 ShowErrorMessage(GetEncodedString(STR_NETWORK_ERROR_NOTAVAILABLE), {}, WarningLevel::Error);
866 } else {
867 assert(this->fop == SaveLoadOperation::Load);
868 switch (this->abstract_filetype) {
869 default: NOT_REACHED();
872 }
873 }
874 break;
875
876 case WID_SL_DELETE_SELECTION: // Delete
877 break;
878
879 case WID_SL_SAVE_GAME: // Save game
880 /* Note, this is also called via the OSK; and we need to lower the button. */
882 break;
883
884 case WID_SL_NEW_DIRECTORY: // Create directory
885 this->ShowNewDirectoryQuery();
886 break;
887 }
888 }
889
890 void OnMouseOver([[maybe_unused]] Point pt, WidgetID widget) override
891 {
892 if (widget == WID_SL_DRIVES_DIRECTORIES_LIST) {
893 auto it = this->vscroll->GetScrolledItemFromWidget(this->display_list, pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WidgetDimensions::scaled.inset.top);
894 if (it == this->display_list.end()) return;
895
896 /* Get the corresponding non-filtered out item from the list */
897 const FiosItem *file = *it;
898
899 if (file != this->highlighted) {
900 this->highlighted = file;
902 }
903 } else if (this->highlighted != nullptr) {
904 this->highlighted = nullptr;
906 }
907 }
908
909 EventState OnKeyPress([[maybe_unused]] char32_t key, uint16_t keycode) override
910 {
911 if (keycode == WKC_ESC) {
912 this->Close();
913 return EventState::Handled;
914 }
915
917 }
918
919 void OnTimeout() override
920 {
921 /* Widgets WID_SL_DELETE_SELECTION and WID_SL_SAVE_GAME only exist when saving to a file. */
922 if (this->fop != SaveLoadOperation::Save) return;
923
924 if (this->IsWidgetLowered(WID_SL_DELETE_SELECTION)) { // Delete button clicked
925 ShowQuery(GetEncodedString(STR_SAVELOAD_DELETE_TITLE), GetEncodedString(STR_SAVELOAD_DELETE_WARNING),
926 this, SaveLoadWindow::DeleteFileConfirmationCallback);
927 } else if (this->IsWidgetLowered(WID_SL_SAVE_GAME)) { // Save button clicked
928 if (this->abstract_filetype == AbstractFileType::Savegame || this->abstract_filetype == AbstractFileType::Scenario) {
929 _file_to_saveload.name = FiosMakeSavegameName(this->filename_editbox.text.GetText());
931 ShowQuery(GetEncodedString(STR_SAVELOAD_OVERWRITE_TITLE), GetEncodedString(STR_SAVELOAD_OVERWRITE_WARNING),
932 this, SaveLoadWindow::SaveGameConfirmationCallback);
933 } else {
935 }
936 } else {
937 _file_to_saveload.name = FiosMakeHeightmapName(this->filename_editbox.text.GetText());
939 ShowQuery(GetEncodedString(STR_SAVELOAD_OVERWRITE_TITLE), GetEncodedString(STR_SAVELOAD_OVERWRITE_WARNING),
940 this, SaveLoadWindow::SaveHeightmapConfirmationCallback);
941 } else {
943 }
944 }
945
946 /* In the editor set up the vehicle engines correctly (date might have changed) */
947 if (_game_mode == GameMode::Editor) StartupEngines();
948 }
949 }
950
951 void OnResize() override
952 {
954 }
955
956 void BuildDisplayList()
957 {
958 /* Filter changes */
959 this->display_list.clear();
960 this->display_list.reserve(this->fios_items.size());
961
962 if (this->string_filter.IsEmpty()) {
963 /* We don't filter anything out if the filter editbox is empty */
964 for (auto &it : this->fios_items) {
965 this->display_list.push_back(&it);
966 }
967 } else {
968 for (auto &it : this->fios_items) {
969 this->string_filter.ResetState();
970 this->string_filter.AddLine(it.title.GetDecodedString());
971 /* We set the vector to show this fios element as filtered depending on the result of the filter */
972 if (this->string_filter.GetState()) {
973 this->display_list.push_back(&it);
974 } else if (&it == this->selected) {
975 /* The selected element has been filtered out */
976 this->selected = nullptr;
978 }
979 }
980 }
981
982 this->vscroll->SetCount(this->display_list.size());
983 }
984
990 void OnInvalidateData(int data = 0, bool gui_scope = true) override
991 {
992 switch (data) {
994 /* Rescan files */
995 this->selected = nullptr;
996 _load_check_data.Clear();
997 if (!gui_scope) break;
998
999 _fios_path_changed = true;
1000 this->fios_items.BuildFileList(this->abstract_filetype, this->fop, true);
1001 this->selected = nullptr;
1002 _load_check_data.Clear();
1003
1004 /* We reset the files filtered */
1006
1007 [[fallthrough]];
1008
1010 /* Selection changes */
1011 if (!gui_scope) break;
1012
1013 if (this->fop == SaveLoadOperation::Save) this->SetWidgetDisabledState(WID_SL_DELETE_SELECTION, this->selected == nullptr);
1014
1015 if (this->fop != SaveLoadOperation::Load) break;
1016
1017 switch (this->abstract_filetype) {
1020 this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == nullptr || _load_check_data.HasErrors());
1021 break;
1022
1025 bool disabled = this->selected == nullptr || _load_check_data.HasErrors();
1026 if (!_settings_client.gui.UserIsAllowedToChangeNewGRFs()) {
1027 disabled |= _load_check_data.HasNewGrfs() && _load_check_data.grf_compatibility == GRFListCompatibility::NotFound;
1028 }
1032 !_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility == GRFListCompatibility::AllGood);
1033 break;
1034 }
1035
1036 default:
1037 NOT_REACHED();
1038 }
1039 break;
1040
1042 this->BuildDisplayList();
1043 break;
1044 }
1045 }
1046
1047 void OnEditboxChanged(WidgetID wid) override
1048 {
1049 if (wid == WID_SL_FILTER) {
1050 this->string_filter.SetFilterTerm(this->filter_editbox.text.GetText());
1052 }
1053
1054 if (wid == WID_SL_SAVE_OSK_TITLE) {
1055 this->selected = nullptr;
1057 }
1058 }
1059
1060 void OnQueryTextFinished(std::optional<std::string> str) override
1061 {
1062 if (str.has_value()) this->HandleNewDirectoryRequest(*str);
1063 }
1064};
1065
1068 WindowPosition::Center, "load_game", 500, 294,
1069 WindowClass::SaveLoad, WindowClass::None,
1070 {},
1072);
1073
1076 WindowPosition::Center, "load_heightmap", 257, 320,
1077 WindowClass::SaveLoad, WindowClass::None,
1078 {},
1080);
1081
1084 WindowPosition::Center, "load_town_data", 257, 320,
1085 WindowClass::SaveLoad, WindowClass::None,
1086 {},
1088);
1089
1092 WindowPosition::Center, "save_game", 500, 294,
1093 WindowClass::SaveLoad, WindowClass::None,
1094 {},
1096);
1097
1104{
1105 CloseWindowById(WindowClass::SaveLoad, 0);
1106
1107 if (fop == SaveLoadOperation::Save) {
1108 new SaveLoadWindow(_save_dialog_desc, abstract_filetype, fop);
1109 } else {
1110 /* Dialogue for loading a file. */
1111 switch (abstract_filetype) {
1113 new SaveLoadWindow(_load_heightmap_dialog_desc, abstract_filetype, fop);
1114 break;
1115
1117 new SaveLoadWindow(_load_town_data_dialog_desc, abstract_filetype, fop);
1118 break;
1119
1120 default:
1121 new SaveLoadWindow(_load_dialog_desc, abstract_filetype, fop);
1122 }
1123 }
1124}
std::string GetDecodedString() const
Decode the encoded string.
Definition strings.cpp:207
List of file information.
Definition fios.h:94
Scrollbar data structure.
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:2548
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
static Date ConvertYMDToDate(Year year, Month month, Day day)
Converts a tuple of Year, Month and Day to a Date.
static constexpr TimerGame< struct Calendar >::Date MIN_DATE
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
int vsep_normal
Normal vertical spacing.
Definition window_gui.h:60
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:95
Functions related to commands.
void StartupEngines()
Start/initialise all our engines.
Definition engine.cpp:836
Functions related to engines.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
Functions related to errors.
void ClearErrorMessages()
Clear all errors from the queue.
@ Error
Errors (eg. saving/loading failed).
Definition error.h:26
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
bool FioRemove(const std::string &filename)
Remove a file.
Definition fileio.cpp:334
std::string _personal_dir
custom directory for personal settings, saves, newgrf, etc.
Definition fileio.cpp:924
bool FioCheckFileExists(std::string_view filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:123
Functions for standard in/out file operations.
SaveLoadOperation
Operation performed on the file.
Definition fileio_type.h:52
@ Check
Load file for checking and/or preview.
Definition fileio_type.h:53
@ Save
File is being saved.
Definition fileio_type.h:55
@ Load
File is being loaded.
Definition fileio_type.h:54
@ FiosDrive
A drive (letter) entry.
Definition fileio_type.h:41
@ GameFile
Save game or scenario file.
Definition fileio_type.h:31
@ FiosDirectory
A directory entry.
Definition fileio_type.h:43
@ FiosParent
A parent directory entry.
Definition fileio_type.h:42
@ Scenario
Base directory for all scenarios.
Definition fileio_type.h:92
@ Heightmap
Subdirectory of scenario for heightmaps.
Definition fileio_type.h:93
@ None
A path without any base directory.
@ Save
Base directory for all savegames.
Definition fileio_type.h:90
AbstractFileType
The different abstract types of files that the system knows about.
Definition fileio_type.h:17
@ Savegame
old or new savegame
Definition fileio_type.h:19
@ Scenario
old or new scenario
Definition fileio_type.h:20
@ Heightmap
heightmap file
Definition fileio_type.h:21
@ TownData
town data file
Definition fileio_type.h:22
bool FiosItemModificationDateSorter(const FiosItem &a, const FiosItem &b)
Sort files by their modification date, and name when they are equal.
Definition fios.cpp:45
std::string FiosMakeSavegameName(std::string_view name)
Make a save game or scenario filename from a name.
Definition fios.cpp:239
bool FiosItemNameSorter(const FiosItem &a, const FiosItem &b)
Sort files by their name.
Definition fios.cpp:39
std::string FiosGetCurrentPath()
Get the current path/working directory.
Definition fios.cpp:123
std::string FiosMakeHeightmapName(std::string_view name)
Construct a filename for a height map.
Definition fios.cpp:251
DirectoryCreateResult FiosCreateDirectory(std::string_view name)
Create a new subdirectory inside the current FIOS path.
Definition fios.cpp:134
bool FiosBrowseTo(const FiosItem *item)
Browse to a new path based on the passed item, starting at _fios_path.
Definition fios.cpp:165
Declarations for savegames operations.
bool FiosItemSorter(const FiosItem &a, const FiosItem &b)
Sorts the FiosItems based on the savegame sorter and order.
Definition fios_gui.cpp:57
@ PermissionDenied
The OS rejected the operation for permission reasons.
Definition fios.h:32
@ Success
Directory was created.
Definition fios.h:30
@ OtherError
Any other filesystem error.
Definition fios.h:33
@ AlreadyExists
A file or directory with that name already exists.
Definition fios.h:31
@ SLIWD_FILTER_CHANGES
The filename filter has changed (via the editbox).
Definition fios.h:25
@ SLIWD_SELECTION_CHANGES
File selection has changed (user click, ...).
Definition fios.h:24
@ SLIWD_RESCAN_FILES
Rescan all files (when changed directory, ...).
Definition fios.h:23
LoadCheckData _load_check_data
Data loaded from save during SL_LOAD_CHECK.
Definition fios_gui.cpp:42
static WindowDesc _save_dialog_desc(WindowPosition::Center, "save_game", 500, 294, WindowClass::SaveLoad, WindowClass::None, {}, _nested_save_dialog_widgets)
Save game/scenario.
bool FiosItemSorter(const FiosItem &a, const FiosItem &b)
Sorts the FiosItems based on the savegame sorter and order.
Definition fios_gui.cpp:57
static SavegameSorter _savegame_sorter
Sorter for savegames.
Definition fios_gui.cpp:53
static bool _savegame_sorter_ascending
Sorter for savegames.
Definition fios_gui.cpp:54
void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Launch save/load dialog in the given mode.
static constexpr std::initializer_list< NWidgetPart > _nested_save_dialog_widgets
Save game/scenario.
Definition fios_gui.cpp:243
static constexpr std::initializer_list< NWidgetPart > _nested_load_heightmap_dialog_widgets
Load heightmap with content download.
Definition fios_gui.cpp:154
static WindowDesc _load_town_data_dialog_desc(WindowPosition::Center, "load_town_data", 257, 320, WindowClass::SaveLoad, WindowClass::None, {}, _nested_load_town_data_dialog_widgets)
Load town data.
static WindowDesc _load_dialog_desc(WindowPosition::Center, "load_game", 500, 294, WindowClass::SaveLoad, WindowClass::None, {}, _nested_load_dialog_widgets)
Load game/scenario.
static constexpr std::initializer_list< NWidgetPart > _nested_load_dialog_widgets
Load game/scenario with optional content download.
Definition fios_gui.cpp:91
static WindowDesc _load_heightmap_dialog_desc(WindowPosition::Center, "load_heightmap", 257, 320, WindowClass::SaveLoad, WindowClass::None, {}, _nested_load_heightmap_dialog_widgets)
Load heightmap.
static constexpr std::initializer_list< NWidgetPart > _nested_load_town_data_dialog_widgets
Load town data.
Definition fios_gui.cpp:201
LoadCheckData _load_check_data
Data loaded from save during SL_LOAD_CHECK.
Definition fios_gui.cpp:42
SavegameSorter
The available sorters for FiosItems.
Definition fios_gui.cpp:48
@ Date
Sort by date.
Definition fios_gui.cpp:49
@ Name
Sort by name.
Definition fios_gui.cpp:50
static const EnumIndexArray< ExtendedTextColour, DetailedFileType, DetailedFileType::End > _fios_colours
Text colours of DetailedFileType fios entries in the window.
Definition fios_gui.cpp:308
static void SortSaveGameList(FileList &file_list)
Sort the collected list save games prior to displaying it in the save/load gui.
Definition fios_gui.cpp:324
Types related to the fios widgets.
@ WID_SL_SORT_BYDATE
Sort by date button.
Definition fios_widget.h:17
@ WID_SL_SAVE_GAME
Save button, only available for save operations.
Definition fios_widget.h:27
@ WID_SL_BACKGROUND
Background of window.
Definition fios_widget.h:19
@ WID_SL_NEW_DIRECTORY
Button to create a new directory in the current path.
Definition fios_widget.h:28
@ WID_SL_SAVE_OSK_TITLE
Title textbox, only available for save operations.
Definition fios_widget.h:25
@ WID_SL_DELETE_SELECTION
Delete button, only available for save operations.
Definition fios_widget.h:26
@ WID_SL_DETAILS
Panel with game details.
Definition fios_widget.h:30
@ WID_SL_FILE_BACKGROUND
Background of file selection.
Definition fios_widget.h:20
@ WID_SL_NEWGRF_INFO
Button to open NewGgrf configuration.
Definition fios_widget.h:31
@ WID_SL_DRIVES_DIRECTORIES_LIST
Drives list.
Definition fios_widget.h:22
@ WID_SL_LOAD_BUTTON
Button to load game/scenario.
Definition fios_widget.h:32
@ WID_SL_FILTER
Filter list of files.
Definition fios_widget.h:18
@ WID_SL_SCROLLBAR
Scrollbar of the file list.
Definition fios_widget.h:23
@ WID_SL_CAPTION
Caption of the window.
Definition fios_widget.h:15
@ WID_SL_HOME_BUTTON
Home button.
Definition fios_widget.h:21
@ WID_SL_SORT_BYNAME
Sort by name button.
Definition fios_widget.h:16
@ WID_SL_MISSING_NEWGRFS
Button to find missing NewGRFs online.
Definition fios_widget.h:33
@ WID_SL_CONTENT_DOWNLOAD_SEL
Selection 'stack' to 'hide' the content download.
Definition fios_widget.h:29
@ WID_SL_CONTENT_DOWNLOAD
Content download button, only available for play scenario/heightmap.
Definition fios_widget.h:24
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:88
Functions to be called to log fundamental changes to the game.
Declaration shared among gamelog.cpp and saveload/gamelog_sl.cpp.
void LoadTownData()
Load town data from _file_to_saveload, place towns at the appropriate locations, and expand them to t...
Definition genworld.cpp:359
Functions related to world/map generation.
void ShowHeightmapLoad()
Start with loading a heightmap.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
@ Centre
Align to the centre.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:899
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:116
SwitchMode _switch_mode
The next mainloop command.
Definition gfx.cpp:50
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, ExtendedTextColour colour, Alignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:787
int DrawString(int left, int right, int top, std::string_view str, ExtendedTextColour colour, Alignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:668
Functions related to the gfx engine.
@ Normal
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ Grey
Grey.
Definition gfx_type.h:299
@ LightBrown
Light brown colour.
Definition gfx_type.h:323
@ LightBlue
Light blue colour.
Definition gfx_type.h:331
@ Yellow
Yellow colour.
Definition gfx_type.h:326
@ FromString
Marker for telling to use the colour from the string.
Definition gfx_type.h:317
@ Orange
Orange colour.
Definition gfx_type.h:324
@ Black
Black colour.
Definition gfx_type.h:334
@ Red
Red colour.
Definition gfx_type.h:321
@ DarkGreen
Dark green colour.
Definition gfx_type.h:327
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 SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
static const CursorID SPR_CURSOR_ZZZ
Definition sprites.h:1568
void SetDirty() const
Mark entire window as dirty (in need of re-paint).
Definition window.cpp:975
GUI functions that shouldn't be here.
Types related to the landscape.
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
Miscellaneous command definitions.
void ShowQuery(EncodedString &&caption, EncodedString &&message, Window *parent, QueryCallbackProc *callback, bool focus)
Show a confirmation window with standard 'yes' and 'no' buttons The window is aligned to the centre o...
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
bool _network_available
is network mode available?
Definition network.cpp:69
bool _networking
are we in networking mode?
Definition network.cpp:67
Basic functions/variables used all over the place.
Part of the network protocol handling content distribution.
void ShowNetworkContentListWindow(ContentVector *cv=nullptr, ContentType type1=ContentType::End, ContentType type2=ContentType::End)
Show the content list window with a given set of content.
void ShowMissingContentWindow(const GRFConfigList &list)
Show the content list window with all missing grfs from the given list.
void ClearGRFConfigList(GRFConfigList &config)
Clear a GRF Config list, freeing all nodes.
@ NotFound
At least one GRF couldn't be found (higher priority than GRFListCompatibility::Compatible).
@ AllGood
All GRF needed by game are present.
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfigList &config)
Setup the NewGRF gui.
@ SaveLoad
A game paused for saving/loading.
Definition openttd.h:73
@ Editor
In the scenario editor.
Definition openttd.h:21
@ Menu
In the main menu.
Definition openttd.h:19
@ LoadGame
Load game, Play Scenario.
Definition openttd.h:32
@ LoadScenario
Load scenario from scenario editor.
Definition openttd.h:37
@ SaveGame
Save game.
Definition openttd.h:34
@ SaveHeightmap
Save heightmap.
Definition openttd.h:35
PixelColour GetColourGradient(Colours colour, Shade shade)
Get colour gradient palette index.
Definition palette.cpp:393
@ Lightest
Lightest colour shade.
static constexpr PixelColour PC_DARK_BLUE
Dark blue palette colour.
static constexpr PixelColour PC_BLACK
Black palette colour.
static constexpr PixelColour PC_VERY_DARK_BLUE
Almost-black blue palette colour.
Base for the GUIs that have an edit box in them.
A number of safeguards to prevent using unsafe methods.
SaveLoadResult SaveOrLoad(std::string_view filename, SaveLoadOperation fop, DetailedFileType dft, Subdirectory sb, bool threaded)
Main Save or Load function where the high-level saveload functions are handled.
FileToSaveLoad _file_to_saveload
File to save or load in the openttd loop.
Definition saveload.cpp:78
std::string GenerateDefaultSaveName()
Get the default name for a savegame or screenshot.
Functions related to saving and loading games.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
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:424
Functions related to OTTD's strings.
StrongType::Typedef< uint32_t, struct StringIDTag, StrongType::Compare, StrongType::Integer > StringID
Numeric value that represents a string, independent of the selected language.
static constexpr StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames).
uint32_t name_2
Parameter of name_1.
StringID name_1
Name of the company if the user did not change it.
std::string name
Name of the company if the user changed it.
Dimensions (a width and height) of a rectangle in 2D.
Deals with finding savegames.
Definition fios.h:86
DetailedFileType detailed
Detailed file type.
Definition fileio_type.h:65
LandscapeType landscape
the landscape we're currently in
GameCreationSettings game_creation
settings used during the creation of a game (map)
Container for loading in mode SL_LOAD_CHECK.
Definition fios.h:41
bool checkable
True if the savegame could be checked by SL_LOAD_CHECK. (Old savegames are not checkable....
Definition fios.h:42
bool HasNewGrfs()
Check whether the game uses any NewGrfs.
Definition fios.h:75
std::string error_msg
Data to pass to string parameters when displaying error.
Definition fios.h:44
TimerGameCalendar::Year starting_year
Starting date.
Definition fios.h:51
CompanyPropertiesMap companies
Company information.
Definition fios.h:53
StringID error
Error message from loading. INVALID_STRING_ID if no error.
Definition fios.h:43
Gamelog gamelog
Gamelog actions.
Definition fios.h:58
void Clear()
Reset read data.
Definition fios_gui.cpp:72
GRFListCompatibility grf_compatibility
Summary state of NewGrfs, whether missing files or only compatible found.
Definition fios.h:56
LandscapeType landscape
Landscape type.
Definition fios.h:50
GRFConfigList grfconfig
NewGrf configuration from save.
Definition fios.h:55
Data stored about a string that can be modified in the GUI.
static const int ACTION_CLEAR
Clear editbox.
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect WithY(int new_top, int new_bottom) const
Create a new Rect, replacing the top and bottom coordinates.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
static std::optional< StringID > GetDirectoryNameError(const std::string &name)
Check a user-entered name for use as a single directory component.
Definition fios_gui.cpp:398
void OnTimeout() override
Called when this window's timeout has been reached.
Definition fios_gui.cpp:919
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition fios_gui.cpp:761
const FiosItem * highlighted
Item in fios_items highlighted by mouse pointer, or nullptr.
Definition fios_gui.cpp:356
QueryString filter_editbox
Filter editbox;.
Definition fios_gui.cpp:360
void GenerateFileName()
Generate a default save filename.
Definition fios_gui.cpp:466
StringFilter string_filter
Filter for available items.
Definition fios_gui.cpp:359
void ShowNewDirectoryQuery(std::string_view initial_name={})
Open the query used to enter a new directory name.
Definition fios_gui.cpp:414
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
Definition fios_gui.cpp:990
std::vector< FiosItem * > display_list
Filtered display list.
Definition fios_gui.cpp:361
void OnMouseOver(Point pt, WidgetID widget) override
The mouse is currently moving over the window or has just moved outside of the window.
Definition fios_gui.cpp:890
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Definition fios_gui.cpp:574
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 fios_gui.cpp:728
void OnResize() override
Called after the window got resized.
Definition fios_gui.cpp:951
SaveLoadOperation fop
File operation to perform.
Definition fios_gui.cpp:352
FileList fios_items
Item list.
Definition fios_gui.cpp:353
QueryString filename_editbox
Filename editbox.
Definition fios_gui.cpp:350
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnPaint() override
The window must be repainted.
Definition fios_gui.cpp:750
void HandleNewDirectoryRequest(const std::string &query_text)
Validate a user-entered directory name and, if valid, create the directory in the current FIOS path.
Definition fios_gui.cpp:432
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Definition fios_gui.cpp:583
AbstractFileType abstract_filetype
Type of file to select.
Definition fios_gui.cpp:351
const FiosItem * selected
Selected item in fios_items, or nullptr.
Definition fios_gui.cpp:355
FiosItem o_dir
Original dir (home dir for this browser).
Definition fios_gui.cpp:354
EventState OnKeyPress(char32_t key, uint16_t keycode) override
A key has been pressed.
Definition fios_gui.cpp:909
static const uint MAX_DIRECTORY_NAME_CHARS
Maximum length of a new directory name in characters.
Definition fios_gui.cpp:348
void OnEditboxChanged(WidgetID wid) override
The text in an editbox has been edited.
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.
std::string_view GetText() const
Get the current text.
Definition textbuf.cpp:284
void Assign(std::string_view text)
Copy a string into the textbuffer.
Definition textbuf.cpp:420
High level window description.
Definition window_gui.h:172
Data structure for an opened window.
Definition window_gui.h:273
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1112
static int SortButtonWidth()
Get width of up/down arrow of sort button state.
Definition widget.cpp:839
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1817
std::map< WidgetID, QueryString * > querystrings
QueryString associated to WWT_EDITBOX widgets.
Definition window_gui.h:320
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:792
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3258
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:565
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void DrawSortButton(WidgetID widget, bool descending) const
Draw a sort button's up or down arrow symbol.
Definition widget.cpp:824
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1807
bool SetFocusedWidget(WidgetID widget_index)
Set focus within this window to the given widget.
Definition window.cpp:494
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition window_gui.h:491
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1841
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:989
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:460
void HandleButtonClick(WidgetID widget)
Do all things to make a button look clicked and mark it to be unclicked in a few ticks.
Definition window.cpp:604
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:322
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:381
@ Scenario
The content consists of a scenario.
@ Heightmap
The content consists of a heightmap.
@ AcceptUnchanged
return success even when the text didn't change
Definition textbuf_gui.h:19
@ LengthIsInChars
the length of the string is counted in characters
Definition textbuf_gui.h:21
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
void SetObjectToPlace(CursorID icon, PaletteID pal, HighLightStyle mode, WindowClass window_class, WindowNumber window_num)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
@ HT_NONE
default
Definition of the game-calendar-timer.
@ 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:40
@ WWT_PUSHIMGBTN
Normal push-button (no toggle button) with image caption.
@ WWT_EDITBOX
a textbox for typing
Definition widget_type.h:62
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window).
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX).
Definition widget_type.h:56
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:49
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ EqualSize
Containers should keep all their (resizing) children equally large.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition window.cpp:1204
Window functions not directly related to making/drawing windows.
@ Center
Center the window.
Definition window_gui.h:147
int WidgetID
Widget ID.
Definition window_type.h:21
EventState
State of handling an event.
@ Handled
The passed event is handled.
@ NotHandled
The passed event is not handled.