# rail_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: rail_gui.cpp 12871 2008-04-24 14:33:18Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "tile_cmd.h"
    00008 #include "landscape.h"
    00009 #include "gui.h"
    00010 #include "window_gui.h"
    00011 #include "station_gui.h"
    00012 #include "terraform_gui.h"
    00013 #include "viewport_func.h"
    00014 #include "gfx_func.h"
    00015 #include "command_func.h"
    00016 #include "station.h"
    00017 #include "waypoint.h"
    00018 #include "debug.h"
    00019 #include "variables.h"
    00020 #include "newgrf_callbacks.h"
    00021 #include "newgrf_station.h"
    00022 #include "train.h"
    00023 #include "strings_func.h"
    00024 #include "functions.h"
    00025 #include "window_func.h"
    00026 #include "date_func.h"
    00027 #include "sound_func.h"
    00028 #include "player_func.h"
    00029 #include "settings_type.h"
    00030 #include "widgets/dropdown_type.h"
    00031 #include "widgets/dropdown_func.h"
    00032
    00033 #include "bridge_map.h"
    00034 #include "rail_map.h"
    00035 #include "road_map.h"
    00036 #include "station_map.h"
    00037 #include "tunnel_map.h"
    00038 #include "tunnelbridge_map.h"
    00039
    00040 #include "table/sprites.h"
    00041 #include "table/strings.h"
    00042
    00043 static RailType _cur_railtype;
    00044 static bool _remove_button_clicked;
    00045 static DiagDirection _build_depot_direction;
    00046 static byte _waypoint_count = 1;
    00047 static byte _cur_waypoint_type;
    00048 static bool _convert_signal_button; // convert signal button in the signal GUI pressed
    00049 static SignalVariant _cur_signal_variant; // set the signal variant (for signal GUI)
    00050 static SignalType _cur_signal_type; // set the signal type (for signal GUI)
    00051
    00052 static struct {
    00053   byte orientation;
    00054   byte numtracks;
    00055   byte platlength;
    00056   bool dragdrop;
    00057
    00058   bool newstations;
    00059   StationClassIDByte station_class;
    00060   byte station_type;
    00061   byte station_count;
    00062 } _railstation;
    00063
    00064
    00065 static void HandleStationPlacement(TileIndex start, TileIndex end);
    00066 static void ShowBuildTrainDepotPicker();
    00067 static void ShowBuildWaypointPicker();
    00068 static void ShowStationBuilder();
    00069 static void ShowSignalBuilder();
    00070
    00071 void CcPlaySound1E(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00072 {
    00073   if (success) SndPlayTileFx(SND_20_SPLAT_2, tile);
    00074 }
    00075
    00076 static void GenericPlaceRail(TileIndex tile, int cmd)
    00077 {
    00078   DoCommandP(tile, _cur_railtype, cmd, CcPlaySound1E,
    00079     _remove_button_clicked ?
    00080     CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) | CMD_NO_WATER :
    00081     CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) | CMD_NO_WATER
    00082   );
    00083 }
    00084
    00085 static void PlaceRail_N(TileIndex tile)
    00086 {
    00087   int cmd = _tile_fract_coords.x > _tile_fract_coords.y ? 4 : 5;
    00088   GenericPlaceRail(tile, cmd);
    00089 }
    00090
    00091 static void PlaceRail_NE(TileIndex tile)
    00092 {
    00093   VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_RAIL_NE);
    00094 }
    00095
    00096 static void PlaceRail_E(TileIndex tile)
    00097 {
    00098   int cmd = _tile_fract_coords.x + _tile_fract_coords.y <= 15 ? 2 : 3;
    00099   GenericPlaceRail(tile, cmd);
    00100 }
    00101
    00102 static void PlaceRail_NW(TileIndex tile)
    00103 {
    00104   VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_RAIL_NW);
    00105 }
    00106
    00107 static void PlaceRail_AutoRail(TileIndex tile)
    00108 {
    00109   VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_AUTORAIL);
    00110 }
    00111
    00112 static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
    00113 {
    00114   if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
    00115   if ((GetTrackBits(tile) & GB(extra, 8, 8)) == 0) return;
    00116
    00117   DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_NO_WATER);
    00118 }
    00119
    00120 static const uint16 _place_depot_extra[12] = {
    00121   0x0604, 0x2102, 0x1202, 0x0505,
    00122   0x2400, 0x2801, 0x1800, 0x1401,
    00123   0x2203, 0x0904, 0x0A05, 0x1103,
    00124 };
    00125
    00126
    00127 void CcRailDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00128 {
    00129   if (success) {
    00130     DiagDirection dir = (DiagDirection)p2;
    00131
    00132     SndPlayTileFx(SND_20_SPLAT_2, tile);
    00133     ResetObjectToPlace();
    00134
    00135     tile += TileOffsByDiagDir(dir);
    00136
    00137     if (IsTileType(tile, MP_RAILWAY)) {
    00138       PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
    00139       PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
    00140       PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
    00141     }
    00142   }
    00143 }
    00144
    00145 static void PlaceRail_Depot(TileIndex tile)
    00146 {
    00147   DoCommandP(tile, _cur_railtype, _build_depot_direction, CcRailDepot,
    00148     CMD_BUILD_TRAIN_DEPOT | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT));
    00149 }
    00150
    00151 static void PlaceRail_Waypoint(TileIndex tile)
    00152 {
    00153   if (_remove_button_clicked) {
    00154     DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT));
    00155   } else {
    00156     DoCommandP(tile, _cur_waypoint_type, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT));
    00157   }
    00158 }
    00159
    00160 void CcStation(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00161 {
    00162   if (success) {
    00163     SndPlayTileFx(SND_20_SPLAT_2, tile);
    00164     /* Only close the station builder window if the default station is chosen. */
    00165     if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0) ResetObjectToPlace();
    00166   }
    00167 }
    00168
    00169 static void PlaceRail_Station(TileIndex tile)
    00170 {
    00171   if (_remove_button_clicked) {
    00172     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
    00173     VpSetPlaceSizingLimit(-1);
    00174   } else if (_railstation.dragdrop) {
    00175     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
    00176     VpSetPlaceSizingLimit(_patches.station_spread);
    00177   } else {
    00178     DoCommandP(tile,
    00179         _railstation.orientation | (_railstation.numtracks << 8) | (_railstation.platlength << 16) | (_ctrl_pressed << 24),
    00180         _cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
    00181         CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
    00182   }
    00183 }
    00184
    00190 static void GenericPlaceSignals(TileIndex tile)
    00191 {
    00192   TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
    00193
    00194   if (trackbits & TRACK_BIT_VERT) { // N-S direction
    00195     trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
    00196   }
    00197
    00198   if (trackbits & TRACK_BIT_HORZ) { // E-W direction
    00199     trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
    00200   }
    00201
    00202   Track track = FindFirstTrack(trackbits);
    00203
    00204   if (_remove_button_clicked) {
    00205     DoCommandP(tile, track, 0, CcPlaySound1E,
    00206       CMD_REMOVE_SIGNALS | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM));
    00207   } else {
    00208     if (!_patches.enable_signal_gui) _cur_signal_variant = _cur_year < _patches.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC;
    00209
    00210     /* various bitstuffed elements for CmdBuildSingleSignal() */
    00211     uint32 p1 = track;
    00212     SB(p1, 3, 1, _ctrl_pressed);
    00213     SB(p1, 4, 1, _cur_signal_variant);
    00214     SB(p1, 5, 2, _patches.enable_signal_gui ? _cur_signal_type : SIGTYPE_NORMAL);
    00215     SB(p1, 7, 1, _convert_signal_button);
    00216
    00217     DoCommandP(tile, p1, 0, CcPlaySound1E, CMD_BUILD_SIGNALS |
    00218       CMD_MSG(_convert_signal_button ? STR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_1010_CAN_T_BUILD_SIGNALS_HERE));
    00219   }
    00220 }
    00221
    00222 static void PlaceRail_Bridge(TileIndex tile)
    00223 {
    00224   VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
    00225 }
    00226
    00227 void CcBuildRailTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00228 {
    00229   if (success) {
    00230     SndPlayTileFx(SND_20_SPLAT_2, tile);
    00231     ResetObjectToPlace();
    00232   } else {
    00233     SetRedErrorSquare(_build_tunnel_endtile);
    00234   }
    00235 }
    00236
    00237 static void PlaceRail_Tunnel(TileIndex tile)
    00238 {
    00239   DoCommandP(tile, _cur_railtype, 0, CcBuildRailTunnel,
    00240     CMD_BUILD_TUNNEL | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE));
    00241 }
    00242
    00243 void PlaceProc_BuyLand(TileIndex tile)
    00244 {
    00245   DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_PURCHASE_LAND_AREA | CMD_NO_WATER | CMD_MSG(STR_5806_CAN_T_PURCHASE_THIS_LAND));
    00246 }
    00247
    00248 static void PlaceRail_ConvertRail(TileIndex tile)
    00249 {
    00250   VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
    00251 }
    00252
    00253 static void PlaceRail_AutoSignals(TileIndex tile)
    00254 {
    00255   VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
    00256 }
    00257
    00258
    00260 enum RailToolbarWidgets {
    00261   RTW_CLOSEBOX = 0,
    00262   RTW_CAPTION,
    00263   RTW_STICKY,
    00264   RTW_SPACER,
    00265   RTW_BUILD_NS,
    00266   RTW_BUILD_X,
    00267   RTW_BUILD_EW,
    00268   RTW_BUILD_Y,
    00269   RTW_AUTORAIL,
    00270   RTW_DEMOLISH,
    00271   RTW_BUILD_DEPOT,
    00272   RTW_BUILD_WAYPOINT,
    00273   RTW_BUILD_STATION,
    00274   RTW_BUILD_SIGNALS,
    00275   RTW_BUILD_BRIDGE,
    00276   RTW_BUILD_TUNNEL,
    00277   RTW_REMOVE,
    00278   RTW_CONVERT_RAIL,
    00279 };
    00280
    00281
    00285 static void ToggleRailButton_Remove(Window *w)
    00286 {
    00287   w->ToggleWidgetLoweredState(RTW_REMOVE);
    00288   w->InvalidateWidget(RTW_REMOVE);
    00289   _remove_button_clicked = w->IsWidgetLowered(RTW_REMOVE);
    00290   SetSelectionRed(_remove_button_clicked);
    00291 }
    00292
    00297 static bool RailToolbar_CtrlChanged(Window *w)
    00298 {
    00299   if (w->IsWidgetDisabled(RTW_REMOVE)) return false;
    00300
    00301   /* allow ctrl to switch remove mode only for these widgets */
    00302   for (uint i = RTW_BUILD_NS; i <= RTW_BUILD_STATION; i++) {
    00303     if ((i <= RTW_AUTORAIL || i >= RTW_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) {
    00304       ToggleRailButton_Remove(w);
    00305       return true;
    00306     }
    00307   }
    00308
    00309   return false;
    00310 }
    00311
    00312
    00313 static void BuildRailClick_N(Window *w)
    00314 {
    00315   HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, VHM_RECT, PlaceRail_N);
    00316 }
    00317
    00318 static void BuildRailClick_NE(Window *w)
    00319 {
    00320   HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, VHM_RECT, PlaceRail_NE);
    00321 }
    00322
    00323 static void BuildRailClick_E(Window *w)
    00324 {
    00325   HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, VHM_RECT, PlaceRail_E);
    00326 }
    00327
    00328 static void BuildRailClick_NW(Window *w)
    00329 {
    00330   HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, VHM_RECT, PlaceRail_NW);
    00331 }
    00332
    00333 static void BuildRailClick_AutoRail(Window *w)
    00334 {
    00335   HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, VHM_RAIL, PlaceRail_AutoRail);
    00336 }
    00337
    00338 static void BuildRailClick_Demolish(Window *w)
    00339 {
    00340   HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, VHM_RECT, PlaceProc_DemolishArea);
    00341 }
    00342
    00343 static void BuildRailClick_Depot(Window *w)
    00344 {
    00345   if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, VHM_RECT, PlaceRail_Depot)) {
    00346     ShowBuildTrainDepotPicker();
    00347   }
    00348 }
    00349
    00350 static void BuildRailClick_Waypoint(Window *w)
    00351 {
    00352   _waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
    00353   if (HandlePlacePushButton(w, RTW_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, VHM_RECT, PlaceRail_Waypoint) &&
    00354       _waypoint_count > 1) {
    00355     ShowBuildWaypointPicker();
    00356   }
    00357 }
    00358
    00359 static void BuildRailClick_Station(Window *w)
    00360 {
    00361   if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, VHM_RECT, PlaceRail_Station)) ShowStationBuilder();
    00362 }
    00363
    00365 static void BuildRailClick_AutoSignals(Window *w)
    00366 {
    00367   if (_patches.enable_signal_gui) {
    00368     if (HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals)) ShowSignalBuilder();
    00369   } else {
    00370     HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals);
    00371   }
    00372 }
    00373
    00374 static void BuildRailClick_Bridge(Window *w)
    00375 {
    00376   HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, VHM_RECT, PlaceRail_Bridge);
    00377 }
    00378
    00379 static void BuildRailClick_Tunnel(Window *w)
    00380 {
    00381   HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, VHM_SPECIAL, PlaceRail_Tunnel);
    00382 }
    00383
    00384 static void BuildRailClick_Remove(Window *w)
    00385 {
    00386   if (w->IsWidgetDisabled(RTW_REMOVE)) return;
    00387   ToggleRailButton_Remove(w);
    00388   SndPlayFx(SND_15_BEEP);
    00389
    00390   /* handle station builder */
    00391   if (w->IsWidgetLowered(RTW_BUILD_STATION)) {
    00392     if (_remove_button_clicked) {
    00393       /* starting drag & drop remove */
    00394       if (!_railstation.dragdrop) {
    00395         SetTileSelectSize(1, 1);
    00396       } else {
    00397         VpSetPlaceSizingLimit(-1);
    00398       }
    00399     } else {
    00400       /* starting station build mode */
    00401       if (!_railstation.dragdrop) {
    00402         int x = _railstation.numtracks;
    00403         int y = _railstation.platlength;
    00404         if (_railstation.orientation == 0) Swap(x, y);
    00405         SetTileSelectSize(x, y);
    00406       } else {
    00407         VpSetPlaceSizingLimit(_patches.station_spread);
    00408       }
    00409     }
    00410   }
    00411 }
    00412
    00413 static void BuildRailClick_Convert(Window *w)
    00414 {
    00415   HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, VHM_RECT, PlaceRail_ConvertRail);
    00416 }
    00417
    00418
    00419 static void DoRailroadTrack(int mode)
    00420 {
    00421   DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), NULL,
    00422     _remove_button_clicked ?
    00423     CMD_REMOVE_RAILROAD_TRACK | CMD_NO_WATER | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) :
    00424     CMD_BUILD_RAILROAD_TRACK  | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK)
    00425   );
    00426 }
    00427
    00428 static void HandleAutodirPlacement()
    00429 {
    00430   TileHighlightData *thd = &_thd;
    00431   int trackstat = thd->drawstyle & 0xF; // 0..5
    00432
    00433   if (thd->drawstyle & HT_RAIL) { // one tile case
    00434     GenericPlaceRail(TileVirtXY(thd->selend.x, thd->selend.y), trackstat);
    00435     return;
    00436   }
    00437
    00438   DoRailroadTrack(trackstat);
    00439 }
    00440
    00447 static void HandleAutoSignalPlacement()
    00448 {
    00449   TileHighlightData *thd = &_thd;
    00450   uint32 p2 = GB(thd->drawstyle, 0, 3); // 0..5
    00451
    00452   if (thd->drawstyle == HT_RECT) { // one tile case
    00453     GenericPlaceSignals(TileVirtXY(thd->selend.x, thd->selend.y));
    00454     return;
    00455   }
    00456
    00457   /* XXX Steal ctrl for autosignal function, until we get some GUI */
    00458   SB(p2,  3, 1, 0);
    00459   SB(p2,  4, 1, _cur_year < _patches.semaphore_build_before);
    00460   SB(p2,  6, 1, _ctrl_pressed);
    00461   SB(p2, 24, 8, _patches.drag_signals_density);
    00462
    00463   /* _patches.drag_signals_density is given as a parameter such that each user
    00464    * in a network game can specify his/her own signal density */
    00465   DoCommandP(
    00466     TileVirtXY(thd->selstart.x, thd->selstart.y),
    00467     TileVirtXY(thd->selend.x, thd->selend.y),
    00468     p2,
    00469     CcPlaySound1E,
    00470     _remove_button_clicked ?
    00471       CMD_REMOVE_SIGNAL_TRACK | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) :
    00472       CMD_BUILD_SIGNAL_TRACK  | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE)
    00473   );
    00474 }
    00475
    00476
    00477 typedef void OnButtonClick(Window *w);
    00478
    00479 static OnButtonClick * const _build_railroad_button_proc[] = {
    00480   BuildRailClick_N,
    00481   BuildRailClick_NE,
    00482   BuildRailClick_E,
    00483   BuildRailClick_NW,
    00484   BuildRailClick_AutoRail,
    00485   BuildRailClick_Demolish,
    00486   BuildRailClick_Depot,
    00487   BuildRailClick_Waypoint,
    00488   BuildRailClick_Station,
    00489   BuildRailClick_AutoSignals,
    00490   BuildRailClick_Bridge,
    00491   BuildRailClick_Tunnel,
    00492   BuildRailClick_Remove,
    00493   BuildRailClick_Convert
    00494 };
    00495
    00496 static const uint16 _rail_keycodes[] = {
    00497   '1',
    00498   '2',
    00499   '3',
    00500   '4',
    00501   '5',
    00502   '6',
    00503   '7', // depot
    00504   '8', // waypoint
    00505   '9', // station
    00506   'S', // signals
    00507   'B', // bridge
    00508   'T', // tunnel
    00509   'R', // remove
    00510   'C', // convert rail
    00511 };
    00512
    00513
    00514 static void UpdateRemoveWidgetStatus(Window *w, int clicked_widget)
    00515 {
    00516   switch (clicked_widget) {
    00517     case RTW_REMOVE:
    00518       /* If it is the removal button that has been clicked, do nothing,
    00519        * as it is up to the other buttons to drive removal status */
    00520       return;
    00521       break;
    00522     case RTW_BUILD_NS:
    00523     case RTW_BUILD_X:
    00524     case RTW_BUILD_EW:
    00525     case RTW_BUILD_Y:
    00526     case RTW_AUTORAIL:
    00527     case RTW_BUILD_WAYPOINT:
    00528     case RTW_BUILD_STATION:
    00529     case RTW_BUILD_SIGNALS:
    00530       /* Removal button is enabled only if the rail/signal/waypoint/station
    00531        * button is still lowered.  Once raised, it has to be disabled */
    00532       w->SetWidgetDisabledState(RTW_REMOVE, !w->IsWidgetLowered(clicked_widget));
    00533       break;
    00534
    00535     default:
    00536       /* When any other buttons than rail/signal/waypoint/station, raise and
    00537        * disable the removal button */
    00538       w->DisableWidget(RTW_REMOVE);
    00539       w->RaiseWidget(RTW_REMOVE);
    00540       break;
    00541   }
    00542 }
    00543
    00550 static void BuildRailToolbWndProc(Window *w, WindowEvent *e)
    00551 {
    00552   switch (e->event) {
    00553   case WE_CREATE: w->DisableWidget(RTW_REMOVE); break;
    00554
    00555   case WE_PAINT: DrawWindowWidgets(w); break;
    00556
    00557   case WE_CLICK:
    00558     if (e->we.click.widget >= RTW_BUILD_NS) {
    00559       _remove_button_clicked = false;
    00560       _build_railroad_button_proc[e->we.click.widget - RTW_BUILD_NS](w);
    00561     }
    00562     UpdateRemoveWidgetStatus(w, e->we.click.widget);
    00563     if (_ctrl_pressed) RailToolbar_CtrlChanged(w);
    00564     break;
    00565
    00566   case WE_KEYPRESS:
    00567     for (uint8 i = 0; i != lengthof(_rail_keycodes); i++) {
    00568       if (e->we.keypress.keycode == _rail_keycodes[i]) {
    00569         e->we.keypress.cont = false;
    00570         _remove_button_clicked = false;
    00571         _build_railroad_button_proc[i](w);
    00572         UpdateRemoveWidgetStatus(w, i + RTW_BUILD_NS);
    00573         if (_ctrl_pressed) RailToolbar_CtrlChanged(w);
    00574         break;
    00575       }
    00576     }
    00577     MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
    00578     break;
    00579
    00580   case WE_PLACE_OBJ:
    00581     _place_proc(e->we.place.tile);
    00582     return;
    00583
    00584   case WE_PLACE_DRAG: {
    00585     /* no dragging if you have pressed the convert button */
    00586     if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && w->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
    00587
    00588     VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
    00589     return;
    00590   }
    00591
    00592   case WE_PLACE_MOUSEUP:
    00593     if (e->we.place.pt.x != -1) {
    00594       TileIndex start_tile = e->we.place.starttile;
    00595       TileIndex end_tile = e->we.place.tile;
    00596
    00597       switch (e->we.place.select_proc) {
    00598         case DDSP_BUILD_BRIDGE:
    00599           ResetObjectToPlace();
    00600           ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype);
    00601           break;
    00602
    00603         case DDSP_PLACE_AUTORAIL:
    00604           HandleAutodirPlacement();
    00605           break;
    00606
    00607         case DDSP_BUILD_SIGNALS:
    00608           HandleAutoSignalPlacement();
    00609           break;
    00610
    00611         case DDSP_DEMOLISH_AREA:
    00612           GUIPlaceProcDragXY(e);
    00613           break;
    00614
    00615         case DDSP_CONVERT_RAIL:
    00616           DoCommandP(end_tile, start_tile, _cur_railtype, CcPlaySound10, CMD_CONVERT_RAIL | CMD_MSG(STR_CANT_CONVERT_RAIL));
    00617           break;
    00618
    00619         case DDSP_REMOVE_STATION:
    00620         case DDSP_BUILD_STATION:
    00621           if (_remove_button_clicked) {
    00622             DoCommandP(end_tile, start_tile, 0, CcPlaySound1E, CMD_REMOVE_FROM_RAILROAD_STATION | CMD_MSG(STR_CANT_REMOVE_PART_OF_STATION));
    00623             break;
    00624           }
    00625           HandleStationPlacement(start_tile, end_tile);
    00626           break;
    00627
    00628         case DDSP_PLACE_RAIL_NE:
    00629         case DDSP_PLACE_RAIL_NW:
    00630           DoRailroadTrack(e->we.place.select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y);
    00631           break;
    00632       }
    00633     }
    00634     break;
    00635
    00636   case WE_ABORT_PLACE_OBJ:
    00637     w->RaiseButtons();
    00638     w->DisableWidget(RTW_REMOVE);
    00639     w->InvalidateWidget(RTW_REMOVE);
    00640
    00641     w = FindWindowById(WC_BUILD_SIGNAL, 0);
    00642     if (w != NULL) WP(w, def_d).close = true;
    00643     w = FindWindowById(WC_BUILD_STATION, 0);
    00644     if (w != NULL) WP(w, def_d).close = true;
    00645     w = FindWindowById(WC_BUILD_DEPOT, 0);
    00646     if (w != NULL) WP(w, def_d).close = true;
    00647     break;
    00648
    00649   case WE_PLACE_PRESIZE: {
    00650     TileIndex tile = e->we.place.tile;
    00651
    00652     DoCommand(tile, 0, 0, DC_AUTO, CMD_BUILD_TUNNEL);
    00653     VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
    00654   } break;
    00655
    00656   case WE_DESTROY:
    00657     if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
    00658     break;
    00659
    00660   case WE_CTRL_CHANGED:
    00661     /* do not toggle Remove button by Ctrl when placing station */
    00662     if (!w->IsWidgetLowered(RTW_BUILD_STATION) && RailToolbar_CtrlChanged(w)) e->we.ctrl.cont = false;
    00663     break;
    00664   }
    00665 }
    00666
    00668 static const Widget _build_rail_widgets[] = {
    00669 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},                   // RTW_CLOSEBOX
    00670 {    WWT_CAPTION,   RESIZE_NONE,     7,    11,   337,     0,    13, STR_100A_RAILROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},         // RTW_CAPTION
    00671 {  WWT_STICKYBOX,   RESIZE_NONE,     7,   338,   349,     0,    13, 0x0,                            STR_STICKY_BUTTON},                       // RTW_STICKY
    00672
    00673 {      WWT_PANEL,   RESIZE_NONE,     7,   110,   113,    14,    35, 0x0,                            STR_NULL},                                // RTW_SPACER
    00674
    00675 {     WWT_IMGBTN,   RESIZE_NONE,     7,    0,     21,    14,    35, SPR_IMG_RAIL_NS,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_NS
    00676 {     WWT_IMGBTN,   RESIZE_NONE,     7,    22,    43,    14,    35, SPR_IMG_RAIL_NE,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_X
    00677 {     WWT_IMGBTN,   RESIZE_NONE,     7,    44,    65,    14,    35, SPR_IMG_RAIL_EW,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_EW
    00678 {     WWT_IMGBTN,   RESIZE_NONE,     7,    66,    87,    14,    35, SPR_IMG_RAIL_NW,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_Y
    00679 {     WWT_IMGBTN,   RESIZE_NONE,     7,    88,   109,    14,    35, SPR_IMG_AUTORAIL,               STR_BUILD_AUTORAIL_TIP},                  // RTW_AUTORAIL
    00680
    00681 {     WWT_IMGBTN,   RESIZE_NONE,     7,   114,   135,    14,    35, SPR_IMG_DYNAMITE,               STR_018D_DEMOLISH_BUILDINGS_ETC},         // RTW_DEMOLISH
    00682 {     WWT_IMGBTN,   RESIZE_NONE,     7,   136,   157,    14,    35, SPR_IMG_DEPOT_RAIL,             STR_1019_BUILD_TRAIN_DEPOT_FOR_BUILDING}, // RTW_BUILD_DEPOT
    00683 {     WWT_IMGBTN,   RESIZE_NONE,     7,   158,   179,    14,    35, SPR_IMG_WAYPOINT,               STR_CONVERT_RAIL_TO_WAYPOINT_TIP},        // RTW_BUILD_WAYPOINT
    00684
    00685 {     WWT_IMGBTN,   RESIZE_NONE,     7,   180,   221,    14,    35, SPR_IMG_RAIL_STATION,           STR_101A_BUILD_RAILROAD_STATION},         // RTW_BUILD_STATION
    00686 {     WWT_IMGBTN,   RESIZE_NONE,     7,   222,   243,    14,    35, SPR_IMG_RAIL_SIGNALS,           STR_101B_BUILD_RAILROAD_SIGNALS},         // RTW_BUILD_SIGNALS
    00687 {     WWT_IMGBTN,   RESIZE_NONE,     7,   244,   285,    14,    35, SPR_IMG_BRIDGE,                 STR_101C_BUILD_RAILROAD_BRIDGE},          // RTW_BUILD_BRIDGE
    00688 {     WWT_IMGBTN,   RESIZE_NONE,     7,   286,   305,    14,    35, SPR_IMG_TUNNEL_RAIL,            STR_101D_BUILD_RAILROAD_TUNNEL},          // RTW_BUILD_TUNNEL
    00689 {     WWT_IMGBTN,   RESIZE_NONE,     7,   306,   327,    14,    35, SPR_IMG_REMOVE,                 STR_101E_TOGGLE_BUILD_REMOVE_FOR},        // RTW_REMOVE
    00690 {     WWT_IMGBTN,   RESIZE_NONE,     7,   328,   349,    14,    35, SPR_IMG_CONVERT_RAIL,           STR_CONVERT_RAIL_TIP},                    // RTW_CONVERT_RAIL
    00691
    00692 {   WIDGETS_END},
    00693 };
    00694
    00695 static const WindowDesc _build_rail_desc = {
    00696   WDP_ALIGN_TBR, 22, 350, 36, 350, 36,
    00697   WC_BUILD_TOOLBAR, WC_NONE,
    00698   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
    00699   _build_rail_widgets,
    00700   BuildRailToolbWndProc
    00701 };
    00702
    00703
    00708 static void SetupRailToolbar(RailType railtype, Window *w)
    00709 {
    00710   const RailtypeInfo *rti = GetRailTypeInfo(railtype);
    00711
    00712   assert(railtype < RAILTYPE_END);
    00713   w->widget[RTW_CAPTION].data = rti->strings.toolbar_caption;
    00714   w->widget[RTW_BUILD_NS].data = rti->gui_sprites.build_ns_rail;
    00715   w->widget[RTW_BUILD_X].data = rti->gui_sprites.build_x_rail;
    00716   w->widget[RTW_BUILD_EW].data = rti->gui_sprites.build_ew_rail;
    00717   w->widget[RTW_BUILD_Y].data = rti->gui_sprites.build_y_rail;
    00718   w->widget[RTW_AUTORAIL].data = rti->gui_sprites.auto_rail;
    00719   w->widget[RTW_BUILD_DEPOT].data = rti->gui_sprites.build_depot;
    00720   w->widget[RTW_CONVERT_RAIL].data = rti->gui_sprites.convert_rail;
    00721   w->widget[RTW_BUILD_TUNNEL].data = rti->gui_sprites.build_tunnel;
    00722 }
    00723
    00724 void ShowBuildRailToolbar(RailType railtype, int button)
    00725 {
    00726   Window *w;
    00727
    00728   if (!IsValidPlayer(_current_player)) return;
    00729   if (!ValParamRailtype(railtype)) return;
    00730
    00731   // don't recreate the window if we're clicking on a button and the window exists.
    00732   if (button < 0 || !(w = FindWindowById(WC_BUILD_TOOLBAR, 0)) || w->wndproc != BuildRailToolbWndProc) {
    00733     DeleteWindowById(WC_BUILD_TOOLBAR, 0);
    00734     _cur_railtype = railtype;
    00735     w = AllocateWindowDesc(&_build_rail_desc);
    00736     SetupRailToolbar(railtype, w);
    00737   }
    00738
    00739   _remove_button_clicked = false;
    00740   if (w != NULL && button >= RTW_CLOSEBOX) {
    00741     _build_railroad_button_proc[button](w);
    00742     UpdateRemoveWidgetStatus(w, button + RTW_BUILD_NS);
    00743   }
    00744   if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
    00745 }
    00746
    00748 enum BuildRailStationWidgets {
    00749   BRSW_CLOSEBOX = 0,
    00750   BRSW_CAPTION,
    00751   BRSW_BACKGROUND,
    00752
    00753   BRSW_PLATFORM_DIR_X,
    00754   BRSW_PLATFORM_DIR_Y,
    00755
    00756   BRSW_PLATFORM_NUM_BEGIN = BRSW_PLATFORM_DIR_Y,
    00757   BRSW_PLATFORM_NUM_1,
    00758   BRSW_PLATFORM_NUM_2,
    00759   BRSW_PLATFORM_NUM_3,
    00760   BRSW_PLATFORM_NUM_4,
    00761   BRSW_PLATFORM_NUM_5,
    00762   BRSW_PLATFORM_NUM_6,
    00763   BRSW_PLATFORM_NUM_7,
    00764
    00765   BRSW_PLATFORM_LEN_BEGIN = BRSW_PLATFORM_NUM_7,
    00766   BRSW_PLATFORM_LEN_1,
    00767   BRSW_PLATFORM_LEN_2,
    00768   BRSW_PLATFORM_LEN_3,
    00769   BRSW_PLATFORM_LEN_4,
    00770   BRSW_PLATFORM_LEN_5,
    00771   BRSW_PLATFORM_LEN_6,
    00772   BRSW_PLATFORM_LEN_7,
    00773
    00774   BRSW_PLATFORM_DRAG_N_DROP,
    00775
    00776   BRSW_HIGHLIGHT_OFF,
    00777   BRSW_HIGHLIGHT_ON,
    00778
    00779   BRSW_NEWST_DROPDOWN,
    00780   BRSW_NEWST_LIST,
    00781   BRSW_NEWST_SCROLL
    00782 };
    00783
    00784 /* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
    00785  * --pasky */
    00786
    00787 static void HandleStationPlacement(TileIndex start, TileIndex end)
    00788 {
    00789   uint sx = TileX(start);
    00790   uint sy = TileY(start);
    00791   uint ex = TileX(end);
    00792   uint ey = TileY(end);
    00793   uint w,h;
    00794
    00795   if (sx > ex) Swap(sx, ex);
    00796   if (sy > ey) Swap(sy, ey);
    00797   w = ex - sx + 1;
    00798   h = ey - sy + 1;
    00799   if (!_railstation.orientation) Swap(w, h);
    00800
    00801   DoCommandP(TileXY(sx, sy),
    00802       _railstation.orientation | (w << 8) | (h << 16) | (_ctrl_pressed << 24),
    00803       _cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
    00804       CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
    00805 }
    00806
    00807 /* Check if the currently selected station size is allowed */
    00808 static void CheckSelectedSize(Window *w, const StationSpec *statspec)
    00809 {
    00810   if (statspec == NULL || _railstation.dragdrop) return;
    00811
    00812   if (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
    00813     w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    00814     _railstation.numtracks = 1;
    00815     while (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
    00816       _railstation.numtracks++;
    00817     }
    00818     w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    00819   }
    00820
    00821   if (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
    00822     w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    00823     _railstation.platlength = 1;
    00824     while (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
    00825       _railstation.platlength++;
    00826     }
    00827     w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    00828   }
    00829 }
    00830
    00831 static DropDownList *BuildStationClassDropDown()
    00832 {
    00833   DropDownList *list = new DropDownList();
    00834
    00835   for (uint i = 0; i < GetNumStationClasses(); i++) {
    00836     if (i == STAT_CLASS_WAYP) continue;
    00837     list->push_back(new DropDownListStringItem(GetStationClassName((StationClassID)i), i, false));
    00838   }
    00839
    00840   return list;
    00841 }
    00842
    00843 static void StationBuildWndProc(Window *w, WindowEvent *e)
    00844 {
    00845   switch (e->event) {
    00846   case WE_CREATE:
    00847     w->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
    00848     if (_railstation.dragdrop) {
    00849       w->LowerWidget(BRSW_PLATFORM_DRAG_N_DROP);
    00850     } else {
    00851       w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    00852       w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    00853     }
    00854     w->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
    00855     w->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
    00856     break;
    00857
    00858   case WE_PAINT: {
    00859     bool newstations = _railstation.newstations;
    00860     DrawPixelInfo tmp_dpi, *old_dpi;
    00861     const StationSpec *statspec = newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    00862
    00863     if (WP(w, def_d).close) return;
    00864
    00865     if (_railstation.dragdrop) {
    00866       SetTileSelectSize(1, 1);
    00867     } else {
    00868       int x = _railstation.numtracks;
    00869       int y = _railstation.platlength;
    00870       if (_railstation.orientation == 0) Swap(x, y);
    00871       if (!_remove_button_clicked)
    00872         SetTileSelectSize(x, y);
    00873     }
    00874
    00875     int rad = (_patches.modified_catchment) ? CA_TRAIN : CA_UNMODIFIED;
    00876
    00877     if (_station_show_coverage)
    00878       SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
    00879
    00880     for (uint bits = 0; bits < 7; bits++) {
    00881       bool disable = bits >= _patches.station_spread;
    00882       if (statspec == NULL) {
    00883         w->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, disable);
    00884         w->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, disable);
    00885       } else {
    00886         w->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable);
    00887         w->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths,   bits) || disable);
    00888       }
    00889     }
    00890
    00891     SetDParam(0, GetStationClassName(_railstation.station_class));
    00892     DrawWindowWidgets(w);
    00893
    00894     int y_offset = newstations ? 90 : 0;
    00895
    00896     /* Set up a clipping area for the '/' station preview */
    00897     if (FillDrawPixelInfo(&tmp_dpi, 7, 26 + y_offset, 66, 48)) {
    00898       old_dpi = _cur_dpi;
    00899       _cur_dpi = &tmp_dpi;
    00900       if (!DrawStationTile(32, 16, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) {
    00901         StationPickerDrawSprite(32, 16, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2);
    00902       }
    00903       _cur_dpi = old_dpi;
    00904     }
    00905
    00906     /* Set up a clipping area for the '\' station preview */
    00907     if (FillDrawPixelInfo(&tmp_dpi, 75, 26 + y_offset, 66, 48)) {
    00908       old_dpi = _cur_dpi;
    00909       _cur_dpi = &tmp_dpi;
    00910       if (!DrawStationTile(32, 16, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) {
    00911         StationPickerDrawSprite(32, 16, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3);
    00912       }
    00913       _cur_dpi = old_dpi;
    00914     }
    00915
    00916     DrawStringCentered(74, 15 + y_offset, STR_3002_ORIENTATION, TC_FROMSTRING);
    00917     DrawStringCentered(74, 76 + y_offset, STR_3003_NUMBER_OF_TRACKS, TC_FROMSTRING);
    00918     DrawStringCentered(74, 101 + y_offset, STR_3004_PLATFORM_LENGTH, TC_FROMSTRING);
    00919     DrawStringCentered(74, 141 + y_offset, STR_3066_COVERAGE_AREA_HIGHLIGHT, TC_FROMSTRING);
    00920
    00921     int text_end = DrawStationCoverageAreaText(2, 166 + y_offset, SCT_ALL, rad) + 4;
    00922     if (text_end > w->widget[BRSW_BACKGROUND].bottom) {
    00923       SetWindowDirty(w);
    00924       ResizeWindowForWidget(w, BRSW_BACKGROUND, 0, text_end - w->widget[BRSW_BACKGROUND].bottom);
    00925       SetWindowDirty(w);
    00926     }
    00927
    00928     if (newstations) {
    00929       uint y = 35;
    00930
    00931       for (uint16 i = w->vscroll.pos; i < _railstation.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++) {
    00932         const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
    00933
    00934         if (statspec != NULL && statspec->name != 0) {
    00935           if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
    00936             GfxFillRect(8, y - 2, 127, y + 10, (1 << PALETTE_MODIFIER_GREYOUT));
    00937           }
    00938
    00939           DrawStringTruncated(9, y, statspec->name, i == _railstation.station_type ? TC_WHITE : TC_BLACK, 118);
    00940         } else {
    00941           DrawStringTruncated(9, y, STR_STAT_CLASS_DFLT, i == _railstation.station_type ? TC_WHITE : TC_BLACK, 118);
    00942         }
    00943
    00944         y += 14;
    00945       }
    00946     }
    00947   } break;
    00948
    00949   case WE_CLICK: {
    00950     switch (e->we.click.widget) {
    00951     case BRSW_PLATFORM_DIR_X:
    00952     case BRSW_PLATFORM_DIR_Y:
    00953       w->RaiseWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
    00954       _railstation.orientation = e->we.click.widget - BRSW_PLATFORM_DIR_X;
    00955       w->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
    00956       SndPlayFx(SND_15_BEEP);
    00957       SetWindowDirty(w);
    00958       break;
    00959
    00960     case BRSW_PLATFORM_NUM_1:
    00961     case BRSW_PLATFORM_NUM_2:
    00962     case BRSW_PLATFORM_NUM_3:
    00963     case BRSW_PLATFORM_NUM_4:
    00964     case BRSW_PLATFORM_NUM_5:
    00965     case BRSW_PLATFORM_NUM_6:
    00966     case BRSW_PLATFORM_NUM_7: {
    00967       w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    00968       w->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
    00969
    00970       _railstation.numtracks = e->we.click.widget - BRSW_PLATFORM_NUM_BEGIN;
    00971       _railstation.dragdrop = false;
    00972
    00973       const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    00974       if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
    00975         /* The previously selected number of platforms in invalid */
    00976         for (uint i = 0; i < 7; i++) {
    00977           if (!HasBit(statspec->disallowed_lengths, i)) {
    00978             w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    00979             _railstation.platlength = i + 1;
    00980             break;
    00981           }
    00982         }
    00983       }
    00984
    00985       w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    00986       w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    00987       SndPlayFx(SND_15_BEEP);
    00988       SetWindowDirty(w);
    00989       break;
    00990     }
    00991
    00992     case BRSW_PLATFORM_LEN_1:
    00993     case BRSW_PLATFORM_LEN_2:
    00994     case BRSW_PLATFORM_LEN_3:
    00995     case BRSW_PLATFORM_LEN_4:
    00996     case BRSW_PLATFORM_LEN_5:
    00997     case BRSW_PLATFORM_LEN_6:
    00998     case BRSW_PLATFORM_LEN_7: {
    00999       w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    01000       w->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
    01001
    01002       _railstation.platlength = e->we.click.widget - BRSW_PLATFORM_LEN_BEGIN;
    01003       _railstation.dragdrop = false;
    01004
    01005       const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    01006       if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
    01007         /* The previously selected number of tracks in invalid */
    01008         for (uint i = 0; i < 7; i++) {
    01009           if (!HasBit(statspec->disallowed_platforms, i)) {
    01010             w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01011             _railstation.numtracks = i + 1;
    01012             break;
    01013           }
    01014         }
    01015       }
    01016
    01017       w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01018       w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    01019       SndPlayFx(SND_15_BEEP);
    01020       SetWindowDirty(w);
    01021       break;
    01022     }
    01023
    01024     case BRSW_PLATFORM_DRAG_N_DROP: {
    01025       _railstation.dragdrop ^= true;
    01026       w->ToggleWidgetLoweredState(BRSW_PLATFORM_DRAG_N_DROP);
    01027
    01028       /* get the first allowed length/number of platforms */
    01029       const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    01030       if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
    01031         for (uint i = 0; i < 7; i++) {
    01032           if (!HasBit(statspec->disallowed_lengths, i)) {
    01033             w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
    01034             _railstation.platlength = i + 1;
    01035             break;
    01036           }
    01037         }
    01038       }
    01039       if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
    01040         for (uint i = 0; i < 7; i++) {
    01041           if (!HasBit(statspec->disallowed_platforms, i)) {
    01042             w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01043             _railstation.numtracks = i + 1;
    01044             break;
    01045           }
    01046         }
    01047       }
    01048
    01049       w->SetWidgetLoweredState(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN, !_railstation.dragdrop);
    01050       w->SetWidgetLoweredState(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN, !_railstation.dragdrop);
    01051       SndPlayFx(SND_15_BEEP);
    01052       SetWindowDirty(w);
    01053     } break;
    01054
    01055     case BRSW_HIGHLIGHT_OFF:
    01056     case BRSW_HIGHLIGHT_ON:
    01057       _station_show_coverage = (e->we.click.widget != BRSW_HIGHLIGHT_OFF);
    01058       w->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
    01059       w->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
    01060       SndPlayFx(SND_15_BEEP);
    01061       SetWindowDirty(w);
    01062       break;
    01063
    01064     case BRSW_NEWST_DROPDOWN:
    01065       ShowDropDownList(w, BuildStationClassDropDown(), _railstation.station_class, BRSW_NEWST_DROPDOWN);
    01066       break;
    01067
    01068     case BRSW_NEWST_LIST: {
    01069       const StationSpec *statspec;
    01070       int y = (e->we.click.pt.y - 32) / 14;
    01071
    01072       if (y >= w->vscroll.cap) return;
    01073       y += w->vscroll.pos;
    01074       if (y >= _railstation.station_count) return;
    01075
    01076       /* Check station availability callback */
    01077       statspec = GetCustomStationSpec(_railstation.station_class, y);
    01078       if (statspec != NULL &&
    01079         HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
    01080         GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
    01081
    01082       _railstation.station_type = y;
    01083
    01084       CheckSelectedSize(w, statspec);
    01085
    01086       SndPlayFx(SND_15_BEEP);
    01087       SetWindowDirty(w);
    01088       break;
    01089     }
    01090     }
    01091   } break;
    01092
    01093   case WE_DROPDOWN_SELECT:
    01094     if (_railstation.station_class != e->we.dropdown.index) {
    01095       _railstation.station_class = (StationClassID)e->we.dropdown.index;
    01096       _railstation.station_type  = 0;
    01097       _railstation.station_count = GetNumCustomStations(_railstation.station_class);
    01098
    01099       CheckSelectedSize(w, GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
    01100
    01101       w->vscroll.count = _railstation.station_count;
    01102       w->vscroll.pos   = _railstation.station_type;
    01103     }
    01104
    01105     SndPlayFx(SND_15_BEEP);
    01106     SetWindowDirty(w);
    01107     break;
    01108
    01109   case WE_MOUSELOOP:
    01110     if (WP(w, def_d).close) {
    01111       DeleteWindow(w);
    01112       return;
    01113     }
    01114     CheckRedrawStationCoverage(w);
    01115     break;
    01116
    01117   case WE_DESTROY:
    01118     if (!WP(w, def_d).close) ResetObjectToPlace();
    01119     break;
    01120   }
    01121 }
    01122
    01124 static const Widget _station_builder_widgets[] = {
    01125 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},               // BRSW_CLOSEBOX
    01126 {    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3000_RAIL_STATION_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},     // BRSW_CAPTION
    01127 {      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   199, 0x0,                             STR_NULL},                            // BRSW_BACKGROUND
    01128 {      WWT_PANEL,   RESIZE_NONE,    14,     7,    72,    26,    73, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},    // BRSW_PLATFORM_DIR_X
    01129 {      WWT_PANEL,   RESIZE_NONE,    14,    75,   140,    26,    73, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},    // BRSW_PLATFORM_DIR_Y
    01130
    01131 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,    87,    98, STR_00CB_1,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_1
    01132 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,    87,    98, STR_00CC_2,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_2
    01133 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,    87,    98, STR_00CD_3,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_3
    01134 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,    87,    98, STR_00CE_4,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_4
    01135 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,    87,    98, STR_00CF_5,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_5
    01136 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,    87,    98, STR_6,                           STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_6
    01137 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,    87,    98, STR_7,                           STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_7
    01138
    01139 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   112,   123, STR_00CB_1,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_1
    01140 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   112,   123, STR_00CC_2,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_2
    01141 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   112,   123, STR_00CD_3,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_3
    01142 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   112,   123, STR_00CE_4,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_4
    01143 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   112,   123, STR_00CF_5,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_5
    01144 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   112,   123, STR_6,                           STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_6
    01145 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   112,   123, STR_7,                           STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_7
    01146
    01147 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,   111,   126,   137, STR_DRAG_DROP,                   STR_STATION_DRAG_DROP},               // BRSW_PLATFORM_DRAG_N_DROP
    01148 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   152,   163, STR_02DB_OFF,                    STR_3065_DON_T_HIGHLIGHT_COVERAGE},   // BRSW_HIGHLIGHT_OFF
    01149 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   152,   163, STR_02DA_ON,                     STR_3064_HIGHLIGHT_COVERAGE_AREA},    // BRSW_HIGHLIGHT_ON
    01150 {   WIDGETS_END},
    01151 };
    01152
    01154 static const Widget _newstation_builder_widgets[] = {
    01155 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},               // BRSW_CLOSEBOX
    01156 {    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3000_RAIL_STATION_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},     // BRSW_CAPTION
    01157 {      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,   289, 0x0,                             STR_NULL},                            // BRSW_BACKGROUND
    01158 {      WWT_PANEL,   RESIZE_NONE,    14,     7,    72,   116,   163, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},    // BRSW_PLATFORM_DIR_X
    01159 {      WWT_PANEL,   RESIZE_NONE,    14,    75,   140,   116,   163, 0x0,                             STR_304E_SELECT_RAILROAD_STATION},    // BRSW_PLATFORM_DIR_Y
    01160
    01161 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   177,   188, STR_00CB_1,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_1
    01162 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   177,   188, STR_00CC_2,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_2
    01163 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   177,   188, STR_00CD_3,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_3
    01164 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   177,   188, STR_00CE_4,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_4
    01165 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   177,   188, STR_00CF_5,                      STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_5
    01166 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   177,   188, STR_6,                           STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_6
    01167 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   177,   188, STR_7,                           STR_304F_SELECT_NUMBER_OF_PLATFORMS}, // BRSW_PLATFORM_NUM_7
    01168
    01169 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    22,    36,   202,   213, STR_00CB_1,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_1
    01170 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,    51,   202,   213, STR_00CC_2,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_2
    01171 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    52,    66,   202,   213, STR_00CD_3,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_3
    01172 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    67,    81,   202,   213, STR_00CE_4,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_4
    01173 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    82,    96,   202,   213, STR_00CF_5,                      STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_5
    01174 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    97,   111,   202,   213, STR_6,                           STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_6
    01175 {    WWT_TEXTBTN,   RESIZE_NONE,    14,   112,   126,   202,   213, STR_7,                           STR_3050_SELECT_LENGTH_OF_RAILROAD},  // BRSW_PLATFORM_LEN_7
    01176
    01177 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    37,   111,   216,   227, STR_DRAG_DROP,                   STR_STATION_DRAG_DROP},               // BRSW_PLATFORM_DRAG_N_DROP
    01178 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,   242,   253, STR_02DB_OFF,                    STR_3065_DON_T_HIGHLIGHT_COVERAGE},   // BRSW_HIGHLIGHT_OFF
    01179 {    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,   242,   253, STR_02DA_ON,                     STR_3064_HIGHLIGHT_COVERAGE_AREA},    // BRSW_HIGHLIGHT_ON
    01180
    01181 /* newstations gui additions */
    01182 { WWT_DROPDOWNIN,   RESIZE_NONE,    14,     7,   140,    17,    28, STR_02BD,                        STR_SELECT_STATION_CLASS_TIP},        // BRSW_NEWST_DROPDOWN
    01183 {     WWT_MATRIX,   RESIZE_NONE,    14,     7,   128,    32,   102, 0x501,                           STR_SELECT_STATION_TYPE_TIP},         // BRSW_NEWST_LIST
    01184 {  WWT_SCROLLBAR,   RESIZE_NONE,    14,   129,   140,    32,   102, 0x0,                             STR_0190_SCROLL_BAR_SCROLLS_LIST},    // BRSW_NEWST_SCROLL
    01185 {   WIDGETS_END},
    01186 };
    01187
    01188 static const WindowDesc _station_builder_desc = {
    01189   WDP_AUTO, WDP_AUTO, 148, 200, 148, 200,
    01190   WC_BUILD_STATION, WC_BUILD_TOOLBAR,
    01191   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    01192   _station_builder_widgets,
    01193   StationBuildWndProc
    01194 };
    01195
    01196 static const WindowDesc _newstation_builder_desc = {
    01197   WDP_AUTO, WDP_AUTO, 148, 290, 148, 290,
    01198   WC_BUILD_STATION, WC_BUILD_TOOLBAR,
    01199   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    01200   _newstation_builder_widgets,
    01201   StationBuildWndProc
    01202 };
    01203
    01204 static void ShowStationBuilder()
    01205 {
    01206   Window *w;
    01207   if (GetNumStationClasses() <= 2 && GetNumCustomStations(STAT_CLASS_DFLT) == 1) {
    01208     w = AllocateWindowDesc(&_station_builder_desc);
    01209     _railstation.newstations = false;
    01210   } else {
    01211     w = AllocateWindowDesc(&_newstation_builder_desc);
    01212     _railstation.newstations = true;
    01213     _railstation.station_count = GetNumCustomStations(_railstation.station_class);
    01214
    01215     w->vscroll.count = _railstation.station_count;
    01216     w->vscroll.cap   = 5;
    01217     w->vscroll.pos   = Clamp(_railstation.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
    01218   }
    01219 }
    01220
    01222 enum BuildSignalWidgets {
    01223   BSW_CLOSEBOX = 0,
    01224   BSW_CAPTION,
    01225   BSW_SEMAPHORE_NORM,
    01226   BSW_SEMAPHORE_ENTRY,
    01227   BSW_SEMAPHORE_EXIT,
    01228   BSW_SEMAPHORE_COMBO,
    01229   BSW_ELECTRIC_NORM,
    01230   BSW_ELECTRIC_ENTRY,
    01231   BSW_ELECTRIC_EXIT,
    01232   BSW_ELECTRIC_COMBO,
    01233   BSW_CONVERT,
    01234   BSW_DRAG_SIGNALS_DENSITY,
    01235   BSW_DRAG_SIGNALS_DENSITY_DECREASE,
    01236   BSW_DRAG_SIGNALS_DENSITY_INCREASE,
    01237 };
    01238
    01249 static void DrawSignalSprite(const Window *w, byte widget_index, SpriteID image, int8 xrel, uint8 xsize)
    01250 {
    01251   DrawSprite(image + w->IsWidgetLowered(widget_index), PAL_NONE,
    01252       w->widget[widget_index].left + (w->widget[widget_index].right - w->widget[widget_index].left) / 2 - xrel - xsize / 2 +
    01253       w->IsWidgetLowered(widget_index), w->widget[widget_index].bottom - 3 + w->IsWidgetLowered(widget_index));
    01254 }
    01255
    01262 static void SignalBuildWndProc(Window *w, WindowEvent *e)
    01263 {
    01264   switch (e->event) {
    01265     case WE_PAINT:
    01266       w->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
    01267
    01268       w->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button);
    01269
    01270       w->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_DECREASE, _patches.drag_signals_density == 1);
    01271       w->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_INCREASE, _patches.drag_signals_density == 20);
    01272
    01273       DrawWindowWidgets(w);
    01274
    01275       /* The 'hardcoded' off sets are needed because they are reused sprites. */
    01276       DrawSignalSprite(w, BSW_SEMAPHORE_NORM,  SPR_IMG_SIGNAL_SEMAPHORE_NORM,   0, 12); // xsize of sprite + 1 ==  9
    01277       DrawSignalSprite(w, BSW_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, -1, 13); // xsize of sprite + 1 == 10
    01278       DrawSignalSprite(w, BSW_SEMAPHORE_EXIT,  SPR_IMG_SIGNAL_SEMAPHORE_EXIT,   0, 12); // xsize of sprite + 1 ==  9
    01279       DrawSignalSprite(w, BSW_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_COMBO,  0, 12); // xsize of sprite + 1 ==  9
    01280       DrawSignalSprite(w, BSW_ELECTRIC_NORM,   SPR_IMG_SIGNAL_ELECTRIC_NORM,   -1,  4);
    01281       DrawSignalSprite(w, BSW_ELECTRIC_ENTRY,  SPR_IMG_SIGNAL_ELECTRIC_ENTRY,  -2,  6);
    01282       DrawSignalSprite(w, BSW_ELECTRIC_EXIT,   SPR_IMG_SIGNAL_ELECTRIC_EXIT,   -2,  6);
    01283       DrawSignalSprite(w, BSW_ELECTRIC_COMBO,  SPR_IMG_SIGNAL_ELECTRIC_COMBO,  -2,  6);
    01284
    01285       /* Draw dragging signal density value in the BSW_DRAG_SIGNALS_DENSITY widget */
    01286       SetDParam(0, _patches.drag_signals_density);
    01287       DrawStringCentered(w->widget[BSW_DRAG_SIGNALS_DENSITY].left + (w->widget[BSW_DRAG_SIGNALS_DENSITY].right -
    01288           w->widget[BSW_DRAG_SIGNALS_DENSITY].left) / 2 + 1,
    01289           w->widget[BSW_DRAG_SIGNALS_DENSITY].top + 2, STR_JUST_INT, TC_ORANGE);
    01290       break;
    01291
    01292     case WE_CLICK:
    01293       switch (e->we.click.widget) {
    01294         case BSW_SEMAPHORE_NORM:
    01295         case BSW_SEMAPHORE_ENTRY:
    01296         case BSW_SEMAPHORE_EXIT:
    01297         case BSW_SEMAPHORE_COMBO:
    01298         case BSW_ELECTRIC_NORM:
    01299         case BSW_ELECTRIC_ENTRY:
    01300         case BSW_ELECTRIC_EXIT:
    01301         case BSW_ELECTRIC_COMBO:
    01302           w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
    01303
    01304           _cur_signal_type = (SignalType)((uint)((e->we.click.widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_COMBO + 1)));
    01305           _cur_signal_variant = e->we.click.widget >= BSW_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE;
    01306           break;
    01307
    01308         case BSW_CONVERT:
    01309           _convert_signal_button = !_convert_signal_button;
    01310           break;
    01311
    01312         case BSW_DRAG_SIGNALS_DENSITY_DECREASE:
    01313           if (_patches.drag_signals_density > 1) {
    01314             _patches.drag_signals_density--;
    01315             const Window *w = FindWindowById(WC_GAME_OPTIONS, 0);
    01316             if (w != NULL) SetWindowDirty(w);
    01317           }
    01318           break;
    01319
    01320         case BSW_DRAG_SIGNALS_DENSITY_INCREASE:
    01321           if (_patches.drag_signals_density < 20) {
    01322             _patches.drag_signals_density++;
    01323             const Window *w = FindWindowById(WC_GAME_OPTIONS, 0);
    01324             if (w != NULL) SetWindowDirty(w);
    01325           }
    01326           break;
    01327
    01328         default: break;
    01329       }
    01330
    01331       SetWindowDirty(w);
    01332       break;
    01333
    01334     case WE_MOUSELOOP:
    01335       if (WP(w, def_d).close) DeleteWindow(w);
    01336       return;
    01337
    01338     case WE_DESTROY:
    01339       if (!WP(w, def_d).close) ResetObjectToPlace();
    01340       break;
    01341     }
    01342 }
    01343
    01345 static const Widget _signal_builder_widgets[] = {
    01346 {   WWT_CLOSEBOX,   RESIZE_NONE,  7,   0,  10,   0,  13, STR_00C5,               STR_018B_CLOSE_WINDOW},                 // BSW_CLOSEBOX
    01347 {    WWT_CAPTION,   RESIZE_NONE,  7,  11, 109,   0,  13, STR_SIGNAL_SELECTION,   STR_018C_WINDOW_TITLE_DRAG_THIS},       // BSW_CAPTION
    01348
    01349 {      WWT_PANEL,   RESIZE_NONE,  7,   0,  21,  14,  40, STR_NULL,               STR_BUILD_SIGNAL_SEMAPHORE_NORM_TIP},   // BSW_SEMAPHORE_NORM
    01350 {      WWT_PANEL,   RESIZE_NONE,  7,  22,  43,  14,  40, STR_NULL,               STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TIP},  // BSW_SEMAPHORE_ENTRY
    01351 {      WWT_PANEL,   RESIZE_NONE,  7,  44,  65,  14,  40, STR_NULL,               STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TIP},   // BSW_SEMAPHORE_EXIT
    01352 {      WWT_PANEL,   RESIZE_NONE,  7,  66,  87,  14,  40, STR_NULL,               STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TIP},  // BSW_SEMAPHORE_COMBO
    01353
    01354 {      WWT_PANEL,   RESIZE_NONE,  7,   0,  21,  41,  67, STR_NULL,               STR_BUILD_SIGNAL_ELECTRIC_NORM_TIP},    // BSW_ELECTRIC_NORM
    01355 {      WWT_PANEL,   RESIZE_NONE,  7,  22,  43,  41,  67, STR_NULL,               STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TIP},   // BSW_ELECTRIC_ENTRY
    01356 {      WWT_PANEL,   RESIZE_NONE,  7,  44,  65,  41,  67, STR_NULL,               STR_BUILD_SIGNAL_ELECTRIC_EXIT_TIP},    // BSW_ELECTRIC_EXIT
    01357 {      WWT_PANEL,   RESIZE_NONE,  7,  66,  87,  41,  67, STR_NULL,               STR_BUILD_SIGNAL_ELECTRIC_COMBO_TIP},   // BSW_ELECTRIC_COMBO
    01358
    01359 {     WWT_IMGBTN,   RESIZE_NONE,  7,  88, 109,  14,  40, SPR_IMG_SIGNAL_CONVERT, STR_SIGNAL_CONVERT_TIP},                // BSW_CONVERT
    01360 {      WWT_PANEL,   RESIZE_NONE,  7,  88, 109,  41,  67, STR_NULL,               STR_DRAG_SIGNALS_DENSITY_TIP},          // BSW_DRAG_SIGNALS_DENSITY
    01361 { WWT_PUSHIMGBTN,   RESIZE_NONE, 14,  90,  98,  54,  65, SPR_ARROW_LEFT,         STR_DRAG_SIGNALS_DENSITY_DECREASE_TIP}, // BSW_DRAG_SIGNALS_DENSITY_DECREASE
    01362 { WWT_PUSHIMGBTN,   RESIZE_NONE, 14,  99, 107,  54,  65, SPR_ARROW_RIGHT,        STR_DRAG_SIGNALS_DENSITY_INCREASE_TIP}, // BSW_DRAG_SIGNALS_DENSITY_INCREASE
    01363
    01364 {   WIDGETS_END},
    01365 };
    01366
    01368 static const WindowDesc _signal_builder_desc = {
    01369   WDP_AUTO, WDP_AUTO, 110, 68, 110, 68,
    01370   WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR,
    01371   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    01372   _signal_builder_widgets,
    01373   SignalBuildWndProc
    01374 };
    01375
    01380 static void ShowSignalBuilder()
    01381 {
    01382   _convert_signal_button = false;
    01383   _cur_signal_variant = _cur_year < _patches.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC;
    01384   _cur_signal_type = SIGTYPE_NORMAL;
    01385
    01386   AllocateWindowDesc(&_signal_builder_desc);
    01387 }
    01388
    01390 enum BuildRailDepotWidgets {
    01391   BRDW_CLOSEBOX = 0,
    01392   BRDW_CAPTION,
    01393   BRDW_BACKGROUND,
    01394   BRDW_DEPOT_NE,
    01395   BRDW_DEPOT_SE,
    01396   BRDW_DEPOT_SW,
    01397   BRDW_DEPOT_NW,
    01398 };
    01399
    01400 static void BuildTrainDepotWndProc(Window *w, WindowEvent *e)
    01401 {
    01402   switch (e->event) {
    01403   case WE_CREATE: w->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE); break;
    01404
    01405   case WE_PAINT: {
    01406     DrawWindowWidgets(w);
    01407
    01408     DrawTrainDepotSprite(70, 17, DIAGDIR_NE, _cur_railtype);
    01409     DrawTrainDepotSprite(70, 69, DIAGDIR_SE, _cur_railtype);
    01410     DrawTrainDepotSprite( 2, 69, DIAGDIR_SW, _cur_railtype);
    01411     DrawTrainDepotSprite( 2, 17, DIAGDIR_NW, _cur_railtype);
    01412     break;
    01413     }
    01414
    01415   case WE_CLICK:
    01416     switch (e->we.click.widget) {
    01417       case BRDW_DEPOT_NE:
    01418       case BRDW_DEPOT_SE:
    01419       case BRDW_DEPOT_SW:
    01420       case BRDW_DEPOT_NW:
    01421         w->RaiseWidget(_build_depot_direction + BRDW_DEPOT_NE);
    01422         _build_depot_direction = (DiagDirection)(e->we.click.widget - BRDW_DEPOT_NE);
    01423         w->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
    01424         SndPlayFx(SND_15_BEEP);
    01425         SetWindowDirty(w);
    01426         break;
    01427     }
    01428     break;
    01429
    01430   case WE_MOUSELOOP:
    01431     if (WP(w, def_d).close) DeleteWindow(w);
    01432     return;
    01433
    01434   case WE_DESTROY:
    01435     if (!WP(w, def_d).close) ResetObjectToPlace();
    01436     break;
    01437   }
    01438 }
    01439
    01441 static const Widget _build_depot_widgets[] = {
    01442 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},                     // BRDW_CLOSEBOX
    01443 {    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_1014_TRAIN_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},           // BRDW_CAPTION
    01444 {      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   121, 0x0,                              STR_NULL},                                  // BRDW_BACKGROUND
    01445 {      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO}, // BRDW_DEPOT_NE
    01446 {      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO}, // BRDW_DEPOT_SE
    01447 {      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO}, // BRDW_DEPOT_SW
    01448 {      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                              STR_1020_SELECT_RAILROAD_DEPOT_ORIENTATIO}, // BRDW_DEPOT_NW
    01449 {   WIDGETS_END},
    01450 };
    01451
    01452 static const WindowDesc _build_depot_desc = {
    01453   WDP_AUTO, WDP_AUTO, 140, 122, 140, 122,
    01454   WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
    01455   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    01456   _build_depot_widgets,
    01457   BuildTrainDepotWndProc
    01458 };
    01459
    01460 static void ShowBuildTrainDepotPicker()
    01461 {
    01462   AllocateWindowDesc(&_build_depot_desc);
    01463 }
    01464
    01466 enum BuildRailWaypointWidgets {
    01467   BRWW_CLOSEBOX = 0,
    01468   BRWW_CAPTION,
    01469   BRWW_BACKGROUND,
    01470   BRWW_WAYPOINT_1,
    01471   BRWW_WAYPOINT_2,
    01472   BRWW_WAYPOINT_3,
    01473   BRWW_WAYPOINT_4,
    01474   BRWW_WAYPOINT_5,
    01475   BRWW_SCROLL,
    01476 };
    01477
    01478 static void BuildWaypointWndProc(Window *w, WindowEvent *e)
    01479 {
    01480   switch (e->event) {
    01481   case WE_PAINT: {
    01482     uint i;
    01483
    01484     for (i = 0; i < w->hscroll.cap; i++) {
    01485       w->SetWidgetLoweredState(i + BRWW_WAYPOINT_1, (w->hscroll.pos + i) == _cur_waypoint_type);
    01486     }
    01487
    01488     DrawWindowWidgets(w);
    01489
    01490     for (i = 0; i < w->hscroll.cap; i++) {
    01491       if (w->hscroll.pos + i < w->hscroll.count) {
    01492         const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, w->hscroll.pos + i);
    01493
    01494         DrawWaypointSprite(2 + i * 68, 25, w->hscroll.pos + i, _cur_railtype);
    01495
    01496         if (statspec != NULL &&
    01497             HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
    01498             GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
    01499           GfxFillRect(4 + i * 68, 18, 67 + i * 68, 75, (1 << PALETTE_MODIFIER_GREYOUT));
    01500         }
    01501       }
    01502     }
    01503     break;
    01504   }
    01505   case WE_CLICK: {
    01506     switch (e->we.click.widget) {
    01507       case BRWW_WAYPOINT_1:
    01508       case BRWW_WAYPOINT_2:
    01509       case BRWW_WAYPOINT_3:
    01510       case BRWW_WAYPOINT_4:
    01511       case BRWW_WAYPOINT_5: {
    01512         byte type = e->we.click.widget - BRWW_WAYPOINT_1 + w->hscroll.pos;
    01513
    01514         /* Check station availability callback */
    01515         const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
    01516         if (statspec != NULL &&
    01517             HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
    01518             GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
    01519
    01520         _cur_waypoint_type = type;
    01521         SndPlayFx(SND_15_BEEP);
    01522         SetWindowDirty(w);
    01523         break;
    01524       }
    01525     }
    01526     break;
    01527   }
    01528
    01529   case WE_MOUSELOOP:
    01530     if (WP(w, def_d).close) DeleteWindow(w);
    01531     break;
    01532
    01533   case WE_DESTROY:
    01534     if (!WP(w, def_d).close) ResetObjectToPlace();
    01535     break;
    01536   }
    01537 }
    01538
    01540 static const Widget _build_waypoint_widgets[] = {
    01541 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,     STR_018B_CLOSE_WINDOW},            // BRWW_CLOSEBOX
    01542 {    WWT_CAPTION,   RESIZE_NONE,     7,    11,   343,     0,    13, STR_WAYPOINT, STR_018C_WINDOW_TITLE_DRAG_THIS},  // BRWW_CAPTION
    01543 {      WWT_PANEL,   RESIZE_NONE,     7,     0,   343,    14,    91, 0x0,          STR_NULL},                         // BRWW_BACKGROUND
    01544
    01545 {      WWT_PANEL,   RESIZE_NONE,     7,     3,    68,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},        // BRWW_WAYPOINT_1
    01546 {      WWT_PANEL,   RESIZE_NONE,     7,    71,   136,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},        // BRWW_WAYPOINT_2
    01547 {      WWT_PANEL,   RESIZE_NONE,     7,   139,   204,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},        // BRWW_WAYPOINT_3
    01548 {      WWT_PANEL,   RESIZE_NONE,     7,   207,   272,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},        // BRWW_WAYPOINT_4
    01549 {      WWT_PANEL,   RESIZE_NONE,     7,   275,   340,    17,    76, 0x0,          STR_WAYPOINT_GRAPHICS_TIP},        // BRWW_WAYPOINT_5
    01550
    01551 { WWT_HSCROLLBAR,   RESIZE_NONE,    7,     1,   343,     80,    91, 0x0,          STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BRWW_SCROLL
    01552 {    WIDGETS_END},
    01553 };
    01554
    01555 static const WindowDesc _build_waypoint_desc = {
    01556   WDP_AUTO, WDP_AUTO, 344, 92, 344, 92,
    01557   WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
    01558   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    01559   _build_waypoint_widgets,
    01560   BuildWaypointWndProc
    01561 };
    01562
    01563 static void ShowBuildWaypointPicker()
    01564 {
    01565   Window *w = AllocateWindowDesc(&_build_waypoint_desc);
    01566   w->hscroll.cap = 5;
    01567   w->hscroll.count = _waypoint_count;
    01568 }
    01569
    01570
    01571 void InitializeRailGui()
    01572 {
    01573   _build_depot_direction = DIAGDIR_NW;
    01574   _railstation.numtracks = 1;
    01575   _railstation.platlength = 1;
    01576   _railstation.dragdrop = true;
    01577 }
    01578
    01579 void ReinitGuiAfterToggleElrail(bool disable)
    01580 {
    01581   extern RailType _last_built_railtype;
    01582   if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) {
    01583     Window *w;
    01584     _last_built_railtype = _cur_railtype = RAILTYPE_RAIL;
    01585     w = FindWindowById(WC_BUILD_TOOLBAR, 0);
    01586     if (w != NULL && w->wndproc == BuildRailToolbWndProc) {
    01587       SetupRailToolbar(_cur_railtype, w);
    01588       SetWindowDirty(w);
    01589     }
    01590   }
    01591   MarkWholeScreenDirty();
    01592 }
    01593
    01594 void SetDefaultRailGui()
    01595 {
    01596   if (_local_player == PLAYER_SPECTATOR || !IsValidPlayer(_local_player)) return;
    01597
    01598   extern RailType _last_built_railtype;
    01599   RailType rt = (RailType)_patches.default_rail_type;
    01600   if (rt >= RAILTYPE_END) {
    01601     if (rt == RAILTYPE_END + 2) {
    01602       /* Find the most used rail type */
    01603       RailType count[RAILTYPE_END];
    01604       memset(count, 0, sizeof(count));
    01605       for (TileIndex t = 0; t < MapSize(); t++) {
    01606         if (IsTileType(t, MP_RAILWAY) || IsLevelCrossingTile(t) || IsRailwayStationTile(t) ||
    01607             (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL)) {
    01608           count[GetRailType(t)]++;
    01609         }
    01610       }
    01611
    01612       rt = RAILTYPE_RAIL;
    01613       for (RailType r = RAILTYPE_ELECTRIC; r < RAILTYPE_END; r++) {
    01614         if (count[r] >= count[rt]) rt = r;
    01615       }
    01616
    01617       /* No rail, just get the first available one */
    01618       if (count[rt] == 0) rt = RAILTYPE_END;
    01619     }
    01620     switch (rt) {
    01621       case RAILTYPE_END + 0:
    01622         rt = RAILTYPE_RAIL;
    01623         while (rt < RAILTYPE_END && !HasRailtypeAvail(_local_player, rt)) rt++;
    01624         break;
    01625
    01626       case RAILTYPE_END + 1:
    01627         rt = GetBestRailtype(_local_player);
    01628         break;
    01629
    01630       default:
    01631         break;
    01632     }
    01633   }
    01634
    01635   _last_built_railtype = _cur_railtype = rt;
    01636   Window *w = FindWindowById(WC_BUILD_TOOLBAR, 0);
    01637   if (w != NULL && w->wndproc == BuildRailToolbWndProc) {
    01638     SetupRailToolbar(_cur_railtype, w);
    01639     SetWindowDirty(w);
    01640   }
    01641 }
    01642
    01643
    01644