main_gui.cpp

Go to the documentation of this file.
00001 /* $Id: main_gui.cpp 14347 2008-09-16 20:29:09Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "heightmap.h"
00008 #include "currency.h"
00009 #include "spritecache.h"
00010 #include "gui.h"
00011 #include "window_gui.h"
00012 #include "window_func.h"
00013 #include "textbuf_gui.h"
00014 #include "viewport_func.h"
00015 #include "command_func.h"
00016 #include "news.h"
00017 #include "town.h"
00018 #include "console.h"
00019 #include "signs.h"
00020 #include "waypoint.h"
00021 #include "variables.h"
00022 #include "train.h"
00023 #include "roadveh.h"
00024 #include "bridge_map.h"
00025 #include "screenshot.h"
00026 #include "genworld.h"
00027 #include "vehicle_gui.h"
00028 #include "transparency_gui.h"
00029 #include "newgrf_config.h"
00030 #include "rail_gui.h"
00031 #include "road_gui.h"
00032 #include "date_func.h"
00033 #include "functions.h"
00034 #include "vehicle_func.h"
00035 #include "sound_func.h"
00036 #include "fios.h"
00037 #include "terraform_gui.h"
00038 #include "industry.h"
00039 #include "transparency.h"
00040 #include "strings_func.h"
00041 #include "zoom_func.h"
00042 #include "string_func.h"
00043 #include "player_base.h"
00044 #include "player_func.h"
00045 #include "player_gui.h"
00046 #include "settings_type.h"
00047 
00048 #include "network/network.h"
00049 #include "network/network_data.h"
00050 #include "network/network_client.h"
00051 #include "network/network_server.h"
00052 #include "network/network_gui.h"
00053 
00054 #include "table/sprites.h"
00055 #include "table/strings.h"
00056 
00057 static int _rename_id = 1;
00058 static int _rename_what = -1;
00059 
00060 RailType _last_built_railtype;
00061 RoadType _last_built_roadtype;
00062 static int _scengen_town_size = 1; // depress medium-sized towns per default
00063 
00064 extern void GenerateIndustries();
00065 extern bool GenerateTowns();
00066 
00067 bool _draw_bounding_boxes = false;
00068 
00069 
00070 void CcGiveMoney(bool success, TileIndex tile, uint32 p1, uint32 p2)
00071 {
00072 #ifdef ENABLE_NETWORK
00073   if (!success || !_patches.give_money) return;
00074 
00075   char msg[20];
00076   /* Inform the player of this action */
00077   snprintf(msg, sizeof(msg), "%d", p1);
00078 
00079   if (!_network_server) {
00080     SEND_COMMAND(PACKET_CLIENT_CHAT)(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg);
00081   } else {
00082     NetworkServer_HandleChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, NETWORK_SERVER_INDEX);
00083   }
00084 #endif /* ENABLE_NETWORK */
00085 }
00086 
00087 void HandleOnEditText(const char *str)
00088 {
00089   int id = _rename_id;
00090   _cmd_text = str;
00091 
00092   switch (_rename_what) {
00093   case 1: // Rename a waypoint
00094     if (*str == '\0') return;
00095     DoCommandP(0, id, 0, NULL, CMD_RENAME_WAYPOINT | CMD_MSG(STR_CANT_CHANGE_WAYPOINT_NAME));
00096     break;
00097 #ifdef ENABLE_NETWORK
00098   case 3: { // Give money, you can only give money in excess of loan
00099     const Player *p = GetPlayer(_current_player);
00100     Money money = min(p->player_money - p->current_loan, (Money)(atoi(str) / _currency->rate));
00101 
00102     uint32 money_c = Clamp(ClampToI32(money), 0, 20000000); // Clamp between 20 million and 0
00103 
00104     /* Give 'id' the money, and substract it from ourself */
00105     DoCommandP(0, money_c, id, CcGiveMoney, CMD_GIVE_MONEY | CMD_MSG(STR_INSUFFICIENT_FUNDS));
00106   } break;
00107 #endif /* ENABLE_NETWORK */
00108     default: NOT_REACHED();
00109   }
00110 
00111   _rename_id = _rename_what = -1;
00112 }
00113 
00125 bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, ViewportHighlightMode mode, PlaceProc *placeproc)
00126 {
00127   if (w->IsWidgetDisabled(widget)) return false;
00128 
00129   SndPlayFx(SND_15_BEEP);
00130   SetWindowDirty(w);
00131 
00132   if (w->IsWidgetLowered(widget)) {
00133     ResetObjectToPlace();
00134     return false;
00135   }
00136 
00137   SetObjectToPlace(cursor, PAL_NONE, mode, w->window_class, w->window_number);
00138   w->LowerWidget(widget);
00139   _place_proc = placeproc;
00140   return true;
00141 }
00142 
00143 
00144 void CcPlaySound10(bool success, TileIndex tile, uint32 p1, uint32 p2)
00145 {
00146   if (success) SndPlayTileFx(SND_12_EXPLOSION, tile);
00147 }
00148 
00149 
00150 static void ToolbarPauseClick(Window *w)
00151 {
00152   if (_networking && !_network_server) return; // only server can pause the game
00153 
00154   if (DoCommandP(0, _pause_game ? 0 : 1, 0, NULL, CMD_PAUSE)) SndPlayFx(SND_15_BEEP);
00155 }
00156 
00157 static void ToolbarFastForwardClick(Window *w)
00158 {
00159   _fast_forward ^= true;
00160   SndPlayFx(SND_15_BEEP);
00161 }
00162 
00163 
00164 static void MenuClickSettings(int index)
00165 {
00166   switch (index) {
00167     case 0: ShowGameOptions();      return;
00168     case 1: ShowGameDifficulty();   return;
00169     case 2: ShowPatchesSelection(); return;
00170     case 3: ShowNewGRFSettings(!_networking, true, true, &_grfconfig);   return;
00171     case 4: ShowTransparencyToolbar(); break;
00172 
00173     case  6: ToggleBit(_display_opt, DO_SHOW_TOWN_NAMES);    break;
00174     case  7: ToggleBit(_display_opt, DO_SHOW_STATION_NAMES); break;
00175     case  8: ToggleBit(_display_opt, DO_SHOW_SIGNS);         break;
00176     case  9: ToggleBit(_display_opt, DO_WAYPOINTS);          break;
00177     case 10: ToggleBit(_display_opt, DO_FULL_ANIMATION);     break;
00178     case 11: ToggleBit(_display_opt, DO_FULL_DETAIL);        break;
00179     case 12: ToggleTransparency(TO_HOUSES);                  break;
00180     case 13: ToggleTransparency(TO_SIGNS);                   break;
00181   }
00182   MarkWholeScreenDirty();
00183 }
00184 
00185 static void MenuClickSaveLoad(int index)
00186 {
00187   if (_game_mode == GM_EDITOR) {
00188     switch (index) {
00189       case 0: ShowSaveLoadDialog(SLD_SAVE_SCENARIO);  break;
00190       case 1: ShowSaveLoadDialog(SLD_LOAD_SCENARIO);  break;
00191       case 2: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
00192       case 3: AskExitToGameMenu();                    break;
00193       case 5: HandleExitGameRequest();                break;
00194     }
00195   } else {
00196     switch (index) {
00197       case 0: ShowSaveLoadDialog(SLD_SAVE_GAME); break;
00198       case 1: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
00199       case 2: AskExitToGameMenu();               break;
00200       case 3: HandleExitGameRequest();           break;
00201     }
00202   }
00203 }
00204 
00205 static void MenuClickMap(int index)
00206 {
00207   switch (index) {
00208     case 0: ShowSmallMap();            break;
00209     case 1: ShowExtraViewPortWindow(); break;
00210     case 2: ShowSignList();            break;
00211   }
00212 }
00213 
00214 static void MenuClickTown(int index)
00215 {
00216   ShowTownDirectory();
00217 }
00218 
00219 static void MenuClickScenMap(int index)
00220 {
00221   switch (index) {
00222     case 0: ShowSmallMap();            break;
00223     case 1: ShowExtraViewPortWindow(); break;
00224     case 2: ShowSignList();            break;
00225     case 3: ShowTownDirectory();       break;
00226   }
00227 }
00228 
00229 static void MenuClickSubsidies(int index)
00230 {
00231   ShowSubsidiesList();
00232 }
00233 
00234 static void MenuClickStations(int index)
00235 {
00236   ShowPlayerStations((PlayerID)index);
00237 }
00238 
00239 static void MenuClickFinances(int index)
00240 {
00241   ShowPlayerFinances((PlayerID)index);
00242 }
00243 
00244 static void MenuClickCompany(int index)
00245 {
00246   if (_networking && index == 0) {
00247     ShowClientList();
00248   } else {
00249     if (_networking) index--;
00250     ShowPlayerCompany((PlayerID)index);
00251   }
00252 }
00253 
00254 static void MenuClickGraphs(int index)
00255 {
00256   switch (index) {
00257     case 0: ShowOperatingProfitGraph();    break;
00258     case 1: ShowIncomeGraph();             break;
00259     case 2: ShowDeliveredCargoGraph();     break;
00260     case 3: ShowPerformanceHistoryGraph(); break;
00261     case 4: ShowCompanyValueGraph();       break;
00262     case 5: ShowCargoPaymentRates();       break;
00263   }
00264 }
00265 
00266 static void MenuClickLeague(int index)
00267 {
00268   switch (index) {
00269     case 0: ShowCompanyLeagueTable();      break;
00270     case 1: ShowPerformanceRatingDetail(); break;
00271   }
00272 }
00273 
00274 static void MenuClickIndustry(int index)
00275 {
00276   switch (index) {
00277     case 0: ShowIndustryDirectory();   break;
00278     case 1: ShowBuildIndustryWindow(); break;
00279   }
00280 }
00281 
00282 static void MenuClickShowTrains(int index)
00283 {
00284   ShowVehicleListWindow((PlayerID)index, VEH_TRAIN);
00285 }
00286 
00287 static void MenuClickShowRoad(int index)
00288 {
00289   ShowVehicleListWindow((PlayerID)index, VEH_ROAD);
00290 }
00291 
00292 static void MenuClickShowShips(int index)
00293 {
00294   ShowVehicleListWindow((PlayerID)index, VEH_SHIP);
00295 }
00296 
00297 static void MenuClickShowAir(int index)
00298 {
00299   ShowVehicleListWindow((PlayerID)index, VEH_AIRCRAFT);
00300 }
00301 
00302 static void MenuClickBuildRail(int index)
00303 {
00304   _last_built_railtype = (RailType)index;
00305   ShowBuildRailToolbar(_last_built_railtype, -1);
00306 }
00307 
00308 static void MenuClickBuildRoad(int index)
00309 {
00310   _last_built_roadtype = (RoadType)index;
00311   ShowBuildRoadToolbar(_last_built_roadtype);
00312 }
00313 
00314 static void MenuClickBuildWater(int index)
00315 {
00316   ShowBuildDocksToolbar();
00317 }
00318 
00319 static void MenuClickBuildAir(int index)
00320 {
00321   ShowBuildAirToolbar();
00322 }
00323 
00324 #ifdef ENABLE_NETWORK
00325 void ShowNetworkGiveMoneyWindow(PlayerID player)
00326 {
00327   _rename_id = player;
00328   _rename_what = 3;
00329   ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, 180, NULL, CS_NUMERAL);
00330 }
00331 #endif /* ENABLE_NETWORK */
00332 
00333 void ShowRenameWaypointWindow(const Waypoint *wp)
00334 {
00335   int id = wp->index;
00336 
00337   /* Are we allowed to change the name of the waypoint? */
00338   if (!IsTileType(wp->xy, MP_RAILWAY) || !CheckTileOwnership(wp->xy)) {
00339     ShowErrorMessage(_error_message, STR_CANT_CHANGE_WAYPOINT_NAME,
00340       TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
00341     return;
00342   }
00343 
00344   _rename_id = id;
00345   _rename_what = 1;
00346   SetDParam(0, id);
00347   ShowQueryString(STR_WAYPOINT_RAW, STR_EDIT_WAYPOINT_NAME, 30, 180, NULL, CS_ALPHANUMERAL);
00348 }
00349 
00350 static void SelectSignTool()
00351 {
00352   if (_cursor.sprite == SPR_CURSOR_SIGN) {
00353     ResetObjectToPlace();
00354   } else {
00355     SetObjectToPlace(SPR_CURSOR_SIGN, PAL_NONE, VHM_RECT, WC_MAIN_TOOLBAR, 0);
00356     _place_proc = PlaceProc_Sign;
00357   }
00358 }
00359 
00360 static void MenuClickForest(int index)
00361 {
00362   switch (index) {
00363     case 0: ShowTerraformToolbar();  break;
00364     case 1: ShowBuildTreesToolbar(); break;
00365     case 2: SelectSignTool();        break;
00366   }
00367 }
00368 
00369 static void MenuClickMusicWindow(int index)
00370 {
00371   ShowMusicWindow();
00372 }
00373 
00374 static void MenuClickNewspaper(int index)
00375 {
00376   switch (index) {
00377     case 0: ShowLastNewsMessage(); break;
00378     case 1: ShowMessageOptions();  break;
00379     case 2: ShowMessageHistory();  break;
00380   }
00381 }
00382 
00383 static void MenuClickSmallScreenshot()
00384 {
00385   SetScreenshotType(SC_VIEWPORT);
00386 }
00387 
00388 static void MenuClickWorldScreenshot()
00389 {
00390   SetScreenshotType(SC_WORLD);
00391 }
00392 
00393 static void MenuClickHelp(int index)
00394 {
00395   switch (index) {
00396     case 0: PlaceLandBlockInfo();       break;
00397     case 2: IConsoleSwitch();           break;
00398     case 3: MenuClickSmallScreenshot(); break;
00399     case 4: MenuClickWorldScreenshot(); break;
00400     case 5: ShowAboutWindow();          break;
00401   }
00402 }
00403 
00404 
00405 typedef void MenuClickedProc(int index);
00406 
00407 static MenuClickedProc * const _menu_clicked_procs[] = {
00408   NULL,                 /* 0 */
00409   NULL,                 /* 1 */
00410   MenuClickSettings,    /* 2 */
00411   MenuClickSaveLoad,    /* 3 */
00412   MenuClickMap,         /* 4 */
00413   MenuClickTown,        /* 5 */
00414   MenuClickSubsidies,   /* 6 */
00415   MenuClickStations,    /* 7 */
00416   MenuClickFinances,    /* 8 */
00417   MenuClickCompany,     /* 9 */
00418   MenuClickGraphs,      /* 10 */
00419   MenuClickLeague,      /* 11 */
00420   MenuClickIndustry,    /* 12 */
00421   MenuClickShowTrains,  /* 13 */
00422   MenuClickShowRoad,    /* 14 */
00423   MenuClickShowShips,   /* 15 */
00424   MenuClickShowAir,     /* 16 */
00425   MenuClickScenMap,     /* 17 */
00426   NULL,                 /* 18 */
00427   MenuClickBuildRail,   /* 19 */
00428   MenuClickBuildRoad,   /* 20 */
00429   MenuClickBuildWater,  /* 21 */
00430   MenuClickBuildAir,    /* 22 */
00431   MenuClickForest,      /* 23 */
00432   MenuClickMusicWindow, /* 24 */
00433   MenuClickNewspaper,   /* 25 */
00434   MenuClickHelp,        /* 26 */
00435 };
00436 
00437 static void MenuWndProc(Window *w, WindowEvent *e)
00438 {
00439   switch (e->event) {
00440     case WE_CREATE: w->widget[0].right = w->width - 1; break;
00441 
00442   case WE_PAINT: {
00443     int x, y;
00444 
00445     byte count = WP(w, menu_d).item_count;
00446     byte sel = WP(w, menu_d).sel_index;
00447     uint16 chk = WP(w, menu_d).checked_items;
00448     StringID string = WP(w, menu_d).string_id;
00449     byte dis = WP(w, menu_d).disabled_items;
00450 
00451     DrawWindowWidgets(w);
00452 
00453     x = 1;
00454     y = 1;
00455 
00456     for (; count != 0; count--, string++, sel--) {
00457       TextColour color = HasBit(dis, 0) ? TC_GREY : (sel == 0) ? TC_WHITE : TC_BLACK;
00458       if (sel == 0) GfxFillRect(x, y, x + w->width - 3, y + 9, 0);
00459 
00460       if (HasBit(chk, 0)) DrawString(x + 2, y, STR_CHECKMARK, color);
00461       DrawString(x + 2, y, string, color);
00462 
00463       y += 10;
00464       chk >>= 1;
00465       dis >>= 1;
00466     }
00467   } break;
00468 
00469   case WE_DESTROY: {
00470       Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
00471       v->RaiseWidget(WP(w, menu_d).main_button);
00472       SetWindowDirty(v);
00473       return;
00474     }
00475 
00476   case WE_POPUPMENU_SELECT: {
00477     int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
00478     int action_id;
00479 
00480 
00481     if (index < 0) {
00482       Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
00483       if (GetWidgetFromPos(w2, e->we.popupmenu.pt.x - w2->left, e->we.popupmenu.pt.y - w2->top) == WP(w, menu_d).main_button)
00484         index = WP(w, menu_d).sel_index;
00485     }
00486 
00487     action_id = WP(w, menu_d).action_id;
00488     DeleteWindow(w);
00489 
00490     if (index >= 0) {
00491       assert((uint)index <= lengthof(_menu_clicked_procs));
00492       _menu_clicked_procs[action_id](index);
00493     }
00494 
00495     break;
00496     }
00497 
00498   case WE_POPUPMENU_OVER: {
00499     int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
00500 
00501     if (index == -1 || index == WP(w, menu_d).sel_index) return;
00502 
00503     WP(w, menu_d).sel_index = index;
00504     SetWindowDirty(w);
00505     return;
00506     }
00507   }
00508 }
00509 
00510 /* Dynamic widget length determined by toolbar-string length.
00511  * See PopupMainToolbMenu en MenuWndProc */
00512 static const Widget _menu_widgets[] = {
00513 {    WWT_PANEL, RESIZE_NONE, 14, 0,  0, 0, 0, 0x0, STR_NULL},
00514 { WIDGETS_END},
00515 };
00516 
00517 
00518 static const Widget _player_menu_widgets[] = {
00519 {    WWT_PANEL, RESIZE_NONE, 14, 0, 240, 0, 81, 0x0, STR_NULL},
00520 { WIDGETS_END},
00521 };
00522 
00523 
00524 static int GetPlayerIndexFromMenu(int index)
00525 {
00526   if (index >= 0) {
00527     const Player *p;
00528 
00529     FOR_ALL_PLAYERS(p) {
00530       if (p->is_active && --index < 0) return p->index;
00531     }
00532   }
00533   return -1;
00534 }
00535 
00536 static void UpdatePlayerMenuHeight(Window *w)
00537 {
00538   byte num = ActivePlayerCount();
00539 
00540   /* Increase one to fit in PlayerList in the menu when in network */
00541   if (_networking && WP(w, menu_d).main_button == 9) num++;
00542 
00543   if (WP(w, menu_d).item_count != num) {
00544     WP(w, menu_d).item_count = num;
00545     SetWindowDirty(w);
00546     num = num * 10 + 2;
00547     w->height = num;
00548     w->widget[0].bottom = w->widget[0].top + num - 1;
00549     SetWindowDirty(w);
00550   }
00551 }
00552 
00553 static void PlayerMenuWndProc(Window *w, WindowEvent *e)
00554 {
00555   switch (e->event) {
00556   case WE_PAINT: {
00557     int x,y;
00558     byte sel;
00559     TextColour color;
00560     Player *p;
00561     uint16 chk;
00562 
00563     UpdatePlayerMenuHeight(w);
00564     DrawWindowWidgets(w);
00565 
00566     x = 1;
00567     y = 1;
00568     sel = WP(w, menu_d).sel_index;
00569     chk = WP(w, menu_d).checked_items; // let this mean gray items.
00570 
00571     /* 9 = playerlist */
00572     if (_networking && WP(w, menu_d).main_button == 9) {
00573       if (sel == 0) {
00574         GfxFillRect(x, y, x + 238, y + 9, 0);
00575       }
00576       DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, TC_FROMSTRING);
00577       y += 10;
00578       sel--;
00579     }
00580 
00581     FOR_ALL_PLAYERS(p) {
00582       if (p->is_active) {
00583         if (p->index == sel) {
00584           GfxFillRect(x, y, x + 238, y + 9, 0);
00585         }
00586 
00587         DrawPlayerIcon(p->index, x + 2, y + 1);
00588 
00589         SetDParam(0, p->index);
00590         SetDParam(1, p->index);
00591 
00592         color = (p->index == sel) ? TC_WHITE : TC_BLACK;
00593         if (chk&1) color = TC_GREY;
00594         DrawString(x + 19, y, STR_7021, color);
00595 
00596         y += 10;
00597       }
00598       chk >>= 1;
00599     }
00600 
00601     break;
00602     }
00603 
00604   case WE_DESTROY: {
00605     Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
00606     v->RaiseWidget(WP(w, menu_d).main_button);
00607     SetWindowDirty(v);
00608     return;
00609     }
00610 
00611   case WE_POPUPMENU_SELECT: {
00612     int index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
00613     int action_id = WP(w, menu_d).action_id;
00614 
00615     /* We have a new entry at the top of the list of menu 9 when networking
00616      *  so keep that in count */
00617     if (_networking && WP(w, menu_d).main_button == 9) {
00618       if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
00619     } else {
00620       index = GetPlayerIndexFromMenu(index);
00621     }
00622 
00623     if (index < 0) {
00624       Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
00625       if (GetWidgetFromPos(w2, e->we.popupmenu.pt.x - w2->left, e->we.popupmenu.pt.y - w2->top) == WP(w, menu_d).main_button)
00626         index = WP(w, menu_d).sel_index;
00627     }
00628 
00629     DeleteWindow(w);
00630 
00631     if (index >= 0) {
00632       assert(index >= 0 && index < 30);
00633       _menu_clicked_procs[action_id](index);
00634     }
00635     break;
00636     }
00637   case WE_POPUPMENU_OVER: {
00638     int index;
00639     UpdatePlayerMenuHeight(w);
00640     index = GetMenuItemIndex(w, e->we.popupmenu.pt.x, e->we.popupmenu.pt.y);
00641 
00642     /* We have a new entry at the top of the list of menu 9 when networking
00643      * so keep that in count */
00644     if (_networking && WP(w, menu_d).main_button == 9) {
00645       if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
00646     } else {
00647       index = GetPlayerIndexFromMenu(index);
00648     }
00649 
00650     if (index == -1 || index == WP(w, menu_d).sel_index) return;
00651 
00652     WP(w, menu_d).sel_index = index;
00653     SetWindowDirty(w);
00654     return;
00655     }
00656   }
00657 }
00658 
00664 static int GetStringListMaxWidth(StringID base_string, byte count)
00665 {
00666   char buffer[512];
00667   int width, max_width;
00668   byte i;
00669 
00670   max_width = 0;
00671   for (i = 0; i != count; i++) {
00672     GetString(buffer, base_string + i, lastof(buffer));
00673     width = GetStringBoundingBox(buffer).width;
00674     if (width > max_width) max_width = width;
00675   }
00676 
00677   return max_width;
00678 }
00679 
00702 static Window *PopupMainToolbMenu(Window *w, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask)
00703 {
00704   int width;
00705   int x = w->widget[GB(parent_button, 0, 8)].left;
00706 
00707   assert(disabled_mask == 0 || item_count <= 8);
00708   w->LowerWidget(parent_button);
00709   w->InvalidateWidget(parent_button);
00710 
00711   DeleteWindowById(WC_TOOLBAR_MENU, 0);
00712 
00713   /* Extend the dropdown toolbar to the longest string in the list and
00714    * also make sure the dropdown is fully visible within the window.
00715    * x + w->left because x is supposed to be the offset of the toolbar-button
00716    * we clicked on and w->left the toolbar window itself. So meaning that
00717    * the default position is aligned with the left side of the clicked button */
00718   width = max(GetStringListMaxWidth(base_string, item_count) + 6, 140);
00719   x = w->left + Clamp(x, 0, w->width - width); // or alternatively '_screen.width - width'
00720 
00721   w = AllocateWindow(x, 22, width, item_count * 10 + 2, MenuWndProc, WC_TOOLBAR_MENU, _menu_widgets);
00722   w->widget[0].bottom = item_count * 10 + 1;
00723   w->flags4 &= ~WF_WHITE_BORDER_MASK;
00724 
00725   WP(w, menu_d).item_count = item_count;
00726   WP(w, menu_d).sel_index = 0;
00727   WP(w, menu_d).main_button = GB(parent_button, 0, 8);
00728   WP(w, menu_d).action_id = (GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button;
00729   WP(w, menu_d).string_id = base_string;
00730   WP(w, menu_d).checked_items = 0;
00731   WP(w, menu_d).disabled_items = disabled_mask;
00732 
00733   _popup_menu_active = true;
00734 
00735   SndPlayFx(SND_15_BEEP);
00736   return w;
00737 }
00738 
00739 static Window *PopupMainPlayerToolbMenu(Window *w, int main_button, int gray)
00740 {
00741   int x = w->widget[main_button].left + w->left;
00742 
00743   w->LowerWidget(main_button);
00744   w->InvalidateWidget(main_button);
00745 
00746   DeleteWindowById(WC_TOOLBAR_MENU, 0);
00747   w = AllocateWindow(x, 0x16, 0xF1, 0x52, PlayerMenuWndProc, WC_TOOLBAR_MENU, _player_menu_widgets);
00748   w->flags4 &= ~WF_WHITE_BORDER_MASK;
00749   WP(w, menu_d).item_count = 0;
00750   WP(w, menu_d).sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
00751   if (_networking && main_button == 9) {
00752     if (_local_player != PLAYER_SPECTATOR) {
00753       WP(w, menu_d).sel_index++;
00754     } else {
00755       /* Select client list by default for spectators */
00756       WP(w, menu_d).sel_index = 0;
00757     }
00758   }
00759   WP(w, menu_d).action_id = main_button;
00760   WP(w, menu_d).main_button = main_button;
00761   WP(w, menu_d).checked_items = gray;
00762   WP(w, menu_d).disabled_items = 0;
00763   _popup_menu_active = true;
00764   SndPlayFx(SND_15_BEEP);
00765   return w;
00766 }
00767 
00768 static void ToolbarSaveClick(Window *w)
00769 {
00770   PopupMainToolbMenu(w, 3, STR_015C_SAVE_GAME, 4, 0);
00771 }
00772 
00773 static void ToolbarMapClick(Window *w)
00774 {
00775   PopupMainToolbMenu(w, 4, STR_02DE_MAP_OF_WORLD, 3, 0);
00776 }
00777 
00778 static void ToolbarTownClick(Window *w)
00779 {
00780   PopupMainToolbMenu(w, 5, STR_02BB_TOWN_DIRECTORY, 1, 0);
00781 }
00782 
00783 static void ToolbarSubsidiesClick(Window *w)
00784 {
00785   PopupMainToolbMenu(w, 6, STR_02DD_SUBSIDIES, 1, 0);
00786 }
00787 
00788 static void ToolbarStationsClick(Window *w)
00789 {
00790   PopupMainPlayerToolbMenu(w, 7, 0);
00791 }
00792 
00793 static void ToolbarMoneyClick(Window *w)
00794 {
00795   PopupMainPlayerToolbMenu(w, 8, 0);
00796 }
00797 
00798 static void ToolbarPlayersClick(Window *w)
00799 {
00800   PopupMainPlayerToolbMenu(w, 9, 0);
00801 }
00802 
00803 static void ToolbarGraphsClick(Window *w)
00804 {
00805   PopupMainToolbMenu(w, 10, STR_0154_OPERATING_PROFIT_GRAPH, 6, 0);
00806 }
00807 
00808 static void ToolbarLeagueClick(Window *w)
00809 {
00810   PopupMainToolbMenu(w, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2, 0);
00811 }
00812 
00813 static void ToolbarIndustryClick(Window *w)
00814 {
00815   /* Disable build-industry menu if we are a spectator */
00816   PopupMainToolbMenu(w, 12, STR_INDUSTRY_DIR, 2, (_current_player == PLAYER_SPECTATOR) ? (1 << 1) : 0);
00817 }
00818 
00819 static void ToolbarTrainClick(Window *w)
00820 {
00821   const Vehicle *v;
00822   int dis = -1;
00823 
00824   FOR_ALL_VEHICLES(v) {
00825     if (v->type == VEH_TRAIN && IsFrontEngine(v)) ClrBit(dis, v->owner);
00826   }
00827   PopupMainPlayerToolbMenu(w, 13, dis);
00828 }
00829 
00830 static void ToolbarRoadClick(Window *w)
00831 {
00832   const Vehicle *v;
00833   int dis = -1;
00834 
00835   FOR_ALL_VEHICLES(v) {
00836     if (v->type == VEH_ROAD && IsRoadVehFront(v)) ClrBit(dis, v->owner);
00837   }
00838   PopupMainPlayerToolbMenu(w, 14, dis);
00839 }
00840 
00841 static void ToolbarShipClick(Window *w)
00842 {
00843   const Vehicle *v;
00844   int dis = -1;
00845 
00846   FOR_ALL_VEHICLES(v) {
00847     if (v->type == VEH_SHIP) ClrBit(dis, v->owner);
00848   }
00849   PopupMainPlayerToolbMenu(w, 15, dis);
00850 }
00851 
00852 static void ToolbarAirClick(Window *w)
00853 {
00854   const Vehicle *v;
00855   int dis = -1;
00856 
00857   FOR_ALL_VEHICLES(v) {
00858     if (v->type == VEH_AIRCRAFT) ClrBit(dis, v->owner);
00859   }
00860   PopupMainPlayerToolbMenu(w, 16, dis);
00861 }
00862 
00863 /* Zooms a viewport in a window in or out */
00864 /* No button handling or what so ever */
00865 bool DoZoomInOutWindow(int how, Window *w)
00866 {
00867   ViewPort *vp;
00868 
00869   assert(w != NULL);
00870   vp = w->viewport;
00871 
00872   switch (how) {
00873     case ZOOM_IN:
00874       if (vp->zoom == ZOOM_LVL_MIN) return false;
00875       vp->zoom = (ZoomLevel)((int)vp->zoom - 1);
00876       vp->virtual_width >>= 1;
00877       vp->virtual_height >>= 1;
00878 
00879       WP(w, vp_d).scrollpos_x += vp->virtual_width >> 1;
00880       WP(w, vp_d).scrollpos_y += vp->virtual_height >> 1;
00881       WP(w, vp_d).dest_scrollpos_x = WP(w,vp_d).scrollpos_x;
00882       WP(w, vp_d).dest_scrollpos_y = WP(w,vp_d).scrollpos_y;
00883       break;
00884     case ZOOM_OUT:
00885       if (vp->zoom == ZOOM_LVL_MAX) return false;
00886       vp->zoom = (ZoomLevel)((int)vp->zoom + 1);
00887 
00888       WP(w, vp_d).scrollpos_x -= vp->virtual_width >> 1;
00889       WP(w, vp_d).scrollpos_y -= vp->virtual_height >> 1;
00890       WP(w, vp_d).dest_scrollpos_x = WP(w,vp_d).scrollpos_x;
00891       WP(w, vp_d).dest_scrollpos_y = WP(w,vp_d).scrollpos_y;
00892 
00893       vp->virtual_width <<= 1;
00894       vp->virtual_height <<= 1;
00895       break;
00896   }
00897   if (vp != NULL) { // the vp can be null when how == ZOOM_NONE
00898     vp->virtual_left = WP(w, vp_d).scrollpos_x;
00899     vp->virtual_top = WP(w, vp_d).scrollpos_y;
00900   }
00901   SetWindowDirty(w);
00902   /* Update the windows that have zoom-buttons to perhaps disable their buttons */
00903   SendWindowMessageClass(w->window_class, how, w->window_number, 0);
00904   return true;
00905 }
00906 
00907 static void ToolbarZoomInClick(Window *w)
00908 {
00909   if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
00910     w->HandleButtonClick(17);
00911     SndPlayFx(SND_15_BEEP);
00912   }
00913 }
00914 
00915 static void ToolbarZoomOutClick(Window *w)
00916 {
00917   if (DoZoomInOutWindow(ZOOM_OUT,FindWindowById(WC_MAIN_WINDOW, 0))) {
00918     w->HandleButtonClick(18);
00919     SndPlayFx(SND_15_BEEP);
00920   }
00921 }
00922 
00923 static void ToolbarBuildRailClick(Window *w)
00924 {
00925   const Player *p = GetPlayer(_local_player);
00926   Window *w2 = PopupMainToolbMenu(w, 19, STR_1015_RAILROAD_CONSTRUCTION, RAILTYPE_END, ~p->avail_railtypes);
00927   WP(w2, menu_d).sel_index = _last_built_railtype;
00928 }
00929 
00930 static void ToolbarBuildRoadClick(Window *w)
00931 {
00932   const Player *p = GetPlayer(_local_player);
00933   /* The standard road button is *always* available */
00934   Window *w2 = PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | ROADTYPES_ROAD));
00935   WP(w2, menu_d).sel_index = _last_built_roadtype;
00936 }
00937 
00938 static void ToolbarBuildWaterClick(Window *w)
00939 {
00940   PopupMainToolbMenu(w, 21, STR_9800_DOCK_CONSTRUCTION, 1, 0);
00941 }
00942 
00943 static void ToolbarBuildAirClick(Window *w)
00944 {
00945   PopupMainToolbMenu(w, 22, STR_A01D_AIRPORT_CONSTRUCTION, 1, 0);
00946 }
00947 
00948 static void ToolbarForestClick(Window *w)
00949 {
00950   PopupMainToolbMenu(w, 23, STR_LANDSCAPING, 3, 0);
00951 }
00952 
00953 static void ToolbarMusicClick(Window *w)
00954 {
00955   PopupMainToolbMenu(w, 24, STR_01D3_SOUND_MUSIC, 1, 0);
00956 }
00957 
00958 static void ToolbarNewspaperClick(Window *w)
00959 {
00960   PopupMainToolbMenu(w, 25, STR_0200_LAST_MESSAGE_NEWS_REPORT, 3, 0);
00961 }
00962 
00963 static void ToolbarHelpClick(Window *w)
00964 {
00965   PopupMainToolbMenu(w, 26, STR_02D5_LAND_BLOCK_INFO, 6, 0);
00966 }
00967 
00968 static void ToolbarOptionsClick(Window *w)
00969 {
00970   uint16 x = 0;
00971 
00972   w = PopupMainToolbMenu(w, 2, STR_02C4_GAME_OPTIONS, 14, 0);
00973 
00974   if (HasBit(_display_opt, DO_SHOW_TOWN_NAMES))    SetBit(x,  6);
00975   if (HasBit(_display_opt, DO_SHOW_STATION_NAMES)) SetBit(x,  7);
00976   if (HasBit(_display_opt, DO_SHOW_SIGNS))         SetBit(x,  8);
00977   if (HasBit(_display_opt, DO_WAYPOINTS))          SetBit(x,  9);
00978   if (HasBit(_display_opt, DO_FULL_ANIMATION))     SetBit(x, 10);
00979   if (HasBit(_display_opt, DO_FULL_DETAIL))        SetBit(x, 11);
00980   if (IsTransparencySet(TO_HOUSES))                SetBit(x, 12);
00981   if (IsTransparencySet(TO_SIGNS))                 SetBit(x, 13);
00982   WP(w, menu_d).checked_items = x;
00983 }
00984 
00985 
00986 static void ToolbarScenSaveOrLoad(Window *w)
00987 {
00988   PopupMainToolbMenu(w, 3, STR_0292_SAVE_SCENARIO, 6, 0);
00989 }
00990 
00991 static void ToolbarScenDateBackward(Window *w)
00992 {
00993   /* don't allow too fast scrolling */
00994   if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
00995     w->HandleButtonClick(6);
00996     SetWindowDirty(w);
00997 
00998     _patches_newgame.starting_year = Clamp(_patches_newgame.starting_year - 1, MIN_YEAR, MAX_YEAR);
00999     SetDate(ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
01000   }
01001   _left_button_clicked = false;
01002 }
01003 
01004 static void ToolbarScenDateForward(Window *w)
01005 {
01006   /* don't allow too fast scrolling */
01007   if ((w->flags4 & WF_TIMEOUT_MASK) <= 2 << WF_TIMEOUT_SHL) {
01008     w->HandleButtonClick(7);
01009     SetWindowDirty(w);
01010 
01011     _patches_newgame.starting_year = Clamp(_patches_newgame.starting_year + 1, MIN_YEAR, MAX_YEAR);
01012     SetDate(ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
01013   }
01014   _left_button_clicked = false;
01015 }
01016 
01017 static void ToolbarScenMapTownDir(Window *w)
01018 {
01019   /* Scenario editor button, *hack*hack* use different button to activate */
01020   PopupMainToolbMenu(w, 8 | (17 << 8), STR_02DE_MAP_OF_WORLD, 4, 0);
01021 }
01022 
01023 static void ToolbarScenZoomIn(Window *w)
01024 {
01025   if (DoZoomInOutWindow(ZOOM_IN, FindWindowById(WC_MAIN_WINDOW, 0))) {
01026     w->HandleButtonClick(9);
01027     SndPlayFx(SND_15_BEEP);
01028   }
01029 }
01030 
01031 static void ToolbarScenZoomOut(Window *w)
01032 {
01033   if (DoZoomInOutWindow(ZOOM_OUT, FindWindowById(WC_MAIN_WINDOW, 0))) {
01034     w->HandleButtonClick(10);
01035     SndPlayFx(SND_15_BEEP);
01036   }
01037 }
01038 
01039 void ZoomInOrOutToCursorWindow(bool in, Window *w)
01040 {
01041   ViewPort *vp;
01042   Point pt;
01043 
01044   assert(w != 0);
01045 
01046   vp = w->viewport;
01047 
01048   if (_game_mode != GM_MENU) {
01049     if ((in && vp->zoom == ZOOM_LVL_MIN) || (!in && vp->zoom == ZOOM_LVL_MAX))
01050       return;
01051 
01052     pt = GetTileZoomCenterWindow(in,w);
01053     if (pt.x != -1) {
01054       ScrollWindowTo(pt.x, pt.y, w, true);
01055 
01056       DoZoomInOutWindow(in ? ZOOM_IN : ZOOM_OUT, w);
01057     }
01058   }
01059 }
01060 
01061 static void ToolbarScenGenLand(Window *w)
01062 {
01063   w->HandleButtonClick(11);
01064   SndPlayFx(SND_15_BEEP);
01065 
01066   ShowEditorTerraformToolbar();
01067 }
01068 
01069 void CcBuildTown(bool success, TileIndex tile, uint32 p1, uint32 p2)
01070 {
01071   if (success) {
01072     SndPlayTileFx(SND_1F_SPLAT, tile);
01073     ResetObjectToPlace();
01074   }
01075 }
01076 
01077 static void PlaceProc_Town(TileIndex tile)
01078 {
01079   uint32 size = min(_scengen_town_size, (int)TSM_CITY);
01080   uint32 mode = _scengen_town_size > TSM_CITY ? TSM_CITY : TSM_FIXED;
01081   DoCommandP(tile, size, mode, CcBuildTown, CMD_BUILD_TOWN | CMD_MSG(STR_0236_CAN_T_BUILD_TOWN_HERE));
01082 }
01083 
01084 
01085 static const Widget _scen_edit_town_gen_widgets[] = {
01086 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
01087 {    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_0233_TOWN_GENERATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
01088 {  WWT_STICKYBOX,   RESIZE_NONE,     7,   148,   159,     0,    13, 0x0,                      STR_STICKY_BUTTON},
01089 {      WWT_PANEL,   RESIZE_NONE,     7,     0,   159,    14,    94, 0x0,                      STR_NULL},
01090 {    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    16,    27, STR_0234_NEW_TOWN,        STR_0235_CONSTRUCT_NEW_TOWN},
01091 {    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    29,    40, STR_023D_RANDOM_TOWN,     STR_023E_BUILD_TOWN_IN_RANDOM_LOCATION},
01092 {    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    42,    53, STR_MANY_RANDOM_TOWNS,    STR_RANDOM_TOWNS_TIP},
01093 {    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,    53,    68,    79, STR_02A1_SMALL,           STR_02A4_SELECT_TOWN_SIZE},
01094 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    54,   105,    68,    79, STR_02A2_MEDIUM,          STR_02A4_SELECT_TOWN_SIZE},
01095 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   106,   157,    68,    79, STR_02A3_LARGE,           STR_02A4_SELECT_TOWN_SIZE},
01096 {    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   157,    81,    92, STR_SCENARIO_EDITOR_CITY, STR_02A4_SELECT_TOWN_SIZE},
01097 {      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    54,    67, STR_02A5_TOWN_SIZE,       STR_NULL},
01098 {   WIDGETS_END},
01099 };
01100 
01101 static void ScenEditTownGenWndProc(Window *w, WindowEvent *e)
01102 {
01103   switch (e->event) {
01104   case WE_PAINT:
01105     DrawWindowWidgets(w);
01106     break;
01107 
01108   case WE_CREATE:
01109     w->LowerWidget(_scengen_town_size + 7);
01110     break;
01111 
01112   case WE_CLICK:
01113     switch (e->we.click.widget) {
01114     case 4: // new town
01115       HandlePlacePushButton(w, 4, SPR_CURSOR_TOWN, VHM_RECT, PlaceProc_Town);
01116       break;
01117     case 5: {// random town
01118       Town *t;
01119       uint size = min(_scengen_town_size, (int)TSM_CITY);
01120       TownSizeMode mode = _scengen_town_size > TSM_CITY ? TSM_CITY : TSM_FIXED;
01121 
01122       w->HandleButtonClick(5);
01123       _generating_world = true;
01124       t = CreateRandomTown(20, mode, size);
01125       _generating_world = false;
01126 
01127       if (t == NULL) {
01128         ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
01129       } else {
01130         ScrollMainWindowToTile(t->xy);
01131       }
01132 
01133       break;
01134     }
01135     case 6: {// many random towns
01136       w->HandleButtonClick(6);
01137 
01138       _generating_world = true;
01139       if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
01140       _generating_world = false;
01141       break;
01142     }
01143 
01144     case 7: case 8: case 9: case 10:
01145       w->RaiseWidget(_scengen_town_size + 7);
01146       _scengen_town_size = e->we.click.widget - 7;
01147       w->LowerWidget(_scengen_town_size + 7);
01148       SetWindowDirty(w);
01149       break;
01150     }
01151     break;
01152 
01153   case WE_TIMEOUT:
01154     w->RaiseWidget(5);
01155     w->RaiseWidget(6);
01156     SetWindowDirty(w);
01157     break;
01158   case WE_PLACE_OBJ:
01159     _place_proc(e->we.place.tile);
01160     break;
01161   case WE_ABORT_PLACE_OBJ:
01162     w->RaiseButtons();
01163     w->LowerWidget(_scengen_town_size + 7);
01164     SetWindowDirty(w);
01165     break;
01166   }
01167 }
01168 
01169 static const WindowDesc _scen_edit_town_gen_desc = {
01170   WDP_AUTO, WDP_AUTO, 160, 95, 160, 95,
01171   WC_SCEN_TOWN_GEN, WC_NONE,
01172   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
01173   _scen_edit_town_gen_widgets,
01174   ScenEditTownGenWndProc,
01175 };
01176 
01177 static void ToolbarScenGenTown(Window *w)
01178 {
01179   w->HandleButtonClick(12);
01180   SndPlayFx(SND_15_BEEP);
01181 
01182   AllocateWindowDescFront(&_scen_edit_town_gen_desc, 0);
01183 }
01184 
01185 static void ToolbarScenGenIndustry(Window *w)
01186 {
01187   w->HandleButtonClick(13);
01188   SndPlayFx(SND_15_BEEP);
01189   ShowBuildIndustryWindow();
01190 }
01191 
01192 static void ToolbarScenBuildRoad(Window *w)
01193 {
01194   w->HandleButtonClick(14);
01195   SndPlayFx(SND_15_BEEP);
01196   ShowBuildRoadScenToolbar();
01197 }
01198 
01199 static void ToolbarScenPlantTrees(Window *w)
01200 {
01201   w->HandleButtonClick(15);
01202   SndPlayFx(SND_15_BEEP);
01203   ShowBuildTreesScenToolbar();
01204 }
01205 
01206 static void ToolbarScenPlaceSign(Window *w)
01207 {
01208   w->HandleButtonClick(16);
01209   SndPlayFx(SND_15_BEEP);
01210   SelectSignTool();
01211 }
01212 
01213 static void ToolbarBtn_NULL(Window *w)
01214 {
01215 }
01216 
01217 
01218 typedef void ToolbarButtonProc(Window *w);
01219 
01220 static ToolbarButtonProc * const _toolbar_button_procs[] = {
01221   ToolbarPauseClick,
01222   ToolbarFastForwardClick,
01223   ToolbarOptionsClick,
01224   ToolbarSaveClick,
01225   ToolbarMapClick,
01226   ToolbarTownClick,
01227   ToolbarSubsidiesClick,
01228   ToolbarStationsClick,
01229   ToolbarMoneyClick,
01230   ToolbarPlayersClick,
01231   ToolbarGraphsClick,
01232   ToolbarLeagueClick,
01233   ToolbarIndustryClick,
01234   ToolbarTrainClick,
01235   ToolbarRoadClick,
01236   ToolbarShipClick,
01237   ToolbarAirClick,
01238   ToolbarZoomInClick,
01239   ToolbarZoomOutClick,
01240   ToolbarBuildRailClick,
01241   ToolbarBuildRoadClick,
01242   ToolbarBuildWaterClick,
01243   ToolbarBuildAirClick,
01244   ToolbarForestClick,
01245   ToolbarMusicClick,
01246   ToolbarNewspaperClick,
01247   ToolbarHelpClick,
01248 };
01249 
01250 static void MainToolbarWndProc(Window *w, WindowEvent *e)
01251 {
01252   switch (e->event) {
01253   case WE_PAINT:
01254     /* Draw brown-red toolbar bg. */
01255     GfxFillRect(0, 0, w->width-1, w->height-1, 0xB2);
01256     GfxFillRect(0, 0, w->width-1, w->height-1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
01257 
01258     /* If spectator, disable all construction buttons
01259      * ie : Build road, rail, ships, airports and landscaping
01260      * Since enabled state is the default, just disable when needed */
01261     w->SetWidgetsDisabledState(_current_player == PLAYER_SPECTATOR, 19, 20, 21, 22, 23, WIDGET_LIST_END);
01262     /* disable company list drop downs, if there are no companies */
01263     w->SetWidgetsDisabledState(ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END);
01264 
01265     w->SetWidgetDisabledState(19, !CanBuildVehicleInfrastructure(VEH_TRAIN));
01266     w->SetWidgetDisabledState(22, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
01267 
01268     DrawWindowWidgets(w);
01269     break;
01270 
01271   case WE_CLICK: {
01272     if (_game_mode != GM_MENU && !w->IsWidgetDisabled(e->we.click.widget))
01273       _toolbar_button_procs[e->we.click.widget](w);
01274   } break;
01275 
01276   case WE_KEYPRESS: {
01277     switch (e->we.keypress.keycode) {
01278     case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
01279     case WKC_F2: ShowGameOptions(); break;
01280     case WKC_F3: MenuClickSaveLoad(0); break;
01281     case WKC_F4: ShowSmallMap(); break;
01282     case WKC_F5: ShowTownDirectory(); break;
01283     case WKC_F6: ShowSubsidiesList(); break;
01284     case WKC_F7: ShowPlayerStations(_local_player); break;
01285     case WKC_F8: ShowPlayerFinances(_local_player); break;
01286     case WKC_F9: ShowPlayerCompany(_local_player); break;
01287     case WKC_F10: ShowOperatingProfitGraph(); break;
01288     case WKC_F11: ShowCompanyLeagueTable(); break;
01289     case WKC_F12: ShowBuildIndustryWindow(); break;
01290     case WKC_SHIFT | WKC_F1: ShowVehicleListWindow(_local_player, VEH_TRAIN); break;
01291     case WKC_SHIFT | WKC_F2: ShowVehicleListWindow(_local_player, VEH_ROAD); break;
01292     case WKC_SHIFT | WKC_F3: ShowVehicleListWindow(_local_player, VEH_SHIP); break;
01293     case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, VEH_AIRCRAFT); break;
01294     case WKC_NUM_PLUS: // Fall through
01295     case WKC_EQUALS: // Fall through
01296     case WKC_SHIFT | WKC_EQUALS: // Fall through
01297     case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
01298     case WKC_NUM_MINUS: // Fall through
01299     case WKC_MINUS: // Fall through
01300     case WKC_SHIFT | WKC_MINUS: // Fall through
01301     case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
01302     case WKC_SHIFT | WKC_F7: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, -1); break;
01303     case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(_last_built_roadtype); break;
01304     case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break;
01305     case WKC_SHIFT | WKC_F10: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
01306     case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break;
01307     case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break;
01308     case WKC_CTRL  | 'S': MenuClickSmallScreenshot(); break;
01309     case WKC_CTRL  | 'G': MenuClickWorldScreenshot(); break;
01310     case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
01311     case 'A': if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, 4); break; // Invoke Autorail
01312     case 'L': ShowTerraformToolbar(); break;
01313     case 'M': ShowSmallMap(); break;
01314     case 'V': ShowExtraViewPortWindow(); break;
01315     default: return;
01316     }
01317     e->we.keypress.cont = false;
01318   } break;
01319 
01320   case WE_PLACE_OBJ: {
01321     _place_proc(e->we.place.tile);
01322   } break;
01323 
01324   case WE_ABORT_PLACE_OBJ: {
01325     w->RaiseWidget(25);
01326     SetWindowDirty(w);
01327   } break;
01328 
01329   case WE_MOUSELOOP:
01330     if (w->IsWidgetLowered(0) != !!_pause_game) {
01331       w->ToggleWidgetLoweredState(0);
01332       w->InvalidateWidget(0);
01333     }
01334 
01335     if (w->IsWidgetLowered(1) != !!_fast_forward) {
01336       w->ToggleWidgetLoweredState(1);
01337       w->InvalidateWidget(1);
01338     }
01339     break;
01340 
01341   case WE_RESIZE: {
01342     /* There are 27 buttons plus some spacings if the space allows it */
01343     uint button_width;
01344     uint spacing;
01345     if (w->width >= 27 * 22) {
01346       button_width = 22;
01347       spacing = w->width - (27 * button_width);
01348     } else {
01349       button_width = w->width / 27;
01350       spacing = 0;
01351     }
01352     uint extra_spacing_at[] = { 4, 8, 13, 17, 19, 24, 0 };
01353 
01354     for (uint i = 0, x = 0, j = 0; i < 27; i++) {
01355       if (extra_spacing_at[j] == i) {
01356         j++;
01357         uint add = spacing / (lengthof(extra_spacing_at) - j);
01358         spacing -= add;
01359         x += add;
01360       }
01361 
01362       w->widget[i].left = x;
01363       x += (spacing != 0) ? button_width : (w->width - x) / (27 - i);
01364       w->widget[i].right = x - 1;
01365     }
01366   } break;
01367 
01368   case WE_TIMEOUT: {
01369     uint i;
01370     for (i = 2; i < w->widget_count; i++) {
01371       if (w->IsWidgetLowered(i)) {
01372         w->RaiseWidget(i);
01373         w->InvalidateWidget(i);
01374       }
01375     }
01376     break;
01377   }
01378 
01379     case WE_MESSAGE:
01380       if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
01381       break;
01382   }
01383 }
01384 
01385 static const Widget _toolb_normal_widgets[] = {
01386 {     WWT_IMGBTN,   RESIZE_LEFT,    14,     0,     0,     0,    21, SPR_IMG_PAUSE,           STR_0171_PAUSE_GAME},
01387 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_FASTFORWARD,     STR_FAST_FORWARD},
01388 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_SETTINGS,        STR_0187_OPTIONS},
01389 {   WWT_IMGBTN_2,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_SAVE,            STR_0172_SAVE_GAME_ABANDON_GAME},
01390 
01391 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_SMALLMAP,        STR_0174_DISPLAY_MAP},
01392 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_TOWN,            STR_0176_DISPLAY_TOWN_DIRECTORY},
01393 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_SUBSIDIES,       STR_02DC_DISPLAY_SUBSIDIES},
01394 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_COMPANY_LIST,    STR_0173_DISPLAY_LIST_OF_COMPANY},
01395 
01396 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_COMPANY_FINANCE, STR_0177_DISPLAY_COMPANY_FINANCES},
01397 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_COMPANY_GENERAL, STR_0178_DISPLAY_COMPANY_GENERAL},
01398 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_GRAPHS,          STR_0179_DISPLAY_GRAPHS},
01399 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_COMPANY_LEAGUE,  STR_017A_DISPLAY_COMPANY_LEAGUE},
01400 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_INDUSTRY,        STR_0312_FUND_CONSTRUCTION_OF_NEW},
01401 
01402 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_TRAINLIST,       STR_017B_DISPLAY_LIST_OF_COMPANY},
01403 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_TRUCKLIST,       STR_017C_DISPLAY_LIST_OF_COMPANY},
01404 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_SHIPLIST,        STR_017D_DISPLAY_LIST_OF_COMPANY},
01405 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_AIRPLANESLIST,   STR_017E_DISPLAY_LIST_OF_COMPANY},
01406 
01407 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_ZOOMIN,          STR_017F_ZOOM_THE_VIEW_IN},
01408 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_ZOOMOUT,         STR_0180_ZOOM_THE_VIEW_OUT},
01409 
01410 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_BUILDRAIL,       STR_0181_BUILD_RAILROAD_TRACK},
01411 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_BUILDROAD,       STR_0182_BUILD_ROADS},
01412 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_BUILDWATER,      STR_0183_BUILD_SHIP_DOCKS},
01413 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_BUILDAIR,        STR_0184_BUILD_AIRPORTS},
01414 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_LANDSCAPING,     STR_LANDSCAPING_TOOLBAR_TIP}, // tree icon is 0x2E6
01415 
01416 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_MUSIC,           STR_01D4_SHOW_SOUND_MUSIC_WINDOW},
01417 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_MESSAGES,        STR_0203_SHOW_LAST_MESSAGE_NEWS},
01418 {     WWT_IMGBTN,   RESIZE_NONE,    14,     0,     0,     0,    21, SPR_IMG_QUERY,           STR_0186_LAND_BLOCK_INFORMATION},
01419 {   WIDGETS_END},
01420 };
01421 
01422 static const WindowDesc _toolb_normal_desc = {
01423   0, 0, 0, 22, 640, 22,
01424   WC_MAIN_TOOLBAR, WC_NONE,
01425   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
01426   _toolb_normal_widgets,
01427   MainToolbarWndProc
01428 };
01429 
01430 
01431 static const Widget _toolb_scen_widgets[] = {
01432 {  WWT_IMGBTN, RESIZE_LEFT, 14,   0,   0,  0, 21, SPR_IMG_PAUSE,       STR_0171_PAUSE_GAME},
01433 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_FASTFORWARD, STR_FAST_FORWARD},
01434 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_SETTINGS,    STR_0187_OPTIONS},
01435 {WWT_IMGBTN_2, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_SAVE,        STR_0297_SAVE_SCENARIO_LOAD_SCENARIO},
01436 
01437 {   WWT_PANEL, RESIZE_NONE, 14,   0,   0,  0, 21, 0x0,                 STR_NULL},
01438 
01439 {   WWT_PANEL, RESIZE_NONE, 14,   0, 129,  0, 21, 0x0,                 STR_NULL},
01440 {  WWT_IMGBTN, RESIZE_NONE, 14,   3,  14,  5, 16, SPR_ARROW_DOWN,      STR_029E_MOVE_THE_STARTING_DATE},
01441 {  WWT_IMGBTN, RESIZE_NONE, 14, 113, 125,  5, 16, SPR_ARROW_UP,        STR_029F_MOVE_THE_STARTING_DATE},
01442 
01443 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_SMALLMAP,    STR_0175_DISPLAY_MAP_TOWN_DIRECTORY},
01444 
01445 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_ZOOMIN,      STR_017F_ZOOM_THE_VIEW_IN},
01446 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_ZOOMOUT,     STR_0180_ZOOM_THE_VIEW_OUT},
01447 
01448 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_LANDSCAPING, STR_022E_LANDSCAPE_GENERATION},
01449 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_TOWN,        STR_022F_TOWN_GENERATION},
01450 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_INDUSTRY,    STR_0230_INDUSTRY_GENERATION},
01451 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_BUILDROAD,   STR_0231_ROAD_CONSTRUCTION},
01452 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_PLANTTREES,  STR_0288_PLANT_TREES},
01453 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_SIGN,        STR_0289_PLACE_SIGN},
01454 
01455 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01456 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01457 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01458 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01459 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01460 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01461 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01462 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_MUSIC,       STR_01D4_SHOW_SOUND_MUSIC_WINDOW},
01463 {   WWT_EMPTY, RESIZE_NONE,  0,   0,   0,  0,  0, 0x0,                 STR_NULL},
01464 {  WWT_IMGBTN, RESIZE_NONE, 14,   0,   0,  0, 21, SPR_IMG_QUERY,       STR_0186_LAND_BLOCK_INFORMATION},
01465 {WIDGETS_END},
01466 };
01467 
01468 static ToolbarButtonProc * const _scen_toolbar_button_procs[] = {
01469   ToolbarPauseClick,
01470   ToolbarFastForwardClick,
01471   ToolbarOptionsClick,
01472   ToolbarScenSaveOrLoad,
01473   ToolbarBtn_NULL,
01474   ToolbarBtn_NULL,
01475   ToolbarScenDateBackward,
01476   ToolbarScenDateForward,
01477   ToolbarScenMapTownDir,
01478   ToolbarScenZoomIn,
01479   ToolbarScenZoomOut,
01480   ToolbarScenGenLand,
01481   ToolbarScenGenTown,
01482   ToolbarScenGenIndustry,
01483   ToolbarScenBuildRoad,
01484   ToolbarScenPlantTrees,
01485   ToolbarScenPlaceSign,
01486   NULL,
01487   NULL,
01488   NULL,
01489   NULL,
01490   NULL,
01491   NULL,
01492   NULL,
01493   ToolbarMusicClick,
01494   NULL,
01495   ToolbarHelpClick,
01496 };
01497 
01498 static void ScenEditToolbarWndProc(Window *w, WindowEvent *e)
01499 {
01500   switch (e->event) {
01501   case WE_PAINT:
01502     w->SetWidgetDisabledState(6, _patches_newgame.starting_year <= MIN_YEAR);
01503     w->SetWidgetDisabledState(7, _patches_newgame.starting_year >= MAX_YEAR);
01504 
01505     /* Draw brown-red toolbar bg. */
01506     GfxFillRect(0, 0, w->width-1, w->height-1, 0xB2);
01507     GfxFillRect(0, 0, w->width-1, w->height-1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
01508 
01509     DrawWindowWidgets(w);
01510 
01511     SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
01512     DrawStringCenteredTruncated(w->widget[6].right, w->widget[7].left, 6, STR_00AF, TC_FROMSTRING);
01513 
01514     /* We hide this panel when the toolbar space gets too small */
01515     if (w->widget[4].left != w->widget[4].right) {
01516       DrawStringCenteredTruncated(w->widget[4].left + 1, w->widget[4].right - 1,  1, STR_0221_OPENTTD, TC_FROMSTRING);
01517       DrawStringCenteredTruncated(w->widget[4].left + 1, w->widget[4].right - 1, 11, STR_0222_SCENARIO_EDITOR, TC_FROMSTRING);
01518     }
01519 
01520     break;
01521 
01522   case WE_CLICK: {
01523     if (_game_mode == GM_MENU) return;
01524     _scen_toolbar_button_procs[e->we.click.widget](w);
01525   } break;
01526 
01527   case WE_KEYPRESS:
01528     switch (e->we.keypress.keycode) {
01529       case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
01530       case WKC_F2: ShowGameOptions(); break;
01531       case WKC_F3: MenuClickSaveLoad(0); break;
01532       case WKC_F4: ToolbarScenGenLand(w); break;
01533       case WKC_F5: ToolbarScenGenTown(w); break;
01534       case WKC_F6: ToolbarScenGenIndustry(w); break;
01535       case WKC_F7: ToolbarScenBuildRoad(w); break;
01536       case WKC_F8: ToolbarScenPlantTrees(w); break;
01537       case WKC_F9: ToolbarScenPlaceSign(w); break;
01538       case WKC_F10: ShowMusicWindow(); break;
01539       case WKC_F11: PlaceLandBlockInfo(); break;
01540       case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
01541       case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
01542 
01543       /* those following are all fall through */
01544       case WKC_NUM_PLUS:
01545       case WKC_EQUALS:
01546       case WKC_SHIFT | WKC_EQUALS:
01547       case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
01548 
01549       /* those following are all fall through */
01550       case WKC_NUM_MINUS:
01551       case WKC_MINUS:
01552       case WKC_SHIFT | WKC_MINUS:
01553       case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
01554 
01555       case 'L': ShowEditorTerraformToolbar(); break;
01556       case 'M': ShowSmallMap(); break;
01557       case 'V': ShowExtraViewPortWindow(); break;
01558       default: return;
01559     }
01560     e->we.keypress.cont = false;
01561     break;
01562 
01563   case WE_PLACE_OBJ: {
01564     _place_proc(e->we.place.tile);
01565   } break;
01566 
01567   case WE_ABORT_PLACE_OBJ: {
01568     w->RaiseWidget(25);
01569     SetWindowDirty(w);
01570   } break;
01571 
01572   case WE_RESIZE: {
01573     /* There are 15 buttons plus some spacings if the space allows it.
01574      * Furthermore there are two panels of which one is non-essential
01575      * and that one can be removed is the space is too small. */
01576     uint buttons_width;
01577     uint spacing;
01578 
01579     static int normal_min_width = (15 * 22) + (2 * 130);
01580     static int one_less_panel_min_width = (15 * 22) + 130;
01581 
01582     if (w->width >= one_less_panel_min_width) {
01583       buttons_width = 15 * 22;
01584       spacing = w->width - ((w->width >= normal_min_width) ? normal_min_width : one_less_panel_min_width);
01585     } else {
01586       buttons_width = w->width - 130;
01587       spacing = 0;
01588     }
01589     uint extra_spacing_at[] = { 3, 4, 7, 8, 10, 16, 0 };
01590 
01591     /* Yes, it defines about 27 widgets for this toolbar */
01592     for (uint i = 0, x = 0, j = 0, b = 0; i < 27; i++) {
01593       switch (i) {
01594         case 4:
01595           w->widget[i].left = x;
01596           if (w->width < normal_min_width) {
01597             w->widget[i].right = x;
01598             j++;
01599             continue;
01600           }
01601 
01602           x += 130;
01603           w->widget[i].right = x - 1;
01604           break;
01605 
01606         case 5: {
01607           int offset = x - w->widget[i].left;
01608           w->widget[i + 1].left  += offset;
01609           w->widget[i + 1].right += offset;
01610           w->widget[i + 2].left  += offset;
01611           w->widget[i + 2].right += offset;
01612           w->widget[i].left = x;
01613           x += 130;
01614           w->widget[i].right = x - 1;
01615           i += 2;
01616         } break;
01617 
01618         default:
01619           if (w->widget[i].bottom == 0) continue;
01620 
01621           w->widget[i].left = x;
01622           x += buttons_width / (15 - b);
01623           w->widget[i].right = x - 1;
01624           buttons_width -= buttons_width / (15 - b);
01625           b++;
01626           break;
01627       }
01628 
01629       if (extra_spacing_at[j] == i) {
01630         j++;
01631         uint add = spacing / (lengthof(extra_spacing_at) - j);
01632         spacing -= add;
01633         x += add;
01634       }
01635     }
01636   } break;
01637 
01638   case WE_MOUSELOOP:
01639     if (w->IsWidgetLowered(0) != !!_pause_game) {
01640       w->ToggleWidgetLoweredState(0);
01641       SetWindowDirty(w);
01642     }
01643 
01644     if (w->IsWidgetLowered(1) != !!_fast_forward) {
01645       w->ToggleWidgetLoweredState(1);
01646       SetWindowDirty(w);
01647     }
01648     break;
01649 
01650     case WE_MESSAGE:
01651       HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 9, 10);
01652       break;
01653   }
01654 }
01655 
01656 static const WindowDesc _toolb_scen_desc = {
01657   0, 0, 130, 22, 640, 22,
01658   WC_MAIN_TOOLBAR, WC_NONE,
01659   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01660   _toolb_scen_widgets,
01661   ScenEditToolbarWndProc
01662 };
01663 
01664 extern GetNewsStringCallbackProc * const _get_news_string_callback[];
01665 
01666 
01667 static bool DrawScrollingStatusText(const NewsItem *ni, int pos, int width)
01668 {
01669   char buf[512];
01670   StringID str;
01671   const char *s, *last;
01672   char *d;
01673   DrawPixelInfo tmp_dpi, *old_dpi;
01674   int x;
01675   char buffer[256];
01676 
01677   if (ni->display_mode == NM_CALLBACK) {
01678     str = _get_news_string_callback[ni->callback](ni);
01679   } else {
01680     CopyInDParam(0, ni->params, lengthof(ni->params));
01681     str = ni->string_id;
01682   }
01683 
01684   GetString(buf, str, lastof(buf));
01685 
01686   s = buf;
01687   d = buffer;
01688   last = lastof(buffer);
01689 
01690   for (;;) {
01691     WChar c = Utf8Consume(&s);
01692     if (c == 0) {
01693       break;
01694     } else if (c == 0x0D) {
01695       if (d + 4 >= last) break;
01696       d[0] = d[1] = d[2] = d[3] = ' ';
01697       d += 4;
01698     } else if (IsPrintable(c)) {
01699       if (d + Utf8CharLen(c) >= last) break;
01700       d += Utf8Encode(d, c);
01701     }
01702   }
01703   *d = '\0';
01704 
01705   if (!FillDrawPixelInfo(&tmp_dpi, 141, 1, width, 11)) return true;
01706 
01707   old_dpi = _cur_dpi;
01708   _cur_dpi = &tmp_dpi;
01709 
01710   x = DoDrawString(buffer, pos, 0, TC_LIGHT_BLUE);
01711   _cur_dpi = old_dpi;
01712 
01713   return x > 0;
01714 }
01715 
01716 static void StatusBarWndProc(Window *w, WindowEvent *e)
01717 {
01718   switch (e->event) {
01719   case WE_PAINT: {
01720     const Player *p = (_local_player == PLAYER_SPECTATOR) ? NULL : GetPlayer(_local_player);
01721 
01722     DrawWindowWidgets(w);
01723     SetDParam(0, _date);
01724     DrawStringCentered(
01725       70, 1, (_pause_game || _patches.status_long_date) ? STR_00AF : STR_00AE, TC_FROMSTRING
01726     );
01727 
01728     if (p != NULL) {
01729       /* Draw player money */
01730       SetDParam(0, p->player_money);
01731       DrawStringCentered(w->widget[2].left + 70, 1, STR_0004, TC_FROMSTRING);
01732     }
01733 
01734     /* Draw status bar */
01735     if (w->message.msg) { // true when saving is active
01736       DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_SAVING_GAME, TC_FROMSTRING);
01737     } else if (_do_autosave) {
01738       DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_032F_AUTOSAVE, TC_FROMSTRING);
01739     } else if (_pause_game) {
01740       DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_0319_PAUSED, TC_FROMSTRING);
01741     } else if (WP(w, def_d).data_1 > -1280 && FindWindowById(WC_NEWS_WINDOW,0) == NULL && _statusbar_news_item.string_id != 0) {
01742       /* Draw the scrolling news text */
01743       if (!DrawScrollingStatusText(&_statusbar_news_item, WP(w, def_d).data_1, w->widget[1].right - w->widget[1].left - 2)) {
01744         WP(w, def_d).data_1 = -1280;
01745         if (p != NULL) {
01746           /* This is the default text */
01747           SetDParam(0, p->index);
01748           DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
01749         }
01750       }
01751     } else {
01752       if (p != NULL) {
01753         /* This is the default text */
01754         SetDParam(0, p->index);
01755         DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
01756       }
01757     }
01758 
01759     if (WP(w, def_d).data_2 > 0) DrawSprite(SPR_BLOT, PALETTE_TO_RED, w->widget[1].right - 11, 2);
01760   } break;
01761 
01762   case WE_MESSAGE:
01763     w->message.msg = e->we.message.msg;
01764     SetWindowDirty(w);
01765     break;
01766 
01767   case WE_CLICK:
01768     switch (e->we.click.widget) {
01769       case 1: ShowLastNewsMessage(); break;
01770       case 2: if (_local_player != PLAYER_SPECTATOR) ShowPlayerFinances(_local_player); break;
01771       default: ResetObjectToPlace();
01772     }
01773     break;
01774 
01775   case WE_TICK: {
01776     if (_pause_game) return;
01777 
01778     if (WP(w, def_d).data_1 > -1280) { // Scrolling text
01779       WP(w, def_d).data_1 -= 2;
01780       w->InvalidateWidget(1);
01781     }
01782 
01783     if (WP(w, def_d).data_2 > 0) { // Red blot to show there are new unread newsmessages
01784       WP(w, def_d).data_2 -= 2;
01785     } else if (WP(w, def_d).data_2 < 0) {
01786       WP(w, def_d).data_2 = 0;
01787       w->InvalidateWidget(1);
01788     }
01789 
01790     break;
01791   }
01792   }
01793 }
01794 
01795 static const Widget _main_status_widgets[] = {
01796 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   139,     0,    11, 0x0, STR_NULL},
01797 {    WWT_PUSHBTN,   RESIZE_RIGHT,   14,   140,   179,     0,    11, 0x0, STR_02B7_SHOW_LAST_MESSAGE_OR_NEWS},
01798 {    WWT_PUSHBTN,   RESIZE_LR,      14,   180,   319,     0,    11, 0x0, STR_NULL},
01799 {   WIDGETS_END},
01800 };
01801 
01802 static WindowDesc _main_status_desc = {
01803   WDP_CENTER, 0, 320, 12, 640, 12,
01804   WC_STATUS_BAR, WC_NONE,
01805   WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
01806   _main_status_widgets,
01807   StatusBarWndProc
01808 };
01809 
01810 extern void UpdateAllStationVirtCoord();
01811 
01812 static void MainWindowWndProc(Window *w, WindowEvent *e)
01813 {
01814   int off_x;
01815 
01816   switch (e->event) {
01817   case WE_PAINT:
01818     DrawWindowViewport(w);
01819     if (_game_mode == GM_MENU) {
01820       off_x = _screen.width / 2;
01821 
01822       DrawSprite(SPR_OTTD_O, PAL_NONE, off_x - 120, 50);
01823       DrawSprite(SPR_OTTD_P, PAL_NONE, off_x -  86, 50);
01824       DrawSprite(SPR_OTTD_E, PAL_NONE, off_x -  53, 50);
01825       DrawSprite(SPR_OTTD_N, PAL_NONE, off_x -  22, 50);
01826 
01827       DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  34, 50);
01828       DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  65, 50);
01829       DrawSprite(SPR_OTTD_D, PAL_NONE, off_x +  96, 50);
01830 
01831       /*
01832       DrawSprite(SPR_OTTD_R, off_x + 119, 50);
01833       DrawSprite(SPR_OTTD_A, off_x + 148, 50);
01834       DrawSprite(SPR_OTTD_N, off_x + 181, 50);
01835       DrawSprite(SPR_OTTD_S, off_x + 215, 50);
01836       DrawSprite(SPR_OTTD_P, off_x + 246, 50);
01837       DrawSprite(SPR_OTTD_O, off_x + 275, 50);
01838       DrawSprite(SPR_OTTD_R, off_x + 307, 50);
01839       DrawSprite(SPR_OTTD_T, off_x + 337, 50);
01840 
01841       DrawSprite(SPR_OTTD_T, off_x + 390, 50);
01842       DrawSprite(SPR_OTTD_Y, off_x + 417, 50);
01843       DrawSprite(SPR_OTTD_C, off_x + 447, 50);
01844       DrawSprite(SPR_OTTD_O, off_x + 478, 50);
01845       DrawSprite(SPR_OTTD_O, off_x + 509, 50);
01846       DrawSprite(SPR_OTTD_N, off_x + 541, 50);
01847       */
01848     }
01849     break;
01850 
01851   case WE_KEYPRESS:
01852     switch (e->we.keypress.keycode) {
01853       case 'Q' | WKC_CTRL:
01854       case 'Q' | WKC_META:
01855         HandleExitGameRequest();
01856         break;
01857     }
01858 
01859     /* Disable all key shortcuts, except quit shortcuts when
01860      * generating the world, otherwise they create threading
01861      * problem during the generating, resulting in random
01862      * assertions that are hard to trigger and debug */
01863     if (IsGeneratingWorld()) break;
01864 
01865     if (e->we.keypress.keycode == WKC_BACKQUOTE) {
01866       IConsoleSwitch();
01867       e->we.keypress.cont = false;
01868       break;
01869     }
01870 
01871     if (e->we.keypress.keycode == ('B' | WKC_CTRL)) {
01872       e->we.keypress.cont = false;
01873       _draw_bounding_boxes = !_draw_bounding_boxes;
01874       MarkWholeScreenDirty();
01875       break;
01876     }
01877 
01878     if (_game_mode == GM_MENU) break;
01879 
01880     switch (e->we.keypress.keycode) {
01881       case 'C':
01882       case 'Z': {
01883         Point pt = GetTileBelowCursor();
01884         if (pt.x != -1) {
01885           if (e->we.keypress.keycode == 'Z') MaxZoomInOut(ZOOM_IN, w);
01886           ScrollMainWindowTo(pt.x, pt.y);
01887         }
01888         break;
01889       }
01890 
01891       case WKC_ESC: ResetObjectToPlace(); break;
01892       case WKC_DELETE: DeleteNonVitalWindows(); break;
01893       case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
01894       case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
01895 
01896 #if defined(_DEBUG)
01897       case '0' | WKC_ALT: // Crash the game
01898         *(byte*)0 = 0;
01899         break;
01900 
01901       case '1' | WKC_ALT: // Gimme money
01902         /* Server can not cheat in advertise mode either! */
01903         if (!_networking || !_network_server || !_network_advertise)
01904           DoCommandP(0, 10000000, 0, NULL, CMD_MONEY_CHEAT);
01905         break;
01906 
01907       case '2' | WKC_ALT: // Update the coordinates of all station signs
01908         UpdateAllStationVirtCoord();
01909         break;
01910 #endif
01911 
01912       case '1' | WKC_CTRL:
01913       case '2' | WKC_CTRL:
01914       case '3' | WKC_CTRL:
01915       case '4' | WKC_CTRL:
01916       case '5' | WKC_CTRL:
01917       case '6' | WKC_CTRL:
01918       case '7' | WKC_CTRL:
01919       case '8' | WKC_CTRL:
01920       case '9' | WKC_CTRL:
01921         /* Transparency toggle hot keys */
01922         ToggleTransparency((TransparencyOption)(e->we.keypress.keycode - ('1' | WKC_CTRL)));
01923         MarkWholeScreenDirty();
01924         break;
01925 
01926       case 'X' | WKC_CTRL:
01927         ShowTransparencyToolbar();
01928         break;
01929 
01930       case 'X':
01931         ResetRestoreAllTransparency();
01932         break;
01933 
01934 #ifdef ENABLE_NETWORK
01935       case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
01936         if (_networking) {
01937           const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
01938           bool teamchat = false;
01939 
01940           if (cio == NULL) break;
01941 
01942           /* Only players actually playing can speak to team. Eg spectators cannot */
01943           if (_patches.prefer_teamchat && IsValidPlayer(cio->client_playas)) {
01944             const NetworkClientInfo *ci;
01945             FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
01946               if (ci->client_playas == cio->client_playas && ci != cio) {
01947                 teamchat = true;
01948                 break;
01949               }
01950             }
01951           }
01952 
01953           ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
01954         }
01955         break;
01956 
01957       case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all players
01958         if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
01959         break;
01960 
01961       case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
01962         if (_networking) {
01963           const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
01964           if (cio == NULL) break;
01965 
01966           ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);
01967         }
01968         break;
01969 #endif
01970 
01971       default: return;
01972     }
01973     e->we.keypress.cont = false;
01974     break;
01975 
01976     case WE_SCROLL: {
01977       ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
01978 
01979       if (vp == NULL) {
01980         _cursor.fix_at = false;
01981         _scrolling_viewport = false;
01982       }
01983 
01984       WP(w, vp_d).scrollpos_x += ScaleByZoom(e->we.scroll.delta.x, vp->zoom);
01985       WP(w, vp_d).scrollpos_y += ScaleByZoom(e->we.scroll.delta.y, vp->zoom);
01986       WP(w, vp_d).dest_scrollpos_x = WP(w, vp_d).scrollpos_x;
01987       WP(w, vp_d).dest_scrollpos_y = WP(w, vp_d).scrollpos_y;
01988     } break;
01989 
01990     case WE_MOUSEWHEEL:
01991       ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
01992       break;
01993 
01994     case WE_MESSAGE:
01995       /* Forward the message to the appropiate toolbar (ingame or scenario editor) */
01996       SendWindowMessage(WC_MAIN_TOOLBAR, 0, e->we.message.msg, e->we.message.wparam, e->we.message.lparam);
01997       break;
01998   }
01999 }
02000 
02001 
02002 void ShowSelectGameWindow();
02003 
02004 void SetupColorsAndInitialWindow()
02005 {
02006   uint i;
02007   Window *w;
02008   int width, height;
02009 
02010   for (i = 0; i != 16; i++) {
02011     const byte *b = GetNonSprite(PALETTE_RECOLOR_START + i);
02012 
02013     assert(b);
02014     memcpy(_colour_gradient[i], b + 0xC6, sizeof(_colour_gradient[i]));
02015   }
02016 
02017   width = _screen.width;
02018   height = _screen.height;
02019 
02020   w = AllocateWindow(0, 0, width, height, MainWindowWndProc, WC_MAIN_WINDOW, NULL);
02021   AssignWindowViewport(w, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
02022 
02023   /* XXX: these are not done */
02024   switch (_game_mode) {
02025     default: NOT_REACHED();
02026     case GM_MENU:
02027       ShowSelectGameWindow();
02028       break;
02029 
02030     case GM_NORMAL:
02031     case GM_EDITOR:
02032       ShowVitalWindows();
02033       break;
02034   }
02035 }
02036 
02037 void ShowVitalWindows()
02038 {
02039   Window *w;
02040 
02041   w = AllocateWindowDesc((_game_mode != GM_EDITOR) ? &_toolb_normal_desc : &_toolb_scen_desc);
02042   DoZoomInOutWindow(ZOOM_NONE, w);
02043 
02044   CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
02045 
02046   w->SetWidgetDisabledState(0, _networking && !_network_server); // if not server, disable pause button
02047   w->SetWidgetDisabledState(1, _networking); // if networking, disable fast-forward button
02048 
02049   /* 'w' is for sure a WC_MAIN_TOOLBAR */
02050   PositionMainToolbar(w);
02051 
02052   /* Status bad only for normal games */
02053   if (_game_mode == GM_EDITOR) return;
02054 
02055   _main_status_desc.top = _screen.height - 12;
02056   w = AllocateWindowDesc(&_main_status_desc);
02057   CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
02058 
02059   WP(w, def_d).data_1 = -1280;
02060 }
02061 
02062 void GameSizeChanged()
02063 {
02064   _cur_resolution[0] = _screen.width;
02065   _cur_resolution[1] = _screen.height;
02066   RelocateAllWindows(_screen.width, _screen.height);
02067   ScreenSizeChanged();
02068   MarkWholeScreenDirty();
02069 }
02070 
02071 void InitializeMainGui()
02072 {
02073   /* Clean old GUI values */
02074   _last_built_railtype = RAILTYPE_RAIL;
02075   _last_built_roadtype = ROADTYPE_ROAD;
02076 }
02077 
02078 
02079 
02080 
02081 

Generated on Mon Sep 22 20:34:16 2008 for openttd by  doxygen 1.5.6