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/>.
8 /** @file toolbar_gui.cpp Code related to the (main) toolbar. */
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"
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"
33 #include "console_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"
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
;
76 /** Callback functions. */
77 enum CallBackFunction
{
83 static CallBackFunction _last_started_action
= CBF_NONE
; ///< Last started user action.
87 * Drop down list entry for showing a checked/unchecked toggle item.
89 class DropDownListCheckedItem
: public DropDownListStringItem
{
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;
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
;
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
{
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
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
);
168 col
= (sel
? TC_SILVER
: TC_GREY
) | TC_NO_SHADE
;
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.
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.
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
)
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)
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));
228 list
.emplace_back(new DropDownListStringItem(STR_STORY_BOOK_SPECTATOR
, CTMN_SPECTATOR
, false));
232 list
.emplace_back(new DropDownListStringItem(STR_GOALS_SPECTATOR
, CTMN_SPECTATOR
, false));
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();
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
);
271 * Toggle fast forward mode.
276 static CallBackFunction
ToolbarFastForwardClick(Window
*w
)
278 ChangeGameSpeed(_game_speed
== 100);
280 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
285 * Game Option button menu entries.
287 enum OptionMenuEntries
{
294 OME_SHOW_STATIONNAMES
,
295 OME_SHOW_WAYPOINTNAMES
,
297 OME_SHOW_COMPETITOR_SIGNS
,
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.
310 static CallBackFunction
ToolbarOptionsClick(Window
*w
)
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
);
338 * Handle click on one of the entries in the Options button menu.
340 * @param index Index being clicked.
343 static CallBackFunction
MenuClickSettings(int 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);
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();
370 * SaveLoad entries in scenario editor mode.
372 enum SaveLoadEditorMenuEntries
{
373 SLEME_SAVE_SCENARIO
= 0,
375 SLEME_SAVE_HEIGHTMAP
,
376 SLEME_LOAD_HEIGHTMAP
,
383 * SaveLoad entries in normal game mode.
385 enum SaveLoadNormalMenuEntries
{
394 * Handle click on Save button in toolbar in normal game mode.
396 * @param w parent window the shown save dialogue is attached to.
399 static CallBackFunction
ToolbarSaveClick(Window
*w
)
401 PopupMainToolbMenu(w
, WID_TN_SAVE
, STR_FILE_MENU_SAVE_GAME
, SLNME_MENUCOUNT
);
406 * Handle click on SaveLoad button in toolbar in the scenario editor.
408 * @param w parent window the shown save dialogue is attached to.
411 static CallBackFunction
ToolbarScenSaveOrLoad(Window
*w
)
413 PopupMainToolbMenu(w
, WID_TE_SAVE
, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO
, SLEME_MENUCOUNT
);
418 * Handle click on one of the entries in the SaveLoad menu.
420 * @param index Index being clicked.
423 static CallBackFunction
MenuClickSaveLoad(int index
= 0)
425 if (_game_mode
== GM_EDITOR
) {
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;
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;
445 /* --- Map button menu --- */
447 enum MapMenuEntries
{
448 MME_SHOW_SMALLMAP
= 0,
449 MME_SHOW_EXTRAVIEWPORTS
,
452 MME_SHOW_TOWNDIRECTORY
,
453 MME_SHOW_INDUSTRYDIRECTORY
,
456 static CallBackFunction
ToolbarMapClick(Window
*w
)
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);
467 static CallBackFunction
ToolbarScenMapTownDir(Window
*w
)
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);
480 * Handle click on one of the entries in the Map menu.
482 * @param index Index being clicked.
485 static CallBackFunction
MenuClickMap(int 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;
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);
507 * Handle click on one of the entries in the Town menu.
509 * @param index Index being clicked.
512 static CallBackFunction
MenuClickTown(int 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();
523 /* --- Subidies button menu --- */
525 static CallBackFunction
ToolbarSubsidiesClick(Window
*w
)
527 PopupMainToolbMenu(w
, WID_TN_SUBSIDIES
, STR_SUBSIDIES_MENU_SUBSIDIES
, 1);
532 * Handle click on the entry in the Subsidies menu.
534 * @param index Unused.
537 static CallBackFunction
MenuClickSubsidies(int index
)
540 case 0: ShowSubsidiesList(); break;
545 /* --- Stations button menu --- */
547 static CallBackFunction
ToolbarStationsClick(Window
*w
)
549 PopupMainCompanyToolbMenu(w
, WID_TN_STATIONS
);
554 * Handle click on the entry in the Stations menu
556 * @param index CompanyID to show station list for
559 static CallBackFunction
MenuClickStations(int index
)
561 ShowCompanyStations((CompanyID
)index
);
565 /* --- Finances button menu --- */
567 static CallBackFunction
ToolbarFinancesClick(Window
*w
)
569 PopupMainCompanyToolbMenu(w
, WID_TN_FINANCES
);
574 * Handle click on the entry in the finances overview menu.
576 * @param index CompanyID to show finances for.
579 static CallBackFunction
MenuClickFinances(int index
)
581 ShowCompanyFinances((CompanyID
)index
);
585 /* --- Company's button menu --- */
587 static CallBackFunction
ToolbarCompaniesClick(Window
*w
)
589 PopupMainCompanyToolbMenu(w
, WID_TN_COMPANIES
, 0);
594 * Handle click on the entry in the Company menu.
596 * @param index Menu entry to handle.
599 static CallBackFunction
MenuClickCompany(int index
)
603 case CTMN_CLIENT_LIST
:
608 ShowCompany((CompanyID
)index
);
612 /* --- Story button menu --- */
614 static CallBackFunction
ToolbarStoryClick(Window
*w
)
616 PopupMainCompanyToolbMenu(w
, WID_TN_STORY
, 0);
621 * Handle click on the entry in the Story menu
623 * @param index CompanyID to show story book for
626 static CallBackFunction
MenuClickStory(int index
)
628 ShowStoryBook(index
== CTMN_SPECTATOR
? INVALID_COMPANY
: (CompanyID
)index
);
632 /* --- Goal button menu --- */
634 static CallBackFunction
ToolbarGoalClick(Window
*w
)
636 PopupMainCompanyToolbMenu(w
, WID_TN_GOAL
, 0);
641 * Handle click on the entry in the Goal menu
643 * @param index CompanyID to show story book for
646 static CallBackFunction
MenuClickGoal(int index
)
648 ShowGoalsList(index
== CTMN_SPECTATOR
? INVALID_COMPANY
: (CompanyID
)index
);
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);
661 * Handle click on the entry in the Graphs menu.
663 * @param index Graph to show.
666 static CallBackFunction
MenuClickGraphs(int 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;
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);
691 * Handle click on the entry in the CompanyLeague menu.
693 * @param index Menu entry number.
696 static CallBackFunction
MenuClickLeague(int index
)
699 case 0: ShowCompanyLeagueTable(); break;
700 case 1: ShowPerformanceRatingDetail(); break;
701 case 2: ShowHighscoreTable(); break;
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);
716 * Handle click on the entry in the Industry menu.
718 * @param index Menu entry number.
721 static CallBackFunction
MenuClickIndustry(int index
)
724 case 0: ShowIndustryDirectory(); break;
725 case 1: ShowIndustryCargoesWindow(); break;
726 case 2: ShowBuildIndustryWindow(); break;
731 /* --- Trains button menu + 1 helper function for all vehicles. --- */
733 static void ToolbarVehicleClick(Window
*w
, VehicleType veh
)
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
);
751 * Handle click on the entry in the Train menu.
753 * @param index CompanyID to show train list for.
756 static CallBackFunction
MenuClickShowTrains(int index
)
758 ShowVehicleListWindow((CompanyID
)index
, VEH_TRAIN
);
762 /* --- Road vehicle button menu --- */
764 static CallBackFunction
ToolbarRoadClick(Window
*w
)
766 ToolbarVehicleClick(w
, VEH_ROAD
);
771 * Handle click on the entry in the Road Vehicles menu.
773 * @param index CompanyID to show road vehicles list for.
776 static CallBackFunction
MenuClickShowRoad(int index
)
778 ShowVehicleListWindow((CompanyID
)index
, VEH_ROAD
);
782 /* --- Ship button menu --- */
784 static CallBackFunction
ToolbarShipClick(Window
*w
)
786 ToolbarVehicleClick(w
, VEH_SHIP
);
791 * Handle click on the entry in the Ships menu.
793 * @param index CompanyID to show ship list for.
796 static CallBackFunction
MenuClickShowShips(int index
)
798 ShowVehicleListWindow((CompanyID
)index
, VEH_SHIP
);
802 /* --- Aircraft button menu --- */
804 static CallBackFunction
ToolbarAirClick(Window
*w
)
806 ToolbarVehicleClick(w
, VEH_AIRCRAFT
);
811 * Handle click on the entry in the Aircraft menu.
813 * @param index CompanyID to show aircraft list for.
816 static CallBackFunction
MenuClickShowAir(int index
)
818 ShowVehicleListWindow((CompanyID
)index
, VEH_AIRCRAFT
);
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
);
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
);
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
);
854 * Handle click on the entry in the Build Rail menu.
856 * @param index RailType to show the build toolbar for.
859 static CallBackFunction
MenuClickBuildRail(int index
)
861 _last_built_railtype
= (RailType
)index
;
862 ShowBuildRailToolbar(_last_built_railtype
);
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
);
876 * Handle click on the entry in the Build Road menu.
878 * @param index RoadType to show the build toolbar for.
881 static CallBackFunction
MenuClickBuildRoad(int index
)
883 _last_built_roadtype
= (RoadType
)index
;
884 ShowBuildRoadToolbar(_last_built_roadtype
);
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
);
898 * Handle click on the entry in the Build Tram menu.
900 * @param index RoadType to show the build toolbar for.
903 static CallBackFunction
MenuClickBuildTram(int index
)
905 _last_built_tramtype
= (RoadType
)index
;
906 ShowBuildRoadToolbar(_last_built_tramtype
);
910 /* --- Water button menu --- */
912 static CallBackFunction
ToolbarBuildWaterClick(Window
*w
)
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
);
922 * Handle click on the entry in the Build Waterways menu.
924 * @param index Unused.
927 static CallBackFunction
MenuClickBuildWater(int index
)
929 ShowBuildDocksToolbar();
933 /* --- Airport button menu --- */
935 static CallBackFunction
ToolbarBuildAirClick(Window
*w
)
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
);
945 * Handle click on the entry in the Build Air menu.
947 * @param index Unused.
950 static CallBackFunction
MenuClickBuildAir(int index
)
952 ShowBuildAirToolbar();
956 /* --- Forest button menu --- */
958 static CallBackFunction
ToolbarForestClick(Window
*w
)
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
);
970 * Handle click on the entry in the landscaping menu.
972 * @param index Menu entry clicked.
975 static CallBackFunction
MenuClickForest(int index
)
978 case 0: ShowTerraformToolbar(); break;
979 case 1: ShowBuildTreesToolbar(); break;
980 case 2: return SelectSignTool();
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);
994 * Handle click on the entry in the Music menu.
996 * @param index Unused.
999 static CallBackFunction
MenuClickMusicWindow(int index
)
1005 /* --- Newspaper button menu --- */
1007 static CallBackFunction
ToolbarNewspaperClick(Window
*w
)
1009 PopupMainToolbMenu(w
, WID_TN_MESSAGES
, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT
, 3);
1014 * Handle click on the entry in the Newspaper menu.
1016 * @param index Menu entry clicked.
1019 static CallBackFunction
MenuClickNewspaper(int index
)
1022 case 0: ShowLastNewsMessage(); break;
1023 case 1: ShowMessageHistory(); break;
1024 case 2: DeleteAllMessages(); break;
1029 /* --- Help button menu --- */
1031 static CallBackFunction
PlaceLandBlockInfo()
1033 if (_last_started_action
== CBF_PLACE_LANDINFO
) {
1034 ResetObjectToPlace();
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);
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.
1100 static CallBackFunction
MenuClickHelp(int 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;
1116 /* --- Switch toolbar button --- */
1118 static CallBackFunction
ToolbarSwitchClick(Window
*w
)
1120 if (_toolbar_mode
!= TB_LOWER
) {
1121 _toolbar_mode
= TB_LOWER
;
1123 _toolbar_mode
= TB_UPPER
;
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
);
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;
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
);
1152 SetStartingYear(_settings_game
.game_creation
.starting_year
- 1);
1154 _left_button_clicked
= false;
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
);
1165 SetStartingYear(_settings_game
.game_creation
.starting_year
+ 1);
1167 _left_button_clicked
= false;
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();
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();
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();
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
);
1205 * Handle click on the entry in the Build Road menu.
1207 * @param index RoadType to show the build toolbar for.
1210 static CallBackFunction
ToolbarScenBuildRoad(int index
)
1212 _last_built_roadtype
= (RoadType
)index
;
1213 ShowBuildRoadScenToolbar(_last_built_roadtype
);
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
);
1225 * Handle click on the entry in the Build Tram menu.
1227 * @param index RoadType to show the build toolbar for.
1230 static CallBackFunction
ToolbarScenBuildTram(int index
)
1232 _last_built_tramtype
= (RoadType
)index
;
1233 ShowBuildRoadScenToolbar(_last_built_tramtype
);
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();
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();
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
)
1265 typedef CallBackFunction
MenuClickedProc(int index
);
1267 static MenuClickedProc
* const _menu_clicked_procs
[] = {
1270 MenuClickSettings
, // 2
1271 MenuClickSaveLoad
, // 3
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
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
1304 uint spacers
; ///< Number of spacer widgets in this toolbar
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
1327 this->resize_x
= 1; // We only resize in this direction
1328 this->resize_y
= 0; // We never resize in this direction
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
)) {
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
) {
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
);
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
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
);
1395 spacer_space
-= add
;
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
;
1406 child_wid
->AssignSizePosition(sizing
, x
+ position
, y
, child_wid
->current_x
, this->current_y
, rtl
);
1407 position
+= child_wid
->current_x
;
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;
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
;
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
1470 static const byte arrange14
[] = {
1472 WID_TN_FAST_FORWARD
,
1501 static const byte arrange15
[] = {
1503 WID_TN_FAST_FORWARD
,
1534 static const byte arrange16
[] = {
1536 WID_TN_FAST_FORWARD
,
1553 WID_TN_FAST_FORWARD
,
1569 static const byte arrange17
[] = {
1571 WID_TN_FAST_FORWARD
,
1589 WID_TN_FAST_FORWARD
,
1606 static const byte arrange18
[] = {
1608 WID_TN_FAST_FORWARD
,
1627 WID_TN_FAST_FORWARD
,
1645 static const byte arrange19
[] = {
1647 WID_TN_FAST_FORWARD
,
1667 WID_TN_FAST_FORWARD
,
1686 static const byte arrange20
[] = {
1688 WID_TN_FAST_FORWARD
,
1709 WID_TN_FAST_FORWARD
,
1729 static const byte arrange_all
[] = {
1731 WID_TN_FAST_FORWARD
,
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
;
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 */
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
[] = {
1802 WID_TE_FAST_FORWARD
,
1810 WID_TE_LAND_GENERATE
,
1811 WID_TE_TOWN_GENERATE
,
1821 static const byte arrange_nopanel
[] = {
1823 WID_TE_FAST_FORWARD
,
1830 WID_TE_LAND_GENERATE
,
1831 WID_TE_TOWN_GENERATE
,
1841 static const byte arrange_switch
[] = {
1844 WID_TE_LAND_GENERATE
,
1845 WID_TE_TOWN_GENERATE
,
1855 WID_TE_FAST_FORWARD
,
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
;
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
;
1888 width
-= this->panel_widths
[1];
1889 arrangable_count
= lengthof(arrange_switch
) / 2;
1890 button_count
= arrangable_count
- 1;
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
[] = {
1902 ToolbarFastForwardClick
,
1903 ToolbarOptionsClick
,
1907 ToolbarSubsidiesClick
,
1908 ToolbarStationsClick
,
1909 ToolbarFinancesClick
,
1910 ToolbarCompaniesClick
,
1915 ToolbarIndustryClick
,
1921 ToolbarZoomOutClick
,
1922 ToolbarBuildRailClick
,
1923 ToolbarBuildRoadClick
,
1924 ToolbarBuildTramClick
,
1925 ToolbarBuildWaterClick
,
1926 ToolbarBuildAirClick
,
1929 ToolbarNewspaperClick
,
1934 enum MainToolbarHotkeys
{
1966 MTHK_SMALL_SCREENSHOT
,
1967 MTHK_ZOOMEDIN_SCREENSHOT
,
1968 MTHK_DEFAULTZOOM_SCREENSHOT
,
1969 MTHK_GIANT_SCREENSHOT
,
1972 MTHK_EXTRA_VIEWPORT
,
1977 /** Main toolbar. */
1978 struct MainToolbarWindow
: Window
{
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
;
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
;
2076 void OnPlaceObject(Point pt
, TileIndex tile
) override
2078 switch (_last_started_action
) {
2079 case CBF_PLACE_SIGN
:
2080 PlaceProc_Sign(tile
);
2083 case CBF_PLACE_LANDINFO
:
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
),
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
++) {
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));
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);
2242 *biggest_index
= std::max
<int>(*biggest_index
, WID_TN_SWITCH_BAR
);
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
,
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
[] = {
2264 MenuClickSettings
, // 2
2265 MenuClickSaveLoad
, // 3
2276 ToolbarScenBuildRoad
, // 14
2277 ToolbarScenBuildTram
, // 15
2282 MenuClickMusicWindow
, // 20
2283 MenuClickHelp
, // 21
2287 static ToolbarButtonProc
* const _scen_toolbar_button_procs
[] = {
2289 ToolbarFastForwardClick
,
2290 ToolbarOptionsClick
,
2291 ToolbarScenSaveOrLoad
,
2293 ToolbarScenDatePanel
,
2294 ToolbarScenDateBackward
,
2295 ToolbarScenDateForward
,
2296 ToolbarScenMapTownDir
,
2298 ToolbarZoomOutClick
,
2301 ToolbarScenGenIndustry
,
2302 ToolbarScenBuildRoadClick
,
2303 ToolbarScenBuildTramClick
,
2304 ToolbarScenBuildDocks
,
2305 ToolbarScenPlantTrees
,
2306 ToolbarScenPlaceSign
,
2313 enum MainToolbarEditorHotkeys
{
2328 MTEHK_SMALL_SCREENSHOT
,
2329 MTEHK_ZOOMEDIN_SCREENSHOT
,
2330 MTEHK_DEFAULTZOOM_SCREENSHOT
,
2331 MTEHK_GIANT_SCREENSHOT
,
2336 MTEHK_EXTRA_VIEWPORT
,
2339 struct ScenarioEditorToolbarWindow
: Window
{
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
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
);
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
);
2383 DrawString(r
.left
, r
.right
, (height
- FONT_HEIGHT_NORMAL
) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR
, TC_FROMSTRING
, SA_HOR_CENTER
);
2390 void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
) override
2394 size
->width
= std::max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD
).width
, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR
).width
) + WD_FRAMERECT_LEFT
+ WD_FRAMERECT_RIGHT
;
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
);
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
;
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
;
2452 void OnPlaceObject(Point pt
, TileIndex tile
) override
2454 switch (_last_started_action
) {
2455 case CBF_PLACE_SIGN
:
2456 PlaceProc_Sign(tile
);
2459 case CBF_PLACE_LANDINFO
:
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
);
2489 if (this->IsWidgetLowered(WID_TE_FAST_FORWARD
) != (_game_speed
!= 100)) {
2490 this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD
);
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;
2512 if (!StrEmpty(str
)) {
2515 /* An empty string means revert to the default */
2516 value
= DEF_START_YEAR
;
2518 SetStartingYear(value
);
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
),
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
),
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
,
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
);
2616 new MainToolbarWindow(&_toolb_normal_desc
);