Make it possible to stop road vehicles from slowing down in curves so "diagonal"...
[openttd-joker.git] / src / toolbar_gui.cpp
blob77277336fee5f3f72e23a8991f62caef9a8474a6
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
6 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
7 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
8 */
10 /** @file toolbar_gui.cpp Code related to the (main) toolbar. */
12 #include "stdafx.h"
13 #include "gui.h"
14 #include "window_gui.h"
15 #include "window_func.h"
16 #include "viewport_func.h"
17 #include "command_func.h"
18 #include "vehicle_gui.h"
19 #include "rail_gui.h"
20 #include "road_gui.h"
21 #include "date_func.h"
22 #include "vehicle_func.h"
23 #include "sound_func.h"
24 #include "terraform_gui.h"
25 #include "strings_func.h"
26 #include "company_func.h"
27 #include "company_gui.h"
28 #include "vehicle_base.h"
29 #include "cheat_func.h"
30 #include "transparency_gui.h"
31 #include "screenshot.h"
32 #include "signs_func.h"
33 #include "fios.h"
34 #include "console_gui.h"
35 #include "news_gui.h"
36 #include "ai/ai_gui.hpp"
37 #include "tilehighlight_func.h"
38 #include "smallmap_gui.h"
39 #include "graph_gui.h"
40 #include "textbuf_gui.h"
41 #include "linkgraph/linkgraph_gui.h"
42 #include "newgrf_debug.h"
43 #include "hotkeys.h"
44 #include "engine_base.h"
45 #include "highscore.h"
46 #include "game/game.hpp"
47 #include "goal_base.h"
48 #include "story_base.h"
49 #include "toolbar_gui.h"
50 #include "plans_func.h"
51 #include "zoning.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;
68 static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm.
70 /** Toobar modes */
71 enum ToolbarMode {
72 TB_NORMAL,
73 TB_UPPER,
74 TB_LOWER
77 /** Callback functions. */
78 enum CallBackFunction {
79 CBF_NONE,
80 CBF_PLACE_SIGN,
81 CBF_PLACE_LANDINFO,
84 static CallBackFunction _last_started_action = CBF_NONE; ///< Last started user action.
87 /**
88 * Drop down list entry for showing a checked/unchecked toggle item.
90 class DropDownListCheckedItem : public DropDownListStringItem {
91 uint checkmark_width;
92 public:
93 bool checked;
95 DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked)
97 this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
100 virtual ~DropDownListCheckedItem() {}
102 uint Width() const
104 return DropDownListStringItem::Width() + this->checkmark_width;
107 void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
109 bool rtl = _current_text_dir == TD_RTL;
110 if (this->checked) {
111 DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK);
113 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);
118 * Drop down list entry for showing a company entry, with companies 'blob'.
120 class DropDownListCompanyItem : public DropDownListItem {
121 Dimension icon_size;
122 public:
123 bool greyed;
125 DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
127 this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
130 virtual ~DropDownListCompanyItem() {}
132 bool Selectable() const
134 return true;
137 uint Width() const
139 CompanyID company = (CompanyID)this->result;
140 SetDParam(0, company);
141 SetDParam(1, company);
142 return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3;
145 uint Height(uint width) const
147 return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
150 void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
152 CompanyID company = (CompanyID)this->result;
153 bool rtl = _current_text_dir == TD_RTL;
155 /* It's possible the company is deleted while the dropdown is open */
156 if (!Company::IsValidID(company)) return;
158 int icon_offset = (bottom - top - icon_size.height) / 2;
159 int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2;
161 DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset);
163 SetDParam(0, company);
164 SetDParam(1, company);
165 TextColour col;
166 if (this->greyed) {
167 col = (sel ? TC_SILVER : TC_GREY) | TC_NO_SHADE;
168 } else {
169 col = sel ? TC_WHITE : TC_BLACK;
171 DrawString(left + WD_FRAMERECT_LEFT + (rtl ? 0 : 3 + this->icon_size.width), right - WD_FRAMERECT_RIGHT - (rtl ? 3 + this->icon_size.width : 0), top + text_offset, STR_COMPANY_NAME_COMPANY_NUM, col);
176 * Pop up a generic text only menu.
177 * @param w Toolbar
178 * @param widget Toolbar button
179 * @param list List of items
180 * @param def Default item
182 static void PopupMainToolbMenu(Window *w, int widget, DropDownList *list, int def)
184 ShowDropDownList(w, list, def, widget, 0, true, true);
185 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
189 * Pop up a generic text only menu.
190 * @param w Toolbar
191 * @param widget Toolbar button
192 * @param string String for the first item in the menu
193 * @param count Number of items in the menu
195 static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count)
197 DropDownList *list = new DropDownList();
198 for (int i = 0; i < count; i++) {
199 *list->Append() = new DropDownListStringItem(string + i, i, false);
201 PopupMainToolbMenu(w, widget, list, 0);
204 /** Enum for the Company Toolbar's network related buttons */
205 static const int CTMN_CLIENT_LIST = -1; ///< Show the client list
206 static const int CTMN_NEW_COMPANY = -2; ///< Create a new company
207 static const int CTMN_SPECTATE = -3; ///< Become spectator
208 static const int CTMN_SPECTATOR = -4; ///< Show a company window as spectator
211 * Pop up a generic company list menu.
212 * @param w The toolbar window.
213 * @param widget The button widget id.
214 * @param grey A bitbask of which items to mark as disabled.
215 * @param include_spectator If true, a spectator option is included in the list.
217 static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0, bool include_spectator = false)
219 DropDownList *list = new DropDownList();
221 #ifdef ENABLE_NETWORK
222 if (_networking) {
223 if (widget == WID_TN_COMPANIES) {
224 /* Add the client list button for the companies menu */
225 *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false);
228 if (include_spectator) {
229 if (widget == WID_TN_COMPANIES) {
230 if (_local_company == COMPANY_SPECTATOR) {
231 *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached());
232 } else {
233 *list->Append() = new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached());
235 } else {
236 *list->Append() = new DropDownListStringItem(STR_NETWORK_TOOLBAR_LIST_SPECTATOR, CTMN_SPECTATOR, false);
240 #endif /* ENABLE_NETWORK */
242 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
243 if (!Company::IsValidID(c)) continue;
244 *list->Append() = new DropDownListCompanyItem(c, false, HasBit(grey, c));
247 PopupMainToolbMenu(w, widget, list, _local_company == COMPANY_SPECTATOR ? CTMN_CLIENT_LIST : (int)_local_company);
251 static ToolbarMode _toolbar_mode;
253 static CallBackFunction SelectSignTool()
255 if (_last_started_action == CBF_PLACE_SIGN) {
256 ResetObjectToPlace();
257 return CBF_NONE;
258 } else {
259 SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
260 return CBF_PLACE_SIGN;
264 /* --- Pausing --- */
266 static CallBackFunction ToolbarPauseClick(Window *w)
268 if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
270 if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) {
271 if (_settings_client.sound.confirm) SndPlayFx(SND_15_BEEP);
273 return CBF_NONE;
277 * Toggle fast forward mode.
279 * @param w Unused.
280 * @return #CBF_NONE
282 static CallBackFunction ToolbarFastForwardClick(Window *w)
284 _fast_forward ^= true;
285 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
286 return CBF_NONE;
290 * Game Option button menu entries.
292 enum OptionMenuEntries {
293 OME_GAMEOPTIONS,
294 OME_SETTINGS,
295 OME_SCRIPT_SETTINGS,
296 OME_NEWGRFSETTINGS,
297 OME_ZONING,
298 OME_TRANSPARENCIES,
299 OME_SHOW_TOWNNAMES,
300 OME_SHOW_STATIONNAMES,
301 OME_SHOW_WAYPOINTNAMES,
302 OME_SHOW_SIGNS,
303 OME_SHOW_COMPETITOR_SIGNS,
304 OME_FULL_ANIMATION,
305 OME_RAIL_FENCES,
306 OME_FULL_DETAILS,
307 OME_TRANSPARENTBUILDINGS,
308 OME_SHOW_STATIONSIGNS,
312 * Handle click on Options button in toolbar.
314 * @param w parent window the shown Drop down list is attached to.
315 * @return #CBF_NONE
317 static CallBackFunction ToolbarOptionsClick(Window *w)
319 DropDownList *list = new DropDownList();
320 *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS, OME_GAMEOPTIONS, false);
321 *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS_TREE, OME_SETTINGS, false);
322 /* Changes to the per-AI settings don't get send from the server to the clients. Clients get
323 * the settings once they join but never update it. As such don't show the window at all
324 * to network clients. */
325 if (!_networking || _network_server) *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false);
326 *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS, OME_NEWGRFSETTINGS, false);
327 *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_ZONING, OME_ZONING, false);
328 *list->Append() = new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS, OME_TRANSPARENCIES, false);
329 *list->Append() = new DropDownListItem(-1, false);
330 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED, OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES));
331 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES));
332 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED, OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES));
333 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED, OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS));
334 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS, OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS));
335 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION, OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION));
336 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_RAIL_FENCES, OME_RAIL_FENCES, false, HasBit(_display_opt, DO_RAIL_FENCES));
337 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL, OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL));
338 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS, OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES));
339 *list->Append() = new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS, OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS));
341 ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true);
342 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
343 return CBF_NONE;
347 * Handle click on one of the entries in the Options button menu.
349 * @param index Index being clicked.
350 * @return #CBF_NONE
352 static CallBackFunction MenuClickSettings(int index)
354 switch (index) {
355 case OME_GAMEOPTIONS: ShowGameOptions(); return CBF_NONE;
356 case OME_SETTINGS: ShowGameSettings(); return CBF_NONE;
357 case OME_SCRIPT_SETTINGS: ShowAIConfigWindow(); return CBF_NONE;
358 case OME_NEWGRFSETTINGS: ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
359 case OME_ZONING: ShowZoningToolbar(); break;
360 case OME_TRANSPARENCIES: ShowTransparencyToolbar(); break;
362 case OME_SHOW_TOWNNAMES: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES); break;
363 case OME_SHOW_STATIONNAMES: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break;
364 case OME_SHOW_WAYPOINTNAMES: ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break;
365 case OME_SHOW_SIGNS: ToggleBit(_display_opt, DO_SHOW_SIGNS); break;
366 case OME_SHOW_COMPETITOR_SIGNS:
367 ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
368 InvalidateWindowClassesData(WC_SIGN_LIST, -1);
369 break;
370 case OME_FULL_ANIMATION: ToggleBit(_display_opt, DO_FULL_ANIMATION); CheckBlitter(); break;
371 case OME_RAIL_FENCES: ToggleBit(_display_opt, DO_RAIL_FENCES); break;
372 case OME_FULL_DETAILS: ToggleBit(_display_opt, DO_FULL_DETAIL); break;
373 case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES); break;
374 case OME_SHOW_STATIONSIGNS: ToggleTransparency(TO_SIGNS); break;
376 MarkWholeScreenDirty();
377 return CBF_NONE;
381 * SaveLoad entries in scenario editor mode.
383 enum SaveLoadEditorMenuEntries {
384 SLEME_SAVE_SCENARIO = 0,
385 SLEME_LOAD_SCENARIO,
386 SLEME_SAVE_HEIGHTMAP,
387 SLEME_LOAD_HEIGHTMAP,
388 SLEME_EXIT_TOINTRO,
389 SLEME_EXIT_GAME = 6,
390 SLEME_MENUCOUNT,
394 * SaveLoad entries in normal game mode.
396 enum SaveLoadNormalMenuEntries {
397 SLNME_SAVE_GAME = 0,
398 SLNME_LOAD_GAME,
399 SLNME_EXIT_TOINTRO,
400 SLNME_EXIT_GAME = 4,
401 SLNME_MENUCOUNT,
405 * Handle click on Save button in toolbar in normal game mode.
407 * @param w parent window the shown save dialogue is attached to.
408 * @return #CBF_NONE
410 static CallBackFunction ToolbarSaveClick(Window *w)
412 PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT);
413 return CBF_NONE;
417 * Handle click on SaveLoad button in toolbar in the scenario editor.
419 * @param w parent window the shown save dialogue is attached to.
420 * @return #CBF_NONE
422 static CallBackFunction ToolbarScenSaveOrLoad(Window *w)
424 PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT);
425 return CBF_NONE;
429 * Handle click on one of the entries in the SaveLoad menu.
431 * @param index Index being clicked.
432 * @return #CBF_NONE
434 static CallBackFunction MenuClickSaveLoad(int index = 0)
436 if (_game_mode == GM_EDITOR) {
437 switch (index) {
438 case SLEME_SAVE_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_SAVE); break;
439 case SLEME_LOAD_SCENARIO: ShowSaveLoadDialog(FT_SCENARIO, SLO_LOAD); break;
440 case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_SAVE); break;
441 case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(FT_HEIGHTMAP,SLO_LOAD); break;
442 case SLEME_EXIT_TOINTRO: AskExitToGameMenu(); break;
443 case SLEME_EXIT_GAME: HandleExitGameRequest(); break;
445 } else {
446 switch (index) {
447 case SLNME_SAVE_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_SAVE); break;
448 case SLNME_LOAD_GAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
449 case SLNME_EXIT_TOINTRO: AskExitToGameMenu(); break;
450 case SLNME_EXIT_GAME: HandleExitGameRequest(); break;
453 return CBF_NONE;
456 /* --- Map button menu --- */
458 enum MapMenuEntries {
459 MME_SHOW_SMALLMAP = 0,
460 MME_SHOW_EXTRAVIEWPORTS,
461 MME_SHOW_LINKGRAPH,
462 MME_SHOW_SIGNLISTS,
463 MME_SHOW_TOWNDIRECTORY,
464 MME_SHOW_INDUSTRYDIRECTORY,
465 MME_SHOW_PLANS,
468 static CallBackFunction ToolbarMapClick(Window *w)
470 DropDownList *list = new DropDownList();
471 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false);
472 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false);
473 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_LINGRAPH_LEGEND, MME_SHOW_LINKGRAPH, false);
474 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false);
475 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_PLAN_LIST, MME_SHOW_PLANS, false);
476 PopupMainToolbMenu(w, WID_TN_SMALL_MAP, list, 0);
477 return CBF_NONE;
480 static CallBackFunction ToolbarScenMapTownDir(Window *w)
482 DropDownList *list = new DropDownList();
483 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_MAP_OF_WORLD, MME_SHOW_SMALLMAP, false);
484 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_EXTRA_VIEW_PORT, MME_SHOW_EXTRAVIEWPORTS, false);
485 *list->Append() = new DropDownListStringItem(STR_MAP_MENU_SIGN_LIST, MME_SHOW_SIGNLISTS, false);
486 *list->Append() = new DropDownListStringItem(STR_TOWN_MENU_TOWN_DIRECTORY, MME_SHOW_TOWNDIRECTORY, false);
487 *list->Append() = new DropDownListStringItem(STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, MME_SHOW_INDUSTRYDIRECTORY, false);
488 PopupMainToolbMenu(w, WID_TE_SMALL_MAP, list, 0);
489 return CBF_NONE;
493 * Handle click on one of the entries in the Map menu.
495 * @param index Index being clicked.
496 * @return #CBF_NONE
498 static CallBackFunction MenuClickMap(int index)
500 switch (index) {
501 case MME_SHOW_SMALLMAP: ShowSmallMap(); break;
502 case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewPortWindow(); break;
503 case MME_SHOW_LINKGRAPH: ShowLinkGraphLegend(); break;
504 case MME_SHOW_SIGNLISTS: ShowSignList(); break;
505 case MME_SHOW_TOWNDIRECTORY: ShowTownDirectory(); break;
506 case MME_SHOW_INDUSTRYDIRECTORY: ShowIndustryDirectory(); break;
507 case MME_SHOW_PLANS: ShowPlansWindow(); break;
509 return CBF_NONE;
512 /* --- Town button menu --- */
514 static CallBackFunction ToolbarTownClick(Window *w)
516 PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
517 return CBF_NONE;
521 * Handle click on one of the entries in the Town menu.
523 * @param index Index being clicked.
524 * @return #CBF_NONE
526 static CallBackFunction MenuClickTown(int index)
528 switch (index) {
529 case 0: ShowTownDirectory(); break;
530 case 1: // setting could be changed when the dropdown was open
531 if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
532 break;
534 return CBF_NONE;
537 /* --- Subidies button menu --- */
539 static CallBackFunction ToolbarSubsidiesClick(Window *w)
541 PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 1);
542 return CBF_NONE;
546 * Handle click on the entry in the Subsidies menu.
548 * @param index Unused.
549 * @return #CBF_NONE
551 static CallBackFunction MenuClickSubsidies(int index)
553 switch (index) {
554 case 0: ShowSubsidiesList(); break;
556 return CBF_NONE;
559 /* --- Stations button menu --- */
561 static CallBackFunction ToolbarStationsClick(Window *w)
563 PopupMainCompanyToolbMenu(w, WID_TN_STATIONS);
564 return CBF_NONE;
568 * Handle click on the entry in the Stations menu
570 * @param index CompanyID to show station list for
571 * @return #CBF_NONE
573 static CallBackFunction MenuClickStations(int index)
575 ShowCompanyStations((CompanyID)index);
576 return CBF_NONE;
579 /* --- Finances button menu --- */
581 static CallBackFunction ToolbarFinancesClick(Window *w)
583 PopupMainCompanyToolbMenu(w, WID_TN_FINANCES);
584 return CBF_NONE;
588 * Handle click on the entry in the finances overview menu.
590 * @param index CompanyID to show finances for.
591 * @return #CBF_NONE
593 static CallBackFunction MenuClickFinances(int index)
595 ShowCompanyFinances((CompanyID)index);
596 return CBF_NONE;
599 /* --- Company's button menu --- */
601 static CallBackFunction ToolbarCompaniesClick(Window *w)
603 PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES, 0, true);
604 return CBF_NONE;
608 * Handle click on the entry in the Company menu.
610 * @param index Menu entry to handle.
611 * @return #CBF_NONE
613 static CallBackFunction MenuClickCompany(int index)
615 #ifdef ENABLE_NETWORK
616 if (_networking) {
617 switch (index) {
618 case CTMN_CLIENT_LIST:
619 ShowClientList();
620 return CBF_NONE;
622 case CTMN_NEW_COMPANY:
623 if (_network_server) {
624 DoCommandP(0, 0, _network_own_client_id, CMD_COMPANY_CTRL);
625 } else {
626 NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, nullptr, nullptr, _local_company, 0);
628 return CBF_NONE;
630 case CTMN_SPECTATE:
631 if (_network_server) {
632 NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR);
633 MarkWholeScreenDirty();
634 } else {
635 NetworkClientRequestMove(COMPANY_SPECTATOR);
637 return CBF_NONE;
640 #endif /* ENABLE_NETWORK */
641 ShowCompany((CompanyID)index);
642 return CBF_NONE;
645 /* --- Story button menu --- */
647 static CallBackFunction ToolbarStoryClick(Window *w)
649 PopupMainCompanyToolbMenu(w, WID_TN_STORY, 0, true);
650 return CBF_NONE;
654 * Handle click on the entry in the Story menu
656 * @param index CompanyID to show story book for
657 * @return #CBF_NONE
659 static CallBackFunction MenuClickStory(int index)
661 ShowStoryBook(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
662 return CBF_NONE;
665 /* --- Goal button menu --- */
667 static CallBackFunction ToolbarGoalClick(Window *w)
669 PopupMainCompanyToolbMenu(w, WID_TN_GOAL, 0, true);
670 return CBF_NONE;
674 * Handle click on the entry in the Goal menu
676 * @param index CompanyID to show story book for
677 * @return #CBF_NONE
679 static CallBackFunction MenuClickGoal(int index)
681 ShowGoalsList(index == CTMN_SPECTATOR ? INVALID_COMPANY : (CompanyID)index);
682 return CBF_NONE;
685 /* --- Graphs button menu --- */
687 static CallBackFunction ToolbarGraphsClick(Window *w)
689 PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8);
690 return CBF_NONE;
694 * Handle click on the entry in the Graphs menu.
696 * @param index Graph to show.
697 * @return #CBF_NONE
699 static CallBackFunction MenuClickGraphs(int index)
701 switch (index) {
702 case 0: ShowOperatingProfitGraph(); break;
703 case 1: ShowIncomeGraph(); break;
704 case 2: ShowDeliveredCargoGraph(); break;
705 case 3: ShowPerformanceHistoryGraph(); break;
706 case 4: ShowCompanyValueGraph(); break;
707 case 5: ShowCargoPaymentRates(); break;
708 /* functions for combined graphs/league button */
709 case 6: ShowCompanyLeagueTable(); break;
710 case 7: ShowPerformanceRatingDetail(); break;
712 return CBF_NONE;
715 /* --- League button menu --- */
717 static CallBackFunction ToolbarLeagueClick(Window *w)
719 PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, _networking ? 2 : 3);
720 return CBF_NONE;
724 * Handle click on the entry in the CompanyLeague menu.
726 * @param index Menu entry number.
727 * @return #CBF_NONE
729 static CallBackFunction MenuClickLeague(int index)
731 switch (index) {
732 case 0: ShowCompanyLeagueTable(); break;
733 case 1: ShowPerformanceRatingDetail(); break;
734 case 2: ShowHighscoreTable(); break;
736 return CBF_NONE;
739 /* --- Industries button menu --- */
741 static CallBackFunction ToolbarIndustryClick(Window *w)
743 /* Disable build-industry menu if we are a spectator */
744 PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 2 : 3);
745 return CBF_NONE;
749 * Handle click on the entry in the Industry menu.
751 * @param index Menu entry number.
752 * @return #CBF_NONE
754 static CallBackFunction MenuClickIndustry(int index)
756 switch (index) {
757 case 0: ShowIndustryDirectory(); break;
758 case 1: ShowIndustryCargoesWindow(); break;
759 case 2: ShowBuildIndustryWindow(); break;
761 return CBF_NONE;
764 /* --- Trains button menu + 1 helper function for all vehicles. --- */
766 static void ToolbarVehicleClick(Window *w, VehicleType veh)
768 const Vehicle *v;
769 int dis = ~0;
771 FOR_ALL_VEHICLES(v) {
772 if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner);
774 PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis);
778 static CallBackFunction ToolbarTrainClick(Window *w)
780 ToolbarVehicleClick(w, VEH_TRAIN);
781 return CBF_NONE;
785 * Handle click on the entry in the Train menu.
787 * @param index CompanyID to show train list for.
788 * @return #CBF_NONE
790 static CallBackFunction MenuClickShowTrains(int index)
792 ShowVehicleListWindow((CompanyID)index, VEH_TRAIN);
793 return CBF_NONE;
796 /* --- Road vehicle button menu --- */
798 static CallBackFunction ToolbarRoadClick(Window *w)
800 ToolbarVehicleClick(w, VEH_ROAD);
801 return CBF_NONE;
805 * Handle click on the entry in the Road Vehicles menu.
807 * @param index CompanyID to show road vehicles list for.
808 * @return #CBF_NONE
810 static CallBackFunction MenuClickShowRoad(int index)
812 ShowVehicleListWindow((CompanyID)index, VEH_ROAD);
813 return CBF_NONE;
816 /* --- Ship button menu --- */
818 static CallBackFunction ToolbarShipClick(Window *w)
820 ToolbarVehicleClick(w, VEH_SHIP);
821 return CBF_NONE;
825 * Handle click on the entry in the Ships menu.
827 * @param index CompanyID to show ship list for.
828 * @return #CBF_NONE
830 static CallBackFunction MenuClickShowShips(int index)
832 ShowVehicleListWindow((CompanyID)index, VEH_SHIP);
833 return CBF_NONE;
836 /* --- Aircraft button menu --- */
838 static CallBackFunction ToolbarAirClick(Window *w)
840 ToolbarVehicleClick(w, VEH_AIRCRAFT);
841 return CBF_NONE;
845 * Handle click on the entry in the Aircraft menu.
847 * @param index CompanyID to show aircraft list for.
848 * @return #CBF_NONE
850 static CallBackFunction MenuClickShowAir(int index)
852 ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT);
853 return CBF_NONE;
856 /* --- Zoom in button --- */
858 static CallBackFunction ToolbarZoomInClick(Window *w)
860 if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
861 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN);
862 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
864 return CBF_NONE;
867 /* --- Zoom out button --- */
869 static CallBackFunction ToolbarZoomOutClick(Window *w)
871 if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
872 w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT);
873 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
875 return CBF_NONE;
878 /* --- Rail button menu --- */
880 static CallBackFunction ToolbarBuildRailClick(Window *w)
882 ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true);
883 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
884 return CBF_NONE;
888 * Handle click on the entry in the Build Rail menu.
890 * @param index RailType to show the build toolbar for.
891 * @return #CBF_NONE
893 static CallBackFunction MenuClickBuildRail(int index)
895 _last_built_railtype = (RailType)index;
896 ShowBuildRailToolbar(_last_built_railtype);
897 return CBF_NONE;
900 /* --- Road button menu --- */
902 static CallBackFunction ToolbarBuildRoadClick(Window *w)
904 const Company *c = Company::Get(_local_company);
905 DropDownList *list = new DropDownList();
907 /* Road is always visible and available. */
908 *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false);
910 /* Tram is only visible when there will be a tram, and available when that has been introduced. */
911 Engine *e;
912 FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
913 if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
914 if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
916 *list->Append() = new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM));
917 break;
919 ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true);
920 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
921 return CBF_NONE;
925 * Handle click on the entry in the Build Road menu.
927 * @param index RoadType to show the build toolbar for.
928 * @return #CBF_NONE
930 static CallBackFunction MenuClickBuildRoad(int index)
932 _last_built_roadtype = (RoadType)index;
933 ShowBuildRoadToolbar(_last_built_roadtype);
934 return CBF_NONE;
937 /* --- Water button menu --- */
939 static CallBackFunction ToolbarBuildWaterClick(Window *w)
941 PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1);
942 return CBF_NONE;
946 * Handle click on the entry in the Build Waterways menu.
948 * @param index Unused.
949 * @return #CBF_NONE
951 static CallBackFunction MenuClickBuildWater(int index)
953 ShowBuildDocksToolbar();
954 return CBF_NONE;
957 /* --- Airport button menu --- */
959 static CallBackFunction ToolbarBuildAirClick(Window *w)
961 PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1);
962 return CBF_NONE;
966 * Handle click on the entry in the Build Air menu.
968 * @param index Unused.
969 * @return #CBF_NONE
971 static CallBackFunction MenuClickBuildAir(int index)
973 ShowBuildAirToolbar();
974 return CBF_NONE;
977 /* --- Forest button menu --- */
979 static CallBackFunction ToolbarForestClick(Window *w)
981 PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3);
982 return CBF_NONE;
986 * Handle click on the entry in the landscaping menu.
988 * @param index Menu entry clicked.
989 * @return #CBF_NONE
991 static CallBackFunction MenuClickForest(int index)
993 switch (index) {
994 case 0: ShowTerraformToolbar(); break;
995 case 1: ShowBuildTreesToolbar(); break;
996 case 2: return SelectSignTool();
998 return CBF_NONE;
1001 /* --- Music button menu --- */
1003 static CallBackFunction ToolbarMusicClick(Window *w)
1005 PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1);
1006 return CBF_NONE;
1010 * Handle click on the entry in the Music menu.
1012 * @param index Unused.
1013 * @return #CBF_NONE
1015 static CallBackFunction MenuClickMusicWindow(int index)
1017 ShowMusicWindow();
1018 return CBF_NONE;
1021 /* --- Newspaper button menu --- */
1023 static CallBackFunction ToolbarNewspaperClick(Window *w)
1025 PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 2);
1026 return CBF_NONE;
1030 * Handle click on the entry in the Newspaper menu.
1032 * @param index Menu entry clicked.
1033 * @return #CBF_NONE
1035 static CallBackFunction MenuClickNewspaper(int index)
1037 switch (index) {
1038 case 0: ShowLastNewsMessage(); break;
1039 case 1: ShowMessageHistory(); break;
1041 return CBF_NONE;
1044 /* --- Help button menu --- */
1046 static CallBackFunction PlaceLandBlockInfo()
1048 if (_last_started_action == CBF_PLACE_LANDINFO) {
1049 ResetObjectToPlace();
1050 return CBF_NONE;
1051 } else {
1052 SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
1053 return CBF_PLACE_LANDINFO;
1057 static CallBackFunction ToolbarHelpClick(Window *w)
1059 PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 16 : 13);
1060 return CBF_NONE;
1063 static void MenuClickSmallScreenshot()
1065 MakeScreenshot(SC_VIEWPORT, nullptr);
1068 static void MenuClickFlatMinimapScreenshot(ScreenshotType type)
1070 MakeScreenshot(type, nullptr);
1074 * Callback on the confirmation window for huge screenshots.
1075 * @param w Window with viewport
1076 * @param confirmed true on confirmation
1078 static void ScreenshotConfirmCallback(Window *w, bool confirmed)
1080 if (confirmed) MakeScreenshot(_confirmed_screenshot_type, nullptr);
1084 * Make a screenshot of the world.
1085 * Ask for confirmation if the screenshot will be huge.
1086 * @param t Screenshot type: World or viewport screenshot
1088 static void MenuClickLargeWorldScreenshot(ScreenshotType t)
1090 ViewPort vp;
1091 SetupScreenshotViewport(t, &vp);
1092 if ((uint64)vp.width * (uint64)vp.height > 8192 * 8192) {
1093 /* Ask for confirmation */
1094 SetDParam(0, vp.width);
1095 SetDParam(1, vp.height);
1096 _confirmed_screenshot_type = t;
1097 ShowQuery(STR_WARNING_SCREENSHOT_SIZE_CAPTION, STR_WARNING_SCREENSHOT_SIZE_MESSAGE, nullptr, ScreenshotConfirmCallback);
1098 } else {
1099 /* Less than 64M pixels, just do it */
1100 MakeScreenshot(t, nullptr);
1105 * Toggle drawing of sprites' bounding boxes.
1106 * @note has only an effect when newgrf_developer_tools are active.
1108 * Function is found here and not in viewport.cpp in order to avoid
1109 * importing the settings structs to there.
1111 void ToggleBoundingBoxes()
1113 extern bool _draw_bounding_boxes;
1114 /* Always allow to toggle them off */
1115 if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) {
1116 _draw_bounding_boxes = !_draw_bounding_boxes;
1117 MarkWholeScreenDirty();
1122 * Toggle drawing of the dirty blocks.
1123 * @note has only an effect when newgrf_developer_tools are active.
1125 * Function is found here and not in viewport.cpp in order to avoid
1126 * importing the settings structs to there.
1128 void ToggleDirtyBlocks()
1130 extern bool _draw_dirty_blocks;
1131 /* Always allow to toggle them off */
1132 if (_settings_client.gui.newgrf_developer_tools || _draw_dirty_blocks) {
1133 _draw_dirty_blocks = !_draw_dirty_blocks;
1134 MarkWholeScreenDirty();
1139 * Set the starting year for a scenario.
1140 * @param year New starting year.
1142 void SetStartingYear(Year year)
1144 _settings_game.game_creation.starting_year = Clamp(year, MIN_YEAR, MAX_YEAR);
1145 Date new_date = ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1);
1146 /* If you open a savegame as scenario there may already be link graphs.*/
1147 LinkGraphSchedule::instance.ShiftDates(new_date - _date);
1148 SetDate(new_date, 0);
1152 * Choose the proper callback function for the main toolbar's help menu.
1153 * @param index The menu index which was selected.
1154 * @return CBF_NONE
1156 static CallBackFunction MenuClickHelp(int index)
1158 switch (index) {
1159 case 0: return PlaceLandBlockInfo();
1160 case 2: IConsoleSwitch(); break;
1161 case 3: ShowAIDebugWindow(); break;
1162 case 4: MenuClickSmallScreenshot(); break;
1163 case 5: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
1164 case 6: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
1165 case 7: MenuClickLargeWorldScreenshot(SC_WORLD); break;
1166 case 8: MenuClickFlatMinimapScreenshot(SC_MINIMAP); break;
1167 case 9: MenuClickFlatMinimapScreenshot(SC_MINI_HEIGHTMAP); break;
1168 case 10: MenuClickFlatMinimapScreenshot(SC_MINI_INDUSTRYMAP); break;
1169 case 11: MenuClickFlatMinimapScreenshot(SC_MINI_OWNERMAP); break;
1170 case 12: ShowAboutWindow(); break;
1171 case 13: ShowSpriteAlignerWindow(); break;
1172 case 14: ToggleBoundingBoxes(); break;
1173 case 15: ToggleDirtyBlocks(); break;
1175 return CBF_NONE;
1178 /* --- Switch toolbar button --- */
1180 static CallBackFunction ToolbarSwitchClick(Window *w)
1182 if (_toolbar_mode != TB_LOWER) {
1183 _toolbar_mode = TB_LOWER;
1184 } else {
1185 _toolbar_mode = TB_UPPER;
1188 w->ReInit();
1189 w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
1190 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1191 return CBF_NONE;
1194 /* --- Scenario editor specific handlers. */
1197 * Called when clicking at the date panel of the scenario editor toolbar.
1199 static CallBackFunction ToolbarScenDatePanel(Window *w)
1201 SetDParam(0, _settings_game.game_creation.starting_year);
1202 ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
1203 _left_button_clicked = false;
1204 return CBF_NONE;
1207 static CallBackFunction ToolbarScenDateBackward(Window *w)
1209 /* don't allow too fast scrolling */
1210 if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1211 w->HandleButtonClick(WID_TE_DATE_BACKWARD);
1212 w->SetDirty();
1214 SetStartingYear(_settings_game.game_creation.starting_year - 1);
1216 _left_button_clicked = false;
1217 return CBF_NONE;
1220 static CallBackFunction ToolbarScenDateForward(Window *w)
1222 /* don't allow too fast scrolling */
1223 if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
1224 w->HandleButtonClick(WID_TE_DATE_FORWARD);
1225 w->SetDirty();
1227 SetStartingYear(_settings_game.game_creation.starting_year + 1);
1229 _left_button_clicked = false;
1230 return CBF_NONE;
1233 static CallBackFunction ToolbarScenGenLand(Window *w)
1235 w->HandleButtonClick(WID_TE_LAND_GENERATE);
1236 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1238 ShowEditorTerraformToolbar();
1239 return CBF_NONE;
1243 static CallBackFunction ToolbarScenGenTown(Window *w)
1245 w->HandleButtonClick(WID_TE_TOWN_GENERATE);
1246 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1247 ShowFoundTownWindow();
1248 return CBF_NONE;
1251 static CallBackFunction ToolbarScenGenIndustry(Window *w)
1253 w->HandleButtonClick(WID_TE_INDUSTRY);
1254 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1255 ShowBuildIndustryWindow();
1256 return CBF_NONE;
1259 static CallBackFunction ToolbarScenBuildRoad(Window *w)
1261 w->HandleButtonClick(WID_TE_ROADS);
1262 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1263 ShowBuildRoadScenToolbar();
1264 return CBF_NONE;
1267 static CallBackFunction ToolbarScenBuildDocks(Window *w)
1269 w->HandleButtonClick(WID_TE_WATER);
1270 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1271 ShowBuildDocksScenToolbar();
1272 return CBF_NONE;
1275 static CallBackFunction ToolbarScenPlantTrees(Window *w)
1277 w->HandleButtonClick(WID_TE_TREES);
1278 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1279 ShowBuildTreesToolbar();
1280 return CBF_NONE;
1283 static CallBackFunction ToolbarScenPlaceSign(Window *w)
1285 w->HandleButtonClick(WID_TE_SIGNS);
1286 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1287 return SelectSignTool();
1290 static CallBackFunction ToolbarBtn_NULL(Window *w)
1292 return CBF_NONE;
1295 typedef CallBackFunction MenuClickedProc(int index);
1297 static MenuClickedProc * const _menu_clicked_procs[] = {
1298 nullptr, // 0
1299 nullptr, // 1
1300 MenuClickSettings, // 2
1301 MenuClickSaveLoad, // 3
1302 MenuClickMap, // 4
1303 MenuClickTown, // 5
1304 MenuClickSubsidies, // 6
1305 MenuClickStations, // 7
1306 MenuClickFinances, // 8
1307 MenuClickCompany, // 9
1308 MenuClickStory, // 10
1309 MenuClickGoal, // 11
1310 MenuClickGraphs, // 12
1311 MenuClickLeague, // 13
1312 MenuClickIndustry, // 14
1313 MenuClickShowTrains, // 15
1314 MenuClickShowRoad, // 16
1315 MenuClickShowShips, // 17
1316 MenuClickShowAir, // 18
1317 MenuClickMap, // 19
1318 nullptr, // 20
1319 MenuClickBuildRail, // 21
1320 MenuClickBuildRoad, // 22
1321 MenuClickBuildWater, // 23
1322 MenuClickBuildAir, // 24
1323 MenuClickForest, // 25
1324 MenuClickMusicWindow, // 26
1325 MenuClickNewspaper, // 27
1326 MenuClickHelp, // 28
1329 /** Full blown container to make it behave exactly as we want :) */
1330 class NWidgetToolbarContainer : public NWidgetContainer {
1331 bool visible[WID_TN_END]; ///< The visible headers
1332 protected:
1333 uint spacers; ///< Number of spacer widgets in this toolbar
1335 public:
1336 NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL)
1341 * Check whether the given widget type is a button for us.
1342 * @param type the widget type to check.
1343 * @return true if it is a button for us.
1345 bool IsButton(WidgetType type) const
1347 return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN;
1350 void SetupSmallestSize(Window *w, bool init_array)
1352 this->smallest_x = 0; // Biggest child
1353 this->smallest_y = 0; // Biggest child
1354 this->fill_x = 1;
1355 this->fill_y = 0;
1356 this->resize_x = 1; // We only resize in this direction
1357 this->resize_y = 0; // We never resize in this direction
1358 this->spacers = 0;
1360 uint nbuttons = 0;
1361 /* First initialise some variables... */
1362 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1363 child_wid->SetupSmallestSize(w, init_array);
1364 this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
1365 if (this->IsButton(child_wid->type)) {
1366 nbuttons++;
1367 this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
1368 } else if (child_wid->type == NWID_SPACER) {
1369 this->spacers++;
1373 /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */
1374 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1375 child_wid->current_y = this->smallest_y;
1376 if (!this->IsButton(child_wid->type)) {
1377 child_wid->current_x = child_wid->smallest_x;
1380 _toolbar_width = nbuttons * this->smallest_x;
1383 void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
1385 assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
1387 this->pos_x = x;
1388 this->pos_y = y;
1389 this->current_x = given_width;
1390 this->current_y = given_height;
1392 /* Figure out what are the visible buttons */
1393 memset(this->visible, 0, sizeof(this->visible));
1394 uint arrangable_count, button_count, spacer_count;
1395 const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count);
1396 for (uint i = 0; i < arrangable_count; i++) {
1397 this->visible[arrangement[i]] = true;
1400 /* Create us ourselves a quick lookup table */
1401 NWidgetBase *widgets[WID_TN_END];
1402 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1403 if (child_wid->type == NWID_SPACER) continue;
1404 widgets[((NWidgetCore*)child_wid)->index] = child_wid;
1407 /* Now assign the widgets to their rightful place */
1408 uint position = 0; // Place to put next child relative to origin of the container.
1409 uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets
1410 uint button_space = given_width - spacer_space; // Remaining spacing for the buttons
1411 uint spacer_i = 0;
1412 uint button_i = 0;
1414 /* Index into the arrangement indices. The macro lastof cannot be used here! */
1415 const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement;
1416 for (uint i = 0; i < arrangable_count; i++) {
1417 NWidgetBase *child_wid = widgets[*cur_wid];
1418 /* If we have to give space to the spacers, do that */
1419 if (spacer_space != 0) {
1420 NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev;
1421 if (possible_spacer != nullptr && possible_spacer->type == NWID_SPACER) {
1422 uint add = spacer_space / (spacer_count - spacer_i);
1423 position += add;
1424 spacer_space -= add;
1425 spacer_i++;
1429 /* Buttons can be scaled, the others not. */
1430 if (this->IsButton(child_wid->type)) {
1431 child_wid->current_x = button_space / (button_count - button_i);
1432 button_space -= child_wid->current_x;
1433 button_i++;
1435 child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
1436 position += child_wid->current_x;
1438 if (rtl) {
1439 cur_wid--;
1440 } else {
1441 cur_wid++;
1446 /* virtual */ void Draw(const Window *w)
1448 /* Draw brown-red toolbar bg. */
1449 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);
1450 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);
1452 bool rtl = _current_text_dir == TD_RTL;
1453 for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != nullptr; child_wid = rtl ? child_wid->prev : child_wid->next) {
1454 if (child_wid->type == NWID_SPACER) continue;
1455 if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1457 child_wid->Draw(w);
1461 /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y)
1463 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return nullptr;
1465 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1466 if (child_wid->type == NWID_SPACER) continue;
1467 if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
1469 NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
1470 if (nwid != nullptr) return nwid;
1472 return nullptr;
1476 * Get the arrangement of the buttons for the toolbar.
1477 * @param width the new width of the toolbar.
1478 * @param arrangable_count output of the number of visible items.
1479 * @param button_count output of the number of visible buttons.
1480 * @param spacer_count output of the number of spacers.
1481 * @return the button configuration.
1483 virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0;
1486 /** Container for the 'normal' main toolbar */
1487 class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
1488 /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
1490 static const uint SMALLEST_ARRANGEMENT = 14;
1491 static const uint BIGGEST_ARRANGEMENT = 20;
1493 /* The number of buttons of each row of the toolbar should match the number of items which we want to be visible.
1494 * The total number of buttons should be equal to arrangable_count * 2.
1495 * No bad things happen, but we could see strange behaviours if we have buttons < (arrangable_count * 2) like a
1496 * pause button appearing on the right of the lower toolbar and weird resizing of the widgets even if there is
1497 * enough space.
1499 static const byte arrange14[] = {
1500 WID_TN_PAUSE,
1501 WID_TN_FAST_FORWARD,
1502 WID_TN_TRAINS,
1503 WID_TN_ROADVEHS,
1504 WID_TN_SHIPS,
1505 WID_TN_AIRCRAFTS,
1506 WID_TN_ZOOM_IN,
1507 WID_TN_ZOOM_OUT,
1508 WID_TN_RAILS,
1509 WID_TN_ROADS,
1510 WID_TN_WATER,
1511 WID_TN_AIR,
1512 WID_TN_LANDSCAPE,
1513 WID_TN_SWITCH_BAR,
1514 // lower toolbar
1515 WID_TN_SETTINGS,
1516 WID_TN_SAVE,
1517 WID_TN_SMALL_MAP,
1518 WID_TN_TOWNS,
1519 WID_TN_SUBSIDIES,
1520 WID_TN_STATIONS,
1521 WID_TN_FINANCES,
1522 WID_TN_COMPANIES,
1523 WID_TN_GRAPHS,
1524 WID_TN_INDUSTRIES,
1525 WID_TN_MUSIC_SOUND,
1526 WID_TN_MESSAGES,
1527 WID_TN_HELP,
1528 WID_TN_SWITCH_BAR,
1530 static const byte arrange15[] = {
1531 WID_TN_PAUSE,
1532 WID_TN_FAST_FORWARD,
1533 WID_TN_SMALL_MAP,
1534 WID_TN_TRAINS,
1535 WID_TN_ROADVEHS,
1536 WID_TN_SHIPS,
1537 WID_TN_AIRCRAFTS,
1538 WID_TN_RAILS,
1539 WID_TN_ROADS,
1540 WID_TN_WATER,
1541 WID_TN_AIR,
1542 WID_TN_LANDSCAPE,
1543 WID_TN_ZOOM_IN,
1544 WID_TN_ZOOM_OUT,
1545 WID_TN_SWITCH_BAR,
1546 // lower toolbar
1547 WID_TN_PAUSE,
1548 WID_TN_SETTINGS,
1549 WID_TN_SMALL_MAP,
1550 WID_TN_SAVE,
1551 WID_TN_TOWNS,
1552 WID_TN_SUBSIDIES,
1553 WID_TN_STATIONS,
1554 WID_TN_FINANCES,
1555 WID_TN_COMPANIES,
1556 WID_TN_GRAPHS,
1557 WID_TN_INDUSTRIES,
1558 WID_TN_MUSIC_SOUND,
1559 WID_TN_MESSAGES,
1560 WID_TN_HELP,
1561 WID_TN_SWITCH_BAR,
1563 static const byte arrange16[] = {
1564 WID_TN_PAUSE,
1565 WID_TN_FAST_FORWARD,
1566 WID_TN_SETTINGS,
1567 WID_TN_SMALL_MAP,
1568 WID_TN_TRAINS,
1569 WID_TN_ROADVEHS,
1570 WID_TN_SHIPS,
1571 WID_TN_AIRCRAFTS,
1572 WID_TN_RAILS,
1573 WID_TN_ROADS,
1574 WID_TN_WATER,
1575 WID_TN_AIR,
1576 WID_TN_LANDSCAPE,
1577 WID_TN_ZOOM_IN,
1578 WID_TN_ZOOM_OUT,
1579 WID_TN_SWITCH_BAR,
1580 // lower toolbar
1581 WID_TN_PAUSE,
1582 WID_TN_FAST_FORWARD,
1583 WID_TN_SAVE,
1584 WID_TN_TOWNS,
1585 WID_TN_SUBSIDIES,
1586 WID_TN_STATIONS,
1587 WID_TN_FINANCES,
1588 WID_TN_COMPANIES,
1589 WID_TN_GRAPHS,
1590 WID_TN_INDUSTRIES,
1591 WID_TN_MUSIC_SOUND,
1592 WID_TN_MESSAGES,
1593 WID_TN_HELP,
1594 WID_TN_ZOOM_IN,
1595 WID_TN_ZOOM_OUT,
1596 WID_TN_SWITCH_BAR,
1598 static const byte arrange17[] = {
1599 WID_TN_PAUSE,
1600 WID_TN_FAST_FORWARD,
1601 WID_TN_SETTINGS,
1602 WID_TN_SMALL_MAP,
1603 WID_TN_SUBSIDIES,
1604 WID_TN_TRAINS,
1605 WID_TN_ROADVEHS,
1606 WID_TN_SHIPS,
1607 WID_TN_AIRCRAFTS,
1608 WID_TN_RAILS,
1609 WID_TN_ROADS,
1610 WID_TN_WATER,
1611 WID_TN_AIR,
1612 WID_TN_LANDSCAPE,
1613 WID_TN_ZOOM_IN,
1614 WID_TN_ZOOM_OUT,
1615 WID_TN_SWITCH_BAR,
1616 // lower toolbar
1617 WID_TN_PAUSE,
1618 WID_TN_FAST_FORWARD,
1619 WID_TN_SAVE,
1620 WID_TN_SMALL_MAP,
1621 WID_TN_SUBSIDIES,
1622 WID_TN_TOWNS,
1623 WID_TN_STATIONS,
1624 WID_TN_FINANCES,
1625 WID_TN_COMPANIES,
1626 WID_TN_GRAPHS,
1627 WID_TN_INDUSTRIES,
1628 WID_TN_MUSIC_SOUND,
1629 WID_TN_MESSAGES,
1630 WID_TN_HELP,
1631 WID_TN_ZOOM_IN,
1632 WID_TN_ZOOM_OUT,
1633 WID_TN_SWITCH_BAR,
1635 static const byte arrange18[] = {
1636 WID_TN_PAUSE,
1637 WID_TN_FAST_FORWARD,
1638 WID_TN_SETTINGS,
1639 WID_TN_SMALL_MAP,
1640 WID_TN_TOWNS,
1641 WID_TN_SUBSIDIES,
1642 WID_TN_STATIONS,
1643 WID_TN_FINANCES,
1644 WID_TN_COMPANIES,
1645 WID_TN_INDUSTRIES,
1646 WID_TN_RAILS,
1647 WID_TN_ROADS,
1648 WID_TN_WATER,
1649 WID_TN_AIR,
1650 WID_TN_LANDSCAPE,
1651 WID_TN_ZOOM_IN,
1652 WID_TN_ZOOM_OUT,
1653 WID_TN_SWITCH_BAR,
1654 // lower toolbar
1655 WID_TN_PAUSE,
1656 WID_TN_FAST_FORWARD,
1657 WID_TN_SAVE,
1658 WID_TN_SMALL_MAP,
1659 WID_TN_TOWNS,
1660 WID_TN_SUBSIDIES,
1661 WID_TN_STATIONS,
1662 WID_TN_GRAPHS,
1663 WID_TN_TRAINS,
1664 WID_TN_ROADVEHS,
1665 WID_TN_SHIPS,
1666 WID_TN_AIRCRAFTS,
1667 WID_TN_MUSIC_SOUND,
1668 WID_TN_MESSAGES,
1669 WID_TN_HELP,
1670 WID_TN_ZOOM_IN,
1671 WID_TN_ZOOM_OUT,
1672 WID_TN_SWITCH_BAR,
1674 static const byte arrange19[] = {
1675 WID_TN_PAUSE,
1676 WID_TN_FAST_FORWARD,
1677 WID_TN_SETTINGS,
1678 WID_TN_SMALL_MAP,
1679 WID_TN_TOWNS,
1680 WID_TN_SUBSIDIES,
1681 WID_TN_TRAINS,
1682 WID_TN_ROADVEHS,
1683 WID_TN_SHIPS,
1684 WID_TN_AIRCRAFTS,
1685 WID_TN_RAILS,
1686 WID_TN_ROADS,
1687 WID_TN_WATER,
1688 WID_TN_AIR,
1689 WID_TN_LANDSCAPE,
1690 WID_TN_MUSIC_SOUND,
1691 WID_TN_ZOOM_IN,
1692 WID_TN_ZOOM_OUT,
1693 WID_TN_SWITCH_BAR,
1694 // lower toolbar
1695 WID_TN_PAUSE,
1696 WID_TN_FAST_FORWARD,
1697 WID_TN_SAVE,
1698 WID_TN_SMALL_MAP,
1699 WID_TN_STATIONS,
1700 WID_TN_FINANCES,
1701 WID_TN_COMPANIES,
1702 WID_TN_GRAPHS,
1703 WID_TN_INDUSTRIES,
1704 WID_TN_MESSAGES,
1705 WID_TN_RAILS,
1706 WID_TN_ROADS,
1707 WID_TN_WATER,
1708 WID_TN_AIR,
1709 WID_TN_LANDSCAPE,
1710 WID_TN_HELP,
1711 WID_TN_ZOOM_IN,
1712 WID_TN_ZOOM_OUT,
1713 WID_TN_SWITCH_BAR,
1715 static const byte arrange20[] = {
1716 WID_TN_PAUSE,
1717 WID_TN_FAST_FORWARD,
1718 WID_TN_SETTINGS,
1719 WID_TN_SMALL_MAP,
1720 WID_TN_TOWNS,
1721 WID_TN_SUBSIDIES,
1722 WID_TN_TRAINS,
1723 WID_TN_ROADVEHS,
1724 WID_TN_SHIPS,
1725 WID_TN_AIRCRAFTS,
1726 WID_TN_RAILS,
1727 WID_TN_ROADS,
1728 WID_TN_WATER,
1729 WID_TN_AIR,
1730 WID_TN_LANDSCAPE,
1731 WID_TN_MUSIC_SOUND,
1732 WID_TN_GOAL,
1733 WID_TN_ZOOM_IN,
1734 WID_TN_ZOOM_OUT,
1735 WID_TN_SWITCH_BAR,
1736 // lower toolbar
1737 WID_TN_PAUSE,
1738 WID_TN_FAST_FORWARD,
1739 WID_TN_SAVE,
1740 WID_TN_SMALL_MAP,
1741 WID_TN_STATIONS,
1742 WID_TN_FINANCES,
1743 WID_TN_COMPANIES,
1744 WID_TN_GRAPHS,
1745 WID_TN_INDUSTRIES,
1746 WID_TN_MESSAGES,
1747 WID_TN_RAILS,
1748 WID_TN_ROADS,
1749 WID_TN_WATER,
1750 WID_TN_AIR,
1751 WID_TN_LANDSCAPE,
1752 WID_TN_STORY,
1753 WID_TN_HELP,
1754 WID_TN_ZOOM_IN,
1755 WID_TN_ZOOM_OUT,
1756 WID_TN_SWITCH_BAR,
1758 static const byte arrange_all[] = {
1759 WID_TN_PAUSE,
1760 WID_TN_FAST_FORWARD,
1761 WID_TN_SETTINGS,
1762 WID_TN_SAVE,
1763 WID_TN_SMALL_MAP,
1764 WID_TN_TOWNS,
1765 WID_TN_SUBSIDIES,
1766 WID_TN_STATIONS,
1767 WID_TN_FINANCES,
1768 WID_TN_COMPANIES,
1769 WID_TN_STORY,
1770 WID_TN_GOAL,
1771 WID_TN_GRAPHS,
1772 WID_TN_LEAGUE,
1773 WID_TN_INDUSTRIES,
1774 WID_TN_TRAINS,
1775 WID_TN_ROADVEHS,
1776 WID_TN_SHIPS,
1777 WID_TN_AIRCRAFTS,
1778 WID_TN_ZOOM_IN,
1779 WID_TN_ZOOM_OUT,
1780 WID_TN_RAILS,
1781 WID_TN_ROADS,
1782 WID_TN_WATER,
1783 WID_TN_AIR,
1784 WID_TN_LANDSCAPE,
1785 WID_TN_MUSIC_SOUND,
1786 WID_TN_MESSAGES,
1787 WID_TN_HELP
1790 /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
1791 uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
1792 if (full_buttons > BIGGEST_ARRANGEMENT) {
1793 button_count = arrangable_count = lengthof(arrange_all);
1794 spacer_count = this->spacers;
1795 return arrange_all;
1798 /* Introduce the split toolbar */
1799 static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19, arrange20 };
1801 button_count = arrangable_count = full_buttons;
1802 spacer_count = this->spacers;
1803 return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
1807 /** Container for the scenario editor's toolbar */
1808 class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer {
1809 uint panel_widths[2]; ///< The width of the two panels (the text panel and date panel)
1811 void SetupSmallestSize(Window *w, bool init_array)
1813 this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array);
1815 /* Find the size of panel_widths */
1816 uint i = 0;
1817 for (NWidgetBase *child_wid = this->head; child_wid != nullptr; child_wid = child_wid->next) {
1818 if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
1820 assert(i < lengthof(this->panel_widths));
1821 this->panel_widths[i++] = child_wid->current_x;
1822 _toolbar_width += child_wid->current_x;
1826 /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
1828 static const byte arrange_all[] = {
1829 WID_TE_PAUSE,
1830 WID_TE_FAST_FORWARD,
1831 WID_TE_SETTINGS,
1832 WID_TE_SAVE,
1833 WID_TE_SPACER,
1834 WID_TE_DATE_PANEL,
1835 WID_TE_SMALL_MAP,
1836 WID_TE_ZOOM_IN,
1837 WID_TE_ZOOM_OUT,
1838 WID_TE_LAND_GENERATE,
1839 WID_TE_TOWN_GENERATE,
1840 WID_TE_INDUSTRY,
1841 WID_TE_ROADS,
1842 WID_TE_WATER,
1843 WID_TE_TREES,
1844 WID_TE_SIGNS,
1845 WID_TE_MUSIC_SOUND,
1846 WID_TE_HELP,
1848 static const byte arrange_nopanel[] = {
1849 WID_TE_PAUSE,
1850 WID_TE_FAST_FORWARD,
1851 WID_TE_SETTINGS,
1852 WID_TE_SAVE,
1853 WID_TE_DATE_PANEL,
1854 WID_TE_SMALL_MAP,
1855 WID_TE_ZOOM_IN,
1856 WID_TE_ZOOM_OUT,
1857 WID_TE_LAND_GENERATE,
1858 WID_TE_TOWN_GENERATE,
1859 WID_TE_INDUSTRY,
1860 WID_TE_ROADS,
1861 WID_TE_WATER,
1862 WID_TE_TREES,
1863 WID_TE_SIGNS,
1864 WID_TE_MUSIC_SOUND,
1865 WID_TE_HELP,
1867 static const byte arrange_switch[] = {
1868 WID_TE_DATE_PANEL,
1869 WID_TE_SMALL_MAP,
1870 WID_TE_LAND_GENERATE,
1871 WID_TE_TOWN_GENERATE,
1872 WID_TE_INDUSTRY,
1873 WID_TE_ROADS,
1874 WID_TE_WATER,
1875 WID_TE_TREES,
1876 WID_TE_SIGNS,
1877 WID_TE_SWITCH_BAR,
1878 // lower toolbar
1879 WID_TE_PAUSE,
1880 WID_TE_FAST_FORWARD,
1881 WID_TE_SETTINGS,
1882 WID_TE_SAVE,
1883 WID_TE_DATE_PANEL,
1884 WID_TE_ZOOM_IN,
1885 WID_TE_ZOOM_OUT,
1886 WID_TE_MUSIC_SOUND,
1887 WID_TE_HELP, WID_TE_SWITCH_BAR,
1890 /* If we can place all buttons *and* the panels, show them. */
1891 uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
1892 if (width >= min_full_width) {
1893 width -= this->panel_widths[0] + this->panel_widths[1];
1894 arrangable_count = lengthof(arrange_all);
1895 button_count = arrangable_count - 2;
1896 spacer_count = this->spacers;
1897 return arrange_all;
1900 /* 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 */
1901 uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
1902 if (width > min_small_width) {
1903 width -= this->panel_widths[1];
1904 arrangable_count = lengthof(arrange_nopanel);
1905 button_count = arrangable_count - 1;
1906 spacer_count = this->spacers - 1;
1907 return arrange_nopanel;
1910 /* Split toolbar */
1911 width -= this->panel_widths[1];
1912 arrangable_count = lengthof(arrange_switch) / 2;
1913 button_count = arrangable_count - 1;
1914 spacer_count = 0;
1915 return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
1919 /* --- Toolbar handling for the 'normal' case */
1921 typedef CallBackFunction ToolbarButtonProc(Window *w);
1923 static ToolbarButtonProc * const _toolbar_button_procs[] = {
1924 ToolbarPauseClick,
1925 ToolbarFastForwardClick,
1926 ToolbarOptionsClick,
1927 ToolbarSaveClick,
1928 ToolbarMapClick,
1929 ToolbarTownClick,
1930 ToolbarSubsidiesClick,
1931 ToolbarStationsClick,
1932 ToolbarFinancesClick,
1933 ToolbarCompaniesClick,
1934 ToolbarStoryClick,
1935 ToolbarGoalClick,
1936 ToolbarGraphsClick,
1937 ToolbarLeagueClick,
1938 ToolbarIndustryClick,
1939 ToolbarTrainClick,
1940 ToolbarRoadClick,
1941 ToolbarShipClick,
1942 ToolbarAirClick,
1943 ToolbarZoomInClick,
1944 ToolbarZoomOutClick,
1945 ToolbarBuildRailClick,
1946 ToolbarBuildRoadClick,
1947 ToolbarBuildWaterClick,
1948 ToolbarBuildAirClick,
1949 ToolbarForestClick,
1950 ToolbarMusicClick,
1951 ToolbarNewspaperClick,
1952 ToolbarHelpClick,
1953 ToolbarSwitchClick,
1956 enum MainToolbarHotkeys {
1957 MTHK_PAUSE,
1958 MTHK_FASTFORWARD,
1959 MTHK_SETTINGS,
1960 MTHK_SAVEGAME,
1961 MTHK_LOADGAME,
1962 MTHK_SMALLMAP,
1963 MTHK_TOWNDIRECTORY,
1964 MTHK_SUBSIDIES,
1965 MTHK_STATIONS,
1966 MTHK_FINANCES,
1967 MTHK_COMPANIES,
1968 MTHK_STORY,
1969 MTHK_GOAL,
1970 MTHK_GRAPHS,
1971 MTHK_LEAGUE,
1972 MTHK_INDUSTRIES,
1973 MTHK_TRAIN_LIST,
1974 MTHK_ROADVEH_LIST,
1975 MTHK_SHIP_LIST,
1976 MTHK_AIRCRAFT_LIST,
1977 MTHK_ZOOM_IN,
1978 MTHK_ZOOM_OUT,
1979 MTHK_BUILD_RAIL,
1980 MTHK_BUILD_ROAD,
1981 MTHK_BUILD_DOCKS,
1982 MTHK_BUILD_AIRPORT,
1983 MTHK_BUILD_TREES,
1984 MTHK_MUSIC,
1985 MTHK_AI_DEBUG,
1986 MTHK_SMALL_SCREENSHOT,
1987 MTHK_ZOOMEDIN_SCREENSHOT,
1988 MTHK_DEFAULTZOOM_SCREENSHOT,
1989 MTHK_GIANT_SCREENSHOT,
1990 MTHK_CHEATS,
1991 MTHK_TERRAFORM,
1992 MTHK_EXTRA_VIEWPORT,
1993 MTHK_CLIENT_LIST,
1994 MTHK_SIGN_LIST,
1995 MTHK_PLAN_LIST,
1998 /** Main toolbar. */
1999 struct MainToolbarWindow : Window {
2000 MainToolbarWindow(WindowDesc *desc) : Window(desc)
2002 this->InitNested(0);
2004 _last_started_action = CBF_NONE;
2005 CLRBITS(this->flags, WF_WHITE_BORDER);
2006 this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
2007 this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
2008 PositionMainToolbar(this);
2009 DoZoomInOutWindow(ZOOM_NONE, this);
2012 virtual void FindWindowPlacementAndResize(int def_width, int def_height)
2014 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
2017 virtual void OnPaint()
2019 /* If spectator, disable all construction buttons
2020 * ie : Build road, rail, ships, airports and landscaping
2021 * Since enabled state is the default, just disable when needed */
2022 this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END);
2023 /* disable company list drop downs, if there are no companies */
2024 this->SetWidgetsDisabledState(Company::GetNumItems() == 0, WID_TN_STATIONS, WID_TN_FINANCES, WID_TN_TRAINS, WID_TN_ROADVEHS, WID_TN_SHIPS, WID_TN_AIRCRAFTS, WIDGET_LIST_END);
2026 this->SetWidgetDisabledState(WID_TN_GOAL, Goal::GetNumItems() == 0);
2027 this->SetWidgetDisabledState(WID_TN_STORY, StoryPage::GetNumItems() == 0);
2029 this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN));
2030 this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
2032 this->DrawWidgets();
2035 virtual void OnClick(Point pt, int widget, int click_count)
2037 if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
2040 virtual void OnDropdownSelect(int widget, int index)
2042 CallBackFunction cbf = _menu_clicked_procs[widget](index);
2043 if (cbf != CBF_NONE) _last_started_action = cbf;
2046 virtual EventState OnHotkey(int hotkey)
2048 switch (hotkey) {
2049 case MTHK_PAUSE: ToolbarPauseClick(this); break;
2050 case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2051 case MTHK_SETTINGS: ShowGameOptions(); break;
2052 case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
2053 case MTHK_LOADGAME: ShowSaveLoadDialog(FT_SAVEGAME, SLO_LOAD); break;
2054 case MTHK_SMALLMAP: ShowSmallMap(); break;
2055 case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
2056 case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
2057 case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
2058 case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
2059 case MTHK_COMPANIES: ShowCompany(_local_company); break;
2060 case MTHK_STORY: ShowStoryBook(_local_company); break;
2061 case MTHK_GOAL: ShowGoalsList(_local_company); break;
2062 case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
2063 case MTHK_LEAGUE: ShowCompanyLeagueTable(); break;
2064 case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
2065 case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
2066 case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
2067 case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
2068 case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
2069 case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2070 case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2071 case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break;
2072 case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
2073 case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
2074 case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
2075 case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
2076 case MTHK_MUSIC: ShowMusicWindow(); break;
2077 case MTHK_AI_DEBUG: ShowAIDebugWindow(); break;
2078 case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
2079 case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
2080 case MTHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
2081 case MTHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
2082 case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
2083 case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
2084 case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
2085 #ifdef ENABLE_NETWORK
2086 case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
2087 #endif
2088 case MTHK_SIGN_LIST: ShowSignList(); break;
2089 case MTHK_PLAN_LIST: ShowPlansWindow(); break;
2090 default: return ES_NOT_HANDLED;
2092 return ES_HANDLED;
2095 virtual void OnPlaceObject(Point pt, TileIndex tile)
2097 switch (_last_started_action) {
2098 case CBF_PLACE_SIGN:
2099 PlaceProc_Sign(tile);
2100 break;
2102 case CBF_PLACE_LANDINFO:
2103 ShowLandInfo(tile);
2104 break;
2106 default: NOT_REACHED();
2110 virtual void OnPlaceObjectAbort()
2112 _last_started_action = CBF_NONE;
2115 virtual void OnTick()
2117 if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
2118 this->ToggleWidgetLoweredState(WID_TN_PAUSE);
2119 this->SetWidgetDirty(WID_TN_PAUSE);
2122 if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) {
2123 this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD);
2124 this->SetWidgetDirty(WID_TN_FAST_FORWARD);
2128 virtual void OnTimeout()
2130 /* We do not want to automatically raise the pause, fast forward and
2131 * switchbar buttons; they have to stay down when pressed etc. */
2132 for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
2133 if (this->IsWidgetLowered(i)) {
2134 this->RaiseWidget(i);
2135 this->SetWidgetDirty(i);
2141 * Some data on this window has become invalid.
2142 * @param data Information about the changed data.
2143 * @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.
2145 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2147 if (!gui_scope) return;
2148 if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
2151 static HotkeyList hotkeys;
2154 const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0};
2155 const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0};
2156 const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0};
2157 const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0};
2159 static Hotkey maintoolbar_hotkeys[] = {
2160 Hotkey(_maintoolbar_pause_keys, "pause", MTHK_PAUSE),
2161 Hotkey((uint16)0, "fastforward", MTHK_FASTFORWARD),
2162 Hotkey(WKC_F2, "settings", MTHK_SETTINGS),
2163 Hotkey(WKC_F3, "saveload", MTHK_SAVEGAME),
2164 Hotkey((uint16)0, "load_game", MTHK_LOADGAME),
2165 Hotkey(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP),
2166 Hotkey(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
2167 Hotkey(WKC_F6, "subsidies", MTHK_SUBSIDIES),
2168 Hotkey(WKC_F7, "station_list", MTHK_STATIONS),
2169 Hotkey(WKC_F8, "finances", MTHK_FINANCES),
2170 Hotkey(WKC_F9, "companies", MTHK_COMPANIES),
2171 Hotkey((uint16)0, "story_book", MTHK_STORY),
2172 Hotkey((uint16)0, "goal_list", MTHK_GOAL),
2173 Hotkey(WKC_F10, "graphs", MTHK_GRAPHS),
2174 Hotkey(WKC_F11, "league", MTHK_LEAGUE),
2175 Hotkey(WKC_F12, "industry_list", MTHK_INDUSTRIES),
2176 Hotkey(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
2177 Hotkey(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
2178 Hotkey(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
2179 Hotkey(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
2180 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN),
2181 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT),
2182 Hotkey(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
2183 Hotkey(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
2184 Hotkey(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
2185 Hotkey(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
2186 Hotkey(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
2187 Hotkey(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
2188 Hotkey((uint16)0, "ai_debug", MTHK_AI_DEBUG),
2189 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
2190 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
2191 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTHK_DEFAULTZOOM_SCREENSHOT),
2192 Hotkey((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
2193 Hotkey(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
2194 Hotkey('L', "terraform", MTHK_TERRAFORM),
2195 Hotkey('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
2196 #ifdef ENABLE_NETWORK
2197 Hotkey((uint16)0, "client_list", MTHK_CLIENT_LIST),
2198 #endif
2199 Hotkey((uint16)0, "sign_list", MTHK_SIGN_LIST),
2200 Hotkey('P', "plan_list", MTHK_PLAN_LIST),
2201 HOTKEY_LIST_END
2203 HotkeyList MainToolbarWindow::hotkeys("maintoolbar", maintoolbar_hotkeys);
2205 static NWidgetBase *MakeMainToolbar(int *biggest_index)
2207 /** Sprites to use for the different toolbar buttons */
2208 static const SpriteID toolbar_button_sprites[] = {
2209 SPR_IMG_PAUSE, // WID_TN_PAUSE
2210 SPR_IMG_FASTFORWARD, // WID_TN_FAST_FORWARD
2211 SPR_IMG_SETTINGS, // WID_TN_SETTINGS
2212 SPR_IMG_SAVE, // WID_TN_SAVE
2213 SPR_IMG_SMALLMAP, // WID_TN_SMALL_MAP
2214 SPR_IMG_TOWN, // WID_TN_TOWNS
2215 SPR_IMG_SUBSIDIES, // WID_TN_SUBSIDIES
2216 SPR_IMG_COMPANY_LIST, // WID_TN_STATIONS
2217 SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
2218 SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
2219 SPR_IMG_STORY_BOOK, // WID_TN_STORY
2220 SPR_IMG_GOAL, // WID_TN_GOAL
2221 SPR_IMG_GRAPHS, // WID_TN_GRAPHS
2222 SPR_IMG_COMPANY_LEAGUE, // WID_TN_LEAGUE
2223 SPR_IMG_INDUSTRY, // WID_TN_INDUSTRIES
2224 SPR_IMG_TRAINLIST, // WID_TN_TRAINS
2225 SPR_IMG_TRUCKLIST, // WID_TN_ROADVEHS
2226 SPR_IMG_SHIPLIST, // WID_TN_SHIPS
2227 SPR_IMG_AIRPLANESLIST, // WID_TN_AIRCRAFT
2228 SPR_IMG_ZOOMIN, // WID_TN_ZOOMIN
2229 SPR_IMG_ZOOMOUT, // WID_TN_ZOOMOUT
2230 SPR_IMG_BUILDRAIL, // WID_TN_RAILS
2231 SPR_IMG_BUILDROAD, // WID_TN_ROADS
2232 SPR_IMG_BUILDWATER, // WID_TN_WATER
2233 SPR_IMG_BUILDAIR, // WID_TN_AIR
2234 SPR_IMG_LANDSCAPING, // WID_TN_LANDSCAPE
2235 SPR_IMG_MUSIC, // WID_TN_MUSIC_SOUND
2236 SPR_IMG_MESSAGES, // WID_TN_MESSAGES
2237 SPR_IMG_QUERY, // WID_TN_HELP
2238 SPR_IMG_SWITCH_TOOLBAR, // WID_TN_SWITCH_BAR
2241 NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
2242 for (uint i = 0; i < WID_TN_END; i++) {
2243 switch (i) {
2244 case WID_TN_SMALL_MAP:
2245 case WID_TN_FINANCES:
2246 case WID_TN_VEHICLE_START:
2247 case WID_TN_ZOOM_IN:
2248 case WID_TN_BUILDING_TOOLS_START:
2249 case WID_TN_MUSIC_SOUND:
2250 hor->Add(new NWidgetSpacer(0, 0));
2251 break;
2253 hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i));
2256 *biggest_index = max<int>(*biggest_index, WID_TN_SWITCH_BAR);
2257 return hor;
2260 static const NWidgetPart _nested_toolbar_normal_widgets[] = {
2261 NWidgetFunction(MakeMainToolbar),
2264 static WindowDesc _toolb_normal_desc(
2265 WDP_MANUAL, nullptr, 0, 0,
2266 WC_MAIN_TOOLBAR, WC_NONE,
2267 WDF_NO_FOCUS,
2268 _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets),
2269 &MainToolbarWindow::hotkeys
2273 /* --- Toolbar handling for the scenario editor */
2275 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
2276 ToolbarPauseClick,
2277 ToolbarFastForwardClick,
2278 ToolbarOptionsClick,
2279 ToolbarScenSaveOrLoad,
2280 ToolbarBtn_NULL,
2281 ToolbarScenDatePanel,
2282 ToolbarScenDateBackward,
2283 ToolbarScenDateForward,
2284 ToolbarScenMapTownDir,
2285 ToolbarZoomInClick,
2286 ToolbarZoomOutClick,
2287 ToolbarScenGenLand,
2288 ToolbarScenGenTown,
2289 ToolbarScenGenIndustry,
2290 ToolbarScenBuildRoad,
2291 ToolbarScenBuildDocks,
2292 ToolbarScenPlantTrees,
2293 ToolbarScenPlaceSign,
2294 ToolbarBtn_NULL,
2295 nullptr,
2296 nullptr,
2297 nullptr,
2298 nullptr,
2299 nullptr,
2300 nullptr,
2301 nullptr,
2302 ToolbarMusicClick,
2303 nullptr,
2304 ToolbarHelpClick,
2305 ToolbarSwitchClick,
2308 enum MainToolbarEditorHotkeys {
2309 MTEHK_PAUSE,
2310 MTEHK_FASTFORWARD,
2311 MTEHK_SETTINGS,
2312 MTEHK_SAVEGAME,
2313 MTEHK_GENLAND,
2314 MTEHK_GENTOWN,
2315 MTEHK_GENINDUSTRY,
2316 MTEHK_BUILD_ROAD,
2317 MTEHK_BUILD_DOCKS,
2318 MTEHK_BUILD_TREES,
2319 MTEHK_SIGN,
2320 MTEHK_MUSIC,
2321 MTEHK_LANDINFO,
2322 MTEHK_SMALL_SCREENSHOT,
2323 MTEHK_ZOOMEDIN_SCREENSHOT,
2324 MTEHK_DEFAULTZOOM_SCREENSHOT,
2325 MTEHK_GIANT_SCREENSHOT,
2326 MTEHK_ZOOM_IN,
2327 MTEHK_ZOOM_OUT,
2328 MTEHK_TERRAFORM,
2329 MTEHK_SMALLMAP,
2330 MTEHK_EXTRA_VIEWPORT,
2333 struct ScenarioEditorToolbarWindow : Window {
2334 ScenarioEditorToolbarWindow(WindowDesc *desc) : Window(desc)
2336 this->InitNested(0);
2338 _last_started_action = CBF_NONE;
2339 CLRBITS(this->flags, WF_WHITE_BORDER);
2340 PositionMainToolbar(this);
2341 DoZoomInOutWindow(ZOOM_NONE, this);
2344 virtual void FindWindowPlacementAndResize(int def_width, int def_height)
2346 Window::FindWindowPlacementAndResize(_toolbar_width, def_height);
2349 virtual void OnPaint()
2351 this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR);
2352 this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR);
2354 this->DrawWidgets();
2357 virtual void DrawWidget(const Rect &r, int widget) const
2359 switch (widget) {
2360 case WID_TE_DATE:
2361 SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
2362 DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER);
2363 break;
2365 case WID_TE_SPACER: {
2366 int height = r.bottom - r.top;
2367 if (height > 2 * FONT_HEIGHT_NORMAL) {
2368 DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
2369 DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2370 } else {
2371 DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
2373 break;
2378 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
2380 switch (widget) {
2381 case WID_TE_SPACER:
2382 size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
2383 break;
2385 case WID_TE_DATE:
2386 SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1));
2387 *size = GetStringBoundingBox(STR_WHITE_DATE_LONG);
2388 size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM);
2389 break;
2393 virtual void OnClick(Point pt, int widget, int click_count)
2395 if (_game_mode == GM_MENU) return;
2396 CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
2397 if (cbf != CBF_NONE) _last_started_action = cbf;
2400 virtual void OnDropdownSelect(int widget, int index)
2402 /* The map button is in a different location on the scenario
2403 * editor toolbar, so we need to adjust for it. */
2404 if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP;
2405 CallBackFunction cbf = _menu_clicked_procs[widget](index);
2406 if (cbf != CBF_NONE) _last_started_action = cbf;
2407 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
2410 virtual EventState OnHotkey(int hotkey)
2412 CallBackFunction cbf = CBF_NONE;
2413 switch (hotkey) {
2414 case MTEHK_PAUSE: ToolbarPauseClick(this); break;
2415 case MTEHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
2416 case MTEHK_SETTINGS: ShowGameOptions(); break;
2417 case MTEHK_SAVEGAME: MenuClickSaveLoad(); break;
2418 case MTEHK_GENLAND: ToolbarScenGenLand(this); break;
2419 case MTEHK_GENTOWN: ToolbarScenGenTown(this); break;
2420 case MTEHK_GENINDUSTRY: ToolbarScenGenIndustry(this); break;
2421 case MTEHK_BUILD_ROAD: ToolbarScenBuildRoad(this); break;
2422 case MTEHK_BUILD_DOCKS: ToolbarScenBuildDocks(this); break;
2423 case MTEHK_BUILD_TREES: ToolbarScenPlantTrees(this); break;
2424 case MTEHK_SIGN: cbf = ToolbarScenPlaceSign(this); break;
2425 case MTEHK_MUSIC: ShowMusicWindow(); break;
2426 case MTEHK_LANDINFO: cbf = PlaceLandBlockInfo(); break;
2427 case MTEHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
2428 case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_ZOOMEDIN); break;
2429 case MTEHK_DEFAULTZOOM_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_DEFAULTZOOM); break;
2430 case MTEHK_GIANT_SCREENSHOT: MenuClickLargeWorldScreenshot(SC_WORLD); break;
2431 case MTEHK_ZOOM_IN: ToolbarZoomInClick(this); break;
2432 case MTEHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
2433 case MTEHK_TERRAFORM: ShowEditorTerraformToolbar(); break;
2434 case MTEHK_SMALLMAP: ShowSmallMap(); break;
2435 case MTEHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
2436 default: return ES_NOT_HANDLED;
2438 if (cbf != CBF_NONE) _last_started_action = cbf;
2439 return ES_HANDLED;
2442 virtual void OnPlaceObject(Point pt, TileIndex tile)
2444 switch (_last_started_action) {
2445 case CBF_PLACE_SIGN:
2446 PlaceProc_Sign(tile);
2447 break;
2449 case CBF_PLACE_LANDINFO:
2450 ShowLandInfo(tile);
2451 break;
2453 default: NOT_REACHED();
2457 virtual void OnPlaceObjectAbort()
2459 _last_started_action = CBF_NONE;
2462 virtual void OnTimeout()
2464 this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END);
2465 this->SetWidgetDirty(WID_TE_DATE_BACKWARD);
2466 this->SetWidgetDirty(WID_TE_DATE_FORWARD);
2469 virtual void OnTick()
2471 if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
2472 this->ToggleWidgetLoweredState(WID_TE_PAUSE);
2473 this->SetDirty();
2476 if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) {
2477 this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD);
2478 this->SetDirty();
2483 * Some data on this window has become invalid.
2484 * @param data Information about the changed data.
2485 * @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.
2487 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
2489 if (!gui_scope) return;
2490 if (FindWindowById(WC_MAIN_WINDOW, 0) != nullptr) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
2493 virtual void OnQueryTextFinished(char *str)
2495 /* Was 'cancel' pressed? */
2496 if (str == nullptr) return;
2498 int32 value;
2499 if (!StrEmpty(str)) {
2500 value = atoi(str);
2501 } else {
2502 /* An empty string means revert to the default */
2503 value = DEF_START_YEAR;
2505 SetStartingYear(value);
2507 this->SetDirty();
2510 static HotkeyList hotkeys;
2513 static Hotkey scenedit_maintoolbar_hotkeys[] = {
2514 Hotkey(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE),
2515 Hotkey((uint16)0, "fastforward", MTEHK_FASTFORWARD),
2516 Hotkey(WKC_F2, "settings", MTEHK_SETTINGS),
2517 Hotkey(WKC_F3, "saveload", MTEHK_SAVEGAME),
2518 Hotkey(WKC_F4, "gen_land", MTEHK_GENLAND),
2519 Hotkey(WKC_F5, "gen_town", MTEHK_GENTOWN),
2520 Hotkey(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
2521 Hotkey(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
2522 Hotkey(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
2523 Hotkey(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
2524 Hotkey(WKC_F10, "build_sign", MTEHK_SIGN),
2525 Hotkey(WKC_F11, "music", MTEHK_MUSIC),
2526 Hotkey(WKC_F12, "land_info", MTEHK_LANDINFO),
2527 Hotkey(WKC_CTRL | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
2528 Hotkey(WKC_CTRL | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
2529 Hotkey(WKC_CTRL | 'D', "defaultzoom_screenshot", MTEHK_DEFAULTZOOM_SCREENSHOT),
2530 Hotkey((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
2531 Hotkey(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN),
2532 Hotkey(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT),
2533 Hotkey('L', "terraform", MTEHK_TERRAFORM),
2534 Hotkey('M', "smallmap", MTEHK_SMALLMAP),
2535 Hotkey('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
2536 HOTKEY_LIST_END
2538 HotkeyList ScenarioEditorToolbarWindow::hotkeys("scenedit_maintoolbar", scenedit_maintoolbar_hotkeys);
2540 static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
2541 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
2542 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
2543 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
2544 NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
2545 NWidget(NWID_SPACER),
2546 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
2547 NWidget(NWID_SPACER),
2548 NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
2549 NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
2550 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD),
2551 NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE),
2552 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD),
2553 EndContainer(),
2554 EndContainer(),
2555 NWidget(NWID_SPACER),
2556 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
2557 NWidget(NWID_SPACER),
2558 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
2559 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
2560 NWidget(NWID_SPACER),
2561 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
2562 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
2563 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
2564 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
2565 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
2566 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
2567 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
2568 NWidget(NWID_SPACER),
2569 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
2570 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
2571 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
2574 static NWidgetBase *MakeScenarioToolbar(int *biggest_index)
2576 return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer());
2579 static const NWidgetPart _nested_toolb_scen_widgets[] = {
2580 NWidgetFunction(MakeScenarioToolbar),
2583 static WindowDesc _toolb_scen_desc(
2584 WDP_MANUAL, nullptr, 0, 0,
2585 WC_MAIN_TOOLBAR, WC_NONE,
2586 WDF_NO_FOCUS,
2587 _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets),
2588 &ScenarioEditorToolbarWindow::hotkeys
2591 /** Allocate the toolbar. */
2592 void AllocateToolbar()
2594 /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
2595 _last_built_roadtype = ROADTYPE_ROAD;
2597 if (_game_mode == GM_EDITOR) {
2598 new ScenarioEditorToolbarWindow(&_toolb_scen_desc);
2599 } else {
2600 new MainToolbarWindow(&_toolb_normal_desc);