toolbar_gui.cpp

Go to the documentation of this file.
00001 /* $Id: toolbar_gui.cpp 23630 2011-12-19 21:03:17Z truebrain $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * 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.
00006  * 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.
00007  * 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/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "gui.h"
00014 #include "window_gui.h"
00015 #include "window_func.h"
00016 #include "viewport_func.h"
00017 #include "command_func.h"
00018 #include "vehicle_gui.h"
00019 #include "rail_gui.h"
00020 #include "road_gui.h"
00021 #include "date_func.h"
00022 #include "vehicle_func.h"
00023 #include "sound_func.h"
00024 #include "terraform_gui.h"
00025 #include "transparency.h"
00026 #include "strings_func.h"
00027 #include "company_func.h"
00028 #include "company_gui.h"
00029 #include "vehicle_base.h"
00030 #include "cheat_func.h"
00031 #include "transparency_gui.h"
00032 #include "screenshot.h"
00033 #include "signs_func.h"
00034 #include "fios.h"
00035 #include "console_gui.h"
00036 #include "news_gui.h"
00037 #include "ai/ai_gui.hpp"
00038 #include "tilehighlight_func.h"
00039 #include "smallmap_gui.h"
00040 #include "graph_gui.h"
00041 #include "textbuf_gui.h"
00042 #include "newgrf_debug.h"
00043 #include "hotkeys.h"
00044 #include "engine_base.h"
00045 #include "settings_type.h"
00046 
00047 #include "widgets/toolbar_widget.h"
00048 
00049 #include "network/network.h"
00050 #include "network/network_gui.h"
00051 #include "network/network_func.h"
00052 
00053 #include "table/strings.h"
00054 #include "table/sprites.h"
00055 
00056 RailType _last_built_railtype;
00057 RoadType _last_built_roadtype;
00058 
00060 enum ToolbarMode {
00061   TB_NORMAL,
00062   TB_UPPER,
00063   TB_LOWER
00064 };
00065 
00067 enum CallBackFunction {
00068   CBF_NONE,
00069   CBF_PLACE_SIGN,
00070   CBF_PLACE_LANDINFO,
00071 };
00072 
00076 class DropDownListCheckedItem : public DropDownListStringItem {
00077   uint checkmark_width;
00078 public:
00079   bool checked;
00080 
00081   DropDownListCheckedItem(StringID string, int result, bool masked, bool checked) : DropDownListStringItem(string, result, masked), checked(checked)
00082   {
00083     this->checkmark_width = GetStringBoundingBox(STR_JUST_CHECKMARK).width + 3;
00084   }
00085 
00086   virtual ~DropDownListCheckedItem() {}
00087 
00088   uint Width() const
00089   {
00090     return DropDownListStringItem::Width() + this->checkmark_width;
00091   }
00092 
00093   void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
00094   {
00095     bool rtl = _current_text_dir == TD_RTL;
00096     if (this->checked) {
00097       DrawString(left + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_JUST_CHECKMARK, sel ? TC_WHITE : TC_BLACK);
00098     }
00099     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);
00100   }
00101 };
00102 
00106 class DropDownListCompanyItem : public DropDownListItem {
00107   Dimension icon_size;
00108 public:
00109   bool greyed;
00110 
00111   DropDownListCompanyItem(int result, bool masked, bool greyed) : DropDownListItem(result, masked), greyed(greyed)
00112   {
00113     this->icon_size = GetSpriteSize(SPR_COMPANY_ICON);
00114   }
00115 
00116   virtual ~DropDownListCompanyItem() {}
00117 
00118   bool Selectable() const
00119   {
00120     return true;
00121   }
00122 
00123   uint Width() const
00124   {
00125     CompanyID company = (CompanyID)this->result;
00126     SetDParam(0, company);
00127     SetDParam(1, company);
00128     return GetStringBoundingBox(STR_COMPANY_NAME_COMPANY_NUM).width + this->icon_size.width + 3;
00129   }
00130 
00131   uint Height(uint width) const
00132   {
00133     return max(this->icon_size.height + 2U, (uint)FONT_HEIGHT_NORMAL);
00134   }
00135 
00136   void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
00137   {
00138     CompanyID company = (CompanyID)this->result;
00139     bool rtl = _current_text_dir == TD_RTL;
00140 
00141     /* It's possible the company is deleted while the dropdown is open */
00142     if (!Company::IsValidID(company)) return;
00143 
00144     int icon_offset = (bottom - top - icon_size.height) / 2;
00145     int text_offset = (bottom - top - FONT_HEIGHT_NORMAL) / 2;
00146 
00147     DrawCompanyIcon(company, rtl ? right - this->icon_size.width - WD_FRAMERECT_RIGHT : left + WD_FRAMERECT_LEFT, top + icon_offset);
00148 
00149     SetDParam(0, company);
00150     SetDParam(1, company);
00151     TextColour col;
00152     if (this->greyed) {
00153       col = TC_GREY;
00154     } else {
00155       col = sel ? TC_WHITE : TC_BLACK;
00156     }
00157     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);
00158   }
00159 };
00160 
00164 static void PopupMainToolbMenu(Window *w, int widget, StringID string, int count)
00165 {
00166   DropDownList *list = new DropDownList();
00167   for (int i = 0; i < count; i++) {
00168     list->push_back(new DropDownListStringItem(string + i, i, false));
00169   }
00170   ShowDropDownList(w, list, 0, widget, 140, true, true);
00171   SndPlayFx(SND_15_BEEP);
00172 }
00173 
00175 static const int CTMN_CLIENT_LIST = -1; 
00176 static const int CTMN_NEW_COMPANY = -2; 
00177 static const int CTMN_SPECTATE    = -3; 
00178 
00182 static void PopupMainCompanyToolbMenu(Window *w, int widget, int grey = 0)
00183 {
00184   DropDownList *list = new DropDownList();
00185 
00186 #ifdef ENABLE_NETWORK
00187   if (widget == WID_TN_COMPANIES && _networking) {
00188     /* Add the client list button for the companies menu */
00189     list->push_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_CLIENT_LIST, CTMN_CLIENT_LIST, false));
00190 
00191     if (_local_company == COMPANY_SPECTATOR) {
00192       list->push_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_NEW_COMPANY, CTMN_NEW_COMPANY, NetworkMaxCompaniesReached()));
00193     } else {
00194       list->push_back(new DropDownListStringItem(STR_NETWORK_COMPANY_LIST_SPECTATE, CTMN_SPECTATE, NetworkMaxSpectatorsReached()));
00195     }
00196   }
00197 #endif /* ENABLE_NETWORK */
00198 
00199   for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00200     if (!Company::IsValidID(c)) continue;
00201     list->push_back(new DropDownListCompanyItem(c, false, HasBit(grey, c)));
00202   }
00203 
00204   ShowDropDownList(w, list, _local_company == COMPANY_SPECTATOR ? CTMN_CLIENT_LIST : (int)_local_company, widget, 240, true, true);
00205   SndPlayFx(SND_15_BEEP);
00206 }
00207 
00208 
00209 static ToolbarMode _toolbar_mode;
00210 
00211 static CallBackFunction SelectSignTool()
00212 {
00213   if (_cursor.sprite == SPR_CURSOR_SIGN) {
00214     ResetObjectToPlace();
00215     return CBF_NONE;
00216   } else {
00217     SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
00218     return CBF_PLACE_SIGN;
00219   }
00220 }
00221 
00222 /* --- Pausing --- */
00223 
00224 static CallBackFunction ToolbarPauseClick(Window *w)
00225 {
00226   if (_networking && !_network_server) return CBF_NONE; // only server can pause the game
00227 
00228   if (DoCommandP(0, PM_PAUSED_NORMAL, _pause_mode == PM_UNPAUSED, CMD_PAUSE)) SndPlayFx(SND_15_BEEP);
00229   return CBF_NONE;
00230 }
00231 
00238 static CallBackFunction ToolbarFastForwardClick(Window *w)
00239 {
00240   _fast_forward ^= true;
00241   SndPlayFx(SND_15_BEEP);
00242   return CBF_NONE;
00243 }
00244 
00248 enum OptionMenuEntries {
00249   OME_GAMEOPTIONS,
00250   OME_DIFFICULTIES,
00251   OME_SETTINGS,
00252   OME_SCRIPT_SETTINGS,
00253   OME_NEWGRFSETTINGS,
00254   OME_TRANSPARENCIES,
00255   OME_SHOW_TOWNNAMES,
00256   OME_SHOW_STATIONNAMES,
00257   OME_SHOW_WAYPOINTNAMES,
00258   OME_SHOW_SIGNS,
00259   OME_SHOW_COMPETITOR_SIGNS,
00260   OME_FULL_ANIMATION,
00261   OME_FULL_DETAILS,
00262   OME_TRANSPARENTBUILDINGS,
00263   OME_SHOW_STATIONSIGNS,
00264 };
00265 
00272 static CallBackFunction ToolbarOptionsClick(Window *w)
00273 {
00274   DropDownList *list = new DropDownList();
00275   list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_GAME_OPTIONS,             OME_GAMEOPTIONS, false));
00276   list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_DIFFICULTY_SETTINGS,      OME_DIFFICULTIES, false));
00277   list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_CONFIG_SETTINGS,          OME_SETTINGS, false));
00278   /* Changes to the per-AI settings don't get send from the server to the clients. Clients get
00279    * the settings once they join but never update it. As such don't show the window at all
00280    * to network clients. */
00281   if (!_networking || _network_server) list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_SCRIPT_SETTINGS, OME_SCRIPT_SETTINGS, false));
00282   list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_NEWGRF_SETTINGS,          OME_NEWGRFSETTINGS, false));
00283   list->push_back(new DropDownListStringItem(STR_SETTINGS_MENU_TRANSPARENCY_OPTIONS,     OME_TRANSPARENCIES, false));
00284   list->push_back(new DropDownListItem(-1, false));
00285   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TOWN_NAMES_DISPLAYED,    OME_SHOW_TOWNNAMES, false, HasBit(_display_opt, DO_SHOW_TOWN_NAMES)));
00286   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_STATION_NAMES_DISPLAYED, OME_SHOW_STATIONNAMES, false, HasBit(_display_opt, DO_SHOW_STATION_NAMES)));
00287   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_WAYPOINTS_DISPLAYED,     OME_SHOW_WAYPOINTNAMES, false, HasBit(_display_opt, DO_SHOW_WAYPOINT_NAMES)));
00288   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SIGNS_DISPLAYED,         OME_SHOW_SIGNS, false, HasBit(_display_opt, DO_SHOW_SIGNS)));
00289   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_SHOW_COMPETITOR_SIGNS,   OME_SHOW_COMPETITOR_SIGNS, false, HasBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS)));
00290   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_ANIMATION,          OME_FULL_ANIMATION, false, HasBit(_display_opt, DO_FULL_ANIMATION)));
00291   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_FULL_DETAIL,             OME_FULL_DETAILS, false, HasBit(_display_opt, DO_FULL_DETAIL)));
00292   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_BUILDINGS,   OME_TRANSPARENTBUILDINGS, false, IsTransparencySet(TO_HOUSES)));
00293   list->push_back(new DropDownListCheckedItem(STR_SETTINGS_MENU_TRANSPARENT_SIGNS,       OME_SHOW_STATIONSIGNS, false, IsTransparencySet(TO_SIGNS)));
00294 
00295   ShowDropDownList(w, list, 0, WID_TN_SETTINGS, 140, true, true);
00296   SndPlayFx(SND_15_BEEP);
00297   return CBF_NONE;
00298 }
00299 
00306 static CallBackFunction MenuClickSettings(int index)
00307 {
00308   switch (index) {
00309     case OME_GAMEOPTIONS:          ShowGameOptions();                               return CBF_NONE;
00310     case OME_DIFFICULTIES:         ShowGameDifficulty();                            return CBF_NONE;
00311     case OME_SETTINGS:             ShowGameSettings();                              return CBF_NONE;
00312     case OME_SCRIPT_SETTINGS:      ShowAIConfigWindow();                            return CBF_NONE;
00313     case OME_NEWGRFSETTINGS:       ShowNewGRFSettings(!_networking && _settings_client.gui.UserIsAllowedToChangeNewGRFs(), true, true, &_grfconfig); return CBF_NONE;
00314     case OME_TRANSPARENCIES:       ShowTransparencyToolbar();                       break;
00315 
00316     case OME_SHOW_TOWNNAMES:       ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES);     break;
00317     case OME_SHOW_STATIONNAMES:    ToggleBit(_display_opt, DO_SHOW_STATION_NAMES);  break;
00318     case OME_SHOW_WAYPOINTNAMES:   ToggleBit(_display_opt, DO_SHOW_WAYPOINT_NAMES); break;
00319     case OME_SHOW_SIGNS:           ToggleBit(_display_opt, DO_SHOW_SIGNS);          break;
00320     case OME_SHOW_COMPETITOR_SIGNS:
00321       ToggleBit(_display_opt, DO_SHOW_COMPETITOR_SIGNS);
00322       InvalidateWindowClassesData(WC_SIGN_LIST, -1);
00323       break;
00324     case OME_FULL_ANIMATION:       ToggleBit(_display_opt, DO_FULL_ANIMATION);      break;
00325     case OME_FULL_DETAILS:         ToggleBit(_display_opt, DO_FULL_DETAIL);         break;
00326     case OME_TRANSPARENTBUILDINGS: ToggleTransparency(TO_HOUSES);                   break;
00327     case OME_SHOW_STATIONSIGNS:    ToggleTransparency(TO_SIGNS);                    break;
00328   }
00329   MarkWholeScreenDirty();
00330   return CBF_NONE;
00331 }
00332 
00336 enum SaveLoadEditorMenuEntries {
00337   SLEME_SAVE_SCENARIO   = 0,
00338   SLEME_LOAD_SCENARIO,
00339   SLEME_SAVE_HEIGHTMAP,
00340   SLEME_LOAD_HEIGHTMAP,
00341   SLEME_EXIT_TOINTRO,
00342   SLEME_EXIT_GAME       = 6,
00343   SLEME_MENUCOUNT,
00344 };
00345 
00349 enum SaveLoadNormalMenuEntries {
00350   SLNME_SAVE_GAME   = 0,
00351   SLNME_LOAD_GAME,
00352   SLNME_EXIT_TOINTRO,
00353   SLNME_EXIT_GAME,
00354   SLNME_MENUCOUNT,
00355 };
00356 
00363 static CallBackFunction ToolbarSaveClick(Window *w)
00364 {
00365   PopupMainToolbMenu(w, WID_TN_SAVE, STR_FILE_MENU_SAVE_GAME, SLNME_MENUCOUNT);
00366   return CBF_NONE;
00367 }
00368 
00375 static CallBackFunction ToolbarScenSaveOrLoad(Window *w)
00376 {
00377   PopupMainToolbMenu(w, WID_TE_SAVE, STR_SCENEDIT_FILE_MENU_SAVE_SCENARIO, SLEME_MENUCOUNT);
00378   return CBF_NONE;
00379 }
00380 
00387 static CallBackFunction MenuClickSaveLoad(int index = 0)
00388 {
00389   if (_game_mode == GM_EDITOR) {
00390     switch (index) {
00391       case SLEME_SAVE_SCENARIO:  ShowSaveLoadDialog(SLD_SAVE_SCENARIO);  break;
00392       case SLEME_LOAD_SCENARIO:  ShowSaveLoadDialog(SLD_LOAD_SCENARIO);  break;
00393       case SLEME_SAVE_HEIGHTMAP: ShowSaveLoadDialog(SLD_SAVE_HEIGHTMAP); break;
00394       case SLEME_LOAD_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
00395       case SLEME_EXIT_TOINTRO:   AskExitToGameMenu();                    break;
00396       case SLEME_EXIT_GAME:      HandleExitGameRequest();                break;
00397     }
00398   } else {
00399     switch (index) {
00400       case SLNME_SAVE_GAME:      ShowSaveLoadDialog(SLD_SAVE_GAME); break;
00401       case SLNME_LOAD_GAME:      ShowSaveLoadDialog(SLD_LOAD_GAME); break;
00402       case SLNME_EXIT_TOINTRO:   AskExitToGameMenu();               break;
00403       case SLNME_EXIT_GAME:      HandleExitGameRequest();           break;
00404     }
00405   }
00406   return CBF_NONE;
00407 }
00408 
00409 /* --- Map button menu --- */
00410 
00411 enum MapMenuEntries {
00412   MME_SHOW_SMALLMAP        = 0,
00413   MME_SHOW_EXTRAVIEWPORTS,
00414   MME_SHOW_SIGNLISTS,
00415   MME_SHOW_TOWNDIRECTORY,    
00416   MME_MENUCOUNT_NORMAL     = 3,
00417   MME_MENUCOUNT_EDITOR     = 4,
00418 };
00419 
00420 static CallBackFunction ToolbarMapClick(Window *w)
00421 {
00422   PopupMainToolbMenu(w, WID_TN_SMALL_MAP, STR_MAP_MENU_MAP_OF_WORLD, MME_MENUCOUNT_NORMAL);
00423   return CBF_NONE;
00424 }
00425 
00426 static CallBackFunction ToolbarScenMapTownDir(Window *w)
00427 {
00428   PopupMainToolbMenu(w, WID_TE_SMALL_MAP, STR_MAP_MENU_MAP_OF_WORLD, MME_MENUCOUNT_EDITOR);
00429   return CBF_NONE;
00430 }
00431 
00438 static CallBackFunction MenuClickMap(int index)
00439 {
00440   switch (index) {
00441     case MME_SHOW_SMALLMAP:       ShowSmallMap();            break;
00442     case MME_SHOW_EXTRAVIEWPORTS: ShowExtraViewPortWindow(); break;
00443     case MME_SHOW_SIGNLISTS:      ShowSignList();            break;
00444     case MME_SHOW_TOWNDIRECTORY:  if (_game_mode == GM_EDITOR) ShowTownDirectory(); break;
00445   }
00446   return CBF_NONE;
00447 }
00448 
00449 /* --- Town button menu --- */
00450 
00451 static CallBackFunction ToolbarTownClick(Window *w)
00452 {
00453   PopupMainToolbMenu(w, WID_TN_TOWNS, STR_TOWN_MENU_TOWN_DIRECTORY, (_settings_game.economy.found_town == TF_FORBIDDEN) ? 1 : 2);
00454   return CBF_NONE;
00455 }
00456 
00463 static CallBackFunction MenuClickTown(int index)
00464 {
00465   switch (index) {
00466     case 0: ShowTownDirectory(); break;
00467     case 1: // setting could be changed when the dropdown was open
00468       if (_settings_game.economy.found_town != TF_FORBIDDEN) ShowFoundTownWindow();
00469       break;
00470   }
00471   return CBF_NONE;
00472 }
00473 
00474 /* --- Subidies button menu --- */
00475 
00476 static CallBackFunction ToolbarSubsidiesClick(Window *w)
00477 {
00478   PopupMainToolbMenu(w, WID_TN_SUBSIDIES, STR_SUBSIDIES_MENU_SUBSIDIES, 2);
00479   return CBF_NONE;
00480 }
00481 
00488 static CallBackFunction MenuClickSubsidies(int index)
00489 {
00490   switch (index) {
00491     case 0: ShowSubsidiesList(); break;
00492     case 1: ShowGoalsList();     break;
00493   }
00494   return CBF_NONE;
00495 }
00496 
00497 /* --- Stations button menu --- */
00498 
00499 static CallBackFunction ToolbarStationsClick(Window *w)
00500 {
00501   PopupMainCompanyToolbMenu(w, WID_TN_STATIONS);
00502   return CBF_NONE;
00503 }
00504 
00511 static CallBackFunction MenuClickStations(int index)
00512 {
00513   ShowCompanyStations((CompanyID)index);
00514   return CBF_NONE;
00515 }
00516 
00517 /* --- Finances button menu --- */
00518 
00519 static CallBackFunction ToolbarFinancesClick(Window *w)
00520 {
00521   PopupMainCompanyToolbMenu(w, WID_TN_FINANCES);
00522   return CBF_NONE;
00523 }
00524 
00531 static CallBackFunction MenuClickFinances(int index)
00532 {
00533   ShowCompanyFinances((CompanyID)index);
00534   return CBF_NONE;
00535 }
00536 
00537 /* --- Company's button menu --- */
00538 
00539 static CallBackFunction ToolbarCompaniesClick(Window *w)
00540 {
00541   PopupMainCompanyToolbMenu(w, WID_TN_COMPANIES);
00542   return CBF_NONE;
00543 }
00544 
00551 static CallBackFunction MenuClickCompany(int index)
00552 {
00553 #ifdef ENABLE_NETWORK
00554   if (_networking) {
00555     switch (index) {
00556       case CTMN_CLIENT_LIST:
00557         ShowClientList();
00558         return CBF_NONE;
00559 
00560       case CTMN_NEW_COMPANY:
00561         if (_network_server) {
00562           DoCommandP(0, 0, _network_own_client_id, CMD_COMPANY_CTRL);
00563         } else {
00564           NetworkSendCommand(0, 0, 0, CMD_COMPANY_CTRL, NULL, NULL, _local_company);
00565         }
00566         return CBF_NONE;
00567 
00568       case CTMN_SPECTATE:
00569         if (_network_server) {
00570           NetworkServerDoMove(CLIENT_ID_SERVER, COMPANY_SPECTATOR);
00571           MarkWholeScreenDirty();
00572         } else {
00573           NetworkClientRequestMove(COMPANY_SPECTATOR);
00574         }
00575         return CBF_NONE;
00576     }
00577   }
00578 #endif /* ENABLE_NETWORK */
00579   ShowCompany((CompanyID)index);
00580   return CBF_NONE;
00581 }
00582 
00583 /* --- Graphs button menu --- */
00584 
00585 static CallBackFunction ToolbarGraphsClick(Window *w)
00586 {
00587   PopupMainToolbMenu(w, WID_TN_GRAPHS, STR_GRAPH_MENU_OPERATING_PROFIT_GRAPH, (_toolbar_mode == TB_NORMAL) ? 6 : 8);
00588   return CBF_NONE;
00589 }
00590 
00597 static CallBackFunction MenuClickGraphs(int index)
00598 {
00599   switch (index) {
00600     case 0: ShowOperatingProfitGraph();    break;
00601     case 1: ShowIncomeGraph();             break;
00602     case 2: ShowDeliveredCargoGraph();     break;
00603     case 3: ShowPerformanceHistoryGraph(); break;
00604     case 4: ShowCompanyValueGraph();       break;
00605     case 5: ShowCargoPaymentRates();       break;
00606     /* functions for combined graphs/league button */
00607     case 6: ShowCompanyLeagueTable();      break;
00608     case 7: ShowPerformanceRatingDetail(); break;
00609   }
00610   return CBF_NONE;
00611 }
00612 
00613 /* --- League button menu --- */
00614 
00615 static CallBackFunction ToolbarLeagueClick(Window *w)
00616 {
00617   PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE, 2);
00618   return CBF_NONE;
00619 }
00620 
00627 static CallBackFunction MenuClickLeague(int index)
00628 {
00629   switch (index) {
00630     case 0: ShowCompanyLeagueTable();      break;
00631     case 1: ShowPerformanceRatingDetail(); break;
00632   }
00633   return CBF_NONE;
00634 }
00635 
00636 /* --- Industries button menu --- */
00637 
00638 static CallBackFunction ToolbarIndustryClick(Window *w)
00639 {
00640   /* Disable build-industry menu if we are a spectator */
00641   PopupMainToolbMenu(w, WID_TN_INDUSTRIES, STR_INDUSTRY_MENU_INDUSTRY_DIRECTORY, (_local_company == COMPANY_SPECTATOR) ? 1 : 2);
00642   return CBF_NONE;
00643 }
00644 
00651 static CallBackFunction MenuClickIndustry(int index)
00652 {
00653   switch (index) {
00654     case 0: ShowIndustryDirectory();   break;
00655     case 1: ShowBuildIndustryWindow(); break;
00656   }
00657   return CBF_NONE;
00658 }
00659 
00660 /* --- Trains button menu + 1 helper function for all vehicles. --- */
00661 
00662 static void ToolbarVehicleClick(Window *w, VehicleType veh)
00663 {
00664   const Vehicle *v;
00665   int dis = ~0;
00666 
00667   FOR_ALL_VEHICLES(v) {
00668     if (v->type == veh && v->IsPrimaryVehicle()) ClrBit(dis, v->owner);
00669   }
00670   PopupMainCompanyToolbMenu(w, WID_TN_VEHICLE_START + veh, dis);
00671 }
00672 
00673 
00674 static CallBackFunction ToolbarTrainClick(Window *w)
00675 {
00676   ToolbarVehicleClick(w, VEH_TRAIN);
00677   return CBF_NONE;
00678 }
00679 
00686 static CallBackFunction MenuClickShowTrains(int index)
00687 {
00688   ShowVehicleListWindow((CompanyID)index, VEH_TRAIN);
00689   return CBF_NONE;
00690 }
00691 
00692 /* --- Road vehicle button menu --- */
00693 
00694 static CallBackFunction ToolbarRoadClick(Window *w)
00695 {
00696   ToolbarVehicleClick(w, VEH_ROAD);
00697   return CBF_NONE;
00698 }
00699 
00706 static CallBackFunction MenuClickShowRoad(int index)
00707 {
00708   ShowVehicleListWindow((CompanyID)index, VEH_ROAD);
00709   return CBF_NONE;
00710 }
00711 
00712 /* --- Ship button menu --- */
00713 
00714 static CallBackFunction ToolbarShipClick(Window *w)
00715 {
00716   ToolbarVehicleClick(w, VEH_SHIP);
00717   return CBF_NONE;
00718 }
00719 
00726 static CallBackFunction MenuClickShowShips(int index)
00727 {
00728   ShowVehicleListWindow((CompanyID)index, VEH_SHIP);
00729   return CBF_NONE;
00730 }
00731 
00732 /* --- Aircraft button menu --- */
00733 
00734 static CallBackFunction ToolbarAirClick(Window *w)
00735 {
00736   ToolbarVehicleClick(w, VEH_AIRCRAFT);
00737   return CBF_NONE;
00738 }
00739 
00746 static CallBackFunction MenuClickShowAir(int index)
00747 {
00748   ShowVehicleListWindow((CompanyID)index, VEH_AIRCRAFT);
00749   return CBF_NONE;
00750 }
00751 
00752 /* --- Zoom in button --- */
00753 
00754 static CallBackFunction ToolbarZoomInClick(Window *w)
00755 {
00756   if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
00757     w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_IN : (byte)WID_TN_ZOOM_IN);
00758     SndPlayFx(SND_15_BEEP);
00759   }
00760   return CBF_NONE;
00761 }
00762 
00763 /* --- Zoom out button --- */
00764 
00765 static CallBackFunction ToolbarZoomOutClick(Window *w)
00766 {
00767   if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
00768     w->HandleButtonClick((_game_mode == GM_EDITOR) ? (byte)WID_TE_ZOOM_OUT : (byte)WID_TN_ZOOM_OUT);
00769     SndPlayFx(SND_15_BEEP);
00770   }
00771   return CBF_NONE;
00772 }
00773 
00774 /* --- Rail button menu --- */
00775 
00776 static CallBackFunction ToolbarBuildRailClick(Window *w)
00777 {
00778   ShowDropDownList(w, GetRailTypeDropDownList(), _last_built_railtype, WID_TN_RAILS, 140, true, true);
00779   SndPlayFx(SND_15_BEEP);
00780   return CBF_NONE;
00781 }
00782 
00789 static CallBackFunction MenuClickBuildRail(int index)
00790 {
00791   _last_built_railtype = (RailType)index;
00792   ShowBuildRailToolbar(_last_built_railtype);
00793   return CBF_NONE;
00794 }
00795 
00796 /* --- Road button menu --- */
00797 
00798 static CallBackFunction ToolbarBuildRoadClick(Window *w)
00799 {
00800   const Company *c = Company::Get(_local_company);
00801   DropDownList *list = new DropDownList();
00802 
00803   /* Road is always visible and available. */
00804   list->push_back(new DropDownListStringItem(STR_ROAD_MENU_ROAD_CONSTRUCTION, ROADTYPE_ROAD, false));
00805 
00806   /* Tram is only visible when there will be a tram, and available when that has been introduced. */
00807   Engine *e;
00808   FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
00809     if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
00810     if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
00811 
00812     list->push_back(new DropDownListStringItem(STR_ROAD_MENU_TRAM_CONSTRUCTION, ROADTYPE_TRAM, !HasBit(c->avail_roadtypes, ROADTYPE_TRAM)));
00813     break;
00814   }
00815   ShowDropDownList(w, list, _last_built_roadtype, WID_TN_ROADS, 140, true, true);
00816   SndPlayFx(SND_15_BEEP);
00817   return CBF_NONE;
00818 }
00819 
00826 static CallBackFunction MenuClickBuildRoad(int index)
00827 {
00828   _last_built_roadtype = (RoadType)index;
00829   ShowBuildRoadToolbar(_last_built_roadtype);
00830   return CBF_NONE;
00831 }
00832 
00833 /* --- Water button menu --- */
00834 
00835 static CallBackFunction ToolbarBuildWaterClick(Window *w)
00836 {
00837   PopupMainToolbMenu(w, WID_TN_WATER, STR_WATERWAYS_MENU_WATERWAYS_CONSTRUCTION, 1);
00838   return CBF_NONE;
00839 }
00840 
00847 static CallBackFunction MenuClickBuildWater(int index)
00848 {
00849   ShowBuildDocksToolbar();
00850   return CBF_NONE;
00851 }
00852 
00853 /* --- Airport button menu --- */
00854 
00855 static CallBackFunction ToolbarBuildAirClick(Window *w)
00856 {
00857   PopupMainToolbMenu(w, WID_TN_AIR, STR_AIRCRAFT_MENU_AIRPORT_CONSTRUCTION, 1);
00858   return CBF_NONE;
00859 }
00860 
00867 static CallBackFunction MenuClickBuildAir(int index)
00868 {
00869   ShowBuildAirToolbar();
00870   return CBF_NONE;
00871 }
00872 
00873 /* --- Forest button menu --- */
00874 
00875 static CallBackFunction ToolbarForestClick(Window *w)
00876 {
00877   PopupMainToolbMenu(w, WID_TN_LANDSCAPE, STR_LANDSCAPING_MENU_LANDSCAPING, 3);
00878   return CBF_NONE;
00879 }
00880 
00887 static CallBackFunction MenuClickForest(int index)
00888 {
00889   switch (index) {
00890     case 0: ShowTerraformToolbar();  break;
00891     case 1: ShowBuildTreesToolbar(); break;
00892     case 2: return SelectSignTool();
00893   }
00894   return CBF_NONE;
00895 }
00896 
00897 /* --- Music button menu --- */
00898 
00899 static CallBackFunction ToolbarMusicClick(Window *w)
00900 {
00901   PopupMainToolbMenu(w, WID_TN_MUSIC_SOUND, STR_TOOLBAR_SOUND_MUSIC, 1);
00902   return CBF_NONE;
00903 }
00904 
00911 static CallBackFunction MenuClickMusicWindow(int index)
00912 {
00913   ShowMusicWindow();
00914   return CBF_NONE;
00915 }
00916 
00917 /* --- Newspaper button menu --- */
00918 
00919 static CallBackFunction ToolbarNewspaperClick(Window *w)
00920 {
00921   PopupMainToolbMenu(w, WID_TN_MESSAGES, STR_NEWS_MENU_LAST_MESSAGE_NEWS_REPORT, 3);
00922   return CBF_NONE;
00923 }
00924 
00931 static CallBackFunction MenuClickNewspaper(int index)
00932 {
00933   switch (index) {
00934     case 0: ShowLastNewsMessage(); break;
00935     case 1: ShowMessageOptions();  break;
00936     case 2: ShowMessageHistory();  break;
00937   }
00938   return CBF_NONE;
00939 }
00940 
00941 /* --- Help button menu --- */
00942 
00943 static CallBackFunction PlaceLandBlockInfo()
00944 {
00945   if (_cursor.sprite == SPR_CURSOR_QUERY) {
00946     ResetObjectToPlace();
00947     return CBF_NONE;
00948   } else {
00949     SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, HT_RECT, WC_MAIN_TOOLBAR, 0);
00950     return CBF_PLACE_LANDINFO;
00951   }
00952 }
00953 
00954 static CallBackFunction ToolbarHelpClick(Window *w)
00955 {
00956   PopupMainToolbMenu(w, WID_TN_HELP, STR_ABOUT_MENU_LAND_BLOCK_INFO, _settings_client.gui.newgrf_developer_tools ? 10 : 8);
00957   return CBF_NONE;
00958 }
00959 
00960 static void MenuClickSmallScreenshot()
00961 {
00962   MakeScreenshot(SC_VIEWPORT, NULL);
00963 }
00964 
00965 static void MenuClickZoomedInScreenshot()
00966 {
00967   MakeScreenshot(SC_ZOOMEDIN, NULL);
00968 }
00969 
00970 static void MenuClickWorldScreenshot()
00971 {
00972   MakeScreenshot(SC_WORLD, NULL);
00973 }
00974 
00982 void ToggleBoundingBoxes()
00983 {
00984   extern bool _draw_bounding_boxes;
00985   /* Always allow to toggle them off */
00986   if (_settings_client.gui.newgrf_developer_tools || _draw_bounding_boxes) {
00987     _draw_bounding_boxes = !_draw_bounding_boxes;
00988     MarkWholeScreenDirty();
00989   }
00990 }
00991 
00997 static CallBackFunction MenuClickHelp(int index)
00998 {
00999   switch (index) {
01000     case 0: return PlaceLandBlockInfo();
01001     case 2: IConsoleSwitch();              break;
01002     case 3: ShowAIDebugWindow();           break;
01003     case 4: MenuClickSmallScreenshot();    break;
01004     case 5: MenuClickZoomedInScreenshot(); break;
01005     case 6: MenuClickWorldScreenshot();    break;
01006     case 7: ShowAboutWindow();             break;
01007     case 8: ShowSpriteAlignerWindow();     break;
01008     case 9: ToggleBoundingBoxes();         break;
01009   }
01010   return CBF_NONE;
01011 }
01012 
01013 /* --- Switch toolbar button --- */
01014 
01015 static CallBackFunction ToolbarSwitchClick(Window *w)
01016 {
01017   if (_toolbar_mode != TB_LOWER) {
01018     _toolbar_mode = TB_LOWER;
01019   } else {
01020     _toolbar_mode = TB_UPPER;
01021   }
01022 
01023   w->ReInit();
01024   w->SetWidgetLoweredState(WID_TN_SWITCH_BAR, _toolbar_mode == TB_LOWER);
01025   SndPlayFx(SND_15_BEEP);
01026   return CBF_NONE;
01027 }
01028 
01029 /* --- Scenario editor specific handlers. */
01030 
01034 static CallBackFunction ToolbarScenDatePanel(Window *w)
01035 {
01036   SetDParam(0, _settings_game.game_creation.starting_year);
01037   ShowQueryString(STR_JUST_INT, STR_MAPGEN_START_DATE_QUERY_CAPT, 8, w, CS_NUMERAL, QSF_ENABLE_DEFAULT);
01038   _left_button_clicked = false;
01039   return CBF_NONE;
01040 }
01041 
01042 static CallBackFunction ToolbarScenDateBackward(Window *w)
01043 {
01044   /* don't allow too fast scrolling */
01045   if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
01046     w->HandleButtonClick(WID_TE_DATE_BACKWARD);
01047     w->SetDirty();
01048 
01049     _settings_game.game_creation.starting_year = Clamp(_settings_game.game_creation.starting_year - 1, MIN_YEAR, MAX_YEAR);
01050     SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
01051   }
01052   _left_button_clicked = false;
01053   return CBF_NONE;
01054 }
01055 
01056 static CallBackFunction ToolbarScenDateForward(Window *w)
01057 {
01058   /* don't allow too fast scrolling */
01059   if (!(w->flags & WF_TIMEOUT) || w->timeout_timer <= 1) {
01060     w->HandleButtonClick(WID_TE_DATE_FORWARD);
01061     w->SetDirty();
01062 
01063     _settings_game.game_creation.starting_year = Clamp(_settings_game.game_creation.starting_year + 1, MIN_YEAR, MAX_YEAR);
01064     SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
01065   }
01066   _left_button_clicked = false;
01067   return CBF_NONE;
01068 }
01069 
01070 static CallBackFunction ToolbarScenGenLand(Window *w)
01071 {
01072   w->HandleButtonClick(WID_TE_LAND_GENERATE);
01073   SndPlayFx(SND_15_BEEP);
01074 
01075   ShowEditorTerraformToolbar();
01076   return CBF_NONE;
01077 }
01078 
01079 
01080 static CallBackFunction ToolbarScenGenTown(Window *w)
01081 {
01082   w->HandleButtonClick(WID_TE_TOWN_GENERATE);
01083   SndPlayFx(SND_15_BEEP);
01084   ShowFoundTownWindow();
01085   return CBF_NONE;
01086 }
01087 
01088 static CallBackFunction ToolbarScenGenIndustry(Window *w)
01089 {
01090   w->HandleButtonClick(WID_TE_INDUSTRY);
01091   SndPlayFx(SND_15_BEEP);
01092   ShowBuildIndustryWindow();
01093   return CBF_NONE;
01094 }
01095 
01096 static CallBackFunction ToolbarScenBuildRoad(Window *w)
01097 {
01098   w->HandleButtonClick(WID_TE_ROADS);
01099   SndPlayFx(SND_15_BEEP);
01100   ShowBuildRoadScenToolbar();
01101   return CBF_NONE;
01102 }
01103 
01104 static CallBackFunction ToolbarScenBuildDocks(Window *w)
01105 {
01106   w->HandleButtonClick(WID_TE_WATER);
01107   SndPlayFx(SND_15_BEEP);
01108   ShowBuildDocksScenToolbar();
01109   return CBF_NONE;
01110 }
01111 
01112 static CallBackFunction ToolbarScenPlantTrees(Window *w)
01113 {
01114   w->HandleButtonClick(WID_TE_TREES);
01115   SndPlayFx(SND_15_BEEP);
01116   ShowBuildTreesToolbar();
01117   return CBF_NONE;
01118 }
01119 
01120 static CallBackFunction ToolbarScenPlaceSign(Window *w)
01121 {
01122   w->HandleButtonClick(WID_TE_SIGNS);
01123   SndPlayFx(SND_15_BEEP);
01124   return SelectSignTool();
01125 }
01126 
01127 static CallBackFunction ToolbarBtn_NULL(Window *w)
01128 {
01129   return CBF_NONE;
01130 }
01131 
01132 typedef CallBackFunction MenuClickedProc(int index);
01133 
01134 static MenuClickedProc * const _menu_clicked_procs[] = {
01135   NULL,                 // 0
01136   NULL,                 // 1
01137   MenuClickSettings,    // 2
01138   MenuClickSaveLoad,    // 3
01139   MenuClickMap,         // 4
01140   MenuClickTown,        // 5
01141   MenuClickSubsidies,   // 6
01142   MenuClickStations,    // 7
01143   MenuClickFinances,    // 8
01144   MenuClickCompany,     // 9
01145   MenuClickGraphs,      // 10
01146   MenuClickLeague,      // 11
01147   MenuClickIndustry,    // 12
01148   MenuClickShowTrains,  // 13
01149   MenuClickShowRoad,    // 14
01150   MenuClickShowShips,   // 15
01151   MenuClickShowAir,     // 16
01152   MenuClickMap,         // 17
01153   NULL,                 // 18
01154   MenuClickBuildRail,   // 19
01155   MenuClickBuildRoad,   // 20
01156   MenuClickBuildWater,  // 21
01157   MenuClickBuildAir,    // 22
01158   MenuClickForest,      // 23
01159   MenuClickMusicWindow, // 24
01160   MenuClickNewspaper,   // 25
01161   MenuClickHelp,        // 26
01162 };
01163 
01164 int16 *_preferred_toolbar_size = NULL; 
01165 
01167 class NWidgetToolbarContainer : public NWidgetContainer {
01168   bool visible[WID_TN_END]; 
01169 protected:
01170   uint spacers;          
01171 
01172 public:
01173   NWidgetToolbarContainer() : NWidgetContainer(NWID_HORIZONTAL)
01174   {
01175   }
01176 
01182   bool IsButton(WidgetType type) const
01183   {
01184     return type == WWT_IMGBTN || type == WWT_IMGBTN_2 || type == WWT_PUSHIMGBTN;
01185   }
01186 
01187   void SetupSmallestSize(Window *w, bool init_array)
01188   {
01189     this->smallest_x = 0; // Biggest child
01190     this->smallest_y = 0; // Biggest child
01191     this->fill_x = 1;
01192     this->fill_y = 0;
01193     this->resize_x = 1; // We only resize in this direction
01194     this->resize_y = 0; // We never resize in this direction
01195     this->spacers = 0;
01196 
01197     uint nbuttons = 0;
01198     /* First initialise some variables... */
01199     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01200       child_wid->SetupSmallestSize(w, init_array);
01201       this->smallest_y = max(this->smallest_y, child_wid->smallest_y + child_wid->padding_top + child_wid->padding_bottom);
01202       if (this->IsButton(child_wid->type)) {
01203         nbuttons++;
01204         this->smallest_x = max(this->smallest_x, child_wid->smallest_x + child_wid->padding_left + child_wid->padding_right);
01205       } else if (child_wid->type == NWID_SPACER) {
01206         this->spacers++;
01207       }
01208     }
01209 
01210     /* ... then in a second pass make sure the 'current' heights are set. Won't change ever. */
01211     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01212       child_wid->current_y = this->smallest_y;
01213       if (!this->IsButton(child_wid->type)) {
01214         child_wid->current_x = child_wid->smallest_x;
01215       }
01216     }
01217     *_preferred_toolbar_size = nbuttons * this->smallest_x;
01218   }
01219 
01220   void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01221   {
01222     assert(given_width >= this->smallest_x && given_height >= this->smallest_y);
01223 
01224     this->pos_x = x;
01225     this->pos_y = y;
01226     this->current_x = given_width;
01227     this->current_y = given_height;
01228 
01229     /* Figure out what are the visible buttons */
01230     memset(this->visible, 0, sizeof(this->visible));
01231     uint arrangable_count, button_count, spacer_count;
01232     const byte *arrangement = GetButtonArrangement(given_width, arrangable_count, button_count, spacer_count);
01233     for (uint i = 0; i < arrangable_count; i++) {
01234       this->visible[arrangement[i]] = true;
01235     }
01236 
01237     /* Create us ourselves a quick lookup table */
01238     NWidgetBase *widgets[WID_TN_END];
01239     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01240       if (child_wid->type == NWID_SPACER) continue;
01241       widgets[((NWidgetCore*)child_wid)->index] = child_wid;
01242     }
01243 
01244     /* Now assign the widgets to their rightful place */
01245     uint position = 0; // Place to put next child relative to origin of the container.
01246     uint spacer_space = max(0, (int)given_width - (int)(button_count * this->smallest_x)); // Remaining spacing for 'spacer' widgets
01247     uint button_space = given_width - spacer_space; // Remaining spacing for the buttons
01248     uint spacer_i = 0;
01249     uint button_i = 0;
01250 
01251     /* Index into the arrangement indices. The macro lastof cannot be used here! */
01252     const byte *cur_wid = rtl ? &arrangement[arrangable_count - 1] : arrangement;
01253     for (uint i = 0; i < arrangable_count; i++) {
01254       NWidgetBase *child_wid = widgets[*cur_wid];
01255       /* If we have to give space to the spacers, do that */
01256       if (spacer_space != 0) {
01257         NWidgetBase *possible_spacer = rtl ? child_wid->next : child_wid->prev;
01258         if (possible_spacer != NULL && possible_spacer->type == NWID_SPACER) {
01259           uint add = spacer_space / (spacer_count - spacer_i);
01260           position += add;
01261           spacer_space -= add;
01262           spacer_i++;
01263         }
01264       }
01265 
01266       /* Buttons can be scaled, the others not. */
01267       if (this->IsButton(child_wid->type)) {
01268         child_wid->current_x = button_space / (button_count - button_i);
01269         button_space -= child_wid->current_x;
01270         button_i++;
01271       }
01272       child_wid->AssignSizePosition(sizing, x + position, y, child_wid->current_x, this->current_y, rtl);
01273       position += child_wid->current_x;
01274 
01275       if (rtl) {
01276         cur_wid--;
01277       } else {
01278         cur_wid++;
01279       }
01280     }
01281   }
01282 
01283   /* virtual */ void Draw(const Window *w)
01284   {
01285     /* Draw brown-red toolbar bg. */
01286     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);
01287     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);
01288 
01289     bool rtl = _current_text_dir == TD_RTL;
01290     for (NWidgetBase *child_wid = rtl ? this->tail : this->head; child_wid != NULL; child_wid = rtl ? child_wid->prev : child_wid->next) {
01291       if (child_wid->type == NWID_SPACER) continue;
01292       if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
01293 
01294       child_wid->Draw(w);
01295     }
01296   }
01297 
01298   /* virtual */ NWidgetCore *GetWidgetFromPos(int x, int y)
01299   {
01300     if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01301 
01302     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01303       if (child_wid->type == NWID_SPACER) continue;
01304       if (!this->visible[((NWidgetCore*)child_wid)->index]) continue;
01305 
01306       NWidgetCore *nwid = child_wid->GetWidgetFromPos(x, y);
01307       if (nwid != NULL) return nwid;
01308     }
01309     return NULL;
01310   }
01311 
01320   virtual const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const = 0;
01321 };
01322 
01324 class NWidgetMainToolbarContainer : public NWidgetToolbarContainer {
01325   /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
01326   {
01327     static const uint SMALLEST_ARRANGEMENT = 14;
01328     static const uint BIGGEST_ARRANGEMENT  = 19;
01329     static const byte arrange14[] = {
01330       0,  1, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 27,
01331       2,  3,  4,  5,  6,  7,  8,  9, 10, 12, 24, 25, 26, 27,
01332     };
01333     static const byte arrange15[] = {
01334       0,  1,  4, 13, 14, 15, 16, 19, 20, 21, 22, 23, 17, 18, 27,
01335       0,  2,  4,  3,  5,  6,  7,  8,  9, 10, 12, 24, 25, 26, 27,
01336     };
01337     static const byte arrange16[] = {
01338       0,  1,  2,  4, 13, 14, 15, 16, 19, 20, 21, 22, 23, 17, 18, 27,
01339       0,  1,  3,  5,  6,  7,  8,  9, 10, 12, 24, 25, 26, 17, 18, 27,
01340     };
01341     static const byte arrange17[] = {
01342       0,  1,  2,  4,  6, 13, 14, 15, 16, 19, 20, 21, 22, 23, 17, 18, 27,
01343       0,  1,  3,  4,  6,  5,  7,  8,  9, 10, 12, 24, 25, 26, 17, 18, 27,
01344     };
01345     static const byte arrange18[] = {
01346       0,  1,  2,  4,  5,  6,  7,  8,  9, 12, 19, 20, 21, 22, 23, 17, 18, 27,
01347       0,  1,  3,  4,  5,  6,  7, 10, 13, 14, 15, 16, 24, 25, 26, 17, 18, 27,
01348     };
01349     static const byte arrange19[] = {
01350       0,  1,  2,  4,  5,  6, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 17, 18, 27,
01351       0,  1,  3,  4,  7,  8,  9, 10, 12, 25, 19, 20, 21, 22, 23, 26, 17, 18, 27,
01352     };
01353     static const byte arrange_all[] = {
01354       0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
01355     };
01356 
01357     /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */
01358     uint full_buttons = max(CeilDiv(width, this->smallest_x), SMALLEST_ARRANGEMENT);
01359     if (full_buttons > BIGGEST_ARRANGEMENT) {
01360       button_count = arrangable_count = lengthof(arrange_all);
01361       spacer_count = this->spacers;
01362       return arrange_all;
01363     }
01364 
01365     /* Introduce the split toolbar */
01366     static const byte * const arrangements[] = { arrange14, arrange15, arrange16, arrange17, arrange18, arrange19 };
01367 
01368     button_count = arrangable_count = full_buttons;
01369     spacer_count = this->spacers;
01370     return arrangements[full_buttons - SMALLEST_ARRANGEMENT] + ((_toolbar_mode == TB_LOWER) ? full_buttons : 0);
01371   }
01372 };
01373 
01375 class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer {
01376   uint panel_widths[2]; 
01377 
01378   void SetupSmallestSize(Window *w, bool init_array)
01379   {
01380     this->NWidgetToolbarContainer::SetupSmallestSize(w, init_array);
01381 
01382     /* Find the size of panel_widths */
01383     uint i = 0;
01384     for (NWidgetBase *child_wid = this->head; child_wid != NULL; child_wid = child_wid->next) {
01385       if (child_wid->type == NWID_SPACER || this->IsButton(child_wid->type)) continue;
01386 
01387       assert(i < lengthof(this->panel_widths));
01388       this->panel_widths[i++] = child_wid->current_x;
01389       *_preferred_toolbar_size += child_wid->current_x;
01390     }
01391   }
01392 
01393   /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const
01394   {
01395     static const byte arrange_all[] = {
01396       0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 24, 26,
01397     };
01398     static const byte arrange_nopanel[] = {
01399       0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 24, 26,
01400     };
01401     static const byte arrange_switch[] = {
01402       18,  8, 11, 12, 13, 14, 15, 16, 17, 27,
01403        0,  1,  2,  3, 18,  9, 10, 24, 26, 27,
01404     };
01405 
01406     /* If we can place all buttons *and* the panels, show them. */
01407     uint min_full_width = (lengthof(arrange_all) - lengthof(this->panel_widths)) * this->smallest_x + this->panel_widths[0] + this->panel_widths[1];
01408     if (width >= min_full_width) {
01409       width -= this->panel_widths[0] + this->panel_widths[1];
01410       arrangable_count = lengthof(arrange_all);
01411       button_count = arrangable_count - 2;
01412       spacer_count = this->spacers;
01413       return arrange_all;
01414     }
01415 
01416     /* 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 */
01417     uint min_small_width = (lengthof(arrange_switch) - lengthof(this->panel_widths)) * this->smallest_x / 2 + this->panel_widths[1];
01418     if (width > min_small_width) {
01419       width -= this->panel_widths[1];
01420       arrangable_count = lengthof(arrange_nopanel);
01421       button_count = arrangable_count - 1;
01422       spacer_count = this->spacers - 1;
01423       return arrange_nopanel;
01424     }
01425 
01426     /* Split toolbar */
01427     width -= this->panel_widths[1];
01428     arrangable_count = lengthof(arrange_switch) / 2;
01429     button_count = arrangable_count - 1;
01430     spacer_count = 0;
01431     return arrange_switch + ((_toolbar_mode == TB_LOWER) ? arrangable_count : 0);
01432   }
01433 };
01434 
01435 /* --- Toolbar handling for the 'normal' case */
01436 
01437 typedef CallBackFunction ToolbarButtonProc(Window *w);
01438 
01439 static ToolbarButtonProc * const _toolbar_button_procs[] = {
01440   ToolbarPauseClick,
01441   ToolbarFastForwardClick,
01442   ToolbarOptionsClick,
01443   ToolbarSaveClick,
01444   ToolbarMapClick,
01445   ToolbarTownClick,
01446   ToolbarSubsidiesClick,
01447   ToolbarStationsClick,
01448   ToolbarFinancesClick,
01449   ToolbarCompaniesClick,
01450   ToolbarGraphsClick,
01451   ToolbarLeagueClick,
01452   ToolbarIndustryClick,
01453   ToolbarTrainClick,
01454   ToolbarRoadClick,
01455   ToolbarShipClick,
01456   ToolbarAirClick,
01457   ToolbarZoomInClick,
01458   ToolbarZoomOutClick,
01459   ToolbarBuildRailClick,
01460   ToolbarBuildRoadClick,
01461   ToolbarBuildWaterClick,
01462   ToolbarBuildAirClick,
01463   ToolbarForestClick,
01464   ToolbarMusicClick,
01465   ToolbarNewspaperClick,
01466   ToolbarHelpClick,
01467   ToolbarSwitchClick,
01468 };
01469 
01470 enum MainToolbarHotkeys {
01471   MTHK_PAUSE,
01472   MTHK_FASTFORWARD,
01473   MTHK_SETTINGS,
01474   MTHK_SAVEGAME,
01475   MTHK_LOADGAME,
01476   MTHK_SMALLMAP,
01477   MTHK_TOWNDIRECTORY,
01478   MTHK_SUBSIDIES,
01479   MTHK_STATIONS,
01480   MTHK_FINANCES,
01481   MTHK_COMPANIES,
01482   MTHK_GRAPHS,
01483   MTHK_LEAGUE,
01484   MTHK_INDUSTRIES,
01485   MTHK_TRAIN_LIST,
01486   MTHK_ROADVEH_LIST,
01487   MTHK_SHIP_LIST,
01488   MTHK_AIRCRAFT_LIST,
01489   MTHK_ZOOM_IN,
01490   MTHK_ZOOM_OUT,
01491   MTHK_BUILD_RAIL,
01492   MTHK_BUILD_ROAD,
01493   MTHK_BUILD_DOCKS,
01494   MTHK_BUILD_AIRPORT,
01495   MTHK_BUILD_TREES,
01496   MTHK_MUSIC,
01497   MTHK_AI_DEBUG,
01498   MTHK_SMALL_SCREENSHOT,
01499   MTHK_ZOOMEDIN_SCREENSHOT,
01500   MTHK_GIANT_SCREENSHOT,
01501   MTHK_CHEATS,
01502   MTHK_TERRAFORM,
01503   MTHK_EXTRA_VIEWPORT,
01504   MTHK_CLIENT_LIST,
01505   MTHK_SIGN_LIST,
01506 };
01507 
01509 struct MainToolbarWindow : Window {
01510   CallBackFunction last_started_action; 
01511 
01512   MainToolbarWindow(const WindowDesc *desc) : Window()
01513   {
01514     this->InitNested(desc, 0);
01515 
01516     this->last_started_action = CBF_NONE;
01517     CLRBITS(this->flags, WF_WHITE_BORDER);
01518     this->SetWidgetDisabledState(WID_TN_PAUSE, _networking && !_network_server); // if not server, disable pause button
01519     this->SetWidgetDisabledState(WID_TN_FAST_FORWARD, _networking); // if networking, disable fast-forward button
01520     PositionMainToolbar(this);
01521     DoZoomInOutWindow(ZOOM_NONE, this);
01522   }
01523 
01524   virtual void OnPaint()
01525   {
01526     /* If spectator, disable all construction buttons
01527      * ie : Build road, rail, ships, airports and landscaping
01528      * Since enabled state is the default, just disable when needed */
01529     this->SetWidgetsDisabledState(_local_company == COMPANY_SPECTATOR, WID_TN_RAILS, WID_TN_ROADS, WID_TN_WATER, WID_TN_AIR, WID_TN_LANDSCAPE, WIDGET_LIST_END);
01530     /* disable company list drop downs, if there are no companies */
01531     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);
01532 
01533     this->SetWidgetDisabledState(WID_TN_RAILS, !CanBuildVehicleInfrastructure(VEH_TRAIN));
01534     this->SetWidgetDisabledState(WID_TN_AIR, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
01535 
01536     this->DrawWidgets();
01537   }
01538 
01539   virtual void OnClick(Point pt, int widget, int click_count)
01540   {
01541     if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
01542   }
01543 
01544   virtual void OnDropdownSelect(int widget, int index)
01545   {
01546     CallBackFunction cbf = _menu_clicked_procs[widget](index);
01547     if (cbf != CBF_NONE) this->last_started_action = cbf;
01548   }
01549 
01550   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01551   {
01552     switch (CheckHotkeyMatch(maintoolbar_hotkeys, keycode, this)) {
01553       case MTHK_PAUSE: ToolbarPauseClick(this); break;
01554       case MTHK_FASTFORWARD: ToolbarFastForwardClick(this); break;
01555       case MTHK_SETTINGS: ShowGameOptions(); break;
01556       case MTHK_SAVEGAME: MenuClickSaveLoad(); break;
01557       case MTHK_LOADGAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
01558       case MTHK_SMALLMAP: ShowSmallMap(); break;
01559       case MTHK_TOWNDIRECTORY: ShowTownDirectory(); break;
01560       case MTHK_SUBSIDIES: ShowSubsidiesList(); break;
01561       case MTHK_STATIONS: ShowCompanyStations(_local_company); break;
01562       case MTHK_FINANCES: ShowCompanyFinances(_local_company); break;
01563       case MTHK_COMPANIES: ShowCompany(_local_company); break;
01564       case MTHK_GRAPHS: ShowOperatingProfitGraph(); break;
01565       case MTHK_LEAGUE: ShowCompanyLeagueTable(); break;
01566       case MTHK_INDUSTRIES: ShowBuildIndustryWindow(); break;
01567       case MTHK_TRAIN_LIST: ShowVehicleListWindow(_local_company, VEH_TRAIN); break;
01568       case MTHK_ROADVEH_LIST: ShowVehicleListWindow(_local_company, VEH_ROAD); break;
01569       case MTHK_SHIP_LIST: ShowVehicleListWindow(_local_company, VEH_SHIP); break;
01570       case MTHK_AIRCRAFT_LIST: ShowVehicleListWindow(_local_company, VEH_AIRCRAFT); break;
01571       case MTHK_ZOOM_IN: ToolbarZoomInClick(this); break;
01572       case MTHK_ZOOM_OUT: ToolbarZoomOutClick(this); break;
01573       case MTHK_BUILD_RAIL: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype); break;
01574       case MTHK_BUILD_ROAD: ShowBuildRoadToolbar(_last_built_roadtype); break;
01575       case MTHK_BUILD_DOCKS: ShowBuildDocksToolbar(); break;
01576       case MTHK_BUILD_AIRPORT: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
01577       case MTHK_BUILD_TREES: ShowBuildTreesToolbar(); break;
01578       case MTHK_MUSIC: ShowMusicWindow(); break;
01579       case MTHK_AI_DEBUG: ShowAIDebugWindow(); break;
01580       case MTHK_SMALL_SCREENSHOT: MenuClickSmallScreenshot(); break;
01581       case MTHK_ZOOMEDIN_SCREENSHOT: MenuClickZoomedInScreenshot(); break;
01582       case MTHK_GIANT_SCREENSHOT: MenuClickWorldScreenshot(); break;
01583       case MTHK_CHEATS: if (!_networking) ShowCheatWindow(); break;
01584       case MTHK_TERRAFORM: ShowTerraformToolbar(); break;
01585       case MTHK_EXTRA_VIEWPORT: ShowExtraViewPortWindowForTileUnderCursor(); break;
01586 #ifdef ENABLE_NETWORK
01587       case MTHK_CLIENT_LIST: if (_networking) ShowClientList(); break;
01588 #endif
01589       case MTHK_SIGN_LIST: ShowSignList(); break;
01590       default: return ES_NOT_HANDLED;
01591     }
01592     return ES_HANDLED;
01593   }
01594 
01595   virtual void OnPlaceObject(Point pt, TileIndex tile)
01596   {
01597     switch (this->last_started_action) {
01598       case CBF_PLACE_SIGN:
01599         PlaceProc_Sign(tile);
01600         break;
01601 
01602       case CBF_PLACE_LANDINFO:
01603         ShowLandInfo(tile);
01604         break;
01605 
01606       default: NOT_REACHED();
01607     }
01608   }
01609 
01610   virtual void OnTick()
01611   {
01612     if (this->IsWidgetLowered(WID_TN_PAUSE) != !!_pause_mode) {
01613       this->ToggleWidgetLoweredState(WID_TN_PAUSE);
01614       this->SetWidgetDirty(WID_TN_PAUSE);
01615     }
01616 
01617     if (this->IsWidgetLowered(WID_TN_FAST_FORWARD) != !!_fast_forward) {
01618       this->ToggleWidgetLoweredState(WID_TN_FAST_FORWARD);
01619       this->SetWidgetDirty(WID_TN_FAST_FORWARD);
01620     }
01621   }
01622 
01623   virtual void OnTimeout()
01624   {
01625     /* We do not want to automatically raise the pause, fast forward and
01626      * switchbar buttons; they have to stay down when pressed etc. */
01627     for (uint i = WID_TN_SETTINGS; i < WID_TN_SWITCH_BAR; i++) {
01628       if (this->IsWidgetLowered(i)) {
01629         this->RaiseWidget(i);
01630         this->SetWidgetDirty(i);
01631       }
01632     }
01633   }
01634 
01640   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
01641   {
01642     if (!gui_scope) return;
01643     if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TN_ZOOM_IN, WID_TN_ZOOM_OUT);
01644   }
01645 
01646   static Hotkey<MainToolbarWindow> maintoolbar_hotkeys[];
01647 };
01648 
01649 const uint16 _maintoolbar_pause_keys[] = {WKC_F1, WKC_PAUSE, 0};
01650 const uint16 _maintoolbar_zoomin_keys[] = {WKC_NUM_PLUS, WKC_EQUALS, WKC_SHIFT | WKC_EQUALS, WKC_SHIFT | WKC_F5, 0};
01651 const uint16 _maintoolbar_zoomout_keys[] = {WKC_NUM_MINUS, WKC_MINUS, WKC_SHIFT | WKC_MINUS, WKC_SHIFT | WKC_F6, 0};
01652 const uint16 _maintoolbar_smallmap_keys[] = {WKC_F4, 'M', 0};
01653 
01654 Hotkey<MainToolbarWindow> MainToolbarWindow::maintoolbar_hotkeys[] = {
01655   Hotkey<MainToolbarWindow>(_maintoolbar_pause_keys, "pause", MTHK_PAUSE),
01656   Hotkey<MainToolbarWindow>((uint16)0, "fastforward", MTHK_FASTFORWARD),
01657   Hotkey<MainToolbarWindow>(WKC_F2, "settings", MTHK_SETTINGS),
01658   Hotkey<MainToolbarWindow>(WKC_F3, "saveload", MTHK_SAVEGAME),
01659   Hotkey<MainToolbarWindow>((uint16)0, "load_game", MTHK_LOADGAME),
01660   Hotkey<MainToolbarWindow>(_maintoolbar_smallmap_keys, "smallmap", MTHK_SMALLMAP),
01661   Hotkey<MainToolbarWindow>(WKC_F5, "town_list", MTHK_TOWNDIRECTORY),
01662   Hotkey<MainToolbarWindow>(WKC_F6, "subsidies", MTHK_SUBSIDIES),
01663   Hotkey<MainToolbarWindow>(WKC_F7, "station_list", MTHK_STATIONS),
01664   Hotkey<MainToolbarWindow>(WKC_F8, "finances", MTHK_FINANCES),
01665   Hotkey<MainToolbarWindow>(WKC_F9, "companies", MTHK_COMPANIES),
01666   Hotkey<MainToolbarWindow>(WKC_F10, "graphs", MTHK_GRAPHS),
01667   Hotkey<MainToolbarWindow>(WKC_F11, "league", MTHK_LEAGUE),
01668   Hotkey<MainToolbarWindow>(WKC_F12, "industry_list", MTHK_INDUSTRIES),
01669   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F1, "train_list", MTHK_TRAIN_LIST),
01670   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F2, "roadveh_list", MTHK_ROADVEH_LIST),
01671   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F3, "ship_list", MTHK_SHIP_LIST),
01672   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F4, "aircraft_list", MTHK_AIRCRAFT_LIST),
01673   Hotkey<MainToolbarWindow>(_maintoolbar_zoomin_keys, "zoomin", MTHK_ZOOM_IN),
01674   Hotkey<MainToolbarWindow>(_maintoolbar_zoomout_keys, "zoomout", MTHK_ZOOM_OUT),
01675   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F7, "build_rail", MTHK_BUILD_RAIL),
01676   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F8, "build_road", MTHK_BUILD_ROAD),
01677   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F9, "build_docks", MTHK_BUILD_DOCKS),
01678   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F10, "build_airport", MTHK_BUILD_AIRPORT),
01679   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F11, "build_trees", MTHK_BUILD_TREES),
01680   Hotkey<MainToolbarWindow>(WKC_SHIFT | WKC_F12, "music", MTHK_MUSIC),
01681   Hotkey<MainToolbarWindow>((uint16)0, "ai_debug", MTHK_AI_DEBUG),
01682   Hotkey<MainToolbarWindow>(WKC_CTRL  | 'S', "small_screenshot", MTHK_SMALL_SCREENSHOT),
01683   Hotkey<MainToolbarWindow>(WKC_CTRL  | 'P', "zoomedin_screenshot", MTHK_ZOOMEDIN_SCREENSHOT),
01684   Hotkey<MainToolbarWindow>((uint16)0, "giant_screenshot", MTHK_GIANT_SCREENSHOT),
01685   Hotkey<MainToolbarWindow>(WKC_CTRL | WKC_ALT | 'C', "cheats", MTHK_CHEATS),
01686   Hotkey<MainToolbarWindow>('L', "terraform", MTHK_TERRAFORM),
01687   Hotkey<MainToolbarWindow>('V', "extra_viewport", MTHK_EXTRA_VIEWPORT),
01688 #ifdef ENABLE_NETWORK
01689   Hotkey<MainToolbarWindow>((uint16)0, "client_list", MTHK_CLIENT_LIST),
01690 #endif
01691   Hotkey<MainToolbarWindow>((uint16)0, "sign_list", MTHK_SIGN_LIST),
01692   HOTKEY_LIST_END(MainToolbarWindow)
01693 };
01694 Hotkey<MainToolbarWindow> *_maintoolbar_hotkeys = MainToolbarWindow::maintoolbar_hotkeys;
01695 
01696 static NWidgetBase *MakeMainToolbar(int *biggest_index)
01697 {
01699   static const SpriteID toolbar_button_sprites[] = {
01700     SPR_IMG_PAUSE,           // WID_TN_PAUSE
01701     SPR_IMG_FASTFORWARD,     // WID_TN_FAST_FORWARD
01702     SPR_IMG_SETTINGS,        // WID_TN_SETTINGS
01703     SPR_IMG_SAVE,            // WID_TN_SAVE
01704     SPR_IMG_SMALLMAP,        // WID_TN_SMALL_MAP
01705     SPR_IMG_TOWN,            // WID_TN_TOWNS
01706     SPR_IMG_SUBSIDIES,       // WID_TN_SUBSIDIES
01707     SPR_IMG_COMPANY_LIST,    // WID_TN_STATIONS
01708     SPR_IMG_COMPANY_FINANCE, // WID_TN_FINANCES
01709     SPR_IMG_COMPANY_GENERAL, // WID_TN_COMPANIES
01710     SPR_IMG_GRAPHS,          // WID_TN_GRAPHS
01711     SPR_IMG_COMPANY_LEAGUE,  // WID_TN_LEAGUE
01712     SPR_IMG_INDUSTRY,        // WID_TN_INDUSTRIES
01713     SPR_IMG_TRAINLIST,       // WID_TN_TRAINS
01714     SPR_IMG_TRUCKLIST,       // WID_TN_ROADVEHS
01715     SPR_IMG_SHIPLIST,        // WID_TN_SHIPS
01716     SPR_IMG_AIRPLANESLIST,   // WID_TN_AIRCRAFT
01717     SPR_IMG_ZOOMIN,          // WID_TN_ZOOMIN
01718     SPR_IMG_ZOOMOUT,         // WID_TN_ZOOMOUT
01719     SPR_IMG_BUILDRAIL,       // WID_TN_RAILS
01720     SPR_IMG_BUILDROAD,       // WID_TN_ROADS
01721     SPR_IMG_BUILDWATER,      // WID_TN_WATER
01722     SPR_IMG_BUILDAIR,        // WID_TN_AIR
01723     SPR_IMG_LANDSCAPING,     // WID_TN_LANDSCAPE
01724     SPR_IMG_MUSIC,           // WID_TN_MUSIC_SOUND
01725     SPR_IMG_MESSAGES,        // WID_TN_MESSAGES
01726     SPR_IMG_QUERY,           // WID_TN_HELP
01727     SPR_IMG_SWITCH_TOOLBAR,  // WID_TN_SWITCH_BAR
01728   };
01729 
01730   NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer();
01731   for (uint i = 0; i < WID_TN_END; i++) {
01732     switch (i) {
01733       case 4: case 8: case 13: case 17: case 19: case 24: hor->Add(new NWidgetSpacer(0, 0)); break;
01734     }
01735     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));
01736   }
01737 
01738   *biggest_index = max<int>(*biggest_index, WID_TN_SWITCH_BAR);
01739   return hor;
01740 }
01741 
01742 static const NWidgetPart _nested_toolbar_normal_widgets[] = {
01743   NWidgetFunction(MakeMainToolbar),
01744 };
01745 
01746 static WindowDesc _toolb_normal_desc(
01747   WDP_MANUAL, 640, 22,
01748   WC_MAIN_TOOLBAR, WC_NONE,
01749   WDF_NO_FOCUS,
01750   _nested_toolbar_normal_widgets, lengthof(_nested_toolbar_normal_widgets)
01751 );
01752 
01753 
01754 /* --- Toolbar handling for the scenario editor */
01755 
01756 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
01757   ToolbarPauseClick,
01758   ToolbarFastForwardClick,
01759   ToolbarOptionsClick,
01760   ToolbarScenSaveOrLoad,
01761   ToolbarBtn_NULL,
01762   ToolbarScenDatePanel,
01763   ToolbarScenDateBackward,
01764   ToolbarScenDateForward,
01765   ToolbarScenMapTownDir,
01766   ToolbarZoomInClick,
01767   ToolbarZoomOutClick,
01768   ToolbarScenGenLand,
01769   ToolbarScenGenTown,
01770   ToolbarScenGenIndustry,
01771   ToolbarScenBuildRoad,
01772   ToolbarScenBuildDocks,
01773   ToolbarScenPlantTrees,
01774   ToolbarScenPlaceSign,
01775   ToolbarBtn_NULL,
01776   NULL,
01777   NULL,
01778   NULL,
01779   NULL,
01780   NULL,
01781   ToolbarMusicClick,
01782   NULL,
01783   ToolbarHelpClick,
01784   ToolbarSwitchClick,
01785 };
01786 
01787 enum MainToolbarEditorHotkeys {
01788   MTEHK_PAUSE,
01789   MTEHK_FASTFORWARD,
01790   MTEHK_SETTINGS,
01791   MTEHK_SAVEGAME,
01792   MTEHK_GENLAND,
01793   MTEHK_GENTOWN,
01794   MTEHK_GENINDUSTRY,
01795   MTEHK_BUILD_ROAD,
01796   MTEHK_BUILD_DOCKS,
01797   MTEHK_BUILD_TREES,
01798   MTEHK_SIGN,
01799   MTEHK_MUSIC,
01800   MTEHK_LANDINFO,
01801   MTEHK_SMALL_SCREENSHOT,
01802   MTEHK_ZOOMEDIN_SCREENSHOT,
01803   MTEHK_GIANT_SCREENSHOT,
01804   MTEHK_ZOOM_IN,
01805   MTEHK_ZOOM_OUT,
01806   MTEHK_TERRAFORM,
01807   MTEHK_SMALLMAP,
01808   MTEHK_EXTRA_VIEWPORT,
01809 };
01810 
01811 struct ScenarioEditorToolbarWindow : Window {
01812   CallBackFunction last_started_action; 
01813 
01814   ScenarioEditorToolbarWindow(const WindowDesc *desc) : Window()
01815   {
01816     this->InitNested(desc, 0);
01817 
01818     this->last_started_action = CBF_NONE;
01819     CLRBITS(this->flags, WF_WHITE_BORDER);
01820     PositionMainToolbar(this);
01821     DoZoomInOutWindow(ZOOM_NONE, this);
01822   }
01823 
01824   virtual void OnPaint()
01825   {
01826     this->SetWidgetDisabledState(WID_TE_DATE_BACKWARD, _settings_game.game_creation.starting_year <= MIN_YEAR);
01827     this->SetWidgetDisabledState(WID_TE_DATE_FORWARD, _settings_game.game_creation.starting_year >= MAX_YEAR);
01828 
01829     this->DrawWidgets();
01830   }
01831 
01832   virtual void DrawWidget(const Rect &r, int widget) const
01833   {
01834     switch (widget) {
01835       case WID_TE_DATE:
01836         SetDParam(0, ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1));
01837         DrawString(r.left, r.right, (this->height - FONT_HEIGHT_NORMAL) / 2, STR_WHITE_DATE_LONG, TC_FROMSTRING, SA_HOR_CENTER);
01838         break;
01839 
01840       case WID_TE_SPACER: {
01841         int height = r.bottom - r.top;
01842         if (height > 2 * FONT_HEIGHT_NORMAL) {
01843           DrawString(r.left, r.right, (height + 1) / 2 - FONT_HEIGHT_NORMAL, STR_SCENEDIT_TOOLBAR_OPENTTD, TC_FROMSTRING, SA_HOR_CENTER);
01844           DrawString(r.left, r.right, (height + 1) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
01845         } else {
01846           DrawString(r.left, r.right, (height - FONT_HEIGHT_NORMAL) / 2, STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR, TC_FROMSTRING, SA_HOR_CENTER);
01847         }
01848         break;
01849       }
01850     }
01851   }
01852 
01853   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01854   {
01855     switch (widget) {
01856       case WID_TE_SPACER:
01857         size->width = max(GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_OPENTTD).width, GetStringBoundingBox(STR_SCENEDIT_TOOLBAR_SCENARIO_EDITOR).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01858         break;
01859 
01860       case WID_TE_DATE:
01861         SetDParam(0, ConvertYMDToDate(MAX_YEAR, 0, 1));
01862         *size = GetStringBoundingBox(STR_WHITE_DATE_LONG);
01863         size->height = max(size->height, GetSpriteSize(SPR_IMG_SAVE).height + WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM);
01864         break;
01865     }
01866   }
01867 
01868   virtual void OnClick(Point pt, int widget, int click_count)
01869   {
01870     if (_game_mode == GM_MENU) return;
01871     CallBackFunction cbf = _scen_toolbar_button_procs[widget](this);
01872     if (cbf != CBF_NONE) this->last_started_action = cbf;
01873   }
01874 
01875   virtual void OnDropdownSelect(int widget, int index)
01876   {
01877     /* The map button is in a different location on the scenario
01878      * editor toolbar, so we need to adjust for it. */
01879     if (widget == WID_TE_SMALL_MAP) widget = WID_TN_SMALL_MAP;
01880     CallBackFunction cbf = _menu_clicked_procs[widget](index);
01881     if (cbf != CBF_NONE) this->last_started_action = cbf;
01882     SndPlayFx(SND_15_BEEP);
01883   }
01884 
01885   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01886   {
01887     CallBackFunction cbf = CBF_NONE;
01888     switch (CheckHotkeyMatch(scenedit_maintoolbar_hotkeys, keycode, this)) {
01889       case MTEHK_PAUSE:               ToolbarPauseClick(this); break;
01890       case MTEHK_FASTFORWARD:         ToolbarFastForwardClick(this); break;
01891       case MTEHK_SETTINGS:            ShowGameOptions(); break;
01892       case MTEHK_SAVEGAME:            MenuClickSaveLoad(); break;
01893       case MTEHK_GENLAND:             ToolbarScenGenLand(this); break;
01894       case MTEHK_GENTOWN:             ToolbarScenGenTown(this); break;
01895       case MTEHK_GENINDUSTRY:         ToolbarScenGenIndustry(this); break;
01896       case MTEHK_BUILD_ROAD:          ToolbarScenBuildRoad(this); break;
01897       case MTEHK_BUILD_DOCKS:         ToolbarScenBuildDocks(this); break;
01898       case MTEHK_BUILD_TREES:         ToolbarScenPlantTrees(this); break;
01899       case MTEHK_SIGN:                cbf = ToolbarScenPlaceSign(this); break;
01900       case MTEHK_MUSIC:               ShowMusicWindow(); break;
01901       case MTEHK_LANDINFO:            cbf = PlaceLandBlockInfo(); break;
01902       case MTEHK_SMALL_SCREENSHOT:    MenuClickSmallScreenshot(); break;
01903       case MTEHK_ZOOMEDIN_SCREENSHOT: MenuClickZoomedInScreenshot(); break;
01904       case MTEHK_GIANT_SCREENSHOT:    MenuClickWorldScreenshot(); break;
01905       case MTEHK_ZOOM_IN:             ToolbarZoomInClick(this); break;
01906       case MTEHK_ZOOM_OUT:            ToolbarZoomOutClick(this); break;
01907       case MTEHK_TERRAFORM:           ShowEditorTerraformToolbar(); break;
01908       case MTEHK_SMALLMAP:            ShowSmallMap(); break;
01909       case MTEHK_EXTRA_VIEWPORT:      ShowExtraViewPortWindowForTileUnderCursor(); break;
01910       default: return ES_NOT_HANDLED;
01911     }
01912     if (cbf != CBF_NONE) this->last_started_action = cbf;
01913     return ES_HANDLED;
01914   }
01915 
01916   virtual void OnPlaceObject(Point pt, TileIndex tile)
01917   {
01918     switch (this->last_started_action) {
01919       case CBF_PLACE_SIGN:
01920         PlaceProc_Sign(tile);
01921         break;
01922 
01923       case CBF_PLACE_LANDINFO:
01924         ShowLandInfo(tile);
01925         break;
01926 
01927       default: NOT_REACHED();
01928     }
01929   }
01930 
01931   virtual void OnTimeout()
01932   {
01933     this->SetWidgetsLoweredState(false, WID_TE_DATE_BACKWARD, WID_TE_DATE_FORWARD, WIDGET_LIST_END);
01934     this->SetWidgetDirty(WID_TE_DATE_BACKWARD);
01935     this->SetWidgetDirty(WID_TE_DATE_FORWARD);
01936   }
01937 
01938   virtual void OnTick()
01939   {
01940     if (this->IsWidgetLowered(WID_TE_PAUSE) != !!_pause_mode) {
01941       this->ToggleWidgetLoweredState(WID_TE_PAUSE);
01942       this->SetDirty();
01943     }
01944 
01945     if (this->IsWidgetLowered(WID_TE_FAST_FORWARD) != !!_fast_forward) {
01946       this->ToggleWidgetLoweredState(WID_TE_FAST_FORWARD);
01947       this->SetDirty();
01948     }
01949   }
01950 
01956   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
01957   {
01958     if (!gui_scope) return;
01959     if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, WID_TE_ZOOM_IN, WID_TE_ZOOM_OUT);
01960   }
01961 
01962   virtual void OnQueryTextFinished(char *str)
01963   {
01964     /* Was 'cancel' pressed? */
01965     if (str == NULL) return;
01966 
01967     int32 value;
01968     if (!StrEmpty(str)) {
01969       value = atoi(str);
01970     } else {
01971       /* An empty string means revert to the default */
01972       value = DEF_START_YEAR;
01973     }
01974     _settings_game.game_creation.starting_year = Clamp(value, MIN_YEAR, MAX_YEAR);
01975     SetDate(ConvertYMDToDate(_settings_game.game_creation.starting_year, 0, 1), 0);
01976 
01977     this->SetDirty();
01978   }
01979 
01980   static Hotkey<ScenarioEditorToolbarWindow> scenedit_maintoolbar_hotkeys[];
01981 };
01982 
01983 Hotkey<ScenarioEditorToolbarWindow> ScenarioEditorToolbarWindow::scenedit_maintoolbar_hotkeys[] = {
01984   Hotkey<ScenarioEditorToolbarWindow>(_maintoolbar_pause_keys, "pause", MTEHK_PAUSE),
01985   Hotkey<ScenarioEditorToolbarWindow>((uint16)0, "fastforward", MTEHK_FASTFORWARD),
01986   Hotkey<ScenarioEditorToolbarWindow>(WKC_F2, "settings", MTEHK_SETTINGS),
01987   Hotkey<ScenarioEditorToolbarWindow>(WKC_F3, "saveload", MTEHK_SAVEGAME),
01988   Hotkey<ScenarioEditorToolbarWindow>(WKC_F4, "gen_land", MTEHK_GENLAND),
01989   Hotkey<ScenarioEditorToolbarWindow>(WKC_F5, "gen_town", MTEHK_GENTOWN),
01990   Hotkey<ScenarioEditorToolbarWindow>(WKC_F6, "gen_industry", MTEHK_GENINDUSTRY),
01991   Hotkey<ScenarioEditorToolbarWindow>(WKC_F7, "build_road", MTEHK_BUILD_ROAD),
01992   Hotkey<ScenarioEditorToolbarWindow>(WKC_F8, "build_docks", MTEHK_BUILD_DOCKS),
01993   Hotkey<ScenarioEditorToolbarWindow>(WKC_F9, "build_trees", MTEHK_BUILD_TREES),
01994   Hotkey<ScenarioEditorToolbarWindow>(WKC_F10, "build_sign", MTEHK_SIGN),
01995   Hotkey<ScenarioEditorToolbarWindow>(WKC_F11, "music", MTEHK_MUSIC),
01996   Hotkey<ScenarioEditorToolbarWindow>(WKC_F12, "land_info", MTEHK_LANDINFO),
01997   Hotkey<ScenarioEditorToolbarWindow>(WKC_CTRL  | 'S', "small_screenshot", MTEHK_SMALL_SCREENSHOT),
01998   Hotkey<ScenarioEditorToolbarWindow>(WKC_CTRL  | 'P', "zoomedin_screenshot", MTEHK_ZOOMEDIN_SCREENSHOT),
01999   Hotkey<ScenarioEditorToolbarWindow>((uint16)0, "giant_screenshot", MTEHK_GIANT_SCREENSHOT),
02000   Hotkey<ScenarioEditorToolbarWindow>(_maintoolbar_zoomin_keys, "zoomin", MTEHK_ZOOM_IN),
02001   Hotkey<ScenarioEditorToolbarWindow>(_maintoolbar_zoomout_keys, "zoomout", MTEHK_ZOOM_OUT),
02002   Hotkey<ScenarioEditorToolbarWindow>('L', "terraform", MTEHK_TERRAFORM),
02003   Hotkey<ScenarioEditorToolbarWindow>('M', "smallmap", MTEHK_SMALLMAP),
02004   Hotkey<ScenarioEditorToolbarWindow>('V', "extra_viewport", MTEHK_EXTRA_VIEWPORT),
02005   HOTKEY_LIST_END(ScenarioEditorToolbarWindow)
02006 };
02007 Hotkey<ScenarioEditorToolbarWindow> *_scenedit_maintoolbar_hotkeys = ScenarioEditorToolbarWindow::scenedit_maintoolbar_hotkeys;
02008 
02009 static const NWidgetPart _nested_toolb_scen_inner_widgets[] = {
02010   NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_PAUSE), SetDataTip(SPR_IMG_PAUSE, STR_TOOLBAR_TOOLTIP_PAUSE_GAME),
02011   NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_FAST_FORWARD), SetDataTip(SPR_IMG_FASTFORWARD, STR_TOOLBAR_TOOLTIP_FORWARD),
02012   NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SETTINGS), SetDataTip(SPR_IMG_SETTINGS, STR_TOOLBAR_TOOLTIP_OPTIONS),
02013   NWidget(WWT_IMGBTN_2, COLOUR_GREY, WID_TE_SAVE), SetDataTip(SPR_IMG_SAVE, STR_SCENEDIT_TOOLBAR_TOOLTIP_SAVE_SCENARIO_LOAD_SCENARIO),
02014   NWidget(NWID_SPACER),
02015   NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_SPACER), EndContainer(),
02016   NWidget(NWID_SPACER),
02017   NWidget(WWT_PANEL, COLOUR_GREY, WID_TE_DATE_PANEL),
02018     NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
02019       NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_BACKWARD), SetDataTip(SPR_ARROW_DOWN, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_BACKWARD),
02020       NWidget(WWT_EMPTY, COLOUR_GREY, WID_TE_DATE), SetDataTip(STR_NULL, STR_SCENEDIT_TOOLBAR_TOOLTIP_SET_DATE),
02021       NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_DATE_FORWARD), SetDataTip(SPR_ARROW_UP, STR_SCENEDIT_TOOLBAR_TOOLTIP_MOVE_THE_STARTING_DATE_FORWARD),
02022     EndContainer(),
02023   EndContainer(),
02024   NWidget(NWID_SPACER),
02025   NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SMALL_MAP), SetDataTip(SPR_IMG_SMALLMAP, STR_SCENEDIT_TOOLBAR_TOOLTIP_DISPLAY_MAP_TOWN_DIRECTORY),
02026   NWidget(NWID_SPACER),
02027   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_IN), SetDataTip(SPR_IMG_ZOOMIN, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_IN),
02028   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ZOOM_OUT), SetDataTip(SPR_IMG_ZOOMOUT, STR_TOOLBAR_TOOLTIP_ZOOM_THE_VIEW_OUT),
02029   NWidget(NWID_SPACER),
02030   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_LAND_GENERATE), SetDataTip(SPR_IMG_LANDSCAPING, STR_SCENEDIT_TOOLBAR_LANDSCAPE_GENERATION),
02031   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TOWN_GENERATE), SetDataTip(SPR_IMG_TOWN, STR_SCENEDIT_TOOLBAR_TOWN_GENERATION),
02032   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_INDUSTRY), SetDataTip(SPR_IMG_INDUSTRY, STR_SCENEDIT_TOOLBAR_INDUSTRY_GENERATION),
02033   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_ROADS), SetDataTip(SPR_IMG_BUILDROAD, STR_SCENEDIT_TOOLBAR_ROAD_CONSTRUCTION),
02034   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_WATER), SetDataTip(SPR_IMG_BUILDWATER, STR_TOOLBAR_TOOLTIP_BUILD_SHIP_DOCKS),
02035   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_TREES), SetDataTip(SPR_IMG_PLANTTREES, STR_SCENEDIT_TOOLBAR_PLANT_TREES),
02036   NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, WID_TE_SIGNS), SetDataTip(SPR_IMG_SIGN, STR_SCENEDIT_TOOLBAR_PLACE_SIGN),
02037   NWidget(NWID_SPACER),
02038   NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_MUSIC_SOUND), SetDataTip(SPR_IMG_MUSIC, STR_TOOLBAR_TOOLTIP_SHOW_SOUND_MUSIC_WINDOW),
02039   NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_HELP), SetDataTip(SPR_IMG_QUERY, STR_TOOLBAR_TOOLTIP_LAND_BLOCK_INFORMATION),
02040   NWidget(WWT_IMGBTN, COLOUR_GREY, WID_TE_SWITCH_BAR), SetDataTip(SPR_IMG_SWITCH_TOOLBAR, STR_TOOLBAR_TOOLTIP_SWITCH_TOOLBAR),
02041 };
02042 
02043 static NWidgetBase *MakeScenarioToolbar(int *biggest_index)
02044 {
02045   return MakeNWidgets(_nested_toolb_scen_inner_widgets, lengthof(_nested_toolb_scen_inner_widgets), biggest_index, new NWidgetScenarioToolbarContainer());
02046 }
02047 
02048 static const NWidgetPart _nested_toolb_scen_widgets[] = {
02049   NWidgetFunction(MakeScenarioToolbar),
02050 };
02051 
02052 static WindowDesc _toolb_scen_desc(
02053   WDP_MANUAL, 640, 22,
02054   WC_MAIN_TOOLBAR, WC_NONE,
02055   WDF_UNCLICK_BUTTONS | WDF_NO_FOCUS,
02056   _nested_toolb_scen_widgets, lengthof(_nested_toolb_scen_widgets)
02057 );
02058 
02060 void AllocateToolbar()
02061 {
02062   /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
02063   _last_built_roadtype = ROADTYPE_ROAD;
02064 
02065   if (_game_mode == GM_EDITOR) {
02066     _preferred_toolbar_size = &_toolb_scen_desc.default_width;
02067     new ScenarioEditorToolbarWindow(&_toolb_scen_desc);
02068   } else {
02069     _preferred_toolbar_size = &_toolb_normal_desc.default_width;
02070     new MainToolbarWindow(&_toolb_normal_desc);
02071   }
02072 }