OpenTTD: src/fios_gui.cpp Source File

OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

fios_gui.cpp
Go to the documentation of this file.
1 /* $Id: fios_gui.cpp 26960 2014-10-05 11:20:02Z peter1138 $ */
2
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
9
12 #include "stdafx.h"
13 #include "saveload/saveload.h"
14 #include "error.h"
15 #include "gui.h"
16 #include "gfx_func.h"
17 #include "command_func.h"
18 #include "network/network.h"
19 #include "network/network_content.h"
20 #include "strings_func.h"
21 #include "fileio_func.h"
22 #include "fios.h"
23 #include "window_func.h"
24 #include "tilehighlight_func.h"
25 #include "querystring_gui.h"
26 #include "engine_func.h"
27 #include "landscape_type.h"
28 #include "date_func.h"
29 #include "core/geometry_func.hpp"
30 #include "gamelog.h"
31
32 #include "widgets/fios_widget.h"
33
34 #include "table/sprites.h"
35 #include "table/strings.h"
36
37 #include "safeguards.h"
38
39 SaveLoadDialogMode _saveload_mode;
40 LoadCheckData _load_check_data;
41
42 static bool _fios_path_changed;
43 static bool _savegame_sort_dirty;
44
45
49 void LoadCheckData::Clear()
50 {
51 this->checkable = false;
52 this->error = INVALID_STRING_ID;
53 free(this->error_data);
54 this->error_data = NULL;
55
56 this->map_size_x = this->map_size_y = 256; // Default for old savegames which do not store mapsize.
57 this->current_date = 0;
58 memset(&this->settings, 0, sizeof(this->settings));
59
60 const CompanyPropertiesMap::iterator end = this->companies.End();
61 for (CompanyPropertiesMap::iterator it = this->companies.Begin(); it != end; it++) {
62 delete it->second;
63 }
64 companies.Clear();
65
66 GamelogFree(this->gamelog_action, this->gamelog_actions);
67 this->gamelog_action = NULL;
68 this->gamelog_actions = 0;
69
70 ClearGRFConfigList(&this->grfconfig);
71 }
72
74 static const NWidgetPart _nested_load_dialog_widgets[] = {
75 NWidget(NWID_HORIZONTAL),
76 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
77 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
78 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
79 EndContainer(),
80 NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(),
81 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
82 NWidget(NWID_VERTICAL),
83 NWidget(NWID_HORIZONTAL),
84 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
85 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
86 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
87 EndContainer(),
88 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON),
89 EndContainer(),
90 NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND),
91 NWidget(NWID_HORIZONTAL),
92 NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetFill(1, 1), SetPadding(2, 1, 2, 2),
93 SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(),
94 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR),
95 EndContainer(),
96 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SL_CONTENT_DOWNLOAD_SEL),
97 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_CONTENT_DOWNLOAD), SetResize(1, 0),
98 SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
99 EndContainer(),
100 EndContainer(),
101 EndContainer(),
102 NWidget(WWT_PANEL, COLOUR_GREY),
103 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SL_DETAILS), SetResize(1, 1), SetFill(1, 1),
104 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_MISSING_NEWGRFS), SetDataTip(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON, STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
105 NWidget(NWID_HORIZONTAL),
106 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
107 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_NEWGRF_INFO), SetDataTip(STR_INTRO_NEWGRF_SETTINGS, STR_NULL), SetFill(1, 0), SetResize(1, 0),
108 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_BUTTON), SetDataTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
109 EndContainer(),
110 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
111 EndContainer(),
112 EndContainer(),
113 EndContainer(),
114 };
115
117 static const NWidgetPart _nested_load_heightmap_dialog_widgets[] = {
118 NWidget(NWID_HORIZONTAL),
119 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
120 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
121 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
122 EndContainer(),
123 NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(),
124 NWidget(NWID_VERTICAL),
125 NWidget(NWID_HORIZONTAL),
126 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
127 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
128 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
129 EndContainer(),
130 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON),
131 EndContainer(),
132 NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND),
133 NWidget(NWID_HORIZONTAL),
134 NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetFill(1, 1), SetPadding(2, 1, 2, 2),
135 SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(),
136 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR),
137 EndContainer(),
138 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
139 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_CONTENT_DOWNLOAD), SetResize(1, 0), SetFill(1, 0),
140 SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
141 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_LOAD_BUTTON), SetResize(1, 0), SetFill(1, 0),
142 SetDataTip(STR_SAVELOAD_LOAD_BUTTON, STR_SAVELOAD_LOAD_HEIGHTMAP_TOOLTIP),
143 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
144 EndContainer(),
145 EndContainer(),
146 EndContainer(),
147 };
148
150 static const NWidgetPart _nested_save_dialog_widgets[] = {
151 NWidget(NWID_HORIZONTAL),
152 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
153 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SL_CAPTION),
154 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
155 EndContainer(),
156 NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_BACKGROUND), SetFill(1, 0), SetResize(1, 0), EndContainer(),
157 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
158 NWidget(NWID_VERTICAL),
159 NWidget(NWID_HORIZONTAL),
160 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
161 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYNAME), SetDataTip(STR_SORT_BY_CAPTION_NAME, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
162 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SORT_BYDATE), SetDataTip(STR_SORT_BY_CAPTION_DATE, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0), SetResize(1, 0),
163 EndContainer(),
164 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_SL_HOME_BUTTON), SetMinimalSize(12, 12), SetDataTip(SPR_HOUSE_ICON, STR_SAVELOAD_HOME_BUTTON),
165 EndContainer(),
166 NWidget(WWT_PANEL, COLOUR_GREY, WID_SL_FILE_BACKGROUND),
167 NWidget(NWID_HORIZONTAL),
168 NWidget(WWT_INSET, COLOUR_GREY, WID_SL_DRIVES_DIRECTORIES_LIST), SetPadding(2, 1, 0, 2),
169 SetDataTip(0x0, STR_SAVELOAD_LIST_TOOLTIP), SetResize(1, 10), SetScrollbar(WID_SL_SCROLLBAR), EndContainer(),
170 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_SL_SCROLLBAR),
171 EndContainer(),
172 NWidget(WWT_EDITBOX, COLOUR_GREY, WID_SL_SAVE_OSK_TITLE), SetPadding(3, 2, 2, 2), SetFill(1, 0), SetResize(1, 0),
173 SetDataTip(STR_SAVELOAD_OSKTITLE, STR_SAVELOAD_EDITBOX_TOOLTIP),
174 EndContainer(),
175 NWidget(NWID_HORIZONTAL),
176 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_DELETE_SELECTION), SetDataTip(STR_SAVELOAD_DELETE_BUTTON, STR_SAVELOAD_DELETE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
177 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SL_SAVE_GAME), SetDataTip(STR_SAVELOAD_SAVE_BUTTON, STR_SAVELOAD_SAVE_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
178 EndContainer(),
179 EndContainer(),
180 NWidget(WWT_PANEL, COLOUR_GREY),
181 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SL_DETAILS), SetResize(1, 1), SetFill(1, 1),
182 NWidget(NWID_HORIZONTAL),
183 NWidget(NWID_SPACER), SetResize(1, 0), SetFill(1, 1),
184 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
185 EndContainer(),
186 EndContainer(),
187 EndContainer(),
188 };
189
191 const TextColour _fios_colours[] = {
192 TC_LIGHT_BLUE, TC_DARK_GREEN, TC_DARK_GREEN, TC_ORANGE, TC_LIGHT_BROWN,
193 TC_ORANGE, TC_LIGHT_BROWN, TC_ORANGE, TC_ORANGE, TC_YELLOW
194 };
195
196 void BuildFileList()
197 {
198 _fios_path_changed = true;
199 FiosFreeSavegameList();
200
201 switch (_saveload_mode) {
202 case SLD_LOAD_SCENARIO:
203 case SLD_SAVE_SCENARIO:
204 FiosGetScenarioList(_saveload_mode); break;
205 case SLD_SAVE_HEIGHTMAP:
206 case SLD_LOAD_HEIGHTMAP:
207 FiosGetHeightmapList(_saveload_mode); break;
208
209 default: FiosGetSavegameList(_saveload_mode); break;
210 }
211
212 /* Invalidate saveload window */
213 InvalidateWindowData(WC_SAVELOAD, 0, 2, true);
214 }
215
216 static void MakeSortedSaveGameList()
217 {
218 uint sort_start = 0;
219 uint sort_end = 0;
220
221 /* Directories are always above the files (FIOS_TYPE_DIR)
222 * Drives (A:\ (windows only) are always under the files (FIOS_TYPE_DRIVE)
223 * Only sort savegames/scenarios, not directories
224 */
225 for (const FiosItem *item = _fios_items.Begin(); item != _fios_items.End(); item++) {
226 switch (item->type) {
227 case FIOS_TYPE_DIR: sort_start++; break;
228 case FIOS_TYPE_PARENT: sort_start++; break;
229 case FIOS_TYPE_DRIVE: sort_end++; break;
230 default: break;
231 }
232 }
233
234 uint s_amount = _fios_items.Length() - sort_start - sort_end;
235 QSortT(_fios_items.Get(sort_start), s_amount, CompareFiosItems);
236 }
237
238 struct SaveLoadWindow : public Window {
239 private:
240 QueryString filename_editbox;
241 FiosItem o_dir;
242 const FiosItem *selected;
243 Scrollbar *vscroll;
244 public:
245
247 void GenerateFileName()
248 {
249 GenerateDefaultSaveName(this->filename_editbox.text.buf, &this->filename_editbox.text.buf[this->filename_editbox.text.max_bytes - 1]);
250 this->filename_editbox.text.UpdateSize();
251 }
252
253 SaveLoadWindow(WindowDesc *desc, SaveLoadDialogMode mode) : Window(desc), filename_editbox(64)
254 {
255 static const StringID saveload_captions[] = {
256 STR_SAVELOAD_LOAD_CAPTION,
257 STR_SAVELOAD_LOAD_SCENARIO,
258 STR_SAVELOAD_SAVE_CAPTION,
259 STR_SAVELOAD_SAVE_SCENARIO,
260 STR_SAVELOAD_LOAD_HEIGHTMAP,
261 STR_SAVELOAD_SAVE_HEIGHTMAP,
262 };
263 assert((uint)mode < lengthof(saveload_captions));
264
265 /* Use an array to define what will be the current file type being handled
266 * by current file mode */
267 switch (mode) {
268 case SLD_SAVE_GAME: this->GenerateFileName(); break;
269 case SLD_SAVE_HEIGHTMAP:
270 case SLD_SAVE_SCENARIO: this->filename_editbox.text.Assign("UNNAMED"); break;
271 default: break;
272 }
273
274 this->querystrings[WID_SL_SAVE_OSK_TITLE] = &this->filename_editbox;
275 this->filename_editbox.ok_button = WID_SL_SAVE_GAME;
276
277 this->CreateNestedTree(true);
278 if (mode == SLD_LOAD_GAME) this->GetWidget<NWidgetStacked>(WID_SL_CONTENT_DOWNLOAD_SEL)->SetDisplayedPlane(SZSP_HORIZONTAL);
279 this->GetWidget<NWidgetCore>(WID_SL_CAPTION)->widget_data = saveload_captions[mode];
280 this->vscroll = this->GetScrollbar(WID_SL_SCROLLBAR);
281
282 this->FinishInitNested(0);
283
284 this->LowerWidget(WID_SL_DRIVES_DIRECTORIES_LIST);
285
286 /* pause is only used in single-player, non-editor mode, non-menu mode. It
287 * will be unpaused in the WE_DESTROY event handler. */
288 if (_game_mode != GM_MENU && !_networking && _game_mode != GM_EDITOR) {
289 DoCommandP(0, PM_PAUSED_SAVELOAD, 1, CMD_PAUSE);
290 }
291 SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
292
293 this->OnInvalidateData(0);
294
295 ResetObjectToPlace();
296
297 o_dir.type = FIOS_TYPE_DIRECT;
298 switch (_saveload_mode) {
299 case SLD_SAVE_GAME:
300 case SLD_LOAD_GAME:
301 FioGetDirectory(o_dir.name, lastof(o_dir.name), SAVE_DIR);
302 break;
303
304 case SLD_SAVE_SCENARIO:
305 case SLD_LOAD_SCENARIO:
306 FioGetDirectory(o_dir.name, lastof(o_dir.name), SCENARIO_DIR);
307 break;
308
309 case SLD_SAVE_HEIGHTMAP:
310 case SLD_LOAD_HEIGHTMAP:
311 FioGetDirectory(o_dir.name, lastof(o_dir.name), HEIGHTMAP_DIR);
312 break;
313
314 default:
315 strecpy(o_dir.name, _personal_dir, lastof(o_dir.name));
316 }
317
318 /* Focus the edit box by default in the save windows */
319 if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP) {
320 this->SetFocusedWidget(WID_SL_SAVE_OSK_TITLE);
321 }
322 }
323
324 virtual ~SaveLoadWindow()
325 {
326 /* pause is only used in single-player, non-editor mode, non menu mode */
327 if (!_networking && _game_mode != GM_EDITOR && _game_mode != GM_MENU) {
328 DoCommandP(0, PM_PAUSED_SAVELOAD, 0, CMD_PAUSE);
329 }
330 FiosFreeSavegameList();
331 }
332
333 virtual void DrawWidget(const Rect &r, int widget) const
334 {
335 switch (widget) {
336 case WID_SL_SORT_BYNAME:
337 case WID_SL_SORT_BYDATE:
338 if (((_savegame_sort_order & SORT_BY_NAME) != 0) == (widget == WID_SL_SORT_BYNAME)) {
339 this->DrawSortButtonState(widget, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP);
340 }
341 break;
342
343 case WID_SL_BACKGROUND: {
344 static const char *path = NULL;
345 static StringID str = STR_ERROR_UNABLE_TO_READ_DRIVE;
346 static uint64 tot = 0;
347
348 if (_fios_path_changed) {
349 str = FiosGetDescText(&path, &tot);
350 _fios_path_changed = false;
351 }
352
353 if (str != STR_ERROR_UNABLE_TO_READ_DRIVE) SetDParam(0, tot);
354 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP, str);
355 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, path, TC_BLACK);
356 break;
357 }
358
359 case WID_SL_DRIVES_DIRECTORIES_LIST: {
360 GfxFillRect(r.left + 1, r.top + 1, r.right, r.bottom, PC_BLACK);
361
362 uint y = r.top + WD_FRAMERECT_TOP;
363 for (uint pos = this->vscroll->GetPosition(); pos < _fios_items.Length(); pos++) {
364 const FiosItem *item = _fios_items.Get(pos);
365
366 if (item == this->selected) {
367 GfxFillRect(r.left + 1, y, r.right, y + this->resize.step_height, PC_DARK_BLUE);
368 }
369 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, item->title, _fios_colours[item->type]);
370 y += this->resize.step_height;
371 if (y >= this->vscroll->GetCapacity() * this->resize.step_height + r.top + WD_FRAMERECT_TOP) break;
372 }
373 break;
374 }
375
376 case WID_SL_DETAILS: {
377 GfxFillRect(r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP,
378 r.right - WD_FRAMERECT_RIGHT, r.top + FONT_HEIGHT_NORMAL * 2 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, PC_GREY);
379 DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL / 2 + WD_FRAMERECT_TOP, STR_SAVELOAD_DETAIL_CAPTION, TC_FROMSTRING, SA_HOR_CENTER);
380
381 if (this->selected == NULL) break;
382
383 uint y = r.top + FONT_HEIGHT_NORMAL * 2 + WD_PAR_VSEP_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
384 uint y_max = r.bottom - FONT_HEIGHT_NORMAL - WD_FRAMERECT_BOTTOM;
385
386 if (y > y_max) break;
387 if (!_load_check_data.checkable) {
388 /* Old savegame, no information available */
389 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_NOT_AVAILABLE);
390 y += FONT_HEIGHT_NORMAL;
391 } else if (_load_check_data.error != INVALID_STRING_ID) {
392 /* Incompatible / broken savegame */
393 SetDParamStr(0, _load_check_data.error_data);
394 y = DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT,
395 y, r.bottom - WD_FRAMERECT_BOTTOM, _load_check_data.error, TC_RED);
396 } else {
397 /* Mapsize */
398 SetDParam(0, _load_check_data.map_size_x);
399 SetDParam(1, _load_check_data.map_size_y);
400 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_MAP_SIZE);
401 y += FONT_HEIGHT_NORMAL;
402 if (y > y_max) break;
403
404 /* Climate */
405 byte landscape = _load_check_data.settings.game_creation.landscape;
406 if (landscape < NUM_LANDSCAPE) {
407 SetDParam(0, STR_CHEAT_SWITCH_CLIMATE_TEMPERATE_LANDSCAPE + landscape);
408 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_LANDSCAPE);
409 y += FONT_HEIGHT_NORMAL;
410 }
411
412 y += WD_PAR_VSEP_NORMAL;
413 if (y > y_max) break;
414
415 /* Start date (if available) */
416 if (_load_check_data.settings.game_creation.starting_year != 0) {
417 SetDParam(0, ConvertYMDToDate(_load_check_data.settings.game_creation.starting_year, 0, 1));
418 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_START_DATE);
419 y += FONT_HEIGHT_NORMAL;
420 }
421 if (y > y_max) break;
422
423 /* Hide current date for scenarios */
424 if (_saveload_mode != SLD_LOAD_SCENARIO && _saveload_mode != SLD_SAVE_SCENARIO) {
425 /* Current date */
426 SetDParam(0, _load_check_data.current_date);
427 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_NETWORK_SERVER_LIST_CURRENT_DATE);
428 y += FONT_HEIGHT_NORMAL;
429 }
430
431 /* Hide the NewGRF stuff when saving. We also hide the button. */
432 if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
433 y += WD_PAR_VSEP_NORMAL;
434 if (y > y_max) break;
435
436 /* NewGrf compatibility */
437 SetDParam(0, _load_check_data.grfconfig == NULL ? STR_NEWGRF_LIST_NONE :
438 STR_NEWGRF_LIST_ALL_FOUND + _load_check_data.grf_compatibility);
439 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_GRFSTATUS);
440 y += FONT_HEIGHT_NORMAL;
441 }
442 if (y > y_max) break;
443
444 /* Hide the company stuff for scenarios */
445 if (_saveload_mode != SLD_LOAD_SCENARIO && _saveload_mode != SLD_SAVE_SCENARIO) {
446 y += FONT_HEIGHT_NORMAL;
447 if (y > y_max) break;
448
449 /* Companies / AIs */
450 CompanyPropertiesMap::const_iterator end = _load_check_data.companies.End();
451 for (CompanyPropertiesMap::const_iterator it = _load_check_data.companies.Begin(); it != end; it++) {
452 SetDParam(0, it->first + 1);
453 const CompanyProperties &c = *it->second;
454 if (c.name != NULL) {
455 SetDParam(1, STR_JUST_RAW_STRING);
456 SetDParamStr(2, c.name);
457 } else {
458 SetDParam(1, c.name_1);
459 SetDParam(2, c.name_2);
460 }
461 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_SAVELOAD_DETAIL_COMPANY_INDEX);
462 y += FONT_HEIGHT_NORMAL;
463 if (y > y_max) break;
464 }
465 }
466 }
467 break;
468 }
469 }
470 }
471
472 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
473 {
474 switch (widget) {
475 case WID_SL_BACKGROUND:
476 size->height = 2 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
477 break;
478
479 case WID_SL_DRIVES_DIRECTORIES_LIST:
480 resize->height = FONT_HEIGHT_NORMAL;
481 size->height = resize->height * 10 + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
482 break;
483 case WID_SL_SORT_BYNAME:
484 case WID_SL_SORT_BYDATE: {
485 Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
486 d.width += padding.width + Window::SortButtonWidth() * 2; // Doubled since the string is centred and it also looks better.
487 d.height += padding.height;
488 *size = maxdim(*size, d);
489 break;
490 }
491 }
492 }
493
494 virtual void OnPaint()
495 {
496 if (_savegame_sort_dirty) {
497 _savegame_sort_dirty = false;
498 MakeSortedSaveGameList();
499 }
500
501 this->vscroll->SetCount(_fios_items.Length());
502 this->DrawWidgets();
503 }
504
505 virtual void OnClick(Point pt, int widget, int click_count)
506 {
507 switch (widget) {
508 case WID_SL_SORT_BYNAME: // Sort save names by name
509 _savegame_sort_order = (_savegame_sort_order == SORT_BY_NAME) ?
510 SORT_BY_NAME | SORT_DESCENDING : SORT_BY_NAME;
511 _savegame_sort_dirty = true;
512 this->SetDirty();
513 break;
514
515 case WID_SL_SORT_BYDATE: // Sort save names by date
516 _savegame_sort_order = (_savegame_sort_order == SORT_BY_DATE) ?
517 SORT_BY_DATE | SORT_DESCENDING : SORT_BY_DATE;
518 _savegame_sort_dirty = true;
519 this->SetDirty();
520 break;
521
522 case WID_SL_HOME_BUTTON: // OpenTTD 'button', jumps to OpenTTD directory
523 FiosBrowseTo(&o_dir);
524 this->InvalidateData();
525 break;
526
527 case WID_SL_LOAD_BUTTON:
528 if (this->selected != NULL && !_load_check_data.HasErrors()) {
529 const char *name = FiosBrowseTo(this->selected);
530 SetFiosType(this->selected->type);
531
532 strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
533 strecpy(_file_to_saveload.title, this->selected->title, lastof(_file_to_saveload.title));
534
535 if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
536 delete this;
537 ShowHeightmapLoad();
538 } else if (!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()) {
539 _switch_mode = (_game_mode == GM_EDITOR) ? SM_LOAD_SCENARIO : SM_LOAD_GAME;
540 ClearErrorMessages();
541 delete this;
542 }
543 }
544 break;
545
546 case WID_SL_NEWGRF_INFO:
547 if (_load_check_data.HasNewGrfs()) {
548 ShowNewGRFSettings(false, false, false, &_load_check_data.grfconfig);
549 }
550 break;
551
552 case WID_SL_MISSING_NEWGRFS:
553 if (!_network_available) {
554 ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
555 } else if (_load_check_data.HasNewGrfs()) {
556 #if defined(ENABLE_NETWORK)
557 ShowMissingContentWindow(_load_check_data.grfconfig);
558 #endif
559 }
560 break;
561
562 case WID_SL_DRIVES_DIRECTORIES_LIST: { // Click the listbox
563 int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SL_DRIVES_DIRECTORIES_LIST, WD_FRAMERECT_TOP);
564 if (y == INT_MAX) return;
565
566 const FiosItem *file = _fios_items.Get(y);
567
568 const char *name = FiosBrowseTo(file);
569 if (name != NULL) {
570 if (click_count == 1) {
571 if (this->selected != file) {
572 this->selected = file;
573 _load_check_data.Clear();
574
575 if (file->type == FIOS_TYPE_FILE || file->type == FIOS_TYPE_SCENARIO) {
576 SaveOrLoad(name, SL_LOAD_CHECK, NO_DIRECTORY, false);
577 }
578
579 this->InvalidateData(1);
580 }
581 if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP) {
582 /* Copy clicked name to editbox */
583 this->filename_editbox.text.Assign(file->title);
584 this->SetWidgetDirty(WID_SL_SAVE_OSK_TITLE);
585 }
586 } else if (!_load_check_data.HasErrors()) {
587 this->selected = file;
588 if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
589 this->OnClick(pt, WID_SL_LOAD_BUTTON, 1);
590 } else if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
591 SetFiosType(file->type);
592 strecpy(_file_to_saveload.name, name, lastof(_file_to_saveload.name));
593 strecpy(_file_to_saveload.title, file->title, lastof(_file_to_saveload.title));
594
595 delete this;
596 ShowHeightmapLoad();
597 }
598 }
599 } else {
600 /* Changed directory, need refresh. */
601 this->InvalidateData();
602 }
603 break;
604 }
605
606 case WID_SL_CONTENT_DOWNLOAD:
607 if (!_network_available) {
608 ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
609 } else {
610 #if defined(ENABLE_NETWORK)
611 switch (_saveload_mode) {
612 default: NOT_REACHED();
613 case SLD_LOAD_SCENARIO: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_SCENARIO); break;
614 case SLD_LOAD_HEIGHTMAP: ShowNetworkContentListWindow(NULL, CONTENT_TYPE_HEIGHTMAP); break;
615 }
616 #endif
617 }
618 break;
619
620 case WID_SL_DELETE_SELECTION: // Delete
621 break;
622
623 case WID_SL_SAVE_GAME: // Save game
624 /* Note, this is also called via the OSK; and we need to lower the button. */
625 this->HandleButtonClick(WID_SL_SAVE_GAME);
626 break;
627 }
628 }
629
630 virtual EventState OnKeyPress(WChar key, uint16 keycode)
631 {
632 if (keycode == WKC_ESC) {
633 delete this;
634 return ES_HANDLED;
635 }
636
637 return ES_NOT_HANDLED;
638 }
639
640 virtual void OnTimeout()
641 {
642 /* This test protects against using widgets 11 and 12 which are only available
643 * in those saveload modes. */
644 if (!(_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO || _saveload_mode == SLD_SAVE_HEIGHTMAP)) return;
645
646 if (this->IsWidgetLowered(WID_SL_DELETE_SELECTION)) { // Delete button clicked
647 if (!FiosDelete(this->filename_editbox.text.buf)) {
648 ShowErrorMessage(STR_ERROR_UNABLE_TO_DELETE_FILE, INVALID_STRING_ID, WL_ERROR);
649 } else {
650 this->InvalidateData();
651 /* Reset file name to current date on successful delete */
652 if (_saveload_mode == SLD_SAVE_GAME) GenerateFileName();
653 }
654 } else if (this->IsWidgetLowered(WID_SL_SAVE_GAME)) { // Save button clicked
655 if (_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) {
656 _switch_mode = SM_SAVE_GAME;
657 FiosMakeSavegameName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name));
658 } else {
659 _switch_mode = SM_SAVE_HEIGHTMAP;
660 FiosMakeHeightmapName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name));
661 }
662
663 /* In the editor set up the vehicle engines correctly (date might have changed) */
664 if (_game_mode == GM_EDITOR) StartupEngines();
665 }
666 }
667
668 virtual void OnResize()
669 {
670 this->vscroll->SetCapacityFromWidget(this, WID_SL_DRIVES_DIRECTORIES_LIST);
671 }
672
678 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
679 {
680 switch (data) {
681 case 0:
682 /* Rescan files */
683 this->selected = NULL;
684 _load_check_data.Clear();
685 if (!gui_scope) break;
686 BuildFileList();
687 /* FALL THROUGH */
688 case 1:
689 /* Selection changes */
690 if (!gui_scope) break;
691 if (_saveload_mode == SLD_LOAD_HEIGHTMAP) {
692 this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON, this->selected == NULL || _load_check_data.HasErrors());
693 }
694 if (_saveload_mode == SLD_LOAD_GAME || _saveload_mode == SLD_LOAD_SCENARIO) {
695 this->SetWidgetDisabledState(WID_SL_LOAD_BUTTON,
696 this->selected == NULL || _load_check_data.HasErrors() || !(!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()));
697 this->SetWidgetDisabledState(WID_SL_NEWGRF_INFO,
698 !_load_check_data.HasNewGrfs());
699 this->SetWidgetDisabledState(WID_SL_MISSING_NEWGRFS,
700 !_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility == GLC_ALL_GOOD);
701 }
702 break;
703 case 2:
704 /* _fios_items changed */
705 this->vscroll->SetCount(_fios_items.Length());
706 this->selected = NULL;
707 _load_check_data.Clear();
708 break;
709 }
710 }
711 };
712
714 static WindowDesc _load_dialog_desc(
715 WDP_CENTER, "load_game", 500, 294,
716 WC_SAVELOAD, WC_NONE,
717 0,
718 _nested_load_dialog_widgets, lengthof(_nested_load_dialog_widgets)
719 );
720
722 static WindowDesc _load_heightmap_dialog_desc(
723 WDP_CENTER, "load_heightmap", 257, 320,
724 WC_SAVELOAD, WC_NONE,
725 0,
726 _nested_load_heightmap_dialog_widgets, lengthof(_nested_load_heightmap_dialog_widgets)
727 );
728
730 static WindowDesc _save_dialog_desc(
731 WDP_CENTER, "save_game", 500, 294,
732 WC_SAVELOAD, WC_NONE,
733 0,
734 _nested_save_dialog_widgets, lengthof(_nested_save_dialog_widgets)
735 );
736
741 static const FileType _file_modetotype[] = {
742 FT_SAVEGAME, // used for SLD_LOAD_GAME
743 FT_SCENARIO, // used for SLD_LOAD_SCENARIO
744 FT_SAVEGAME, // used for SLD_SAVE_GAME
745 FT_SCENARIO, // used for SLD_SAVE_SCENARIO
746 FT_HEIGHTMAP, // used for SLD_LOAD_HEIGHTMAP
747 FT_HEIGHTMAP, // used for SLD_SAVE_HEIGHTMAP
748 };
749
754 void ShowSaveLoadDialog(SaveLoadDialogMode mode)
755 {
756 DeleteWindowById(WC_SAVELOAD, 0);
757
758 WindowDesc *sld;
759 switch (mode) {
760 case SLD_SAVE_GAME:
761 case SLD_SAVE_SCENARIO:
762 case SLD_SAVE_HEIGHTMAP:
763 sld = &_save_dialog_desc; break;
764 case SLD_LOAD_HEIGHTMAP:
765 sld = &_load_heightmap_dialog_desc; break;
766 default:
767 sld = &_load_dialog_desc; break;
768 }
769
770 _saveload_mode = mode;
771 _file_to_saveload.filetype = _file_modetotype[mode];
772
773 new SaveLoadWindow(sld, mode);
774 }
775
776 void SetFiosType(const byte fiostype)
777 {
778 switch (fiostype) {
779 case FIOS_TYPE_FILE:
780 case FIOS_TYPE_SCENARIO:
781 _file_to_saveload.mode = SL_LOAD;
782 break;
783
784 case FIOS_TYPE_OLDFILE:
785 case FIOS_TYPE_OLD_SCENARIO:
786 _file_to_saveload.mode = SL_OLD_LOAD;
787 break;
788
789 #ifdef WITH_PNG
790 case FIOS_TYPE_PNG:
791 _file_to_saveload.mode = SL_PNG;
792 break;
793 #endif /* WITH_PNG */
794
795 case FIOS_TYPE_BMP:
796 _file_to_saveload.mode = SL_BMP;
797 break;
798
799 default:
800 _file_to_saveload.mode = SL_INVALID;
801 break;
802 }
803 }