OpenTTD: src/toolbar_gui.cpp Source File

OpenTTD

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

- File List
- Globals

toolbar_gui.cpp
Go to the documentation of this file.
1 /* $Id: toolbar_gui.cpp 27671 2016-10-30 17:36:57Z 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"
41 #include "linkgraph/linkgraph_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
66 static ScreenshotType _confirmed_screenshot_type;
67
69 enum ToolbarMode {
70 TB_NORMAL,
71 TB_UPPER,
72 TB_LOWER
73 };
74
76 enum CallBackFunction {
77 CBF_NONE,
78 CBF_PLACE_SIGN,
79 CBF_PLACE_LANDINFO,
80 };
81
82 static CallBackFunction _last_started_action = CBF_NONE;
83
84
88 class DropDownListCheckedItem : public DropDownListStringItem {
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
118 class DropDownListCompanyItem : public DropDownListItem {
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) {
228 if (_local_company == COMPANY_SPECTATOR) {
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
245 PopupMainToolbMenu(w, widget, list, _local_company == COMPANY_SPECTATOR ? CTMN_CLIENT_LIST : (int)_local_company);
246 }
247
248
249 static ToolbarMode _toolbar_mode;
250
251 static CallBackFunction SelectSignTool()
252 {
253 if (_last_started_action == CBF_PLACE_SIGN) {
254 ResetObjectToPlace();
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
268 if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) {
269 if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
270 }
271 return CBF_NONE;
272 }
273
280 static CallBackFunction ToolbarFastForwardClick(Window *w)
281 {
282 _fast_forward ^= true;
283 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
284 return CBF_NONE;
285 }
286
290 enum OptionMenuEntries {
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
313 static CallBackFunction ToolbarOptionsClick(Window *w)
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
346 static CallBackFunction MenuClickSettings(int index)
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:
360 ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
361 InvalidateWindowClassesData(WC_SIGN_LIST, -1);
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 }
368 MarkWholeScreenDirty();
369 return CBF_NONE;
370 }
371
375 enum SaveLoadEditorMenuEntries {
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
388 enum SaveLoadNormalMenuEntries {
389 SLNME_SAVE_GAME = 0,
390 SLNME_LOAD_GAME,
391 SLNME_EXIT_TOINTRO,
392 SLNME_EXIT_GAME = 4,
393 SLNME_MENUCOUNT,
394 };
395
402 static CallBackFunction ToolbarSaveClick(Window *w)
403 {
404 PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT);
405 return CBF_NONE;
406 }
407
414 static CallBackFunction ToolbarScenSaveOrLoad(Window *w)
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(FT_SCENARIO, SLO_SAVE); break;
431 case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD); break;
432 case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_SAVE); break;
433 case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_LOAD); 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(FT_SAVEGAME, SLO_SAVE); break;
440 case SLNME_LOAD_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); 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);
466 PopupMainToolbMenu(w, WID_TN_SMALL_MAP, list, 0);
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);
478 PopupMainToolbMenu(w, WID_TE_SMALL_MAP, list, 0);
479 return CBF_NONE;
480 }
481
488 static CallBackFunction MenuClickMap(int index)
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
515 static CallBackFunction MenuClickTown(int index)
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
540 static CallBackFunction MenuClickSubsidies(int index)
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 {
552 PopupMainCompanyToolbMenu(w, WID_TN_STATIONS);
553 return CBF_NONE;
554 }
555
562 static CallBackFunction MenuClickStations(int index)
563 {
564 ShowCompanyStations((CompanyID)index);
565 return CBF_NONE;
566 }
567
568 /* --- Finances button menu --- */
569
570 static CallBackFunction ToolbarFinancesClick(Window *w)
571 {
572 PopupMainCompanyToolbMenu(w, WID_TN_FINANCES);
573 return CBF_NONE;
574 }
575
582 static CallBackFunction MenuClickFinances(int index)
583 {
584 ShowCompanyFinances((CompanyID)index);
585 return CBF_NONE;
586 }
587
588 /* --- Company's button menu --- */
589
590 static CallBackFunction ToolbarCompaniesClick(Window *w)
591 {
592 PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0, true);
593 return CBF_NONE;
594 }
595
602 static CallBackFunction MenuClickCompany(int index)
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) {
613 DoCommandP(0, 0, _network_own_client_id, CMD_COMPANY_CTRL);
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) {
621 NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR);
622 MarkWholeScreenDirty();
623 } else {
624 NetworkClientRequestMove(COMPANY_SPECTATOR);
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 {
638 PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0, true);
639 return CBF_NONE;
640 }
641
648 static CallBackFunction MenuClickStory(int index)
649 {
650 ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
651 return CBF_NONE;
652 }
653
654 /* --- Goal button menu --- */
655
656 static CallBackFunction ToolbarGoalClick(Window *w)
657 {
658 PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0, true);
659 return CBF_NONE;
660 }
661
668 static CallBackFunction MenuClickGoal(int index)
669 {
670 ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
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
688 static CallBackFunction MenuClickGraphs(int index)
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
718 static CallBackFunction MenuClickLeague(int index)
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
743 static CallBackFunction MenuClickIndustry(int index)
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 }
763 PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis);
764 }
765
766
767 static CallBackFunction ToolbarTrainClick(Window *w)
768 {
769 ToolbarVehicleClick(w, VEH_TRAIN);
770 return CBF_NONE;
771 }
772
779 static CallBackFunction MenuClickShowTrains(int index)
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
799 static CallBackFunction MenuClickShowRoad(int index)
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
819 static CallBackFunction MenuClickShowShips(int index)
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
839 static CallBackFunction MenuClickShowAir(int index)
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 {
849 if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
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 {
860 if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
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
882 static CallBackFunction MenuClickBuildRail(int index)
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
919 static CallBackFunction MenuClickBuildRoad(int index)
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
940 static CallBackFunction MenuClickBuildWater(int index)
941 {
942 ShowBuildDocksToolbar();
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
960 static CallBackFunction MenuClickBuildAir(int index)
961 {
962 ShowBuildAirToolbar();
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
980 static CallBackFunction MenuClickForest(int index)
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
1004 static CallBackFunction MenuClickMusicWindow(int index)
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
1024 static CallBackFunction MenuClickNewspaper(int index)
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) {
1038 ResetObjectToPlace();
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
1072 static void MenuClickLargeWorldScreenshot(ScreenshotType t)
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);
1080 _confirmed_screenshot_type = t;
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
1095 void ToggleBoundingBoxes()
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;
1101 MarkWholeScreenDirty();
1102 }
1103 }
1104
1112 void ToggleDirtyBlocks()
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;
1118 MarkWholeScreenDirty();
1119 }
1120 }
1121
1126 void SetStartingYear(Year year)
1127 {
1128 _settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR);
1129 Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
1130 /* If you open a savegame as scenario there may already be link graphs.*/
1131 LinkGraphSchedule::instance.ShiftDates(new_date - _date);
1132 SetDate(new_date, 0);
1133 }
1134
1140 static CallBackFunction MenuClickHelp(int index)
1141 {
1142 switch (index) {
1143 case 0: return PlaceLandBlockInfo();
1144 case 2: IConsoleSwitch(); break;
1145 case 3: ShowAIDebugWindow(); break;
1146 case 4: MenuClickSmallScreenshot(); break;
1147 case 5: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
1148 case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); 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
1179 static CallBackFunction ToolbarScenDatePanel(Window *w)
1180 {
1181 SetDParam(0, _settings_game.game_creation.starting_year);
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) {
1191 w->HandleButtonClick(WID_TE_DATE_BACKWARD);
1192 w->SetDirty();
1193
1194 SetStartingYear(_settings_game.game_creation.starting_year - 1);
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) {
1204 w->HandleButtonClick(WID_TE_DATE_FORWARD);
1205 w->SetDirty();
1206
1207 SetStartingYear(_settings_game.game_creation.starting_year + 1);
1208 }
1209 _left_button_clicked = false;
1210 return CBF_NONE;
1211 }
1212
1213 static CallBackFunction ToolbarScenGenLand(Window *w)
1214 {
1215 w->HandleButtonClick(WID_TE_LAND_GENERATE);
1216 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1217
1218 ShowEditorTerraformToolbar();
1219 return CBF_NONE;
1220 }
1221
1222
1223 static CallBackFunction ToolbarScenGenTown(Window *w)
1224 {
1225 w->HandleButtonClick(WID_TE_TOWN_GENERATE);
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 {
1233 w->HandleButtonClick(WID_TE_INDUSTRY);
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 {
1241 w->HandleButtonClick(WID_TE_ROADS);
1242 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1243 ShowBuildRoadScenToolbar();
1244 return CBF_NONE;
1245 }
1246
1247 static CallBackFunction ToolbarScenBuildDocks(Window *w)
1248 {
1249 w->HandleButtonClick(WID_TE_WATER);
1250 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1251 ShowBuildDocksScenToolbar();
1252 return CBF_NONE;
1253 }
1254
1255 static CallBackFunction ToolbarScenPlantTrees(Window *w)
1256 {
1257 w->HandleButtonClick(WID_TE_TREES);
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 {
1265 w->HandleButtonClick(WID_TE_SIGNS);
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
1310 class NWidgetToolbarContainer : public NWidgetContainer {
1311 bool visible[WID_TN_END];
1312 protected:
1313 uint spacers;
1314
1315 public:
1316 NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL)
1317 {
1318 }
1319
1325 bool IsButton(WidgetType type) const
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
1467 class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
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
1473 /* The number of buttons of each row of the toolbar should match the number of items which we want to be visible.
1474 * The total number of buttons should be equal to arrangable_count * 2.
1475 * No bad things happen, but we could see strange behaviours if we have buttons < (arrangable_count * 2) like a
1476 * pause button appearing on the right of the lower toolbar and weird resizing of the widgets even if there is
1477 * enough space.
1478 */
1479 static const byte arrange14[] = {
1480 WID_TN_PAUSE,
1481 WID_TN_FAST_FORWARD,
1482 WID_TN_TRAINS,
1483 WID_TN_ROADVEHS,
1484 WID_TN_SHIPS,
1485 WID_TN_AIRCRAFTS,
1486 WID_TN_ZOOM_IN,
1487 WID_TN_ZOOM_OUT,
1488 WID_TN_RAILS,
1489 WID_TN_ROADS,
1490 WID_TN_WATER,
1491 WID_TN_AIR,
1492 WID_TN_LANDSCAPE,
1493 WID_TN_SWITCH_BAR,
1494 // lower toolbar
1495 WID_TN_SETTINGS,
1496 WID_TN_SAVE,
1497 WID_TN_SMALL_MAP,
1498 WID_TN_TOWNS,
1499 WID_TN_SUBSIDIES,
1500 WID_TN_STATIONS,
1501 WID_TN_FINANCES,
1502 WID_TN_COMPANIES,
1503 WID_TN_GRAPHS,
1504 WID_TN_INDUSTRIES,
1505 WID_TN_MUSIC_SOUND,
1506 WID_TN_MESSAGES,
1507 WID_TN_HELP,
1508 WID_TN_SWITCH_BAR,
1509 };
1510 static const byte arrange15[] = {
1511 WID_TN_PAUSE,
1512 WID_TN_FAST_FORWARD,
1513 WID_TN_SMALL_MAP,
1514 WID_TN_TRAINS,
1515 WID_TN_ROADVEHS,
1516 WID_TN_SHIPS,
1517 WID_TN_AIRCRAFTS,
1518 WID_TN_RAILS,
1519 WID_TN_ROADS,
1520 WID_TN_WATER,
1521 WID_TN_AIR,
1522 WID_TN_LANDSCAPE,
1523 WID_TN_ZOOM_IN,
1524 WID_TN_ZOOM_OUT,
1525 WID_TN_SWITCH_BAR,
1526 // lower toolbar
1527 WID_TN_PAUSE,
1528 WID_TN_SETTINGS,
1529 WID_TN_SMALL_MAP,
1530 WID_TN_SAVE,
1531 WID_TN_TOWNS,
1532 WID_TN_SUBSIDIES,
1533 WID_TN_STATIONS,
1534 WID_TN_FINANCES,
1535 WID_TN_COMPANIES,
1536 WID_TN_GRAPHS,
1537 WID_TN_INDUSTRIES,
1538 WID_TN_MUSIC_SOUND,
1539 WID_TN_MESSAGES,
1540 WID_TN_HELP,
1541 WID_TN_SWITCH_BAR,
1542 };
1543 static const byte arrange16[] = {
1544 WID_TN_PAUSE,
1545 WID_TN_FAST_FORWARD,
1546 WID_TN_SETTINGS,
1547 WID_TN_SMALL_MAP,
1548 WID_TN_TRAINS,
1549 WID_TN_ROADVEHS,
1550 WID_TN_SHIPS,
1551 WID_TN_AIRCRAFTS,
1552 WID_TN_RAILS,
1553 WID_TN_ROADS,
1554 WID_TN_WATER,
1555 WID_TN_AIR,
1556 WID_TN_LANDSCAPE,
1557 WID_TN_ZOOM_IN,
1558 WID_TN_ZOOM_OUT,
1559 WID_TN_SWITCH_BAR,
1560 // lower toolbar
1561 WID_TN_PAUSE,
1562 WID_TN_FAST_FORWARD,
1563 WID_TN_SAVE,
1564 WID_TN_TOWNS,
1565 WID_TN_SUBSIDIES,
1566 WID_TN_STATIONS,
1567 WID_TN_FINANCES,
1568 WID_TN_COMPANIES,
1569 WID_TN_GRAPHS,
1570 WID_TN_INDUSTRIES,
1571 WID_TN_MUSIC_SOUND,
1572 WID_TN_MESSAGES,
1573 WID_TN_HELP,
1574 WID_TN_ZOOM_IN,
1575 WID_TN_ZOOM_OUT,
1576 WID_TN_SWITCH_BAR,
1577 };
1578 static const byte arrange17[] = {
1579 WID_TN_PAUSE,
1580 WID_TN_FAST_FORWARD,
1581 WID_TN_SETTINGS,
1582 WID_TN_SMALL_MAP,
1583 WID_TN_SUBSIDIES,
1584 WID_TN_TRAINS,
1585 WID_TN_ROADVEHS,
1586 WID_TN_SHIPS,
1587 WID_TN_AIRCRAFTS,
1588 WID_TN_RAILS,
1589 WID_TN_ROADS,
1590 WID_TN_WATER,
1591 WID_TN_AIR,
1592 WID_TN_LANDSCAPE,
1593 WID_TN_ZOOM_IN,
1594 WID_TN_ZOOM_OUT,
1595 WID_TN_SWITCH_BAR,
1596 // lower toolbar
1597 WID_TN_PAUSE,
1598 WID_TN_FAST_FORWARD,
1599 WID_TN_SAVE,
1600 WID_TN_SMALL_MAP,
1601 WID_TN_SUBSIDIES,
1602 WID_TN_TOWNS,
1603 WID_TN_STATIONS,
1604 WID_TN_FINANCES,
1605 WID_TN_COMPANIES,
1606 WID_TN_GRAPHS,
1607 WID_TN_INDUSTRIES,
1608 WID_TN_MUSIC_SOUND,
1609 WID_TN_MESSAGES,
1610 WID_TN_HELP,
1611 WID_TN_ZOOM_IN,
1612 WID_TN_ZOOM_OUT,
1613 WID_TN_SWITCH_BAR,
1614 };
1615 static const byte arrange18[] = {
1616 WID_TN_PAUSE,
1617 WID_TN_FAST_FORWARD,
1618 WID_TN_SETTINGS,
1619 WID_TN_SMALL_MAP,
1620 WID_TN_TOWNS,
1621 WID_TN_SUBSIDIES,
1622 WID_TN_STATIONS,
1623 WID_TN_FINANCES,
1624 WID_TN_COMPANIES,
1625 WID_TN_INDUSTRIES,
1626 WID_TN_RAILS,
1627 WID_TN_ROADS,
1628 WID_TN_WATER,
1629 WID_TN_AIR,
1630 WID_TN_LANDSCAPE,
1631 WID_TN_ZOOM_IN,
1632 WID_TN_ZOOM_OUT,
1633 WID_TN_SWITCH_BAR,
1634 // lower toolbar
1635 WID_TN_PAUSE,
1636 WID_TN_FAST_FORWARD,
1637 WID_TN_SAVE,
1638 WID_TN_SMALL_MAP,
1639 WID_TN_TOWNS,
1640 WID_TN_SUBSIDIES,
1641 WID_TN_STATIONS,
1642 WID_TN_GRAPHS,
1643 WID_TN_TRAINS,
1644 WID_TN_ROADVEHS,
1645 WID_TN_SHIPS,
1646 WID_TN_AIRCRAFTS,
1647 WID_TN_MUSIC_SOUND,
1648 WID_TN_MESSAGES,
1649 WID_TN_HELP,
1650 WID_TN_ZOOM_IN,
1651 WID_TN_ZOOM_OUT,
1652 WID_TN_SWITCH_BAR,
1653 };
1654 static const byte arrange19[] = {
1655 WID_TN_PAUSE,
1656 WID_TN_FAST_FORWARD,
1657 WID_TN_SETTINGS,
1658 WID_TN_SMALL_MAP,
1659 WID_TN_TOWNS,
1660 WID_TN_SUBSIDIES,
1661 WID_TN_TRAINS,
1662 WID_TN_ROADVEHS,
1663 WID_TN_SHIPS,
1664 WID_TN_AIRCRAFTS,
1665 WID_TN_RAILS,
1666 WID_TN_ROADS,
1667 WID_TN_WATER,
1668 WID_TN_AIR,
1669 WID_TN_LANDSCAPE,
1670 WID_TN_MUSIC_SOUND,
1671 WID_TN_ZOOM_IN,
1672 WID_TN_ZOOM_OUT,
1673 WID_TN_SWITCH_BAR,
1674 // lower toolbar
1675 WID_TN_PAUSE,
1676 WID_TN_FAST_FORWARD,
1677 WID_TN_SAVE,
1678 WID_TN_SMALL_MAP,
1679 WID_TN_STATIONS,
1680 WID_TN_FINANCES,
1681 WID_TN_COMPANIES,
1682 WID_TN_GRAPHS,
1683 WID_TN_INDUSTRIES,
1684 WID_TN_MESSAGES,
1685 WID_TN_RAILS,
1686 WID_TN_ROADS,
1687 WID_TN_WATER,
1688 WID_TN_AIR,
1689 WID_TN_LANDSCAPE,
1690 WID_TN_HELP,
1691 WID_TN_ZOOM_IN,
1692 WID_TN_ZOOM_OUT,
1693 WID_TN_SWITCH_BAR,
1694 };
1695 static const byte arrange20[] = {
1696 WID_TN_PAUSE,
1697 WID_TN_FAST_FORWARD,
1698 WID_TN_SETTINGS,
1699 WID_TN_SMALL_MAP,
1700 WID_TN_TOWNS,
1701 WID_TN_SUBSIDIES,
1702 WID_TN_TRAINS,
1703 WID_TN_ROADVEHS,
1704 WID_TN_SHIPS,
1705 WID_TN_AIRCRAFTS,
1706 WID_TN_RAILS,
1707 WID_TN_ROADS,
1708 WID_TN_WATER,
1709 WID_TN_AIR,
1710 WID_TN_LANDSCAPE,
1711 WID_TN_MUSIC_SOUND,
1712 WID_TN_GOAL,
1713 WID_TN_ZOOM_IN,
1714 WID_TN_ZOOM_OUT,
1715 WID_TN_SWITCH_BAR,
1716 // lower toolbar
1717 WID_TN_PAUSE,
1718 WID_TN_FAST_FORWARD,
1719 WID_TN_SAVE,
1720 WID_TN_SMALL_MAP,
1721 WID_TN_STATIONS,
1722 WID_TN_FINANCES,
1723 WID_TN_COMPANIES,
1724 WID_TN_GRAPHS,
1725 WID_TN_INDUSTRIES,
1726 WID_TN_MESSAGES,
1727 WID_TN_RAILS,
1728 WID_TN_ROADS,
1729 WID_TN_WATER,
1730 WID_TN_AIR,
1731 WID_TN_LANDSCAPE,
1732 WID_TN_STORY,
1733 WID_TN_HELP,
1734 WID_TN_ZOOM_IN,
1735 WID_TN_ZOOM_OUT,
1736 WID_TN_SWITCH_BAR,
1737 };
1738 static const byte arrange_all[] = {
1739 WID_TN_PAUSE,
1740 WID_TN_FAST_FORWARD,
1741 WID_TN_SETTINGS,
1742 WID_TN_SAVE,
1743 WID_TN_SMALL_MAP,
1744 WID_TN_TOWNS,
1745 WID_TN_SUBSIDIES,
1746 WID_TN_STATIONS,
1747 WID_TN_FINANCES,
1748 WID_TN_COMPANIES,
1749 WID_TN_STORY,
1750 WID_TN_GOAL,
1751 WID_TN_GRAPHS,
1752 WID_TN_LEAGUE,
1753 WID_TN_INDUSTRIES,
1754 WID_TN_TRAINS,
1755 WID_TN_ROADVEHS,
1756 WID_TN_SHIPS,
1757 WID_TN_AIRCRAFTS,
1758 WID_TN_ZOOM_IN,
1759 WID_TN_ZOOM_OUT,
1760 WID_TN_RAILS,
1761 WID_TN_ROADS,
1762 WID_TN_WATER,
1763 WID_TN_AIR,
1764 WID_TN_LANDSCAPE,
1765 WID_TN_MUSIC_SOUND,
1766 WID_TN_MESSAGES,
1767 WID_TN_HELP
1768 };
1769
1770 /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
1771 uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
1772 if (full_buttons > BIGGEST_ARRANGEMENT) {
1773 button_count = arrangable_count = lengthof(arrange_all);
1774 spacer_count = this->spacers;
1775 return arrange_all;
1776 }
1777
1778 /* Introduce the split toolbar */
1779 static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
1780
1781 button_count = arrangable_count = full_buttons;
1782 spacer_count = this->spacers;
1783 return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
1784 }
1785 };
1786
1788 class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer {
1789 uint panel_widths[2];
1790
1791 void SetupSmallestSize(Window *w, bool init_array)
1792 {
1793 this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array);
1794
1795 /* Find the size of panel_widths */
1796 uint i = 0;
1797 for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
1798 if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
1799
1800 assert(i < lengthof(this->panel_widths));
1801 this->panel_widths[i++] = child_wid->current_x;
1802 _toolbar_width += child_wid->current_x;
1803 }
1804 }
1805
1806 /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
1807 {
1808 static const byte arrange_all[] = {
1809 WID_TE_PAUSE,
1810 WID_TE_FAST_FORWARD,
1811 WID_TE_SETTINGS,
1812 WID_TE_SAVE,
1813 WID_TE_SPACER,
1814 WID_TE_DATE_PANEL,
1815 WID_TE_SMALL_MAP,
1816 WID_TE_ZOOM_IN,
1817 WID_TE_ZOOM_OUT,
1818 WID_TE_LAND_GENERATE,
1819 WID_TE_TOWN_GENERATE,
1820 WID_TE_INDUSTRY,
1821 WID_TE_ROADS,
1822 WID_TE_WATER,
1823 WID_TE_TREES,
1824 WID_TE_SIGNS,
1825 WID_TE_MUSIC_SOUND,
1826 WID_TE_HELP,
1827 };
1828 static const byte arrange_nopanel[] = {
1829 WID_TE_PAUSE,
1830 WID_TE_FAST_FORWARD,
1831 WID_TE_SETTINGS,
1832 WID_TE_SAVE,
1833 WID_TE_DATE_PANEL,
1834 WID_TE_SMALL_MAP,
1835 WID_TE_ZOOM_IN,
1836 WID_TE_ZOOM_OUT,
1837 WID_TE_LAND_GENERATE,
1838 WID_TE_TOWN_GENERATE,
1839 WID_TE_INDUSTRY,
1840 WID_TE_ROADS,
1841 WID_TE_WATER,
1842 WID_TE_TREES,
1843 WID_TE_SIGNS,
1844 WID_TE_MUSIC_SOUND,
1845 WID_TE_HELP,
1846 };
1847 static const byte arrange_switch[] = {
1848 WID_TE_DATE_PANEL,
1849 WID_TE_SMALL_MAP,
1850 WID_TE_LAND_GENERATE,
1851 WID_TE_TOWN_GENERATE,
1852 WID_TE_INDUSTRY,
1853 WID_TE_ROADS,
1854 WID_TE_WATER,
1855 WID_TE_TREES,
1856 WID_TE_SIGNS,
1857 WID_TE_SWITCH_BAR,
1858 // lower toolbar
1859 WID_TE_PAUSE,
1860 WID_TE_FAST_FORWARD,
1861 WID_TE_SETTINGS,
1862 WID_TE_SAVE,
1863 WID_TE_DATE_PANEL,
1864 WID_TE_ZOOM_IN,
1865 WID_TE_ZOOM_OUT,
1866 WID_TE_MUSIC_SOUND,
1867 WID_TE_HELP, WID_TE_SWITCH_BAR,
1868 };
1869
1870 /* If we can place all buttons *and* the panels, show them. */
1871 uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
1872 if (width >= min_full_width) {
1873 width -= this->panel_widths[0] + this->panel_widths[1];
1874 arrangable_count = lengthof(arrange_all);
1875 button_count = arrangable_count - 2;
1876 spacer_count = this->spacers;
1877 return arrange_all;
1878 }
1879
1880 /* 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 */
1881 uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
1882 if (width > min_small_width) {
1883 width -= this->panel_widths[1];
1884 arrangable_count = lengthof(arrange_nopanel);
1885 button_count = arrangable_count - 1;
1886 spacer_count = this->spacers - 1;
1887 return arrange_nopanel;
1888 }
1889
1890 /* Split toolbar */
1891 width -= this->panel_widths[1];
1892 arrangable_count = lengthof(arrange_switch) / 2;
1893 button_count = arrangable_count - 1;
1894 spacer_count = 0;
1895 return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
1896 }
1897 };
1898
1899 /* --- Toolbar handling for the 'normal' case */
1900
1901 typedef CallBackFunction ToolbarButtonProc(Window *w);
1902
1903 static ToolbarButtonProc * const _toolbar_button_procs[] = {
1904 ToolbarPauseClick,
1905 ToolbarFastForwardClick,
1906 ToolbarOptionsClick,
1907 ToolbarSaveClick,
1908 ToolbarMapClick,
1909 ToolbarTownClick,
1910 ToolbarSubsidiesClick,
1911 ToolbarStationsClick,
1912 ToolbarFinancesClick,
1913 ToolbarCompaniesClick,
1914 ToolbarStoryClick,
1915 ToolbarGoalClick,
1916 ToolbarGraphsClick,
1917 ToolbarLeagueClick,
1918 ToolbarIndustryClick,
1919 ToolbarTrainClick,
1920 ToolbarRoadClick,
1921 ToolbarShipClick,
1922 ToolbarAirClick,
1923 ToolbarZoomInClick,
1924 ToolbarZoomOutClick,
1925 ToolbarBuildRailClick,
1926 ToolbarBuildRoadClick,
1927 ToolbarBuildWaterClick,
1928 ToolbarBuildAirClick,
1929 ToolbarForestClick,
1930 ToolbarMusicClick,
1931 ToolbarNewspaperClick,
1932 ToolbarHelpClick,
1933 ToolbarSwitchClick,
1934 };
1935
1936 enum MainToolbarHotkeys {
1937 MTHK_PAUSE,
1938 MTHK_FASTFORWARD,
1939 MTHK_SETTINGS,
1940 MTHK_SAVEGAME,
1941 MTHK_LOADGAME,
1942 MTHK_SMALLMAP,
1943 MTHK_TOWNDIRECTORY,
1944 MTHK_SUBSIDIES,
1945 MTHK_STATIONS,
1946 MTHK_FINANCES,
1947 MTHK_COMPANIES,
1948 MTHK_STORY,
1949 MTHK_GOAL,
1950 MTHK_GRAPHS,
1951 MTHK_LEAGUE,
1952 MTHK_INDUSTRIES,
1953 MTHK_TRAIN_LIST,
1954 MTHK_ROADVEH_LIST,
1955 MTHK_SHIP_LIST,
1956 MTHK_AIRCRAFT_LIST,
1957 MTHK_ZOOM_IN,
1958 MTHK_ZOOM_OUT,
1959 MTHK_BUILD_RAIL,
1960 MTHK_BUILD_ROAD,
1961 MTHK_BUILD_DOCKS,
1962 MTHK_BUILD_AIRPORT,
1963 MTHK_BUILD_TREES,
1964 MTHK_MUSIC,
1965 MTHK_AI_DEBUG,
1966 MTHK_SMALL_SCREENSHOT,
1967 MTHK_ZOOMEDIN_SCREENSHOT,
1968 MTHK_DEFAULTZOOM_SCREENSHOT,
1969 MTHK_GIANT_SCREENSHOT,
1970 MTHK_CHEATS,
1971 MTHK_TERRAFORM,
1972 MTHK_EXTRA_VIEWPORT,
1973 MTHK_CLIENT_LIST,
1974 MTHK_SIGN_LIST,
1975 };
1976
1978 struct MainToolbarWindow : Window {
1979 MainToolbarWindow(WindowDesc *desc) : Window(desc)
1980 {
1981 this->InitNested(0);
1982
1983 _last_started_action = CBF_NONE;
1984 CLRBITS(this->flags, WF_WHITE_BORDER);
1985 this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
1986 this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
1987 PositionMainToolbar(this);
1988 DoZoomInOutWindow(ZOOM_NONE, this);
1989 }
1990
1991 virtual void FindWindowPlacementAndResize(int def_width, int def_height)
1992 {
1993 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
1994 }
1995
1996 virtual void OnPaint()
1997 {
1998 /* If spectator, disable all construction buttons
1999 * ie : Build road, rail, ships, airports and landscaping
2000 * Since enabled state is the default, just disable when needed */
2001 this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END);
2002 /* disable company list drop downs, if there are no companies */
2003 this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END);
2004
2005 this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0);
2006 this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0);
2007
2008 this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN));
2009 this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
2010
2011 this->DrawWidgets();
2012 }
2013
2014 virtual void OnClick(Point pt, int widget, int click_count)
2015 {
2016 if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
2017 }
2018
2019 virtual void OnDropdownSelect(int widget, int index)
2020 {
2021 CallBackFunction cbf = _menu_clicked_procs[widget](index);
2022 if (cbf != CBF_NONE) _last_started_action = cbf;
2023 }
2024
2025 virtual EventState OnHotkey(int hotkey)
2026 {
2027 switch (hotkey) {
2028 case MTHK_PAUSE: ToolbarPauseClick(this); break;
2029 case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2030 case MTHK_SETTINGS: ShowGameOptions(); break;
2031 case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
2032 case MTHK_LOADGAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
2033 case MTHK_SMALLMAP: ShowSmallMap(); break;
2034 case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
2035 case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
2036 case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
2037 case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
2038 case MTHK_COMPANIES: ShowCompany(_local_company); break;
2039 case MTHK_STORY: ShowStoryBook(_local_company); break;
2040 case MTHK_GOAL: ShowGoalsList(_local_company); break;
2041 case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
2042 case MTHK_LEAGUE: ShowCompanyLeagueTable(); break;
2043 case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
2044 case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
2045 case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
2046 case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
2047 case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
2048 case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2049 case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2050 case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break;
2051 case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
2052 case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
2053 case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
2054 case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
2055 case MTHK_MUSIC: ShowMusicWindow(); break;
2056 case MTHK_AI_DEBUG: ShowAIDebugWindow(); break;
2057 case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
2058 case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
2059 case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
2060 case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
2061 case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
2062 case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
2063 case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
2064 #ifdef ENABLE_NETWORK
2065 case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
2066 #endif
2067 case MTHK_SIGN_LIST: ShowSignList(); break;
2068 default: return ES_NOT_HANDLED;
2069 }
2070 return ES_HANDLED;
2071 }
2072
2073 virtual void OnPlaceObject(Point pt, TileIndex tile)
2074 {
2075 switch (_last_started_action) {
2076 case CBF_PLACE_SIGN:
2077 PlaceProc_Sign(tile);
2078 break;
2079
2080 case CBF_PLACE_LANDINFO:
2081 ShowLandInfo(tile);
2082 break;
2083
2084 default: NOT_REACHED();
2085 }
2086 }
2087
2088 virtual void OnPlaceObjectAbort()
2089 {
2090 _last_started_action = CBF_NONE;
2091 }
2092
2093 virtual void OnTick()
2094 {
2095 if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
2096 this->ToggleWidgetLoweredState(WID_TN_PAUSE);
2097 this->SetWidgetDirty(WID_TN_PAUSE);
2098 }
2099
2100 if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) {
2101 this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD);
2102 this->SetWidgetDirty(WID_TN_FAST_FORWARD);
2103 }
2104 }
2105
2106 virtual void OnTimeout()
2107 {
2108 /* We do not want to automatically raise the pause, fast forward and
2109 * switchbar buttons; they have to stay down when pressed etc. */
2110 for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
2111 if (this->IsWidgetLowered(i)) {
2112 this->RaiseWidget(i);
2113 this->SetWidgetDirty(i);
2114 }
2115 }
2116 }
2117
2123 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2124 {
2125 if (!gui_scope) return;
2126 if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
2127 }
2128
2129 static HotkeyList hotkeys;
2130 };
2131
2132 const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0};
2133 const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0};
2134 const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0};
2135 const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0};
2136
2137 static Hotkey maintoolbar_hotkeys[] = {
2138 Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE),
2139 Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD),
2140 Hotkey(WKC_F2, "settings", MTHK_SETTINGS),
2141 Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME),
2142 Hotkey((uint16)0, "load_game", MTHK_LOADGAME),
2143 Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP),
2144 Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
2145 Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES),
2146 Hotkey(WKC_F7, "station_list", MTHK_STATIONS),
2147 Hotkey(WKC_F8, "finances", MTHK_FINANCES),
2148 Hotkey(WKC_F9, "companies", MTHK_COMPANIES),
2149 Hotkey((uint16)0, "story_book", MTHK_STORY),
2150 Hotkey((uint16)0, "goal_list", MTHK_GOAL),
2151 Hotkey(WKC_F10, "graphs", MTHK_GRAPHS),
2152 Hotkey(WKC_F11, "league", MTHK_LEAGUE),
2153 Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES),
2154 Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
2155 Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
2156 Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
2157 Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
2158 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN),
2159 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT),
2160 Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
2161 Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
2162 Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
2163 Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
2164 Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
2165 Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
2166 Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG),
2167 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
2168 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
2169 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT),
2170 Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
2171 Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
2172 Hotkey('L', "terraform", MTHK_TERRAFORM),
2173 Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
2174 #ifdef ENABLE_NETWORK
2175 Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
2176 #endif
2177 Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
2178 HOTKEY_LIST_END
2179 };
2180 HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
2181
2182 static NWidgetBase *MakeMainToolbar(int *biggest_index)
2183 {
2185 static const SpriteID toolbar_button_sprites[] = {
2186 SPR_IMG_PAUSE, // WID_TN_PAUSE
2187 SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD
2188 SPR_IMG_SETTINGS, // WID_TN_SETTINGS
2189 SPR_IMG_SAVE, // WID_TN_SAVE
2190 SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP
2191 SPR_IMG_TOWN, // WID_TN_TOWNS
2192 SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES
2193 SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS
2194 SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
2195 SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
2196 SPR_IMG_STORY_BOOK, // WID_TN_STORY
2197 SPR_IMG_GOAL, // WID_TN_GOAL
2198 SPR_IMG_GRAPHS, // WID_TN_GRAPHS
2199 SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE
2200 SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES
2201 SPR_IMG_TRAINLIST, // WID_TN_TRAINS
2202 SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS
2203 SPR_IMG_SHIPLIST, // WID_TN_SHIPS
2204 SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT
2205 SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN
2206 SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT
2207 SPR_IMG_BUILDRAIL, // WID_TN_RAILS
2208 SPR_IMG_BUILDROAD, // WID_TN_ROADS
2209 SPR_IMG_BUILDWATER, // WID_TN_WATER
2210 SPR_IMG_BUILDAIR, // WID_TN_AIR
2211 SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
2212 SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
2213 SPR_IMG_MESSAGES, // WID_TN_MESSAGES
2214 SPR_IMG_QUERY, // WID_TN_HELP
2215 SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
2216 };
2217
2218 NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
2219 for (uint i = 0; i < WID_TN_END; i++) {
2220 switch (i) {
2221 case WID_TN_SMALL_MAP:
2222 case WID_TN_FINANCES:
2223 case WID_TN_VEHICLE_START:
2224 case WID_TN_ZOOM_IN:
2225 case WID_TN_BUILDING_TOOLS_START:
2226 case WID_TN_MUSIC_SOUND:
2227 hor->Add(new NWidgetSpacer(0, 0));
2228 break;
2229 }
2230 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));
2231 }
2232
2233 *biggest_index = max<int>(*biggest_index, WID_TN_SWITCH_BAR);
2234 return hor;
2235 }
2236
2237 static const NWidgetPart _nested_toolbar_normal_widgets[] = {
2238 NWidgetFunction(MakeMainToolbar),
2239 };
2240
2241 static WindowDesc _toolb_normal_desc(
2242 WDP_MANUAL, NULL, 0, 0,
2243 WC_MAIN_TOOLBAR, WC_NONE,
2244 WDF_NO_FOCUS,
2245 _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets),
2246 &MainToolbarWindow::hotkeys
2247 );
2248
2249
2250 /* --- Toolbar handling for the scenario editor */
2251
2252 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
2253 ToolbarPauseClick,
2254 ToolbarFastForwardClick,
2255 ToolbarOptionsClick,
2256 ToolbarScenSaveOrLoad,
2257 ToolbarBtn_NULL,
2258 ToolbarScenDatePanel,
2259 ToolbarScenDateBackward,
2260 ToolbarScenDateForward,
2261 ToolbarScenMapTownDir,
2262 ToolbarZoomInClick,
2263 ToolbarZoomOutClick,
2264 ToolbarScenGenLand,
2265 ToolbarScenGenTown,
2266 ToolbarScenGenIndustry,
2267 ToolbarScenBuildRoad,
2268 ToolbarScenBuildDocks,
2269 ToolbarScenPlantTrees,
2270 ToolbarScenPlaceSign,
2271 ToolbarBtn_NULL,
2272 NULL,
2273 NULL,
2274 NULL,
2275 NULL,
2276 NULL,
2277 NULL,
2278 NULL,
2279 ToolbarMusicClick,
2280 NULL,
2281 ToolbarHelpClick,
2282 ToolbarSwitchClick,
2283 };
2284
2285 enum MainToolbarEditorHotkeys {
2286 MTEHK_PAUSE,
2287 MTEHK_FASTFORWARD,
2288 MTEHK_SETTINGS,
2289 MTEHK_SAVEGAME,
2290 MTEHK_GENLAND,
2291 MTEHK_GENTOWN,
2292 MTEHK_GENINDUSTRY,
2293 MTEHK_BUILD_ROAD,
2294 MTEHK_BUILD_DOCKS,
2295 MTEHK_BUILD_TREES,
2296 MTEHK_SIGN,
2297 MTEHK_MUSIC,
2298 MTEHK_LANDINFO,
2299 MTEHK_SMALL_SCREENSHOT,
2300 MTEHK_ZOOMEDIN_SCREENSHOT,
2301 MTEHK_DEFAULTZOOM_SCREENSHOT,
2302 MTEHK_GIANT_SCREENSHOT,
2303 MTEHK_ZOOM_IN,
2304 MTEHK_ZOOM_OUT,
2305 MTEHK_TERRAFORM,
2306 MTEHK_SMALLMAP,
2307 MTEHK_EXTRA_VIEWPORT,
2308 };
2309
2310 struct ScenarioEditorToolbarWindow : Window {
2311 ScenarioEditorToolbarWindow(WindowDesc *desc) : Window(desc)
2312 {
2313 this->InitNested(0);
2314
2315 _last_started_action = CBF_NONE;
2316 CLRBITS(this->flags, WF_WHITE_BORDER);
2317 PositionMainToolbar(this);
2318 DoZoomInOutWindow(ZOOM_NONE, this);
2319 }
2320
2321 virtual void FindWindowPlacementAndResize(int def_width, int def_height)
2322 {
2323 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
2324 }
2325
2326 virtual void OnPaint()
2327 {
2328 this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR);
2329 this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR);
2330
2331 this->DrawWidgets();
2332 }
2333
2334 virtual void DrawWidget(const Rect &r, int widget) const
2335 {
2336 switch (widget) {
2337 case WID_TE_DATE:
2338 SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
2339 DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER);
2340 break;
2341
2342 case WID_TE_SPACER: {
2343 int height = r.bottom - r.top;
2344 if (height > 2 * FONT_HEIGHT_NORMAL) {
2345 DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
2346 DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2347 } else {
2348 DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2349 }
2350 break;
2351 }
2352 }
2353 }
2354
2355 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
2356 {
2357 switch (widget) {
2358 case WID_TE_SPACER:
2359 size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
2360 break;
2361
2362 case WID_TE_DATE:
2363 SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1));
2364 *size = GetStringBoundingBox(STR_WHITE_DATE_LONG);
2365 size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM);
2366 break;
2367 }
2368 }
2369
2370 virtual void OnClick(Point pt, int widget, int click_count)
2371 {
2372 if (_game_mode == GM_MENU) return;
2373 CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
2374 if (cbf != CBF_NONE) _last_started_action = cbf;
2375 }
2376
2377 virtual void OnDropdownSelect(int widget, int index)
2378 {
2379 /* The map button is in a different location on the scenario
2380 * editor toolbar, so we need to adjust for it. */
2381 if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP;
2382 CallBackFunction cbf = _menu_clicked_procs[widget](index);
2383 if (cbf != CBF_NONE) _last_started_action = cbf;
2384 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
2385 }
2386
2387 virtual EventState OnHotkey(int hotkey)
2388 {
2389 CallBackFunction cbf = CBF_NONE;
2390 switch (hotkey) {
2391 case MTEHK_PAUSE: ToolbarPauseClick(this); break;
2392 case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2393 case MTEHK_SETTINGS: ShowGameOptions(); break;
2394 case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
2395 case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
2396 case MTEHK_GENTOWN: ToolbarScenGenTown(this); break;
2397 case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
2398 case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break;
2399 case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break;
2400 case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break;
2401 case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break;
2402 case MTEHK_MUSIC: ShowMusicWindow(); break;
2403 case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2404 case MTEHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
2405 case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
2406 case MTEHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
2407 case MTEHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
2408 case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2409 case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2410 case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break;
2411 case MTEHK_SMALLMAP: ShowSmallMap(); break;
2412 case MTEHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
2413 default: return ES_NOT_HANDLED;
2414 }
2415 if (cbf != CBF_NONE) _last_started_action = cbf;
2416 return ES_HANDLED;
2417 }
2418
2419 virtual void OnPlaceObject(Point pt, TileIndex tile)
2420 {
2421 switch (_last_started_action) {
2422 case CBF_PLACE_SIGN:
2423 PlaceProc_Sign(tile);
2424 break;
2425
2426 case CBF_PLACE_LANDINFO:
2427 ShowLandInfo(tile);
2428 break;
2429
2430 default: NOT_REACHED();
2431 }
2432 }
2433
2434 virtual void OnPlaceObjectAbort()
2435 {
2436 _last_started_action = CBF_NONE;
2437 }
2438
2439 virtual void OnTimeout()
2440 {
2441 this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END);
2442 this->SetWidgetDirty(WID_TE_DATE_BACKWARD);
2443 this->SetWidgetDirty(WID_TE_DATE_FORWARD);
2444 }
2445
2446 virtual void OnTick()
2447 {
2448 if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
2449 this->ToggleWidgetLoweredState(WID_TE_PAUSE);
2450 this->SetDirty();
2451 }
2452
2453 if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) {
2454 this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD);
2455 this->SetDirty();
2456 }
2457 }
2458
2464 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2465 {
2466 if (!gui_scope) return;
2467 if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
2468 }
2469
2470 virtual void OnQueryTextFinished(char *str)
2471 {
2472 /* Was 'cancel' pressed? */
2473 if (str == NULL) return;
2474
2475 int32 value;
2476 if (!StrEmpty(str)) {
2477 value = atoi(str);
2478 } else {
2479 /* An empty string means revert to the default */
2480 value = DEF_START_YEAR;
2481 }
2482 SetStartingYear(value);
2483
2484 this->SetDirty();
2485 }
2486
2487 static HotkeyList hotkeys;
2488 };
2489
2490 static Hotkey scenedit_maintoolbar_hotkeys[] = {
2491 Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE),
2492 Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD),
2493 Hotkey(WKC_F2, "settings", MTEHK_SETTINGS),
2494 Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME),
2495 Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND),
2496 Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN),
2497 Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
2498 Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
2499 Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
2500 Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
2501 Hotkey(WKC_F10, "build_sign", MTEHK_SIGN),
2502 Hotkey(WKC_F11, "music", MTEHK_MUSIC),
2503 Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO),
2504 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
2505 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
2506 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT),
2507 Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
2508 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN),
2509 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT),
2510 Hotkey('L', "terraform", MTEHK_TERRAFORM),
2511 Hotkey('M', "smallmap", MTEHK_SMALLMAP),
2512 Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
2513 HOTKEY_LIST_END
2514 };
2515 HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys);
2516
2517 static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
2518 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
2519 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
2520 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
2521 NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
2522 NWidget(NWID_SPACER),
2523 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
2524 NWidget(NWID_SPACER),
2525 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
2526 NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
2527 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD),
2528 NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE),
2529 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD),
2530 EndContainer(),
2531 EndContainer(),
2532 NWidget(NWID_SPACER),
2533 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
2534 NWidget(NWID_SPACER),
2535 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
2536 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
2537 NWidget(NWID_SPACER),
2538 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
2539 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
2540 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
2541 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
2542 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
2543 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
2544 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
2545 NWidget(NWID_SPACER),
2546 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
2547 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
2548 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
2549 };
2550
2551 static NWidgetBase *MakeScenarioToolbar(int *biggest_index)
2552 {
2553 return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer());
2554 }
2555
2556 static const NWidgetPart _nested_toolb_scen_widgets[] = {
2557 NWidgetFunction(MakeScenarioToolbar),
2558 };
2559
2560 static WindowDesc _toolb_scen_desc(
2561 WDP_MANUAL, NULL, 0, 0,
2562 WC_MAIN_TOOLBAR, WC_NONE,
2563 WDF_NO_FOCUS,
2564 _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets),
2565 &ScenarioEditorToolbarWindow::hotkeys
2566 );
2567
2569 void AllocateToolbar()
2570 {
2571 /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
2572 _last_built_roadtype = ROADTYPE_ROAD;
2573
2574 if (_game_mode == GM_EDITOR) {
2575 new ScenarioEditorToolbarWindow(&_toolb_scen_desc);
2576 } else {
2577 new MainToolbarWindow(&_toolb_normal_desc);
2578 }
2579 }