# rail_gui.cpp

Go to the documentation of this file.

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