Change: Let AI developers edit non-editable AI/Game Script Parameters (#8895)
[openttd-github.git] / src / toolbar_gui.cpp
blob8c2db4d88722172e005627d28574a38f433c427f
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file toolbar_gui.cpp Code related to the (main) toolbar. */
10 #include "stdafx.h"
11 #include "gui.h"
12 #include "window_gui.h"
13 #include "window_func.h"
14 #include "viewport_func.h"
15 #include "command_func.h"
16 #include "vehicle_gui.h"
17 #include "rail_gui.h"
18 #include "road.h"
19 #include "road_gui.h"
20 #include "date_func.h"
21 #include "vehicle_func.h"
22 #include "sound_func.h"
23 #include "terraform_gui.h"
24 #include "strings_func.h"
25 #include "company_func.h"
26 #include "company_gui.h"
27 #include "vehicle_base.h"
28 #include "cheat_func.h"
29 #include "transparency_gui.h"
30 #include "screenshot.h"
31 #include "signs_func.h"
32 #include "fios.h"
33 #include "console_gui.h"
34 #include "news_gui.h"
35 #include "ai/ai_gui.hpp"
36 #include "tilehighlight_func.h"
37 #include "smallmap_gui.h"
38 #include "graph_gui.h"
39 #include "textbuf_gui.h"
40 #include "linkgraph/linkgraph_gui.h"
41 #include "newgrf_debug.h"
42 #include "hotkeys.h"
43 #include "engine_base.h"
44 #include "highscore.h"
45 #include "game/game.hpp"
46 #include "goal_base.h"
47 #include "story_base.h"
48 #include "toolbar_gui.h"
49 #include "framerate_type.h"
50 #include "guitimer_func.h"
51 #include "screenshot_gui.h"
52 #include "misc_cmd.h"
54 #include "widgets/toolbar_widget.h"
56 #include "network/network.h"
57 #include "network/network_gui.h"
58 #include "network/network_func.h"
60 #include "safeguards.h"
63 /** Width of the toolbar, shared by statusbar. */
64 uint _toolbar_width = 0;
66 RailType _last_built_railtype;
67 RoadType _last_built_roadtype;
68 RoadType _last_built_tramtype;
70 /** Toobar modes */
71 enum ToolbarMode {
72 TB_NORMAL,
73 TB_UPPER,
74 TB_LOWER
77 /** Callback functions. */
78 enum CallBackFunction {
79 CBF_NONE,
80 CBF_PLACE_SIGN,
81 CBF_PLACE_LANDINFO,
84 static CallBackFunction _last_started_action = CBF_NONE; ///< Last started user action.
87 /**
88 * Drop down list entry for showing a checked/unchecked toggle item.
90 class DropDownListCheckedItem : public DropDownListStringItem {
91 uint checkmark_width;
92 public:
93 bool checked;
95 DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked)
97 this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
100 uint Width() const
102 return DropDownListStringItem::Width() + this->checkmark_width;
105 void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const
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);
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);
116 * Drop down list entry for showing a company entry, with companies 'blob'.
118 class DropDownListCompanyItem : public DropDownListItem {
119 Dimension icon_size;
120 Dimension lock_size;
121 public:
122 bool greyed;
124 DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
126 this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
127 this->lock_size = GetSpriteSize(SPR_LOCK);
130 bool Selectable() const override
132 return true;
135 uint Width() const override
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 + this->lock_size.width + 6;
143 uint Height(uint width) const override
145 return std::max(std::max(this->icon_size.height, this->lock_size.height) + 2U, (uint)FONT_HEIGHT_NORMAL);
148 void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const override
150 CompanyID company = (CompanyID)this->result;
151 bool rtl = _current_text_dir == TD_RTL;
153 /* It's possible the company is deleted while the dropdown is open */
154 if (!Company::IsValidID(company)) return;
156 int icon_offset = (bottom - top - icon_size.height) / 2;
157 int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2;
158 int lock_offset = (bottom - top - lock_size.height) / 2;
160 DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset);
161 if (NetworkCompanyIsPassworded(company)) {
162 DrawSprite(SPR_LOCK, PAL_NONE, rtl ? left + WD_FRAMERECT_LEFT : right - this->lock_size.width - WD_FRAMERECT_RIGHT, top + lock_offset);
165 SetDParam(0, company);
166 SetDParam(1, company);
167 TextColour col;
168 if (this->greyed) {
169 col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
170 } else {
171 col = sel ? TC_WHITE : TC_BLACK;
173 DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 3 + this->lock_size.width : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 3 + this->lock_size.width), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col);
178 * Pop up a generic text only menu.
179 * @param w Toolbar
180 * @param widget Toolbar button
181 * @param list List of items
182 * @param def Default item
184 static void PopupMainToolbMenu(Window *w, int widget, DropDownList &&list, int def)
186 ShowDropDownList(w, std::move(list), def, widget, 0, true, true);
187 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
191 * Pop up a generic text only menu.
192 * @param w Toolbar
193 * @param widget Toolbar button
194 * @param string String for the first item in the menu
195 * @param count Number of items in the menu
197 static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count)
199 DropDownList list;
200 for (int i = 0; i < count; i++) {
201 list.emplace_back(new DropDownListStringItem(string + i, i, false));
203 PopupMainToolbMenu(w, widget, std::move(list), 0);
206 /** Enum for the Company Toolbar's network related buttons */
207 static const int CTMN_CLIENT_LIST = -1; ///< Show the client list
208 static const int CTMN_SPECTATE = -2; ///< Become spectator
209 static const int CTMN_SPECTATOR = -3; ///< Show a company window as spectator
212 * Pop up a generic company list menu.
213 * @param w The toolbar window.
214 * @param widget The button widget id.
215 * @param grey A bitbask of which items to mark as disabled.
217 static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0)
219 DropDownList list;
221 switch (widget) {
222 case WID_TN_COMPANIES:
223 if (!_networking) break;
225 /* Add the client list button for the companies menu */
226 list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false));
228 if (_local_company != COMPANY_SPECTATOR) {
229 list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, false));
231 break;
232 case WID_TN_STORY:
233 list.emplace_back(new DropDownListStringItem(STR_STORY_BOOK_SPECTATOR, CTMN_SPECTATOR, false));
234 break;
236 case WID_TN_GOAL:
237 list.emplace_back(new DropDownListStringItem(STR_GOALS_SPECTATOR, CTMN_SPECTATOR, false));
238 break;
241 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
242 if (!Company::IsValidID(c)) continue;
243 list.emplace_back(new DropDownListCompanyItem(c, false, HasBit(grey, c)));
246 PopupMainToolbMenu(w, widget, std::move(list), _local_company == COMPANY_SPECTATOR ? (widget == WID_TN_COMPANIES ? CTMN_CLIENT_LIST : CTMN_SPECTATOR) : (int)_local_company);
250 static ToolbarMode _toolbar_mode;
252 static CallBackFunction SelectSignTool()
254 if (_last_started_action == CBF_PLACE_SIGN) {
255 ResetObjectToPlace();
256 return CBF_NONE;
257 } else {
258 SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
259 return CBF_PLACE_SIGN;
263 /* --- Pausing --- */
265 static CallBackFunction ToolbarPauseClick(Window *w)
267 if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
269 if (Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED)) {
270 if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
272 return CBF_NONE;
276 * Toggle fast forward mode.
278 * @param w Unused.
279 * @return #CBF_NONE
281 static CallBackFunction ToolbarFastForwardClick(Window *w)
283 ChangeGameSpeed(_game_speed == 100);
285 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
286 return CBF_NONE;
290 * Game Option button menu entries.
292 enum OptionMenuEntries {
293 OME_GAMEOPTIONS,
294 OME_SETTINGS,
295 OME_SCRIPT_SETTINGS,
296 OME_NEWGRFSETTINGS,
297 OME_TRANSPARENCIES,
298 OME_SHOW_TOWNNAMES,
299 OME_SHOW_STATIONNAMES,
300 OME_SHOW_WAYPOINTNAMES,
301 OME_SHOW_SIGNS,
302 OME_SHOW_COMPETITOR_SIGNS,
303 OME_FULL_ANIMATION,
304 OME_FULL_DETAILS,
305 OME_TRANSPARENTBUILDINGS,
306 OME_SHOW_STATIONSIGNS,
310 * Handle click on Options button in toolbar.
312 * @param w parent window the shown Drop down list is attached to.
313 * @return #CBF_NONE
315 static CallBackFunction ToolbarOptionsClick(Window *w)
317 DropDownList list;
318 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false));
319 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false));
320 /* Changes to the per-AI settings don't get send from the server to the clients. Clients get
321 * the settings once they join but never update it. As such don't show the window at all
322 * to network clients. */
323 if (!_networking || _network_server) list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false));
324 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false));
325 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false));
326 list.emplace_back(new DropDownListItem(-1, false));
327 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)));
328 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)));
329 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)));
330 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)));
331 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)));
332 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)));
333 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)));
334 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)));
335 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)));
337 ShowDropDownList(w, std::move(list), 0, WID_TN_SETTINGS, 140, true, true);
338 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
339 return CBF_NONE;
343 * Handle click on one of the entries in the Options button menu.
345 * @param index Index being clicked.
346 * @return #CBF_NONE
348 static CallBackFunction MenuClickSettings(int index)
350 switch (index) {
351 case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE;
352 case OME_SETTINGS: ShowGameSettings(); return CBF_NONE;
353 case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE;
354 case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
355 case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break;
357 case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break;
358 case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break;
359 case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break;
360 case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break;
361 case OME_SHOW_COMPETITOR_SIGNS:
362 ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
363 InvalidateWindowClassesData(WC_SIGN_LIST, -1);
364 break;
365 case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break;
366 case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break;
367 case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break;
368 case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break;
370 MarkWholeScreenDirty();
371 return CBF_NONE;
375 * SaveLoad entries in scenario editor mode.
377 enum SaveLoadEditorMenuEntries {
378 SLEME_SAVE_SCENARIO = 0,
379 SLEME_LOAD_SCENARIO,
380 SLEME_SAVE_HEIGHTMAP,
381 SLEME_LOAD_HEIGHTMAP,
382 SLEME_EXIT_TOINTRO,
383 SLEME_EXIT_GAME = 6,
384 SLEME_MENUCOUNT,
388 * SaveLoad entries in normal game mode.
390 enum SaveLoadNormalMenuEntries {
391 SLNME_SAVE_GAME = 0,
392 SLNME_LOAD_GAME,
393 SLNME_EXIT_TOINTRO,
394 SLNME_EXIT_GAME = 4,
395 SLNME_MENUCOUNT,
399 * Handle click on Save button in toolbar in normal game mode.
401 * @param w parent window the shown save dialogue is attached to.
402 * @return #CBF_NONE
404 static CallBackFunction ToolbarSaveClick(Window *w)
406 PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT);
407 return CBF_NONE;
411 * Handle click on SaveLoad button in toolbar in the scenario editor.
413 * @param w parent window the shown save dialogue is attached to.
414 * @return #CBF_NONE
416 static CallBackFunction ToolbarScenSaveOrLoad(Window *w)
418 PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT);
419 return CBF_NONE;
423 * Handle click on one of the entries in the SaveLoad menu.
425 * @param index Index being clicked.
426 * @return #CBF_NONE
428 static CallBackFunction MenuClickSaveLoad(int index = 0)
430 if (_game_mode == GM_EDITOR) {
431 switch (index) {
432 case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_SAVE); break;
433 case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD); break;
434 case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_SAVE); break;
435 case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_LOAD); break;
436 case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break;
437 case SLEME_EXIT_GAME: HandleExitGameRequest(); break;
439 } else {
440 switch (index) {
441 case SLNME_SAVE_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_SAVE); break;
442 case SLNME_LOAD_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
443 case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break;
444 case SLNME_EXIT_GAME: HandleExitGameRequest(); break;
447 return CBF_NONE;
450 /* --- Map button menu --- */
452 enum MapMenuEntries {
453 MME_SHOW_SMALLMAP = 0,
454 MME_SHOW_EXTRAVIEWPORTS,
455 MME_SHOW_LINKGRAPH,
456 MME_SHOW_SIGNLISTS,
457 MME_SHOW_TOWNDIRECTORY,
458 MME_SHOW_INDUSTRYDIRECTORY,
461 static CallBackFunction ToolbarMapClick(Window *w)
463 DropDownList list;
464 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false));
465 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEWPORT, MME_SHOW_EXTRAVIEWPORTS, false));
466 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false));
467 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false));
468 PopupMainToolbMenu(w, WID_TN_SMALL_MAP, std::move(list), 0);
469 return CBF_NONE;
472 static CallBackFunction ToolbarScenMapTownDir(Window *w)
474 DropDownList list;
475 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false));
476 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEWPORT, MME_SHOW_EXTRAVIEWPORTS, false));
477 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false));
478 list.emplace_back(new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false));
479 list.emplace_back(new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false));
480 PopupMainToolbMenu(w, WID_TE_SMALL_MAP, std::move(list), 0);
481 return CBF_NONE;
485 * Handle click on one of the entries in the Map menu.
487 * @param index Index being clicked.
488 * @return #CBF_NONE
490 static CallBackFunction MenuClickMap(int index)
492 switch (index) {
493 case MME_SHOW_SMALLMAP: ShowSmallMap(); break;
494 case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewportWindow(); break;
495 case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break;
496 case MME_SHOW_SIGNLISTS: ShowSignList(); break;
497 case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
498 case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break;
500 return CBF_NONE;
503 /* --- Town button menu --- */
505 static CallBackFunction ToolbarTownClick(Window *w)
507 PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
508 return CBF_NONE;
512 * Handle click on one of the entries in the Town menu.
514 * @param index Index being clicked.
515 * @return #CBF_NONE
517 static CallBackFunction MenuClickTown(int index)
519 switch (index) {
520 case 0: ShowTownDirectory(); break;
521 case 1: // setting could be changed when the dropdown was open
522 if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
523 break;
525 return CBF_NONE;
528 /* --- Subidies button menu --- */
530 static CallBackFunction ToolbarSubsidiesClick(Window *w)
532 PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1);
533 return CBF_NONE;
537 * Handle click on the entry in the Subsidies menu.
539 * @param index Unused.
540 * @return #CBF_NONE
542 static CallBackFunction MenuClickSubsidies(int index)
544 switch (index) {
545 case 0: ShowSubsidiesList(); break;
547 return CBF_NONE;
550 /* --- Stations button menu --- */
552 static CallBackFunction ToolbarStationsClick(Window *w)
554 PopupMainCompanyToolbMenu(w, WID_TN_STATIONS);
555 return CBF_NONE;
559 * Handle click on the entry in the Stations menu
561 * @param index CompanyID to show station list for
562 * @return #CBF_NONE
564 static CallBackFunction MenuClickStations(int index)
566 ShowCompanyStations((CompanyID)index);
567 return CBF_NONE;
570 /* --- Finances button menu --- */
572 static CallBackFunction ToolbarFinancesClick(Window *w)
574 PopupMainCompanyToolbMenu(w, WID_TN_FINANCES);
575 return CBF_NONE;
579 * Handle click on the entry in the finances overview menu.
581 * @param index CompanyID to show finances for.
582 * @return #CBF_NONE
584 static CallBackFunction MenuClickFinances(int index)
586 ShowCompanyFinances((CompanyID)index);
587 return CBF_NONE;
590 /* --- Company's button menu --- */
592 static CallBackFunction ToolbarCompaniesClick(Window *w)
594 PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0);
595 return CBF_NONE;
599 * Handle click on the entry in the Company menu.
601 * @param index Menu entry to handle.
602 * @return #CBF_NONE
604 static CallBackFunction MenuClickCompany(int index)
606 if (_networking) {
607 switch (index) {
608 case CTMN_CLIENT_LIST:
609 ShowClientList();
610 return CBF_NONE;
612 case CTMN_SPECTATE:
613 if (_network_server) {
614 NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR);
615 MarkWholeScreenDirty();
616 } else {
617 NetworkClientRequestMove(COMPANY_SPECTATOR);
619 return CBF_NONE;
622 ShowCompany((CompanyID)index);
623 return CBF_NONE;
626 /* --- Story button menu --- */
628 static CallBackFunction ToolbarStoryClick(Window *w)
630 PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0);
631 return CBF_NONE;
635 * Handle click on the entry in the Story menu
637 * @param index CompanyID to show story book for
638 * @return #CBF_NONE
640 static CallBackFunction MenuClickStory(int index)
642 ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
643 return CBF_NONE;
646 /* --- Goal button menu --- */
648 static CallBackFunction ToolbarGoalClick(Window *w)
650 PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0);
651 return CBF_NONE;
655 * Handle click on the entry in the Goal menu
657 * @param index CompanyID to show story book for
658 * @return #CBF_NONE
660 static CallBackFunction MenuClickGoal(int index)
662 ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
663 return CBF_NONE;
666 /* --- Graphs button menu --- */
668 static CallBackFunction ToolbarGraphsClick(Window *w)
670 PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8);
671 return CBF_NONE;
675 * Handle click on the entry in the Graphs menu.
677 * @param index Graph to show.
678 * @return #CBF_NONE
680 static CallBackFunction MenuClickGraphs(int index)
682 switch (index) {
683 case 0: ShowOperatingProfitGraph(); break;
684 case 1: ShowIncomeGraph(); break;
685 case 2: ShowDeliveredCargoGraph(); break;
686 case 3: ShowPerformanceHistoryGraph(); break;
687 case 4: ShowCompanyValueGraph(); break;
688 case 5: ShowCargoPaymentRates(); break;
689 /* functions for combined graphs/league button */
690 case 6: ShowCompanyLeagueTable(); break;
691 case 7: ShowPerformanceRatingDetail(); break;
693 return CBF_NONE;
696 /* --- League button menu --- */
698 static CallBackFunction ToolbarLeagueClick(Window *w)
700 PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3);
701 return CBF_NONE;
705 * Handle click on the entry in the CompanyLeague menu.
707 * @param index Menu entry number.
708 * @return #CBF_NONE
710 static CallBackFunction MenuClickLeague(int index)
712 switch (index) {
713 case 0: ShowCompanyLeagueTable(); break;
714 case 1: ShowPerformanceRatingDetail(); break;
715 case 2: ShowHighscoreTable(); break;
717 return CBF_NONE;
720 /* --- Industries button menu --- */
722 static CallBackFunction ToolbarIndustryClick(Window *w)
724 /* Disable build-industry menu if we are a spectator */
725 PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3);
726 return CBF_NONE;
730 * Handle click on the entry in the Industry menu.
732 * @param index Menu entry number.
733 * @return #CBF_NONE
735 static CallBackFunction MenuClickIndustry(int index)
737 switch (index) {
738 case 0: ShowIndustryDirectory(); break;
739 case 1: ShowIndustryCargoesWindow(); break;
740 case 2: ShowBuildIndustryWindow(); break;
742 return CBF_NONE;
745 /* --- Trains button menu + 1 helper function for all vehicles. --- */
747 static void ToolbarVehicleClick(Window *w, VehicleType veh)
749 int dis = ~0;
751 for (const Vehicle *v : Vehicle::Iterate()) {
752 if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner);
754 PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis);
758 static CallBackFunction ToolbarTrainClick(Window *w)
760 ToolbarVehicleClick(w, VEH_TRAIN);
761 return CBF_NONE;
765 * Handle click on the entry in the Train menu.
767 * @param index CompanyID to show train list for.
768 * @return #CBF_NONE
770 static CallBackFunction MenuClickShowTrains(int index)
772 ShowVehicleListWindow((CompanyID)index, VEH_TRAIN);
773 return CBF_NONE;
776 /* --- Road vehicle button menu --- */
778 static CallBackFunction ToolbarRoadClick(Window *w)
780 ToolbarVehicleClick(w, VEH_ROAD);
781 return CBF_NONE;
785 * Handle click on the entry in the Road Vehicles menu.
787 * @param index CompanyID to show road vehicles list for.
788 * @return #CBF_NONE
790 static CallBackFunction MenuClickShowRoad(int index)
792 ShowVehicleListWindow((CompanyID)index, VEH_ROAD);
793 return CBF_NONE;
796 /* --- Ship button menu --- */
798 static CallBackFunction ToolbarShipClick(Window *w)
800 ToolbarVehicleClick(w, VEH_SHIP);
801 return CBF_NONE;
805 * Handle click on the entry in the Ships menu.
807 * @param index CompanyID to show ship list for.
808 * @return #CBF_NONE
810 static CallBackFunction MenuClickShowShips(int index)
812 ShowVehicleListWindow((CompanyID)index, VEH_SHIP);
813 return CBF_NONE;
816 /* --- Aircraft button menu --- */
818 static CallBackFunction ToolbarAirClick(Window *w)
820 ToolbarVehicleClick(w, VEH_AIRCRAFT);
821 return CBF_NONE;
825 * Handle click on the entry in the Aircraft menu.
827 * @param index CompanyID to show aircraft list for.
828 * @return #CBF_NONE
830 static CallBackFunction MenuClickShowAir(int index)
832 ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT);
833 return CBF_NONE;
836 /* --- Zoom in button --- */
838 static CallBackFunction ToolbarZoomInClick(Window *w)
840 if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
841 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN);
842 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
844 return CBF_NONE;
847 /* --- Zoom out button --- */
849 static CallBackFunction ToolbarZoomOutClick(Window *w)
851 if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
852 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT);
853 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
855 return CBF_NONE;
858 /* --- Rail button menu --- */
860 static CallBackFunction ToolbarBuildRailClick(Window *w)
862 ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true);
863 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
864 return CBF_NONE;
868 * Handle click on the entry in the Build Rail menu.
870 * @param index RailType to show the build toolbar for.
871 * @return #CBF_NONE
873 static CallBackFunction MenuClickBuildRail(int index)
875 _last_built_railtype = (RailType)index;
876 ShowBuildRailToolbar(_last_built_railtype);
877 return CBF_NONE;
880 /* --- Road button menu --- */
882 static CallBackFunction ToolbarBuildRoadClick(Window *w)
884 ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TN_ROADS, 140, true, true);
885 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
886 return CBF_NONE;
890 * Handle click on the entry in the Build Road menu.
892 * @param index RoadType to show the build toolbar for.
893 * @return #CBF_NONE
895 static CallBackFunction MenuClickBuildRoad(int index)
897 _last_built_roadtype = (RoadType)index;
898 ShowBuildRoadToolbar(_last_built_roadtype);
899 return CBF_NONE;
902 /* --- Tram button menu --- */
904 static CallBackFunction ToolbarBuildTramClick(Window *w)
906 ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TN_TRAMS, 140, true, true);
907 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
908 return CBF_NONE;
912 * Handle click on the entry in the Build Tram menu.
914 * @param index RoadType to show the build toolbar for.
915 * @return #CBF_NONE
917 static CallBackFunction MenuClickBuildTram(int index)
919 _last_built_tramtype = (RoadType)index;
920 ShowBuildRoadToolbar(_last_built_tramtype);
921 return CBF_NONE;
924 /* --- Water button menu --- */
926 static CallBackFunction ToolbarBuildWaterClick(Window *w)
928 DropDownList list;
929 list.emplace_back(new DropDownListIconItem(SPR_IMG_BUILD_CANAL, PAL_NONE, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 0, false));
930 ShowDropDownList(w, std::move(list), 0, WID_TN_WATER, 140, true, true);
931 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
932 return CBF_NONE;
936 * Handle click on the entry in the Build Waterways menu.
938 * @param index Unused.
939 * @return #CBF_NONE
941 static CallBackFunction MenuClickBuildWater(int index)
943 ShowBuildDocksToolbar();
944 return CBF_NONE;
947 /* --- Airport button menu --- */
949 static CallBackFunction ToolbarBuildAirClick(Window *w)
951 DropDownList list;
952 list.emplace_back(new DropDownListIconItem(SPR_IMG_AIRPORT, PAL_NONE, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 0, false));
953 ShowDropDownList(w, std::move(list), 0, WID_TN_AIR, 140, true, true);
954 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
955 return CBF_NONE;
959 * Handle click on the entry in the Build Air menu.
961 * @param index Unused.
962 * @return #CBF_NONE
964 static CallBackFunction MenuClickBuildAir(int index)
966 ShowBuildAirToolbar();
967 return CBF_NONE;
970 /* --- Forest button menu --- */
972 static CallBackFunction ToolbarForestClick(Window *w)
974 DropDownList list;
975 list.emplace_back(new DropDownListIconItem(SPR_IMG_LANDSCAPING, PAL_NONE, STR_LANDSCAPING_MENU_LANDSCAPING, 0, false));
976 list.emplace_back(new DropDownListIconItem(SPR_IMG_PLANTTREES, PAL_NONE, STR_LANDSCAPING_MENU_PLANT_TREES, 1, false));
977 list.emplace_back(new DropDownListIconItem(SPR_IMG_SIGN, PAL_NONE, STR_LANDSCAPING_MENU_PLACE_SIGN, 2, false));
978 ShowDropDownList(w, std::move(list), 0, WID_TN_LANDSCAPE, 100, true, true);
979 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
980 return CBF_NONE;
984 * Handle click on the entry in the landscaping menu.
986 * @param index Menu entry clicked.
987 * @return #CBF_NONE
989 static CallBackFunction MenuClickForest(int index)
991 switch (index) {
992 case 0: ShowTerraformToolbar(); break;
993 case 1: ShowBuildTreesToolbar(); break;
994 case 2: return SelectSignTool();
996 return CBF_NONE;
999 /* --- Music button menu --- */
1001 static CallBackFunction ToolbarMusicClick(Window *w)
1003 PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_MUSIC_SOUND : (int)WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1);
1004 return CBF_NONE;
1008 * Handle click on the entry in the Music menu.
1010 * @param index Unused.
1011 * @return #CBF_NONE
1013 static CallBackFunction MenuClickMusicWindow(int index)
1015 ShowMusicWindow();
1016 return CBF_NONE;
1019 /* --- Newspaper button menu --- */
1021 static CallBackFunction ToolbarNewspaperClick(Window *w)
1023 PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 3);
1024 return CBF_NONE;
1028 * Handle click on the entry in the Newspaper menu.
1030 * @param index Menu entry clicked.
1031 * @return #CBF_NONE
1033 static CallBackFunction MenuClickNewspaper(int index)
1035 switch (index) {
1036 case 0: ShowLastNewsMessage(); break;
1037 case 1: ShowMessageHistory(); break;
1038 case 2: DeleteAllMessages(); break;
1040 return CBF_NONE;
1043 /* --- Help button menu --- */
1045 static CallBackFunction PlaceLandBlockInfo()
1047 if (_last_started_action == CBF_PLACE_LANDINFO) {
1048 ResetObjectToPlace();
1049 return CBF_NONE;
1050 } else {
1051 SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
1052 return CBF_PLACE_LANDINFO;
1056 static CallBackFunction ToolbarHelpClick(Window *w)
1058 PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_HELP : (int)WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 10 : 7);
1059 return CBF_NONE;
1063 * Toggle drawing of sprites' bounding boxes.
1064 * @note has only an effect when newgrf_developer_tools are active.
1066 * Function is found here and not in viewport.cpp in order to avoid
1067 * importing the settings structs to there.
1069 void ToggleBoundingBoxes()
1071 extern bool _draw_bounding_boxes;
1072 /* Always allow to toggle them off */
1073 if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) {
1074 _draw_bounding_boxes = !_draw_bounding_boxes;
1075 MarkWholeScreenDirty();
1080 * Toggle drawing of the dirty blocks.
1081 * @note has only an effect when newgrf_developer_tools are active.
1083 * Function is found here and not in viewport.cpp in order to avoid
1084 * importing the settings structs to there.
1086 void ToggleDirtyBlocks()
1088 extern bool _draw_dirty_blocks;
1089 /* Always allow to toggle them off */
1090 if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) {
1091 _draw_dirty_blocks = !_draw_dirty_blocks;
1092 MarkWholeScreenDirty();
1097 * Set the starting year for a scenario.
1098 * @param year New starting year.
1100 void SetStartingYear(Year year)
1102 _settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR);
1103 Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
1104 /* If you open a savegame as scenario there may already be link graphs.*/
1105 LinkGraphSchedule::instance.ShiftDates(new_date - _date);
1106 SetDate(new_date, 0);
1110 * Choose the proper callback function for the main toolbar's help menu.
1111 * @param index The menu index which was selected.
1112 * @return CBF_NONE
1114 static CallBackFunction MenuClickHelp(int index)
1116 switch (index) {
1117 case 0: return PlaceLandBlockInfo();
1118 case 2: IConsoleSwitch(); break;
1119 case 3: ShowAIDebugWindow(); break;
1120 case 4: ShowScreenshotWindow(); break;
1121 case 5: ShowFramerateWindow(); break;
1122 case 6: ShowAboutWindow(); break;
1123 case 7: ShowSpriteAlignerWindow(); break;
1124 case 8: ToggleBoundingBoxes(); break;
1125 case 9: ToggleDirtyBlocks(); break;
1127 return CBF_NONE;
1130 /* --- Switch toolbar button --- */
1132 static CallBackFunction ToolbarSwitchClick(Window *w)
1134 if (_toolbar_mode != TB_LOWER) {
1135 _toolbar_mode = TB_LOWER;
1136 } else {
1137 _toolbar_mode = TB_UPPER;
1140 w->ReInit();
1141 w->SetWidgetLoweredState(_game_mode == GM_EDITOR ? (uint)WID_TE_SWITCH_BAR : (uint)WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
1142 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1143 return CBF_NONE;
1146 /* --- Scenario editor specific handlers. */
1149 * Called when clicking at the date panel of the scenario editor toolbar.
1151 static CallBackFunction ToolbarScenDatePanel(Window *w)
1153 SetDParam(0, _settings_game.game_creation.starting_year);
1154 ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
1155 return CBF_NONE;
1158 static CallBackFunction ToolbarScenDateBackward(Window *w)
1160 /* don't allow too fast scrolling */
1161 if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1162 w->HandleButtonClick(WID_TE_DATE_BACKWARD);
1163 w->SetDirty();
1165 SetStartingYear(_settings_game.game_creation.starting_year - 1);
1167 _left_button_clicked = false;
1168 return CBF_NONE;
1171 static CallBackFunction ToolbarScenDateForward(Window *w)
1173 /* don't allow too fast scrolling */
1174 if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1175 w->HandleButtonClick(WID_TE_DATE_FORWARD);
1176 w->SetDirty();
1178 SetStartingYear(_settings_game.game_creation.starting_year + 1);
1180 _left_button_clicked = false;
1181 return CBF_NONE;
1184 static CallBackFunction ToolbarScenGenLand(Window *w)
1186 w->HandleButtonClick(WID_TE_LAND_GENERATE);
1187 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1189 ShowEditorTerraformToolbar();
1190 return CBF_NONE;
1194 static CallBackFunction ToolbarScenGenTown(Window *w)
1196 w->HandleButtonClick(WID_TE_TOWN_GENERATE);
1197 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1198 ShowFoundTownWindow();
1199 return CBF_NONE;
1202 static CallBackFunction ToolbarScenGenIndustry(Window *w)
1204 w->HandleButtonClick(WID_TE_INDUSTRY);
1205 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1206 ShowBuildIndustryWindow();
1207 return CBF_NONE;
1210 static CallBackFunction ToolbarScenBuildRoadClick(Window *w)
1212 ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TE_ROADS, 140, true, true);
1213 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1214 return CBF_NONE;
1218 * Handle click on the entry in the Build Road menu.
1220 * @param index RoadType to show the build toolbar for.
1221 * @return #CBF_NONE
1223 static CallBackFunction ToolbarScenBuildRoad(int index)
1225 _last_built_roadtype = (RoadType)index;
1226 ShowBuildRoadScenToolbar(_last_built_roadtype);
1227 return CBF_NONE;
1230 static CallBackFunction ToolbarScenBuildTramClick(Window *w)
1232 ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TE_TRAMS, 140, true, true);
1233 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1234 return CBF_NONE;
1238 * Handle click on the entry in the Build Tram menu.
1240 * @param index RoadType to show the build toolbar for.
1241 * @return #CBF_NONE
1243 static CallBackFunction ToolbarScenBuildTram(int index)
1245 _last_built_tramtype = (RoadType)index;
1246 ShowBuildRoadScenToolbar(_last_built_tramtype);
1247 return CBF_NONE;
1250 static CallBackFunction ToolbarScenBuildDocks(Window *w)
1252 w->HandleButtonClick(WID_TE_WATER);
1253 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1254 ShowBuildDocksScenToolbar();
1255 return CBF_NONE;
1258 static CallBackFunction ToolbarScenPlantTrees(Window *w)
1260 w->HandleButtonClick(WID_TE_TREES);
1261 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1262 ShowBuildTreesToolbar();
1263 return CBF_NONE;
1266 static CallBackFunction ToolbarScenPlaceSign(Window *w)
1268 w->HandleButtonClick(WID_TE_SIGNS);
1269 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1270 return SelectSignTool();
1273 static CallBackFunction ToolbarBtn_NULL(Window *w)
1275 return CBF_NONE;
1278 typedef CallBackFunction MenuClickedProc(int index);
1280 static MenuClickedProc * const _menu_clicked_procs[] = {
1281 nullptr, // 0
1282 nullptr, // 1
1283 MenuClickSettings, // 2
1284 MenuClickSaveLoad, // 3
1285 MenuClickMap, // 4
1286 MenuClickTown, // 5
1287 MenuClickSubsidies, // 6
1288 MenuClickStations, // 7
1289 MenuClickFinances, // 8
1290 MenuClickCompany, // 9
1291 MenuClickStory, // 10
1292 MenuClickGoal, // 11
1293 MenuClickGraphs, // 12
1294 MenuClickLeague, // 13
1295 MenuClickIndustry, // 14
1296 MenuClickShowTrains, // 15
1297 MenuClickShowRoad, // 16
1298 MenuClickShowShips, // 17
1299 MenuClickShowAir, // 18
1300 MenuClickMap, // 19
1301 nullptr, // 20
1302 MenuClickBuildRail, // 21
1303 MenuClickBuildRoad, // 22
1304 MenuClickBuildTram, // 23
1305 MenuClickBuildWater, // 24
1306 MenuClickBuildAir, // 25
1307 MenuClickForest, // 26
1308 MenuClickMusicWindow, // 27
1309 MenuClickNewspaper, // 28
1310 MenuClickHelp, // 29
1313 /** Full blown container to make it behave exactly as we want :) */
1314 class NWidgetToolbarContainer : public NWidgetContainer {
1315 bool visible[WID_TN_END]; ///< The visible headers
1316 protected:
1317 uint spacers; ///< Number of spacer widgets in this toolbar
1319 public:
1320 NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL)
1325 * Check whether the given widget type is a button for us.
1326 * @param type the widget type to check.
1327 * @return true if it is a button for us.
1329 bool IsButton(WidgetType type) const
1331 return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN;
1334 void SetupSmallestSize(Window *w, bool init_array) override
1336 this->smallest_x = 0; // Biggest child
1337 this->smallest_y = 0; // Biggest child
1338 this->fill_x = 1;
1339 this->fill_y = 0;
1340 this->resize_x = 1; // We only resize in this direction
1341 this->resize_y = 0; // We never resize in this direction
1342 this->spacers = 0;
1344 uint nbuttons = 0;
1345 /* First initialise some variables... */
1346 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1347 child_wid->SetupSmallestSize(w, init_array);
1348 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
1349 if (this->IsButton(child_wid->type)) {
1350 nbuttons++;
1351 this->smallest_x = std::max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
1352 } else if (child_wid->type == NWID_SPACER) {
1353 this->spacers++;
1357 /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */
1358 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1359 child_wid->current_y = this->smallest_y;
1360 if (!this->IsButton(child_wid->type)) {
1361 child_wid->current_x = child_wid->smallest_x;
1364 _toolbar_width = nbuttons * this->smallest_x;
1367 void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override
1369 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
1371 this->pos_x = x;
1372 this->pos_y = y;
1373 this->current_x = given_width;
1374 this->current_y = given_height;
1376 /* Figure out what are the visible buttons */
1377 memset(this->visible, 0, sizeof(this->visible));
1378 uint arrangable_count, button_count, spacer_count;
1379 const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count);
1380 for (uint i = 0; i < arrangable_count; i++) {
1381 this->visible[arrangement[i]] = true;
1384 /* Create us ourselves a quick lookup table */
1385 NWidgetBase *widgets[WID_TN_END];
1386 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1387 if (child_wid->type == NWID_SPACER) continue;
1388 widgets[((NWidgetCore*)child_wid)->index] = child_wid;
1391 /* Now assign the widgets to their rightful place */
1392 uint position = 0; // Place to put next child relative to origin of the container.
1393 uint spacer_space = std::max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets
1394 uint button_space = given_width - spacer_space; // Remaining spacing for the buttons
1395 uint spacer_i = 0;
1396 uint button_i = 0;
1398 /* Index into the arrangement indices. The macro lastof cannot be used here! */
1399 const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement;
1400 for (uint i = 0; i < arrangable_count; i++) {
1401 NWidgetBase *child_wid = widgets[*cur_wid];
1402 /* If we have to give space to the spacers, do that */
1403 if (spacer_space != 0) {
1404 NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev;
1405 if (possible_spacer != nullptr && possible_spacer->type == NWID_SPACER) {
1406 uint add = spacer_space / (spacer_count - spacer_i);
1407 position += add;
1408 spacer_space -= add;
1409 spacer_i++;
1413 /* Buttons can be scaled, the others not. */
1414 if (this->IsButton(child_wid->type)) {
1415 child_wid->current_x = button_space / (button_count - button_i);
1416 button_space -= child_wid->current_x;
1417 button_i++;
1419 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
1420 position += child_wid->current_x;
1422 if (rtl) {
1423 cur_wid--;
1424 } else {
1425 cur_wid++;
1430 void Draw(const Window *w) override
1432 /* Draw brown-red toolbar bg. */
1433 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);
1434 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);
1436 bool rtl = _current_text_dir == TD_RTL;
1437 for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != nullptr; child_wid = rtl ? child_wid->prev : child_wid->next) {
1438 if (child_wid->type == NWID_SPACER) continue;
1439 if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1441 child_wid->Draw(w);
1445 NWidgetCore *GetWidgetFromPos(int x, int y) override
1447 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
1449 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1450 if (child_wid->type == NWID_SPACER) continue;
1451 if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1453 NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
1454 if (nwid != nullptr) return nwid;
1456 return nullptr;
1460 * Get the arrangement of the buttons for the toolbar.
1461 * @param width the new width of the toolbar.
1462 * @param arrangable_count output of the number of visible items.
1463 * @param button_count output of the number of visible buttons.
1464 * @param spacer_count output of the number of spacers.
1465 * @return the button configuration.
1467 virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0;
1470 /** Container for the 'normal' main toolbar */
1471 class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
1472 const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override
1474 static const uint SMALLEST_ARRANGEMENT = 14;
1475 static const uint BIGGEST_ARRANGEMENT = 20;
1477 /* The number of buttons of each row of the toolbar should match the number of items which we want to be visible.
1478 * The total number of buttons should be equal to arrangable_count * 2.
1479 * No bad things happen, but we could see strange behaviours if we have buttons < (arrangable_count * 2) like a
1480 * pause button appearing on the right of the lower toolbar and weird resizing of the widgets even if there is
1481 * enough space.
1483 static const byte arrange14[] = {
1484 WID_TN_PAUSE,
1485 WID_TN_FAST_FORWARD,
1486 WID_TN_TRAINS,
1487 WID_TN_ROADVEHS,
1488 WID_TN_SHIPS,
1489 WID_TN_AIRCRAFT,
1490 WID_TN_ZOOM_IN,
1491 WID_TN_ZOOM_OUT,
1492 WID_TN_RAILS,
1493 WID_TN_ROADS,
1494 WID_TN_WATER,
1495 WID_TN_AIR,
1496 WID_TN_LANDSCAPE,
1497 WID_TN_SWITCH_BAR,
1498 // lower toolbar
1499 WID_TN_SETTINGS,
1500 WID_TN_SAVE,
1501 WID_TN_SMALL_MAP,
1502 WID_TN_TOWNS,
1503 WID_TN_SUBSIDIES,
1504 WID_TN_STATIONS,
1505 WID_TN_FINANCES,
1506 WID_TN_COMPANIES,
1507 WID_TN_GRAPHS,
1508 WID_TN_INDUSTRIES,
1509 WID_TN_MUSIC_SOUND,
1510 WID_TN_MESSAGES,
1511 WID_TN_HELP,
1512 WID_TN_SWITCH_BAR,
1514 static const byte arrange15[] = {
1515 WID_TN_PAUSE,
1516 WID_TN_FAST_FORWARD,
1517 WID_TN_SMALL_MAP,
1518 WID_TN_TRAINS,
1519 WID_TN_ROADVEHS,
1520 WID_TN_SHIPS,
1521 WID_TN_AIRCRAFT,
1522 WID_TN_RAILS,
1523 WID_TN_ROADS,
1524 WID_TN_WATER,
1525 WID_TN_AIR,
1526 WID_TN_LANDSCAPE,
1527 WID_TN_ZOOM_IN,
1528 WID_TN_ZOOM_OUT,
1529 WID_TN_SWITCH_BAR,
1530 // lower toolbar
1531 WID_TN_PAUSE,
1532 WID_TN_SETTINGS,
1533 WID_TN_SMALL_MAP,
1534 WID_TN_SAVE,
1535 WID_TN_TOWNS,
1536 WID_TN_SUBSIDIES,
1537 WID_TN_STATIONS,
1538 WID_TN_FINANCES,
1539 WID_TN_COMPANIES,
1540 WID_TN_GRAPHS,
1541 WID_TN_INDUSTRIES,
1542 WID_TN_MUSIC_SOUND,
1543 WID_TN_MESSAGES,
1544 WID_TN_HELP,
1545 WID_TN_SWITCH_BAR,
1547 static const byte arrange16[] = {
1548 WID_TN_PAUSE,
1549 WID_TN_FAST_FORWARD,
1550 WID_TN_SETTINGS,
1551 WID_TN_SMALL_MAP,
1552 WID_TN_TRAINS,
1553 WID_TN_ROADVEHS,
1554 WID_TN_SHIPS,
1555 WID_TN_AIRCRAFT,
1556 WID_TN_RAILS,
1557 WID_TN_ROADS,
1558 WID_TN_WATER,
1559 WID_TN_AIR,
1560 WID_TN_LANDSCAPE,
1561 WID_TN_ZOOM_IN,
1562 WID_TN_ZOOM_OUT,
1563 WID_TN_SWITCH_BAR,
1564 // lower toolbar
1565 WID_TN_PAUSE,
1566 WID_TN_FAST_FORWARD,
1567 WID_TN_SAVE,
1568 WID_TN_TOWNS,
1569 WID_TN_SUBSIDIES,
1570 WID_TN_STATIONS,
1571 WID_TN_FINANCES,
1572 WID_TN_COMPANIES,
1573 WID_TN_GRAPHS,
1574 WID_TN_INDUSTRIES,
1575 WID_TN_MUSIC_SOUND,
1576 WID_TN_MESSAGES,
1577 WID_TN_HELP,
1578 WID_TN_ZOOM_IN,
1579 WID_TN_ZOOM_OUT,
1580 WID_TN_SWITCH_BAR,
1582 static const byte arrange17[] = {
1583 WID_TN_PAUSE,
1584 WID_TN_FAST_FORWARD,
1585 WID_TN_SETTINGS,
1586 WID_TN_SMALL_MAP,
1587 WID_TN_SUBSIDIES,
1588 WID_TN_TRAINS,
1589 WID_TN_ROADVEHS,
1590 WID_TN_SHIPS,
1591 WID_TN_AIRCRAFT,
1592 WID_TN_RAILS,
1593 WID_TN_ROADS,
1594 WID_TN_WATER,
1595 WID_TN_AIR,
1596 WID_TN_LANDSCAPE,
1597 WID_TN_ZOOM_IN,
1598 WID_TN_ZOOM_OUT,
1599 WID_TN_SWITCH_BAR,
1600 // lower toolbar
1601 WID_TN_PAUSE,
1602 WID_TN_FAST_FORWARD,
1603 WID_TN_SAVE,
1604 WID_TN_SMALL_MAP,
1605 WID_TN_SUBSIDIES,
1606 WID_TN_TOWNS,
1607 WID_TN_STATIONS,
1608 WID_TN_FINANCES,
1609 WID_TN_COMPANIES,
1610 WID_TN_GRAPHS,
1611 WID_TN_INDUSTRIES,
1612 WID_TN_MUSIC_SOUND,
1613 WID_TN_MESSAGES,
1614 WID_TN_HELP,
1615 WID_TN_ZOOM_IN,
1616 WID_TN_ZOOM_OUT,
1617 WID_TN_SWITCH_BAR,
1619 static const byte arrange18[] = {
1620 WID_TN_PAUSE,
1621 WID_TN_FAST_FORWARD,
1622 WID_TN_SETTINGS,
1623 WID_TN_SMALL_MAP,
1624 WID_TN_TOWNS,
1625 WID_TN_SUBSIDIES,
1626 WID_TN_STATIONS,
1627 WID_TN_FINANCES,
1628 WID_TN_COMPANIES,
1629 WID_TN_INDUSTRIES,
1630 WID_TN_RAILS,
1631 WID_TN_ROADS,
1632 WID_TN_WATER,
1633 WID_TN_AIR,
1634 WID_TN_LANDSCAPE,
1635 WID_TN_ZOOM_IN,
1636 WID_TN_ZOOM_OUT,
1637 WID_TN_SWITCH_BAR,
1638 // lower toolbar
1639 WID_TN_PAUSE,
1640 WID_TN_FAST_FORWARD,
1641 WID_TN_SAVE,
1642 WID_TN_SMALL_MAP,
1643 WID_TN_TOWNS,
1644 WID_TN_SUBSIDIES,
1645 WID_TN_STATIONS,
1646 WID_TN_GRAPHS,
1647 WID_TN_TRAINS,
1648 WID_TN_ROADVEHS,
1649 WID_TN_SHIPS,
1650 WID_TN_AIRCRAFT,
1651 WID_TN_MUSIC_SOUND,
1652 WID_TN_MESSAGES,
1653 WID_TN_HELP,
1654 WID_TN_ZOOM_IN,
1655 WID_TN_ZOOM_OUT,
1656 WID_TN_SWITCH_BAR,
1658 static const byte arrange19[] = {
1659 WID_TN_PAUSE,
1660 WID_TN_FAST_FORWARD,
1661 WID_TN_SETTINGS,
1662 WID_TN_SMALL_MAP,
1663 WID_TN_TOWNS,
1664 WID_TN_SUBSIDIES,
1665 WID_TN_TRAINS,
1666 WID_TN_ROADVEHS,
1667 WID_TN_SHIPS,
1668 WID_TN_AIRCRAFT,
1669 WID_TN_RAILS,
1670 WID_TN_ROADS,
1671 WID_TN_WATER,
1672 WID_TN_AIR,
1673 WID_TN_LANDSCAPE,
1674 WID_TN_MUSIC_SOUND,
1675 WID_TN_ZOOM_IN,
1676 WID_TN_ZOOM_OUT,
1677 WID_TN_SWITCH_BAR,
1678 // lower toolbar
1679 WID_TN_PAUSE,
1680 WID_TN_FAST_FORWARD,
1681 WID_TN_SAVE,
1682 WID_TN_SMALL_MAP,
1683 WID_TN_STATIONS,
1684 WID_TN_FINANCES,
1685 WID_TN_COMPANIES,
1686 WID_TN_GRAPHS,
1687 WID_TN_INDUSTRIES,
1688 WID_TN_MESSAGES,
1689 WID_TN_RAILS,
1690 WID_TN_ROADS,
1691 WID_TN_WATER,
1692 WID_TN_AIR,
1693 WID_TN_LANDSCAPE,
1694 WID_TN_HELP,
1695 WID_TN_ZOOM_IN,
1696 WID_TN_ZOOM_OUT,
1697 WID_TN_SWITCH_BAR,
1699 static const byte arrange20[] = {
1700 WID_TN_PAUSE,
1701 WID_TN_FAST_FORWARD,
1702 WID_TN_SETTINGS,
1703 WID_TN_SMALL_MAP,
1704 WID_TN_TOWNS,
1705 WID_TN_SUBSIDIES,
1706 WID_TN_TRAINS,
1707 WID_TN_ROADVEHS,
1708 WID_TN_SHIPS,
1709 WID_TN_AIRCRAFT,
1710 WID_TN_RAILS,
1711 WID_TN_ROADS,
1712 WID_TN_WATER,
1713 WID_TN_AIR,
1714 WID_TN_LANDSCAPE,
1715 WID_TN_MUSIC_SOUND,
1716 WID_TN_GOAL,
1717 WID_TN_ZOOM_IN,
1718 WID_TN_ZOOM_OUT,
1719 WID_TN_SWITCH_BAR,
1720 // lower toolbar
1721 WID_TN_PAUSE,
1722 WID_TN_FAST_FORWARD,
1723 WID_TN_SAVE,
1724 WID_TN_SMALL_MAP,
1725 WID_TN_STATIONS,
1726 WID_TN_FINANCES,
1727 WID_TN_COMPANIES,
1728 WID_TN_GRAPHS,
1729 WID_TN_INDUSTRIES,
1730 WID_TN_MESSAGES,
1731 WID_TN_RAILS,
1732 WID_TN_ROADS,
1733 WID_TN_WATER,
1734 WID_TN_AIR,
1735 WID_TN_LANDSCAPE,
1736 WID_TN_STORY,
1737 WID_TN_HELP,
1738 WID_TN_ZOOM_IN,
1739 WID_TN_ZOOM_OUT,
1740 WID_TN_SWITCH_BAR,
1742 static const byte arrange_all[] = {
1743 WID_TN_PAUSE,
1744 WID_TN_FAST_FORWARD,
1745 WID_TN_SETTINGS,
1746 WID_TN_SAVE,
1747 WID_TN_SMALL_MAP,
1748 WID_TN_TOWNS,
1749 WID_TN_SUBSIDIES,
1750 WID_TN_STATIONS,
1751 WID_TN_FINANCES,
1752 WID_TN_COMPANIES,
1753 WID_TN_STORY,
1754 WID_TN_GOAL,
1755 WID_TN_GRAPHS,
1756 WID_TN_LEAGUE,
1757 WID_TN_INDUSTRIES,
1758 WID_TN_TRAINS,
1759 WID_TN_ROADVEHS,
1760 WID_TN_SHIPS,
1761 WID_TN_AIRCRAFT,
1762 WID_TN_ZOOM_IN,
1763 WID_TN_ZOOM_OUT,
1764 WID_TN_RAILS,
1765 WID_TN_ROADS,
1766 WID_TN_TRAMS,
1767 WID_TN_WATER,
1768 WID_TN_AIR,
1769 WID_TN_LANDSCAPE,
1770 WID_TN_MUSIC_SOUND,
1771 WID_TN_MESSAGES,
1772 WID_TN_HELP
1775 /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
1776 uint full_buttons = std::max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
1777 if (full_buttons > BIGGEST_ARRANGEMENT) {
1778 button_count = arrangable_count = lengthof(arrange_all);
1779 spacer_count = this->spacers;
1780 return arrange_all;
1783 /* Introduce the split toolbar */
1784 static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
1786 button_count = arrangable_count = full_buttons;
1787 spacer_count = this->spacers;
1788 return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
1792 /** Container for the scenario editor's toolbar */
1793 class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer {
1794 uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel)
1796 void SetupSmallestSize(Window *w, bool init_array) override
1798 this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array);
1800 /* Find the size of panel_widths */
1801 uint i = 0;
1802 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1803 if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
1805 assert(i < lengthof(this->panel_widths));
1806 this->panel_widths[i++] = child_wid->current_x;
1807 _toolbar_width += child_wid->current_x;
1811 const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override
1813 static const byte arrange_all[] = {
1814 WID_TE_PAUSE,
1815 WID_TE_FAST_FORWARD,
1816 WID_TE_SETTINGS,
1817 WID_TE_SAVE,
1818 WID_TE_SPACER,
1819 WID_TE_DATE_PANEL,
1820 WID_TE_SMALL_MAP,
1821 WID_TE_ZOOM_IN,
1822 WID_TE_ZOOM_OUT,
1823 WID_TE_LAND_GENERATE,
1824 WID_TE_TOWN_GENERATE,
1825 WID_TE_INDUSTRY,
1826 WID_TE_ROADS,
1827 WID_TE_TRAMS,
1828 WID_TE_WATER,
1829 WID_TE_TREES,
1830 WID_TE_SIGNS,
1831 WID_TE_MUSIC_SOUND,
1832 WID_TE_HELP,
1834 static const byte arrange_nopanel[] = {
1835 WID_TE_PAUSE,
1836 WID_TE_FAST_FORWARD,
1837 WID_TE_SETTINGS,
1838 WID_TE_SAVE,
1839 WID_TE_DATE_PANEL,
1840 WID_TE_SMALL_MAP,
1841 WID_TE_ZOOM_IN,
1842 WID_TE_ZOOM_OUT,
1843 WID_TE_LAND_GENERATE,
1844 WID_TE_TOWN_GENERATE,
1845 WID_TE_INDUSTRY,
1846 WID_TE_ROADS,
1847 WID_TE_TRAMS,
1848 WID_TE_WATER,
1849 WID_TE_TREES,
1850 WID_TE_SIGNS,
1851 WID_TE_MUSIC_SOUND,
1852 WID_TE_HELP,
1854 static const byte arrange_switch[] = {
1855 WID_TE_DATE_PANEL,
1856 WID_TE_SMALL_MAP,
1857 WID_TE_LAND_GENERATE,
1858 WID_TE_TOWN_GENERATE,
1859 WID_TE_INDUSTRY,
1860 WID_TE_ROADS,
1861 WID_TE_TRAMS,
1862 WID_TE_WATER,
1863 WID_TE_TREES,
1864 WID_TE_SIGNS,
1865 WID_TE_SWITCH_BAR,
1866 // lower toolbar
1867 WID_TE_PAUSE,
1868 WID_TE_FAST_FORWARD,
1869 WID_TE_SETTINGS,
1870 WID_TE_SAVE,
1871 WID_TE_DATE_PANEL,
1872 WID_TE_SMALL_MAP,
1873 WID_TE_ZOOM_IN,
1874 WID_TE_ZOOM_OUT,
1875 WID_TE_MUSIC_SOUND,
1876 WID_TE_HELP,
1877 WID_TE_SWITCH_BAR,
1880 /* If we can place all buttons *and* the panels, show them. */
1881 uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
1882 if (width >= min_full_width) {
1883 width -= this->panel_widths[0] + this->panel_widths[1];
1884 arrangable_count = lengthof(arrange_all);
1885 button_count = arrangable_count - 2;
1886 spacer_count = this->spacers;
1887 return arrange_all;
1890 /* 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 */
1891 uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
1892 if (width > min_small_width) {
1893 width -= this->panel_widths[1];
1894 arrangable_count = lengthof(arrange_nopanel);
1895 button_count = arrangable_count - 1;
1896 spacer_count = this->spacers - 1;
1897 return arrange_nopanel;
1900 /* Split toolbar */
1901 width -= this->panel_widths[1];
1902 arrangable_count = lengthof(arrange_switch) / 2;
1903 button_count = arrangable_count - 1;
1904 spacer_count = 0;
1905 return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
1909 /* --- Toolbar handling for the 'normal' case */
1911 typedef CallBackFunction ToolbarButtonProc(Window *w);
1913 static ToolbarButtonProc * const _toolbar_button_procs[] = {
1914 ToolbarPauseClick,
1915 ToolbarFastForwardClick,
1916 ToolbarOptionsClick,
1917 ToolbarSaveClick,
1918 ToolbarMapClick,
1919 ToolbarTownClick,
1920 ToolbarSubsidiesClick,
1921 ToolbarStationsClick,
1922 ToolbarFinancesClick,
1923 ToolbarCompaniesClick,
1924 ToolbarStoryClick,
1925 ToolbarGoalClick,
1926 ToolbarGraphsClick,
1927 ToolbarLeagueClick,
1928 ToolbarIndustryClick,
1929 ToolbarTrainClick,
1930 ToolbarRoadClick,
1931 ToolbarShipClick,
1932 ToolbarAirClick,
1933 ToolbarZoomInClick,
1934 ToolbarZoomOutClick,
1935 ToolbarBuildRailClick,
1936 ToolbarBuildRoadClick,
1937 ToolbarBuildTramClick,
1938 ToolbarBuildWaterClick,
1939 ToolbarBuildAirClick,
1940 ToolbarForestClick,
1941 ToolbarMusicClick,
1942 ToolbarNewspaperClick,
1943 ToolbarHelpClick,
1944 ToolbarSwitchClick,
1947 /** Main toolbar. */
1948 struct MainToolbarWindow : Window {
1949 GUITimer timer;
1951 MainToolbarWindow(WindowDesc *desc) : Window(desc)
1953 this->InitNested(0);
1955 _last_started_action = CBF_NONE;
1956 CLRBITS(this->flags, WF_WHITE_BORDER);
1957 this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
1958 this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
1959 PositionMainToolbar(this);
1960 DoZoomInOutWindow(ZOOM_NONE, this);
1962 this->timer.SetInterval(MILLISECONDS_PER_TICK);
1965 void FindWindowPlacementAndResize(int def_width, int def_height) override
1967 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
1970 void OnPaint() override
1972 /* If spectator, disable all construction buttons
1973 * ie : Build road, rail, ships, airports and landscaping
1974 * Since enabled state is the default, just disable when needed */
1975 this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_TRAMS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END);
1976 /* disable company list drop downs, if there are no companies */
1977 this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFT, WIDGET_LIST_END);
1979 this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0);
1980 this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0);
1982 this->DrawWidgets();
1985 void OnClick(Point pt, int widget, int click_count) override
1987 if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
1990 void OnDropdownSelect(int widget, int index) override
1992 CallBackFunction cbf = _menu_clicked_procs[widget](index);
1993 if (cbf != CBF_NONE) _last_started_action = cbf;
1996 EventState OnHotkey(int hotkey) override
1998 CallBackFunction cbf = CBF_NONE;
1999 switch (hotkey) {
2000 case MTHK_PAUSE: ToolbarPauseClick(this); break;
2001 case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2002 case MTHK_SETTINGS: ShowGameOptions(); break;
2003 case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
2004 case MTHK_LOADGAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
2005 case MTHK_SMALLMAP: ShowSmallMap(); break;
2006 case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
2007 case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
2008 case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
2009 case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
2010 case MTHK_COMPANIES: ShowCompany(_local_company); break;
2011 case MTHK_STORY: ShowStoryBook(_local_company); break;
2012 case MTHK_GOAL: ShowGoalsList(_local_company); break;
2013 case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
2014 case MTHK_LEAGUE: ShowCompanyLeagueTable(); break;
2015 case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
2016 case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
2017 case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
2018 case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
2019 case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
2020 case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2021 case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2022 case MTHK_BUILD_RAIL: ShowBuildRailToolbar(_last_built_railtype); break;
2023 case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
2024 case MTHK_BUILD_TRAM: ShowBuildRoadToolbar(_last_built_tramtype); break;
2025 case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
2026 case MTHK_BUILD_AIRPORT: ShowBuildAirToolbar(); break;
2027 case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
2028 case MTHK_MUSIC: ShowMusicWindow(); break;
2029 case MTHK_AI_DEBUG: ShowAIDebugWindow(); break;
2030 case MTHK_SMALL_SCREENSHOT: MakeScreenshotWithConfirm(SC_VIEWPORT); break;
2031 case MTHK_ZOOMEDIN_SCREENSHOT: MakeScreenshotWithConfirm(SC_ZOOMEDIN); break;
2032 case MTHK_DEFAULTZOOM_SCREENSHOT: MakeScreenshotWithConfirm(SC_DEFAULTZOOM); break;
2033 case MTHK_GIANT_SCREENSHOT: MakeScreenshotWithConfirm(SC_WORLD); break;
2034 case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
2035 case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
2036 case MTHK_EXTRA_VIEWPORT: ShowExtraViewportWindowForTileUnderCursor(); break;
2037 case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
2038 case MTHK_SIGN_LIST: ShowSignList(); break;
2039 case MTHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2040 default: return ES_NOT_HANDLED;
2042 if (cbf != CBF_NONE) _last_started_action = cbf;
2043 return ES_HANDLED;
2046 void OnPlaceObject(Point pt, TileIndex tile) override
2048 switch (_last_started_action) {
2049 case CBF_PLACE_SIGN:
2050 PlaceProc_Sign(tile);
2051 break;
2053 case CBF_PLACE_LANDINFO:
2054 ShowLandInfo(tile);
2055 break;
2057 default: NOT_REACHED();
2061 void OnPlaceObjectAbort() override
2063 _last_started_action = CBF_NONE;
2066 void OnRealtimeTick(uint delta_ms) override
2068 if (!this->timer.Elapsed(delta_ms)) return;
2069 this->timer.SetInterval(MILLISECONDS_PER_TICK);
2071 if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
2072 this->ToggleWidgetLoweredState(WID_TN_PAUSE);
2073 this->SetWidgetDirty(WID_TN_PAUSE);
2076 if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != (_game_speed != 100)) {
2077 this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD);
2078 this->SetWidgetDirty(WID_TN_FAST_FORWARD);
2082 void OnTimeout() override
2084 /* We do not want to automatically raise the pause, fast forward and
2085 * switchbar buttons; they have to stay down when pressed etc. */
2086 for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
2087 if (this->IsWidgetLowered(i)) {
2088 this->RaiseWidget(i);
2089 this->SetWidgetDirty(i);
2095 * Some data on this window has become invalid.
2096 * @param data Information about the changed data.
2097 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
2099 void OnInvalidateData(int data = 0, bool gui_scope = true) override
2101 if (!gui_scope) return;
2102 if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
2105 static HotkeyList hotkeys;
2108 const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0};
2109 const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0};
2110 const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0};
2111 const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0};
2113 static Hotkey maintoolbar_hotkeys[] = {
2114 Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE),
2115 Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD),
2116 Hotkey(WKC_F2, "settings", MTHK_SETTINGS),
2117 Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME),
2118 Hotkey((uint16)0, "load_game", MTHK_LOADGAME),
2119 Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP),
2120 Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
2121 Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES),
2122 Hotkey(WKC_F7, "station_list", MTHK_STATIONS),
2123 Hotkey(WKC_F8, "finances", MTHK_FINANCES),
2124 Hotkey(WKC_F9, "companies", MTHK_COMPANIES),
2125 Hotkey((uint16)0, "story_book", MTHK_STORY),
2126 Hotkey((uint16)0, "goal_list", MTHK_GOAL),
2127 Hotkey(WKC_F10, "graphs", MTHK_GRAPHS),
2128 Hotkey(WKC_F11, "league", MTHK_LEAGUE),
2129 Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES),
2130 Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
2131 Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
2132 Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
2133 Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
2134 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN),
2135 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT),
2136 Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
2137 Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
2138 Hotkey((uint16)0, "build_tram", MTHK_BUILD_TRAM),
2139 Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
2140 Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
2141 Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
2142 Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
2143 Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG),
2144 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
2145 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
2146 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT),
2147 Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
2148 Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
2149 Hotkey('L', "terraform", MTHK_TERRAFORM),
2150 Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
2151 Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
2152 Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
2153 Hotkey((uint16)0, "land_info", MTHK_LANDINFO),
2154 HOTKEY_LIST_END
2156 HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
2158 static NWidgetBase *MakeMainToolbar(int *biggest_index)
2160 /** Sprites to use for the different toolbar buttons */
2161 static const SpriteID toolbar_button_sprites[] = {
2162 SPR_IMG_PAUSE, // WID_TN_PAUSE
2163 SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD
2164 SPR_IMG_SETTINGS, // WID_TN_SETTINGS
2165 SPR_IMG_SAVE, // WID_TN_SAVE
2166 SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP
2167 SPR_IMG_TOWN, // WID_TN_TOWNS
2168 SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES
2169 SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS
2170 SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
2171 SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
2172 SPR_IMG_STORY_BOOK, // WID_TN_STORY
2173 SPR_IMG_GOAL, // WID_TN_GOAL
2174 SPR_IMG_GRAPHS, // WID_TN_GRAPHS
2175 SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE
2176 SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES
2177 SPR_IMG_TRAINLIST, // WID_TN_TRAINS
2178 SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS
2179 SPR_IMG_SHIPLIST, // WID_TN_SHIPS
2180 SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT
2181 SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN
2182 SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT
2183 SPR_IMG_BUILDRAIL, // WID_TN_RAILS
2184 SPR_IMG_BUILDROAD, // WID_TN_ROADS
2185 SPR_IMG_BUILDTRAMS, // WID_TN_TRAMS
2186 SPR_IMG_BUILDWATER, // WID_TN_WATER
2187 SPR_IMG_BUILDAIR, // WID_TN_AIR
2188 SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
2189 SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
2190 SPR_IMG_MESSAGES, // WID_TN_MESSAGES
2191 SPR_IMG_QUERY, // WID_TN_HELP
2192 SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
2195 NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
2196 for (uint i = 0; i < WID_TN_END; i++) {
2197 switch (i) {
2198 case WID_TN_SMALL_MAP:
2199 case WID_TN_FINANCES:
2200 case WID_TN_VEHICLE_START:
2201 case WID_TN_ZOOM_IN:
2202 case WID_TN_BUILDING_TOOLS_START:
2203 case WID_TN_MUSIC_SOUND:
2204 hor->Add(new NWidgetSpacer(0, 0));
2205 break;
2207 NWidgetLeaf *leaf = new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i);
2208 leaf->SetMinimalSize(20, 20);
2209 hor->Add(leaf);
2212 *biggest_index = std::max<int>(*biggest_index, WID_TN_SWITCH_BAR);
2213 return hor;
2216 static const NWidgetPart _nested_toolbar_normal_widgets[] = {
2217 NWidgetFunction(MakeMainToolbar),
2220 static WindowDesc _toolb_normal_desc(
2221 WDP_MANUAL, nullptr, 0, 0,
2222 WC_MAIN_TOOLBAR, WC_NONE,
2223 WDF_NO_FOCUS,
2224 _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets),
2225 &MainToolbarWindow::hotkeys
2229 /* --- Toolbar handling for the scenario editor */
2231 static MenuClickedProc * const _scen_toolbar_dropdown_procs[] = {
2232 nullptr, // 0
2233 nullptr, // 1
2234 MenuClickSettings, // 2
2235 MenuClickSaveLoad, // 3
2236 nullptr, // 4
2237 nullptr, // 5
2238 nullptr, // 6
2239 nullptr, // 7
2240 MenuClickMap, // 8
2241 nullptr, // 9
2242 nullptr, // 10
2243 nullptr, // 11
2244 nullptr, // 12
2245 nullptr, // 13
2246 ToolbarScenBuildRoad, // 14
2247 ToolbarScenBuildTram, // 15
2248 nullptr, // 16
2249 nullptr, // 17
2250 nullptr, // 18
2251 nullptr, // 19
2252 MenuClickMusicWindow, // 20
2253 MenuClickHelp, // 21
2254 nullptr, // 22
2257 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
2258 ToolbarPauseClick,
2259 ToolbarFastForwardClick,
2260 ToolbarOptionsClick,
2261 ToolbarScenSaveOrLoad,
2262 ToolbarBtn_NULL,
2263 ToolbarScenDatePanel,
2264 ToolbarScenDateBackward,
2265 ToolbarScenDateForward,
2266 ToolbarScenMapTownDir,
2267 ToolbarZoomInClick,
2268 ToolbarZoomOutClick,
2269 ToolbarScenGenLand,
2270 ToolbarScenGenTown,
2271 ToolbarScenGenIndustry,
2272 ToolbarScenBuildRoadClick,
2273 ToolbarScenBuildTramClick,
2274 ToolbarScenBuildDocks,
2275 ToolbarScenPlantTrees,
2276 ToolbarScenPlaceSign,
2277 ToolbarBtn_NULL,
2278 ToolbarMusicClick,
2279 ToolbarHelpClick,
2280 ToolbarSwitchClick,
2283 enum MainToolbarEditorHotkeys {
2284 MTEHK_PAUSE,
2285 MTEHK_FASTFORWARD,
2286 MTEHK_SETTINGS,
2287 MTEHK_SAVEGAME,
2288 MTEHK_GENLAND,
2289 MTEHK_GENTOWN,
2290 MTEHK_GENINDUSTRY,
2291 MTEHK_BUILD_ROAD,
2292 MTEHK_BUILD_TRAM,
2293 MTEHK_BUILD_DOCKS,
2294 MTEHK_BUILD_TREES,
2295 MTEHK_SIGN,
2296 MTEHK_MUSIC,
2297 MTEHK_LANDINFO,
2298 MTEHK_SMALL_SCREENSHOT,
2299 MTEHK_ZOOMEDIN_SCREENSHOT,
2300 MTEHK_DEFAULTZOOM_SCREENSHOT,
2301 MTEHK_GIANT_SCREENSHOT,
2302 MTEHK_ZOOM_IN,
2303 MTEHK_ZOOM_OUT,
2304 MTEHK_TERRAFORM,
2305 MTEHK_SMALLMAP,
2306 MTEHK_EXTRA_VIEWPORT,
2309 struct ScenarioEditorToolbarWindow : Window {
2310 GUITimer timer;
2312 ScenarioEditorToolbarWindow(WindowDesc *desc) : Window(desc)
2314 this->InitNested(0);
2316 _last_started_action = CBF_NONE;
2317 CLRBITS(this->flags, WF_WHITE_BORDER);
2318 PositionMainToolbar(this);
2319 DoZoomInOutWindow(ZOOM_NONE, this);
2321 this->timer.SetInterval(MILLISECONDS_PER_TICK);
2324 void FindWindowPlacementAndResize(int def_width, int def_height) override
2326 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
2329 void OnPaint() override
2331 this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR);
2332 this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR);
2333 this->SetWidgetDisabledState(WID_TE_ROADS, (GetRoadTypes(true) & ~_roadtypes_type) == ROADTYPES_NONE);
2334 this->SetWidgetDisabledState(WID_TE_TRAMS, (GetRoadTypes(true) & _roadtypes_type) == ROADTYPES_NONE);
2336 this->DrawWidgets();
2339 void SetStringParameters(int widget) const override
2341 switch (widget) {
2342 case WID_TE_DATE:
2343 SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
2344 break;
2348 void DrawWidget(const Rect &r, int widget) const override
2350 switch (widget) {
2351 case WID_TE_SPACER: {
2352 int height = r.bottom - r.top;
2353 if (height > 2 * FONT_HEIGHT_NORMAL) {
2354 DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
2355 DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2356 } else {
2357 DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2359 break;
2364 void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2366 switch (widget) {
2367 case WID_TE_SPACER:
2368 size->width = std::max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
2369 break;
2371 case WID_TE_DATE:
2372 SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1));
2373 *size = GetStringBoundingBox(STR_WHITE_DATE_LONG);
2374 break;
2378 void OnClick(Point pt, int widget, int click_count) override
2380 if (_game_mode == GM_MENU) return;
2381 CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
2382 if (cbf != CBF_NONE) _last_started_action = cbf;
2385 void OnDropdownSelect(int widget, int index) override
2387 CallBackFunction cbf = _scen_toolbar_dropdown_procs[widget](index);
2388 if (cbf != CBF_NONE) _last_started_action = cbf;
2389 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
2392 EventState OnHotkey(int hotkey) override
2394 CallBackFunction cbf = CBF_NONE;
2395 switch (hotkey) {
2396 case MTEHK_PAUSE: ToolbarPauseClick(this); break;
2397 case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2398 case MTEHK_SETTINGS: ShowGameOptions(); break;
2399 case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
2400 case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
2401 case MTEHK_GENTOWN: ToolbarScenGenTown(this); break;
2402 case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
2403 case MTEHK_BUILD_ROAD: ToolbarScenBuildRoadClick(this); break;
2404 case MTEHK_BUILD_TRAM: ToolbarScenBuildTramClick(this); break;
2405 case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break;
2406 case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break;
2407 case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break;
2408 case MTEHK_MUSIC: ShowMusicWindow(); break;
2409 case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2410 case MTEHK_SMALL_SCREENSHOT: MakeScreenshotWithConfirm(SC_VIEWPORT); break;
2411 case MTEHK_ZOOMEDIN_SCREENSHOT: MakeScreenshotWithConfirm(SC_ZOOMEDIN); break;
2412 case MTEHK_DEFAULTZOOM_SCREENSHOT: MakeScreenshotWithConfirm(SC_DEFAULTZOOM); break;
2413 case MTEHK_GIANT_SCREENSHOT: MakeScreenshotWithConfirm(SC_WORLD); break;
2414 case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2415 case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2416 case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break;
2417 case MTEHK_SMALLMAP: ShowSmallMap(); break;
2418 case MTEHK_EXTRA_VIEWPORT: ShowExtraViewportWindowForTileUnderCursor(); break;
2419 default: return ES_NOT_HANDLED;
2421 if (cbf != CBF_NONE) _last_started_action = cbf;
2422 return ES_HANDLED;
2425 void OnPlaceObject(Point pt, TileIndex tile) override
2427 switch (_last_started_action) {
2428 case CBF_PLACE_SIGN:
2429 PlaceProc_Sign(tile);
2430 break;
2432 case CBF_PLACE_LANDINFO:
2433 ShowLandInfo(tile);
2434 break;
2436 default: NOT_REACHED();
2440 void OnPlaceObjectAbort() override
2442 _last_started_action = CBF_NONE;
2445 void OnTimeout() override
2447 this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END);
2448 this->SetWidgetDirty(WID_TE_DATE_BACKWARD);
2449 this->SetWidgetDirty(WID_TE_DATE_FORWARD);
2452 void OnRealtimeTick(uint delta_ms) override
2454 if (!this->timer.Elapsed(delta_ms)) return;
2455 this->timer.SetInterval(MILLISECONDS_PER_TICK);
2457 if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
2458 this->ToggleWidgetLoweredState(WID_TE_PAUSE);
2459 this->SetDirty();
2462 if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != (_game_speed != 100)) {
2463 this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD);
2464 this->SetDirty();
2469 * Some data on this window has become invalid.
2470 * @param data Information about the changed data.
2471 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
2473 void OnInvalidateData(int data = 0, bool gui_scope = true) override
2475 if (!gui_scope) return;
2476 if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
2479 void OnQueryTextFinished(char *str) override
2481 /* Was 'cancel' pressed? */
2482 if (str == nullptr) return;
2484 int32 value;
2485 if (!StrEmpty(str)) {
2486 value = atoi(str);
2487 } else {
2488 /* An empty string means revert to the default */
2489 value = DEF_START_YEAR;
2491 SetStartingYear(value);
2493 this->SetDirty();
2496 static HotkeyList hotkeys;
2499 static Hotkey scenedit_maintoolbar_hotkeys[] = {
2500 Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE),
2501 Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD),
2502 Hotkey(WKC_F2, "settings", MTEHK_SETTINGS),
2503 Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME),
2504 Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND),
2505 Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN),
2506 Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
2507 Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
2508 Hotkey((uint16)0, "build_tram", MTEHK_BUILD_TRAM),
2509 Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
2510 Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
2511 Hotkey(WKC_F10, "build_sign", MTEHK_SIGN),
2512 Hotkey(WKC_F11, "music", MTEHK_MUSIC),
2513 Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO),
2514 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
2515 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
2516 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT),
2517 Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
2518 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN),
2519 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT),
2520 Hotkey('L', "terraform", MTEHK_TERRAFORM),
2521 Hotkey('M', "smallmap", MTEHK_SMALLMAP),
2522 Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
2523 HOTKEY_LIST_END
2525 HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys);
2527 static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
2528 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
2529 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
2530 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
2531 NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
2532 NWidget(NWID_SPACER),
2533 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
2534 NWidget(NWID_SPACER),
2535 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
2536 NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2), SetPadding(1),
2537 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD), SetFill(0, 1),
2538 NWidget(WWT_TEXT, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_WHITE_DATE_LONG, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), SetAlignment(SA_CENTER), SetFill(0, 1),
2539 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD), SetFill(0, 1),
2540 EndContainer(),
2541 EndContainer(),
2542 NWidget(NWID_SPACER),
2543 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
2544 NWidget(NWID_SPACER),
2545 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
2546 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
2547 NWidget(NWID_SPACER),
2548 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
2549 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
2550 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
2551 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
2552 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_TRAMS), SetDataTip(SPR_IMG_BUILDTRAMS, STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION),
2553 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
2554 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
2555 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
2556 NWidget(NWID_SPACER),
2557 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
2558 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
2559 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
2562 static NWidgetBase *MakeScenarioToolbar(int *biggest_index)
2564 return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer());
2567 static const NWidgetPart _nested_toolb_scen_widgets[] = {
2568 NWidgetFunction(MakeScenarioToolbar),
2571 static WindowDesc _toolb_scen_desc(
2572 WDP_MANUAL, nullptr, 0, 0,
2573 WC_MAIN_TOOLBAR, WC_NONE,
2574 WDF_NO_FOCUS,
2575 _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets),
2576 &ScenarioEditorToolbarWindow::hotkeys
2579 /** Allocate the toolbar. */
2580 void AllocateToolbar()
2582 /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
2583 _last_built_roadtype = ROADTYPE_ROAD;
2584 _last_built_tramtype = ROADTYPE_TRAM;
2586 if (_game_mode == GM_EDITOR) {
2587 new ScenarioEditorToolbarWindow(&_toolb_scen_desc);
2588 } else {
2589 new MainToolbarWindow(&_toolb_normal_desc);