Update: Translations from eints
[openttd-github.git] / src / toolbar_gui.cpp
blobc1aa2ff2673e44755dcb08f62b7c24ee3cdf83f9
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 "dropdown_type.h"
17 #include "dropdown_func.h"
18 #include "dropdown_common_type.h"
19 #include "house.h"
20 #include "vehicle_gui.h"
21 #include "rail_gui.h"
22 #include "road.h"
23 #include "road_gui.h"
24 #include "vehicle_func.h"
25 #include "sound_func.h"
26 #include "terraform_gui.h"
27 #include "strings_func.h"
28 #include "company_func.h"
29 #include "company_gui.h"
30 #include "vehicle_base.h"
31 #include "cheat_func.h"
32 #include "transparency_gui.h"
33 #include "screenshot.h"
34 #include "signs_func.h"
35 #include "fios.h"
36 #include "console_gui.h"
37 #include "news_gui.h"
38 #include "ai/ai_gui.hpp"
39 #include "game/game_gui.hpp"
40 #include "script/script_gui.h"
41 #include "tilehighlight_func.h"
42 #include "smallmap_gui.h"
43 #include "graph_gui.h"
44 #include "textbuf_gui.h"
45 #include "linkgraph/linkgraph_gui.h"
46 #include "newgrf_debug.h"
47 #include "hotkeys.h"
48 #include "engine_base.h"
49 #include "highscore.h"
50 #include "game/game.hpp"
51 #include "goal_base.h"
52 #include "story_base.h"
53 #include "toolbar_gui.h"
54 #include "framerate_type.h"
55 #include "screenshot_gui.h"
56 #include "misc_cmd.h"
57 #include "league_gui.h"
58 #include "league_base.h"
59 #include "timer/timer.h"
60 #include "timer/timer_window.h"
61 #include "timer/timer_game_calendar.h"
62 #include "help_gui.h"
64 #include "widgets/toolbar_widget.h"
66 #include "network/network.h"
67 #include "network/network_gui.h"
68 #include "network/network_func.h"
70 #include "safeguards.h"
73 /** Width of the toolbar, shared by statusbar. */
74 uint _toolbar_width = 0;
76 RailType _last_built_railtype;
77 RoadType _last_built_roadtype;
78 RoadType _last_built_tramtype;
80 /** Toobar modes */
81 enum ToolbarMode {
82 TB_NORMAL,
83 TB_UPPER,
84 TB_LOWER
87 /** Callback functions. */
88 enum CallBackFunction {
89 CBF_NONE,
90 CBF_PLACE_SIGN,
91 CBF_PLACE_LANDINFO,
94 static CallBackFunction _last_started_action = CBF_NONE; ///< Last started user action.
96 /**
97 * Company name list item, with company-colour icon, name, and lock components.
99 class DropDownListCompanyItem : public DropDownIcon<DropDownIcon<DropDownString<DropDownListItem>, true>> {
100 public:
101 DropDownListCompanyItem(CompanyID company, bool shaded) : DropDownIcon<DropDownIcon<DropDownString<DropDownListItem>, true>>(SPR_COMPANY_ICON, COMPANY_SPRITE_COLOUR(company), NetworkCanJoinCompany(company) ? SPR_EMPTY : SPR_LOCK, PAL_NONE, STR_NULL, company, false, shaded)
103 SetDParam(0, company);
104 SetDParam(1, company);
105 this->SetString(GetString(STR_COMPANY_NAME_COMPANY_NUM));
110 * Pop up a generic text only menu.
111 * @param w Toolbar
112 * @param widget Toolbar button
113 * @param list List of items
114 * @param def Default item
116 static void PopupMainToolbarMenu(Window *w, WidgetID widget, DropDownList &&list, int def)
118 ShowDropDownList(w, std::move(list), def, widget, 0, true);
119 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
123 * Pop up a generic text only menu.
124 * @param w Toolbar
125 * @param widget Toolbar button
126 * @param strings List of strings for each item in the menu
128 static void PopupMainToolbarMenu(Window *w, WidgetID widget, const std::initializer_list<StringID> &strings)
130 DropDownList list;
131 int i = 0;
132 for (StringID string : strings) {
133 if (string == STR_NULL) {
134 list.push_back(MakeDropDownListDividerItem());
135 } else {
136 list.push_back(MakeDropDownListStringItem(string, i));
137 i++;
140 PopupMainToolbarMenu(w, widget, std::move(list), 0);
143 /** Enum for the Company Toolbar's network related buttons */
144 static const int CTMN_CLIENT_LIST = -1; ///< Show the client list
145 static const int CTMN_SPECTATE = -2; ///< Become spectator
146 static const int CTMN_SPECTATOR = -3; ///< Show a company window as spectator
149 * Pop up a generic company list menu.
150 * @param w The toolbar window.
151 * @param widget The button widget id.
152 * @param grey A bitmask of which companies to mark as disabled.
154 static void PopupMainCompanyToolbMenu(Window *w, WidgetID widget, CompanyMask grey = 0)
156 DropDownList list;
158 switch (widget) {
159 case WID_TN_COMPANIES:
160 if (!_networking) break;
162 /* Add the client list button for the companies menu */
163 list.push_back(MakeDropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST));
165 if (_local_company != COMPANY_SPECTATOR) {
166 list.push_back(MakeDropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE));
168 break;
169 case WID_TN_STORY:
170 list.push_back(MakeDropDownListStringItem(STR_STORY_BOOK_SPECTATOR, CTMN_SPECTATOR));
171 break;
173 case WID_TN_GOAL:
174 list.push_back(MakeDropDownListStringItem(STR_GOALS_SPECTATOR, CTMN_SPECTATOR));
175 break;
178 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
179 if (!Company::IsValidID(c)) continue;
180 list.push_back(std::make_unique<DropDownListCompanyItem>(c, HasBit(grey, c)));
183 PopupMainToolbarMenu(w, widget, std::move(list), _local_company == COMPANY_SPECTATOR ? (widget == WID_TN_COMPANIES ? CTMN_CLIENT_LIST : CTMN_SPECTATOR) : (int)_local_company);
186 static ToolbarMode _toolbar_mode;
188 static CallBackFunction SelectSignTool()
190 if (_last_started_action == CBF_PLACE_SIGN) {
191 ResetObjectToPlace();
192 return CBF_NONE;
193 } else {
194 SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
195 return CBF_PLACE_SIGN;
199 /* --- Pausing --- */
201 static CallBackFunction ToolbarPauseClick(Window *)
203 if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
205 if (Command<CMD_PAUSE>::Post(PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED)) {
206 if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
208 return CBF_NONE;
212 * Toggle fast forward mode.
214 * @return #CBF_NONE
216 static CallBackFunction ToolbarFastForwardClick(Window *)
218 if (_networking) return CBF_NONE; // no fast forward in network game
220 ChangeGameSpeed(_game_speed == 100);
222 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
223 return CBF_NONE;
227 * Game Option button menu entries.
229 enum OptionMenuEntries {
230 OME_GAMEOPTIONS,
231 OME_SETTINGS,
232 OME_AI_SETTINGS,
233 OME_GAMESCRIPT_SETTINGS,
234 OME_NEWGRFSETTINGS,
235 OME_SANDBOX,
236 OME_TRANSPARENCIES,
237 OME_SHOW_TOWNNAMES,
238 OME_SHOW_STATIONNAMES,
239 OME_SHOW_WAYPOINTNAMES,
240 OME_SHOW_SIGNS,
241 OME_SHOW_COMPETITOR_SIGNS,
242 OME_FULL_ANIMATION,
243 OME_FULL_DETAILS,
244 OME_TRANSPARENTBUILDINGS,
245 OME_SHOW_STATIONSIGNS,
249 * Handle click on Options button in toolbar.
251 * @param w parent window the shown Drop down list is attached to.
252 * @return #CBF_NONE
254 static CallBackFunction ToolbarOptionsClick(Window *w)
256 DropDownList list;
257 list.push_back(MakeDropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS));
258 list.push_back(MakeDropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS));
259 /* Changes to the per-AI settings don't get send from the server to the clients. Clients get
260 * the settings once they join but never update it. As such don't show the window at all
261 * to network clients. */
262 if (!_networking || _network_server) {
263 list.push_back(MakeDropDownListStringItem(STR_SETTINGS_MENU_AI_SETTINGS, OME_AI_SETTINGS));
264 list.push_back(MakeDropDownListStringItem(STR_SETTINGS_MENU_GAMESCRIPT_SETTINGS, OME_GAMESCRIPT_SETTINGS));
266 list.push_back(MakeDropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS));
267 if (_game_mode != GM_EDITOR && !_networking) {
268 list.push_back(MakeDropDownListStringItem(STR_SETTINGS_MENU_SANDBOX_OPTIONS, OME_SANDBOX));
270 list.push_back(MakeDropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES));
271 list.push_back(MakeDropDownListDividerItem());
272 list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_TOWN_NAMES), STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES));
273 list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_STATION_NAMES), STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES));
274 list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES), STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES));
275 list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_SIGNS), STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS));
276 list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS), STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS));
277 list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_FULL_ANIMATION), STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION));
278 list.push_back(MakeDropDownListCheckedItem(HasBit(_display_opt, DO_FULL_DETAIL), STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS));
279 list.push_back(MakeDropDownListCheckedItem(IsTransparencySet(TO_HOUSES), STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS));
280 list.push_back(MakeDropDownListCheckedItem(IsTransparencySet(TO_SIGNS), STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS));
282 ShowDropDownList(w, std::move(list), 0, WID_TN_SETTINGS, 140, true);
283 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
284 return CBF_NONE;
288 * Handle click on one of the entries in the Options button menu.
290 * @param index Index being clicked.
291 * @return #CBF_NONE
293 static CallBackFunction MenuClickSettings(int index)
295 switch (index) {
296 case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE;
297 case OME_SETTINGS: ShowGameSettings(); return CBF_NONE;
298 case OME_AI_SETTINGS: ShowAIConfigWindow(); return CBF_NONE;
299 case OME_GAMESCRIPT_SETTINGS: ShowGSConfigWindow(); return CBF_NONE;
300 case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
301 case OME_SANDBOX: ShowCheatWindow(); break;
302 case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break;
304 case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break;
305 case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break;
306 case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break;
307 case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break;
308 case OME_SHOW_COMPETITOR_SIGNS:
309 ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
310 InvalidateWindowClassesData(WC_SIGN_LIST, -1);
311 break;
312 case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break;
313 case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break;
314 case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break;
315 case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break;
317 MarkWholeScreenDirty();
318 return CBF_NONE;
322 * SaveLoad entries in scenario editor mode.
324 enum SaveLoadEditorMenuEntries {
325 SLEME_SAVE_SCENARIO = 0,
326 SLEME_LOAD_SCENARIO,
327 SLEME_SAVE_HEIGHTMAP,
328 SLEME_LOAD_HEIGHTMAP,
329 SLEME_EXIT_TOINTRO,
330 SLEME_EXIT_GAME,
334 * SaveLoad entries in normal game mode.
336 enum SaveLoadNormalMenuEntries {
337 SLNME_SAVE_GAME = 0,
338 SLNME_LOAD_GAME,
339 SLNME_EXIT_TOINTRO,
340 SLNME_EXIT_GAME,
344 * Handle click on Save button in toolbar in normal game mode.
346 * @param w parent window the shown save dialogue is attached to.
347 * @return #CBF_NONE
349 static CallBackFunction ToolbarSaveClick(Window *w)
351 PopupMainToolbarMenu(w, WID_TN_SAVE, {STR_FILE_MENU_SAVE_GAME, STR_FILE_MENU_LOAD_GAME, STR_FILE_MENU_QUIT_GAME,
352 STR_NULL, STR_FILE_MENU_EXIT});
353 return CBF_NONE;
357 * Handle click on SaveLoad button in toolbar in the scenario editor.
359 * @param w parent window the shown save dialogue is attached to.
360 * @return #CBF_NONE
362 static CallBackFunction ToolbarScenSaveOrLoad(Window *w)
364 PopupMainToolbarMenu(w, WID_TE_SAVE, {STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, STR_SCENEDIT_FILE_MENU_LOAD_SCENARIO,
365 STR_SCENEDIT_FILE_MENU_SAVE_HEIGHTMAP, STR_SCENEDIT_FILE_MENU_LOAD_HEIGHTMAP,
366 STR_SCENEDIT_FILE_MENU_QUIT_EDITOR, STR_NULL, STR_SCENEDIT_FILE_MENU_QUIT});
367 return CBF_NONE;
371 * Handle click on one of the entries in the SaveLoad menu.
373 * @param index Index being clicked.
374 * @return #CBF_NONE
376 static CallBackFunction MenuClickSaveLoad(int index = 0)
378 if (_game_mode == GM_EDITOR) {
379 switch (index) {
380 case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_SAVE); break;
381 case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD); break;
382 case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP, SLO_SAVE); break;
383 case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP, SLO_LOAD); break;
384 case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break;
385 case SLEME_EXIT_GAME: HandleExitGameRequest(); break;
387 } else {
388 switch (index) {
389 case SLNME_SAVE_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_SAVE); break;
390 case SLNME_LOAD_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
391 case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break;
392 case SLNME_EXIT_GAME: HandleExitGameRequest(); break;
395 return CBF_NONE;
398 /* --- Map button menu --- */
400 enum MapMenuEntries {
401 MME_SHOW_SMALLMAP = 0,
402 MME_SHOW_EXTRAVIEWPORTS,
403 MME_SHOW_LINKGRAPH,
404 MME_SHOW_SIGNLISTS,
405 MME_SHOW_TOWNDIRECTORY,
406 MME_SHOW_INDUSTRYDIRECTORY,
409 static CallBackFunction ToolbarMapClick(Window *w)
411 DropDownList list;
412 list.push_back(MakeDropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP));
413 list.push_back(MakeDropDownListStringItem(STR_MAP_MENU_EXTRA_VIEWPORT, MME_SHOW_EXTRAVIEWPORTS));
414 list.push_back(MakeDropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH));
415 list.push_back(MakeDropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS));
416 PopupMainToolbarMenu(w, WID_TN_SMALL_MAP, std::move(list), 0);
417 return CBF_NONE;
420 static CallBackFunction ToolbarScenMapTownDir(Window *w)
422 DropDownList list;
423 list.push_back(MakeDropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP));
424 list.push_back(MakeDropDownListStringItem(STR_MAP_MENU_EXTRA_VIEWPORT, MME_SHOW_EXTRAVIEWPORTS));
425 list.push_back(MakeDropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS));
426 list.push_back(MakeDropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY));
427 list.push_back(MakeDropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY));
428 PopupMainToolbarMenu(w, WID_TE_SMALL_MAP, std::move(list), 0);
429 return CBF_NONE;
433 * Handle click on one of the entries in the Map menu.
435 * @param index Index being clicked.
436 * @return #CBF_NONE
438 static CallBackFunction MenuClickMap(int index)
440 switch (index) {
441 case MME_SHOW_SMALLMAP: ShowSmallMap(); break;
442 case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewportWindow(); break;
443 case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break;
444 case MME_SHOW_SIGNLISTS: ShowSignList(); break;
445 case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
446 case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break;
448 return CBF_NONE;
451 /* --- Town button menu --- */
453 static CallBackFunction ToolbarTownClick(Window *w)
455 if (_settings_game.economy.found_town == TF_FORBIDDEN) {
456 PopupMainToolbarMenu(w, WID_TN_TOWNS, {STR_TOWN_MENU_TOWN_DIRECTORY});
457 } else {
458 PopupMainToolbarMenu(w, WID_TN_TOWNS, {STR_TOWN_MENU_TOWN_DIRECTORY, STR_TOWN_MENU_FOUND_TOWN});
460 return CBF_NONE;
464 * Handle click on one of the entries in the Town menu.
466 * @param index Index being clicked.
467 * @return #CBF_NONE
469 static CallBackFunction MenuClickTown(int index)
471 switch (index) {
472 case 0: ShowTownDirectory(); break;
473 case 1: // setting could be changed when the dropdown was open
474 if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
475 break;
477 return CBF_NONE;
480 /* --- Subidies button menu --- */
482 static CallBackFunction ToolbarSubsidiesClick(Window *w)
484 PopupMainToolbarMenu(w, WID_TN_SUBSIDIES, {STR_SUBSIDIES_MENU_SUBSIDIES});
485 return CBF_NONE;
489 * Handle click on the entry in the Subsidies menu.
491 * @return #CBF_NONE
493 static CallBackFunction MenuClickSubsidies(int)
495 ShowSubsidiesList();
496 return CBF_NONE;
499 /* --- Stations button menu --- */
501 static CallBackFunction ToolbarStationsClick(Window *w)
503 PopupMainCompanyToolbMenu(w, WID_TN_STATIONS);
504 return CBF_NONE;
508 * Handle click on the entry in the Stations menu
510 * @param index CompanyID to show station list for
511 * @return #CBF_NONE
513 static CallBackFunction MenuClickStations(int index)
515 ShowCompanyStations((CompanyID)index);
516 return CBF_NONE;
519 /* --- Finances button menu --- */
521 static CallBackFunction ToolbarFinancesClick(Window *w)
523 PopupMainCompanyToolbMenu(w, WID_TN_FINANCES);
524 return CBF_NONE;
528 * Handle click on the entry in the finances overview menu.
530 * @param index CompanyID to show finances for.
531 * @return #CBF_NONE
533 static CallBackFunction MenuClickFinances(int index)
535 ShowCompanyFinances((CompanyID)index);
536 return CBF_NONE;
539 /* --- Company's button menu --- */
541 static CallBackFunction ToolbarCompaniesClick(Window *w)
543 PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0);
544 return CBF_NONE;
548 * Handle click on the entry in the Company menu.
550 * @param index Menu entry to handle.
551 * @return #CBF_NONE
553 static CallBackFunction MenuClickCompany(int index)
555 if (_networking) {
556 switch (index) {
557 case CTMN_CLIENT_LIST:
558 ShowClientList();
559 return CBF_NONE;
561 case CTMN_SPECTATE:
562 if (_network_server) {
563 NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR);
564 MarkWholeScreenDirty();
565 } else {
566 NetworkClientRequestMove(COMPANY_SPECTATOR);
568 return CBF_NONE;
571 ShowCompany((CompanyID)index);
572 return CBF_NONE;
575 /* --- Story button menu --- */
577 static CallBackFunction ToolbarStoryClick(Window *w)
579 PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0);
580 return CBF_NONE;
584 * Handle click on the entry in the Story menu
586 * @param index CompanyID to show story book for
587 * @return #CBF_NONE
589 static CallBackFunction MenuClickStory(int index)
591 ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
592 return CBF_NONE;
595 /* --- Goal button menu --- */
597 static CallBackFunction ToolbarGoalClick(Window *w)
599 PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0);
600 return CBF_NONE;
604 * Handle click on the entry in the Goal menu
606 * @param index CompanyID to show story book for
607 * @return #CBF_NONE
609 static CallBackFunction MenuClickGoal(int index)
611 ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
612 return CBF_NONE;
615 /* --- Graphs and League Table button menu --- */
618 * Enum for the League Toolbar's and Graph Toolbar's related buttons.
619 * Use continuous numbering as League Toolbar can be combined into the Graph Toolbar.
621 static const int GRMN_OPERATING_PROFIT_GRAPH = -1; ///< Show operating profit graph
622 static const int GRMN_INCOME_GRAPH = -2; ///< Show income graph
623 static const int GRMN_DELIVERED_CARGO_GRAPH = -3; ///< Show delivered cargo graph
624 static const int GRMN_PERFORMANCE_HISTORY_GRAPH = -4; ///< Show performance history graph
625 static const int GRMN_COMPANY_VALUE_GRAPH = -5; ///< Show company value graph
626 static const int GRMN_CARGO_PAYMENT_RATES = -6; ///< Show cargo payment rates graph
627 static const int LTMN_PERFORMANCE_LEAGUE = -7; ///< Show default league table
628 static const int LTMN_PERFORMANCE_RATING = -8; ///< Show detailed performance rating
629 static const int LTMN_HIGHSCORE = -9; ///< Show highscrore table
631 static void AddDropDownLeagueTableOptions(DropDownList &list)
633 if (LeagueTable::GetNumItems() > 0) {
634 for (LeagueTable *lt : LeagueTable::Iterate()) {
635 list.push_back(MakeDropDownListStringItem(lt->title, lt->index));
637 } else {
638 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, LTMN_PERFORMANCE_LEAGUE));
639 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING, LTMN_PERFORMANCE_RATING));
640 if (!_networking) {
641 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_HIGHSCORE, LTMN_HIGHSCORE));
646 static CallBackFunction ToolbarGraphsClick(Window *w)
648 DropDownList list;
650 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, GRMN_OPERATING_PROFIT_GRAPH));
651 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_INCOME_GRAPH, GRMN_INCOME_GRAPH));
652 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_DELIVERED_CARGO_GRAPH, GRMN_DELIVERED_CARGO_GRAPH));
653 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_PERFORMANCE_HISTORY_GRAPH, GRMN_PERFORMANCE_HISTORY_GRAPH));
654 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_COMPANY_VALUE_GRAPH, GRMN_COMPANY_VALUE_GRAPH));
655 list.push_back(MakeDropDownListStringItem(STR_GRAPH_MENU_CARGO_PAYMENT_RATES, GRMN_CARGO_PAYMENT_RATES));
657 if (_toolbar_mode != TB_NORMAL) AddDropDownLeagueTableOptions(list);
659 ShowDropDownList(w, std::move(list), GRMN_OPERATING_PROFIT_GRAPH, WID_TN_GRAPHS, 140, true);
660 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
662 return CBF_NONE;
665 static CallBackFunction ToolbarLeagueClick(Window *w)
667 DropDownList list;
669 AddDropDownLeagueTableOptions(list);
671 int selected = list[0]->result;
672 ShowDropDownList(w, std::move(list), selected, WID_TN_LEAGUE, 140, true);
673 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
675 return CBF_NONE;
679 * Handle click on the entry in the Graphs or CompanyLeague.
681 * @param index Graph to show.
682 * @return #CBF_NONE
684 static CallBackFunction MenuClickGraphsOrLeague(int index)
686 switch (index) {
687 case GRMN_OPERATING_PROFIT_GRAPH: ShowOperatingProfitGraph(); break;
688 case GRMN_INCOME_GRAPH: ShowIncomeGraph(); break;
689 case GRMN_DELIVERED_CARGO_GRAPH: ShowDeliveredCargoGraph(); break;
690 case GRMN_PERFORMANCE_HISTORY_GRAPH: ShowPerformanceHistoryGraph(); break;
691 case GRMN_COMPANY_VALUE_GRAPH: ShowCompanyValueGraph(); break;
692 case GRMN_CARGO_PAYMENT_RATES: ShowCargoPaymentRates(); break;
693 case LTMN_PERFORMANCE_LEAGUE: ShowPerformanceLeagueTable(); break;
694 case LTMN_PERFORMANCE_RATING: ShowPerformanceRatingDetail(); break;
695 case LTMN_HIGHSCORE: ShowHighscoreTable(); break;
696 default: {
697 if (LeagueTable::IsValidID(index)) {
698 ShowScriptLeagueTable((LeagueTableID)index);
702 return CBF_NONE;
707 /* --- Industries button menu --- */
709 static CallBackFunction ToolbarIndustryClick(Window *w)
711 /* Disable build-industry menu if we are a spectator */
712 if (_local_company == COMPANY_SPECTATOR) {
713 PopupMainToolbarMenu(w, WID_TN_INDUSTRIES, {STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, STR_INDUSTRY_MENU_INDUSTRY_CHAIN});
714 } else {
715 PopupMainToolbarMenu(w, WID_TN_INDUSTRIES, {STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, STR_INDUSTRY_MENU_INDUSTRY_CHAIN, STR_INDUSTRY_MENU_FUND_NEW_INDUSTRY});
717 return CBF_NONE;
721 * Handle click on the entry in the Industry menu.
723 * @param index Menu entry number.
724 * @return #CBF_NONE
726 static CallBackFunction MenuClickIndustry(int index)
728 switch (index) {
729 case 0: ShowIndustryDirectory(); break;
730 case 1: ShowIndustryCargoesWindow(); break;
731 case 2: ShowBuildIndustryWindow(); break;
733 return CBF_NONE;
736 /* --- Trains button menu + 1 helper function for all vehicles. --- */
738 static void ToolbarVehicleClick(Window *w, VehicleType veh)
740 CompanyMask dis = 0;
742 for (const Company *c : Company::Iterate()) {
743 if (c->group_all[veh].num_vehicle == 0) SetBit(dis, c->index);
745 PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis);
749 static CallBackFunction ToolbarTrainClick(Window *w)
751 ToolbarVehicleClick(w, VEH_TRAIN);
752 return CBF_NONE;
756 * Handle click on the entry in the Train menu.
758 * @param index CompanyID to show train list for.
759 * @return #CBF_NONE
761 static CallBackFunction MenuClickShowTrains(int index)
763 ShowVehicleListWindow((CompanyID)index, VEH_TRAIN);
764 return CBF_NONE;
767 /* --- Road vehicle button menu --- */
769 static CallBackFunction ToolbarRoadClick(Window *w)
771 ToolbarVehicleClick(w, VEH_ROAD);
772 return CBF_NONE;
776 * Handle click on the entry in the Road Vehicles menu.
778 * @param index CompanyID to show road vehicles list for.
779 * @return #CBF_NONE
781 static CallBackFunction MenuClickShowRoad(int index)
783 ShowVehicleListWindow((CompanyID)index, VEH_ROAD);
784 return CBF_NONE;
787 /* --- Ship button menu --- */
789 static CallBackFunction ToolbarShipClick(Window *w)
791 ToolbarVehicleClick(w, VEH_SHIP);
792 return CBF_NONE;
796 * Handle click on the entry in the Ships menu.
798 * @param index CompanyID to show ship list for.
799 * @return #CBF_NONE
801 static CallBackFunction MenuClickShowShips(int index)
803 ShowVehicleListWindow((CompanyID)index, VEH_SHIP);
804 return CBF_NONE;
807 /* --- Aircraft button menu --- */
809 static CallBackFunction ToolbarAirClick(Window *w)
811 ToolbarVehicleClick(w, VEH_AIRCRAFT);
812 return CBF_NONE;
816 * Handle click on the entry in the Aircraft menu.
818 * @param index CompanyID to show aircraft list for.
819 * @return #CBF_NONE
821 static CallBackFunction MenuClickShowAir(int index)
823 ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT);
824 return CBF_NONE;
827 /* --- Zoom in button --- */
829 static CallBackFunction ToolbarZoomInClick(Window *w)
831 if (DoZoomInOutWindow(ZOOM_IN, GetMainWindow())) {
832 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (WidgetID)WID_TE_ZOOM_IN : (WidgetID)WID_TN_ZOOM_IN);
833 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
835 return CBF_NONE;
838 /* --- Zoom out button --- */
840 static CallBackFunction ToolbarZoomOutClick(Window *w)
842 if (DoZoomInOutWindow(ZOOM_OUT, GetMainWindow())) {
843 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (WidgetID)WID_TE_ZOOM_OUT : (WidgetID)WID_TN_ZOOM_OUT);
844 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
846 return CBF_NONE;
849 /* --- Rail button menu --- */
851 static CallBackFunction ToolbarBuildRailClick(Window *w)
853 ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true);
854 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
855 return CBF_NONE;
859 * Handle click on the entry in the Build Rail menu.
861 * @param index RailType to show the build toolbar for.
862 * @return #CBF_NONE
864 static CallBackFunction MenuClickBuildRail(int index)
866 _last_built_railtype = (RailType)index;
867 ShowBuildRailToolbar(_last_built_railtype);
868 return CBF_NONE;
871 /* --- Road button menu --- */
873 static CallBackFunction ToolbarBuildRoadClick(Window *w)
875 ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TN_ROADS, 140, true);
876 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
877 return CBF_NONE;
881 * Handle click on the entry in the Build Road menu.
883 * @param index RoadType to show the build toolbar for.
884 * @return #CBF_NONE
886 static CallBackFunction MenuClickBuildRoad(int index)
888 _last_built_roadtype = (RoadType)index;
889 ShowBuildRoadToolbar(_last_built_roadtype);
890 return CBF_NONE;
893 /* --- Tram button menu --- */
895 static CallBackFunction ToolbarBuildTramClick(Window *w)
897 ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TN_TRAMS, 140, true);
898 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
899 return CBF_NONE;
903 * Handle click on the entry in the Build Tram menu.
905 * @param index RoadType to show the build toolbar for.
906 * @return #CBF_NONE
908 static CallBackFunction MenuClickBuildTram(int index)
910 _last_built_tramtype = (RoadType)index;
911 ShowBuildRoadToolbar(_last_built_tramtype);
912 return CBF_NONE;
915 /* --- Water button menu --- */
917 static CallBackFunction ToolbarBuildWaterClick(Window *w)
919 DropDownList list;
920 list.push_back(MakeDropDownListIconItem(SPR_IMG_BUILD_CANAL, PAL_NONE, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 0));
921 ShowDropDownList(w, std::move(list), 0, WID_TN_WATER, 140, true);
922 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
923 return CBF_NONE;
927 * Handle click on the entry in the Build Waterways menu.
929 * @return #CBF_NONE
931 static CallBackFunction MenuClickBuildWater(int)
933 ShowBuildDocksToolbar();
934 return CBF_NONE;
937 /* --- Airport button menu --- */
939 static CallBackFunction ToolbarBuildAirClick(Window *w)
941 DropDownList list;
942 list.push_back(MakeDropDownListIconItem(SPR_IMG_AIRPORT, PAL_NONE, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 0));
943 ShowDropDownList(w, std::move(list), 0, WID_TN_AIR, 140, true);
944 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
945 return CBF_NONE;
949 * Handle click on the entry in the Build Air menu.
951 * @return #CBF_NONE
953 static CallBackFunction MenuClickBuildAir(int)
955 ShowBuildAirToolbar();
956 return CBF_NONE;
959 /* --- Forest button menu --- */
961 static CallBackFunction ToolbarForestClick(Window *w)
963 DropDownList list;
964 list.push_back(MakeDropDownListIconItem(SPR_IMG_LANDSCAPING, PAL_NONE, STR_LANDSCAPING_MENU_LANDSCAPING, 0));
965 list.push_back(MakeDropDownListIconItem(SPR_IMG_PLANTTREES, PAL_NONE, STR_LANDSCAPING_MENU_PLANT_TREES, 1));
966 list.push_back(MakeDropDownListIconItem(SPR_IMG_SIGN, PAL_NONE, STR_LANDSCAPING_MENU_PLACE_SIGN, 2));
967 ShowDropDownList(w, std::move(list), 0, WID_TN_LANDSCAPE, 100, true);
968 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
969 return CBF_NONE;
973 * Handle click on the entry in the landscaping menu.
975 * @param index Menu entry clicked.
976 * @return #CBF_NONE
978 static CallBackFunction MenuClickForest(int index)
980 switch (index) {
981 case 0: ShowTerraformToolbar(); break;
982 case 1: ShowBuildTreesToolbar(); break;
983 case 2: return SelectSignTool();
985 return CBF_NONE;
988 /* --- Music button menu --- */
990 static CallBackFunction ToolbarMusicClick(Window *w)
992 PopupMainToolbarMenu(w, _game_mode == GM_EDITOR ? (WidgetID)WID_TE_MUSIC_SOUND : (WidgetID)WID_TN_MUSIC_SOUND, {STR_TOOLBAR_SOUND_MUSIC});
993 return CBF_NONE;
997 * Handle click on the entry in the Music menu.
999 * @return #CBF_NONE
1001 static CallBackFunction MenuClickMusicWindow(int)
1003 ShowMusicWindow();
1004 return CBF_NONE;
1007 /* --- Newspaper button menu --- */
1009 static CallBackFunction ToolbarNewspaperClick(Window *w)
1011 PopupMainToolbarMenu(w, WID_TN_MESSAGES, {STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, STR_NEWS_MENU_MESSAGE_HISTORY_MENU, STR_NEWS_MENU_DELETE_ALL_MESSAGES});
1012 return CBF_NONE;
1016 * Handle click on the entry in the Newspaper menu.
1018 * @param index Menu entry clicked.
1019 * @return #CBF_NONE
1021 static CallBackFunction MenuClickNewspaper(int index)
1023 switch (index) {
1024 case 0: ShowLastNewsMessage(); break;
1025 case 1: ShowMessageHistory(); break;
1026 case 2: DeleteAllMessages(); break;
1028 return CBF_NONE;
1031 /* --- Help button menu --- */
1033 static CallBackFunction PlaceLandBlockInfo()
1035 if (_last_started_action == CBF_PLACE_LANDINFO) {
1036 ResetObjectToPlace();
1037 return CBF_NONE;
1038 } else {
1039 SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
1040 return CBF_PLACE_LANDINFO;
1044 static CallBackFunction ToolbarHelpClick(Window *w)
1046 if (_settings_client.gui.newgrf_developer_tools) {
1047 PopupMainToolbarMenu(w, _game_mode == GM_EDITOR ? (WidgetID)WID_TE_HELP : (WidgetID)WID_TN_HELP, {STR_ABOUT_MENU_LAND_BLOCK_INFO,
1048 STR_ABOUT_MENU_HELP, STR_NULL, STR_ABOUT_MENU_TOGGLE_CONSOLE, STR_ABOUT_MENU_AI_DEBUG,
1049 STR_ABOUT_MENU_SCREENSHOT, STR_ABOUT_MENU_SHOW_FRAMERATE, STR_ABOUT_MENU_ABOUT_OPENTTD,
1050 STR_ABOUT_MENU_SPRITE_ALIGNER, STR_ABOUT_MENU_TOGGLE_BOUNDING_BOXES, STR_ABOUT_MENU_TOGGLE_DIRTY_BLOCKS,
1051 STR_ABOUT_MENU_TOGGLE_WIDGET_OUTLINES});
1052 } else {
1053 PopupMainToolbarMenu(w, _game_mode == GM_EDITOR ? (WidgetID)WID_TE_HELP : (WidgetID)WID_TN_HELP, {STR_ABOUT_MENU_LAND_BLOCK_INFO,
1054 STR_ABOUT_MENU_HELP, STR_NULL, STR_ABOUT_MENU_TOGGLE_CONSOLE, STR_ABOUT_MENU_AI_DEBUG,
1055 STR_ABOUT_MENU_SCREENSHOT, STR_ABOUT_MENU_SHOW_FRAMERATE, STR_ABOUT_MENU_ABOUT_OPENTTD});
1057 return CBF_NONE;
1061 * Toggle drawing of sprites' bounding boxes.
1062 * @note has only an effect when newgrf_developer_tools are active.
1064 * Function is found here and not in viewport.cpp in order to avoid
1065 * importing the settings structs to there.
1067 void ToggleBoundingBoxes()
1069 extern bool _draw_bounding_boxes;
1070 /* Always allow to toggle them off */
1071 if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) {
1072 _draw_bounding_boxes = !_draw_bounding_boxes;
1073 MarkWholeScreenDirty();
1078 * Toggle drawing of the dirty blocks.
1079 * @note has only an effect when newgrf_developer_tools are active.
1081 * Function is found here and not in viewport.cpp in order to avoid
1082 * importing the settings structs to there.
1084 void ToggleDirtyBlocks()
1086 extern bool _draw_dirty_blocks;
1087 /* Always allow to toggle them off */
1088 if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) {
1089 _draw_dirty_blocks = !_draw_dirty_blocks;
1090 MarkWholeScreenDirty();
1095 * Toggle drawing of widget outlihes.
1096 * @note has only an effect when newgrf_developer_tools are active.
1098 void ToggleWidgetOutlines()
1100 extern bool _draw_widget_outlines;
1101 /* Always allow to toggle them off */
1102 if (_settings_client.gui.newgrf_developer_tools || _draw_widget_outlines) {
1103 _draw_widget_outlines = !_draw_widget_outlines;
1104 MarkWholeScreenDirty();
1109 * Set the starting year for a scenario.
1110 * @param year New starting year.
1112 void SetStartingYear(TimerGameCalendar::Year year)
1114 _settings_game.game_creation.starting_year = Clamp(year, CalendarTime::MIN_YEAR, CalendarTime::MAX_YEAR);
1115 TimerGameCalendar::Date new_calendar_date = TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
1116 TimerGameEconomy::Date new_economy_date = new_calendar_date.base();
1118 /* We must set both Calendar and Economy dates to keep them in sync. Calendar first. */
1119 TimerGameCalendar::SetDate(new_calendar_date, 0);
1121 /* If you open a savegame as a scenario, there may already be link graphs and/or vehicles. These use economy date. */
1122 LinkGraphSchedule::instance.ShiftDates(new_economy_date - TimerGameEconomy::date);
1123 for (auto v : Vehicle::Iterate()) v->ShiftDates(new_economy_date - TimerGameEconomy::date);
1125 /* Only change the date after changing cached values above. */
1126 TimerGameEconomy::SetDate(new_economy_date, 0);
1130 * Choose the proper callback function for the main toolbar's help menu.
1131 * @param index The menu index which was selected.
1132 * @return CBF_NONE
1134 static CallBackFunction MenuClickHelp(int index)
1136 switch (index) {
1137 case 0: return PlaceLandBlockInfo();
1138 case 1: ShowHelpWindow(); break;
1139 case 2: IConsoleSwitch(); break;
1140 case 3: ShowScriptDebugWindow(INVALID_COMPANY, _ctrl_pressed); break;
1141 case 4: ShowScreenshotWindow(); break;
1142 case 5: ShowFramerateWindow(); break;
1143 case 6: ShowAboutWindow(); break;
1144 case 7: ShowSpriteAlignerWindow(); break;
1145 case 8: ToggleBoundingBoxes(); break;
1146 case 9: ToggleDirtyBlocks(); break;
1147 case 10: ToggleWidgetOutlines(); break;
1149 return CBF_NONE;
1152 /* --- Switch toolbar button --- */
1154 static CallBackFunction ToolbarSwitchClick(Window *w)
1156 if (_toolbar_mode != TB_LOWER) {
1157 _toolbar_mode = TB_LOWER;
1158 } else {
1159 _toolbar_mode = TB_UPPER;
1162 w->ReInit();
1163 w->SetWidgetLoweredState(_game_mode == GM_EDITOR ? (WidgetID)WID_TE_SWITCH_BAR : (WidgetID)WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
1164 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1165 return CBF_NONE;
1168 /* --- Scenario editor specific handlers. */
1171 * Called when clicking at the date panel of the scenario editor toolbar.
1173 static CallBackFunction ToolbarScenDatePanel(Window *w)
1175 SetDParam(0, _settings_game.game_creation.starting_year);
1176 ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
1177 return CBF_NONE;
1180 static CallBackFunction ToolbarScenDateBackward(Window *w)
1182 /* don't allow too fast scrolling */
1183 if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1184 w->HandleButtonClick(WID_TE_DATE_BACKWARD);
1185 w->SetDirty();
1187 SetStartingYear(_settings_game.game_creation.starting_year - 1);
1189 _left_button_clicked = false;
1190 return CBF_NONE;
1193 static CallBackFunction ToolbarScenDateForward(Window *w)
1195 /* don't allow too fast scrolling */
1196 if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1197 w->HandleButtonClick(WID_TE_DATE_FORWARD);
1198 w->SetDirty();
1200 SetStartingYear(_settings_game.game_creation.starting_year + 1);
1202 _left_button_clicked = false;
1203 return CBF_NONE;
1206 static CallBackFunction ToolbarScenGenLand(Window *w)
1208 w->HandleButtonClick(WID_TE_LAND_GENERATE);
1209 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1211 ShowEditorTerraformToolbar();
1212 return CBF_NONE;
1215 static CallBackFunction ToolbarScenGenTownClick(Window *w)
1217 PopupMainToolbarMenu(w, WID_TE_TOWN_GENERATE, {STR_SCENEDIT_TOWN_MENU_BUILD_TOWN, STR_SCENEDIT_TOWN_MENU_PACE_HOUSE});
1218 return CBF_NONE;
1221 static CallBackFunction ToolbarScenGenTown(int index)
1223 switch (index) {
1224 case 0: ShowFoundTownWindow(); break;
1225 case 1: ShowBuildHousePicker(nullptr); break;
1227 return CBF_NONE;
1230 static CallBackFunction ToolbarScenGenIndustry(Window *w)
1232 w->HandleButtonClick(WID_TE_INDUSTRY);
1233 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1234 ShowBuildIndustryWindow();
1235 return CBF_NONE;
1238 static CallBackFunction ToolbarScenBuildRoadClick(Window *w)
1240 ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TE_ROADS, 140, true);
1241 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1242 return CBF_NONE;
1246 * Handle click on the entry in the Build Road menu.
1248 * @param index RoadType to show the build toolbar for.
1249 * @return #CBF_NONE
1251 static CallBackFunction ToolbarScenBuildRoad(int index)
1253 _last_built_roadtype = (RoadType)index;
1254 ShowBuildRoadScenToolbar(_last_built_roadtype);
1255 return CBF_NONE;
1258 static CallBackFunction ToolbarScenBuildTramClick(Window *w)
1260 ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TE_TRAMS, 140, true);
1261 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1262 return CBF_NONE;
1266 * Handle click on the entry in the Build Tram menu.
1268 * @param index RoadType to show the build toolbar for.
1269 * @return #CBF_NONE
1271 static CallBackFunction ToolbarScenBuildTram(int index)
1273 _last_built_tramtype = (RoadType)index;
1274 ShowBuildRoadScenToolbar(_last_built_tramtype);
1275 return CBF_NONE;
1278 static CallBackFunction ToolbarScenBuildDocks(Window *w)
1280 w->HandleButtonClick(WID_TE_WATER);
1281 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1282 ShowBuildDocksScenToolbar();
1283 return CBF_NONE;
1286 static CallBackFunction ToolbarScenPlantTrees(Window *w)
1288 w->HandleButtonClick(WID_TE_TREES);
1289 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1290 ShowBuildTreesToolbar();
1291 return CBF_NONE;
1294 static CallBackFunction ToolbarScenPlaceSign(Window *w)
1296 w->HandleButtonClick(WID_TE_SIGNS);
1297 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1298 return SelectSignTool();
1301 static CallBackFunction ToolbarBtn_NULL(Window *)
1303 return CBF_NONE;
1306 typedef CallBackFunction MenuClickedProc(int index);
1308 static MenuClickedProc * const _menu_clicked_procs[] = {
1309 nullptr, // 0
1310 nullptr, // 1
1311 MenuClickSettings, // 2
1312 MenuClickSaveLoad, // 3
1313 MenuClickMap, // 4
1314 MenuClickTown, // 5
1315 MenuClickSubsidies, // 6
1316 MenuClickStations, // 7
1317 MenuClickFinances, // 8
1318 MenuClickCompany, // 9
1319 MenuClickStory, // 10
1320 MenuClickGoal, // 11
1321 MenuClickGraphsOrLeague, // 12
1322 MenuClickGraphsOrLeague, // 13
1323 MenuClickIndustry, // 14
1324 MenuClickShowTrains, // 15
1325 MenuClickShowRoad, // 16
1326 MenuClickShowShips, // 17
1327 MenuClickShowAir, // 18
1328 MenuClickMap, // 19
1329 nullptr, // 20
1330 MenuClickBuildRail, // 21
1331 MenuClickBuildRoad, // 22
1332 MenuClickBuildTram, // 23
1333 MenuClickBuildWater, // 24
1334 MenuClickBuildAir, // 25
1335 MenuClickForest, // 26
1336 MenuClickMusicWindow, // 27
1337 MenuClickNewspaper, // 28
1338 MenuClickHelp, // 29
1341 /** Full blown container to make it behave exactly as we want :) */
1342 class NWidgetToolbarContainer : public NWidgetContainer {
1343 protected:
1344 uint spacers; ///< Number of spacer widgets in this toolbar
1346 public:
1347 NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL)
1352 * Check whether the given widget type is a button for us.
1353 * @param type the widget type to check.
1354 * @return true if it is a button for us.
1356 bool IsButton(WidgetType type) const
1358 return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN;
1361 void SetupSmallestSize(Window *w) override
1363 this->smallest_x = 0; // Biggest child
1364 this->smallest_y = 0; // Biggest child
1365 this->fill_x = 1;
1366 this->fill_y = 0;
1367 this->resize_x = 1; // We only resize in this direction
1368 this->resize_y = 0; // We never resize in this direction
1369 this->spacers = 0;
1371 uint nbuttons = 0;
1372 /* First initialise some variables... */
1373 for (const auto &child_wid : this->children) {
1374 child_wid->SetupSmallestSize(w);
1375 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding.Vertical());
1376 if (this->IsButton(child_wid->type)) {
1377 nbuttons++;
1378 this->smallest_x = std::max(this->smallest_x, child_wid->smallest_x + child_wid->padding.Horizontal());
1379 } else if (child_wid->type == NWID_SPACER) {
1380 this->spacers++;
1384 /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */
1385 for (const auto &child_wid : this->children) {
1386 child_wid->current_y = this->smallest_y;
1387 if (!this->IsButton(child_wid->type)) {
1388 child_wid->current_x = child_wid->smallest_x;
1391 _toolbar_width = nbuttons * this->smallest_x;
1394 void AssignSizePosition(SizingType sizing, int x, int y, uint given_width, uint given_height, bool rtl) override
1396 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
1398 this->pos_x = x;
1399 this->pos_y = y;
1400 this->current_x = given_width;
1401 this->current_y = given_height;
1403 /* Figure out what are the visible buttons */
1404 uint arrangable_count, button_count, spacer_count;
1405 const WidgetID *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count);
1407 /* Create us ourselves a quick lookup table from WidgetID to slot. */
1408 std::map<WidgetID, uint> lookup;
1409 for (auto it = std::begin(this->children); it != std::end(this->children); ++it) {
1410 NWidgetBase *nwid = it->get();
1411 nwid->current_x = 0; /* Hide widget, it will be revealed in the next step. */
1412 if (nwid->type == NWID_SPACER) continue;
1413 lookup[dynamic_cast<NWidgetCore *>(nwid)->index] = std::distance(this->children.begin(), it);
1416 /* Now assign the widgets to their rightful place */
1417 uint position = 0; // Place to put next child relative to origin of the container.
1418 uint spacer_space = std::max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets
1419 uint button_space = given_width - spacer_space; // Remaining spacing for the buttons
1420 uint spacer_i = 0;
1421 uint button_i = 0;
1423 /* Index into the arrangement indices. */
1424 const WidgetID *slotp = rtl ? &arrangement[arrangable_count - 1] : arrangement;
1425 for (uint i = 0; i < arrangable_count; i++) {
1426 uint slot = lookup[*slotp];
1427 auto &child_wid = this->children[slot];
1428 /* If we have space to give to the spacers, do that. */
1429 if (spacer_space > 0 && slot > 0 && slot < this->children.size() - 1) {
1430 const auto &possible_spacer = this->children[slot + (rtl ? 1 : -1)];
1431 if (possible_spacer != nullptr && possible_spacer->type == NWID_SPACER) {
1432 uint add = spacer_space / (spacer_count - spacer_i);
1433 position += add;
1434 spacer_space -= add;
1435 spacer_i++;
1439 /* Buttons can be scaled, the others not. */
1440 if (this->IsButton(child_wid->type)) {
1441 child_wid->current_x = button_space / (button_count - button_i);
1442 button_space -= child_wid->current_x;
1443 button_i++;
1444 } else {
1445 child_wid->current_x = child_wid->smallest_x;
1447 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
1448 position += child_wid->current_x;
1450 if (rtl) {
1451 slotp--;
1452 } else {
1453 slotp++;
1458 void Draw(const Window *w) override
1460 /* Draw brown-red toolbar bg. */
1461 const Rect r = this->GetCurrentRect();
1462 GfxFillRect(r, PC_VERY_DARK_RED);
1463 GfxFillRect(r, PC_DARK_RED, FILLRECT_CHECKER);
1465 this->NWidgetContainer::Draw(w);
1469 * Get the arrangement of the buttons for the toolbar.
1470 * @param width the new width of the toolbar.
1471 * @param arrangable_count output of the number of visible items.
1472 * @param button_count output of the number of visible buttons.
1473 * @param spacer_count output of the number of spacers.
1474 * @return the button configuration.
1476 virtual const WidgetID *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0;
1479 /** Container for the 'normal' main toolbar */
1480 class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
1481 const WidgetID *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override
1483 static const uint SMALLEST_ARRANGEMENT = 14;
1484 static const uint BIGGEST_ARRANGEMENT = 20;
1486 /* The number of buttons of each row of the toolbar should match the number of items which we want to be visible.
1487 * The total number of buttons should be equal to arrangable_count * 2.
1488 * No bad things happen, but we could see strange behaviours if we have buttons < (arrangable_count * 2) like a
1489 * pause button appearing on the right of the lower toolbar and weird resizing of the widgets even if there is
1490 * enough space.
1492 static const WidgetID arrange14[] = {
1493 WID_TN_PAUSE,
1494 WID_TN_FAST_FORWARD,
1495 WID_TN_TRAINS,
1496 WID_TN_ROADVEHS,
1497 WID_TN_SHIPS,
1498 WID_TN_AIRCRAFT,
1499 WID_TN_ZOOM_IN,
1500 WID_TN_ZOOM_OUT,
1501 WID_TN_RAILS,
1502 WID_TN_ROADS,
1503 WID_TN_WATER,
1504 WID_TN_AIR,
1505 WID_TN_LANDSCAPE,
1506 WID_TN_SWITCH_BAR,
1507 // lower toolbar
1508 WID_TN_SETTINGS,
1509 WID_TN_SAVE,
1510 WID_TN_SMALL_MAP,
1511 WID_TN_TOWNS,
1512 WID_TN_SUBSIDIES,
1513 WID_TN_STATIONS,
1514 WID_TN_FINANCES,
1515 WID_TN_COMPANIES,
1516 WID_TN_GRAPHS,
1517 WID_TN_INDUSTRIES,
1518 WID_TN_MUSIC_SOUND,
1519 WID_TN_MESSAGES,
1520 WID_TN_HELP,
1521 WID_TN_SWITCH_BAR,
1523 static const WidgetID arrange15[] = {
1524 WID_TN_PAUSE,
1525 WID_TN_FAST_FORWARD,
1526 WID_TN_SMALL_MAP,
1527 WID_TN_TRAINS,
1528 WID_TN_ROADVEHS,
1529 WID_TN_SHIPS,
1530 WID_TN_AIRCRAFT,
1531 WID_TN_RAILS,
1532 WID_TN_ROADS,
1533 WID_TN_WATER,
1534 WID_TN_AIR,
1535 WID_TN_LANDSCAPE,
1536 WID_TN_ZOOM_IN,
1537 WID_TN_ZOOM_OUT,
1538 WID_TN_SWITCH_BAR,
1539 // lower toolbar
1540 WID_TN_PAUSE,
1541 WID_TN_SETTINGS,
1542 WID_TN_SMALL_MAP,
1543 WID_TN_SAVE,
1544 WID_TN_TOWNS,
1545 WID_TN_SUBSIDIES,
1546 WID_TN_STATIONS,
1547 WID_TN_FINANCES,
1548 WID_TN_COMPANIES,
1549 WID_TN_GRAPHS,
1550 WID_TN_INDUSTRIES,
1551 WID_TN_MUSIC_SOUND,
1552 WID_TN_MESSAGES,
1553 WID_TN_HELP,
1554 WID_TN_SWITCH_BAR,
1556 static const WidgetID arrange16[] = {
1557 WID_TN_PAUSE,
1558 WID_TN_FAST_FORWARD,
1559 WID_TN_SETTINGS,
1560 WID_TN_SMALL_MAP,
1561 WID_TN_TRAINS,
1562 WID_TN_ROADVEHS,
1563 WID_TN_SHIPS,
1564 WID_TN_AIRCRAFT,
1565 WID_TN_RAILS,
1566 WID_TN_ROADS,
1567 WID_TN_WATER,
1568 WID_TN_AIR,
1569 WID_TN_LANDSCAPE,
1570 WID_TN_ZOOM_IN,
1571 WID_TN_ZOOM_OUT,
1572 WID_TN_SWITCH_BAR,
1573 // lower toolbar
1574 WID_TN_PAUSE,
1575 WID_TN_FAST_FORWARD,
1576 WID_TN_SAVE,
1577 WID_TN_TOWNS,
1578 WID_TN_SUBSIDIES,
1579 WID_TN_STATIONS,
1580 WID_TN_FINANCES,
1581 WID_TN_COMPANIES,
1582 WID_TN_GRAPHS,
1583 WID_TN_INDUSTRIES,
1584 WID_TN_MUSIC_SOUND,
1585 WID_TN_MESSAGES,
1586 WID_TN_HELP,
1587 WID_TN_ZOOM_IN,
1588 WID_TN_ZOOM_OUT,
1589 WID_TN_SWITCH_BAR,
1591 static const WidgetID arrange17[] = {
1592 WID_TN_PAUSE,
1593 WID_TN_FAST_FORWARD,
1594 WID_TN_SETTINGS,
1595 WID_TN_SMALL_MAP,
1596 WID_TN_SUBSIDIES,
1597 WID_TN_TRAINS,
1598 WID_TN_ROADVEHS,
1599 WID_TN_SHIPS,
1600 WID_TN_AIRCRAFT,
1601 WID_TN_RAILS,
1602 WID_TN_ROADS,
1603 WID_TN_WATER,
1604 WID_TN_AIR,
1605 WID_TN_LANDSCAPE,
1606 WID_TN_ZOOM_IN,
1607 WID_TN_ZOOM_OUT,
1608 WID_TN_SWITCH_BAR,
1609 // lower toolbar
1610 WID_TN_PAUSE,
1611 WID_TN_FAST_FORWARD,
1612 WID_TN_SAVE,
1613 WID_TN_SMALL_MAP,
1614 WID_TN_SUBSIDIES,
1615 WID_TN_TOWNS,
1616 WID_TN_STATIONS,
1617 WID_TN_FINANCES,
1618 WID_TN_COMPANIES,
1619 WID_TN_GRAPHS,
1620 WID_TN_INDUSTRIES,
1621 WID_TN_MUSIC_SOUND,
1622 WID_TN_MESSAGES,
1623 WID_TN_HELP,
1624 WID_TN_ZOOM_IN,
1625 WID_TN_ZOOM_OUT,
1626 WID_TN_SWITCH_BAR,
1628 static const WidgetID arrange18[] = {
1629 WID_TN_PAUSE,
1630 WID_TN_FAST_FORWARD,
1631 WID_TN_SETTINGS,
1632 WID_TN_SMALL_MAP,
1633 WID_TN_TOWNS,
1634 WID_TN_SUBSIDIES,
1635 WID_TN_STATIONS,
1636 WID_TN_FINANCES,
1637 WID_TN_COMPANIES,
1638 WID_TN_INDUSTRIES,
1639 WID_TN_RAILS,
1640 WID_TN_ROADS,
1641 WID_TN_WATER,
1642 WID_TN_AIR,
1643 WID_TN_LANDSCAPE,
1644 WID_TN_ZOOM_IN,
1645 WID_TN_ZOOM_OUT,
1646 WID_TN_SWITCH_BAR,
1647 // lower toolbar
1648 WID_TN_PAUSE,
1649 WID_TN_FAST_FORWARD,
1650 WID_TN_SAVE,
1651 WID_TN_SMALL_MAP,
1652 WID_TN_TOWNS,
1653 WID_TN_SUBSIDIES,
1654 WID_TN_STATIONS,
1655 WID_TN_GRAPHS,
1656 WID_TN_TRAINS,
1657 WID_TN_ROADVEHS,
1658 WID_TN_SHIPS,
1659 WID_TN_AIRCRAFT,
1660 WID_TN_MUSIC_SOUND,
1661 WID_TN_MESSAGES,
1662 WID_TN_HELP,
1663 WID_TN_ZOOM_IN,
1664 WID_TN_ZOOM_OUT,
1665 WID_TN_SWITCH_BAR,
1667 static const WidgetID arrange19[] = {
1668 WID_TN_PAUSE,
1669 WID_TN_FAST_FORWARD,
1670 WID_TN_SETTINGS,
1671 WID_TN_SMALL_MAP,
1672 WID_TN_TOWNS,
1673 WID_TN_SUBSIDIES,
1674 WID_TN_TRAINS,
1675 WID_TN_ROADVEHS,
1676 WID_TN_SHIPS,
1677 WID_TN_AIRCRAFT,
1678 WID_TN_RAILS,
1679 WID_TN_ROADS,
1680 WID_TN_WATER,
1681 WID_TN_AIR,
1682 WID_TN_LANDSCAPE,
1683 WID_TN_MUSIC_SOUND,
1684 WID_TN_ZOOM_IN,
1685 WID_TN_ZOOM_OUT,
1686 WID_TN_SWITCH_BAR,
1687 // lower toolbar
1688 WID_TN_PAUSE,
1689 WID_TN_FAST_FORWARD,
1690 WID_TN_SAVE,
1691 WID_TN_SMALL_MAP,
1692 WID_TN_STATIONS,
1693 WID_TN_FINANCES,
1694 WID_TN_COMPANIES,
1695 WID_TN_GRAPHS,
1696 WID_TN_INDUSTRIES,
1697 WID_TN_MESSAGES,
1698 WID_TN_RAILS,
1699 WID_TN_ROADS,
1700 WID_TN_WATER,
1701 WID_TN_AIR,
1702 WID_TN_LANDSCAPE,
1703 WID_TN_HELP,
1704 WID_TN_ZOOM_IN,
1705 WID_TN_ZOOM_OUT,
1706 WID_TN_SWITCH_BAR,
1708 static const WidgetID arrange20[] = {
1709 WID_TN_PAUSE,
1710 WID_TN_FAST_FORWARD,
1711 WID_TN_SETTINGS,
1712 WID_TN_SMALL_MAP,
1713 WID_TN_TOWNS,
1714 WID_TN_SUBSIDIES,
1715 WID_TN_TRAINS,
1716 WID_TN_ROADVEHS,
1717 WID_TN_SHIPS,
1718 WID_TN_AIRCRAFT,
1719 WID_TN_RAILS,
1720 WID_TN_ROADS,
1721 WID_TN_WATER,
1722 WID_TN_AIR,
1723 WID_TN_LANDSCAPE,
1724 WID_TN_MUSIC_SOUND,
1725 WID_TN_GOAL,
1726 WID_TN_ZOOM_IN,
1727 WID_TN_ZOOM_OUT,
1728 WID_TN_SWITCH_BAR,
1729 // lower toolbar
1730 WID_TN_PAUSE,
1731 WID_TN_FAST_FORWARD,
1732 WID_TN_SAVE,
1733 WID_TN_SMALL_MAP,
1734 WID_TN_STATIONS,
1735 WID_TN_FINANCES,
1736 WID_TN_COMPANIES,
1737 WID_TN_GRAPHS,
1738 WID_TN_INDUSTRIES,
1739 WID_TN_MESSAGES,
1740 WID_TN_RAILS,
1741 WID_TN_ROADS,
1742 WID_TN_WATER,
1743 WID_TN_AIR,
1744 WID_TN_LANDSCAPE,
1745 WID_TN_STORY,
1746 WID_TN_HELP,
1747 WID_TN_ZOOM_IN,
1748 WID_TN_ZOOM_OUT,
1749 WID_TN_SWITCH_BAR,
1751 static const WidgetID arrange_all[] = {
1752 WID_TN_PAUSE,
1753 WID_TN_FAST_FORWARD,
1754 WID_TN_SETTINGS,
1755 WID_TN_SAVE,
1756 WID_TN_SMALL_MAP,
1757 WID_TN_TOWNS,
1758 WID_TN_SUBSIDIES,
1759 WID_TN_STATIONS,
1760 WID_TN_FINANCES,
1761 WID_TN_COMPANIES,
1762 WID_TN_STORY,
1763 WID_TN_GOAL,
1764 WID_TN_GRAPHS,
1765 WID_TN_LEAGUE,
1766 WID_TN_INDUSTRIES,
1767 WID_TN_TRAINS,
1768 WID_TN_ROADVEHS,
1769 WID_TN_SHIPS,
1770 WID_TN_AIRCRAFT,
1771 WID_TN_ZOOM_IN,
1772 WID_TN_ZOOM_OUT,
1773 WID_TN_RAILS,
1774 WID_TN_ROADS,
1775 WID_TN_TRAMS,
1776 WID_TN_WATER,
1777 WID_TN_AIR,
1778 WID_TN_LANDSCAPE,
1779 WID_TN_MUSIC_SOUND,
1780 WID_TN_MESSAGES,
1781 WID_TN_HELP
1784 /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
1785 uint full_buttons = std::max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
1786 if (full_buttons > BIGGEST_ARRANGEMENT) {
1787 button_count = arrangable_count = lengthof(arrange_all);
1788 spacer_count = this->spacers;
1789 return arrange_all;
1792 /* Introduce the split toolbar */
1793 static const WidgetID * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
1795 button_count = arrangable_count = full_buttons;
1796 spacer_count = this->spacers;
1797 return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
1801 /** Container for the scenario editor's toolbar */
1802 class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer {
1803 uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel)
1805 void SetupSmallestSize(Window *w) override
1807 this->NWidgetToolbarContainer::SetupSmallestSize(w);
1809 /* Find the size of panel_widths */
1810 uint i = 0;
1811 for (const auto &child_wid : this->children) {
1812 if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
1814 assert(i < lengthof(this->panel_widths));
1815 this->panel_widths[i++] = child_wid->current_x;
1816 _toolbar_width += child_wid->current_x;
1820 const WidgetID *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override
1822 static const WidgetID arrange_all[] = {
1823 WID_TE_PAUSE,
1824 WID_TE_FAST_FORWARD,
1825 WID_TE_SETTINGS,
1826 WID_TE_SAVE,
1827 WID_TE_SPACER,
1828 WID_TE_DATE_PANEL,
1829 WID_TE_SMALL_MAP,
1830 WID_TE_ZOOM_IN,
1831 WID_TE_ZOOM_OUT,
1832 WID_TE_LAND_GENERATE,
1833 WID_TE_TOWN_GENERATE,
1834 WID_TE_INDUSTRY,
1835 WID_TE_ROADS,
1836 WID_TE_TRAMS,
1837 WID_TE_WATER,
1838 WID_TE_TREES,
1839 WID_TE_SIGNS,
1840 WID_TE_MUSIC_SOUND,
1841 WID_TE_HELP,
1843 static const WidgetID arrange_nopanel[] = {
1844 WID_TE_PAUSE,
1845 WID_TE_FAST_FORWARD,
1846 WID_TE_SETTINGS,
1847 WID_TE_SAVE,
1848 WID_TE_DATE_PANEL,
1849 WID_TE_SMALL_MAP,
1850 WID_TE_ZOOM_IN,
1851 WID_TE_ZOOM_OUT,
1852 WID_TE_LAND_GENERATE,
1853 WID_TE_TOWN_GENERATE,
1854 WID_TE_INDUSTRY,
1855 WID_TE_ROADS,
1856 WID_TE_TRAMS,
1857 WID_TE_WATER,
1858 WID_TE_TREES,
1859 WID_TE_SIGNS,
1860 WID_TE_MUSIC_SOUND,
1861 WID_TE_HELP,
1863 static const WidgetID arrange_switch[] = {
1864 WID_TE_DATE_PANEL,
1865 WID_TE_SMALL_MAP,
1866 WID_TE_LAND_GENERATE,
1867 WID_TE_TOWN_GENERATE,
1868 WID_TE_INDUSTRY,
1869 WID_TE_ROADS,
1870 WID_TE_TRAMS,
1871 WID_TE_WATER,
1872 WID_TE_TREES,
1873 WID_TE_SIGNS,
1874 WID_TE_SWITCH_BAR,
1875 // lower toolbar
1876 WID_TE_PAUSE,
1877 WID_TE_FAST_FORWARD,
1878 WID_TE_SETTINGS,
1879 WID_TE_SAVE,
1880 WID_TE_DATE_PANEL,
1881 WID_TE_SMALL_MAP,
1882 WID_TE_ZOOM_IN,
1883 WID_TE_ZOOM_OUT,
1884 WID_TE_MUSIC_SOUND,
1885 WID_TE_HELP,
1886 WID_TE_SWITCH_BAR,
1889 /* If we can place all buttons *and* the panels, show them. */
1890 uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
1891 if (width >= min_full_width) {
1892 width -= this->panel_widths[0] + this->panel_widths[1];
1893 arrangable_count = lengthof(arrange_all);
1894 button_count = arrangable_count - 2;
1895 spacer_count = this->spacers;
1896 return arrange_all;
1899 /* 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 */
1900 uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
1901 if (width > min_small_width) {
1902 width -= this->panel_widths[1];
1903 arrangable_count = lengthof(arrange_nopanel);
1904 button_count = arrangable_count - 1;
1905 spacer_count = this->spacers - 1;
1906 return arrange_nopanel;
1909 /* Split toolbar */
1910 width -= this->panel_widths[1];
1911 arrangable_count = lengthof(arrange_switch) / 2;
1912 button_count = arrangable_count - 1;
1913 spacer_count = 0;
1914 return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
1918 /* --- Toolbar handling for the 'normal' case */
1920 typedef CallBackFunction ToolbarButtonProc(Window *w);
1922 static ToolbarButtonProc * const _toolbar_button_procs[] = {
1923 ToolbarPauseClick,
1924 ToolbarFastForwardClick,
1925 ToolbarOptionsClick,
1926 ToolbarSaveClick,
1927 ToolbarMapClick,
1928 ToolbarTownClick,
1929 ToolbarSubsidiesClick,
1930 ToolbarStationsClick,
1931 ToolbarFinancesClick,
1932 ToolbarCompaniesClick,
1933 ToolbarStoryClick,
1934 ToolbarGoalClick,
1935 ToolbarGraphsClick,
1936 ToolbarLeagueClick,
1937 ToolbarIndustryClick,
1938 ToolbarTrainClick,
1939 ToolbarRoadClick,
1940 ToolbarShipClick,
1941 ToolbarAirClick,
1942 ToolbarZoomInClick,
1943 ToolbarZoomOutClick,
1944 ToolbarBuildRailClick,
1945 ToolbarBuildRoadClick,
1946 ToolbarBuildTramClick,
1947 ToolbarBuildWaterClick,
1948 ToolbarBuildAirClick,
1949 ToolbarForestClick,
1950 ToolbarMusicClick,
1951 ToolbarNewspaperClick,
1952 ToolbarHelpClick,
1953 ToolbarSwitchClick,
1956 /** Main toolbar. */
1957 struct MainToolbarWindow : Window {
1958 MainToolbarWindow(WindowDesc &desc) : Window(desc)
1960 this->InitNested(0);
1962 _last_started_action = CBF_NONE;
1963 CLRBITS(this->flags, WF_WHITE_BORDER);
1964 this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
1965 this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
1966 PositionMainToolbar(this);
1967 DoZoomInOutWindow(ZOOM_NONE, this);
1970 void FindWindowPlacementAndResize([[maybe_unused]] int def_width, [[maybe_unused]] int def_height) override
1972 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
1975 void OnPaint() override
1977 /* If spectator, disable all construction buttons
1978 * ie : Build road, rail, ships, airports and landscaping
1979 * Since enabled state is the default, just disable when needed */
1980 this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_TRAMS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE);
1981 /* disable company list drop downs, if there are no companies */
1982 this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFT);
1984 this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0);
1985 this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0);
1987 this->DrawWidgets();
1990 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1992 if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
1995 void OnDropdownSelect(WidgetID widget, int index) override
1997 CallBackFunction cbf = _menu_clicked_procs[widget](index);
1998 if (cbf != CBF_NONE) _last_started_action = cbf;
2001 EventState OnHotkey(int hotkey) override
2003 CallBackFunction cbf = CBF_NONE;
2004 switch (hotkey) {
2005 case MTHK_PAUSE: ToolbarPauseClick(this); break;
2006 case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2007 case MTHK_SETTINGS: ShowGameOptions(); break;
2008 case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
2009 case MTHK_LOADGAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
2010 case MTHK_SMALLMAP: ShowSmallMap(); break;
2011 case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
2012 case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
2013 case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
2014 case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
2015 case MTHK_COMPANIES: ShowCompany(_local_company); break;
2016 case MTHK_STORY: ShowStoryBook(_local_company); break;
2017 case MTHK_GOAL: ShowGoalsList(_local_company); break;
2018 case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
2019 case MTHK_LEAGUE: ShowFirstLeagueTable(); break;
2020 case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
2021 case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
2022 case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
2023 case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
2024 case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
2025 case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2026 case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2027 case MTHK_BUILD_RAIL: ShowBuildRailToolbar(_last_built_railtype); break;
2028 case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
2029 case MTHK_BUILD_TRAM: ShowBuildRoadToolbar(_last_built_tramtype); break;
2030 case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
2031 case MTHK_BUILD_AIRPORT: ShowBuildAirToolbar(); break;
2032 case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
2033 case MTHK_MUSIC: ShowMusicWindow(); break;
2034 case MTHK_SCRIPT_DEBUG: ShowScriptDebugWindow(); break;
2035 case MTHK_SMALL_SCREENSHOT: MakeScreenshotWithConfirm(SC_VIEWPORT); break;
2036 case MTHK_ZOOMEDIN_SCREENSHOT: MakeScreenshotWithConfirm(SC_ZOOMEDIN); break;
2037 case MTHK_DEFAULTZOOM_SCREENSHOT: MakeScreenshotWithConfirm(SC_DEFAULTZOOM); break;
2038 case MTHK_GIANT_SCREENSHOT: MakeScreenshotWithConfirm(SC_WORLD); break;
2039 case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
2040 case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
2041 case MTHK_EXTRA_VIEWPORT: ShowExtraViewportWindowForTileUnderCursor(); break;
2042 case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
2043 case MTHK_SIGN_LIST: ShowSignList(); break;
2044 case MTHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2045 default: return ES_NOT_HANDLED;
2047 if (cbf != CBF_NONE) _last_started_action = cbf;
2048 return ES_HANDLED;
2051 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
2053 switch (_last_started_action) {
2054 case CBF_PLACE_SIGN:
2055 PlaceProc_Sign(tile);
2056 break;
2058 case CBF_PLACE_LANDINFO:
2059 ShowLandInfo(tile);
2060 break;
2062 default: NOT_REACHED();
2066 void OnPlaceObjectAbort() override
2068 _last_started_action = CBF_NONE;
2071 /** Refresh the state of pause / game-speed on a regular interval.*/
2072 IntervalTimer<TimerWindow> refresh_interval = {std::chrono::milliseconds(30), [this](auto) {
2073 if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
2074 this->ToggleWidgetLoweredState(WID_TN_PAUSE);
2075 this->SetWidgetDirty(WID_TN_PAUSE);
2078 if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != (_game_speed != 100)) {
2079 this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD);
2080 this->SetWidgetDirty(WID_TN_FAST_FORWARD);
2084 void OnTimeout() override
2086 /* We do not want to automatically raise the pause, fast forward and
2087 * switchbar buttons; they have to stay down when pressed etc. */
2088 for (WidgetID i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
2089 this->RaiseWidgetWhenLowered(i);
2094 * Some data on this window has become invalid.
2095 * @param data Information about the changed data.
2096 * @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.
2098 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2100 if (!gui_scope) return;
2101 HandleZoomMessage(this, GetMainWindow()->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
2104 static inline HotkeyList hotkeys{"maintoolbar", {
2105 Hotkey({WKC_F1, WKC_PAUSE}, "pause", MTHK_PAUSE),
2106 Hotkey(0, "fastforward", MTHK_FASTFORWARD),
2107 Hotkey(WKC_F2, "settings", MTHK_SETTINGS),
2108 Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME),
2109 Hotkey(0, "load_game", MTHK_LOADGAME),
2110 Hotkey({WKC_F4, 'M'}, "smallmap", MTHK_SMALLMAP),
2111 Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
2112 Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES),
2113 Hotkey(WKC_F7, "station_list", MTHK_STATIONS),
2114 Hotkey(WKC_F8, "finances", MTHK_FINANCES),
2115 Hotkey(WKC_F9, "companies", MTHK_COMPANIES),
2116 Hotkey(0, "story_book", MTHK_STORY),
2117 Hotkey(0, "goal_list", MTHK_GOAL),
2118 Hotkey(WKC_F10, "graphs", MTHK_GRAPHS),
2119 Hotkey(WKC_F11, "league", MTHK_LEAGUE),
2120 Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES),
2121 Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
2122 Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
2123 Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
2124 Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
2125 Hotkey({WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5}, "zoomin", MTHK_ZOOM_IN),
2126 Hotkey({WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6}, "zoomout", MTHK_ZOOM_OUT),
2127 Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
2128 Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
2129 Hotkey(0, "build_tram", MTHK_BUILD_TRAM),
2130 Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
2131 Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
2132 Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
2133 Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
2134 Hotkey(0, "ai_debug", MTHK_SCRIPT_DEBUG),
2135 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
2136 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
2137 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT),
2138 Hotkey(0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
2139 Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
2140 Hotkey('L', "terraform", MTHK_TERRAFORM),
2141 Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
2142 Hotkey(0, "client_list", MTHK_CLIENT_LIST),
2143 Hotkey(0, "sign_list", MTHK_SIGN_LIST),
2144 Hotkey(0, "land_info", MTHK_LANDINFO),
2148 static std::unique_ptr<NWidgetBase> MakeMainToolbar()
2150 /** Sprites to use for the different toolbar buttons */
2151 static const SpriteID toolbar_button_sprites[] = {
2152 SPR_IMG_PAUSE, // WID_TN_PAUSE
2153 SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD
2154 SPR_IMG_SETTINGS, // WID_TN_SETTINGS
2155 SPR_IMG_SAVE, // WID_TN_SAVE
2156 SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP
2157 SPR_IMG_TOWN, // WID_TN_TOWNS
2158 SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES
2159 SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS
2160 SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
2161 SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
2162 SPR_IMG_STORY_BOOK, // WID_TN_STORY
2163 SPR_IMG_GOAL, // WID_TN_GOAL
2164 SPR_IMG_GRAPHS, // WID_TN_GRAPHS
2165 SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE
2166 SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES
2167 SPR_IMG_TRAINLIST, // WID_TN_TRAINS
2168 SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS
2169 SPR_IMG_SHIPLIST, // WID_TN_SHIPS
2170 SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT
2171 SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN
2172 SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT
2173 SPR_IMG_BUILDRAIL, // WID_TN_RAILS
2174 SPR_IMG_BUILDROAD, // WID_TN_ROADS
2175 SPR_IMG_BUILDTRAMS, // WID_TN_TRAMS
2176 SPR_IMG_BUILDWATER, // WID_TN_WATER
2177 SPR_IMG_BUILDAIR, // WID_TN_AIR
2178 SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
2179 SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
2180 SPR_IMG_MESSAGES, // WID_TN_MESSAGES
2181 SPR_IMG_QUERY, // WID_TN_HELP
2182 SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
2185 auto hor = std::make_unique<NWidgetMainToolbarContainer>();
2186 for (WidgetID i = 0; i < WID_TN_END; i++) {
2187 switch (i) {
2188 case WID_TN_SMALL_MAP:
2189 case WID_TN_FINANCES:
2190 case WID_TN_VEHICLE_START:
2191 case WID_TN_ZOOM_IN:
2192 case WID_TN_BUILDING_TOOLS_START:
2193 case WID_TN_MUSIC_SOUND:
2194 hor->Add(std::make_unique<NWidgetSpacer>(0, 0));
2195 break;
2197 auto leaf = std::make_unique<NWidgetLeaf>(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i);
2198 leaf->SetMinimalSize(20, 20);
2199 hor->Add(std::move(leaf));
2202 return hor;
2205 static constexpr NWidgetPart _nested_toolbar_normal_widgets[] = {
2206 NWidgetFunction(MakeMainToolbar),
2209 static WindowDesc _toolb_normal_desc(
2210 WDP_MANUAL, nullptr, 0, 0,
2211 WC_MAIN_TOOLBAR, WC_NONE,
2212 WDF_NO_FOCUS | WDF_NO_CLOSE,
2213 _nested_toolbar_normal_widgets,
2214 &MainToolbarWindow::hotkeys
2218 /* --- Toolbar handling for the scenario editor */
2220 static MenuClickedProc * const _scen_toolbar_dropdown_procs[] = {
2221 nullptr, // 0
2222 nullptr, // 1
2223 MenuClickSettings, // 2
2224 MenuClickSaveLoad, // 3
2225 nullptr, // 4
2226 nullptr, // 5
2227 nullptr, // 6
2228 nullptr, // 7
2229 MenuClickMap, // 8
2230 nullptr, // 9
2231 nullptr, // 10
2232 nullptr, // 11
2233 ToolbarScenGenTown, // 12
2234 nullptr, // 13
2235 ToolbarScenBuildRoad, // 14
2236 ToolbarScenBuildTram, // 15
2237 nullptr, // 16
2238 nullptr, // 17
2239 nullptr, // 18
2240 nullptr, // 19
2241 MenuClickMusicWindow, // 20
2242 MenuClickHelp, // 21
2243 nullptr, // 22
2246 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
2247 ToolbarPauseClick,
2248 ToolbarFastForwardClick,
2249 ToolbarOptionsClick,
2250 ToolbarScenSaveOrLoad,
2251 ToolbarBtn_NULL,
2252 ToolbarScenDatePanel,
2253 ToolbarScenDateBackward,
2254 ToolbarScenDateForward,
2255 ToolbarScenMapTownDir,
2256 ToolbarZoomInClick,
2257 ToolbarZoomOutClick,
2258 ToolbarScenGenLand,
2259 ToolbarScenGenTownClick,
2260 ToolbarScenGenIndustry,
2261 ToolbarScenBuildRoadClick,
2262 ToolbarScenBuildTramClick,
2263 ToolbarScenBuildDocks,
2264 ToolbarScenPlantTrees,
2265 ToolbarScenPlaceSign,
2266 ToolbarBtn_NULL,
2267 ToolbarMusicClick,
2268 ToolbarHelpClick,
2269 ToolbarSwitchClick,
2272 enum MainToolbarEditorHotkeys {
2273 MTEHK_PAUSE,
2274 MTEHK_FASTFORWARD,
2275 MTEHK_SETTINGS,
2276 MTEHK_SAVEGAME,
2277 MTEHK_GENLAND,
2278 MTEHK_GENTOWN,
2279 MTEHK_GENINDUSTRY,
2280 MTEHK_BUILD_ROAD,
2281 MTEHK_BUILD_TRAM,
2282 MTEHK_BUILD_DOCKS,
2283 MTEHK_BUILD_TREES,
2284 MTEHK_SIGN,
2285 MTEHK_MUSIC,
2286 MTEHK_LANDINFO,
2287 MTEHK_SMALL_SCREENSHOT,
2288 MTEHK_ZOOMEDIN_SCREENSHOT,
2289 MTEHK_DEFAULTZOOM_SCREENSHOT,
2290 MTEHK_GIANT_SCREENSHOT,
2291 MTEHK_ZOOM_IN,
2292 MTEHK_ZOOM_OUT,
2293 MTEHK_TERRAFORM,
2294 MTEHK_SMALLMAP,
2295 MTEHK_EXTRA_VIEWPORT,
2298 struct ScenarioEditorToolbarWindow : Window {
2299 ScenarioEditorToolbarWindow(WindowDesc &desc) : Window(desc)
2301 this->InitNested(0);
2303 _last_started_action = CBF_NONE;
2304 CLRBITS(this->flags, WF_WHITE_BORDER);
2305 PositionMainToolbar(this);
2306 DoZoomInOutWindow(ZOOM_NONE, this);
2309 void FindWindowPlacementAndResize([[maybe_unused]] int def_width, [[maybe_unused]] int def_height) override
2311 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
2314 void OnPaint() override
2316 this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= CalendarTime::MIN_YEAR);
2317 this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= CalendarTime::MAX_YEAR);
2318 this->SetWidgetDisabledState(WID_TE_ROADS, (GetRoadTypes(true) & ~_roadtypes_type) == ROADTYPES_NONE);
2319 this->SetWidgetDisabledState(WID_TE_TRAMS, (GetRoadTypes(true) & _roadtypes_type) == ROADTYPES_NONE);
2321 this->DrawWidgets();
2324 void SetStringParameters(WidgetID widget) const override
2326 switch (widget) {
2327 case WID_TE_DATE:
2328 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
2329 break;
2333 void DrawWidget(const Rect &r, WidgetID widget) const override
2335 switch (widget) {
2336 case WID_TE_SPACER: {
2337 int height = r.Height();
2338 if (height > 2 * GetCharacterHeight(FS_NORMAL)) {
2339 DrawString(r.left, r.right, height / 2 - GetCharacterHeight(FS_NORMAL), STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
2340 DrawString(r.left, r.right, height / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2341 } else {
2342 DrawString(r.left, r.right, (height - GetCharacterHeight(FS_NORMAL)) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2344 break;
2349 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2351 switch (widget) {
2352 case WID_TE_SPACER:
2353 size.width = std::max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + padding.width;
2354 break;
2356 case WID_TE_DATE:
2357 SetDParam(0, TimerGameCalendar::ConvertYMDToDate(CalendarTime::MAX_YEAR, 0, 1));
2358 size = GetStringBoundingBox(STR_JUST_DATE_LONG);
2359 break;
2363 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2365 if (_game_mode == GM_MENU) return;
2366 CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
2367 if (cbf != CBF_NONE) _last_started_action = cbf;
2370 void OnDropdownSelect(WidgetID widget, int index) override
2372 CallBackFunction cbf = _scen_toolbar_dropdown_procs[widget](index);
2373 if (cbf != CBF_NONE) _last_started_action = cbf;
2374 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
2377 EventState OnHotkey(int hotkey) override
2379 CallBackFunction cbf = CBF_NONE;
2380 switch (hotkey) {
2381 case MTEHK_PAUSE: ToolbarPauseClick(this); break;
2382 case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2383 case MTEHK_SETTINGS: ShowGameOptions(); break;
2384 case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
2385 case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
2386 case MTEHK_GENTOWN: ToolbarScenGenTownClick(this); break;
2387 case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
2388 case MTEHK_BUILD_ROAD: ToolbarScenBuildRoadClick(this); break;
2389 case MTEHK_BUILD_TRAM: ToolbarScenBuildTramClick(this); break;
2390 case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break;
2391 case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break;
2392 case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break;
2393 case MTEHK_MUSIC: ShowMusicWindow(); break;
2394 case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2395 case MTEHK_SMALL_SCREENSHOT: MakeScreenshotWithConfirm(SC_VIEWPORT); break;
2396 case MTEHK_ZOOMEDIN_SCREENSHOT: MakeScreenshotWithConfirm(SC_ZOOMEDIN); break;
2397 case MTEHK_DEFAULTZOOM_SCREENSHOT: MakeScreenshotWithConfirm(SC_DEFAULTZOOM); break;
2398 case MTEHK_GIANT_SCREENSHOT: MakeScreenshotWithConfirm(SC_WORLD); break;
2399 case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2400 case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2401 case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break;
2402 case MTEHK_SMALLMAP: ShowSmallMap(); break;
2403 case MTEHK_EXTRA_VIEWPORT: ShowExtraViewportWindowForTileUnderCursor(); break;
2404 default: return ES_NOT_HANDLED;
2406 if (cbf != CBF_NONE) _last_started_action = cbf;
2407 return ES_HANDLED;
2410 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
2412 switch (_last_started_action) {
2413 case CBF_PLACE_SIGN:
2414 PlaceProc_Sign(tile);
2415 break;
2417 case CBF_PLACE_LANDINFO:
2418 ShowLandInfo(tile);
2419 break;
2421 default: NOT_REACHED();
2425 void OnPlaceObjectAbort() override
2427 _last_started_action = CBF_NONE;
2430 void OnTimeout() override
2432 this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD);
2433 this->SetWidgetDirty(WID_TE_DATE_BACKWARD);
2434 this->SetWidgetDirty(WID_TE_DATE_FORWARD);
2437 /** Refresh the state of pause / game-speed on a regular interval.*/
2438 IntervalTimer<TimerWindow> refresh_interval = {std::chrono::milliseconds(30), [this](auto) {
2439 if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
2440 this->ToggleWidgetLoweredState(WID_TE_PAUSE);
2441 this->SetDirty();
2444 if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != (_game_speed != 100)) {
2445 this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD);
2446 this->SetDirty();
2451 * Some data on this window has become invalid.
2452 * @param data Information about the changed data.
2453 * @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.
2455 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2457 if (!gui_scope) return;
2458 HandleZoomMessage(this, GetMainWindow()->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
2461 void OnQueryTextFinished(std::optional<std::string> str) override
2463 /* Was 'cancel' pressed? */
2464 if (!str.has_value()) return;
2466 TimerGameCalendar::Year value;
2467 if (!str->empty()) {
2468 value = atoi(str->c_str());
2469 } else {
2470 /* An empty string means revert to the default */
2471 value = CalendarTime::DEF_START_YEAR.base();
2473 SetStartingYear(value);
2475 this->SetDirty();
2478 static inline HotkeyList hotkeys{"scenedit_maintoolbar", {
2479 Hotkey({WKC_F1, WKC_PAUSE}, "pause", MTEHK_PAUSE),
2480 Hotkey(0, "fastforward", MTEHK_FASTFORWARD),
2481 Hotkey(WKC_F2, "settings", MTEHK_SETTINGS),
2482 Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME),
2483 Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND),
2484 Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN),
2485 Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
2486 Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
2487 Hotkey(0, "build_tram", MTEHK_BUILD_TRAM),
2488 Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
2489 Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
2490 Hotkey(WKC_F10, "build_sign", MTEHK_SIGN),
2491 Hotkey(WKC_F11, "music", MTEHK_MUSIC),
2492 Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO),
2493 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
2494 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
2495 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT),
2496 Hotkey(0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
2497 Hotkey({WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5}, "zoomin", MTEHK_ZOOM_IN),
2498 Hotkey({WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6}, "zoomout", MTEHK_ZOOM_OUT),
2499 Hotkey('L', "terraform", MTEHK_TERRAFORM),
2500 Hotkey('M', "smallmap", MTEHK_SMALLMAP),
2501 Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
2505 static constexpr NWidgetPart _nested_toolb_scen_inner_widgets[] = {
2506 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
2507 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
2508 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
2509 NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
2510 NWidget(NWID_SPACER),
2511 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
2512 NWidget(NWID_SPACER),
2513 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
2514 NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2), SetPadding(1),
2515 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),
2516 NWidget(WWT_TEXT, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_JUST_DATE_LONG, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE), SetTextStyle(TC_WHITE), SetAlignment(SA_CENTER), SetFill(0, 1),
2517 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),
2518 EndContainer(),
2519 EndContainer(),
2520 NWidget(NWID_SPACER),
2521 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
2522 NWidget(NWID_SPACER),
2523 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
2524 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
2525 NWidget(NWID_SPACER),
2526 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
2527 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
2528 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
2529 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
2530 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_TRAMS), SetDataTip(SPR_IMG_BUILDTRAMS, STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION),
2531 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
2532 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
2533 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
2534 NWidget(NWID_SPACER),
2535 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
2536 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
2537 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
2540 static std::unique_ptr<NWidgetBase> MakeScenarioToolbar()
2542 return MakeNWidgets(_nested_toolb_scen_inner_widgets, std::make_unique<NWidgetScenarioToolbarContainer>());
2545 static constexpr NWidgetPart _nested_toolb_scen_widgets[] = {
2546 NWidgetFunction(MakeScenarioToolbar),
2549 static WindowDesc _toolb_scen_desc(
2550 WDP_MANUAL, nullptr, 0, 0,
2551 WC_MAIN_TOOLBAR, WC_NONE,
2552 WDF_NO_FOCUS | WDF_NO_CLOSE,
2553 _nested_toolb_scen_widgets,
2554 &ScenarioEditorToolbarWindow::hotkeys
2557 /** Allocate the toolbar. */
2558 void AllocateToolbar()
2560 /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
2561 _last_built_roadtype = ROADTYPE_ROAD;
2562 _last_built_tramtype = ROADTYPE_TRAM;
2564 if (_game_mode == GM_EDITOR) {
2565 new ScenarioEditorToolbarWindow(_toolb_scen_desc);
2566 } else {
2567 new MainToolbarWindow(_toolb_normal_desc);