Fix #8316: Make sort industries by production and transported with a cargo filter...
[openttd-github.git] / src / toolbar_gui.cpp
blob4cbd13dbf72701389f8c0a14458fc0ca71c6bc48
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"
53 #include "widgets/toolbar_widget.h"
55 #include "network/network.h"
56 #include "network/network_gui.h"
57 #include "network/network_func.h"
59 #include "safeguards.h"
62 /** Width of the toolbar, shared by statusbar. */
63 uint _toolbar_width = 0;
65 RailType _last_built_railtype;
66 RoadType _last_built_roadtype;
67 RoadType _last_built_tramtype;
69 /** Toobar modes */
70 enum ToolbarMode {
71 TB_NORMAL,
72 TB_UPPER,
73 TB_LOWER
76 /** Callback functions. */
77 enum CallBackFunction {
78 CBF_NONE,
79 CBF_PLACE_SIGN,
80 CBF_PLACE_LANDINFO,
83 static CallBackFunction _last_started_action = CBF_NONE; ///< Last started user action.
86 /**
87 * Drop down list entry for showing a checked/unchecked toggle item.
89 class DropDownListCheckedItem : public DropDownListStringItem {
90 uint checkmark_width;
91 public:
92 bool checked;
94 DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked)
96 this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
99 uint Width() const
101 return DropDownListStringItem::Width() + this->checkmark_width;
104 void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const
106 bool rtl = _current_text_dir == TD_RTL;
107 if (this->checked) {
108 DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK);
110 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);
115 * Drop down list entry for showing a company entry, with companies 'blob'.
117 class DropDownListCompanyItem : public DropDownListItem {
118 Dimension icon_size;
119 Dimension lock_size;
120 public:
121 bool greyed;
123 DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
125 this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
126 this->lock_size = GetSpriteSize(SPR_LOCK);
129 bool Selectable() const override
131 return true;
134 uint Width() const override
136 CompanyID company = (CompanyID)this->result;
137 SetDParam(0, company);
138 SetDParam(1, company);
139 return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + this->lock_size.width + 6;
142 uint Height(uint width) const override
144 return std::max(std::max(this->icon_size.height, this->lock_size.height) + 2U, (uint)FONT_HEIGHT_NORMAL);
147 void Draw(int left, int right, int top, int bottom, bool sel, Colours bg_colour) const override
149 CompanyID company = (CompanyID)this->result;
150 bool rtl = _current_text_dir == TD_RTL;
152 /* It's possible the company is deleted while the dropdown is open */
153 if (!Company::IsValidID(company)) return;
155 int icon_offset = (bottom - top - icon_size.height) / 2;
156 int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2;
157 int lock_offset = (bottom - top - lock_size.height) / 2;
159 DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset);
160 if (NetworkCompanyIsPassworded(company)) {
161 DrawSprite(SPR_LOCK, PAL_NONE, rtl ? left + WD_FRAMERECT_LEFT : right - this->lock_size.width - WD_FRAMERECT_RIGHT, top + lock_offset);
164 SetDParam(0, company);
165 SetDParam(1, company);
166 TextColour col;
167 if (this->greyed) {
168 col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
169 } else {
170 col = sel ? TC_WHITE : TC_BLACK;
172 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);
177 * Pop up a generic text only menu.
178 * @param w Toolbar
179 * @param widget Toolbar button
180 * @param list List of items
181 * @param def Default item
183 static void PopupMainToolbMenu(Window *w, int widget, DropDownList &&list, int def)
185 ShowDropDownList(w, std::move(list), def, widget, 0, true, true);
186 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
190 * Pop up a generic text only menu.
191 * @param w Toolbar
192 * @param widget Toolbar button
193 * @param string String for the first item in the menu
194 * @param count Number of items in the menu
196 static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count)
198 DropDownList list;
199 for (int i = 0; i < count; i++) {
200 list.emplace_back(new DropDownListStringItem(string + i, i, false));
202 PopupMainToolbMenu(w, widget, std::move(list), 0);
205 /** Enum for the Company Toolbar's network related buttons */
206 static const int CTMN_CLIENT_LIST = -1; ///< Show the client list
207 static const int CTMN_SPECTATOR = -2; ///< Show a company window as spectator
210 * Pop up a generic company list menu.
211 * @param w The toolbar window.
212 * @param widget The button widget id.
213 * @param grey A bitbask of which items to mark as disabled.
215 static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0)
217 DropDownList list;
219 switch (widget) {
220 case WID_TN_COMPANIES:
221 if (!_networking) break;
223 /* Add the client list button for the companies menu */
224 list.emplace_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false));
225 break;
227 case WID_TN_STORY:
228 list.emplace_back(new DropDownListStringItem(STR_STORY_BOOK_SPECTATOR, CTMN_SPECTATOR, false));
229 break;
231 case WID_TN_GOAL:
232 list.emplace_back(new DropDownListStringItem(STR_GOALS_SPECTATOR, CTMN_SPECTATOR, false));
233 break;
236 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
237 if (!Company::IsValidID(c)) continue;
238 list.emplace_back(new DropDownListCompanyItem(c, false, HasBit(grey, c)));
241 PopupMainToolbMenu(w, widget, std::move(list), _local_company == COMPANY_SPECTATOR ? (widget == WID_TN_COMPANIES ? CTMN_CLIENT_LIST : CTMN_SPECTATOR) : (int)_local_company);
245 static ToolbarMode _toolbar_mode;
247 static CallBackFunction SelectSignTool()
249 if (_last_started_action == CBF_PLACE_SIGN) {
250 ResetObjectToPlace();
251 return CBF_NONE;
252 } else {
253 SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
254 return CBF_PLACE_SIGN;
258 /* --- Pausing --- */
260 static CallBackFunction ToolbarPauseClick(Window *w)
262 if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
264 if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) {
265 if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
267 return CBF_NONE;
271 * Toggle fast forward mode.
273 * @param w Unused.
274 * @return #CBF_NONE
276 static CallBackFunction ToolbarFastForwardClick(Window *w)
278 ChangeGameSpeed(_game_speed == 100);
280 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
281 return CBF_NONE;
285 * Game Option button menu entries.
287 enum OptionMenuEntries {
288 OME_GAMEOPTIONS,
289 OME_SETTINGS,
290 OME_SCRIPT_SETTINGS,
291 OME_NEWGRFSETTINGS,
292 OME_TRANSPARENCIES,
293 OME_SHOW_TOWNNAMES,
294 OME_SHOW_STATIONNAMES,
295 OME_SHOW_WAYPOINTNAMES,
296 OME_SHOW_SIGNS,
297 OME_SHOW_COMPETITOR_SIGNS,
298 OME_FULL_ANIMATION,
299 OME_FULL_DETAILS,
300 OME_TRANSPARENTBUILDINGS,
301 OME_SHOW_STATIONSIGNS,
305 * Handle click on Options button in toolbar.
307 * @param w parent window the shown Drop down list is attached to.
308 * @return #CBF_NONE
310 static CallBackFunction ToolbarOptionsClick(Window *w)
312 DropDownList list;
313 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false));
314 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false));
315 /* Changes to the per-AI settings don't get send from the server to the clients. Clients get
316 * the settings once they join but never update it. As such don't show the window at all
317 * to network clients. */
318 if (!_networking || _network_server) list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false));
319 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false));
320 list.emplace_back(new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false));
321 list.emplace_back(new DropDownListItem(-1, false));
322 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)));
323 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)));
324 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)));
325 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)));
326 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)));
327 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)));
328 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)));
329 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)));
330 list.emplace_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)));
332 ShowDropDownList(w, std::move(list), 0, WID_TN_SETTINGS, 140, true, true);
333 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
334 return CBF_NONE;
338 * Handle click on one of the entries in the Options button menu.
340 * @param index Index being clicked.
341 * @return #CBF_NONE
343 static CallBackFunction MenuClickSettings(int index)
345 switch (index) {
346 case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE;
347 case OME_SETTINGS: ShowGameSettings(); return CBF_NONE;
348 case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE;
349 case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
350 case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break;
352 case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break;
353 case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break;
354 case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break;
355 case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break;
356 case OME_SHOW_COMPETITOR_SIGNS:
357 ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
358 InvalidateWindowClassesData(WC_SIGN_LIST, -1);
359 break;
360 case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break;
361 case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break;
362 case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break;
363 case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break;
365 MarkWholeScreenDirty();
366 return CBF_NONE;
370 * SaveLoad entries in scenario editor mode.
372 enum SaveLoadEditorMenuEntries {
373 SLEME_SAVE_SCENARIO = 0,
374 SLEME_LOAD_SCENARIO,
375 SLEME_SAVE_HEIGHTMAP,
376 SLEME_LOAD_HEIGHTMAP,
377 SLEME_EXIT_TOINTRO,
378 SLEME_EXIT_GAME = 6,
379 SLEME_MENUCOUNT,
383 * SaveLoad entries in normal game mode.
385 enum SaveLoadNormalMenuEntries {
386 SLNME_SAVE_GAME = 0,
387 SLNME_LOAD_GAME,
388 SLNME_EXIT_TOINTRO,
389 SLNME_EXIT_GAME = 4,
390 SLNME_MENUCOUNT,
394 * Handle click on Save button in toolbar in normal game mode.
396 * @param w parent window the shown save dialogue is attached to.
397 * @return #CBF_NONE
399 static CallBackFunction ToolbarSaveClick(Window *w)
401 PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT);
402 return CBF_NONE;
406 * Handle click on SaveLoad button in toolbar in the scenario editor.
408 * @param w parent window the shown save dialogue is attached to.
409 * @return #CBF_NONE
411 static CallBackFunction ToolbarScenSaveOrLoad(Window *w)
413 PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT);
414 return CBF_NONE;
418 * Handle click on one of the entries in the SaveLoad menu.
420 * @param index Index being clicked.
421 * @return #CBF_NONE
423 static CallBackFunction MenuClickSaveLoad(int index = 0)
425 if (_game_mode == GM_EDITOR) {
426 switch (index) {
427 case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_SAVE); break;
428 case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD); break;
429 case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_SAVE); break;
430 case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_LOAD); break;
431 case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break;
432 case SLEME_EXIT_GAME: HandleExitGameRequest(); break;
434 } else {
435 switch (index) {
436 case SLNME_SAVE_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_SAVE); break;
437 case SLNME_LOAD_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
438 case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break;
439 case SLNME_EXIT_GAME: HandleExitGameRequest(); break;
442 return CBF_NONE;
445 /* --- Map button menu --- */
447 enum MapMenuEntries {
448 MME_SHOW_SMALLMAP = 0,
449 MME_SHOW_EXTRAVIEWPORTS,
450 MME_SHOW_LINKGRAPH,
451 MME_SHOW_SIGNLISTS,
452 MME_SHOW_TOWNDIRECTORY,
453 MME_SHOW_INDUSTRYDIRECTORY,
456 static CallBackFunction ToolbarMapClick(Window *w)
458 DropDownList list;
459 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false));
460 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEWPORT, MME_SHOW_EXTRAVIEWPORTS, false));
461 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false));
462 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false));
463 PopupMainToolbMenu(w, WID_TN_SMALL_MAP, std::move(list), 0);
464 return CBF_NONE;
467 static CallBackFunction ToolbarScenMapTownDir(Window *w)
469 DropDownList list;
470 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false));
471 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEWPORT, MME_SHOW_EXTRAVIEWPORTS, false));
472 list.emplace_back(new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false));
473 list.emplace_back(new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false));
474 list.emplace_back(new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false));
475 PopupMainToolbMenu(w, WID_TE_SMALL_MAP, std::move(list), 0);
476 return CBF_NONE;
480 * Handle click on one of the entries in the Map menu.
482 * @param index Index being clicked.
483 * @return #CBF_NONE
485 static CallBackFunction MenuClickMap(int index)
487 switch (index) {
488 case MME_SHOW_SMALLMAP: ShowSmallMap(); break;
489 case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewportWindow(); break;
490 case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break;
491 case MME_SHOW_SIGNLISTS: ShowSignList(); break;
492 case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
493 case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break;
495 return CBF_NONE;
498 /* --- Town button menu --- */
500 static CallBackFunction ToolbarTownClick(Window *w)
502 PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
503 return CBF_NONE;
507 * Handle click on one of the entries in the Town menu.
509 * @param index Index being clicked.
510 * @return #CBF_NONE
512 static CallBackFunction MenuClickTown(int index)
514 switch (index) {
515 case 0: ShowTownDirectory(); break;
516 case 1: // setting could be changed when the dropdown was open
517 if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
518 break;
520 return CBF_NONE;
523 /* --- Subidies button menu --- */
525 static CallBackFunction ToolbarSubsidiesClick(Window *w)
527 PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1);
528 return CBF_NONE;
532 * Handle click on the entry in the Subsidies menu.
534 * @param index Unused.
535 * @return #CBF_NONE
537 static CallBackFunction MenuClickSubsidies(int index)
539 switch (index) {
540 case 0: ShowSubsidiesList(); break;
542 return CBF_NONE;
545 /* --- Stations button menu --- */
547 static CallBackFunction ToolbarStationsClick(Window *w)
549 PopupMainCompanyToolbMenu(w, WID_TN_STATIONS);
550 return CBF_NONE;
554 * Handle click on the entry in the Stations menu
556 * @param index CompanyID to show station list for
557 * @return #CBF_NONE
559 static CallBackFunction MenuClickStations(int index)
561 ShowCompanyStations((CompanyID)index);
562 return CBF_NONE;
565 /* --- Finances button menu --- */
567 static CallBackFunction ToolbarFinancesClick(Window *w)
569 PopupMainCompanyToolbMenu(w, WID_TN_FINANCES);
570 return CBF_NONE;
574 * Handle click on the entry in the finances overview menu.
576 * @param index CompanyID to show finances for.
577 * @return #CBF_NONE
579 static CallBackFunction MenuClickFinances(int index)
581 ShowCompanyFinances((CompanyID)index);
582 return CBF_NONE;
585 /* --- Company's button menu --- */
587 static CallBackFunction ToolbarCompaniesClick(Window *w)
589 PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0);
590 return CBF_NONE;
594 * Handle click on the entry in the Company menu.
596 * @param index Menu entry to handle.
597 * @return #CBF_NONE
599 static CallBackFunction MenuClickCompany(int index)
601 if (_networking) {
602 switch (index) {
603 case CTMN_CLIENT_LIST:
604 ShowClientList();
605 return CBF_NONE;
608 ShowCompany((CompanyID)index);
609 return CBF_NONE;
612 /* --- Story button menu --- */
614 static CallBackFunction ToolbarStoryClick(Window *w)
616 PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0);
617 return CBF_NONE;
621 * Handle click on the entry in the Story menu
623 * @param index CompanyID to show story book for
624 * @return #CBF_NONE
626 static CallBackFunction MenuClickStory(int index)
628 ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
629 return CBF_NONE;
632 /* --- Goal button menu --- */
634 static CallBackFunction ToolbarGoalClick(Window *w)
636 PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0);
637 return CBF_NONE;
641 * Handle click on the entry in the Goal menu
643 * @param index CompanyID to show story book for
644 * @return #CBF_NONE
646 static CallBackFunction MenuClickGoal(int index)
648 ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
649 return CBF_NONE;
652 /* --- Graphs button menu --- */
654 static CallBackFunction ToolbarGraphsClick(Window *w)
656 PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8);
657 return CBF_NONE;
661 * Handle click on the entry in the Graphs menu.
663 * @param index Graph to show.
664 * @return #CBF_NONE
666 static CallBackFunction MenuClickGraphs(int index)
668 switch (index) {
669 case 0: ShowOperatingProfitGraph(); break;
670 case 1: ShowIncomeGraph(); break;
671 case 2: ShowDeliveredCargoGraph(); break;
672 case 3: ShowPerformanceHistoryGraph(); break;
673 case 4: ShowCompanyValueGraph(); break;
674 case 5: ShowCargoPaymentRates(); break;
675 /* functions for combined graphs/league button */
676 case 6: ShowCompanyLeagueTable(); break;
677 case 7: ShowPerformanceRatingDetail(); break;
679 return CBF_NONE;
682 /* --- League button menu --- */
684 static CallBackFunction ToolbarLeagueClick(Window *w)
686 PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3);
687 return CBF_NONE;
691 * Handle click on the entry in the CompanyLeague menu.
693 * @param index Menu entry number.
694 * @return #CBF_NONE
696 static CallBackFunction MenuClickLeague(int index)
698 switch (index) {
699 case 0: ShowCompanyLeagueTable(); break;
700 case 1: ShowPerformanceRatingDetail(); break;
701 case 2: ShowHighscoreTable(); break;
703 return CBF_NONE;
706 /* --- Industries button menu --- */
708 static CallBackFunction ToolbarIndustryClick(Window *w)
710 /* Disable build-industry menu if we are a spectator */
711 PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3);
712 return CBF_NONE;
716 * Handle click on the entry in the Industry menu.
718 * @param index Menu entry number.
719 * @return #CBF_NONE
721 static CallBackFunction MenuClickIndustry(int index)
723 switch (index) {
724 case 0: ShowIndustryDirectory(); break;
725 case 1: ShowIndustryCargoesWindow(); break;
726 case 2: ShowBuildIndustryWindow(); break;
728 return CBF_NONE;
731 /* --- Trains button menu + 1 helper function for all vehicles. --- */
733 static void ToolbarVehicleClick(Window *w, VehicleType veh)
735 int dis = ~0;
737 for (const Vehicle *v : Vehicle::Iterate()) {
738 if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner);
740 PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis);
744 static CallBackFunction ToolbarTrainClick(Window *w)
746 ToolbarVehicleClick(w, VEH_TRAIN);
747 return CBF_NONE;
751 * Handle click on the entry in the Train menu.
753 * @param index CompanyID to show train list for.
754 * @return #CBF_NONE
756 static CallBackFunction MenuClickShowTrains(int index)
758 ShowVehicleListWindow((CompanyID)index, VEH_TRAIN);
759 return CBF_NONE;
762 /* --- Road vehicle button menu --- */
764 static CallBackFunction ToolbarRoadClick(Window *w)
766 ToolbarVehicleClick(w, VEH_ROAD);
767 return CBF_NONE;
771 * Handle click on the entry in the Road Vehicles menu.
773 * @param index CompanyID to show road vehicles list for.
774 * @return #CBF_NONE
776 static CallBackFunction MenuClickShowRoad(int index)
778 ShowVehicleListWindow((CompanyID)index, VEH_ROAD);
779 return CBF_NONE;
782 /* --- Ship button menu --- */
784 static CallBackFunction ToolbarShipClick(Window *w)
786 ToolbarVehicleClick(w, VEH_SHIP);
787 return CBF_NONE;
791 * Handle click on the entry in the Ships menu.
793 * @param index CompanyID to show ship list for.
794 * @return #CBF_NONE
796 static CallBackFunction MenuClickShowShips(int index)
798 ShowVehicleListWindow((CompanyID)index, VEH_SHIP);
799 return CBF_NONE;
802 /* --- Aircraft button menu --- */
804 static CallBackFunction ToolbarAirClick(Window *w)
806 ToolbarVehicleClick(w, VEH_AIRCRAFT);
807 return CBF_NONE;
811 * Handle click on the entry in the Aircraft menu.
813 * @param index CompanyID to show aircraft list for.
814 * @return #CBF_NONE
816 static CallBackFunction MenuClickShowAir(int index)
818 ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT);
819 return CBF_NONE;
822 /* --- Zoom in button --- */
824 static CallBackFunction ToolbarZoomInClick(Window *w)
826 if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
827 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN);
828 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
830 return CBF_NONE;
833 /* --- Zoom out button --- */
835 static CallBackFunction ToolbarZoomOutClick(Window *w)
837 if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
838 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT);
839 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
841 return CBF_NONE;
844 /* --- Rail button menu --- */
846 static CallBackFunction ToolbarBuildRailClick(Window *w)
848 ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true);
849 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
850 return CBF_NONE;
854 * Handle click on the entry in the Build Rail menu.
856 * @param index RailType to show the build toolbar for.
857 * @return #CBF_NONE
859 static CallBackFunction MenuClickBuildRail(int index)
861 _last_built_railtype = (RailType)index;
862 ShowBuildRailToolbar(_last_built_railtype);
863 return CBF_NONE;
866 /* --- Road button menu --- */
868 static CallBackFunction ToolbarBuildRoadClick(Window *w)
870 ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TN_ROADS, 140, true, true);
871 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
872 return CBF_NONE;
876 * Handle click on the entry in the Build Road menu.
878 * @param index RoadType to show the build toolbar for.
879 * @return #CBF_NONE
881 static CallBackFunction MenuClickBuildRoad(int index)
883 _last_built_roadtype = (RoadType)index;
884 ShowBuildRoadToolbar(_last_built_roadtype);
885 return CBF_NONE;
888 /* --- Tram button menu --- */
890 static CallBackFunction ToolbarBuildTramClick(Window *w)
892 ShowDropDownList(w, GetRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TN_TRAMS, 140, true, true);
893 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
894 return CBF_NONE;
898 * Handle click on the entry in the Build Tram menu.
900 * @param index RoadType to show the build toolbar for.
901 * @return #CBF_NONE
903 static CallBackFunction MenuClickBuildTram(int index)
905 _last_built_tramtype = (RoadType)index;
906 ShowBuildRoadToolbar(_last_built_tramtype);
907 return CBF_NONE;
910 /* --- Water button menu --- */
912 static CallBackFunction ToolbarBuildWaterClick(Window *w)
914 DropDownList list;
915 list.emplace_back(new DropDownListIconItem(SPR_IMG_BUILD_CANAL, PAL_NONE, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 0, false));
916 ShowDropDownList(w, std::move(list), 0, WID_TN_WATER, 140, true, true);
917 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
918 return CBF_NONE;
922 * Handle click on the entry in the Build Waterways menu.
924 * @param index Unused.
925 * @return #CBF_NONE
927 static CallBackFunction MenuClickBuildWater(int index)
929 ShowBuildDocksToolbar();
930 return CBF_NONE;
933 /* --- Airport button menu --- */
935 static CallBackFunction ToolbarBuildAirClick(Window *w)
937 DropDownList list;
938 list.emplace_back(new DropDownListIconItem(SPR_IMG_AIRPORT, PAL_NONE, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 0, false));
939 ShowDropDownList(w, std::move(list), 0, WID_TN_AIR, 140, true, true);
940 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
941 return CBF_NONE;
945 * Handle click on the entry in the Build Air menu.
947 * @param index Unused.
948 * @return #CBF_NONE
950 static CallBackFunction MenuClickBuildAir(int index)
952 ShowBuildAirToolbar();
953 return CBF_NONE;
956 /* --- Forest button menu --- */
958 static CallBackFunction ToolbarForestClick(Window *w)
960 DropDownList list;
961 list.emplace_back(new DropDownListIconItem(SPR_IMG_LANDSCAPING, PAL_NONE, STR_LANDSCAPING_MENU_LANDSCAPING, 0, false));
962 list.emplace_back(new DropDownListIconItem(SPR_IMG_PLANTTREES, PAL_NONE, STR_LANDSCAPING_MENU_PLANT_TREES, 1, false));
963 list.emplace_back(new DropDownListIconItem(SPR_IMG_SIGN, PAL_NONE, STR_LANDSCAPING_MENU_PLACE_SIGN, 2, false));
964 ShowDropDownList(w, std::move(list), 0, WID_TN_LANDSCAPE, 100, true, true);
965 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
966 return CBF_NONE;
970 * Handle click on the entry in the landscaping menu.
972 * @param index Menu entry clicked.
973 * @return #CBF_NONE
975 static CallBackFunction MenuClickForest(int index)
977 switch (index) {
978 case 0: ShowTerraformToolbar(); break;
979 case 1: ShowBuildTreesToolbar(); break;
980 case 2: return SelectSignTool();
982 return CBF_NONE;
985 /* --- Music button menu --- */
987 static CallBackFunction ToolbarMusicClick(Window *w)
989 PopupMainToolbMenu(w, _game_mode == GM_EDITOR ? (int)WID_TE_MUSIC_SOUND : (int)WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1);
990 return CBF_NONE;
994 * Handle click on the entry in the Music menu.
996 * @param index Unused.
997 * @return #CBF_NONE
999 static CallBackFunction MenuClickMusicWindow(int index)
1001 ShowMusicWindow();
1002 return CBF_NONE;
1005 /* --- Newspaper button menu --- */
1007 static CallBackFunction ToolbarNewspaperClick(Window *w)
1009 PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 3);
1010 return CBF_NONE;
1014 * Handle click on the entry in the Newspaper menu.
1016 * @param index Menu entry clicked.
1017 * @return #CBF_NONE
1019 static CallBackFunction MenuClickNewspaper(int index)
1021 switch (index) {
1022 case 0: ShowLastNewsMessage(); break;
1023 case 1: ShowMessageHistory(); break;
1024 case 2: DeleteAllMessages(); break;
1026 return CBF_NONE;
1029 /* --- Help button menu --- */
1031 static CallBackFunction PlaceLandBlockInfo()
1033 if (_last_started_action == CBF_PLACE_LANDINFO) {
1034 ResetObjectToPlace();
1035 return CBF_NONE;
1036 } else {
1037 SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
1038 return CBF_PLACE_LANDINFO;
1042 static CallBackFunction ToolbarHelpClick(Window *w)
1044 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);
1045 return CBF_NONE;
1049 * Toggle drawing of sprites' bounding boxes.
1050 * @note has only an effect when newgrf_developer_tools are active.
1052 * Function is found here and not in viewport.cpp in order to avoid
1053 * importing the settings structs to there.
1055 void ToggleBoundingBoxes()
1057 extern bool _draw_bounding_boxes;
1058 /* Always allow to toggle them off */
1059 if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) {
1060 _draw_bounding_boxes = !_draw_bounding_boxes;
1061 MarkWholeScreenDirty();
1066 * Toggle drawing of the dirty blocks.
1067 * @note has only an effect when newgrf_developer_tools are active.
1069 * Function is found here and not in viewport.cpp in order to avoid
1070 * importing the settings structs to there.
1072 void ToggleDirtyBlocks()
1074 extern bool _draw_dirty_blocks;
1075 /* Always allow to toggle them off */
1076 if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) {
1077 _draw_dirty_blocks = !_draw_dirty_blocks;
1078 MarkWholeScreenDirty();
1083 * Set the starting year for a scenario.
1084 * @param year New starting year.
1086 void SetStartingYear(Year year)
1088 _settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR);
1089 Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
1090 /* If you open a savegame as scenario there may already be link graphs.*/
1091 LinkGraphSchedule::instance.ShiftDates(new_date - _date);
1092 SetDate(new_date, 0);
1096 * Choose the proper callback function for the main toolbar's help menu.
1097 * @param index The menu index which was selected.
1098 * @return CBF_NONE
1100 static CallBackFunction MenuClickHelp(int index)
1102 switch (index) {
1103 case 0: return PlaceLandBlockInfo();
1104 case 2: IConsoleSwitch(); break;
1105 case 3: ShowAIDebugWindow(); break;
1106 case 4: ShowScreenshotWindow(); break;
1107 case 5: ShowFramerateWindow(); break;
1108 case 6: ShowAboutWindow(); break;
1109 case 7: ShowSpriteAlignerWindow(); break;
1110 case 8: ToggleBoundingBoxes(); break;
1111 case 9: ToggleDirtyBlocks(); break;
1113 return CBF_NONE;
1116 /* --- Switch toolbar button --- */
1118 static CallBackFunction ToolbarSwitchClick(Window *w)
1120 if (_toolbar_mode != TB_LOWER) {
1121 _toolbar_mode = TB_LOWER;
1122 } else {
1123 _toolbar_mode = TB_UPPER;
1126 w->ReInit();
1127 w->SetWidgetLoweredState(_game_mode == GM_EDITOR ? (uint)WID_TE_SWITCH_BAR : (uint)WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
1128 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1129 return CBF_NONE;
1132 /* --- Scenario editor specific handlers. */
1135 * Called when clicking at the date panel of the scenario editor toolbar.
1137 static CallBackFunction ToolbarScenDatePanel(Window *w)
1139 SetDParam(0, _settings_game.game_creation.starting_year);
1140 ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
1141 _left_button_clicked = false;
1142 return CBF_NONE;
1145 static CallBackFunction ToolbarScenDateBackward(Window *w)
1147 /* don't allow too fast scrolling */
1148 if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1149 w->HandleButtonClick(WID_TE_DATE_BACKWARD);
1150 w->SetDirty();
1152 SetStartingYear(_settings_game.game_creation.starting_year - 1);
1154 _left_button_clicked = false;
1155 return CBF_NONE;
1158 static CallBackFunction ToolbarScenDateForward(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_FORWARD);
1163 w->SetDirty();
1165 SetStartingYear(_settings_game.game_creation.starting_year + 1);
1167 _left_button_clicked = false;
1168 return CBF_NONE;
1171 static CallBackFunction ToolbarScenGenLand(Window *w)
1173 w->HandleButtonClick(WID_TE_LAND_GENERATE);
1174 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1176 ShowEditorTerraformToolbar();
1177 return CBF_NONE;
1181 static CallBackFunction ToolbarScenGenTown(Window *w)
1183 w->HandleButtonClick(WID_TE_TOWN_GENERATE);
1184 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1185 ShowFoundTownWindow();
1186 return CBF_NONE;
1189 static CallBackFunction ToolbarScenGenIndustry(Window *w)
1191 w->HandleButtonClick(WID_TE_INDUSTRY);
1192 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1193 ShowBuildIndustryWindow();
1194 return CBF_NONE;
1197 static CallBackFunction ToolbarScenBuildRoadClick(Window *w)
1199 ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_ROAD), _last_built_roadtype, WID_TE_ROADS, 140, true, true);
1200 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1201 return CBF_NONE;
1205 * Handle click on the entry in the Build Road menu.
1207 * @param index RoadType to show the build toolbar for.
1208 * @return #CBF_NONE
1210 static CallBackFunction ToolbarScenBuildRoad(int index)
1212 _last_built_roadtype = (RoadType)index;
1213 ShowBuildRoadScenToolbar(_last_built_roadtype);
1214 return CBF_NONE;
1217 static CallBackFunction ToolbarScenBuildTramClick(Window *w)
1219 ShowDropDownList(w, GetScenRoadTypeDropDownList(RTTB_TRAM), _last_built_tramtype, WID_TE_TRAMS, 140, true, true);
1220 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1221 return CBF_NONE;
1225 * Handle click on the entry in the Build Tram menu.
1227 * @param index RoadType to show the build toolbar for.
1228 * @return #CBF_NONE
1230 static CallBackFunction ToolbarScenBuildTram(int index)
1232 _last_built_tramtype = (RoadType)index;
1233 ShowBuildRoadScenToolbar(_last_built_tramtype);
1234 return CBF_NONE;
1237 static CallBackFunction ToolbarScenBuildDocks(Window *w)
1239 w->HandleButtonClick(WID_TE_WATER);
1240 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1241 ShowBuildDocksScenToolbar();
1242 return CBF_NONE;
1245 static CallBackFunction ToolbarScenPlantTrees(Window *w)
1247 w->HandleButtonClick(WID_TE_TREES);
1248 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1249 ShowBuildTreesToolbar();
1250 return CBF_NONE;
1253 static CallBackFunction ToolbarScenPlaceSign(Window *w)
1255 w->HandleButtonClick(WID_TE_SIGNS);
1256 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1257 return SelectSignTool();
1260 static CallBackFunction ToolbarBtn_NULL(Window *w)
1262 return CBF_NONE;
1265 typedef CallBackFunction MenuClickedProc(int index);
1267 static MenuClickedProc * const _menu_clicked_procs[] = {
1268 nullptr, // 0
1269 nullptr, // 1
1270 MenuClickSettings, // 2
1271 MenuClickSaveLoad, // 3
1272 MenuClickMap, // 4
1273 MenuClickTown, // 5
1274 MenuClickSubsidies, // 6
1275 MenuClickStations, // 7
1276 MenuClickFinances, // 8
1277 MenuClickCompany, // 9
1278 MenuClickStory, // 10
1279 MenuClickGoal, // 11
1280 MenuClickGraphs, // 12
1281 MenuClickLeague, // 13
1282 MenuClickIndustry, // 14
1283 MenuClickShowTrains, // 15
1284 MenuClickShowRoad, // 16
1285 MenuClickShowShips, // 17
1286 MenuClickShowAir, // 18
1287 MenuClickMap, // 19
1288 nullptr, // 20
1289 MenuClickBuildRail, // 21
1290 MenuClickBuildRoad, // 22
1291 MenuClickBuildTram, // 23
1292 MenuClickBuildWater, // 24
1293 MenuClickBuildAir, // 25
1294 MenuClickForest, // 26
1295 MenuClickMusicWindow, // 27
1296 MenuClickNewspaper, // 28
1297 MenuClickHelp, // 29
1300 /** Full blown container to make it behave exactly as we want :) */
1301 class NWidgetToolbarContainer : public NWidgetContainer {
1302 bool visible[WID_TN_END]; ///< The visible headers
1303 protected:
1304 uint spacers; ///< Number of spacer widgets in this toolbar
1306 public:
1307 NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL)
1312 * Check whether the given widget type is a button for us.
1313 * @param type the widget type to check.
1314 * @return true if it is a button for us.
1316 bool IsButton(WidgetType type) const
1318 return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN;
1321 void SetupSmallestSize(Window *w, bool init_array) override
1323 this->smallest_x = 0; // Biggest child
1324 this->smallest_y = 0; // Biggest child
1325 this->fill_x = 1;
1326 this->fill_y = 0;
1327 this->resize_x = 1; // We only resize in this direction
1328 this->resize_y = 0; // We never resize in this direction
1329 this->spacers = 0;
1331 uint nbuttons = 0;
1332 /* First initialise some variables... */
1333 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1334 child_wid->SetupSmallestSize(w, init_array);
1335 this->smallest_y = std::max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
1336 if (this->IsButton(child_wid->type)) {
1337 nbuttons++;
1338 this->smallest_x = std::max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
1339 } else if (child_wid->type == NWID_SPACER) {
1340 this->spacers++;
1344 /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */
1345 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1346 child_wid->current_y = this->smallest_y;
1347 if (!this->IsButton(child_wid->type)) {
1348 child_wid->current_x = child_wid->smallest_x;
1351 _toolbar_width = nbuttons * this->smallest_x;
1354 void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl) override
1356 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
1358 this->pos_x = x;
1359 this->pos_y = y;
1360 this->current_x = given_width;
1361 this->current_y = given_height;
1363 /* Figure out what are the visible buttons */
1364 memset(this->visible, 0, sizeof(this->visible));
1365 uint arrangable_count, button_count, spacer_count;
1366 const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count);
1367 for (uint i = 0; i < arrangable_count; i++) {
1368 this->visible[arrangement[i]] = true;
1371 /* Create us ourselves a quick lookup table */
1372 NWidgetBase *widgets[WID_TN_END];
1373 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1374 if (child_wid->type == NWID_SPACER) continue;
1375 widgets[((NWidgetCore*)child_wid)->index] = child_wid;
1378 /* Now assign the widgets to their rightful place */
1379 uint position = 0; // Place to put next child relative to origin of the container.
1380 uint spacer_space = std::max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets
1381 uint button_space = given_width - spacer_space; // Remaining spacing for the buttons
1382 uint spacer_i = 0;
1383 uint button_i = 0;
1385 /* Index into the arrangement indices. The macro lastof cannot be used here! */
1386 const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement;
1387 for (uint i = 0; i < arrangable_count; i++) {
1388 NWidgetBase *child_wid = widgets[*cur_wid];
1389 /* If we have to give space to the spacers, do that */
1390 if (spacer_space != 0) {
1391 NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev;
1392 if (possible_spacer != nullptr && possible_spacer->type == NWID_SPACER) {
1393 uint add = spacer_space / (spacer_count - spacer_i);
1394 position += add;
1395 spacer_space -= add;
1396 spacer_i++;
1400 /* Buttons can be scaled, the others not. */
1401 if (this->IsButton(child_wid->type)) {
1402 child_wid->current_x = button_space / (button_count - button_i);
1403 button_space -= child_wid->current_x;
1404 button_i++;
1406 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
1407 position += child_wid->current_x;
1409 if (rtl) {
1410 cur_wid--;
1411 } else {
1412 cur_wid++;
1417 void Draw(const Window *w) override
1419 /* Draw brown-red toolbar bg. */
1420 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);
1421 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);
1423 bool rtl = _current_text_dir == TD_RTL;
1424 for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != nullptr; child_wid = rtl ? child_wid->prev : child_wid->next) {
1425 if (child_wid->type == NWID_SPACER) continue;
1426 if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1428 child_wid->Draw(w);
1432 NWidgetCore *GetWidgetFromPos(int x, int y) override
1434 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
1436 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1437 if (child_wid->type == NWID_SPACER) continue;
1438 if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1440 NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
1441 if (nwid != nullptr) return nwid;
1443 return nullptr;
1447 * Get the arrangement of the buttons for the toolbar.
1448 * @param width the new width of the toolbar.
1449 * @param arrangable_count output of the number of visible items.
1450 * @param button_count output of the number of visible buttons.
1451 * @param spacer_count output of the number of spacers.
1452 * @return the button configuration.
1454 virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0;
1457 /** Container for the 'normal' main toolbar */
1458 class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
1459 const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override
1461 static const uint SMALLEST_ARRANGEMENT = 14;
1462 static const uint BIGGEST_ARRANGEMENT = 20;
1464 /* The number of buttons of each row of the toolbar should match the number of items which we want to be visible.
1465 * The total number of buttons should be equal to arrangable_count * 2.
1466 * No bad things happen, but we could see strange behaviours if we have buttons < (arrangable_count * 2) like a
1467 * pause button appearing on the right of the lower toolbar and weird resizing of the widgets even if there is
1468 * enough space.
1470 static const byte arrange14[] = {
1471 WID_TN_PAUSE,
1472 WID_TN_FAST_FORWARD,
1473 WID_TN_TRAINS,
1474 WID_TN_ROADVEHS,
1475 WID_TN_SHIPS,
1476 WID_TN_AIRCRAFT,
1477 WID_TN_ZOOM_IN,
1478 WID_TN_ZOOM_OUT,
1479 WID_TN_RAILS,
1480 WID_TN_ROADS,
1481 WID_TN_WATER,
1482 WID_TN_AIR,
1483 WID_TN_LANDSCAPE,
1484 WID_TN_SWITCH_BAR,
1485 // lower toolbar
1486 WID_TN_SETTINGS,
1487 WID_TN_SAVE,
1488 WID_TN_SMALL_MAP,
1489 WID_TN_TOWNS,
1490 WID_TN_SUBSIDIES,
1491 WID_TN_STATIONS,
1492 WID_TN_FINANCES,
1493 WID_TN_COMPANIES,
1494 WID_TN_GRAPHS,
1495 WID_TN_INDUSTRIES,
1496 WID_TN_MUSIC_SOUND,
1497 WID_TN_MESSAGES,
1498 WID_TN_HELP,
1499 WID_TN_SWITCH_BAR,
1501 static const byte arrange15[] = {
1502 WID_TN_PAUSE,
1503 WID_TN_FAST_FORWARD,
1504 WID_TN_SMALL_MAP,
1505 WID_TN_TRAINS,
1506 WID_TN_ROADVEHS,
1507 WID_TN_SHIPS,
1508 WID_TN_AIRCRAFT,
1509 WID_TN_RAILS,
1510 WID_TN_ROADS,
1511 WID_TN_WATER,
1512 WID_TN_AIR,
1513 WID_TN_LANDSCAPE,
1514 WID_TN_ZOOM_IN,
1515 WID_TN_ZOOM_OUT,
1516 WID_TN_SWITCH_BAR,
1517 // lower toolbar
1518 WID_TN_PAUSE,
1519 WID_TN_SETTINGS,
1520 WID_TN_SMALL_MAP,
1521 WID_TN_SAVE,
1522 WID_TN_TOWNS,
1523 WID_TN_SUBSIDIES,
1524 WID_TN_STATIONS,
1525 WID_TN_FINANCES,
1526 WID_TN_COMPANIES,
1527 WID_TN_GRAPHS,
1528 WID_TN_INDUSTRIES,
1529 WID_TN_MUSIC_SOUND,
1530 WID_TN_MESSAGES,
1531 WID_TN_HELP,
1532 WID_TN_SWITCH_BAR,
1534 static const byte arrange16[] = {
1535 WID_TN_PAUSE,
1536 WID_TN_FAST_FORWARD,
1537 WID_TN_SETTINGS,
1538 WID_TN_SMALL_MAP,
1539 WID_TN_TRAINS,
1540 WID_TN_ROADVEHS,
1541 WID_TN_SHIPS,
1542 WID_TN_AIRCRAFT,
1543 WID_TN_RAILS,
1544 WID_TN_ROADS,
1545 WID_TN_WATER,
1546 WID_TN_AIR,
1547 WID_TN_LANDSCAPE,
1548 WID_TN_ZOOM_IN,
1549 WID_TN_ZOOM_OUT,
1550 WID_TN_SWITCH_BAR,
1551 // lower toolbar
1552 WID_TN_PAUSE,
1553 WID_TN_FAST_FORWARD,
1554 WID_TN_SAVE,
1555 WID_TN_TOWNS,
1556 WID_TN_SUBSIDIES,
1557 WID_TN_STATIONS,
1558 WID_TN_FINANCES,
1559 WID_TN_COMPANIES,
1560 WID_TN_GRAPHS,
1561 WID_TN_INDUSTRIES,
1562 WID_TN_MUSIC_SOUND,
1563 WID_TN_MESSAGES,
1564 WID_TN_HELP,
1565 WID_TN_ZOOM_IN,
1566 WID_TN_ZOOM_OUT,
1567 WID_TN_SWITCH_BAR,
1569 static const byte arrange17[] = {
1570 WID_TN_PAUSE,
1571 WID_TN_FAST_FORWARD,
1572 WID_TN_SETTINGS,
1573 WID_TN_SMALL_MAP,
1574 WID_TN_SUBSIDIES,
1575 WID_TN_TRAINS,
1576 WID_TN_ROADVEHS,
1577 WID_TN_SHIPS,
1578 WID_TN_AIRCRAFT,
1579 WID_TN_RAILS,
1580 WID_TN_ROADS,
1581 WID_TN_WATER,
1582 WID_TN_AIR,
1583 WID_TN_LANDSCAPE,
1584 WID_TN_ZOOM_IN,
1585 WID_TN_ZOOM_OUT,
1586 WID_TN_SWITCH_BAR,
1587 // lower toolbar
1588 WID_TN_PAUSE,
1589 WID_TN_FAST_FORWARD,
1590 WID_TN_SAVE,
1591 WID_TN_SMALL_MAP,
1592 WID_TN_SUBSIDIES,
1593 WID_TN_TOWNS,
1594 WID_TN_STATIONS,
1595 WID_TN_FINANCES,
1596 WID_TN_COMPANIES,
1597 WID_TN_GRAPHS,
1598 WID_TN_INDUSTRIES,
1599 WID_TN_MUSIC_SOUND,
1600 WID_TN_MESSAGES,
1601 WID_TN_HELP,
1602 WID_TN_ZOOM_IN,
1603 WID_TN_ZOOM_OUT,
1604 WID_TN_SWITCH_BAR,
1606 static const byte arrange18[] = {
1607 WID_TN_PAUSE,
1608 WID_TN_FAST_FORWARD,
1609 WID_TN_SETTINGS,
1610 WID_TN_SMALL_MAP,
1611 WID_TN_TOWNS,
1612 WID_TN_SUBSIDIES,
1613 WID_TN_STATIONS,
1614 WID_TN_FINANCES,
1615 WID_TN_COMPANIES,
1616 WID_TN_INDUSTRIES,
1617 WID_TN_RAILS,
1618 WID_TN_ROADS,
1619 WID_TN_WATER,
1620 WID_TN_AIR,
1621 WID_TN_LANDSCAPE,
1622 WID_TN_ZOOM_IN,
1623 WID_TN_ZOOM_OUT,
1624 WID_TN_SWITCH_BAR,
1625 // lower toolbar
1626 WID_TN_PAUSE,
1627 WID_TN_FAST_FORWARD,
1628 WID_TN_SAVE,
1629 WID_TN_SMALL_MAP,
1630 WID_TN_TOWNS,
1631 WID_TN_SUBSIDIES,
1632 WID_TN_STATIONS,
1633 WID_TN_GRAPHS,
1634 WID_TN_TRAINS,
1635 WID_TN_ROADVEHS,
1636 WID_TN_SHIPS,
1637 WID_TN_AIRCRAFT,
1638 WID_TN_MUSIC_SOUND,
1639 WID_TN_MESSAGES,
1640 WID_TN_HELP,
1641 WID_TN_ZOOM_IN,
1642 WID_TN_ZOOM_OUT,
1643 WID_TN_SWITCH_BAR,
1645 static const byte arrange19[] = {
1646 WID_TN_PAUSE,
1647 WID_TN_FAST_FORWARD,
1648 WID_TN_SETTINGS,
1649 WID_TN_SMALL_MAP,
1650 WID_TN_TOWNS,
1651 WID_TN_SUBSIDIES,
1652 WID_TN_TRAINS,
1653 WID_TN_ROADVEHS,
1654 WID_TN_SHIPS,
1655 WID_TN_AIRCRAFT,
1656 WID_TN_RAILS,
1657 WID_TN_ROADS,
1658 WID_TN_WATER,
1659 WID_TN_AIR,
1660 WID_TN_LANDSCAPE,
1661 WID_TN_MUSIC_SOUND,
1662 WID_TN_ZOOM_IN,
1663 WID_TN_ZOOM_OUT,
1664 WID_TN_SWITCH_BAR,
1665 // lower toolbar
1666 WID_TN_PAUSE,
1667 WID_TN_FAST_FORWARD,
1668 WID_TN_SAVE,
1669 WID_TN_SMALL_MAP,
1670 WID_TN_STATIONS,
1671 WID_TN_FINANCES,
1672 WID_TN_COMPANIES,
1673 WID_TN_GRAPHS,
1674 WID_TN_INDUSTRIES,
1675 WID_TN_MESSAGES,
1676 WID_TN_RAILS,
1677 WID_TN_ROADS,
1678 WID_TN_WATER,
1679 WID_TN_AIR,
1680 WID_TN_LANDSCAPE,
1681 WID_TN_HELP,
1682 WID_TN_ZOOM_IN,
1683 WID_TN_ZOOM_OUT,
1684 WID_TN_SWITCH_BAR,
1686 static const byte arrange20[] = {
1687 WID_TN_PAUSE,
1688 WID_TN_FAST_FORWARD,
1689 WID_TN_SETTINGS,
1690 WID_TN_SMALL_MAP,
1691 WID_TN_TOWNS,
1692 WID_TN_SUBSIDIES,
1693 WID_TN_TRAINS,
1694 WID_TN_ROADVEHS,
1695 WID_TN_SHIPS,
1696 WID_TN_AIRCRAFT,
1697 WID_TN_RAILS,
1698 WID_TN_ROADS,
1699 WID_TN_WATER,
1700 WID_TN_AIR,
1701 WID_TN_LANDSCAPE,
1702 WID_TN_MUSIC_SOUND,
1703 WID_TN_GOAL,
1704 WID_TN_ZOOM_IN,
1705 WID_TN_ZOOM_OUT,
1706 WID_TN_SWITCH_BAR,
1707 // lower toolbar
1708 WID_TN_PAUSE,
1709 WID_TN_FAST_FORWARD,
1710 WID_TN_SAVE,
1711 WID_TN_SMALL_MAP,
1712 WID_TN_STATIONS,
1713 WID_TN_FINANCES,
1714 WID_TN_COMPANIES,
1715 WID_TN_GRAPHS,
1716 WID_TN_INDUSTRIES,
1717 WID_TN_MESSAGES,
1718 WID_TN_RAILS,
1719 WID_TN_ROADS,
1720 WID_TN_WATER,
1721 WID_TN_AIR,
1722 WID_TN_LANDSCAPE,
1723 WID_TN_STORY,
1724 WID_TN_HELP,
1725 WID_TN_ZOOM_IN,
1726 WID_TN_ZOOM_OUT,
1727 WID_TN_SWITCH_BAR,
1729 static const byte arrange_all[] = {
1730 WID_TN_PAUSE,
1731 WID_TN_FAST_FORWARD,
1732 WID_TN_SETTINGS,
1733 WID_TN_SAVE,
1734 WID_TN_SMALL_MAP,
1735 WID_TN_TOWNS,
1736 WID_TN_SUBSIDIES,
1737 WID_TN_STATIONS,
1738 WID_TN_FINANCES,
1739 WID_TN_COMPANIES,
1740 WID_TN_STORY,
1741 WID_TN_GOAL,
1742 WID_TN_GRAPHS,
1743 WID_TN_LEAGUE,
1744 WID_TN_INDUSTRIES,
1745 WID_TN_TRAINS,
1746 WID_TN_ROADVEHS,
1747 WID_TN_SHIPS,
1748 WID_TN_AIRCRAFT,
1749 WID_TN_ZOOM_IN,
1750 WID_TN_ZOOM_OUT,
1751 WID_TN_RAILS,
1752 WID_TN_ROADS,
1753 WID_TN_TRAMS,
1754 WID_TN_WATER,
1755 WID_TN_AIR,
1756 WID_TN_LANDSCAPE,
1757 WID_TN_MUSIC_SOUND,
1758 WID_TN_MESSAGES,
1759 WID_TN_HELP
1762 /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
1763 uint full_buttons = std::max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
1764 if (full_buttons > BIGGEST_ARRANGEMENT) {
1765 button_count = arrangable_count = lengthof(arrange_all);
1766 spacer_count = this->spacers;
1767 return arrange_all;
1770 /* Introduce the split toolbar */
1771 static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
1773 button_count = arrangable_count = full_buttons;
1774 spacer_count = this->spacers;
1775 return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
1779 /** Container for the scenario editor's toolbar */
1780 class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer {
1781 uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel)
1783 void SetupSmallestSize(Window *w, bool init_array) override
1785 this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array);
1787 /* Find the size of panel_widths */
1788 uint i = 0;
1789 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1790 if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
1792 assert(i < lengthof(this->panel_widths));
1793 this->panel_widths[i++] = child_wid->current_x;
1794 _toolbar_width += child_wid->current_x;
1798 const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const override
1800 static const byte arrange_all[] = {
1801 WID_TE_PAUSE,
1802 WID_TE_FAST_FORWARD,
1803 WID_TE_SETTINGS,
1804 WID_TE_SAVE,
1805 WID_TE_SPACER,
1806 WID_TE_DATE_PANEL,
1807 WID_TE_SMALL_MAP,
1808 WID_TE_ZOOM_IN,
1809 WID_TE_ZOOM_OUT,
1810 WID_TE_LAND_GENERATE,
1811 WID_TE_TOWN_GENERATE,
1812 WID_TE_INDUSTRY,
1813 WID_TE_ROADS,
1814 WID_TE_TRAMS,
1815 WID_TE_WATER,
1816 WID_TE_TREES,
1817 WID_TE_SIGNS,
1818 WID_TE_MUSIC_SOUND,
1819 WID_TE_HELP,
1821 static const byte arrange_nopanel[] = {
1822 WID_TE_PAUSE,
1823 WID_TE_FAST_FORWARD,
1824 WID_TE_SETTINGS,
1825 WID_TE_SAVE,
1826 WID_TE_DATE_PANEL,
1827 WID_TE_SMALL_MAP,
1828 WID_TE_ZOOM_IN,
1829 WID_TE_ZOOM_OUT,
1830 WID_TE_LAND_GENERATE,
1831 WID_TE_TOWN_GENERATE,
1832 WID_TE_INDUSTRY,
1833 WID_TE_ROADS,
1834 WID_TE_TRAMS,
1835 WID_TE_WATER,
1836 WID_TE_TREES,
1837 WID_TE_SIGNS,
1838 WID_TE_MUSIC_SOUND,
1839 WID_TE_HELP,
1841 static const byte arrange_switch[] = {
1842 WID_TE_DATE_PANEL,
1843 WID_TE_SMALL_MAP,
1844 WID_TE_LAND_GENERATE,
1845 WID_TE_TOWN_GENERATE,
1846 WID_TE_INDUSTRY,
1847 WID_TE_ROADS,
1848 WID_TE_TRAMS,
1849 WID_TE_WATER,
1850 WID_TE_TREES,
1851 WID_TE_SIGNS,
1852 WID_TE_SWITCH_BAR,
1853 // lower toolbar
1854 WID_TE_PAUSE,
1855 WID_TE_FAST_FORWARD,
1856 WID_TE_SETTINGS,
1857 WID_TE_SAVE,
1858 WID_TE_DATE_PANEL,
1859 WID_TE_SMALL_MAP,
1860 WID_TE_ZOOM_IN,
1861 WID_TE_ZOOM_OUT,
1862 WID_TE_MUSIC_SOUND,
1863 WID_TE_HELP,
1864 WID_TE_SWITCH_BAR,
1867 /* If we can place all buttons *and* the panels, show them. */
1868 uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
1869 if (width >= min_full_width) {
1870 width -= this->panel_widths[0] + this->panel_widths[1];
1871 arrangable_count = lengthof(arrange_all);
1872 button_count = arrangable_count - 2;
1873 spacer_count = this->spacers;
1874 return arrange_all;
1877 /* 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 */
1878 uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
1879 if (width > min_small_width) {
1880 width -= this->panel_widths[1];
1881 arrangable_count = lengthof(arrange_nopanel);
1882 button_count = arrangable_count - 1;
1883 spacer_count = this->spacers - 1;
1884 return arrange_nopanel;
1887 /* Split toolbar */
1888 width -= this->panel_widths[1];
1889 arrangable_count = lengthof(arrange_switch) / 2;
1890 button_count = arrangable_count - 1;
1891 spacer_count = 0;
1892 return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
1896 /* --- Toolbar handling for the 'normal' case */
1898 typedef CallBackFunction ToolbarButtonProc(Window *w);
1900 static ToolbarButtonProc * const _toolbar_button_procs[] = {
1901 ToolbarPauseClick,
1902 ToolbarFastForwardClick,
1903 ToolbarOptionsClick,
1904 ToolbarSaveClick,
1905 ToolbarMapClick,
1906 ToolbarTownClick,
1907 ToolbarSubsidiesClick,
1908 ToolbarStationsClick,
1909 ToolbarFinancesClick,
1910 ToolbarCompaniesClick,
1911 ToolbarStoryClick,
1912 ToolbarGoalClick,
1913 ToolbarGraphsClick,
1914 ToolbarLeagueClick,
1915 ToolbarIndustryClick,
1916 ToolbarTrainClick,
1917 ToolbarRoadClick,
1918 ToolbarShipClick,
1919 ToolbarAirClick,
1920 ToolbarZoomInClick,
1921 ToolbarZoomOutClick,
1922 ToolbarBuildRailClick,
1923 ToolbarBuildRoadClick,
1924 ToolbarBuildTramClick,
1925 ToolbarBuildWaterClick,
1926 ToolbarBuildAirClick,
1927 ToolbarForestClick,
1928 ToolbarMusicClick,
1929 ToolbarNewspaperClick,
1930 ToolbarHelpClick,
1931 ToolbarSwitchClick,
1934 enum MainToolbarHotkeys {
1935 MTHK_PAUSE,
1936 MTHK_FASTFORWARD,
1937 MTHK_SETTINGS,
1938 MTHK_SAVEGAME,
1939 MTHK_LOADGAME,
1940 MTHK_SMALLMAP,
1941 MTHK_TOWNDIRECTORY,
1942 MTHK_SUBSIDIES,
1943 MTHK_STATIONS,
1944 MTHK_FINANCES,
1945 MTHK_COMPANIES,
1946 MTHK_STORY,
1947 MTHK_GOAL,
1948 MTHK_GRAPHS,
1949 MTHK_LEAGUE,
1950 MTHK_INDUSTRIES,
1951 MTHK_TRAIN_LIST,
1952 MTHK_ROADVEH_LIST,
1953 MTHK_SHIP_LIST,
1954 MTHK_AIRCRAFT_LIST,
1955 MTHK_ZOOM_IN,
1956 MTHK_ZOOM_OUT,
1957 MTHK_BUILD_RAIL,
1958 MTHK_BUILD_ROAD,
1959 MTHK_BUILD_TRAM,
1960 MTHK_BUILD_DOCKS,
1961 MTHK_BUILD_AIRPORT,
1962 MTHK_BUILD_TREES,
1963 MTHK_MUSIC,
1964 MTHK_LANDINFO,
1965 MTHK_AI_DEBUG,
1966 MTHK_SMALL_SCREENSHOT,
1967 MTHK_ZOOMEDIN_SCREENSHOT,
1968 MTHK_DEFAULTZOOM_SCREENSHOT,
1969 MTHK_GIANT_SCREENSHOT,
1970 MTHK_CHEATS,
1971 MTHK_TERRAFORM,
1972 MTHK_EXTRA_VIEWPORT,
1973 MTHK_CLIENT_LIST,
1974 MTHK_SIGN_LIST,
1977 /** Main toolbar. */
1978 struct MainToolbarWindow : Window {
1979 GUITimer timer;
1981 MainToolbarWindow(WindowDesc *desc) : Window(desc)
1983 this->InitNested(0);
1985 _last_started_action = CBF_NONE;
1986 CLRBITS(this->flags, WF_WHITE_BORDER);
1987 this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
1988 this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
1989 PositionMainToolbar(this);
1990 DoZoomInOutWindow(ZOOM_NONE, this);
1992 this->timer.SetInterval(MILLISECONDS_PER_TICK);
1995 void FindWindowPlacementAndResize(int def_width, int def_height) override
1997 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
2000 void OnPaint() override
2002 /* If spectator, disable all construction buttons
2003 * ie : Build road, rail, ships, airports and landscaping
2004 * Since enabled state is the default, just disable when needed */
2005 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);
2006 /* disable company list drop downs, if there are no companies */
2007 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);
2009 this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0);
2010 this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0);
2012 this->DrawWidgets();
2015 void OnClick(Point pt, int widget, int click_count) override
2017 if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
2020 void OnDropdownSelect(int widget, int index) override
2022 CallBackFunction cbf = _menu_clicked_procs[widget](index);
2023 if (cbf != CBF_NONE) _last_started_action = cbf;
2026 EventState OnHotkey(int hotkey) override
2028 CallBackFunction cbf = CBF_NONE;
2029 switch (hotkey) {
2030 case MTHK_PAUSE: ToolbarPauseClick(this); break;
2031 case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2032 case MTHK_SETTINGS: ShowGameOptions(); break;
2033 case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
2034 case MTHK_LOADGAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
2035 case MTHK_SMALLMAP: ShowSmallMap(); break;
2036 case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
2037 case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
2038 case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
2039 case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
2040 case MTHK_COMPANIES: ShowCompany(_local_company); break;
2041 case MTHK_STORY: ShowStoryBook(_local_company); break;
2042 case MTHK_GOAL: ShowGoalsList(_local_company); break;
2043 case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
2044 case MTHK_LEAGUE: ShowCompanyLeagueTable(); break;
2045 case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
2046 case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
2047 case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
2048 case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
2049 case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
2050 case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2051 case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2052 case MTHK_BUILD_RAIL: ShowBuildRailToolbar(_last_built_railtype); break;
2053 case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
2054 case MTHK_BUILD_TRAM: ShowBuildRoadToolbar(_last_built_tramtype); break;
2055 case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
2056 case MTHK_BUILD_AIRPORT: ShowBuildAirToolbar(); break;
2057 case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
2058 case MTHK_MUSIC: ShowMusicWindow(); break;
2059 case MTHK_AI_DEBUG: ShowAIDebugWindow(); break;
2060 case MTHK_SMALL_SCREENSHOT: MakeScreenshotWithConfirm(SC_VIEWPORT); break;
2061 case MTHK_ZOOMEDIN_SCREENSHOT: MakeScreenshotWithConfirm(SC_ZOOMEDIN); break;
2062 case MTHK_DEFAULTZOOM_SCREENSHOT: MakeScreenshotWithConfirm(SC_DEFAULTZOOM); break;
2063 case MTHK_GIANT_SCREENSHOT: MakeScreenshotWithConfirm(SC_WORLD); break;
2064 case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
2065 case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
2066 case MTHK_EXTRA_VIEWPORT: ShowExtraViewportWindowForTileUnderCursor(); break;
2067 case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
2068 case MTHK_SIGN_LIST: ShowSignList(); break;
2069 case MTHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2070 default: return ES_NOT_HANDLED;
2072 if (cbf != CBF_NONE) _last_started_action = cbf;
2073 return ES_HANDLED;
2076 void OnPlaceObject(Point pt, TileIndex tile) override
2078 switch (_last_started_action) {
2079 case CBF_PLACE_SIGN:
2080 PlaceProc_Sign(tile);
2081 break;
2083 case CBF_PLACE_LANDINFO:
2084 ShowLandInfo(tile);
2085 break;
2087 default: NOT_REACHED();
2091 void OnPlaceObjectAbort() override
2093 _last_started_action = CBF_NONE;
2096 void OnRealtimeTick(uint delta_ms) override
2098 if (!this->timer.Elapsed(delta_ms)) return;
2099 this->timer.SetInterval(MILLISECONDS_PER_TICK);
2101 if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
2102 this->ToggleWidgetLoweredState(WID_TN_PAUSE);
2103 this->SetWidgetDirty(WID_TN_PAUSE);
2106 if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != (_game_speed != 100)) {
2107 this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD);
2108 this->SetWidgetDirty(WID_TN_FAST_FORWARD);
2112 void OnTimeout() override
2114 /* We do not want to automatically raise the pause, fast forward and
2115 * switchbar buttons; they have to stay down when pressed etc. */
2116 for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
2117 if (this->IsWidgetLowered(i)) {
2118 this->RaiseWidget(i);
2119 this->SetWidgetDirty(i);
2125 * Some data on this window has become invalid.
2126 * @param data Information about the changed data.
2127 * @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.
2129 void OnInvalidateData(int data = 0, bool gui_scope = true) override
2131 if (!gui_scope) return;
2132 if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
2135 static HotkeyList hotkeys;
2138 const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0};
2139 const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0};
2140 const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0};
2141 const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0};
2143 static Hotkey maintoolbar_hotkeys[] = {
2144 Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE),
2145 Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD),
2146 Hotkey(WKC_F2, "settings", MTHK_SETTINGS),
2147 Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME),
2148 Hotkey((uint16)0, "load_game", MTHK_LOADGAME),
2149 Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP),
2150 Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
2151 Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES),
2152 Hotkey(WKC_F7, "station_list", MTHK_STATIONS),
2153 Hotkey(WKC_F8, "finances", MTHK_FINANCES),
2154 Hotkey(WKC_F9, "companies", MTHK_COMPANIES),
2155 Hotkey((uint16)0, "story_book", MTHK_STORY),
2156 Hotkey((uint16)0, "goal_list", MTHK_GOAL),
2157 Hotkey(WKC_F10, "graphs", MTHK_GRAPHS),
2158 Hotkey(WKC_F11, "league", MTHK_LEAGUE),
2159 Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES),
2160 Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
2161 Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
2162 Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
2163 Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
2164 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN),
2165 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT),
2166 Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
2167 Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
2168 Hotkey((uint16)0, "build_tram", MTHK_BUILD_TRAM),
2169 Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
2170 Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
2171 Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
2172 Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
2173 Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG),
2174 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
2175 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
2176 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT),
2177 Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
2178 Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
2179 Hotkey('L', "terraform", MTHK_TERRAFORM),
2180 Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
2181 Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
2182 Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
2183 Hotkey((uint16)0, "land_info", MTHK_LANDINFO),
2184 HOTKEY_LIST_END
2186 HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
2188 static NWidgetBase *MakeMainToolbar(int *biggest_index)
2190 /** Sprites to use for the different toolbar buttons */
2191 static const SpriteID toolbar_button_sprites[] = {
2192 SPR_IMG_PAUSE, // WID_TN_PAUSE
2193 SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD
2194 SPR_IMG_SETTINGS, // WID_TN_SETTINGS
2195 SPR_IMG_SAVE, // WID_TN_SAVE
2196 SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP
2197 SPR_IMG_TOWN, // WID_TN_TOWNS
2198 SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES
2199 SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS
2200 SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
2201 SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
2202 SPR_IMG_STORY_BOOK, // WID_TN_STORY
2203 SPR_IMG_GOAL, // WID_TN_GOAL
2204 SPR_IMG_GRAPHS, // WID_TN_GRAPHS
2205 SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE
2206 SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES
2207 SPR_IMG_TRAINLIST, // WID_TN_TRAINS
2208 SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS
2209 SPR_IMG_SHIPLIST, // WID_TN_SHIPS
2210 SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT
2211 SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN
2212 SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT
2213 SPR_IMG_BUILDRAIL, // WID_TN_RAILS
2214 SPR_IMG_BUILDROAD, // WID_TN_ROADS
2215 SPR_IMG_BUILDTRAMS, // WID_TN_TRAMS
2216 SPR_IMG_BUILDWATER, // WID_TN_WATER
2217 SPR_IMG_BUILDAIR, // WID_TN_AIR
2218 SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
2219 SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
2220 SPR_IMG_MESSAGES, // WID_TN_MESSAGES
2221 SPR_IMG_QUERY, // WID_TN_HELP
2222 SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
2225 NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
2226 for (uint i = 0; i < WID_TN_END; i++) {
2227 switch (i) {
2228 case WID_TN_SMALL_MAP:
2229 case WID_TN_FINANCES:
2230 case WID_TN_VEHICLE_START:
2231 case WID_TN_ZOOM_IN:
2232 case WID_TN_BUILDING_TOOLS_START:
2233 case WID_TN_MUSIC_SOUND:
2234 hor->Add(new NWidgetSpacer(0, 0));
2235 break;
2237 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);
2238 leaf->SetMinimalSize(20, 20);
2239 hor->Add(leaf);
2242 *biggest_index = std::max<int>(*biggest_index, WID_TN_SWITCH_BAR);
2243 return hor;
2246 static const NWidgetPart _nested_toolbar_normal_widgets[] = {
2247 NWidgetFunction(MakeMainToolbar),
2250 static WindowDesc _toolb_normal_desc(
2251 WDP_MANUAL, nullptr, 0, 0,
2252 WC_MAIN_TOOLBAR, WC_NONE,
2253 WDF_NO_FOCUS,
2254 _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets),
2255 &MainToolbarWindow::hotkeys
2259 /* --- Toolbar handling for the scenario editor */
2261 static MenuClickedProc * const _scen_toolbar_dropdown_procs[] = {
2262 nullptr, // 0
2263 nullptr, // 1
2264 MenuClickSettings, // 2
2265 MenuClickSaveLoad, // 3
2266 nullptr, // 4
2267 nullptr, // 5
2268 nullptr, // 6
2269 nullptr, // 7
2270 MenuClickMap, // 8
2271 nullptr, // 9
2272 nullptr, // 10
2273 nullptr, // 11
2274 nullptr, // 12
2275 nullptr, // 13
2276 ToolbarScenBuildRoad, // 14
2277 ToolbarScenBuildTram, // 15
2278 nullptr, // 16
2279 nullptr, // 17
2280 nullptr, // 18
2281 nullptr, // 19
2282 MenuClickMusicWindow, // 20
2283 MenuClickHelp, // 21
2284 nullptr, // 22
2287 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
2288 ToolbarPauseClick,
2289 ToolbarFastForwardClick,
2290 ToolbarOptionsClick,
2291 ToolbarScenSaveOrLoad,
2292 ToolbarBtn_NULL,
2293 ToolbarScenDatePanel,
2294 ToolbarScenDateBackward,
2295 ToolbarScenDateForward,
2296 ToolbarScenMapTownDir,
2297 ToolbarZoomInClick,
2298 ToolbarZoomOutClick,
2299 ToolbarScenGenLand,
2300 ToolbarScenGenTown,
2301 ToolbarScenGenIndustry,
2302 ToolbarScenBuildRoadClick,
2303 ToolbarScenBuildTramClick,
2304 ToolbarScenBuildDocks,
2305 ToolbarScenPlantTrees,
2306 ToolbarScenPlaceSign,
2307 ToolbarBtn_NULL,
2308 ToolbarMusicClick,
2309 ToolbarHelpClick,
2310 ToolbarSwitchClick,
2313 enum MainToolbarEditorHotkeys {
2314 MTEHK_PAUSE,
2315 MTEHK_FASTFORWARD,
2316 MTEHK_SETTINGS,
2317 MTEHK_SAVEGAME,
2318 MTEHK_GENLAND,
2319 MTEHK_GENTOWN,
2320 MTEHK_GENINDUSTRY,
2321 MTEHK_BUILD_ROAD,
2322 MTEHK_BUILD_TRAM,
2323 MTEHK_BUILD_DOCKS,
2324 MTEHK_BUILD_TREES,
2325 MTEHK_SIGN,
2326 MTEHK_MUSIC,
2327 MTEHK_LANDINFO,
2328 MTEHK_SMALL_SCREENSHOT,
2329 MTEHK_ZOOMEDIN_SCREENSHOT,
2330 MTEHK_DEFAULTZOOM_SCREENSHOT,
2331 MTEHK_GIANT_SCREENSHOT,
2332 MTEHK_ZOOM_IN,
2333 MTEHK_ZOOM_OUT,
2334 MTEHK_TERRAFORM,
2335 MTEHK_SMALLMAP,
2336 MTEHK_EXTRA_VIEWPORT,
2339 struct ScenarioEditorToolbarWindow : Window {
2340 GUITimer timer;
2342 ScenarioEditorToolbarWindow(WindowDesc *desc) : Window(desc)
2344 this->InitNested(0);
2346 _last_started_action = CBF_NONE;
2347 CLRBITS(this->flags, WF_WHITE_BORDER);
2348 PositionMainToolbar(this);
2349 DoZoomInOutWindow(ZOOM_NONE, this);
2351 this->timer.SetInterval(MILLISECONDS_PER_TICK);
2354 void FindWindowPlacementAndResize(int def_width, int def_height) override
2356 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
2359 void OnPaint() override
2361 this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR);
2362 this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR);
2363 this->SetWidgetDisabledState(WID_TE_ROADS, (GetRoadTypes(true) & ~_roadtypes_type) == ROADTYPES_NONE);
2364 this->SetWidgetDisabledState(WID_TE_TRAMS, (GetRoadTypes(true) & _roadtypes_type) == ROADTYPES_NONE);
2366 this->DrawWidgets();
2369 void DrawWidget(const Rect &r, int widget) const override
2371 switch (widget) {
2372 case WID_TE_DATE:
2373 SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
2374 DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER);
2375 break;
2377 case WID_TE_SPACER: {
2378 int height = r.bottom - r.top;
2379 if (height > 2 * FONT_HEIGHT_NORMAL) {
2380 DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
2381 DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2382 } else {
2383 DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2385 break;
2390 void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
2392 switch (widget) {
2393 case WID_TE_SPACER:
2394 size->width = std::max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
2395 break;
2397 case WID_TE_DATE:
2398 SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1));
2399 *size = GetStringBoundingBox(STR_WHITE_DATE_LONG);
2400 size->height = std::max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM);
2401 break;
2405 void OnClick(Point pt, int widget, int click_count) override
2407 if (_game_mode == GM_MENU) return;
2408 CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
2409 if (cbf != CBF_NONE) _last_started_action = cbf;
2412 void OnDropdownSelect(int widget, int index) override
2414 CallBackFunction cbf = _scen_toolbar_dropdown_procs[widget](index);
2415 if (cbf != CBF_NONE) _last_started_action = cbf;
2416 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
2419 EventState OnHotkey(int hotkey) override
2421 CallBackFunction cbf = CBF_NONE;
2422 switch (hotkey) {
2423 case MTEHK_PAUSE: ToolbarPauseClick(this); break;
2424 case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2425 case MTEHK_SETTINGS: ShowGameOptions(); break;
2426 case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
2427 case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
2428 case MTEHK_GENTOWN: ToolbarScenGenTown(this); break;
2429 case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
2430 case MTEHK_BUILD_ROAD: ToolbarScenBuildRoadClick(this); break;
2431 case MTEHK_BUILD_TRAM: ToolbarScenBuildTramClick(this); break;
2432 case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break;
2433 case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break;
2434 case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break;
2435 case MTEHK_MUSIC: ShowMusicWindow(); break;
2436 case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2437 case MTEHK_SMALL_SCREENSHOT: MakeScreenshotWithConfirm(SC_VIEWPORT); break;
2438 case MTEHK_ZOOMEDIN_SCREENSHOT: MakeScreenshotWithConfirm(SC_ZOOMEDIN); break;
2439 case MTEHK_DEFAULTZOOM_SCREENSHOT: MakeScreenshotWithConfirm(SC_DEFAULTZOOM); break;
2440 case MTEHK_GIANT_SCREENSHOT: MakeScreenshotWithConfirm(SC_WORLD); break;
2441 case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2442 case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2443 case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break;
2444 case MTEHK_SMALLMAP: ShowSmallMap(); break;
2445 case MTEHK_EXTRA_VIEWPORT: ShowExtraViewportWindowForTileUnderCursor(); break;
2446 default: return ES_NOT_HANDLED;
2448 if (cbf != CBF_NONE) _last_started_action = cbf;
2449 return ES_HANDLED;
2452 void OnPlaceObject(Point pt, TileIndex tile) override
2454 switch (_last_started_action) {
2455 case CBF_PLACE_SIGN:
2456 PlaceProc_Sign(tile);
2457 break;
2459 case CBF_PLACE_LANDINFO:
2460 ShowLandInfo(tile);
2461 break;
2463 default: NOT_REACHED();
2467 void OnPlaceObjectAbort() override
2469 _last_started_action = CBF_NONE;
2472 void OnTimeout() override
2474 this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END);
2475 this->SetWidgetDirty(WID_TE_DATE_BACKWARD);
2476 this->SetWidgetDirty(WID_TE_DATE_FORWARD);
2479 void OnRealtimeTick(uint delta_ms) override
2481 if (!this->timer.Elapsed(delta_ms)) return;
2482 this->timer.SetInterval(MILLISECONDS_PER_TICK);
2484 if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
2485 this->ToggleWidgetLoweredState(WID_TE_PAUSE);
2486 this->SetDirty();
2489 if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != (_game_speed != 100)) {
2490 this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD);
2491 this->SetDirty();
2496 * Some data on this window has become invalid.
2497 * @param data Information about the changed data.
2498 * @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.
2500 void OnInvalidateData(int data = 0, bool gui_scope = true) override
2502 if (!gui_scope) return;
2503 if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
2506 void OnQueryTextFinished(char *str) override
2508 /* Was 'cancel' pressed? */
2509 if (str == nullptr) return;
2511 int32 value;
2512 if (!StrEmpty(str)) {
2513 value = atoi(str);
2514 } else {
2515 /* An empty string means revert to the default */
2516 value = DEF_START_YEAR;
2518 SetStartingYear(value);
2520 this->SetDirty();
2523 static HotkeyList hotkeys;
2526 static Hotkey scenedit_maintoolbar_hotkeys[] = {
2527 Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE),
2528 Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD),
2529 Hotkey(WKC_F2, "settings", MTEHK_SETTINGS),
2530 Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME),
2531 Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND),
2532 Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN),
2533 Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
2534 Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
2535 Hotkey((uint16)0, "build_tram", MTEHK_BUILD_TRAM),
2536 Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
2537 Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
2538 Hotkey(WKC_F10, "build_sign", MTEHK_SIGN),
2539 Hotkey(WKC_F11, "music", MTEHK_MUSIC),
2540 Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO),
2541 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
2542 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
2543 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT),
2544 Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
2545 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN),
2546 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT),
2547 Hotkey('L', "terraform", MTEHK_TERRAFORM),
2548 Hotkey('M', "smallmap", MTEHK_SMALLMAP),
2549 Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
2550 HOTKEY_LIST_END
2552 HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys);
2554 static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
2555 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
2556 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
2557 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
2558 NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
2559 NWidget(NWID_SPACER),
2560 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
2561 NWidget(NWID_SPACER),
2562 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
2563 NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
2564 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD),
2565 NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE),
2566 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD),
2567 EndContainer(),
2568 EndContainer(),
2569 NWidget(NWID_SPACER),
2570 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
2571 NWidget(NWID_SPACER),
2572 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
2573 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
2574 NWidget(NWID_SPACER),
2575 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
2576 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
2577 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
2578 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
2579 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_TRAMS), SetDataTip(SPR_IMG_BUILDTRAMS, STR_SCENEDIT_TOOLBAR_TRAM_CONSTRUCTION),
2580 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
2581 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
2582 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
2583 NWidget(NWID_SPACER),
2584 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
2585 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
2586 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
2589 static NWidgetBase *MakeScenarioToolbar(int *biggest_index)
2591 return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer());
2594 static const NWidgetPart _nested_toolb_scen_widgets[] = {
2595 NWidgetFunction(MakeScenarioToolbar),
2598 static WindowDesc _toolb_scen_desc(
2599 WDP_MANUAL, nullptr, 0, 0,
2600 WC_MAIN_TOOLBAR, WC_NONE,
2601 WDF_NO_FOCUS,
2602 _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets),
2603 &ScenarioEditorToolbarWindow::hotkeys
2606 /** Allocate the toolbar. */
2607 void AllocateToolbar()
2609 /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
2610 _last_built_roadtype = ROADTYPE_ROAD;
2611 _last_built_tramtype = ROADTYPE_TRAM;
2613 if (_game_mode == GM_EDITOR) {
2614 new ScenarioEditorToolbarWindow(&_toolb_scen_desc);
2615 } else {
2616 new MainToolbarWindow(&_toolb_normal_desc);