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 

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