OpenTTD
toolbar_gui.cpp
Go to the documentation of this file.
1 /* $Id: toolbar_gui.cpp 27626 2016-08-15 18:32:25Z 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 #include "toolbar_gui.h"
50 
51 #include "widgets/toolbar_widget.h"
52 
53 #include "network/network.h"
54 #include "network/network_gui.h"
55 #include "network/network_func.h"
56 
57 #include "safeguards.h"
58 
59 
61 uint _toolbar_width = 0;
62 
63 RailType _last_built_railtype;
64 RoadType _last_built_roadtype;
65 
67 
70  TB_NORMAL,
71  TB_UPPER,
72  TB_LOWER
73 };
74 
77  CBF_NONE,
78  CBF_PLACE_SIGN,
79  CBF_PLACE_LANDINFO,
80 };
81 
83 
84 
89  uint checkmark_width;
90 public:
91  bool checked;
92 
93  DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked)
94  {
95  this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
96  }
97 
98  virtual ~DropDownListCheckedItem() {}
99 
100  uint Width() const
101  {
102  return DropDownListStringItem::Width() + this->checkmark_width;
103  }
104 
105  void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
106  {
107  bool rtl = _current_text_dir == TD_RTL;
108  if (this->checked) {
109  DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK);
110  }
111  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);
112  }
113 };
114 
119  Dimension icon_size;
120 public:
121  bool greyed;
122 
123  DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
124  {
125  this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
126  }
127 
128  virtual ~DropDownListCompanyItem() {}
129 
130  bool Selectable() const
131  {
132  return true;
133  }
134 
135  uint Width() const
136  {
137  CompanyID company = (CompanyID)this->result;
138  SetDParam(0, company);
139  SetDParam(1, company);
140  return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3;
141  }
142 
143  uint Height(uint width) const
144  {
145  return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
146  }
147 
148  void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
149  {
150  CompanyID company = (CompanyID)this->result;
151  bool rtl = _current_text_dir == TD_RTL;
152 
153  /* It's possible the company is deleted while the dropdown is open */
154  if (!Company::IsValidID(company)) return;
155 
156  int icon_offset = (bottom - top - icon_size.height) / 2;
157  int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2;
158 
159  DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset);
160 
161  SetDParam(0, company);
162  SetDParam(1, company);
163  TextColour col;
164  if (this->greyed) {
165  col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
166  } else {
167  col = sel ? TC_WHITE : TC_BLACK;
168  }
169  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);
170  }
171 };
172 
180 static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def)
181 {
182  ShowDropDownList(w, list, def, widget, 0, true, true);
183  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
184 }
185 
193 static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count)
194 {
195  DropDownList *list = new DropDownList();
196  for (int i = 0; i < count; i++) {
197  *list->Append() = new DropDownListStringItem(string + i, i, false);
198  }
199  PopupMainToolbMenu(w, widget, list, 0);
200 }
201 
203 static const int CTMN_CLIENT_LIST = -1;
204 static const int CTMN_NEW_COMPANY = -2;
205 static const int CTMN_SPECTATE = -3;
206 static const int CTMN_SPECTATOR = -4;
207 
215 static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0, bool include_spectator = false)
216 {
217  DropDownList *list = new DropDownList();
218 
219 #ifdef ENABLE_NETWORK
220  if (_networking) {
221  if (widget == WID_TN_COMPANIES) {
222  /* Add the client list button for the companies menu */
223  *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false);
224  }
225 
226  if (include_spectator) {
227  if (widget == WID_TN_COMPANIES) {
229  *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached());
230  } else {
231  *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached());
232  }
233  } else {
234  *list->Append() = new DropDownListStringItem(STR_NETWORK_TOOLBAR_LIST_SPECTATOR, CTMN_SPECTATOR, false);
235  }
236  }
237  }
238 #endif /* ENABLE_NETWORK */
239 
240  for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
241  if (!Company::IsValidID(c)) continue;
242  *list->Append() = new DropDownListCompanyItem(c, false, HasBit(grey, c));
243  }
244 
246 }
247 
248 
249 static ToolbarMode _toolbar_mode;
250 
251 static CallBackFunction SelectSignTool()
252 {
253  if (_last_started_action == CBF_PLACE_SIGN) {
255  return CBF_NONE;
256  } else {
257  SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
258  return CBF_PLACE_SIGN;
259  }
260 }
261 
262 /* --- Pausing --- */
263 
264 static CallBackFunction ToolbarPauseClick(Window *w)
265 {
266  if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
267 
269  if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
270  }
271  return CBF_NONE;
272 }
273 
281 {
282  _fast_forward ^= true;
283  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
284  return CBF_NONE;
285 }
286 
291  OME_GAMEOPTIONS,
292  OME_SETTINGS,
293  OME_SCRIPT_SETTINGS,
294  OME_NEWGRFSETTINGS,
295  OME_TRANSPARENCIES,
296  OME_SHOW_TOWNNAMES,
297  OME_SHOW_STATIONNAMES,
298  OME_SHOW_WAYPOINTNAMES,
299  OME_SHOW_SIGNS,
300  OME_SHOW_COMPETITOR_SIGNS,
301  OME_FULL_ANIMATION,
302  OME_FULL_DETAILS,
303  OME_TRANSPARENTBUILDINGS,
304  OME_SHOW_STATIONSIGNS,
305 };
306 
314 {
315  DropDownList *list = new DropDownList();
316  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false);
317  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false);
318  /* Changes to the per-AI settings don't get send from the server to the clients. Clients get
319  * the settings once they join but never update it. As such don't show the window at all
320  * to network clients. */
321  if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false);
322  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false);
323  *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false);
324  *list->Append() = new DropDownListItem(-1, false);
325  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES));
326  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES));
327  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES));
328  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS));
329  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS));
330  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION));
331  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL));
332  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES));
333  *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS));
334 
335  ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true);
336  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
337  return CBF_NONE;
338 }
339 
347 {
348  switch (index) {
349  case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE;
350  case OME_SETTINGS: ShowGameSettings(); return CBF_NONE;
351  case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE;
352  case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
353  case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break;
354 
355  case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break;
356  case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break;
357  case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break;
358  case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break;
359  case OME_SHOW_COMPETITOR_SIGNS:
362  break;
363  case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break;
364  case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break;
365  case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break;
366  case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break;
367  }
369  return CBF_NONE;
370 }
371 
376  SLEME_SAVE_SCENARIO = 0,
377  SLEME_LOAD_SCENARIO,
378  SLEME_SAVE_HEIGHTMAP,
379  SLEME_LOAD_HEIGHTMAP,
380  SLEME_EXIT_TOINTRO,
381  SLEME_EXIT_GAME = 6,
382  SLEME_MENUCOUNT,
383 };
384 
389  SLNME_SAVE_GAME = 0,
390  SLNME_LOAD_GAME,
391  SLNME_EXIT_TOINTRO,
392  SLNME_EXIT_GAME = 4,
393  SLNME_MENUCOUNT,
394 };
395 
403 {
404  PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT);
405  return CBF_NONE;
406 }
407 
415 {
416  PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT);
417  return CBF_NONE;
418 }
419 
426 static CallBackFunction MenuClickSaveLoad(int index = 0)
427 {
428  if (_game_mode == GM_EDITOR) {
429  switch (index) {
430  case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(SLD_SAVE_SCENARIO); break;
431  case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
432  case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(SLD_SAVE_HEIGHTMAP); break;
433  case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
434  case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break;
435  case SLEME_EXIT_GAME: HandleExitGameRequest(); break;
436  }
437  } else {
438  switch (index) {
439  case SLNME_SAVE_GAME: ShowSaveLoadDialog(SLD_SAVE_GAME); break;
440  case SLNME_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
441  case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break;
442  case SLNME_EXIT_GAME: HandleExitGameRequest(); break;
443  }
444  }
445  return CBF_NONE;
446 }
447 
448 /* --- Map button menu --- */
449 
450 enum MapMenuEntries {
451  MME_SHOW_SMALLMAP = 0,
452  MME_SHOW_EXTRAVIEWPORTS,
453  MME_SHOW_LINKGRAPH,
454  MME_SHOW_SIGNLISTS,
455  MME_SHOW_TOWNDIRECTORY,
456  MME_SHOW_INDUSTRYDIRECTORY,
457 };
458 
459 static CallBackFunction ToolbarMapClick(Window *w)
460 {
461  DropDownList *list = new DropDownList();
462  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false);
463  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false);
464  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false);
465  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false);
467  return CBF_NONE;
468 }
469 
470 static CallBackFunction ToolbarScenMapTownDir(Window *w)
471 {
472  DropDownList *list = new DropDownList();
473  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false);
474  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false);
475  *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false);
476  *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false);
477  *list->Append() = new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false);
479  return CBF_NONE;
480 }
481 
489 {
490  switch (index) {
491  case MME_SHOW_SMALLMAP: ShowSmallMap(); break;
492  case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewPortWindow(); break;
493  case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break;
494  case MME_SHOW_SIGNLISTS: ShowSignList(); break;
495  case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
496  case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break;
497  }
498  return CBF_NONE;
499 }
500 
501 /* --- Town button menu --- */
502 
503 static CallBackFunction ToolbarTownClick(Window *w)
504 {
505  PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
506  return CBF_NONE;
507 }
508 
516 {
517  switch (index) {
518  case 0: ShowTownDirectory(); break;
519  case 1: // setting could be changed when the dropdown was open
520  if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
521  break;
522  }
523  return CBF_NONE;
524 }
525 
526 /* --- Subidies button menu --- */
527 
528 static CallBackFunction ToolbarSubsidiesClick(Window *w)
529 {
530  PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1);
531  return CBF_NONE;
532 }
533 
541 {
542  switch (index) {
543  case 0: ShowSubsidiesList(); break;
544  }
545  return CBF_NONE;
546 }
547 
548 /* --- Stations button menu --- */
549 
550 static CallBackFunction ToolbarStationsClick(Window *w)
551 {
553  return CBF_NONE;
554 }
555 
563 {
565  return CBF_NONE;
566 }
567 
568 /* --- Finances button menu --- */
569 
570 static CallBackFunction ToolbarFinancesClick(Window *w)
571 {
573  return CBF_NONE;
574 }
575 
583 {
585  return CBF_NONE;
586 }
587 
588 /* --- Company's button menu --- */
589 
590 static CallBackFunction ToolbarCompaniesClick(Window *w)
591 {
593  return CBF_NONE;
594 }
595 
603 {
604 #ifdef ENABLE_NETWORK
605  if (_networking) {
606  switch (index) {
607  case CTMN_CLIENT_LIST:
608  ShowClientList();
609  return CBF_NONE;
610 
611  case CTMN_NEW_COMPANY:
612  if (_network_server) {
614  } else {
615  NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company);
616  }
617  return CBF_NONE;
618 
619  case CTMN_SPECTATE:
620  if (_network_server) {
623  } else {
625  }
626  return CBF_NONE;
627  }
628  }
629 #endif /* ENABLE_NETWORK */
630  ShowCompany((CompanyID)index);
631  return CBF_NONE;
632 }
633 
634 /* --- Story button menu --- */
635 
636 static CallBackFunction ToolbarStoryClick(Window *w)
637 {
639  return CBF_NONE;
640 }
641 
649 {
651  return CBF_NONE;
652 }
653 
654 /* --- Goal button menu --- */
655 
656 static CallBackFunction ToolbarGoalClick(Window *w)
657 {
659  return CBF_NONE;
660 }
661 
669 {
671  return CBF_NONE;
672 }
673 
674 /* --- Graphs button menu --- */
675 
676 static CallBackFunction ToolbarGraphsClick(Window *w)
677 {
678  PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8);
679  return CBF_NONE;
680 }
681 
689 {
690  switch (index) {
691  case 0: ShowOperatingProfitGraph(); break;
692  case 1: ShowIncomeGraph(); break;
693  case 2: ShowDeliveredCargoGraph(); break;
694  case 3: ShowPerformanceHistoryGraph(); break;
695  case 4: ShowCompanyValueGraph(); break;
696  case 5: ShowCargoPaymentRates(); break;
697  /* functions for combined graphs/league button */
698  case 6: ShowCompanyLeagueTable(); break;
699  case 7: ShowPerformanceRatingDetail(); break;
700  }
701  return CBF_NONE;
702 }
703 
704 /* --- League button menu --- */
705 
706 static CallBackFunction ToolbarLeagueClick(Window *w)
707 {
708  PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3);
709  return CBF_NONE;
710 }
711 
719 {
720  switch (index) {
721  case 0: ShowCompanyLeagueTable(); break;
722  case 1: ShowPerformanceRatingDetail(); break;
723  case 2: ShowHighscoreTable(); break;
724  }
725  return CBF_NONE;
726 }
727 
728 /* --- Industries button menu --- */
729 
730 static CallBackFunction ToolbarIndustryClick(Window *w)
731 {
732  /* Disable build-industry menu if we are a spectator */
733  PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3);
734  return CBF_NONE;
735 }
736 
744 {
745  switch (index) {
746  case 0: ShowIndustryDirectory(); break;
747  case 1: ShowIndustryCargoesWindow(); break;
748  case 2: ShowBuildIndustryWindow(); break;
749  }
750  return CBF_NONE;
751 }
752 
753 /* --- Trains button menu + 1 helper function for all vehicles. --- */
754 
755 static void ToolbarVehicleClick(Window *w, VehicleType veh)
756 {
757  const Vehicle *v;
758  int dis = ~0;
759 
760  FOR_ALL_VEHICLES(v) {
761  if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner);
762  }
764 }
765 
766 
767 static CallBackFunction ToolbarTrainClick(Window *w)
768 {
769  ToolbarVehicleClick(w, VEH_TRAIN);
770  return CBF_NONE;
771 }
772 
780 {
781  ShowVehicleListWindow((CompanyID)index, VEH_TRAIN);
782  return CBF_NONE;
783 }
784 
785 /* --- Road vehicle button menu --- */
786 
787 static CallBackFunction ToolbarRoadClick(Window *w)
788 {
789  ToolbarVehicleClick(w, VEH_ROAD);
790  return CBF_NONE;
791 }
792 
800 {
801  ShowVehicleListWindow((CompanyID)index, VEH_ROAD);
802  return CBF_NONE;
803 }
804 
805 /* --- Ship button menu --- */
806 
807 static CallBackFunction ToolbarShipClick(Window *w)
808 {
809  ToolbarVehicleClick(w, VEH_SHIP);
810  return CBF_NONE;
811 }
812 
820 {
821  ShowVehicleListWindow((CompanyID)index, VEH_SHIP);
822  return CBF_NONE;
823 }
824 
825 /* --- Aircraft button menu --- */
826 
827 static CallBackFunction ToolbarAirClick(Window *w)
828 {
829  ToolbarVehicleClick(w, VEH_AIRCRAFT);
830  return CBF_NONE;
831 }
832 
840 {
841  ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT);
842  return CBF_NONE;
843 }
844 
845 /* --- Zoom in button --- */
846 
847 static CallBackFunction ToolbarZoomInClick(Window *w)
848 {
850  w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN);
851  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
852  }
853  return CBF_NONE;
854 }
855 
856 /* --- Zoom out button --- */
857 
858 static CallBackFunction ToolbarZoomOutClick(Window *w)
859 {
861  w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT);
862  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
863  }
864  return CBF_NONE;
865 }
866 
867 /* --- Rail button menu --- */
868 
869 static CallBackFunction ToolbarBuildRailClick(Window *w)
870 {
871  ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true);
872  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
873  return CBF_NONE;
874 }
875 
883 {
884  _last_built_railtype = (RailType)index;
885  ShowBuildRailToolbar(_last_built_railtype);
886  return CBF_NONE;
887 }
888 
889 /* --- Road button menu --- */
890 
891 static CallBackFunction ToolbarBuildRoadClick(Window *w)
892 {
893  const Company *c = Company::Get(_local_company);
894  DropDownList *list = new DropDownList();
895 
896  /* Road is always visible and available. */
897  *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false);
898 
899  /* Tram is only visible when there will be a tram, and available when that has been introduced. */
900  Engine *e;
901  FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
902  if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
903  if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
904 
905  *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM));
906  break;
907  }
908  ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true);
909  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
910  return CBF_NONE;
911 }
912 
920 {
921  _last_built_roadtype = (RoadType)index;
922  ShowBuildRoadToolbar(_last_built_roadtype);
923  return CBF_NONE;
924 }
925 
926 /* --- Water button menu --- */
927 
928 static CallBackFunction ToolbarBuildWaterClick(Window *w)
929 {
930  PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1);
931  return CBF_NONE;
932 }
933 
941 {
943  return CBF_NONE;
944 }
945 
946 /* --- Airport button menu --- */
947 
948 static CallBackFunction ToolbarBuildAirClick(Window *w)
949 {
950  PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1);
951  return CBF_NONE;
952 }
953 
961 {
963  return CBF_NONE;
964 }
965 
966 /* --- Forest button menu --- */
967 
968 static CallBackFunction ToolbarForestClick(Window *w)
969 {
970  PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3);
971  return CBF_NONE;
972 }
973 
981 {
982  switch (index) {
983  case 0: ShowTerraformToolbar(); break;
984  case 1: ShowBuildTreesToolbar(); break;
985  case 2: return SelectSignTool();
986  }
987  return CBF_NONE;
988 }
989 
990 /* --- Music button menu --- */
991 
992 static CallBackFunction ToolbarMusicClick(Window *w)
993 {
994  PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1);
995  return CBF_NONE;
996 }
997 
1005 {
1006  ShowMusicWindow();
1007  return CBF_NONE;
1008 }
1009 
1010 /* --- Newspaper button menu --- */
1011 
1012 static CallBackFunction ToolbarNewspaperClick(Window *w)
1013 {
1014  PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 2);
1015  return CBF_NONE;
1016 }
1017 
1025 {
1026  switch (index) {
1027  case 0: ShowLastNewsMessage(); break;
1028  case 1: ShowMessageHistory(); break;
1029  }
1030  return CBF_NONE;
1031 }
1032 
1033 /* --- Help button menu --- */
1034 
1035 static CallBackFunction PlaceLandBlockInfo()
1036 {
1037  if (_last_started_action == CBF_PLACE_LANDINFO) {
1039  return CBF_NONE;
1040  } else {
1041  SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
1042  return CBF_PLACE_LANDINFO;
1043  }
1044 }
1045 
1046 static CallBackFunction ToolbarHelpClick(Window *w)
1047 {
1048  PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 12 : 9);
1049  return CBF_NONE;
1050 }
1051 
1052 static void MenuClickSmallScreenshot()
1053 {
1054  MakeScreenshot(SC_VIEWPORT, NULL);
1055 }
1056 
1062 static void ScreenshotConfirmCallback(Window *w, bool confirmed)
1063 {
1064  if (confirmed) MakeScreenshot(_confirmed_screenshot_type, NULL);
1065 }
1066 
1073 {
1074  ViewPort vp;
1075  SetupScreenshotViewport(t, &vp);
1076  if ((uint64)vp.width * (uint64)vp.height > 8192 * 8192) {
1077  /* Ask for confirmation */
1078  SetDParam(0, vp.width);
1079  SetDParam(1, vp.height);
1081  ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, NULL, ScreenshotConfirmCallback);
1082  } else {
1083  /* Less than 64M pixels, just do it */
1084  MakeScreenshot(t, NULL);
1085  }
1086 }
1087 
1096 {
1097  extern bool _draw_bounding_boxes;
1098  /* Always allow to toggle them off */
1099  if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) {
1100  _draw_bounding_boxes = !_draw_bounding_boxes;
1102  }
1103 }
1104 
1113 {
1114  extern bool _draw_dirty_blocks;
1115  /* Always allow to toggle them off */
1116  if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) {
1117  _draw_dirty_blocks = !_draw_dirty_blocks;
1119  }
1120 }
1121 
1127 {
1130  /* If you open a savegame as scenario there may already be link graphs.*/
1132  SetDate(new_date, 0);
1133 }
1134 
1141 {
1142  switch (index) {
1143  case 0: return PlaceLandBlockInfo();
1144  case 2: IConsoleSwitch(); break;
1145  case 3: ShowAIDebugWindow(); break;
1146  case 4: MenuClickSmallScreenshot(); break;
1149  case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break;
1150  case 8: ShowAboutWindow(); break;
1151  case 9: ShowSpriteAlignerWindow(); break;
1152  case 10: ToggleBoundingBoxes(); break;
1153  case 11: ToggleDirtyBlocks(); break;
1154  }
1155  return CBF_NONE;
1156 }
1157 
1158 /* --- Switch toolbar button --- */
1159 
1160 static CallBackFunction ToolbarSwitchClick(Window *w)
1161 {
1162  if (_toolbar_mode != TB_LOWER) {
1163  _toolbar_mode = TB_LOWER;
1164  } else {
1165  _toolbar_mode = TB_UPPER;
1166  }
1167 
1168  w->ReInit();
1169  w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
1170  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1171  return CBF_NONE;
1172 }
1173 
1174 /* --- Scenario editor specific handlers. */
1175 
1180 {
1182  ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
1183  _left_button_clicked = false;
1184  return CBF_NONE;
1185 }
1186 
1187 static CallBackFunction ToolbarScenDateBackward(Window *w)
1188 {
1189  /* don't allow too fast scrolling */
1190  if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1192  w->SetDirty();
1193 
1195  }
1196  _left_button_clicked = false;
1197  return CBF_NONE;
1198 }
1199 
1200 static CallBackFunction ToolbarScenDateForward(Window *w)
1201 {
1202  /* don't allow too fast scrolling */
1203  if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1205  w->SetDirty();
1206 
1208  }
1209  _left_button_clicked = false;
1210  return CBF_NONE;
1211 }
1212 
1213 static CallBackFunction ToolbarScenGenLand(Window *w)
1214 {
1216  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1217 
1219  return CBF_NONE;
1220 }
1221 
1222 
1223 static CallBackFunction ToolbarScenGenTown(Window *w)
1224 {
1226  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1227  ShowFoundTownWindow();
1228  return CBF_NONE;
1229 }
1230 
1231 static CallBackFunction ToolbarScenGenIndustry(Window *w)
1232 {
1234  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1235  ShowBuildIndustryWindow();
1236  return CBF_NONE;
1237 }
1238 
1239 static CallBackFunction ToolbarScenBuildRoad(Window *w)
1240 {
1242  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1244  return CBF_NONE;
1245 }
1246 
1247 static CallBackFunction ToolbarScenBuildDocks(Window *w)
1248 {
1250  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1252  return CBF_NONE;
1253 }
1254 
1255 static CallBackFunction ToolbarScenPlantTrees(Window *w)
1256 {
1258  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1259  ShowBuildTreesToolbar();
1260  return CBF_NONE;
1261 }
1262 
1263 static CallBackFunction ToolbarScenPlaceSign(Window *w)
1264 {
1266  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1267  return SelectSignTool();
1268 }
1269 
1270 static CallBackFunction ToolbarBtn_NULL(Window *w)
1271 {
1272  return CBF_NONE;
1273 }
1274 
1275 typedef CallBackFunction MenuClickedProc(int index);
1276 
1277 static MenuClickedProc * const _menu_clicked_procs[] = {
1278  NULL, // 0
1279  NULL, // 1
1280  MenuClickSettings, // 2
1281  MenuClickSaveLoad, // 3
1282  MenuClickMap, // 4
1283  MenuClickTown, // 5
1284  MenuClickSubsidies, // 6
1285  MenuClickStations, // 7
1286  MenuClickFinances, // 8
1287  MenuClickCompany, // 9
1288  MenuClickStory, // 10
1289  MenuClickGoal, // 11
1290  MenuClickGraphs, // 12
1291  MenuClickLeague, // 13
1292  MenuClickIndustry, // 14
1293  MenuClickShowTrains, // 15
1294  MenuClickShowRoad, // 16
1295  MenuClickShowShips, // 17
1296  MenuClickShowAir, // 18
1297  MenuClickMap, // 19
1298  NULL, // 20
1299  MenuClickBuildRail, // 21
1300  MenuClickBuildRoad, // 22
1301  MenuClickBuildWater, // 23
1302  MenuClickBuildAir, // 24
1303  MenuClickForest, // 25
1304  MenuClickMusicWindow, // 26
1305  MenuClickNewspaper, // 27
1306  MenuClickHelp, // 28
1307 };
1308 
1312 protected:
1313  uint spacers;
1314 
1315 public:
1317  {
1318  }
1319 
1326  {
1327  return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN;
1328  }
1329 
1330  void SetupSmallestSize(Window *w, bool init_array)
1331  {
1332  this->smallest_x = 0; // Biggest child
1333  this->smallest_y = 0; // Biggest child
1334  this->fill_x = 1;
1335  this->fill_y = 0;
1336  this->resize_x = 1; // We only resize in this direction
1337  this->resize_y = 0; // We never resize in this direction
1338  this->spacers = 0;
1339 
1340  uint nbuttons = 0;
1341  /* First initialise some variables... */
1342  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1343  child_wid->SetupSmallestSize(w, init_array);
1344  this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
1345  if (this->IsButton(child_wid->type)) {
1346  nbuttons++;
1347  this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
1348  } else if (child_wid->type == NWID_SPACER) {
1349  this->spacers++;
1350  }
1351  }
1352 
1353  /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */
1354  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1355  child_wid->current_y = this->smallest_y;
1356  if (!this->IsButton(child_wid->type)) {
1357  child_wid->current_x = child_wid->smallest_x;
1358  }
1359  }
1360  _toolbar_width = nbuttons * this->smallest_x;
1361  }
1362 
1363  void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
1364  {
1365  assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
1366 
1367  this->pos_x = x;
1368  this->pos_y = y;
1369  this->current_x = given_width;
1370  this->current_y = given_height;
1371 
1372  /* Figure out what are the visible buttons */
1373  memset(this->visible, 0, sizeof(this->visible));
1374  uint arrangable_count, button_count, spacer_count;
1375  const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count);
1376  for (uint i = 0; i < arrangable_count; i++) {
1377  this->visible[arrangement[i]] = true;
1378  }
1379 
1380  /* Create us ourselves a quick lookup table */
1381  NWidgetBase *widgets[WID_TN_END];
1382  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1383  if (child_wid->type == NWID_SPACER) continue;
1384  widgets[((NWidgetCore*)child_wid)->index] = child_wid;
1385  }
1386 
1387  /* Now assign the widgets to their rightful place */
1388  uint position = 0; // Place to put next child relative to origin of the container.
1389  uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets
1390  uint button_space = given_width - spacer_space; // Remaining spacing for the buttons
1391  uint spacer_i = 0;
1392  uint button_i = 0;
1393 
1394  /* Index into the arrangement indices. The macro lastof cannot be used here! */
1395  const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement;
1396  for (uint i = 0; i < arrangable_count; i++) {
1397  NWidgetBase *child_wid = widgets[*cur_wid];
1398  /* If we have to give space to the spacers, do that */
1399  if (spacer_space != 0) {
1400  NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev;
1401  if (possible_spacer != NULL && possible_spacer->type == NWID_SPACER) {
1402  uint add = spacer_space / (spacer_count - spacer_i);
1403  position += add;
1404  spacer_space -= add;
1405  spacer_i++;
1406  }
1407  }
1408 
1409  /* Buttons can be scaled, the others not. */
1410  if (this->IsButton(child_wid->type)) {
1411  child_wid->current_x = button_space / (button_count - button_i);
1412  button_space -= child_wid->current_x;
1413  button_i++;
1414  }
1415  child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
1416  position += child_wid->current_x;
1417 
1418  if (rtl) {
1419  cur_wid--;
1420  } else {
1421  cur_wid++;
1422  }
1423  }
1424  }
1425 
1426  /* virtual */ void Draw(const Window *w)
1427  {
1428  /* Draw brown-red toolbar bg. */
1429  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);
1430  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);
1431 
1432  bool rtl = _current_text_dir == TD_RTL;
1433  for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != NULL; child_wid = rtl ? child_wid->prev : child_wid->next) {
1434  if (child_wid->type == NWID_SPACER) continue;
1435  if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1436 
1437  child_wid->Draw(w);
1438  }
1439  }
1440 
1441  /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y)
1442  {
1443  if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
1444 
1445  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1446  if (child_wid->type == NWID_SPACER) continue;
1447  if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1448 
1449  NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
1450  if (nwid != NULL) return nwid;
1451  }
1452  return NULL;
1453  }
1454 
1463  virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0;
1464 };
1465 
1468  /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
1469  {
1470  static const uint SMALLEST_ARRANGEMENT = 14;
1471  static const uint BIGGEST_ARRANGEMENT = 20;
1472  static const byte arrange14[] = {
1473  0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29,
1474  2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29,
1475  };
1476  static const byte arrange15[] = {
1477  0, 1, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
1478  0, 2, 4, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29,
1479  };
1480  static const byte arrange16[] = {
1481  0, 1, 2, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
1482  0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29,
1483  };
1484  static const byte arrange17[] = {
1485  0, 1, 2, 4, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29,
1486  0, 1, 3, 4, 6, 5, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29,
1487  };
1488  static const byte arrange18[] = {
1489  0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29,
1490  0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29,
1491  };
1492  static const byte arrange19[] = {
1493  0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29,
1494  0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29,
1495  };
1496  static const byte arrange20[] = {
1497  0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29,
1498  0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29,
1499  };
1500  static const byte arrange_all[] = {
1501  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
1502  };
1503 
1504  /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
1505  uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
1506  if (full_buttons > BIGGEST_ARRANGEMENT) {
1507  button_count = arrangable_count = lengthof(arrange_all);
1508  spacer_count = this->spacers;
1509  return arrange_all;
1510  }
1511 
1512  /* Introduce the split toolbar */
1513  static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
1514 
1515  button_count = arrangable_count = full_buttons;
1516  spacer_count = this->spacers;
1517  return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
1518  }
1519 };
1520 
1523  uint panel_widths[2];
1524 
1525  void SetupSmallestSize(Window *w, bool init_array)
1526  {
1527  this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array);
1528 
1529  /* Find the size of panel_widths */
1530  uint i = 0;
1531  for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1532  if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
1533 
1534  assert(i < lengthof(this->panel_widths));
1535  this->panel_widths[i++] = child_wid->current_x;
1536  _toolbar_width += child_wid->current_x;
1537  }
1538  }
1539 
1540  /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
1541  {
1542  static const byte arrange_all[] = {
1543  0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
1544  };
1545  static const byte arrange_nopanel[] = {
1546  0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28,
1547  };
1548  static const byte arrange_switch[] = {
1549  18, 8, 11, 12, 13, 14, 15, 16, 17, 29,
1550  0, 1, 2, 3, 18, 9, 10, 26, 28, 29,
1551  };
1552 
1553  /* If we can place all buttons *and* the panels, show them. */
1554  uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
1555  if (width >= min_full_width) {
1556  width -= this->panel_widths[0] + this->panel_widths[1];
1557  arrangable_count = lengthof(arrange_all);
1558  button_count = arrangable_count - 2;
1559  spacer_count = this->spacers;
1560  return arrange_all;
1561  }
1562 
1563  /* 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 */
1564  uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
1565  if (width > min_small_width) {
1566  width -= this->panel_widths[1];
1567  arrangable_count = lengthof(arrange_nopanel);
1568  button_count = arrangable_count - 1;
1569  spacer_count = this->spacers - 1;
1570  return arrange_nopanel;
1571  }
1572 
1573  /* Split toolbar */
1574  width -= this->panel_widths[1];
1575  arrangable_count = lengthof(arrange_switch) / 2;
1576  button_count = arrangable_count - 1;
1577  spacer_count = 0;
1578  return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
1579  }
1580 };
1581 
1582 /* --- Toolbar handling for the 'normal' case */
1583 
1584 typedef CallBackFunction ToolbarButtonProc(Window *w);
1585 
1586 static ToolbarButtonProc * const _toolbar_button_procs[] = {
1587  ToolbarPauseClick,
1591  ToolbarMapClick,
1592  ToolbarTownClick,
1593  ToolbarSubsidiesClick,
1594  ToolbarStationsClick,
1595  ToolbarFinancesClick,
1596  ToolbarCompaniesClick,
1597  ToolbarStoryClick,
1598  ToolbarGoalClick,
1599  ToolbarGraphsClick,
1600  ToolbarLeagueClick,
1601  ToolbarIndustryClick,
1602  ToolbarTrainClick,
1603  ToolbarRoadClick,
1604  ToolbarShipClick,
1605  ToolbarAirClick,
1606  ToolbarZoomInClick,
1607  ToolbarZoomOutClick,
1608  ToolbarBuildRailClick,
1609  ToolbarBuildRoadClick,
1610  ToolbarBuildWaterClick,
1611  ToolbarBuildAirClick,
1612  ToolbarForestClick,
1613  ToolbarMusicClick,
1614  ToolbarNewspaperClick,
1615  ToolbarHelpClick,
1616  ToolbarSwitchClick,
1617 };
1618 
1619 enum MainToolbarHotkeys {
1620  MTHK_PAUSE,
1621  MTHK_FASTFORWARD,
1622  MTHK_SETTINGS,
1623  MTHK_SAVEGAME,
1624  MTHK_LOADGAME,
1625  MTHK_SMALLMAP,
1626  MTHK_TOWNDIRECTORY,
1627  MTHK_SUBSIDIES,
1628  MTHK_STATIONS,
1629  MTHK_FINANCES,
1630  MTHK_COMPANIES,
1631  MTHK_STORY,
1632  MTHK_GOAL,
1633  MTHK_GRAPHS,
1634  MTHK_LEAGUE,
1635  MTHK_INDUSTRIES,
1636  MTHK_TRAIN_LIST,
1637  MTHK_ROADVEH_LIST,
1638  MTHK_SHIP_LIST,
1639  MTHK_AIRCRAFT_LIST,
1640  MTHK_ZOOM_IN,
1641  MTHK_ZOOM_OUT,
1642  MTHK_BUILD_RAIL,
1643  MTHK_BUILD_ROAD,
1644  MTHK_BUILD_DOCKS,
1645  MTHK_BUILD_AIRPORT,
1646  MTHK_BUILD_TREES,
1647  MTHK_MUSIC,
1648  MTHK_AI_DEBUG,
1649  MTHK_SMALL_SCREENSHOT,
1650  MTHK_ZOOMEDIN_SCREENSHOT,
1651  MTHK_DEFAULTZOOM_SCREENSHOT,
1652  MTHK_GIANT_SCREENSHOT,
1653  MTHK_CHEATS,
1654  MTHK_TERRAFORM,
1655  MTHK_EXTRA_VIEWPORT,
1656  MTHK_CLIENT_LIST,
1657  MTHK_SIGN_LIST,
1658 };
1659 
1662  MainToolbarWindow(WindowDesc *desc) : Window(desc)
1663  {
1664  this->InitNested(0);
1665 
1666  _last_started_action = CBF_NONE;
1667  CLRBITS(this->flags, WF_WHITE_BORDER);
1668  this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
1669  this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
1670  PositionMainToolbar(this);
1672  }
1673 
1674  virtual void FindWindowPlacementAndResize(int def_width, int def_height)
1675  {
1677  }
1678 
1679  virtual void OnPaint()
1680  {
1681  /* If spectator, disable all construction buttons
1682  * ie : Build road, rail, ships, airports and landscaping
1683  * Since enabled state is the default, just disable when needed */
1685  /* disable company list drop downs, if there are no companies */
1687 
1690 
1693 
1694  this->DrawWidgets();
1695  }
1696 
1697  virtual void OnClick(Point pt, int widget, int click_count)
1698  {
1699  if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
1700  }
1701 
1702  virtual void OnDropdownSelect(int widget, int index)
1703  {
1704  CallBackFunction cbf = _menu_clicked_procs[widget](index);
1705  if (cbf != CBF_NONE) _last_started_action = cbf;
1706  }
1707 
1708  virtual EventState OnHotkey(int hotkey)
1709  {
1710  switch (hotkey) {
1711  case MTHK_PAUSE: ToolbarPauseClick(this); break;
1712  case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
1713  case MTHK_SETTINGS: ShowGameOptions(); break;
1714  case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
1715  case MTHK_LOADGAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
1716  case MTHK_SMALLMAP: ShowSmallMap(); break;
1717  case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
1718  case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
1719  case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
1720  case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
1721  case MTHK_COMPANIES: ShowCompany(_local_company); break;
1722  case MTHK_STORY: ShowStoryBook(_local_company); break;
1723  case MTHK_GOAL: ShowGoalsList(_local_company); break;
1724  case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
1725  case MTHK_LEAGUE: ShowCompanyLeagueTable(); break;
1726  case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
1727  case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
1728  case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
1729  case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
1730  case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
1731  case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
1732  case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
1733  case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break;
1734  case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
1735  case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
1736  case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
1737  case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
1738  case MTHK_MUSIC: ShowMusicWindow(); break;
1739  case MTHK_AI_DEBUG: ShowAIDebugWindow(); break;
1740  case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
1741  case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
1742  case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
1743  case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
1744  case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
1745  case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
1746  case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
1747 #ifdef ENABLE_NETWORK
1748  case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
1749 #endif
1750  case MTHK_SIGN_LIST: ShowSignList(); break;
1751  default: return ES_NOT_HANDLED;
1752  }
1753  return ES_HANDLED;
1754  }
1755 
1756  virtual void OnPlaceObject(Point pt, TileIndex tile)
1757  {
1758  switch (_last_started_action) {
1759  case CBF_PLACE_SIGN:
1760  PlaceProc_Sign(tile);
1761  break;
1762 
1763  case CBF_PLACE_LANDINFO:
1764  ShowLandInfo(tile);
1765  break;
1766 
1767  default: NOT_REACHED();
1768  }
1769  }
1770 
1771  virtual void OnPlaceObjectAbort()
1772  {
1773  _last_started_action = CBF_NONE;
1774  }
1775 
1776  virtual void OnTick()
1777  {
1778  if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
1781  }
1782 
1783  if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) {
1786  }
1787  }
1788 
1789  virtual void OnTimeout()
1790  {
1791  /* We do not want to automatically raise the pause, fast forward and
1792  * switchbar buttons; they have to stay down when pressed etc. */
1793  for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
1794  if (this->IsWidgetLowered(i)) {
1795  this->RaiseWidget(i);
1796  this->SetWidgetDirty(i);
1797  }
1798  }
1799  }
1800 
1806  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
1807  {
1808  if (!gui_scope) return;
1810  }
1811 
1812  static HotkeyList hotkeys;
1813 };
1814 
1815 const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0};
1816 const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0};
1817 const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0};
1818 const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0};
1819 
1820 static Hotkey maintoolbar_hotkeys[] = {
1821  Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE),
1822  Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD),
1823  Hotkey(WKC_F2, "settings", MTHK_SETTINGS),
1824  Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME),
1825  Hotkey((uint16)0, "load_game", MTHK_LOADGAME),
1826  Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP),
1827  Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
1828  Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES),
1829  Hotkey(WKC_F7, "station_list", MTHK_STATIONS),
1830  Hotkey(WKC_F8, "finances", MTHK_FINANCES),
1831  Hotkey(WKC_F9, "companies", MTHK_COMPANIES),
1832  Hotkey((uint16)0, "story_book", MTHK_STORY),
1833  Hotkey((uint16)0, "goal_list", MTHK_GOAL),
1834  Hotkey(WKC_F10, "graphs", MTHK_GRAPHS),
1835  Hotkey(WKC_F11, "league", MTHK_LEAGUE),
1836  Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES),
1837  Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
1838  Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
1839  Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
1840  Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
1841  Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN),
1842  Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT),
1843  Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
1844  Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
1845  Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
1846  Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
1847  Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
1848  Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
1849  Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG),
1850  Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
1851  Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
1852  Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT),
1853  Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
1854  Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
1855  Hotkey('L', "terraform", MTHK_TERRAFORM),
1856  Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
1857 #ifdef ENABLE_NETWORK
1858  Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
1859 #endif
1860  Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
1861  HOTKEY_LIST_END
1862 };
1863 HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
1864 
1865 static NWidgetBase *MakeMainToolbar(int *biggest_index)
1866 {
1868  static const SpriteID toolbar_button_sprites[] = {
1869  SPR_IMG_PAUSE, // WID_TN_PAUSE
1870  SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD
1871  SPR_IMG_SETTINGS, // WID_TN_SETTINGS
1872  SPR_IMG_SAVE, // WID_TN_SAVE
1873  SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP
1874  SPR_IMG_TOWN, // WID_TN_TOWNS
1875  SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES
1876  SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS
1877  SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
1878  SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
1879  SPR_IMG_STORY_BOOK, // WID_TN_STORY
1880  SPR_IMG_GOAL, // WID_TN_GOAL
1881  SPR_IMG_GRAPHS, // WID_TN_GRAPHS
1882  SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE
1883  SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES
1884  SPR_IMG_TRAINLIST, // WID_TN_TRAINS
1885  SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS
1886  SPR_IMG_SHIPLIST, // WID_TN_SHIPS
1887  SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT
1888  SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN
1889  SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT
1890  SPR_IMG_BUILDRAIL, // WID_TN_RAILS
1891  SPR_IMG_BUILDROAD, // WID_TN_ROADS
1892  SPR_IMG_BUILDWATER, // WID_TN_WATER
1893  SPR_IMG_BUILDAIR, // WID_TN_AIR
1894  SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
1895  SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
1896  SPR_IMG_MESSAGES, // WID_TN_MESSAGES
1897  SPR_IMG_QUERY, // WID_TN_HELP
1898  SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
1899  };
1900 
1902  for (uint i = 0; i < WID_TN_END; i++) {
1903  switch (i) {
1904  case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break;
1905  }
1906  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));
1907  }
1908 
1909  *biggest_index = max<int>(*biggest_index, WID_TN_SWITCH_BAR);
1910  return hor;
1911 }
1912 
1913 static const NWidgetPart _nested_toolbar_normal_widgets[] = {
1915 };
1916 
1917 static WindowDesc _toolb_normal_desc(
1918  WDP_MANUAL, NULL, 0, 0,
1920  WDF_NO_FOCUS,
1921  _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets),
1922  &MainToolbarWindow::hotkeys
1923 );
1924 
1925 
1926 /* --- Toolbar handling for the scenario editor */
1927 
1928 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
1929  ToolbarPauseClick,
1933  ToolbarBtn_NULL,
1935  ToolbarScenDateBackward,
1936  ToolbarScenDateForward,
1937  ToolbarScenMapTownDir,
1938  ToolbarZoomInClick,
1939  ToolbarZoomOutClick,
1940  ToolbarScenGenLand,
1941  ToolbarScenGenTown,
1942  ToolbarScenGenIndustry,
1943  ToolbarScenBuildRoad,
1944  ToolbarScenBuildDocks,
1945  ToolbarScenPlantTrees,
1946  ToolbarScenPlaceSign,
1947  ToolbarBtn_NULL,
1948  NULL,
1949  NULL,
1950  NULL,
1951  NULL,
1952  NULL,
1953  NULL,
1954  NULL,
1955  ToolbarMusicClick,
1956  NULL,
1957  ToolbarHelpClick,
1958  ToolbarSwitchClick,
1959 };
1960 
1961 enum MainToolbarEditorHotkeys {
1962  MTEHK_PAUSE,
1963  MTEHK_FASTFORWARD,
1964  MTEHK_SETTINGS,
1965  MTEHK_SAVEGAME,
1966  MTEHK_GENLAND,
1967  MTEHK_GENTOWN,
1968  MTEHK_GENINDUSTRY,
1969  MTEHK_BUILD_ROAD,
1970  MTEHK_BUILD_DOCKS,
1971  MTEHK_BUILD_TREES,
1972  MTEHK_SIGN,
1973  MTEHK_MUSIC,
1974  MTEHK_LANDINFO,
1975  MTEHK_SMALL_SCREENSHOT,
1976  MTEHK_ZOOMEDIN_SCREENSHOT,
1977  MTEHK_DEFAULTZOOM_SCREENSHOT,
1978  MTEHK_GIANT_SCREENSHOT,
1979  MTEHK_ZOOM_IN,
1980  MTEHK_ZOOM_OUT,
1981  MTEHK_TERRAFORM,
1982  MTEHK_SMALLMAP,
1983  MTEHK_EXTRA_VIEWPORT,
1984 };
1985 
1988  {
1989  this->InitNested(0);
1990 
1991  _last_started_action = CBF_NONE;
1992  CLRBITS(this->flags, WF_WHITE_BORDER);
1993  PositionMainToolbar(this);
1995  }
1996 
1997  virtual void FindWindowPlacementAndResize(int def_width, int def_height)
1998  {
2000  }
2001 
2002  virtual void OnPaint()
2003  {
2006 
2007  this->DrawWidgets();
2008  }
2009 
2010  virtual void DrawWidget(const Rect &r, int widget) const
2011  {
2012  switch (widget) {
2013  case WID_TE_DATE:
2015  DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER);
2016  break;
2017 
2018  case WID_TE_SPACER: {
2019  int height = r.bottom - r.top;
2020  if (height > 2 * FONT_HEIGHT_NORMAL) {
2021  DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
2022  DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2023  } else {
2024  DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2025  }
2026  break;
2027  }
2028  }
2029  }
2030 
2031  virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
2032  {
2033  switch (widget) {
2034  case WID_TE_SPACER:
2035  size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
2036  break;
2037 
2038  case WID_TE_DATE:
2039  SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1));
2040  *size = GetStringBoundingBox(STR_WHITE_DATE_LONG);
2041  size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM);
2042  break;
2043  }
2044  }
2045 
2046  virtual void OnClick(Point pt, int widget, int click_count)
2047  {
2048  if (_game_mode == GM_MENU) return;
2049  CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
2050  if (cbf != CBF_NONE) _last_started_action = cbf;
2051  }
2052 
2053  virtual void OnDropdownSelect(int widget, int index)
2054  {
2055  /* The map button is in a different location on the scenario
2056  * editor toolbar, so we need to adjust for it. */
2057  if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP;
2058  CallBackFunction cbf = _menu_clicked_procs[widget](index);
2059  if (cbf != CBF_NONE) _last_started_action = cbf;
2060  if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
2061  }
2062 
2063  virtual EventState OnHotkey(int hotkey)
2064  {
2065  CallBackFunction cbf = CBF_NONE;
2066  switch (hotkey) {
2067  case MTEHK_PAUSE: ToolbarPauseClick(this); break;
2068  case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2069  case MTEHK_SETTINGS: ShowGameOptions(); break;
2070  case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
2071  case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
2072  case MTEHK_GENTOWN: ToolbarScenGenTown(this); break;
2073  case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
2074  case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break;
2075  case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break;
2076  case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break;
2077  case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break;
2078  case MTEHK_MUSIC: ShowMusicWindow(); break;
2079  case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2080  case MTEHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
2081  case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
2082  case MTEHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
2083  case MTEHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
2084  case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2085  case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2086  case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break;
2087  case MTEHK_SMALLMAP: ShowSmallMap(); break;
2088  case MTEHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
2089  default: return ES_NOT_HANDLED;
2090  }
2091  if (cbf != CBF_NONE) _last_started_action = cbf;
2092  return ES_HANDLED;
2093  }
2094 
2095  virtual void OnPlaceObject(Point pt, TileIndex tile)
2096  {
2097  switch (_last_started_action) {
2098  case CBF_PLACE_SIGN:
2099  PlaceProc_Sign(tile);
2100  break;
2101 
2102  case CBF_PLACE_LANDINFO:
2103  ShowLandInfo(tile);
2104  break;
2105 
2106  default: NOT_REACHED();
2107  }
2108  }
2109 
2110  virtual void OnPlaceObjectAbort()
2111  {
2112  _last_started_action = CBF_NONE;
2113  }
2114 
2115  virtual void OnTimeout()
2116  {
2120  }
2121 
2122  virtual void OnTick()
2123  {
2124  if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
2126  this->SetDirty();
2127  }
2128 
2129  if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) {
2131  this->SetDirty();
2132  }
2133  }
2134 
2140  virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2141  {
2142  if (!gui_scope) return;
2144  }
2145 
2146  virtual void OnQueryTextFinished(char *str)
2147  {
2148  /* Was 'cancel' pressed? */
2149  if (str == NULL) return;
2150 
2151  int32 value;
2152  if (!StrEmpty(str)) {
2153  value = atoi(str);
2154  } else {
2155  /* An empty string means revert to the default */
2156  value = DEF_START_YEAR;
2157  }
2158  SetStartingYear(value);
2159 
2160  this->SetDirty();
2161  }
2162 
2163  static HotkeyList hotkeys;
2164 };
2165 
2166 static Hotkey scenedit_maintoolbar_hotkeys[] = {
2167  Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE),
2168  Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD),
2169  Hotkey(WKC_F2, "settings", MTEHK_SETTINGS),
2170  Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME),
2171  Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND),
2172  Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN),
2173  Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
2174  Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
2175  Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
2176  Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
2177  Hotkey(WKC_F10, "build_sign", MTEHK_SIGN),
2178  Hotkey(WKC_F11, "music", MTEHK_MUSIC),
2179  Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO),
2180  Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
2181  Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
2182  Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT),
2183  Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
2184  Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN),
2185  Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT),
2186  Hotkey('L', "terraform", MTEHK_TERRAFORM),
2187  Hotkey('M', "smallmap", MTEHK_SMALLMAP),
2188  Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
2189  HOTKEY_LIST_END
2190 };
2191 HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys);
2192 
2193 static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
2194  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
2195  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
2196  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
2197  NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
2199  NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
2201  NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
2202  NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
2203  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD),
2204  NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE),
2205  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD),
2206  EndContainer(),
2207  EndContainer(),
2209  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
2211  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
2212  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
2214  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
2215  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
2216  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
2217  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
2218  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
2219  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
2220  NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
2222  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
2223  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
2224  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
2225 };
2226 
2227 static NWidgetBase *MakeScenarioToolbar(int *biggest_index)
2228 {
2229  return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer());
2230 }
2231 
2232 static const NWidgetPart _nested_toolb_scen_widgets[] = {
2233  NWidgetFunction(MakeScenarioToolbar),
2234 };
2235 
2236 static WindowDesc _toolb_scen_desc(
2237  WDP_MANUAL, NULL, 0, 0,
2239  WDF_NO_FOCUS,
2240  _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets),
2241  &ScenarioEditorToolbarWindow::hotkeys
2242 );
2243 
2246 {
2247  /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
2248  _last_built_roadtype = ROADTYPE_ROAD;
2249 
2250  if (_game_mode == GM_EDITOR) {
2251  new ScenarioEditorToolbarWindow(&_toolb_scen_desc);
2252  } else {
2253  new MainToolbarWindow(&_toolb_normal_desc);
2254  }
2255 }