rail_gui.cpp

Go to the documentation of this file.
00001 /* $Id: rail_gui.cpp 14422 2008-09-30 20:51:04Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "direction_type.h"
00007 #include "openttd.h"
00008 #include "tile_cmd.h"
00009 #include "landscape.h"
00010 #include "gui.h"
00011 #include "window_gui.h"
00012 #include "station_gui.h"
00013 #include "terraform_gui.h"
00014 #include "viewport_func.h"
00015 #include "gfx_func.h"
00016 #include "command_func.h"
00017 #include "town_type.h"
00018 #include "waypoint.h"
00019 #include "debug.h"
00020 #include "variables.h"
00021 #include "newgrf_callbacks.h"
00022 #include "newgrf_station.h"
00023 #include "train.h"
00024 #include "strings_func.h"
00025 #include "functions.h"
00026 #include "window_func.h"
00027 #include "date_func.h"
00028 #include "sound_func.h"
00029 #include "company_func.h"
00030 #include "settings_type.h"
00031 #include "widgets/dropdown_type.h"
00032 #include "widgets/dropdown_func.h"
00033 #include "tunnelbridge.h"
00034 #include "tilehighlight_func.h"
00035 
00036 #include "bridge_map.h"
00037 #include "rail_map.h"
00038 #include "road_map.h"
00039 #include "station_map.h"
00040 #include "tunnel_map.h"
00041 #include "tunnelbridge_map.h"
00042 
00043 #include "table/sprites.h"
00044 #include "table/strings.h"
00045 
00046 static RailType _cur_railtype;               
00047 static bool _remove_button_clicked;          
00048 static DiagDirection _build_depot_direction; 
00049 static byte _waypoint_count = 1;             
00050 static byte _cur_waypoint_type;              
00051 static bool _convert_signal_button;          
00052 static SignalVariant _cur_signal_variant;    
00053 static SignalType _cur_signal_type;          
00054 
00055 /* Map _patches.default_signal_type to the corresponding signal type */
00056 static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY};
00057 
00058 struct RailStationGUISettings {
00059   Axis orientation;                 
00060   byte numtracks;                   
00061   byte platlength;                  
00062   bool dragdrop;                    
00063 
00064   bool newstations;                 
00065   StationClassIDByte station_class; 
00066   byte station_type;                
00067   byte station_count;               
00068 };
00069 static RailStationGUISettings _railstation; 
00070 
00071 
00072 static void HandleStationPlacement(TileIndex start, TileIndex end);
00073 static void ShowBuildTrainDepotPicker(Window *parent);
00074 static void ShowBuildWaypointPicker(Window *parent);
00075 static void ShowStationBuilder(Window *parent);
00076 static void ShowSignalBuilder(Window *parent);
00077 
00078 void CcPlaySound1E(bool success, TileIndex tile, uint32 p1, uint32 p2)
00079 {
00080   if (success) SndPlayTileFx(SND_20_SPLAT_2, tile);
00081 }
00082 
00083 static void GenericPlaceRail(TileIndex tile, int cmd)
00084 {
00085   DoCommandP(tile, _cur_railtype, cmd, CcPlaySound1E,
00086     _remove_button_clicked ?
00087     CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) | CMD_NO_WATER :
00088     CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) | CMD_NO_WATER
00089   );
00090 }
00091 
00092 static void PlaceRail_N(TileIndex tile)
00093 {
00094   int cmd = _tile_fract_coords.x > _tile_fract_coords.y ? 4 : 5;
00095   GenericPlaceRail(tile, cmd);
00096 }
00097 
00098 static void PlaceRail_NE(TileIndex tile)
00099 {
00100   VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_RAIL_NE);
00101 }
00102 
00103 static void PlaceRail_E(TileIndex tile)
00104 {
00105   int cmd = _tile_fract_coords.x + _tile_fract_coords.y <= 15 ? 2 : 3;
00106   GenericPlaceRail(tile, cmd);
00107 }
00108 
00109 static void PlaceRail_NW(TileIndex tile)
00110 {
00111   VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_RAIL_NW);
00112 }
00113 
00114 static void PlaceRail_AutoRail(TileIndex tile)
00115 {
00116   VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_AUTORAIL);
00117 }
00118 
00125 static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
00126 {
00127   if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
00128   if ((GetTrackBits(tile) & GB(extra, 8, 8)) == 0) return;
00129 
00130   DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_NO_WATER);
00131 }
00132 
00134 static const uint16 _place_depot_extra[12] = {
00135   0x0604, 0x2102, 0x1202, 0x0505,  // First additional track for directions 0..3
00136   0x2400, 0x2801, 0x1800, 0x1401,  // Second additional track
00137   0x2203, 0x0904, 0x0A05, 0x1103,  // Third additional track
00138 };
00139 
00140 
00141 void CcRailDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
00142 {
00143   if (success) {
00144     DiagDirection dir = (DiagDirection)p2;
00145 
00146     SndPlayTileFx(SND_20_SPLAT_2, tile);
00147     ResetObjectToPlace();
00148 
00149     tile += TileOffsByDiagDir(dir);
00150 
00151     if (IsTileType(tile, MP_RAILWAY)) {
00152       PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
00153       PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
00154       PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
00155     }
00156   }
00157 }
00158 
00159 static void PlaceRail_Depot(TileIndex tile)
00160 {
00161   DoCommandP(tile, _cur_railtype, _build_depot_direction, CcRailDepot,
00162     CMD_BUILD_TRAIN_DEPOT | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT));
00163 }
00164 
00165 static void PlaceRail_Waypoint(TileIndex tile)
00166 {
00167   if (_remove_button_clicked) {
00168     DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT));
00169   } else {
00170     DoCommandP(tile, _cur_waypoint_type, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT));
00171   }
00172 }
00173 
00174 void CcStation(bool success, TileIndex tile, uint32 p1, uint32 p2)
00175 {
00176   if (success) {
00177     SndPlayTileFx(SND_20_SPLAT_2, tile);
00178     /* Only close the station builder window if the default station is chosen. */
00179     if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0) ResetObjectToPlace();
00180   }
00181 }
00182 
00183 static void PlaceRail_Station(TileIndex tile)
00184 {
00185   if (_remove_button_clicked) {
00186     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
00187     VpSetPlaceSizingLimit(-1);
00188   } else if (_railstation.dragdrop) {
00189     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
00190     VpSetPlaceSizingLimit(_settings_game.station.station_spread);
00191   } else {
00192     DoCommandP(tile,
00193         _railstation.orientation | (_railstation.numtracks << 8) | (_railstation.platlength << 16) | (_ctrl_pressed << 24),
00194         _cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
00195         CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
00196   }
00197 }
00198 
00204 static void GenericPlaceSignals(TileIndex tile)
00205 {
00206   TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
00207 
00208   if (trackbits & TRACK_BIT_VERT) { // N-S direction
00209     trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
00210   }
00211 
00212   if (trackbits & TRACK_BIT_HORZ) { // E-W direction
00213     trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
00214   }
00215 
00216   Track track = FindFirstTrack(trackbits);
00217 
00218   if (_remove_button_clicked) {
00219     DoCommandP(tile, track, 0, CcPlaySound1E,
00220       CMD_REMOVE_SIGNALS | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM));
00221   } else {
00222     const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
00223 
00224     /* Map _patches.cycle_signal_types to the lower and upper allowed signal type. */
00225     static const uint cycle_bounds[] = {SIGTYPE_NORMAL | (SIGTYPE_LAST_NOPBS << 3), SIGTYPE_PBS | (SIGTYPE_LAST << 3), SIGTYPE_NORMAL | (SIGTYPE_LAST << 3)};
00226 
00227     /* various bitstuffed elements for CmdBuildSingleSignal() */
00228     uint32 p1 = track;
00229 
00230     if (w != NULL) {
00231       /* signal GUI is used */
00232       SB(p1, 3, 1, _ctrl_pressed);
00233       SB(p1, 4, 1, _cur_signal_variant);
00234       SB(p1, 5, 3, _cur_signal_type);
00235       SB(p1, 8, 1, _convert_signal_button);
00236       SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
00237     } else {
00238       SB(p1, 3, 1, _ctrl_pressed);
00239       SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
00240       SB(p1, 5, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
00241       SB(p1, 8, 1, 0);
00242       SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
00243     }
00244 
00245     DoCommandP(tile, p1, 0, CcPlaySound1E, CMD_BUILD_SIGNALS |
00246       CMD_MSG((w != NULL && _convert_signal_button) ? STR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_1010_CAN_T_BUILD_SIGNALS_HERE));
00247   }
00248 }
00249 
00250 static void PlaceRail_Bridge(TileIndex tile)
00251 {
00252   VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
00253 }
00254 
00256 void CcBuildRailTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
00257 {
00258   if (success) {
00259     SndPlayTileFx(SND_20_SPLAT_2, tile);
00260     ResetObjectToPlace();
00261   } else {
00262     SetRedErrorSquare(_build_tunnel_endtile);
00263   }
00264 }
00265 
00266 static void PlaceRail_Tunnel(TileIndex tile)
00267 {
00268   DoCommandP(tile, _cur_railtype, 0, CcBuildRailTunnel,
00269     CMD_BUILD_TUNNEL | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE));
00270 }
00271 
00272 static void PlaceRail_ConvertRail(TileIndex tile)
00273 {
00274   VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
00275 }
00276 
00277 static void PlaceRail_AutoSignals(TileIndex tile)
00278 {
00279   VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
00280 }
00281 
00282 
00284 enum RailToolbarWidgets {
00285   RTW_CLOSEBOX = 0,
00286   RTW_CAPTION,
00287   RTW_STICKY,
00288   RTW_SPACER,
00289   RTW_BUILD_NS,
00290   RTW_BUILD_X,
00291   RTW_BUILD_EW,
00292   RTW_BUILD_Y,
00293   RTW_AUTORAIL,
00294   RTW_DEMOLISH,
00295   RTW_BUILD_DEPOT,
00296   RTW_BUILD_WAYPOINT,
00297   RTW_BUILD_STATION,
00298   RTW_BUILD_SIGNALS,
00299   RTW_BUILD_BRIDGE,
00300   RTW_BUILD_TUNNEL,
00301   RTW_REMOVE,
00302   RTW_CONVERT_RAIL,
00303 };
00304 
00305 
00309 static void ToggleRailButton_Remove(Window *w)
00310 {
00311   w->ToggleWidgetLoweredState(RTW_REMOVE);
00312   w->InvalidateWidget(RTW_REMOVE);
00313   _remove_button_clicked = w->IsWidgetLowered(RTW_REMOVE);
00314   SetSelectionRed(_remove_button_clicked);
00315 }
00316 
00321 static bool RailToolbar_CtrlChanged(Window *w)
00322 {
00323   if (w->IsWidgetDisabled(RTW_REMOVE)) return false;
00324 
00325   /* allow ctrl to switch remove mode only for these widgets */
00326   for (uint i = RTW_BUILD_NS; i <= RTW_BUILD_STATION; i++) {
00327     if ((i <= RTW_AUTORAIL || i >= RTW_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) {
00328       ToggleRailButton_Remove(w);
00329       return true;
00330     }
00331   }
00332 
00333   return false;
00334 }
00335 
00336 
00342 static void BuildRailClick_N(Window *w)
00343 {
00344   HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, VHM_RECT, PlaceRail_N);
00345 }
00346 
00352 static void BuildRailClick_NE(Window *w)
00353 {
00354   HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, VHM_RECT, PlaceRail_NE);
00355 }
00356 
00362 static void BuildRailClick_E(Window *w)
00363 {
00364   HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, VHM_RECT, PlaceRail_E);
00365 }
00366 
00372 static void BuildRailClick_NW(Window *w)
00373 {
00374   HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, VHM_RECT, PlaceRail_NW);
00375 }
00376 
00382 static void BuildRailClick_AutoRail(Window *w)
00383 {
00384   HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, VHM_RAIL, PlaceRail_AutoRail);
00385 }
00386 
00392 static void BuildRailClick_Demolish(Window *w)
00393 {
00394   HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, VHM_RECT, PlaceProc_DemolishArea);
00395 }
00396 
00402 static void BuildRailClick_Depot(Window *w)
00403 {
00404   if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, VHM_RECT, PlaceRail_Depot)) {
00405     ShowBuildTrainDepotPicker(w);
00406   }
00407 }
00408 
00415 static void BuildRailClick_Waypoint(Window *w)
00416 {
00417   _waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
00418   if (HandlePlacePushButton(w, RTW_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, VHM_RECT, PlaceRail_Waypoint) &&
00419       _waypoint_count > 1) {
00420     ShowBuildWaypointPicker(w);
00421   }
00422 }
00423 
00429 static void BuildRailClick_Station(Window *w)
00430 {
00431   if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, VHM_RECT, PlaceRail_Station)) ShowStationBuilder(w);
00432 }
00433 
00440 static void BuildRailClick_AutoSignals(Window *w)
00441 {
00442   if (_settings_client.gui.enable_signal_gui != _ctrl_pressed) {
00443     if (HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals)) ShowSignalBuilder(w);
00444   } else {
00445     HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals);
00446   }
00447 }
00448 
00454 static void BuildRailClick_Bridge(Window *w)
00455 {
00456   HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, VHM_RECT, PlaceRail_Bridge);
00457 }
00458 
00464 static void BuildRailClick_Tunnel(Window *w)
00465 {
00466   HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, VHM_SPECIAL, PlaceRail_Tunnel);
00467 }
00468 
00474 static void BuildRailClick_Remove(Window *w)
00475 {
00476   if (w->IsWidgetDisabled(RTW_REMOVE)) return;
00477   ToggleRailButton_Remove(w);
00478   SndPlayFx(SND_15_BEEP);
00479 
00480   /* handle station builder */
00481   if (w->IsWidgetLowered(RTW_BUILD_STATION)) {
00482     if (_remove_button_clicked) {
00483       /* starting drag & drop remove */
00484       if (!_railstation.dragdrop) {
00485         SetTileSelectSize(1, 1);
00486       } else {
00487         VpSetPlaceSizingLimit(-1);
00488       }
00489     } else {
00490       /* starting station build mode */
00491       if (!_railstation.dragdrop) {
00492         int x = _railstation.numtracks;
00493         int y = _railstation.platlength;
00494         if (_railstation.orientation == 0) Swap(x, y);
00495         SetTileSelectSize(x, y);
00496       } else {
00497         VpSetPlaceSizingLimit(_settings_game.station.station_spread);
00498       }
00499     }
00500   }
00501 }
00502 
00509 static void BuildRailClick_Convert(Window *w)
00510 {
00511   HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, VHM_RECT, PlaceRail_ConvertRail);
00512 }
00513 
00514 
00515 static void DoRailroadTrack(int mode)
00516 {
00517   DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), NULL,
00518     _remove_button_clicked ?
00519     CMD_REMOVE_RAILROAD_TRACK | CMD_NO_WATER | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) :
00520     CMD_BUILD_RAILROAD_TRACK  | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK)
00521   );
00522 }
00523 
00524 static void HandleAutodirPlacement()
00525 {
00526   TileHighlightData *thd = &_thd;
00527   int trackstat = thd->drawstyle & 0xF; // 0..5
00528 
00529   if (thd->drawstyle & HT_RAIL) { // one tile case
00530     GenericPlaceRail(TileVirtXY(thd->selend.x, thd->selend.y), trackstat);
00531     return;
00532   }
00533 
00534   DoRailroadTrack(trackstat);
00535 }
00536 
00543 static void HandleAutoSignalPlacement()
00544 {
00545   TileHighlightData *thd = &_thd;
00546   uint32 p2 = GB(thd->drawstyle, 0, 3); // 0..5
00547 
00548   if (thd->drawstyle == HT_RECT) { // one tile case
00549     GenericPlaceSignals(TileVirtXY(thd->selend.x, thd->selend.y));
00550     return;
00551   }
00552 
00553   const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
00554 
00555   if (w != NULL) {
00556     /* signal GUI is used */
00557     SB(p2,  3, 1, 0);
00558     SB(p2,  4, 1, _cur_signal_variant);
00559     SB(p2,  6, 1, _ctrl_pressed);
00560     SB(p2,  7, 3, _cur_signal_type);
00561     SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
00562   } else {
00563     SB(p2,  3, 1, 0);
00564     SB(p2,  4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
00565     SB(p2,  6, 1, _ctrl_pressed);
00566     SB(p2,  7, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
00567     SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
00568   }
00569 
00570   /* _settings_client.gui.drag_signals_density is given as a parameter such that each user
00571    * in a network game can specify his/her own signal density */
00572   DoCommandP(
00573     TileVirtXY(thd->selstart.x, thd->selstart.y),
00574     TileVirtXY(thd->selend.x, thd->selend.y),
00575     p2,
00576     CcPlaySound1E,
00577     _remove_button_clicked ?
00578       CMD_REMOVE_SIGNAL_TRACK | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) :
00579       CMD_BUILD_SIGNAL_TRACK  | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE)
00580   );
00581 }
00582 
00583 
00584 typedef void OnButtonClick(Window *w);
00585 
00587 struct RailBuildingGUIButtonData {
00588   uint16 keycode;            
00589   OnButtonClick *click_proc; 
00590 };
00591 
00596 static const RailBuildingGUIButtonData _rail_build_button_data[] = {
00597   {'1', BuildRailClick_N          },
00598   {'2', BuildRailClick_NE         },
00599   {'3', BuildRailClick_E          },
00600   {'4', BuildRailClick_NW         },
00601   {'5', BuildRailClick_AutoRail   },
00602   {'6', BuildRailClick_Demolish   },
00603   {'7', BuildRailClick_Depot      },
00604   {'8', BuildRailClick_Waypoint   },
00605   {'9', BuildRailClick_Station    },
00606   {'S', BuildRailClick_AutoSignals},
00607   {'B', BuildRailClick_Bridge     },
00608   {'T', BuildRailClick_Tunnel     },
00609   {'R', BuildRailClick_Remove     },
00610   {'C', BuildRailClick_Convert    }
00611 };
00612 
00618 struct BuildRailToolbarWindow : Window {
00619   BuildRailToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00620   {
00621     this->DisableWidget(RTW_REMOVE);
00622 
00623     this->FindWindowPlacementAndResize(desc);
00624     if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this);
00625   }
00626 
00627   ~BuildRailToolbarWindow()
00628   {
00629     if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
00630   }
00631 
00632   void UpdateRemoveWidgetStatus(int clicked_widget)
00633   {
00634     switch (clicked_widget) {
00635       case RTW_REMOVE:
00636         /* If it is the removal button that has been clicked, do nothing,
00637         * as it is up to the other buttons to drive removal status */
00638         return;
00639         break;
00640       case RTW_BUILD_NS:
00641       case RTW_BUILD_X:
00642       case RTW_BUILD_EW:
00643       case RTW_BUILD_Y:
00644       case RTW_AUTORAIL:
00645       case RTW_BUILD_WAYPOINT:
00646       case RTW_BUILD_STATION:
00647       case RTW_BUILD_SIGNALS:
00648         /* Removal button is enabled only if the rail/signal/waypoint/station
00649         * button is still lowered.  Once raised, it has to be disabled */
00650         this->SetWidgetDisabledState(RTW_REMOVE, !this->IsWidgetLowered(clicked_widget));
00651         break;
00652 
00653       default:
00654         /* When any other buttons than rail/signal/waypoint/station, raise and
00655         * disable the removal button */
00656         this->DisableWidget(RTW_REMOVE);
00657         this->RaiseWidget(RTW_REMOVE);
00658         break;
00659     }
00660   }
00661 
00662   virtual void OnPaint()
00663   {
00664     this->DrawWidgets();
00665   }
00666 
00667   virtual void OnClick(Point pt, int widget)
00668   {
00669     if (widget >= RTW_BUILD_NS) {
00670       _remove_button_clicked = false;
00671       _rail_build_button_data[widget - RTW_BUILD_NS].click_proc(this);
00672     }
00673     this->UpdateRemoveWidgetStatus(widget);
00674     if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
00675   }
00676 
00677   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00678   {
00679     EventState state = ES_NOT_HANDLED;
00680     for (uint8 i = 0; i != lengthof(_rail_build_button_data); i++) {
00681       if (keycode == _rail_build_button_data[i].keycode) {
00682         _remove_button_clicked = false;
00683         _rail_build_button_data[i].click_proc(this);
00684         this->UpdateRemoveWidgetStatus(i + RTW_BUILD_NS);
00685         if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
00686         state = ES_HANDLED;
00687         break;
00688       }
00689     }
00690     MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
00691     return state;
00692   }
00693 
00694   virtual void OnPlaceObject(Point pt, TileIndex tile)
00695   {
00696     _place_proc(tile);
00697   }
00698 
00699   virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
00700   {
00701     /* no dragging if you have pressed the convert button */
00702     if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
00703 
00704     VpSelectTilesWithMethod(pt.x, pt.y, select_method);
00705   }
00706 
00707   virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
00708   {
00709     if (pt.x != -1) {
00710       switch (select_proc) {
00711         default: NOT_REACHED();
00712         case DDSP_BUILD_BRIDGE:
00713           ResetObjectToPlace();
00714           ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype);
00715           break;
00716 
00717         case DDSP_PLACE_AUTORAIL:
00718           HandleAutodirPlacement();
00719           break;
00720 
00721         case DDSP_BUILD_SIGNALS:
00722           HandleAutoSignalPlacement();
00723           break;
00724 
00725         case DDSP_DEMOLISH_AREA:
00726           GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
00727           break;
00728 
00729         case DDSP_CONVERT_RAIL:
00730           DoCommandP(end_tile, start_tile, _cur_railtype, CcPlaySound10, CMD_CONVERT_RAIL | CMD_MSG(STR_CANT_CONVERT_RAIL));
00731           break;
00732 
00733         case DDSP_REMOVE_STATION:
00734         case DDSP_BUILD_STATION:
00735           if (_remove_button_clicked) {
00736             DoCommandP(end_tile, start_tile, 0, CcPlaySound1E, CMD_REMOVE_FROM_RAILROAD_STATION | CMD_MSG(STR_CANT_REMOVE_PART_OF_STATION));
00737             break;
00738           }
00739           HandleStationPlacement(start_tile, end_tile);
00740           break;
00741 
00742         case DDSP_PLACE_RAIL_NE:
00743         case DDSP_PLACE_RAIL_NW:
00744           DoRailroadTrack(select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y);
00745           break;
00746       }
00747     }
00748   }
00749 
00750   virtual void OnPlaceObjectAbort()
00751   {
00752     this->RaiseButtons();
00753     this->DisableWidget(RTW_REMOVE);
00754     this->InvalidateWidget(RTW_REMOVE);
00755 
00756     delete FindWindowById(WC_BUILD_SIGNAL, 0);
00757     delete FindWindowById(WC_BUILD_STATION, 0);
00758     delete FindWindowById(WC_BUILD_DEPOT, 0);
00759   }
00760 
00761   virtual void OnPlacePresize(Point pt, TileIndex tile)
00762   {
00763     DoCommand(tile, 0, 0, DC_AUTO, CMD_BUILD_TUNNEL);
00764     VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
00765   }
00766 
00767   virtual EventState OnCTRLStateChange()
00768   {
00769     /* do not toggle Remove button by Ctrl when placing station */
00770     if (!this->IsWidgetLowered(RTW_BUILD_STATION) && RailToolbar_CtrlChanged(this)) return ES_HANDLED;
00771     return ES_NOT_HANDLED;
00772   }
00773 };
00774 
00776 static const Widget _build_rail_widgets[] = {
00777 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_DARK_GREEN,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},                   // RTW_CLOSEBOX
00778 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_DARK_GREEN,    11,   337,     0,    13, STR_100A_RAILROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},         // RTW_CAPTION
00779 {  WWT_STICKYBOX,   RESIZE_NONE,  COLOUR_DARK_GREEN,   338,   349,     0,    13, 0x0,                            STR_STICKY_BUTTON},                       // RTW_STICKY
00780 
00781 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_DARK_GREEN,   110,   113,    14,    35, 0x0,                            STR_NULL},                                // RTW_SPACER
00782 
00783 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,     0,    21,    14,    35, SPR_IMG_RAIL_NS,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_NS
00784 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,    22,    43,    14,    35, SPR_IMG_RAIL_NE,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_X
00785 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,    44,    65,    14,    35, SPR_IMG_RAIL_EW,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_EW
00786 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,    66,    87,    14,    35, SPR_IMG_RAIL_NW,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_Y
00787 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,    88,   109,    14,    35, SPR_IMG_AUTORAIL,               STR_BUILD_AUTORAIL_TIP},                  // RTW_AUTORAIL
00788 
00789 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   114,   135,    14,    35, SPR_IMG_DYNAMITE,               STR_018D_DEMOLISH_BUILDINGS_ETC},         // RTW_DEMOLISH
00790 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   136,   157,    14,    35, SPR_IMG_DEPOT_RAIL,             STR_1019_BUILD_TRAIN_DEPOT_FOR_BUILDING}, // RTW_BUILD_DEPOT
00791 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   158,   179,    14,    35, SPR_IMG_WAYPOINT,               STR_CONVERT_RAIL_TO_WAYPOINT_TIP},        // RTW_BUILD_WAYPOINT
00792 
00793 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   180,   221,    14,    35, SPR_IMG_RAIL_STATION,           STR_101A_BUILD_RAILROAD_STATION},         // RTW_BUILD_STATION
00794 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   222,   243,    14,    35, SPR_IMG_RAIL_SIGNALS,           STR_101B_BUILD_RAILROAD_SIGNALS},         // RTW_BUILD_SIGNALS
00795 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   244,   285,    14,    35, SPR_IMG_BRIDGE,                 STR_101C_BUILD_RAILROAD_BRIDGE},          // RTW_BUILD_BRIDGE
00796 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   286,   305,    14,    35, SPR_IMG_TUNNEL_RAIL,            STR_101D_BUILD_RAILROAD_TUNNEL},          // RTW_BUILD_TUNNEL
00797 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   306,   327,    14,    35, SPR_IMG_REMOVE,                 STR_101E_TOGGLE_BUILD_REMOVE_FOR},        // RTW_REMOVE
00798 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,   328,   349,    14,    35, SPR_IMG_CONVERT_RAIL,           STR_CONVERT_RAIL_TIP},                    // RTW_CONVERT_RAIL
00799 
00800 {   WIDGETS_END},
00801 };
00802 
00803 static const WindowDesc _build_rail_desc = {
00804   WDP_ALIGN_TBR, 22, 350, 36, 350, 36,
00805   WC_BUILD_TOOLBAR, WC_NONE,
00806