OpenTTD
toolbar_gui.cpp
Go to the documentation of this file.
1 /* $Id: toolbar_gui.cpp 26986 2014-10-09 21:16:29Z frosch $ */
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 "gui.h"
14 #include "window_gui.h"
15 #include "window_func.h"
16 #include "viewport_func.h"
17 #include "command_func.h"
18 #include "vehicle_gui.h"
19 #include "rail_gui.h"
20 #include "road_gui.h"
21 #include "date_func.h"
22 #include "vehicle_func.h"
23 #include "sound_func.h"
24 #include "terraform_gui.h"
25 #include "strings_func.h"
26 #include "company_func.h"
27 #include "company_gui.h"
28 #include "vehicle_base.h"
29 #include "cheat_func.h"
30 #include "transparency_gui.h"
31 #include "screenshot.h"
32 #include "signs_func.h"
33 #include "fios.h"
34 #include "console_gui.h"
35 #include "news_gui.h"
36 #include "ai/ai_gui.hpp"
37 #include "tilehighlight_func.h"
38 #include "smallmap_gui.h"
39 #include "graph_gui.h"
40 #include "textbuf_gui.h"
42 #include "newgrf_debug.h"
43 #include "hotkeys.h"
44 #include "engine_base.h"
45 #include "highscore.h"
46 #include "game/game.hpp"
47 #include "goal_base.h"
48 #include "story_base.h"
49 
50 #include "widgets/toolbar_widget.h"
51 
52 #include "network/network.h"
53 #include "network/network_gui.h"
54 #include "network/network_func.h"
55 
56 #include "safeguards.h"
57 
58 
59 RailType _last_built_railtype;
60 RoadType _last_built_roadtype;
61 
63 
66  TB_NORMAL,
67  TB_UPPER,
68  TB_LOWER
69 };
70 
73  CBF_NONE,
74  CBF_PLACE_SIGN,
75  CBF_PLACE_LANDINFO,
76 };
77 
82  uint checkmark_width;
83 public:
84  bool checked;
85 
86  DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked)
87  {
88  this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
89  }
90 
91  virtual ~DropDownListCheckedItem() {}
92 
93  uint Width() const
94  {
95  return DropDownListStringItem::Width() + this->checkmark_width;
96  }
97 
98  void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
99  {
100  bool rtl = _current_text_dir == TD_RTL;
101  if (this->checked) {
102  DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK);
103  }
104  DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : this->checkmark_width), right - WD_FRAMERECT_RIGHT - (rtl ? this->checkmark_width : 0), top, this->String(), sel ? TC_WHITE : TC_BLACK);
105  }
106 };
107 
112  Dimension icon_size;
113 public:
114  bool greyed;
115 
116  DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
117  {
118  this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
119  }
120 
121  virtual ~DropDownListCompanyItem() {}
122 
123  bool Selectable() const
124  {
125  return true;
126  }
127 
128  uint Width() const
129  {
130  CompanyID company = (CompanyID)this->result;
131  SetDParam(0, company);
132  SetDParam(1, company);
133  return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3;
134  }
135 
136  uint Height(uint width) const
137  {
138  return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
139  }
140 
141  void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
142  {
143  CompanyID company = (CompanyID)this->result;
144  bool rtl = _current_text_dir == TD_RTL;
145 
146  /* It's possible the company is deleted while the dropdown is open */
147  if (!Company::IsValidID(company)) return;
148 
149  int icon_offset = (bottom - top - icon_size.height) / 2;
150  int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2;
151 
152  DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset);
153 
154  SetDParam(0, company);
155  SetDParam(1, company);
156  TextColour col;
157  if (this->greyed) {
158  col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
159  } else {
160  col = sel ? TC_WHITE : TC_BLACK;
161  }
162  DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col);
163  }
164 };
165 
173 static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def)
174 {
175  ShowDropDownList(w, list, def, widget, 0, true, true);
176  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
177 }
178 
186 static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count)
187 {
188  DropDownList *list = new DropDownList();
189  for (int i = 0; i < count; i++) {
190  *list->Append() = new DropDownListStringItem(string + i, i, false);
191  }
192  PopupMainToolbMenu(w, widget, list, 0);
193 }
194 
196 static const int CTMN_CLIENT_LIST = -1;
197 static const int CTMN_NEW_COMPANY = -2;
198 static const int CTMN_SPECTATE = -3;
199 static const int CTMN_SPECTATOR = -4;
200 
208 static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0, bool include_spectator = false)
209 {
210  DropDownList *list = new DropDownList();
211 
212 #ifdef ENABLE_NETWORK
213  if (_networking) {
214  if (widget == WID_TN_COMPANIES) {
215  /* Add the client list button for the companies menu */
216  *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false);
217  }
218 
219  if (include_spectator) {
220  if (widget == WID_TN_COMPANIES) {
222  *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached());
223  } else {
224  *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached());
225  }
226  } else {
227  *list->Append() = new DropDownListStringItem(STR_NETWORK_TOOLBAR_LIST_SPECTATOR, CTMN_SPECTATOR, false);
228  }
229  }
230  }
231 #endif /* ENABLE_NETWORK */
232 
233  for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
234  if (!Company::IsValidID(c)) continue;
235  *list->Append() = new DropDownListCompanyItem(c, false, HasBit(grey, c));
236  }
237 
239 }
240 
241 
242 static ToolbarMode _toolbar_mode;
243 
244 static CallBackFunction SelectSignTool()
245 {
246  if (_cursor.sprite == SPR_CURSOR_SIGN) {
247  ResetObjectToPlace();
248  return CBF_NONE;
249  } else {
250  SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
251  return CBF_PLACE_SIGN;
252  }
253 }
254 
255 /* --- Pausing --- */
256 
257 static CallBackFunction ToolbarPauseClick(Window *w)
258 {
259  if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
260 
262  if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
263  }
264  return CBF_NONE;
265 }
266 
274 {
275  _fast_forward ^= true;
276  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
277  return CBF_NONE;
278 }
279 
284  OME_GAMEOPTIONS,
285  OME_SETTINGS,
286  OME_SCRIPT_SETTINGS,
287  OME_NEWGRFSETTINGS,
288  OME_TRANSPARENCIES,
289  OME_SHOW_TOWNNAMES,
290  OME_SHOW_STATIONNAMES,
291  OME_SHOW_WAYPOINTNAMES,
292  OME_SHOW_SIGNS,
293  OME_SHOW_COMPETITOR_SIGNS,
294  OME_FULL_ANIMATION,
295  OME_FULL_DETAILS,
296  OME_TRANSPARENTBUILDINGS,
297  OME_SHOW_STATIONSIGNS,
298 };
299 
307 {
308  DropDownList *list = new DropDownList();
309  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false);
310  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false);
311  /* Changes to the per-AI settings don't get send from the server to the clients. Clients get
312  * the settings once they join but never update it. As such don't show the window at all
313  * to network clients. */
314  if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false);
315  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false);
316  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false);
317  *list->Append() = new DropDownListItem(-1, false);
318  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES));
319  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES));
320  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES));
321  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS));
322  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS));
323  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION));
324  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL));
325  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES));
326  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS));
327 
328  ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true);
329  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
330  return CBF_NONE;
331 }
332 
340 {
341  switch (index) {
342  case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE;
343  case OME_SETTINGS: ShowGameSettings(); return CBF_NONE;
344  case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE;
345  case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
346  case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break;
347 
348  case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break;
349  case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break;
350  case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break;
351  case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break;
352  case OME_SHOW_COMPETITOR_SIGNS:
355  break;
356  case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break;
357  case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break;
358  case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break;
359  case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break;
360  }
362  return CBF_NONE;
363 }
364 
369  SLEME_SAVE_SCENARIO = 0,
370  SLEME_LOAD_SCENARIO,
371  SLEME_SAVE_HEIGHTMAP,
372  SLEME_LOAD_HEIGHTMAP,
373  SLEME_EXIT_TOINTRO,
374  SLEME_EXIT_GAME = 6,
375  SLEME_MENUCOUNT,
376 };
377 
382  SLNME_SAVE_GAME = 0,
383  SLNME_LOAD_GAME,
384  SLNME_EXIT_TOINTRO,
385  SLNME_EXIT_GAME = 4,
386  SLNME_MENUCOUNT,
387 };
388 
396 {
397  PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT);
398  return CBF_NONE;
399 }
400 
408 {
409  PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT);
410  return CBF_NONE;
411 }
412 
419 static CallBackFunction MenuClickSaveLoad(int index = 0)
420 {
421  if (_game_mode == GM_EDITOR) {
422  switch (index) {
423  case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break;
424  case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
425  case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(SLD_SAVE_HEIGHTMAP); break;
426  case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
427  case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break;
428  case SLEME_EXIT_GAME: HandleExitGameRequest(); break;
429  }
430  } else {
431  switch (index) {
432  case SLNME_SAVE_GAME: ShowSaveLoadDialog(SLD_SAVE_GAME); break;
433  case SLNME_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
434  case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break;
435  case SLNME_EXIT_GAME: HandleExitGameRequest(); break;
436  }
437  }
438  return CBF_NONE;
439 }
440 
441 /* --- Map button menu --- */
442 
443 enum MapMenuEntries {
444  MME_SHOW_SMALLMAP = 0,
445  MME_SHOW_EXTRAVIEWPORTS,
446  MME_SHOW_LINKGRAPH,
447  MME_SHOW_SIGNLISTS,
448  MME_SHOW_TOWNDIRECTORY,
449  MME_SHOW_INDUSTRYDIRECTORY,
450 };
451 
452 static CallBackFunction ToolbarMapClick(Window *w)
453 {
454  DropDownList *list = new DropDownList();
455  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false);
456  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false);
457  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false);
458  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false);
460  return CBF_NONE;
461 }
462 
463 static CallBackFunction ToolbarScenMapTownDir(Window *w)
464 {
465  DropDownList *list = new DropDownList();
466  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false);
467  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false);
468  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false);
469  *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false);
470  *list->Append() = new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false);
472  return CBF_NONE;
473 }
474 
482 {
483  switch (index) {
484  case MME_SHOW_SMALLMAP: ShowSmallMap(); break;
485  case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewPortWindow(); break;
486  case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break;
487  case MME_SHOW_SIGNLISTS: ShowSignList(); break;
488  case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
489  case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break;
490  }
491  return CBF_NONE;
492 }
493 
494 /* --- Town button menu --- */
495 
496 static CallBackFunction ToolbarTownClick(Window *w)
497 {
498  PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
499  return CBF_NONE;
500 }
501 
509 {
510  switch (index) {
511  case 0: ShowTownDirectory(); break;
512  case 1: // setting could be changed when the dropdown was open
513  if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
514  break;
515  }
516  return CBF_NONE;
517 }
518 
519 /* --- Subidies button menu --- */
520 
521 static CallBackFunction ToolbarSubsidiesClick(Window *w)
522 {
523  PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1);
524  return CBF_NONE;
525 }
526 
534 {
535  switch (index) {
536  case 0: ShowSubsidiesList(); break;
537  }
538  return CBF_NONE;
539 }
540 
541 /* --- Stations button menu --- */
542 
543 static CallBackFunction ToolbarStationsClick(Window *w)
544 {
546  return CBF_NONE;
547 }
548 
556 {
558  return CBF_NONE;
559 }
560 
561 /* --- Finances button menu --- */
562 
563 static CallBackFunction ToolbarFinancesClick(Window *w)
564 {
566  return CBF_NONE;
567 }
568 
576 {
578  return CBF_NONE;
579 }
580 
581 /* --- Company's button menu --- */
582 
583 static CallBackFunction ToolbarCompaniesClick(Window *w)
584 {
586  return CBF_NONE;
587 }
588 
596 {
597 #ifdef ENABLE_NETWORK
598  if (_networking) {
599  switch (index) {
600  case CTMN_CLIENT_LIST:
601  ShowClientList();
602  return CBF_NONE;
603 
604  case CTMN_NEW_COMPANY:
605  if (_network_server) {
607  } else {
608  NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company);
609  }
610  return CBF_NONE;
611 
612  case CTMN_SPECTATE:
613  if (_network_server) {
616  } else {
618  }
619  return CBF_NONE;
620  }
621  }
622 #endif /* ENABLE_NETWORK */
623  ShowCompany((CompanyID)index);
624  return CBF_NONE;
625 }
626 
627 /* --- Story button menu --- */
628 
629 static CallBackFunction ToolbarStoryClick(Window *w)
630 {
632  return CBF_NONE;
633 }
634 
642 {
644  return CBF_NONE;
645 }
646 
647 /* --- Goal button menu --- */
648 
649 static CallBackFunction ToolbarGoalClick(Window *w)
650 {
652  return CBF_NONE;
653 }
654 
662 {
664  return CBF_NONE;
665 }
666 
667 /* --- Graphs button menu --- */
668 
669 static CallBackFunction ToolbarGraphsClick(Window *w)
670 {
671  PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8);
672  return CBF_NONE;
673 }
674 
682 {
683  switch (index) {
684  case 0: ShowOperatingProfitGraph(); break;
685  case 1: ShowIncomeGraph(); break;
686  case 2: ShowDeliveredCargoGraph(); break;
687  case 3: ShowPerformanceHistoryGraph(); break;
688  case 4: ShowCompanyValueGraph(); break;
689  case 5: ShowCargoPaymentRates(); break;
690  /* functions for combined graphs/league button */
691  case 6: ShowCompanyLeagueTable(); break;
692  case 7: ShowPerformanceRatingDetail(); break;
693  }
694  return CBF_NONE;
695 }
696 
697 /* --- League button menu --- */
698 
699 static CallBackFunction ToolbarLeagueClick(Window *w)
700 {
701  PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3);
702  return CBF_NONE;
703 }
704 
712 {
713  switch (index) {
714  case 0: ShowCompanyLeagueTable(); break;
715  case 1: ShowPerformanceRatingDetail(); break;
716  case 2: ShowHighscoreTable(); break;
717  }
718  return CBF_NONE;
719 }
720 
721 /* --- Industries button menu --- */
722 
723 static CallBackFunction ToolbarIndustryClick(Window *w)
724 {
725  /* Disable build-industry menu if we are a spectator */
726  PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3);
727  return CBF_NONE;
728 }
729 
737 {
738  switch (index) {
739  case 0: ShowIndustryDirectory(); break;
740  case 1: ShowIndustryCargoesWindow(); break;
741  case 2: ShowBuildIndustryWindow(); break;
742  }
743  return CBF_NONE;
744 }
745 
746 /* --- Trains button menu + 1 helper function for all vehicles. --- */
747 
748 static void ToolbarVehicleClick(Window *w, VehicleType veh)
749 {
750  const Vehicle *v;
751  int dis = ~0;
752 
753  FOR_ALL_VEHICLES(v) {
754  if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner);
755  }
757 }
758 
759 
760 static CallBackFunction ToolbarTrainClick(Window *w)
761 {
762  ToolbarVehicleClick(w, VEH_TRAIN);
763  return CBF_NONE;
764 }
765 
773 {
774  ShowVehicleListWindow((CompanyID)index, VEH_TRAIN);
775  return CBF_NONE;
776 }
777 
778 /* --- Road vehicle button menu --- */
779 
780 static CallBackFunction ToolbarRoadClick(Window *w)
781 {
782  ToolbarVehicleClick(w, VEH_ROAD);
783  return CBF_NONE;
784 }
785 
793 {
794  ShowVehicleListWindow((CompanyID)index, VEH_ROAD);
795  return CBF_NONE;
796 }
797 
798 /* --- Ship button menu --- */
799 
800 static CallBackFunction ToolbarShipClick(Window *w)
801 {
802  ToolbarVehicleClick(w, VEH_SHIP);
803  return CBF_NONE;
804 }
805 
813 {
814  ShowVehicleListWindow((CompanyID)index, VEH_SHIP);
815  return CBF_NONE;
816 }
817 
818 /* --- Aircraft button menu --- */
819 
820 static CallBackFunction ToolbarAirClick(Window *w)
821 {
822  ToolbarVehicleClick(w, VEH_AIRCRAFT);
823  return CBF_NONE;
824 }
825 
833 {
834  ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT);
835  return CBF_NONE;
836 }
837 
838 /* --- Zoom in button --- */
839 
840 static CallBackFunction ToolbarZoomInClick(Window *w)
841 {
843  w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN);
844  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
845  }
846  return CBF_NONE;
847 }
848 
849 /* --- Zoom out button --- */
850 
851 static CallBackFunction ToolbarZoomOutClick(Window *w)
852 {
854  w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT);
855  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
856  }
857  return CBF_NONE;
858 }
859 
860 /* --- Rail button menu --- */
861 
862 static CallBackFunction ToolbarBuildRailClick(Window *w)
863 {
864  ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true);
865  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
866  return CBF_NONE;
867 }
868 
876 {
877  _last_built_railtype = (RailType)index;
878  ShowBuildRailToolbar(_last_built_railtype);
879  return CBF_NONE;
880 }
881 
882 /* --- Road button menu --- */
883 
884 static CallBackFunction ToolbarBuildRoadClick(Window *w)
885 {
886  const Company *c = Company::Get(_local_company);
887  DropDownList *list = new DropDownList();
888 
889  /* Road is always visible and available. */
890  *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false);
891 
892  /* Tram is only visible when there will be a tram, and available when that has been introduced. */
893  Engine *e;
894  FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
895  if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
896  if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
897 
898  *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM));
899  break;
900  }
901  ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true);
902  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
903  return CBF_NONE;
904 }
905 
913 {
914  _last_built_roadtype = (RoadType)index;
915  ShowBuildRoadToolbar(_last_built_roadtype);
916  return CBF_NONE;
917 }
918 
919 /* --- Water button menu --- */
920 
921 static CallBackFunction ToolbarBuildWaterClick(Window *w)
922 {
923  PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1);
924  return CBF_NONE;
925 }
926 
934 {
936  return CBF_NONE;
937 }
938 
939 /* --- Airport button menu --- */
940 
941 static CallBackFunction ToolbarBuildAirClick(Window *w)
942 {
943  PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1);
944  return CBF_NONE;
945 }
946 
954 {
956  return CBF_NONE;
957 }
958 
959 /* --- Forest button menu --- */
960 
961 static CallBackFunction ToolbarForestClick(Window *w)
962 {
963  PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3);
964  return CBF_NONE;
965 }
966 
974 {
975  switch (index) {
976  case 0: ShowTerraformToolbar(); break;
977  case 1: ShowBuildTreesToolbar(); break;
978  case 2: return SelectSignTool();
979  }
980  return CBF_NONE;
981 }
982 
983 /* --- Music button menu --- */
984 
985 static CallBackFunction ToolbarMusicClick(Window *w)
986 {
987  PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1);
988  return CBF_NONE;
989 }
990 
998 {
999  ShowMusicWindow();
1000  return CBF_NONE;
1001 }
1002 
1003 /* --- Newspaper button menu --- */
1004 
1005 static CallBackFunction ToolbarNewspaperClick(Window *w)
1006 {
1007  PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 2);
1008  return CBF_NONE;
1009 }
1010 
1018 {
1019  switch (index) {
1020  case 0: ShowLastNewsMessage(); break;
1021  case 1: ShowMessageHistory(); break;
1022  }
1023  return CBF_NONE;
1024 }
1025 
1026 /* --- Help button menu --- */
1027 
1028 static CallBackFunction PlaceLandBlockInfo()
1029 {
1030  if (_cursor.sprite == SPR_CURSOR_QUERY) {
1031  ResetObjectToPlace();
1032  return CBF_NONE;
1033  } else {
1034  SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
1035  return CBF_PLACE_LANDINFO;
1036  }
1037 }
1038 
1039 static CallBackFunction ToolbarHelpClick(Window *w)
1040 {
1041  PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 9);
1042  return CBF_NONE;
1043 }
1044 
1045 static void MenuClickSmallScreenshot()
1046 {
1047  MakeScreenshot(SC_VIEWPORT, NULL);
1048 }
1049 
1055 static void ScreenshotConfirmCallback(Window *w, bool confirmed)
1056 {
1057  if (confirmed) MakeScreenshot(_confirmed_screenshot_type, NULL);
1058 }
1059 
1066 {
1067  ViewPort vp;
1068  SetupScreenshotViewport(t, &vp);
1069  if ((uint64)vp.width * (uint64)vp.height > 8192 * 8192) {
1070  /* Ask for confirmation */
1071  SetDParam(0, vp.width);
1072  SetDParam(1, vp.height);
1074  ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, NULL, ScreenshotConfirmCallback);
1075  } else {
1076  /* Less than 64M pixels, just do it */
1077  MakeScreenshot(t, NULL);
1078  }
1079 }
1080 
1089 {
1090  extern bool _draw_bounding_boxes;
1091  /* Always allow to toggle them off */
1092  if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) {
1093  _draw_bounding_boxes = !_draw_bounding_boxes;
1095  }
1096 }
1097 
1106 {
1107  extern bool _draw_dirty_blocks;
1108  /* Always allow to toggle them off */
1109  if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) {
1110  _draw_dirty_blocks = !_draw_dirty_blocks;
1112  }
1113 }
1114 
1120 {
1123  /* If you open a savegame as scenario there may already be link graphs.*/
1125  SetDate(new_date, 0);
1126 }
1127 
1134 {
1135  switch (index) {
1136  case 0: return PlaceLandBlockInfo();
1137  case 2: IConsoleSwitch(); break;
1138  case 3: ShowAIDebugWindow(); break;
1139  case 4: MenuClickSmallScreenshot(); break;
1142  case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break;
1143  case 8: ShowAboutWindow(); break;
1144  case 9: ShowSpriteAlignerWindow(); break;
1145  case 10: ToggleBoundingBoxes(); break;
1146  case 11: ToggleDirtyBlocks(); break;
1147  }
1148  return CBF_NONE;
1149 }
1150 
1151 /* --- Switch toolbar button --- */
1152 
1153 static CallBackFunction ToolbarSwitchClick(Window *w)
1154 {
1155  if (_toolbar_mode != TB_LOWER) {
1156  _toolbar_mode = TB_LOWER;
1157  } else {
1158  _toolbar_mode = TB_UPPER;
1159  }
1160 
1161  w->ReInit();
1162  w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
1163  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1164  return CBF_NONE;
1165 }
1166 
1167 /* --- Scenario editor specific handlers. */
1168 
1173 {
1175  ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
1176  _left_button_clicked = false;
1177  return CBF_NONE;
1178 }
1179 
1180 static CallBackFunction ToolbarScenDateBackward(Window *w)
1181 {
1182  /* don't allow too fast scrolling */
1183  if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1185  w->SetDirty();
1186 
1188  }
1189  _left_button_clicked = false;
1190  return CBF_NONE;
1191 }
1192 
1193 static CallBackFunction ToolbarScenDateForward(Window *w)
1194 {
1195  /* don't allow too fast scrolling */
1196  if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1198  w->SetDirty();
1199 
1201  }
1202  _left_button_clicked = false;
1203  return CBF_NONE;
1204 }
1205 
1206 static CallBackFunction ToolbarScenGenLand(Window *w)
1207 {
1209  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1210 
1212  return CBF_NONE;
1213 }
1214 
1215 
1216 static CallBackFunction ToolbarScenGenTown(Window *w)
1217 {
1219  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1220  ShowFoundTownWindow();
1221  return CBF_NONE;
1222 }
1223 
1224 static CallBackFunction ToolbarScenGenIndustry(Window *w)
1225 {
1227  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1228  ShowBuildIndustryWindow();
1229  return CBF_NONE;
1230 }
1231 
1232 static CallBackFunction ToolbarScenBuildRoad(Window *w)
1233 {
1235  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1237  return CBF_NONE;
1238 }
1239 
1240 static CallBackFunction ToolbarScenBuildDocks(Window *w)
1241 {
1243  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1245  return CBF_NONE;
1246 }
1247 
1248 static CallBackFunction ToolbarScenPlantTrees(Window *w)
1249 {
1251  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1252  ShowBuildTreesToolbar();
1253  return CBF_NONE;
1254 }
1255 
1256 static CallBackFunction ToolbarScenPlaceSign(Window *w)
1257 {
1259  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1260  return SelectSignTool();
1261 }
1262 
1263 static CallBackFunction ToolbarBtn_NULL(Window *w)
1264 {
1265  return CBF_NONE;
1266 }
1267 
1268 typedef CallBackFunction MenuClickedProc(int index);
1269 
1270 static MenuClickedProc * const _menu_clicked_procs[] = {
1271  NULL, // 0
1272  NULL, // 1
1273  MenuClickSettings, // 2
1274  MenuClickSaveLoad, // 3
1275  MenuClickMap, // 4
1276  MenuClickTown, // 5
1277  MenuClickSubsidies, // 6
1278  MenuClickStations, // 7
1279  MenuClickFinances, // 8
1280  MenuClickCompany, // 9
1281  MenuClickStory, // 10
1282  MenuClickGoal, // 11
1283  MenuClickGraphs, // 12
1284  MenuClickLeague, // 13
1285  MenuClickIndustry, // 14
1286  MenuClickShowTrains, // 15
1287  MenuClickShowRoad, // 16
1288  MenuClickShowShips, // 17
1289  MenuClickShowAir, // 18
1290  MenuClickMap, // 19
1291  NULL, // 20
1292  MenuClickBuildRail, // 21
1293  MenuClickBuildRoad, // 22
1294  MenuClickBuildWater, // 23
1295  MenuClickBuildAir, // 24
1296  MenuClickForest, // 25
1297  MenuClickMusicWindow, // 26
1298  MenuClickNewspaper, // 27
1299  MenuClickHelp, // 28
1300 };
1301 
1305 protected:
1306  uint spacers;
1307 
1308 public:
1310  {
1311  }
1312 
1319  {
1320  return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN;
1321  }
1322 
1323  void SetupSmallestSize(Window *w, bool init_array)
1324  {
1325  this->smallest_x = 0; // Biggest child
1326  this->smallest_y = 0; // Biggest child
1327  this->fill_x = 1;
1328  this->fill_y = 0;
1329  this->resize_x = 1; // We only resize in this direction
1330  this->resize_y = 0; // We never resize in this direction
1331  this->spacers = 0;
1332 
1333  uint nbuttons = 0;
1334  /* First initialise some variables... */
1335  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1336  child_wid->SetupSmallestSize(w, init_array);
1337  this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
1338  if (this->IsButton(child_wid->type)) {
1339  nbuttons++;
1340  this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
1341  } else if (child_wid->type == NWID_SPACER) {
1342  this->spacers++;
1343  }
1344  }
1345 
1346  /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */
1347  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1348  child_wid->current_y = this->smallest_y;
1349  if (!this->IsButton(child_wid->type)) {
1350  child_wid->current_x = child_wid->smallest_x;
1351  }
1352  }
1353  w->window_desc->default_width = nbuttons * this->smallest_x;
1354  }
1355 
1356  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
1357  {
1358  assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
1359 
1360  this->pos_x = x;
1361  this->pos_y = y;
1362  this->current_x = given_width;
1363  this->current_y = given_height;
1364 
1365  /* Figure out what are the visible buttons */
1366  memset(this->visible, 0, sizeof(this->visible));
1367  uint arrangable_count, button_count, spacer_count;
1368  const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count);
1369  for (uint i = 0; i < arrangable_count; i++) {
1370  this->visible[arrangement[i]] = true;
1371  }
1372 
1373  /* Create us ourselves a quick lookup table */
1374  NWidgetBase *widgets[WID_TN_END];
1375  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1376  if (child_wid->type == NWID_SPACER) continue;
1377  widgets[((NWidgetCore*)child_wid)->index] = child_wid;
1378  }
1379 
1380  /* Now assign the widgets to their rightful place */
1381  uint position = 0; // Place to put next child relative to origin of the container.
1382  uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets
1383  uint button_space = given_width - spacer_space; // Remaining spacing for the buttons
1384  uint spacer_i = 0;
1385  uint button_i = 0;
1386 
1387  /* Index into the arrangement indices. The macro lastof cannot be used here! */
1388  const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement;
1389  for (uint i = 0; i < arrangable_count; i++) {
1390  NWidgetBase *child_wid = widgets[*cur_wid];
1391  /* If we have to give space to the spacers, do that */
1392  if (spacer_space != 0) {
1393  NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev;
1394  if (possible_spacer != NULL && possible_spacer->type == NWID_SPACER) {
1395  uint add = spacer_space / (spacer_count - spacer_i);
1396  position += add;
1397  spacer_space -= add;
1398  spacer_i++;
1399  }
1400  }
1401 
1402  /* Buttons can be scaled, the others not. */
1403  if (this->IsButton(child_wid->type)) {
1404  child_wid->current_x = button_space / (button_count - button_i);
1405  button_space -= child_wid->current_x;
1406  button_i++;
1407  }
1408  child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
1409  position += child_wid->current_x;
1410 
1411  if (rtl) {
1412  cur_wid--;
1413  } else {
1414  cur_wid++;
1415  }
1416  }
1417  }
1418 
1419  /* virtual */ void Draw(const Window *w)
1420  {
1421  /* Draw brown-red toolbar bg. */
1422  GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_VERY_DARK_RED);
1423  GfxFillRect(this->pos_x, this->pos_y, this->pos_x + this->current_x - 1, this->pos_y + this->current_y - 1, PC_DARK_RED, FILLRECT_CHECKER);
1424 
1425  bool rtl = _current_text_dir == TD_RTL;
1426  for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != NULL; child_wid = rtl ? child_wid->prev : child_wid->next) {
1427  if (child_wid->type == NWID_SPACER) continue;
1428  if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1429 
1430  child_wid->Draw(w);
1431  }
1432  }
1433 
1434  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y)
1435  {
1436  if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
1437 
1438  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1439  if (child_wid->type == NWID_SPACER) continue;
1440  if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1441 
1442  NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
1443  if (nwid != NULL) return nwid;
1444  }
1445  return NULL;
1446  }
1447 
1456  virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0;
1457 };
1458 
1461  /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
1462  {
1463  static const uint SMALLEST_ARRANGEMENT = 14;
1464  static const uint BIGGEST_ARRANGEMENT = 20;
1465  static const byte arrange14[] = {
1466  0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29,
1467  2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29,
1468  };
1469  static const byte arrange15[] = {
1470  0, 1, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
1471  0, 2, 4, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29,
1472  };
1473  static const byte arrange16[] = {
1474  0, 1, 2, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
1475  0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29,
1476  };
1477  static const byte arrange17[] = {
1478  0, 1, 2, 4, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
1479  0, 1, 3, 4, 6, 5, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29,
1480  };
1481  static const byte arrange18[] = {
1482  0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29,
1483  0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29,
1484  };
1485  static const byte arrange19[] = {
1486  0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29,
1487  0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29,
1488  };
1489  static const byte arrange20[] = {
1490  0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29,
1491  0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29,
1492  };
1493  static const byte arrange_all[] = {
1494  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28
1495  };
1496 
1497  /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
1498  uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
1499  if (full_buttons > BIGGEST_ARRANGEMENT) {
1500  button_count = arrangable_count = lengthof(arrange_all);
1501  spacer_count = this->spacers;
1502  return arrange_all;
1503  }
1504 
1505  /* Introduce the split toolbar */
1506  static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
1507 
1508  button_count = arrangable_count = full_buttons;
1509  spacer_count = this->spacers;
1510  return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
1511  }
1512 };
1513 
1516  uint panel_widths[2];
1517 
1518  void SetupSmallestSize(Window *w, bool init_array)
1519  {
1520  this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array);
1521 
1522  /* Find the size of panel_widths */
1523  uint i = 0;
1524  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1525  if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
1526 
1527  assert(i < lengthof(this->panel_widths));
1528  this->panel_widths[i++] = child_wid->current_x;
1529  w->window_desc->default_width += child_wid->current_x;
1530  }
1531  }
1532 
1533  /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
1534  {
1535  static const byte arrange_all[] = {
1536  0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
1537  };
1538  static const byte arrange_nopanel[] = {
1539  0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
1540  };
1541  static const byte arrange_switch[] = {
1542  18, 8, 11, 12, 13, 14, 15, 16, 17, 29,
1543  0, 1, 2, 3, 18, 9, 10, 26, 28, 29,
1544  };
1545 
1546  /* If we can place all buttons *and* the panels, show them. */
1547  uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
1548  if (width >= min_full_width) {
1549  width -= this->panel_widths[0] + this->panel_widths[1];
1550  arrangable_count = lengthof(arrange_all);
1551  button_count = arrangable_count - 2;
1552  spacer_count = this->spacers;
1553  return arrange_all;
1554  }
1555 
1556  /* Otherwise don't show the date panel and if we can't fit half the buttons and the panels anymore, split the toolbar in two */
1557  uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
1558  if (width > min_small_width) {
1559  width -= this->panel_widths[1];
1560  arrangable_count = lengthof(arrange_nopanel);
1561  button_count = arrangable_count - 1;
1562  spacer_count = this->spacers - 1;
1563  return arrange_nopanel;
1564  }
1565 
1566  /* Split toolbar */
1567  width -= this->panel_widths[1];
1568  arrangable_count = lengthof(arrange_switch) / 2;
1569  button_count = arrangable_count - 1;
1570  spacer_count = 0;
1571  return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
1572  }
1573 };
1574 
1575 /* --- Toolbar handling for the 'normal' case */
1576 
1577 typedef CallBackFunction ToolbarButtonProc(Window *w);
1578 
1579 static ToolbarButtonProc * const _toolbar_button_procs[] = {
1580  ToolbarPauseClick,
1584  ToolbarMapClick,
1585  ToolbarTownClick,
1586  ToolbarSubsidiesClick,
1587  ToolbarStationsClick,
1588  ToolbarFinancesClick,
1589  ToolbarCompaniesClick,
1590  ToolbarStoryClick,
1591  ToolbarGoalClick,
1592  ToolbarGraphsClick,
1593  ToolbarLeagueClick,
1594  ToolbarIndustryClick,
1595  ToolbarTrainClick,
1596  ToolbarRoadClick,
1597  ToolbarShipClick,
1598  ToolbarAirClick,
1599  ToolbarZoomInClick,
1600  ToolbarZoomOutClick,
1601  ToolbarBuildRailClick,
1602  ToolbarBuildRoadClick,
1603  ToolbarBuildWaterClick,
1604  ToolbarBuildAirClick,
1605  ToolbarForestClick,
1606  ToolbarMusicClick,
1607  ToolbarNewspaperClick,
1608  ToolbarHelpClick,
1609  ToolbarSwitchClick,
1610 };
1611 
1612 enum MainToolbarHotkeys {
1613  MTHK_PAUSE,
1614  MTHK_FASTFORWARD,
1615  MTHK_SETTINGS,
1616  MTHK_SAVEGAME,
1617  MTHK_LOADGAME,
1618  MTHK_SMALLMAP,
1619  MTHK_TOWNDIRECTORY,
1620  MTHK_SUBSIDIES,
1621  MTHK_STATIONS,
1622  MTHK_FINANCES,
1623  MTHK_COMPANIES,
1624  MTHK_STORY,
1625  MTHK_GOAL,
1626  MTHK_GRAPHS,
1627  MTHK_LEAGUE,
1628  MTHK_INDUSTRIES,
1629  MTHK_TRAIN_LIST,
1630  MTHK_ROADVEH_LIST,
1631  MTHK_SHIP_LIST,
1632  MTHK_AIRCRAFT_LIST,
1633  MTHK_ZOOM_IN,
1634  MTHK_ZOOM_OUT,
1635  MTHK_BUILD_RAIL,
1636  MTHK_BUILD_ROAD,
1637  MTHK_BUILD_DOCKS,
1638  MTHK_BUILD_AIRPORT,
1639  MTHK_BUILD_TREES,
1640  MTHK_MUSIC,
1641  MTHK_AI_DEBUG,
1642  MTHK_SMALL_SCREENSHOT,
1643  MTHK_ZOOMEDIN_SCREENSHOT,
1644  MTHK_DEFAULTZOOM_SCREENSHOT,
1645  MTHK_GIANT_SCREENSHOT,
1646  MTHK_CHEATS,
1647  MTHK_TERRAFORM,
1648  MTHK_EXTRA_VIEWPORT,
1649  MTHK_CLIENT_LIST,
1650  MTHK_SIGN_LIST,
1651 };
1652 
1656 
1657  MainToolbarWindow(WindowDesc *desc) : Window(desc)
1658  {
1659  this->InitNested(0);
1660 
1661  this->last_started_action = CBF_NONE;
1662  CLRBITS(this->flags, WF_WHITE_BORDER);
1663  this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
1664  this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
1665  PositionMainToolbar(this);
1667  }
1668 
1669  virtual void OnPaint()
1670  {
1671  /* If spectator, disable all construction buttons
1672  * ie : Build road, rail, ships, airports and landscaping
1673  * Since enabled state is the default, just disable when needed */
1675  /* disable company list drop downs, if there are no companies */
1677 
1680 
1683 
1684  this->DrawWidgets();
1685  }
1686 
1687  virtual void OnClick(Point pt, int widget, int click_count)
1688  {
1689  if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
1690  }
1691 
1692  virtual void OnDropdownSelect(int widget, int index)
1693  {
1694  CallBackFunction cbf = _menu_clicked_procs[widget](index);
1695  if (cbf != CBF_NONE) this->last_started_action = cbf;
1696  }
1697 
1698  virtual EventState OnHotkey(int hotkey)
1699  {
1700  switch (hotkey) {
1701  case MTHK_PAUSE: ToolbarPauseClick(this); break;
1702  case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
1703  case MTHK_SETTINGS: ShowGameOptions(); break;
1704  case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
1705  case MTHK_LOADGAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
1706  case MTHK_SMALLMAP: ShowSmallMap(); break;
1707  case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
1708  case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
1709  case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
1710  case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
1711  case MTHK_COMPANIES: ShowCompany(_local_company); break;
1712  case MTHK_STORY: ShowStoryBook(_local_company); break;
1713  case MTHK_GOAL: ShowGoalsList(_local_company); break;
1714  case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
1715  case MTHK_LEAGUE: ShowCompanyLeagueTable(); break;
1716  case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
1717  case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
1718  case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
1719  case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
1720  case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
1721  case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
1722  case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
1723  case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break;
1724  case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
1725  case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
1726  case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
1727  case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
1728  case MTHK_MUSIC: ShowMusicWindow(); break;
1729  case MTHK_AI_DEBUG: ShowAIDebugWindow(); break;
1730  case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
1731  case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
1732  case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
1733  case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
1734  case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
1735  case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
1736  case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
1737 #ifdef ENABLE_NETWORK
1738  case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
1739 #endif
1740  case MTHK_SIGN_LIST: ShowSignList(); break;
1741  default: return ES_NOT_HANDLED;
1742  }
1743  return ES_HANDLED;
1744  }
1745 
1746  virtual void OnPlaceObject(Point pt, TileIndex tile)
1747  {
1748  switch (this->last_started_action) {
1749  case CBF_PLACE_SIGN:
1750  PlaceProc_Sign(tile);
1751  break;
1752 
1753  case CBF_PLACE_LANDINFO:
1754  ShowLandInfo(tile);
1755  break;
1756 
1757  default: NOT_REACHED();
1758  }
1759  }
1760 
1761  virtual void OnTick()
1762  {
1763  if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
1766  }
1767 
1768  if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) {
1771  }
1772  }
1773 
1774  virtual void OnTimeout()
1775  {
1776  /* We do not want to automatically raise the pause, fast forward and
1777  * switchbar buttons; they have to stay down when pressed etc. */
1778  for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
1779  if (this->IsWidgetLowered(i)) {
1780  this->RaiseWidget(i);
1781  this->SetWidgetDirty(i);
1782  }
1783  }
1784  }
1785 
1791  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
1792  {
1793  if (!gui_scope) return;
1795  }
1796 
1797  static HotkeyList hotkeys;
1798 };
1799 
1800 const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0};
1801 const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0};
1802 const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0};
1803 const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0};
1804 
1805 static Hotkey maintoolbar_hotkeys[] = {
1806  Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE),
1807  Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD),
1808  Hotkey(WKC_F2, "settings", MTHK_SETTINGS),
1809  Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME),
1810  Hotkey((uint16)0, "load_game", MTHK_LOADGAME),
1811  Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP),
1812  Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
1813  Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES),
1814  Hotkey(WKC_F7, "station_list", MTHK_STATIONS),
1815  Hotkey(WKC_F8, "finances", MTHK_FINANCES),
1816  Hotkey(WKC_F9, "companies", MTHK_COMPANIES),
1817  Hotkey((uint16)0, "story_book", MTHK_STORY),
1818  Hotkey((uint16)0, "goal_list", MTHK_GOAL),
1819  Hotkey(WKC_F10, "graphs", MTHK_GRAPHS),
1820  Hotkey(WKC_F11, "league", MTHK_LEAGUE),
1821  Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES),
1822  Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
1823  Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
1824  Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
1825  Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
1826  Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN),
1827  Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT),
1828  Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
1829  Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
1830  Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
1831  Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
1832  Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
1833  Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
1834  Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG),
1835  Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
1836  Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
1837  Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT),
1838  Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
1839  Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
1840  Hotkey('L', "terraform", MTHK_TERRAFORM),
1841  Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
1842 #ifdef ENABLE_NETWORK
1843  Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
1844 #endif
1845  Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
1846  HOTKEY_LIST_END
1847 };
1848 HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
1849 
1850 static NWidgetBase *MakeMainToolbar(int *biggest_index)
1851 {
1853  static const SpriteID toolbar_button_sprites[] = {
1854  SPR_IMG_PAUSE, // WID_TN_PAUSE
1855  SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD
1856  SPR_IMG_SETTINGS, // WID_TN_SETTINGS
1857  SPR_IMG_SAVE, // WID_TN_SAVE
1858  SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP
1859  SPR_IMG_TOWN, // WID_TN_TOWNS
1860  SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES
1861  SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS
1862  SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
1863  SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
1864  SPR_IMG_STORY_BOOK, // WID_TN_STORY
1865  SPR_IMG_GOAL, // WID_TN_GOAL
1866  SPR_IMG_GRAPHS, // WID_TN_GRAPHS
1867  SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE
1868  SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES
1869  SPR_IMG_TRAINLIST, // WID_TN_TRAINS
1870  SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS
1871  SPR_IMG_SHIPLIST, // WID_TN_SHIPS
1872  SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT
1873  SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN
1874  SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT
1875  SPR_IMG_BUILDRAIL, // WID_TN_RAILS
1876  SPR_IMG_BUILDROAD, // WID_TN_ROADS
1877  SPR_IMG_BUILDWATER, // WID_TN_WATER
1878  SPR_IMG_BUILDAIR, // WID_TN_AIR
1879  SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
1880  SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
1881  SPR_IMG_MESSAGES, // WID_TN_MESSAGES
1882  SPR_IMG_QUERY, // WID_TN_HELP
1883  SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
1884  };
1885 
1887  for (uint i = 0; i < WID_TN_END; i++) {
1888  switch (i) {
1889  case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break;
1890  }
1891  hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i));
1892  }
1893 
1894  *biggest_index = max<int>(*biggest_index, WID_TN_SWITCH_BAR);
1895  return hor;
1896 }
1897 
1898 static const NWidgetPart _nested_toolbar_normal_widgets[] = {
1900 };
1901 
1902 static WindowDesc _toolb_normal_desc(
1903  WDP_MANUAL, NULL, 640, 22,
1905  WDF_NO_FOCUS,
1906  _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets),
1907  &MainToolbarWindow::hotkeys
1908 );
1909 
1910 
1911 /* --- Toolbar handling for the scenario editor */
1912 
1913 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
1914  ToolbarPauseClick,
1918  ToolbarBtn_NULL,
1920  ToolbarScenDateBackward,
1921  ToolbarScenDateForward,
1922  ToolbarScenMapTownDir,
1923  ToolbarZoomInClick,
1924  ToolbarZoomOutClick,
1925  ToolbarScenGenLand,
1926  ToolbarScenGenTown,
1927  ToolbarScenGenIndustry,
1928  ToolbarScenBuildRoad,
1929  ToolbarScenBuildDocks,
1930  ToolbarScenPlantTrees,
1931  ToolbarScenPlaceSign,
1932  ToolbarBtn_NULL,
1933  NULL,
1934  NULL,
1935  NULL,
1936  NULL,
1937  NULL,
1938  NULL,
1939  NULL,
1940  ToolbarMusicClick,
1941  NULL,
1942  ToolbarHelpClick,
1943  ToolbarSwitchClick,
1944 };
1945 
1946 enum MainToolbarEditorHotkeys {
1947  MTEHK_PAUSE,
1948  MTEHK_FASTFORWARD,
1949  MTEHK_SETTINGS,
1950  MTEHK_SAVEGAME,
1951  MTEHK_GENLAND,
1952  MTEHK_GENTOWN,
1953  MTEHK_GENINDUSTRY,
1954  MTEHK_BUILD_ROAD,
1955  MTEHK_BUILD_DOCKS,
1956  MTEHK_BUILD_TREES,
1957  MTEHK_SIGN,
1958  MTEHK_MUSIC,
1959  MTEHK_LANDINFO,
1960  MTEHK_SMALL_SCREENSHOT,
1961  MTEHK_ZOOMEDIN_SCREENSHOT,
1962  MTEHK_DEFAULTZOOM_SCREENSHOT,
1963  MTEHK_GIANT_SCREENSHOT,
1964  MTEHK_ZOOM_IN,
1965  MTEHK_ZOOM_OUT,
1966  MTEHK_TERRAFORM,
1967  MTEHK_SMALLMAP,
1968  MTEHK_EXTRA_VIEWPORT,
1969 };
1970 
1973 
1975  {
1976  this->InitNested(0);
1977 
1978  this->last_started_action = CBF_NONE;
1979  CLRBITS(this->flags, WF_WHITE_BORDER);
1980  PositionMainToolbar(this);
1982  }
1983 
1984  virtual void OnPaint()
1985  {
1988 
1989  this->DrawWidgets();
1990  }
1991 
1992  virtual void DrawWidget(const Rect &r, int widget) const
1993  {
1994  switch (widget) {
1995  case WID_TE_DATE:
1997  DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER);
1998  break;
1999 
2000  case WID_TE_SPACER: {
2001  int height = r.bottom - r.top;
2002  if (height > 2 * FONT_HEIGHT_NORMAL) {
2003  DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
2004  DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2005  } else {
2006  DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2007  }
2008  break;
2009  }
2010  }
2011  }
2012 
2013  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
2014  {
2015  switch (widget) {
2016  case WID_TE_SPACER:
2017  size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
2018  break;
2019 
2020  case WID_TE_DATE:
2021  SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1));
2022  *size = GetStringBoundingBox(STR_WHITE_DATE_LONG);
2023  size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM);
2024  break;
2025  }
2026  }
2027 
2028  virtual void OnClick(Point pt, int widget, int click_count)
2029  {
2030  if (_game_mode == GM_MENU) return;
2031  CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
2032  if (cbf != CBF_NONE) this->last_started_action = cbf;
2033  }
2034 
2035  virtual void OnDropdownSelect(int widget, int index)
2036  {
2037  /* The map button is in a different location on the scenario
2038  * editor toolbar, so we need to adjust for it. */
2039  if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP;
2040  CallBackFunction cbf = _menu_clicked_procs[widget](index);
2041  if (cbf != CBF_NONE) this->last_started_action = cbf;
2042  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
2043  }
2044 
2045  virtual EventState OnHotkey(int hotkey)
2046  {
2047  CallBackFunction cbf = CBF_NONE;
2048  switch (hotkey) {
2049  case MTEHK_PAUSE: ToolbarPauseClick(this); break;
2050  case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2051  case MTEHK_SETTINGS: ShowGameOptions(); break;
2052  case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
2053  case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
2054  case MTEHK_GENTOWN: ToolbarScenGenTown(this); break;
2055  case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
2056  case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break;
2057  case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break;
2058  case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break;
2059  case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break;
2060  case MTEHK_MUSIC: ShowMusicWindow(); break;
2061  case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2062  case MTEHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
2063  case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
2064  case MTEHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
2065  case MTEHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
2066  case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2067  case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2068  case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break;
2069  case MTEHK_SMALLMAP: ShowSmallMap(); break;
2070  case MTEHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
2071  default: return ES_NOT_HANDLED;
2072  }
2073  if (cbf != CBF_NONE) this->last_started_action = cbf;
2074  return ES_HANDLED;
2075  }
2076 
2077  virtual void OnPlaceObject(Point pt, TileIndex tile)
2078  {
2079  switch (this->last_started_action) {
2080  case CBF_PLACE_SIGN:
2081  PlaceProc_Sign(tile);
2082  break;
2083 
2084  case CBF_PLACE_LANDINFO:
2085  ShowLandInfo(tile);
2086  break;
2087 
2088  default: NOT_REACHED();
2089  }
2090  }
2091 
2092  virtual void OnTimeout()
2093  {
2097  }
2098 
2099  virtual void OnTick()
2100  {
2101  if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
2103  this->SetDirty();
2104  }
2105 
2106  if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) {
2108  this->SetDirty();
2109  }
2110  }
2111 
2117  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2118  {
2119  if (!gui_scope) return;
2121  }
2122 
2123  virtual void OnQueryTextFinished(char *str)
2124  {
2125  /* Was 'cancel' pressed? */
2126  if (str == NULL) return;
2127 
2128  int32 value;
2129  if (!StrEmpty(str)) {
2130  value = atoi(str);
2131  } else {
2132  /* An empty string means revert to the default */
2133  value = DEF_START_YEAR;
2134  }
2135  SetStartingYear(value);
2136 
2137  this->SetDirty();
2138  }
2139 
2140  static HotkeyList hotkeys;
2141 };
2142 
2143 static Hotkey scenedit_maintoolbar_hotkeys[] = {
2144  Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE),
2145  Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD),
2146  Hotkey(WKC_F2, "settings", MTEHK_SETTINGS),
2147  Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME),
2148  Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND),
2149  Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN),
2150  Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
2151  Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
2152  Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
2153  Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
2154  Hotkey(WKC_F10, "build_sign", MTEHK_SIGN),
2155  Hotkey(WKC_F11, "music", MTEHK_MUSIC),
2156  Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO),
2157  Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
2158  Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
2159  Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT),
2160  Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
2161  Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN),
2162  Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT),
2163  Hotkey('L', "terraform", MTEHK_TERRAFORM),
2164  Hotkey('M', "smallmap", MTEHK_SMALLMAP),
2165  Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
2166  HOTKEY_LIST_END
2167 };
2168 HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys);
2169 
2170 static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
2171  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
2172  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
2173  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
2174  NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
2176  NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
2178  NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
2179  NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
2180  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD),
2181  NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE),
2182  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD),
2183  EndContainer(),
2184  EndContainer(),
2186  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
2188  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
2189  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
2191  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
2192  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
2193  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
2194  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
2195  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
2196  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
2197  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
2199  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
2200  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
2201  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
2202 };
2203 
2204 static NWidgetBase *MakeScenarioToolbar(int *biggest_index)
2205 {
2206  return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer());
2207 }
2208 
2209 static const NWidgetPart _nested_toolb_scen_widgets[] = {
2210  NWidgetFunction(MakeScenarioToolbar),
2211 };
2212 
2213 static WindowDesc _toolb_scen_desc(
2214  WDP_MANUAL, NULL, 640, 22,
2216  WDF_NO_FOCUS,
2217  _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets),
2218  &ScenarioEditorToolbarWindow::hotkeys
2219 );
2220 
2223 {
2224  /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
2225  _last_built_roadtype = ROADTYPE_ROAD;
2226 
2227  if (_game_mode == GM_EDITOR) {
2228  new ScenarioEditorToolbarWindow(&_toolb_scen_desc);
2229  } else {
2230  new MainToolbarWindow(&_toolb_normal_desc);
2231  }
2232 }