# 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