OpenTTD
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"
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;
41 
42 static bool _fios_path_changed;
43 static bool _savegame_sort_dirty;
44 
45 
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 
67  this->gamelog_action = NULL;
68  this->gamelog_actions = 0;
69 
71 }
72 
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(),
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(),
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(),
95  EndContainer(),
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),
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 
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(),
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(),
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(),
137  EndContainer(),
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 
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(),
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(),
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(),
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(),
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),
183  NWidget(NWID_SPACER), SetResize(1, 0), SetFill(1, 1),
184  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
185  EndContainer(),
186  EndContainer(),
187  EndContainer(),
188 };
189 
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;
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:
241  FiosItem o_dir;
242  const FiosItem *selected;
243  Scrollbar *vscroll;
244 public:
245 
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 
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 
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 
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) {
290  }
291  SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
292 
293  this->OnInvalidateData(0);
294 
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) {
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) {
329  }
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);
355  DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, path, TC_BLACK);
356  break;
357  }
358 
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: {
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 
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);
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:
477  break;
478 
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;
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;
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 
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);
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;
597  }
598  }
599  } else {
600  /* Changed directory, need refresh. */
601  this->InvalidateData();
602  }
603  break;
604  }
605 
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();
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. */
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) {
657  FiosMakeSavegameName(_file_to_saveload.name, this->filename_editbox.text.buf, lastof(_file_to_saveload.name));
658  } else {
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) {
696  this->selected == NULL || _load_check_data.HasErrors() || !(!_load_check_data.HasNewGrfs() || _load_check_data.grf_compatibility != GLC_NOT_FOUND || _settings_client.gui.UserIsAllowedToChangeNewGRFs()));
698  !_load_check_data.HasNewGrfs());
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 
715  WDP_CENTER, "load_game", 500, 294,
717  0,
718  _nested_load_dialog_widgets, lengthof(_nested_load_dialog_widgets)
719 );
720 
723  WDP_CENTER, "load_heightmap", 257, 320,
725  0,
726  _nested_load_heightmap_dialog_widgets, lengthof(_nested_load_heightmap_dialog_widgets)
727 );
728 
731  WDP_CENTER, "save_game", 500, 294,
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 
755 {
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 }