rail_gui.cpp

Go to the documentation of this file.
00001 /* $Id: rail_gui.cpp 19439 2010-03-16 20:54:26Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "gui.h"
00014 #include "window_gui.h"
00015 #include "station_gui.h"
00016 #include "terraform_gui.h"
00017 #include "viewport_func.h"
00018 #include "command_func.h"
00019 #include "waypoint_func.h"
00020 #include "newgrf_station.h"
00021 #include "company_base.h"
00022 #include "strings_func.h"
00023 #include "functions.h"
00024 #include "window_func.h"
00025 #include "date_func.h"
00026 #include "sound_func.h"
00027 #include "company_func.h"
00028 #include "widgets/dropdown_type.h"
00029 #include "tunnelbridge.h"
00030 #include "tilehighlight_func.h"
00031 #include "spritecache.h"
00032 #include "core/geometry_func.hpp"
00033 
00034 #include "station_map.h"
00035 #include "tunnelbridge_map.h"
00036 
00037 #include "table/sprites.h"
00038 #include "table/strings.h"
00039 
00040 static RailType _cur_railtype;               
00041 static bool _remove_button_clicked;          
00042 static DiagDirection _build_depot_direction; 
00043 static byte _waypoint_count = 1;             
00044 static byte _cur_waypoint_type;              
00045 static bool _convert_signal_button;          
00046 static SignalVariant _cur_signal_variant;    
00047 static SignalType _cur_signal_type;          
00048 
00049 /* Map the setting: default_signal_type to the corresponding signal type */
00050 static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY};
00051 
00052 struct RailStationGUISettings {
00053   Axis orientation;                 
00054 
00055   bool newstations;                 
00056   StationClassIDByte station_class; 
00057   byte station_type;                
00058   byte station_count;               
00059 };
00060 static RailStationGUISettings _railstation; 
00061 
00062 
00063 static void HandleStationPlacement(TileIndex start, TileIndex end);
00064 static void ShowBuildTrainDepotPicker(Window *parent);
00065 static void ShowBuildWaypointPicker(Window *parent);
00066 static void ShowStationBuilder(Window *parent);
00067 static void ShowSignalBuilder(Window *parent);
00068 
00069 void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00070 {
00071   if (result.Succeeded()) SndPlayTileFx(SND_20_SPLAT_2, tile);
00072 }
00073 
00074 static void GenericPlaceRail(TileIndex tile, int cmd)
00075 {
00076   DoCommandP(tile, _cur_railtype, cmd,
00077     _remove_button_clicked ?
00078     CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
00079     CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK),
00080     CcPlaySound1E
00081   );
00082 }
00083 
00084 static void PlaceRail_N(TileIndex tile)
00085 {
00086   VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
00087 }
00088 
00089 static void PlaceRail_NE(TileIndex tile)
00090 {
00091   VpStartPlaceSizing(tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL);
00092 }
00093 
00094 static void PlaceRail_E(TileIndex tile)
00095 {
00096   VpStartPlaceSizing(tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
00097 }
00098 
00099 static void PlaceRail_NW(TileIndex tile)
00100 {
00101   VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL);
00102 }
00103 
00104 static void PlaceRail_AutoRail(TileIndex tile)
00105 {
00106   VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL);
00107 }
00108 
00115 static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
00116 {
00117   if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
00118   if ((GetTrackBits(tile) & GB(extra, 8, 8)) == 0) return;
00119 
00120   DoCommandP(tile, _cur_railtype, extra & 0xFF, CMD_BUILD_SINGLE_RAIL);
00121 }
00122 
00124 static const uint16 _place_depot_extra[12] = {
00125   0x0604, 0x2102, 0x1202, 0x0505,  // First additional track for directions 0..3
00126   0x2400, 0x2801, 0x1800, 0x1401,  // Second additional track
00127   0x2203, 0x0904, 0x0A05, 0x1103,  // Third additional track
00128 };
00129 
00130 
00131 void CcRailDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00132 {
00133   if (result.Failed()) return;
00134 
00135   DiagDirection dir = (DiagDirection)p2;
00136 
00137   SndPlayTileFx(SND_20_SPLAT_2, tile);
00138   if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
00139 
00140   tile += TileOffsByDiagDir(dir);
00141 
00142   if (IsTileType(tile, MP_RAILWAY)) {
00143     PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
00144     PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
00145     PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
00146   }
00147 }
00148 
00149 static void PlaceRail_Depot(TileIndex tile)
00150 {
00151   DoCommandP(tile, _cur_railtype, _build_depot_direction,
00152     CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT),
00153     CcRailDepot);
00154 }
00155 
00156 static void PlaceRail_Waypoint(TileIndex tile)
00157 {
00158   if (_remove_button_clicked) {
00159     VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION);
00160     return;
00161   }
00162 
00163   Axis axis = GetAxisForNewWaypoint(tile);
00164   if (IsValidAxis(axis)) {
00165     /* Valid tile for waypoints */
00166     VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_FIX_X : VPM_FIX_Y, DDSP_BUILD_STATION);
00167   } else {
00168     /* Tile where we can't build rail waypoints. This is always going to fail,
00169      * but provides the user with a proper error message. */
00170     DoCommandP(tile, 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT));
00171   }
00172 }
00173 
00174 void CcStation(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00175 {
00176   if (result.Failed()) return;
00177 
00178   SndPlayTileFx(SND_20_SPLAT_2, tile);
00179   /* Only close the station builder window if the default station and non persistent building is chosen. */
00180   if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0 && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
00181 }
00182 
00183 static void PlaceRail_Station(TileIndex tile)
00184 {
00185   if (_remove_button_clicked) {
00186     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
00187     VpSetPlaceSizingLimit(-1);
00188   } else if (_settings_client.gui.station_dragdrop) {
00189     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
00190     VpSetPlaceSizingLimit(_settings_game.station.station_spread);
00191   } else {
00192     uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24;
00193     uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16;
00194 
00195     int w = _settings_client.gui.station_numtracks;
00196     int h = _settings_client.gui.station_platlength;
00197     if (!_railstation.orientation) Swap(w, h);
00198 
00199     CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" };
00200     ShowSelectStationIfNeeded(cmdcont, TileArea(tile, w, h));
00201   }
00202 }
00203 
00209 static void GenericPlaceSignals(TileIndex tile)
00210 {
00211   TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00212 
00213   if (trackbits & TRACK_BIT_VERT) { // N-S direction
00214     trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
00215   }
00216 
00217   if (trackbits & TRACK_BIT_HORZ) { // E-W direction
00218     trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
00219   }
00220 
00221   Track track = FindFirstTrack(trackbits);
00222 
00223   if (_remove_button_clicked) {
00224     DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E);
00225   } else {
00226     const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
00227 
00228     /* Map the setting cycle_signal_types to the lower and upper allowed signal type. */
00229     static const uint cycle_bounds[] = {SIGTYPE_NORMAL | (SIGTYPE_LAST_NOPBS << 3), SIGTYPE_PBS | (SIGTYPE_LAST << 3), SIGTYPE_NORMAL | (SIGTYPE_LAST << 3)};
00230 
00231     /* various bitstuffed elements for CmdBuildSingleSignal() */
00232     uint32 p1 = track;
00233 
00234     if (w != NULL) {
00235       /* signal GUI is used */
00236       SB(p1, 3, 1, _ctrl_pressed);
00237       SB(p1, 4, 1, _cur_signal_variant);
00238       SB(p1, 5, 3, _cur_signal_type);
00239       SB(p1, 8, 1, _convert_signal_button);
00240       SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
00241     } else {
00242       SB(p1, 3, 1, _ctrl_pressed);
00243       SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
00244       SB(p1, 5, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
00245       SB(p1, 8, 1, 0);
00246       SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
00247     }
00248 
00249     DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS |
00250       CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE),
00251       CcPlaySound1E);
00252   }
00253 }
00254 
00255 static void PlaceRail_Bridge(TileIndex tile)
00256 {
00257   VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
00258 }
00259 
00261 void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00262 {
00263   if (result.Succeeded()) {
00264     SndPlayTileFx(SND_20_SPLAT_2, tile);
00265     if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
00266   } else {
00267     SetRedErrorSquare(_build_tunnel_endtile);
00268   }
00269 }
00270 
00271 static void PlaceRail_Tunnel(TileIndex tile)
00272 {
00273   DoCommandP(tile, _cur_railtype, 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel);
00274 }
00275 
00276 static void PlaceRail_ConvertRail(TileIndex tile)
00277 {
00278   VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
00279 }
00280 
00281 static void PlaceRail_AutoSignals(TileIndex tile)
00282 {
00283   VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
00284 }
00285 
00286 
00288 enum RailToolbarWidgets {
00289   RTW_CAPTION,
00290   RTW_BUILD_NS,
00291   RTW_BUILD_X,
00292   RTW_BUILD_EW,
00293   RTW_BUILD_Y,
00294   RTW_AUTORAIL,
00295   RTW_DEMOLISH,
00296   RTW_BUILD_DEPOT,
00297   RTW_BUILD_WAYPOINT,
00298   RTW_BUILD_STATION,
00299   RTW_BUILD_SIGNALS,
00300   RTW_BUILD_BRIDGE,
00301   RTW_BUILD_TUNNEL,
00302   RTW_REMOVE,
00303   RTW_CONVERT_RAIL,
00304 };
00305 
00306 
00310 static void ToggleRailButton_Remove(Window *w)
00311 {
00312   DeleteWindowById(WC_SELECT_STATION, 0);
00313   w->ToggleWidgetLoweredState(RTW_REMOVE);
00314   w->SetWidgetDirty(RTW_REMOVE);
00315   _remove_button_clicked = w->IsWidgetLowered(RTW_REMOVE);
00316   SetSelectionRed(_remove_button_clicked);
00317 }
00318 
00323 static bool RailToolbar_CtrlChanged(Window *w)
00324 {
00325   if (w->IsWidgetDisabled(RTW_REMOVE)) return false;
00326 
00327   /* allow ctrl to switch remove mode only for these widgets */
00328   for (uint i = RTW_BUILD_NS; i <= RTW_BUILD_STATION; i++) {
00329     if ((i <= RTW_AUTORAIL || i >= RTW_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) {
00330       ToggleRailButton_Remove(w);
00331       return true;
00332     }
00333   }
00334 
00335   return false;
00336 }
00337 
00338 
00344 static void BuildRailClick_N(Window *w)
00345 {
00346   HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL, PlaceRail_N);
00347 }
00348 
00354 static void BuildRailClick_NE(Window *w)
00355 {
00356   HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X, PlaceRail_NE);
00357 }
00358 
00364 static void BuildRailClick_E(Window *w)
00365 {
00366   HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL, PlaceRail_E);
00367 }
00368 
00374 static void BuildRailClick_NW(Window *w)
00375 {
00376   HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y, PlaceRail_NW);
00377 }
00378 
00384 static void BuildRailClick_AutoRail(Window *w)
00385 {
00386   HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, HT_RAIL, PlaceRail_AutoRail);
00387 }
00388 
00394 static void BuildRailClick_Demolish(Window *w)
00395 {
00396   HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT, PlaceProc_DemolishArea);
00397 }
00398 
00404 static void BuildRailClick_Depot(Window *w)
00405 {
00406   if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT, PlaceRail_Depot)) {
00407     ShowBuildTrainDepotPicker(w);
00408   }
00409 }
00410 
00417 static void BuildRailClick_Waypoint(Window *w)
00418 {
00419   _waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
00420   if (HandlePlacePushButton(w, RTW_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT, PlaceRail_Waypoint) &&
00421       _waypoint_count > 1) {
00422     ShowBuildWaypointPicker(w);
00423   }
00424 }
00425 
00431 static void BuildRailClick_Station(Window *w)
00432 {
00433   if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT, PlaceRail_Station)) ShowStationBuilder(w);
00434 }
00435 
00442 static void BuildRailClick_AutoSignals(Window *w)
00443 {
00444   if (_settings_client.gui.enable_signal_gui != _ctrl_pressed) {
00445     if (HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT, PlaceRail_AutoSignals)) ShowSignalBuilder(w);
00446   } else {
00447     HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT, PlaceRail_AutoSignals);
00448   }
00449 }
00450 
00456 static void BuildRailClick_Bridge(Window *w)
00457 {
00458   HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT, PlaceRail_Bridge);
00459 }
00460 
00466 static void BuildRailClick_Tunnel(Window *w)
00467 {
00468   HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, HT_SPECIAL, PlaceRail_Tunnel);
00469 }
00470 
00476 static void BuildRailClick_Remove(Window *w)
00477 {
00478   if (w->IsWidgetDisabled(RTW_REMOVE)) return;
00479   ToggleRailButton_Remove(w);
00480   SndPlayFx(SND_15_BEEP);
00481 
00482   /* handle station builder */
00483   if (w->IsWidgetLowered(RTW_BUILD_STATION)) {
00484     if (_remove_button_clicked) {
00485       /* starting drag & drop remove */
00486       if (!_settings_client.gui.station_dragdrop) {
00487         SetTileSelectSize(1, 1);
00488       } else {
00489         VpSetPlaceSizingLimit(-1);
00490       }
00491     } else {
00492       /* starting station build mode */
00493       if (!_settings_client.gui.station_dragdrop) {
00494         int x = _settings_client.gui.station_numtracks;
00495         int y = _settings_client.gui.station_platlength;
00496         if (_railstation.orientation == 0) Swap(x, y);
00497         SetTileSelectSize(x, y);
00498       } else {
00499         VpSetPlaceSizingLimit(_settings_game.station.station_spread);
00500       }
00501     }
00502   }
00503 }
00504 
00511 static void BuildRailClick_Convert(Window *w)
00512 {
00513   HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, HT_RECT, PlaceRail_ConvertRail);
00514 }
00515 
00516 
00517 static void DoRailroadTrack(int mode)
00518 {
00519   DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4),
00520     _remove_button_clicked ?
00521     CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
00522     CMD_BUILD_RAILROAD_TRACK  | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK)
00523   );
00524 }
00525 
00526 static void HandleAutodirPlacement()
00527 {
00528   TileHighlightData *thd = &_thd;
00529   int trackstat = thd->drawstyle & 0xF; // 0..5
00530 
00531   if (thd->drawstyle & HT_RAIL) { // one tile case
00532     GenericPlaceRail(TileVirtXY(thd->selend.x, thd->selend.y), trackstat);
00533     return;
00534   }
00535 
00536   DoRailroadTrack(trackstat);
00537 }
00538 
00545 static void HandleAutoSignalPlacement()
00546 {
00547   TileHighlightData *thd = &_thd;
00548   uint32 p2 = GB(thd->drawstyle, 0, 3); // 0..5
00549 
00550   if (thd->drawstyle == HT_RECT) { // one tile case
00551     GenericPlaceSignals(TileVirtXY(thd->selend.x, thd->selend.y));
00552     return;
00553   }
00554 
00555   const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
00556 
00557   if (w != NULL) {
00558     /* signal GUI is used */
00559     SB(p2,  3, 1, 0);
00560     SB(p2,  4, 1, _cur_signal_variant);
00561     SB(p2,  6, 1, _ctrl_pressed);
00562     SB(p2,  7, 3, _cur_signal_type);
00563     SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
00564   } else {
00565     SB(p2,  3, 1, 0);
00566     SB(p2,  4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
00567     SB(p2,  6, 1, _ctrl_pressed);
00568     SB(p2,  7, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
00569     SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
00570   }
00571 
00572   /* _settings_client.gui.drag_signals_density is given as a parameter such that each user
00573    * in a network game can specify his/her own signal density */
00574   DoCommandP(
00575     TileVirtXY(thd->selstart.x, thd->selstart.y),
00576     TileVirtXY(thd->selend.x, thd->selend.y),
00577     p2,
00578     _remove_button_clicked ?
00579       CMD_REMOVE_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM) :
00580       CMD_BUILD_SIGNAL_TRACK  | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE),
00581     CcPlaySound1E);
00582 }
00583 
00584 
00585 typedef void OnButtonClick(Window *w);
00586 
00588 struct RailBuildingGUIButtonData {
00589   uint16 keycode;            
00590   OnButtonClick *click_proc; 
00591 };
00592 
00597 static const RailBuildingGUIButtonData _rail_build_button_data[] = {
00598   {'1', BuildRailClick_N          },
00599   {'2', BuildRailClick_NE         },
00600   {'3', BuildRailClick_E          },
00601   {'4', BuildRailClick_NW         },
00602   {'5', BuildRailClick_AutoRail   },
00603   {'6', BuildRailClick_Demolish   },
00604   {'7', BuildRailClick_Depot      },
00605   {'8', BuildRailClick_Waypoint   },
00606   {'9', BuildRailClick_Station    },
00607   {'S', BuildRailClick_AutoSignals},
00608   {'B', BuildRailClick_Bridge     },
00609   {'T', BuildRailClick_Tunnel     },
00610   {'R', BuildRailClick_Remove     },
00611   {'C', BuildRailClick_Convert    }
00612 };
00613 
00619 struct BuildRailToolbarWindow : Window {
00620   RailType railtype;
00621 
00622   BuildRailToolbarWindow(const WindowDesc *desc, WindowNumber window_number, RailType railtype) : Window()
00623   {
00624     this->InitNested(desc);
00625     this->SetupRailToolbar(railtype);
00626     this->DisableWidget(RTW_REMOVE);
00627 
00628     if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this);
00629   }
00630 
00631   ~BuildRailToolbarWindow()
00632   {
00633     if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false);
00634   }
00635 
00639   void SetupRailToolbar(RailType railtype)
00640   {
00641     this->railtype = railtype;
00642     const RailtypeInfo *rti = GetRailTypeInfo(railtype);
00643 
00644     assert(railtype < RAILTYPE_END);
00645     this->GetWidget<NWidgetCore>(RTW_CAPTION)->widget_data      = rti->max_speed > 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY : STR_JUST_STRING;
00646     this->GetWidget<NWidgetCore>(RTW_BUILD_NS)->widget_data     = rti->gui_sprites.build_ns_rail;
00647     this->GetWidget<NWidgetCore>(RTW_BUILD_X)->widget_data      = rti->gui_sprites.build_x_rail;
00648     this->GetWidget<NWidgetCore>(RTW_BUILD_EW)->widget_data     = rti->gui_sprites.build_ew_rail;
00649     this->GetWidget<NWidgetCore>(RTW_BUILD_Y)->widget_data      = rti->gui_sprites.build_y_rail;
00650     this->GetWidget<NWidgetCore>(RTW_AUTORAIL)->widget_data     = rti->gui_sprites.auto_rail;
00651     this->GetWidget<NWidgetCore>(RTW_BUILD_DEPOT)->widget_data  = rti->gui_sprites.build_depot;
00652     this->GetWidget<NWidgetCore>(RTW_CONVERT_RAIL)->widget_data = rti->gui_sprites.convert_rail;
00653     this->GetWidget<NWidgetCore>(RTW_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel;
00654   }
00655 
00659   void ModifyRailType(RailType railtype)
00660   {
00661     this->SetupRailToolbar(railtype);
00662     this->ReInit();
00663   }
00664 
00665   void UpdateRemoveWidgetStatus(int clicked_widget)
00666   {
00667     switch (clicked_widget) {
00668       case RTW_REMOVE:
00669         /* If it is the removal button that has been clicked, do nothing,
00670          * as it is up to the other buttons to drive removal status */
00671         return;
00672         break;
00673       case RTW_BUILD_NS:
00674       case RTW_BUILD_X:
00675       case RTW_BUILD_EW:
00676       case RTW_BUILD_Y:
00677       case RTW_AUTORAIL:
00678       case RTW_BUILD_WAYPOINT:
00679       case RTW_BUILD_STATION:
00680       case RTW_BUILD_SIGNALS:
00681         /* Removal button is enabled only if the rail/signal/waypoint/station
00682          * button is still lowered.  Once raised, it has to be disabled */
00683         this->SetWidgetDisabledState(RTW_REMOVE, !this->IsWidgetLowered(clicked_widget));
00684         break;
00685 
00686       default:
00687         /* When any other buttons than rail/signal/waypoint/station, raise and
00688          * disable the removal button */
00689         this->DisableWidget(RTW_REMOVE);
00690         this->RaiseWidget(RTW_REMOVE);
00691         break;
00692     }
00693   }
00694 
00695   virtual void SetStringParameters(int widget) const
00696   {
00697     if (widget == RTW_CAPTION) {
00698       const RailtypeInfo *rti = GetRailTypeInfo(this->railtype);
00699       SetDParam(0, rti->strings.toolbar_caption);
00700       SetDParam(1, rti->max_speed);
00701     }
00702   }
00703 
00704   virtual void OnPaint()
00705   {
00706     this->DrawWidgets();
00707   }
00708 
00709   virtual void OnClick(Point pt, int widget, int click_count)
00710   {
00711     if (widget >= RTW_BUILD_NS) {
00712       _remove_button_clicked = false;
00713       _rail_build_button_data[widget - RTW_BUILD_NS].click_proc(this);
00714     }
00715     this->UpdateRemoveWidgetStatus(widget);
00716     if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
00717   }
00718 
00719   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00720   {
00721     EventState state = ES_NOT_HANDLED;
00722     for (uint8 i = 0; i != lengthof(_rail_build_button_data); i++) {
00723       if (keycode == _rail_build_button_data[i].keycode) {
00724         _remove_button_clicked = false;
00725         _rail_build_button_data[i].click_proc(this);
00726         this->UpdateRemoveWidgetStatus(i + RTW_BUILD_NS);
00727         if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
00728         state = ES_HANDLED;
00729         break;
00730       }
00731     }
00732     MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection
00733     return state;
00734   }
00735 
00736   virtual void OnPlaceObject(Point pt, TileIndex tile)
00737   {
00738     _place_proc(tile);
00739   }
00740 
00741   virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
00742   {
00743     /* no dragging if you have pressed the convert button */
00744     if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
00745 
00746     VpSelectTilesWithMethod(pt.x, pt.y, select_method);
00747   }
00748 
00749   virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
00750   {
00751     if (pt.x != -1) {
00752       switch (select_proc) {
00753         default: NOT_REACHED();
00754         case DDSP_BUILD_BRIDGE:
00755           if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
00756           ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype);
00757           break;
00758 
00759         case DDSP_PLACE_RAIL:
00760           HandleAutodirPlacement();
00761           break;
00762 
00763         case DDSP_BUILD_SIGNALS:
00764           HandleAutoSignalPlacement();
00765           break;
00766 
00767         case DDSP_DEMOLISH_AREA:
00768           GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
00769           break;
00770 
00771         case DDSP_CONVERT_RAIL:
00772           DoCommandP(end_tile, start_tile, _cur_railtype, CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10);
00773           break;
00774 
00775         case DDSP_REMOVE_STATION:
00776         case DDSP_BUILD_STATION:
00777           if (this->IsWidgetLowered(RTW_BUILD_STATION)) {
00778             /* Station */
00779             if (_remove_button_clicked) {
00780               DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E);
00781             } else {
00782               HandleStationPlacement(start_tile, end_tile);
00783             }
00784           } else {
00785             /* Waypoint */
00786             if (_remove_button_clicked) {
00787               DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E);
00788             } else {
00789               TileArea ta(start_tile, end_tile);
00790               uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24;
00791               uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16;
00792 
00793               CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, "" };
00794               ShowSelectWaypointIfNeeded(cmdcont, ta);
00795             }
00796           }
00797           break;
00798       }
00799     }
00800   }
00801 
00802   virtual void OnPlaceObjectAbort()
00803   {
00804     this->RaiseButtons();
00805     this->DisableWidget(RTW_REMOVE);
00806     this->SetWidgetDirty(RTW_REMOVE);
00807 
00808     DeleteWindowById(WC_BUILD_SIGNAL, TRANSPORT_RAIL);
00809     DeleteWindowById(WC_BUILD_STATION, TRANSPORT_RAIL);
00810     DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_RAIL);
00811     DeleteWindowById(WC_SELECT_STATION, 0);
00812     DeleteWindowByClass(WC_BUILD_BRIDGE);
00813   }
00814 
00815   virtual void OnPlacePresize(Point pt, TileIndex tile)
00816   {
00817     DoCommand(tile, _cur_railtype, 0, DC_AUTO, CMD_BUILD_TUNNEL);
00818     VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
00819   }
00820 
00821   virtual EventState OnCTRLStateChange()
00822   {
00823     /* do not toggle Remove button by Ctrl when placing station */
00824     if (!this->IsWidgetLowered(RTW_BUILD_STATION) && !this->IsWidgetLowered(RTW_BUILD_WAYPOINT) && RailToolbar_CtrlChanged(this)) return ES_HANDLED;
00825     return ES_NOT_HANDLED;
00826   }
00827 };
00828 
00829 static const NWidgetPart _nested_build_rail_widgets[] = {
00830   NWidget(NWID_HORIZONTAL),
00831     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
00832     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, RTW_CAPTION), SetDataTip(STR_RAIL_TOOLBAR_RAILROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00833     NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
00834   EndContainer(),
00835   NWidget(NWID_HORIZONTAL),
00836     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_NS),
00837             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
00838     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_X),
00839             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
00840     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_EW),
00841             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_EW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
00842     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_Y),
00843             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
00844     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_AUTORAIL),
00845             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL),
00846 
00847     NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL), EndContainer(),
00848 
00849     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_DEMOLISH),
00850             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
00851     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_DEPOT),
00852             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DEPOT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING),
00853     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_WAYPOINT),
00854             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT),
00855     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_STATION),
00856             SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION),
00857     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_SIGNALS),
00858             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_SIGNALS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS),
00859     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_BRIDGE),
00860             SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE),
00861     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_TUNNEL),
00862             SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL),
00863     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_REMOVE),
00864             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR),
00865     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_CONVERT_RAIL),
00866             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL),
00867   EndContainer(),
00868 };
00869 
00870 static const WindowDesc _build_rail_desc(
00871   WDP_ALIGN_TOOLBAR, 0, 0,
00872   WC_BUILD_TOOLBAR, WC_NONE,
00873   WDF_CONSTRUCTION,
00874   _nested_build_rail_widgets, lengthof(_nested_build_rail_widgets)
00875 );
00876 
00877 
00889 void ShowBuildRailToolbar(RailType railtype, int button)
00890 {
00891   if (!Company::IsValidID(_local_company)) return;
00892   if (!ValParamRailtype(railtype)) return;
00893 
00894   BuildRailToolbarWindow *w = (BuildRailToolbarWindow *)FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL);
00895 
00896   /* don't recreate the window if we're clicking on a button and the window exists. */
00897   if (button < 0 || w == NULL) {
00898     DeleteWindowByClass(WC_BUILD_TOOLBAR);
00899     _cur_railtype = railtype;
00900     w = new BuildRailToolbarWindow(&_build_rail_desc, TRANSPORT_RAIL, railtype);
00901   }
00902 
00903   _remove_button_clicked = false;
00904   if (w != NULL && button >= 0) {
00905     _rail_build_button_data[button].click_proc(w);
00906     w->UpdateRemoveWidgetStatus(button + RTW_BUILD_NS);
00907   }
00908 }
00909 
00910 /* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
00911  * --pasky */
00912 
00913 static void HandleStationPlacement(TileIndex start, TileIndex end)
00914 {
00915   TileArea ta(start, end);
00916   uint numtracks = ta.w;
00917   uint platlength = ta.h;
00918 
00919   if (_railstation.orientation == AXIS_X) Swap(numtracks, platlength);
00920 
00921   uint32 p1 = _cur_railtype | _railstation.orientation << 4 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24;
00922   uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16;
00923 
00924   CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" };
00925   ShowSelectStationIfNeeded(cmdcont, ta);
00926 }
00927 
00929 enum BuildRailStationWidgets {
00930   BRSW_BACKGROUND,
00931 
00932   BRSW_PLATFORM_DIR_X,
00933   BRSW_PLATFORM_DIR_Y,
00934 
00935   BRSW_PLATFORM_NUM_1,
00936   BRSW_PLATFORM_NUM_2,
00937   BRSW_PLATFORM_NUM_3,
00938   BRSW_PLATFORM_NUM_4,
00939   BRSW_PLATFORM_NUM_5,
00940   BRSW_PLATFORM_NUM_6,
00941   BRSW_PLATFORM_NUM_7,
00942 
00943   BRSW_PLATFORM_LEN_1,
00944   BRSW_PLATFORM_LEN_2,
00945   BRSW_PLATFORM_LEN_3,
00946   BRSW_PLATFORM_LEN_4,
00947   BRSW_PLATFORM_LEN_5,
00948   BRSW_PLATFORM_LEN_6,
00949   BRSW_PLATFORM_LEN_7,
00950 
00951   BRSW_PLATFORM_DRAG_N_DROP,
00952 
00953   BRSW_HIGHLIGHT_OFF,
00954   BRSW_HIGHLIGHT_ON,
00955 
00956   BRSW_NEWST_DROPDOWN,
00957   BRSW_NEWST_LIST,
00958   BRSW_NEWST_SCROLL,
00959 
00960   BRSW_PLATFORM_NUM_BEGIN = BRSW_PLATFORM_NUM_1 - 1,
00961   BRSW_PLATFORM_LEN_BEGIN = BRSW_PLATFORM_LEN_1 - 1,
00962 };
00963 
00964 struct BuildRailStationWindow : public PickerWindowBase {
00965 private:
00966   uint line_height; 
00967 
00973   void CheckSelectedSize(const StationSpec *statspec)
00974   {
00975     if (statspec == NULL || _settings_client.gui.station_dragdrop) return;
00976 
00977     /* If current number of tracks is not allowed, make it as big as possible (which is always less than currently selected) */
00978     if (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
00979       this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
00980       _settings_client.gui.station_numtracks = 1;
00981       while (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
00982         _settings_client.gui.station_numtracks++;
00983       }
00984       this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
00985     }
00986 
00987     if (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
00988       this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
00989       _settings_client.gui.station_platlength = 1;
00990       while (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
00991         _settings_client.gui.station_platlength++;
00992       }
00993       this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
00994     }
00995   }
00996 
00998   static DropDownList *BuildStationClassDropDown()
00999   {
01000     DropDownList *list = new DropDownList();
01001 
01002     for (uint i = 0; i < GetNumStationClasses(); i++) {
01003       if (i == STAT_CLASS_WAYP) continue;
01004       list->push_back(new DropDownListStringItem(GetStationClassName((StationClassID)i), i, false));
01005     }
01006 
01007     return list;
01008   }
01009 
01010 public:
01011   BuildRailStationWindow(const WindowDesc *desc, Window *parent, bool newstation) : PickerWindowBase(parent)
01012   {
01013     this->InitNested(desc, TRANSPORT_RAIL);
01014 
01015     this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
01016     if (_settings_client.gui.station_dragdrop) {
01017       this->LowerWidget(BRSW_PLATFORM_DRAG_N_DROP);
01018     } else {
01019       this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
01020       this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
01021     }
01022     this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage);
01023     this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage);
01024 
01025     _railstation.newstations = newstation;
01026 
01027     if (newstation) {
01028       _railstation.station_count = GetNumCustomStations(_railstation.station_class);
01029 
01030       this->vscroll.SetCount(_railstation.station_count);
01031       this->vscroll.SetCapacity(GB(this->GetWidget<NWidgetCore>(BRSW_NEWST_LIST)->widget_data, MAT_ROW_START, MAT_ROW_BITS));
01032       this->vscroll.SetPosition(Clamp(_railstation.station_type - 2, 0, max(this->vscroll.GetCount() - this->vscroll.GetCapacity(), 0)));
01033     } else {
01034       /* New stations are not available, so ensure the default station
01035        * type is 'selected'. */
01036       _railstation.station_class = STAT_CLASS_DFLT;
01037       _railstation.station_type = 0;
01038     }
01039   }
01040 
01041   virtual ~BuildRailStationWindow()
01042   {
01043     DeleteWindowById(WC_SELECT_STATION, 0);
01044   }
01045 
01046   virtual void OnPaint()
01047   {
01048     bool newstations = _railstation.newstations;
01049     const StationSpec *statspec = newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
01050 
01051     if (_settings_client.gui.station_dragdrop) {
01052       SetTileSelectSize(1, 1);
01053     } else {
01054       int x = _settings_client.gui.station_numtracks;
01055       int y = _settings_client.gui.station_platlength;
01056       if (_railstation.orientation == AXIS_X) Swap(x, y);
01057       if (!_remove_button_clicked)
01058         SetTileSelectSize(x, y);
01059     }
01060 
01061     int rad = (_settings_game.station.modified_catchment) ? CA_TRAIN : CA_UNMODIFIED;
01062 
01063     if (_settings_client.gui.station_show_coverage)
01064       SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
01065 
01066     for (uint bits = 0; bits < 7; bits++) {
01067       bool disable = bits >= _settings_game.station.station_spread;
01068       if (statspec == NULL) {
01069         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, disable);
01070         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, disable);
01071       } else {
01072         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable);
01073         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths,   bits) || disable);
01074       }
01075     }
01076 
01077     this->DrawWidgets();
01078 
01079     /* 'Accepts' and 'Supplies' texts. */
01080     int top = this->GetWidget<NWidgetBase>(BRSW_HIGHLIGHT_ON)->pos_y + this->GetWidget<NWidgetBase>(BRSW_HIGHLIGHT_ON)->current_y + WD_PAR_VSEP_NORMAL;
01081     NWidgetBase *back_nwi = this->GetWidget<NWidgetBase>(BRSW_BACKGROUND);
01082     int right = back_nwi->pos_x +  back_nwi->current_x;
01083     int bottom = back_nwi->pos_y +  back_nwi->current_y;
01084     top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL;
01085     top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL;
01086     /* Resize background if the text is not equally long as the window. */
01087     if (top > bottom || (top < bottom && back_nwi->current_y > back_nwi->smallest_y)) {
01088       ResizeWindow(this, 0, top - bottom);
01089     }
01090   }
01091 
01092   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01093   {
01094     switch (widget) {
01095       case BRSW_NEWST_DROPDOWN: {
01096         Dimension d = {0, 0};
01097         for (uint i = 0; i < GetNumStationClasses(); i++) {
01098           if (i == STAT_CLASS_WAYP) continue;
01099           SetDParam(0, GetStationClassName((StationClassID)i));
01100           d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING));
01101         }
01102         d.width += padding.width;
01103         d.height += padding.height;
01104         *size = maxdim(*size, d);
01105         break;
01106       }
01107       case BRSW_NEWST_LIST: {
01108         Dimension d = GetStringBoundingBox(STR_STATION_CLASS_DFLT);
01109         for (StationClassID statclass = STAT_CLASS_BEGIN; statclass < (StationClassID)GetNumStationClasses(); statclass++) {
01110           if (statclass == STAT_CLASS_WAYP) continue;
01111           for (uint16 j = 0; j < GetNumCustomStations(statclass); j++) {
01112             const StationSpec *statspec = GetCustomStationSpec(statclass, j);
01113             if (statspec != NULL && statspec->name != 0) d = maxdim(d, GetStringBoundingBox(statspec->name));
01114           }
01115         }
01116         size->width = max(size->width, d.width + padding.width);
01117 
01118         this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
01119         size->height = GB(this->GetWidget<NWidgetCore>(widget)->widget_data, MAT_ROW_START, MAT_ROW_BITS) * this->line_height;
01120         break;
01121       }
01122     }
01123   }
01124 
01125   virtual void DrawWidget(const Rect &r, int widget) const
01126   {
01127     DrawPixelInfo tmp_dpi;
01128 
01129     switch (widget) {
01130       case BRSW_PLATFORM_DIR_X:
01131         /* Set up a clipping area for the '/' station preview */
01132         if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) {
01133           DrawPixelInfo *old_dpi = _cur_dpi;
01134           _cur_dpi = &tmp_dpi;
01135           if (!DrawStationTile(32, 16, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) {
01136             StationPickerDrawSprite(32, 16, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2);
01137           }
01138           _cur_dpi = old_dpi;
01139         }
01140         break;
01141 
01142       case BRSW_PLATFORM_DIR_Y:
01143         /* Set up a clipping area for the '\' station preview */
01144         if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) {
01145           DrawPixelInfo *old_dpi = _cur_dpi;
01146           _cur_dpi = &tmp_dpi;
01147           if (!DrawStationTile(32, 16, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) {
01148             StationPickerDrawSprite(32, 16, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3);
01149           }
01150           _cur_dpi = old_dpi;
01151         }
01152         break;
01153 
01154       case BRSW_NEWST_LIST: {
01155         uint y = r.top;
01156         for (uint16 i = this->vscroll.GetPosition(); i < _railstation.station_count && this->vscroll.IsVisible(i); i++) {
01157           const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
01158 
01159           StringID str = STR_STATION_CLASS_DFLT;
01160           if (statspec != NULL && statspec->name != 0) {
01161             if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
01162               GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, 0, FILLRECT_CHECKER);
01163             }
01164             str = statspec->name;
01165           }
01166           DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, str, i == _railstation.station_type ? TC_WHITE : TC_BLACK);
01167 
01168           y += this->line_height;
01169         }
01170         break;
01171       }
01172     }
01173   }
01174 
01175   virtual void SetStringParameters(int widget) const
01176   {
01177     if (widget == BRSW_NEWST_DROPDOWN) SetDParam(0, GetStationClassName(_railstation.station_class));
01178   }
01179 
01180   virtual void OnClick(Point pt, int widget, int click_count)
01181   {
01182     switch (widget) {
01183       case BRSW_PLATFORM_DIR_X:
01184       case BRSW_PLATFORM_DIR_Y:
01185         this->RaiseWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
01186         _railstation.orientation = (Axis)(widget - BRSW_PLATFORM_DIR_X);
01187         this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
01188         SndPlayFx(SND_15_BEEP);
01189         this->SetDirty();
01190         DeleteWindowById(WC_SELECT_STATION, 0);
01191         break;
01192 
01193       case BRSW_PLATFORM_NUM_1:
01194       case BRSW_PLATFORM_NUM_2:
01195       case BRSW_PLATFORM_NUM_3:
01196       case BRSW_PLATFORM_NUM_4:
01197       case BRSW_PLATFORM_NUM_5:
01198       case BRSW_PLATFORM_NUM_6:
01199       case BRSW_PLATFORM_NUM_7: {
01200         this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
01201         this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
01202 
01203         _settings_client.gui.station_numtracks = widget - BRSW_PLATFORM_NUM_BEGIN;
01204         _settings_client.gui.station_dragdrop = false;
01205 
01206         _settings_client.gui.station_dragdrop = false;
01207 
01208         const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
01209         if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
01210           /* The previously selected number of platforms in invalid */
01211           for (uint i = 0; i < 7; i++) {
01212             if (!HasBit(statspec->disallowed_lengths, i)) {
01213               this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
01214               _settings_client.gui.station_platlength = i + 1;
01215               break;
01216             }
01217           }
01218         }
01219 
01220         this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
01221         this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
01222         SndPlayFx(SND_15_BEEP);
01223         this->SetDirty();
01224         DeleteWindowById(WC_SELECT_STATION, 0);
01225         break;
01226       }
01227 
01228       case BRSW_PLATFORM_LEN_1:
01229       case BRSW_PLATFORM_LEN_2:
01230       case BRSW_PLATFORM_LEN_3:
01231       case BRSW_PLATFORM_LEN_4:
01232       case BRSW_PLATFORM_LEN_5:
01233       case BRSW_PLATFORM_LEN_6:
01234       case BRSW_PLATFORM_LEN_7: {
01235         this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
01236         this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
01237 
01238         _settings_client.gui.station_platlength = widget - BRSW_PLATFORM_LEN_BEGIN;
01239         _settings_client.gui.station_dragdrop = false;
01240 
01241         _settings_client.gui.station_dragdrop = false;
01242 
01243         const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
01244         if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
01245           /* The previously selected number of tracks in invalid */
01246           for (uint i = 0; i < 7; i++) {
01247             if (!HasBit(statspec->disallowed_platforms, i)) {
01248               this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
01249               _settings_client.gui.station_numtracks = i + 1;
01250               break;
01251             }
01252           }
01253         }
01254 
01255         this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
01256         this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
01257         SndPlayFx(SND_15_BEEP);
01258         this->SetDirty();
01259         DeleteWindowById(WC_SELECT_STATION, 0);
01260         break;
01261       }
01262 
01263       case BRSW_PLATFORM_DRAG_N_DROP: {
01264         _settings_client.gui.station_dragdrop ^= true;
01265 
01266         this->ToggleWidgetLoweredState(BRSW_PLATFORM_DRAG_N_DROP);
01267 
01268         /* get the first allowed length/number of platforms */
01269         const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
01270         if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
01271           for (uint i = 0; i < 7; i++) {
01272             if (!HasBit(statspec->disallowed_lengths, i)) {
01273               this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
01274               _settings_client.gui.station_platlength = i + 1;
01275               break;
01276             }
01277           }
01278         }
01279         if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
01280           for (uint i = 0; i < 7; i++) {
01281             if (!HasBit(statspec->disallowed_platforms, i)) {
01282               this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
01283               _settings_client.gui.station_numtracks = i + 1;
01284               break;
01285             }
01286           }
01287         }
01288 
01289         this->SetWidgetLoweredState(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN, !_settings_client.gui.station_dragdrop);
01290         this->SetWidgetLoweredState(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN, !_settings_client.gui.station_dragdrop);
01291         SndPlayFx(SND_15_BEEP);
01292         this->SetDirty();
01293         DeleteWindowById(WC_SELECT_STATION, 0);
01294       } break;
01295 
01296       case BRSW_HIGHLIGHT_OFF:
01297       case BRSW_HIGHLIGHT_ON:
01298         _settings_client.gui.station_show_coverage = (widget != BRSW_HIGHLIGHT_OFF);
01299 
01300         this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage);
01301         this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage);
01302         SndPlayFx(SND_15_BEEP);
01303         this->SetDirty();
01304         break;
01305 
01306       case BRSW_NEWST_DROPDOWN:
01307         ShowDropDownList(this, BuildStationClassDropDown(), _railstation.station_class, BRSW_NEWST_DROPDOWN);
01308         break;
01309 
01310       case BRSW_NEWST_LIST: {
01311         const StationSpec *statspec;
01312         int y = (pt.y - this->GetWidget<NWidgetBase>(BRSW_NEWST_LIST)->pos_y) / this->line_height;
01313 
01314         if (y >= this->vscroll.GetCapacity()) return;
01315         y += this->vscroll.GetPosition();
01316         if (y >= _railstation.station_count) return;
01317 
01318         /* Check station availability callback */
01319         statspec = GetCustomStationSpec(_railstation.station_class, y);
01320         if (statspec != NULL &&
01321           HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
01322           GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
01323 
01324         _railstation.station_type = y;
01325 
01326         this->CheckSelectedSize(statspec);
01327 
01328         SndPlayFx(SND_15_BEEP);
01329         this->SetDirty();
01330         DeleteWindowById(WC_SELECT_STATION, 0);
01331         break;
01332       }
01333     }
01334   }
01335 
01336   virtual void OnDropdownSelect(int widget, int index)
01337   {
01338     if (_railstation.station_class != index) {
01339       _railstation.station_class = (StationClassID)index;
01340       _railstation.station_type  = 0;
01341       _railstation.station_count = GetNumCustomStations(_railstation.station_class);
01342 
01343       this->CheckSelectedSize(GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
01344 
01345       this->vscroll.SetCount(_railstation.station_count);
01346       this->vscroll.SetPosition(_railstation.station_type);
01347     }
01348 
01349     SndPlayFx(SND_15_BEEP);
01350     this->SetDirty();
01351     DeleteWindowById(WC_SELECT_STATION, 0);
01352   }
01353 
01354   virtual void OnTick()
01355   {
01356     CheckRedrawStationCoverage(this);
01357   }
01358 };
01359 
01360 static const NWidgetPart _nested_station_builder_widgets[] = {
01361   NWidget(NWID_HORIZONTAL),
01362     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
01363     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01364   EndContainer(),
01365   NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRSW_BACKGROUND),
01366     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2),
01367     NWidget(NWID_HORIZONTAL),
01368       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
01369       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_X), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
01370       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01371       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_Y), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
01372       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
01373     EndContainer(),
01374     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL), SetPadding(2, 2, 0, 2),
01375     NWidget(NWID_HORIZONTAL),
01376       NWidget(NWID_SPACER), SetFill(1, 0),
01377       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01378       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01379       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01380       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01381       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01382       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01383       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01384       NWidget(NWID_SPACER), SetFill(1, 0),
01385     EndContainer(),
01386     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH, STR_NULL), SetPadding(2, 2, 0, 2),
01387     NWidget(NWID_HORIZONTAL),
01388       NWidget(NWID_SPACER), SetFill(1, 0),
01389       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01390       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01391       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01392       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01393       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01394       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01395       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01396       NWidget(NWID_SPACER), SetFill(1, 0),
01397     EndContainer(),
01398     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01399     NWidget(NWID_HORIZONTAL),
01400       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01401       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP),
01402       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01403     EndContainer(),
01404     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2),
01405     NWidget(NWID_HORIZONTAL),
01406       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01407       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_OFF), SetMinimalSize(60, 12),
01408                     SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
01409       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_ON), SetMinimalSize(60, 12),
01410                     SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
01411       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01412     EndContainer(),
01413     NWidget(NWID_SPACER), SetMinimalSize(0, 20), SetResize(0, 1),
01414   EndContainer(),
01415 };
01416 
01417 static const NWidgetPart _nested_newstation_builder_widgets[] = {
01418   NWidget(NWID_HORIZONTAL),
01419     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
01420     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01421   EndContainer(),
01422   NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRSW_BACKGROUND),
01423     /* begin newstations gui additions. */
01424     NWidget(WWT_DROPDOWN, COLOUR_GREY, BRSW_NEWST_DROPDOWN), SetMinimalSize(134, 12), SetFill(1, 0), SetPadding(3, 7, 3, 7), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_STATION_CLASS_TOOLTIP),
01425     NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7),
01426       NWidget(WWT_MATRIX, COLOUR_GREY, BRSW_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0), SetDataTip(0x501, STR_STATION_BUILD_STATION_TYPE_TOOLTIP),
01427       NWidget(WWT_SCROLLBAR, COLOUR_GREY, BRSW_NEWST_SCROLL),
01428     EndContainer(),
01429     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
01430     /* end newstations gui additions. */
01431     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2),
01432     NWidget(NWID_HORIZONTAL),
01433       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
01434       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_X), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
01435       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01436       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_Y), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
01437       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
01438     EndContainer(),
01439     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL), SetPadding(2, 2, 0, 2),
01440     NWidget(NWID_HORIZONTAL),
01441       NWidget(NWID_SPACER), SetFill(1, 0),
01442       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01443       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01444       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01445       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01446       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01447       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01448       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
01449       NWidget(NWID_SPACER), SetFill(1, 0),
01450     EndContainer(),
01451     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH, STR_NULL), SetPadding(2, 2, 0, 2),
01452     NWidget(NWID_HORIZONTAL),
01453       NWidget(NWID_SPACER), SetFill(1, 0),
01454       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01455       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01456       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01457       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01458       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01459       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01460       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
01461       NWidget(NWID_SPACER), SetFill(1, 0),
01462     EndContainer(),
01463     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01464     NWidget(NWID_HORIZONTAL),
01465       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01466       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP),
01467       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01468     EndContainer(),
01469     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2),
01470     NWidget(NWID_HORIZONTAL),
01471       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01472       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_OFF), SetMinimalSize(60, 12),
01473                     SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
01474       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_ON), SetMinimalSize(60, 12),
01475                     SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
01476       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
01477     EndContainer(),
01478     NWidget(NWID_SPACER), SetMinimalSize(0, 20), SetResize(0, 1),
01479   EndContainer(),
01480 };
01481 
01483 static const WindowDesc _station_builder_desc(
01484   WDP_AUTO, 0, 0,
01485   WC_BUILD_STATION, WC_BUILD_TOOLBAR,
01486   WDF_CONSTRUCTION,
01487   _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets)
01488 );
01489 
01491 static const WindowDesc _newstation_builder_desc(
01492   WDP_AUTO, 0, 0,
01493   WC_BUILD_STATION, WC_BUILD_TOOLBAR,
01494   WDF_CONSTRUCTION,
01495   _nested_newstation_builder_widgets, lengthof(_nested_newstation_builder_widgets)
01496 );
01497 
01499 static void ShowStationBuilder(Window *parent)
01500 {
01501   if (GetNumStationClasses() <= 2 && GetNumCustomStations(STAT_CLASS_DFLT) == 1) {
01502     new BuildRailStationWindow(&_station_builder_desc, parent, false);
01503   } else {
01504     new BuildRailStationWindow(&_newstation_builder_desc, parent, true);
01505   }
01506 }
01507 
01509 enum BuildSignalWidgets {
01510   BSW_SEMAPHORE_NORM,
01511   BSW_SEMAPHORE_ENTRY,
01512   BSW_SEMAPHORE_EXIT,
01513   BSW_SEMAPHORE_COMBO,
01514   BSW_SEMAPHORE_PBS,
01515   BSW_SEMAPHORE_PBS_OWAY,
01516   BSW_ELECTRIC_NORM,
01517   BSW_ELECTRIC_ENTRY,
01518   BSW_ELECTRIC_EXIT,
01519   BSW_ELECTRIC_COMBO,
01520   BSW_ELECTRIC_PBS,
01521   BSW_ELECTRIC_PBS_OWAY,
01522   BSW_CONVERT,
01523   BSW_DRAG_SIGNALS_DENSITY,
01524   BSW_DRAG_SIGNALS_DENSITY_LABEL,
01525   BSW_DRAG_SIGNALS_DENSITY_DECREASE,
01526   BSW_DRAG_SIGNALS_DENSITY_INCREASE,
01527 };
01528 
01529 struct BuildSignalWindow : public PickerWindowBase {
01530 private:
01538   void DrawSignalSprite(byte widget_index, SpriteID image) const
01539   {
01540     /* First get the right image, which is one later for 'green' signals. */
01541     image += this->IsWidgetLowered(widget_index);
01542 
01543     /* Next get the actual sprite so we can calculate the right offsets. */
01544     const Sprite *sprite = GetSprite(image, ST_NORMAL);
01545 
01546     /* For the x offset we want the sprite to be centered, so undo the offset
01547      * for sprite drawing and add half of the sprite's width. For the y offset
01548      * we want the sprite to be aligned on the bottom, so again we undo the
01549      * offset for sprite drawing and assume it is the bottom of the sprite. */
01550     int sprite_center_x_offset = sprite->x_offs + sprite->width / 2;
01551     int sprite_bottom_y_offset = sprite->height + sprite->y_offs;
01552 
01553     /* Next we want to know where on the window to draw. Calculate the center
01554      * and the bottom of the area to draw. */
01555     const NWidgetBase *widget = this->GetWidget<NWidgetBase>(widget_index);
01556     int widget_center_x = widget->pos_x + widget->current_x / 2;
01557     int widget_bottom_y = widget->pos_y + widget->current_y - 2;
01558 
01559     /* Finally we draw the signal. */
01560     DrawSprite(image, PAL_NONE,
01561         widget_center_x - sprite_center_x_offset + this->IsWidgetLowered(widget_index),
01562         widget_bottom_y - sprite_bottom_y_offset + this->IsWidgetLowered(widget_index));
01563   }
01564 
01565 public:
01566   BuildSignalWindow(const WindowDesc *desc, Window *parent) : PickerWindowBase(parent)
01567   {
01568     this->InitNested(desc, TRANSPORT_RAIL);
01569     this->OnInvalidateData();
01570   };
01571 
01572   virtual void SetStringParameters(int widget) const
01573   {
01574     switch (widget) {
01575       case BSW_DRAG_SIGNALS_DENSITY_LABEL:
01576         SetDParam(0, _settings_client.gui.drag_signals_density);
01577         break;
01578     }
01579   }
01580 
01581   virtual void OnPaint()
01582   {
01583     this->DrawWidgets();
01584   }
01585 
01586   virtual void DrawWidget(const Rect &r, int widget) const
01587   {
01588     if (IsInsideMM(widget, BSW_SEMAPHORE_NORM, BSW_ELECTRIC_PBS_OWAY + 1)) {
01589       /* We need to do some custom sprite widget drawing for the signals. */
01590       const SpriteID _signal_lookup[] = {
01591         SPR_IMG_SIGNAL_SEMAPHORE_NORM,  SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_EXIT,
01592         SPR_IMG_SIGNAL_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_PBS,   SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY,
01593 
01594         SPR_IMG_SIGNAL_ELECTRIC_NORM,  SPR_IMG_SIGNAL_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_EXIT,
01595         SPR_IMG_SIGNAL_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_PBS,   SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY
01596       };
01597 
01598       this->DrawSignalSprite(widget, _signal_lookup[widget - BSW_SEMAPHORE_NORM]);
01599     }
01600   }
01601 
01602   virtual void OnClick(Point pt, int widget, int click_count)
01603   {
01604     switch (widget) {
01605       case BSW_SEMAPHORE_NORM:
01606       case BSW_SEMAPHORE_ENTRY:
01607       case BSW_SEMAPHORE_EXIT:
01608       case BSW_SEMAPHORE_COMBO:
01609       case BSW_SEMAPHORE_PBS:
01610       case BSW_SEMAPHORE_PBS_OWAY:
01611       case BSW_ELECTRIC_NORM:
01612       case BSW_ELECTRIC_ENTRY:
01613       case BSW_ELECTRIC_EXIT:
01614       case BSW_ELECTRIC_COMBO:
01615       case BSW_ELECTRIC_PBS:
01616       case BSW_ELECTRIC_PBS_OWAY:
01617         this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
01618 
01619         _cur_signal_type = (SignalType)((uint)((widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_LAST + 1)));
01620         _cur_signal_variant = widget >= BSW_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE;
01621         break;
01622 
01623       case BSW_CONVERT:
01624         _convert_signal_button = !_convert_signal_button;
01625         break;
01626 
01627       case BSW_DRAG_SIGNALS_DENSITY_DECREASE:
01628         if (_settings_client.gui.drag_signals_density > 1) {
01629           _settings_client.gui.drag_signals_density--;
01630           SetWindowDirty(WC_GAME_OPTIONS, 0);
01631         }
01632         break;
01633 
01634       case BSW_DRAG_SIGNALS_DENSITY_INCREASE:
01635         if (_settings_client.gui.drag_signals_density < 20) {
01636           _settings_client.gui.drag_signals_density++;
01637           SetWindowDirty(WC_GAME_OPTIONS, 0);
01638         }
01639         break;
01640 
01641       default: break;
01642     }
01643 
01644     this->InvalidateData();
01645   }
01646 
01647   virtual void OnInvalidateData(int data = 0)
01648   {
01649     this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
01650 
01651     this->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button);
01652 
01653     this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1);
01654     this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20);
01655   }
01656 };
01657 
01659 static const NWidgetPart _nested_signal_builder_widgets[] = {
01660   NWidget(NWID_HORIZONTAL),
01661     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
01662     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_SIGNAL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01663   EndContainer(),
01664   NWidget(NWID_VERTICAL, NC_EQUALSIZE),
01665     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01666       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP), EndContainer(), SetFill(1, 1),
01667       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1),
01668       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1),
01669       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1),
01670       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
01671       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
01672       NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, BSW_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1),
01673     EndContainer(),
01674     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01675       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1),
01676       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1),
01677       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1),
01678       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1),
01679       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
01680       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
01681       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_DRAG_SIGNALS_DENSITY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1),
01682         NWidget(WWT_LABEL, COLOUR_DARK_GREEN, BSW_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1),
01683         NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
01684           NWidget(NWID_SPACER), SetFill(1, 0),
01685           NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, BSW_DRAG_SIGNALS_DENSITY_DECREASE), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP),
01686           NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, BSW_DRAG_SIGNALS_DENSITY_INCREASE), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP),
01687           NWidget(NWID_SPACER), SetFill(1, 0),
01688         EndContainer(),
01689         NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
01690       EndContainer(),
01691     EndContainer(),
01692   EndContainer(),
01693 };
01694 
01696 static const WindowDesc _signal_builder_desc(
01697   WDP_AUTO, 0, 0,
01698   WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR,
01699   WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
01700   _nested_signal_builder_widgets, lengthof(_nested_signal_builder_widgets)
01701 );
01702 
01706 static void ShowSignalBuilder(Window *parent)
01707 {
01708   new BuildSignalWindow(&_signal_builder_desc, parent);
01709 }
01710 
01712 enum BuildRailDepotWidgets {
01713   BRDW_DEPOT_NE,
01714   BRDW_DEPOT_SE,
01715   BRDW_DEPOT_SW,
01716   BRDW_DEPOT_NW,
01717 };
01718 
01719 struct BuildRailDepotWindow : public PickerWindowBase {
01720   BuildRailDepotWindow(const WindowDesc *desc, Window *parent) : PickerWindowBase(parent)
01721   {
01722     this->InitNested(desc, TRANSPORT_RAIL);
01723     this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
01724   }
01725 
01726   virtual void OnPaint()
01727   {
01728     this->DrawWidgets();
01729   }
01730 
01731   virtual void DrawWidget(const Rect &r, int widget) const
01732   {
01733     if (!IsInsideMM(widget, BRDW_DEPOT_NE, BRDW_DEPOT_NW + 1)) return;
01734 
01735     DrawTrainDepotSprite(r.left - 1, r.top, widget - BRDW_DEPOT_NE + DIAGDIR_NE, _cur_railtype);
01736   }
01737 
01738   virtual void OnClick(Point pt, int widget, int click_count)
01739   {
01740     switch (widget) {
01741       case BRDW_DEPOT_NE:
01742       case BRDW_DEPOT_SE:
01743       case BRDW_DEPOT_SW:
01744       case BRDW_DEPOT_NW:
01745         this->RaiseWidget(_build_depot_direction + BRDW_DEPOT_NE);
01746         _build_depot_direction = (DiagDirection)(widget - BRDW_DEPOT_NE);
01747         this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
01748         SndPlayFx(SND_15_BEEP);
01749         this->SetDirty();
01750         break;
01751     }
01752   }
01753 };
01754 
01756 static const NWidgetPart _nested_build_depot_widgets[] = {
01757   NWidget(NWID_HORIZONTAL),
01758     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
01759     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01760   EndContainer(),
01761   NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
01762     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
01763     NWidget(NWID_HORIZONTAL_LTR),
01764       NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
01765       NWidget(NWID_VERTICAL),
01766         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
01767         EndContainer(),
01768         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01769         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
01770         EndContainer(),
01771       EndContainer(),
01772       NWidget(NWID_SPACER), SetMinimalSize(2, 0),
01773       NWidget(NWID_VERTICAL),
01774         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
01775         EndContainer(),
01776         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01777         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
01778         EndContainer(),
01779       EndContainer(),
01780       NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
01781     EndContainer(),
01782     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
01783   EndContainer(),
01784 };
01785 
01786 static const WindowDesc _build_depot_desc(
01787   WDP_AUTO, 0, 0,
01788   WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
01789   WDF_CONSTRUCTION,
01790   _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets)
01791 );
01792 
01793 static void ShowBuildTrainDepotPicker(Window *parent)
01794 {
01795   new BuildRailDepotWindow(&_build_depot_desc, parent);
01796 }
01797 
01799 enum BuildRailWaypointWidgets {
01800   BRWW_WAYPOINT_1,
01801   BRWW_WAYPOINT_2,
01802   BRWW_WAYPOINT_3,
01803   BRWW_WAYPOINT_4,
01804   BRWW_WAYPOINT_5,
01805   BRWW_SCROLL,
01806 };
01807 
01808 struct BuildRailWaypointWindow : PickerWindowBase {
01809   BuildRailWaypointWindow(const WindowDesc *desc, Window *parent) : PickerWindowBase(parent)
01810   {
01811     this->InitNested(desc, TRANSPORT_RAIL);
01812     this->hscroll.SetCapacity(5);
01813     this->hscroll.SetCount(_waypoint_count);
01814   };
01815 
01816   virtual void OnPaint()
01817   {
01818     for (uint i = 0; i < this->hscroll.GetCapacity(); i++) {
01819       this->SetWidgetLoweredState(i + BRWW_WAYPOINT_1, (this->hscroll.GetPosition() + i) == _cur_waypoint_type);
01820     }
01821 
01822     this->DrawWidgets();
01823 
01824     for (uint i = 0; i < this->hscroll.GetCapacity(); i++) {
01825       if (this->hscroll.GetPosition() + i < this->hscroll.GetCount()) {
01826         const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, this->hscroll.GetPosition() + i);
01827         NWidgetBase *nw = this->GetWidget<NWidgetBase>(BRWW_WAYPOINT_1 + i);
01828 
01829         int bottom = nw->pos_y + nw->current_y;
01830         DrawWaypointSprite(nw->pos_x + TILE_PIXELS, bottom - TILE_PIXELS, this->hscroll.GetPosition() + i, _cur_railtype);
01831 
01832         if (statspec != NULL &&
01833             HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
01834             GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
01835           GfxFillRect(nw->pos_x + 1, nw->pos_y + 1, nw->pos_x + nw->current_x - 2, bottom - 2, 0, FILLRECT_CHECKER);
01836         }
01837       }
01838     }
01839   }
01840 
01841   virtual void OnClick(Point pt, int widget, int click_count)
01842   {
01843     switch (widget) {
01844       case BRWW_WAYPOINT_1:
01845       case BRWW_WAYPOINT_2:
01846       case BRWW_WAYPOINT_3:
01847       case BRWW_WAYPOINT_4:
01848       case BRWW_WAYPOINT_5: {
01849         byte type = widget - BRWW_WAYPOINT_1 + this->hscroll.GetPosition();
01850 
01851         /* Check station availability callback */
01852         const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
01853         if (statspec != NULL &&
01854             HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
01855             GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
01856 
01857         _cur_waypoint_type = type;
01858         SndPlayFx(SND_15_BEEP);
01859         this->SetDirty();
01860         break;
01861       }
01862     }
01863   }
01864 };
01865 
01867 static const NWidgetPart _nested_build_waypoint_widgets[] = {
01868   NWidget(NWID_HORIZONTAL),
01869     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
01870     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WAYPOINT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01871   EndContainer(),
01872   NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
01873     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
01874     NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
01875       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_1), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
01876       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_2), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
01877       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_3), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
01878       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_4), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
01879       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_5), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
01880     EndContainer(),
01881     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
01882     NWidget(WWT_HSCROLLBAR, COLOUR_DARK_GREEN, BRWW_SCROLL),
01883   EndContainer(),
01884 };
01885 
01886 static const WindowDesc _build_waypoint_desc(
01887   WDP_AUTO, 0, 0,
01888   WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
01889   WDF_CONSTRUCTION,
01890   _nested_build_waypoint_widgets, lengthof(_nested_build_waypoint_widgets)
01891 );
01892 
01893 static void ShowBuildWaypointPicker(Window *parent)
01894 {
01895   new BuildRailWaypointWindow(&_build_waypoint_desc, parent);
01896 }
01897 
01901 void InitializeRailGui()
01902 {
01903   _build_depot_direction = DIAGDIR_NW;
01904 }
01905 
01910 void ReinitGuiAfterToggleElrail(bool disable)
01911 {
01912   extern RailType _last_built_railtype;
01913   if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) {
01914     _last_built_railtype = _cur_railtype = RAILTYPE_RAIL;
01915     BuildRailToolbarWindow *w = dynamic_cast<BuildRailToolbarWindow *>(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL));
01916     if (w != NULL) w->ModifyRailType(_cur_railtype);
01917   }
01918   MarkWholeScreenDirty();
01919 }
01920 
01922 static void SetDefaultRailGui()
01923 {
01924   if (_local_company == COMPANY_SPECTATOR || !Company::IsValidID(_local_company)) return;
01925 
01926   extern RailType _last_built_railtype;
01927   RailType rt = (RailType)(_settings_client.gui.default_rail_type + RAILTYPE_END);
01928   if (rt == DEF_RAILTYPE_MOST_USED) {
01929     /* Find the most used rail type */
01930     RailType count[RAILTYPE_END];
01931     memset(count, 0, sizeof(count));
01932     for (TileIndex t = 0; t < MapSize(); t++) {
01933       if (IsTileType(t, MP_RAILWAY) || IsLevelCrossingTile(t) || HasStationTileRail(t) ||
01934           (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL)) {
01935         count[GetRailType(t)]++;
01936       }
01937     }
01938 
01939     rt = RAILTYPE_RAIL;
01940     for (RailType r = RAILTYPE_ELECTRIC; r < RAILTYPE_END; r++) {
01941       if (count[r] >= count[rt]) rt = r;
01942     }
01943 
01944     /* No rail, just get the first available one */
01945     if (count[rt] == 0) rt = DEF_RAILTYPE_FIRST;
01946   }
01947   switch (rt) {
01948     case DEF_RAILTYPE_FIRST:
01949       rt = RAILTYPE_RAIL;
01950       while (rt < RAILTYPE_END && !HasRailtypeAvail(_local_company, rt)) rt++;
01951       break;
01952 
01953     case DEF_RAILTYPE_LAST:
01954       rt = GetBestRailtype(_local_company);
01955       break;
01956 
01957     default:
01958       break;
01959   }
01960 
01961   _last_built_railtype = _cur_railtype = rt;
01962   BuildRailToolbarWindow *w = dynamic_cast<BuildRailToolbarWindow *>(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL));
01963   if (w != NULL) w->ModifyRailType(_cur_railtype);
01964 }
01965 
01972 bool ResetSignalVariant(int32 p = 0)
01973 {
01974   SignalVariant new_variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC);
01975 
01976   if (new_variant != _cur_signal_variant) {
01977     Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
01978     if (w != NULL) {
01979       w->SetDirty();
01980       w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
01981     }
01982     _cur_signal_variant = new_variant;
01983   }
01984 
01985   return true;
01986 }
01987 
01991 void InitializeRailGUI()
01992 {
01993   SetDefaultRailGui();
01994 
01995   _convert_signal_button = false;
01996   _cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type];
01997   ResetSignalVariant();
01998 }

Generated on Wed Mar 17 23:50:15 2010 for OpenTTD by  doxygen 1.6.1