build_vehicle_gui.cpp

Go to the documentation of this file.
00001 /* $Id: build_vehicle_gui.cpp 14422 2008-09-30 20:51:04Z rubidium $ */
00002 
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "train.h"
00008 #include "roadveh.h"
00009 #include "ship.h"
00010 #include "aircraft.h"
00011 #include "debug.h"
00012 #include "gui.h"
00013 #include "articulated_vehicles.h"
00014 #include "textbuf_gui.h"
00015 #include "command_func.h"
00016 #include "company_func.h"
00017 #include "airport.h"
00018 #include "vehicle_gui.h"
00019 #include "newgrf_engine.h"
00020 #include "cargotype.h"
00021 #include "group.h"
00022 #include "road_map.h"
00023 #include "strings_func.h"
00024 #include "window_func.h"
00025 #include "date_func.h"
00026 #include "vehicle_func.h"
00027 #include "settings_type.h"
00028 #include "gfx_func.h"
00029 #include "widgets/dropdown_func.h"
00030 #include "string_func.h"
00031 #include "window_gui.h"
00032 #include "engine_gui.h"
00033 
00034 #include "table/sprites.h"
00035 #include "table/strings.h"
00036 
00037 enum BuildVehicleWidgets {
00038   BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
00039   BUILD_VEHICLE_WIDGET_CAPTION,
00040   BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING,
00041   BUILD_VEHICLE_WIDGET_SORT_DROPDOWN,
00042   BUILD_VEHICLE_WIDGET_LIST,
00043   BUILD_VEHICLE_WIDGET_SCROLLBAR,
00044   BUILD_VEHICLE_WIDGET_PANEL,
00045   BUILD_VEHICLE_WIDGET_BUILD,
00046   BUILD_VEHICLE_WIDGET_RENAME,
00047   BUILD_VEHICLE_WIDGET_RESIZE,
00048   BUILD_VEHICLE_WIDGET_END
00049 };
00050 
00051 static const Widget _build_vehicle_widgets[] = {
00052   {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW },
00053   {    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_GREY,    11,   239,     0,    13, 0x0,                     STR_018C_WINDOW_TITLE_DRAG_THIS },
00054   { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    80,    14,    25, STR_SORT_BY,             STR_SORT_ORDER_TIP},
00055   {   WWT_DROPDOWN,  RESIZE_RIGHT,  COLOUR_GREY,    81,   239,    14,    25, 0x0,                     STR_SORT_CRITERIA_TIP},
00056   {     WWT_MATRIX,     RESIZE_RB,  COLOUR_GREY,     0,   227,    26,    39, 0x101,                   STR_NULL },
00057   {  WWT_SCROLLBAR,    RESIZE_LRB,  COLOUR_GREY,   228,   239,    26,    39, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST },
00058   {      WWT_PANEL,    RESIZE_RTB,  COLOUR_GREY,     0,   239,    40,   161, 0x0,                     STR_NULL },
00059 
00060   { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_GREY,     0,   114,   162,   173, 0x0,                     STR_NULL },
00061   { WWT_PUSHTXTBTN,    RESIZE_RTB,  COLOUR_GREY,   115,   227,   162,   173, 0x0,                     STR_NULL },
00062   {  WWT_RESIZEBOX,   RESIZE_LRTB,  COLOUR_GREY,   228,   239,   162,   173, 0x0,                     STR_RESIZE_BUTTON },
00063   {   WIDGETS_END},
00064 };
00065 
00066 static bool _internal_sort_order; // descending/ascending
00067 static byte _last_sort_criteria[]    = {0, 0, 0, 0};
00068 static bool _last_sort_order[]       = {false, false, false, false};
00069 
00070 static int CDECL EngineNumberSorter(const void *a, const void *b)
00071 {
00072   const EngineID va = *(const EngineID*)a;
00073   const EngineID vb = *(const EngineID*)b;
00074   int r = ListPositionOfEngine(va) - ListPositionOfEngine(vb);
00075 
00076   return _internal_sort_order ? -r : r;
00077 }
00078 
00079 static int CDECL EngineIntroDateSorter(const void *a, const void *b)
00080 {
00081   const int va = GetEngine(*(const EngineID*)a)->intro_date;
00082   const int vb = GetEngine(*(const EngineID*)b)->intro_date;
00083   const int r = va - vb;
00084 
00085   if (r == 0) {
00086     /* Use EngineID to sort instead since we want consistent sorting */
00087     return EngineNumberSorter(a, b);
00088   }
00089   return _internal_sort_order ? -r : r;
00090 }
00091 
00092 static int CDECL EngineNameSorter(const void *a, const void *b)
00093 {
00094   static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
00095   static char     last_name[2][64] = { "\0", "\0" };
00096 
00097   const EngineID va = *(const EngineID*)a;
00098   const EngineID vb = *(const EngineID*)b;
00099   int r;
00100 
00101   if (va != last_engine[0]) {
00102     last_engine[0] = va;
00103     SetDParam(0, va);
00104     GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0]));
00105   }
00106 
00107   if (vb != last_engine[1]) {
00108     last_engine[1] = vb;
00109     SetDParam(0, vb);
00110     GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1]));
00111   }
00112 
00113   r = strcmp(last_name[0], last_name[1]); // sort by name
00114 
00115   if (r == 0) {
00116     /* Use EngineID to sort instead since we want consistent sorting */
00117     return EngineNumberSorter(a, b);
00118   }
00119   return _internal_sort_order ? -r : r;
00120 }
00121 
00122 static int CDECL EngineReliabilitySorter(const void *a, const void *b)
00123 {
00124   const int va = GetEngine(*(const EngineID*)a)->reliability;
00125   const int vb = GetEngine(*(const EngineID*)b)->reliability;
00126   const int r = va - vb;
00127 
00128   if (r == 0) {
00129     /* Use EngineID to sort instead since we want consistent sorting */
00130     return EngineNumberSorter(a, b);
00131   }
00132   return _internal_sort_order ? -r : r;
00133 }
00134 
00135 /* Train sorting functions */
00136 static int CDECL TrainEngineCostSorter(const void *a, const void *b)
00137 {
00138   int va = RailVehInfo(*(const EngineID*)a)->cost_factor;
00139   int vb = RailVehInfo(*(const EngineID*)b)->cost_factor;
00140   int r = va - vb;
00141 
00142   return _internal_sort_order ? -r : r;
00143 }
00144 
00145 static int CDECL TrainEngineSpeedSorter(const void *a, const void *b)
00146 {
00147   int va = RailVehInfo(*(const EngineID*)a)->max_speed;
00148   int vb = RailVehInfo(*(const EngineID*)b)->max_speed;
00149   int r = va - vb;
00150 
00151   return _internal_sort_order ? -r : r;
00152 }
00153 
00154 static int CDECL TrainEnginePowerSorter(const void *a, const void *b)
00155 {
00156   const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
00157   const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
00158 
00159   int va = rvi_a->power;
00160   int vb = rvi_b->power;
00161   int r = va - vb;
00162 
00163   return _internal_sort_order ? -r : r;
00164 }
00165 
00166 static int CDECL TrainEngineRunningCostSorter(const void *a, const void *b)
00167 {
00168   const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
00169   const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
00170 
00171   Money va = rvi_a->running_cost * GetPriceByIndex(rvi_a->running_cost_class);
00172   Money vb = rvi_b->running_cost * GetPriceByIndex(rvi_b->running_cost_class);
00173   int r = ClampToI32(va - vb);
00174 
00175   return _internal_sort_order ? -r : r;
00176 }
00177 
00178 static int CDECL TrainEnginePowerVsRunningCostSorter(const void *a, const void *b)
00179 {
00180   const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
00181   const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
00182 
00183   /* Here we are using a few tricks to get the right sort.
00184     * We want power/running cost, but since we usually got higher running cost than power and we store the result in an int,
00185     * we will actually calculate cunning cost/power (to make it more than 1).
00186     * Because of this, the return value have to be reversed as well and we return b - a instead of a - b.
00187     * Another thing is that both power and running costs should be doubled for multiheaded engines.
00188     * Since it would be multipling with 2 in both numerator and denumerator, it will even themselves out and we skip checking for multiheaded. */
00189   Money va = (rvi_a->running_cost * GetPriceByIndex(rvi_a->running_cost_class)) / max(1U, (uint)rvi_a->power);
00190   Money vb = (rvi_b->running_cost * GetPriceByIndex(rvi_b->running_cost_class)) / max(1U, (uint)rvi_b->power);
00191   int r = ClampToI32(vb - va);
00192 
00193   return _internal_sort_order ? -r : r;
00194 }
00195 
00196 static int CDECL TrainEngineCapacitySorter(const void *a, const void *b)
00197 {
00198   const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
00199   const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
00200 
00201   int va = rvi_a->capacity * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
00202   int vb = rvi_b->capacity * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
00203   int r = va - vb;
00204 
00205   if (r == 0) {
00206     /* Use EngineID to sort instead since we want consistent sorting */
00207     return EngineNumberSorter(a, b);
00208   }
00209   return _internal_sort_order ? -r : r;
00210 }
00211 
00212 static int CDECL TrainEnginesThenWagonsSorter(const void *a, const void *b)
00213 {
00214   EngineID va = *(const EngineID*)a;
00215   EngineID vb = *(const EngineID*)b;
00216   int val_a = (RailVehInfo(va)->railveh_type == RAILVEH_WAGON ? 1 : 0);
00217   int val_b = (RailVehInfo(vb)->railveh_type == RAILVEH_WAGON ? 1 : 0);
00218   int r = val_a - val_b;
00219 
00220   /* Use EngineID to sort instead since we want consistent sorting */
00221   if (r == 0) return EngineNumberSorter(a, b);
00222 
00223   return _internal_sort_order ? -r : r;
00224 }
00225 
00226 /* Road vehicle sorting functions */
00227 static int CDECL RoadVehEngineCostSorter(const void *a, const void *b)
00228 {
00229   int va = RoadVehInfo(*(const EngineID*)a)->cost_factor;
00230   int vb = RoadVehInfo(*(const EngineID*)b)->cost_factor;
00231   int r = va - vb;
00232 
00233   return _internal_sort_order ? -r : r;
00234 }
00235 
00236 static int CDECL RoadVehEngineSpeedSorter(const void *a, const void *b)
00237 {
00238   int va = RoadVehInfo(*(const EngineID*)a)->max_speed;
00239   int vb = RoadVehInfo(*(const EngineID*)b)->max_speed;
00240   int r = va - vb;
00241 
00242   return _internal_sort_order ? -r : r;
00243 }
00244 
00245 static int CDECL RoadVehEngineRunningCostSorter(const void *a, const void *b)
00246 {
00247   const RoadVehicleInfo *rvi_a = RoadVehInfo(*(const EngineID*)a);
00248   const RoadVehicleInfo *rvi_b = RoadVehInfo(*(const EngineID*)b);
00249 
00250   Money va = rvi_a->running_cost * GetPriceByIndex(rvi_a->running_cost_class);
00251   Money vb = rvi_b->running_cost * GetPriceByIndex(rvi_b->running_cost_class);
00252   int r = ClampToI32(va - vb);
00253 
00254   if (r == 0) {
00255     /* Use EngineID to sort instead since we want consistent sorting */
00256     return EngineNumberSorter(a, b);
00257   }
00258   return _internal_sort_order ? -r : r;
00259 }
00260 
00261 static int CDECL RoadVehEngineCapacitySorter(const void *a, const void *b)
00262 {
00263   int va = RoadVehInfo(*(const EngineID*)a)->capacity;
00264   int vb = RoadVehInfo(*(const EngineID*)b)->capacity;
00265   int r = va - vb;
00266 
00267   if (r == 0) {
00268     /* Use EngineID to sort instead since we want consistent sorting */
00269     return EngineNumberSorter(a, b);
00270   }
00271   return _internal_sort_order ? -r : r;
00272 }
00273 
00274 /* Road vehicle sorting functions */
00275 static int CDECL ShipEngineCostSorter(const void *a, const void *b)
00276 {
00277   int va = ShipVehInfo(*(const EngineID*)a)->cost_factor;
00278   int vb = ShipVehInfo(*(const EngineID*)b)->cost_factor;
00279   int r = va - vb;
00280 
00281   return _internal_sort_order ? -r : r;
00282 }
00283 
00284 static int CDECL ShipEngineSpeedSorter(const void *a, const void *b)
00285 {
00286   int va = ShipVehInfo(*(const EngineID*)a)->max_speed;
00287   int vb = ShipVehInfo(*(const EngineID*)b)->max_speed;
00288   int r = va - vb;
00289 
00290   return _internal_sort_order ? -r : r;
00291 }
00292 
00293 static int CDECL ShipEngineRunningCostSorter(const void *a, const void *b)
00294 {
00295   const int va = ShipVehInfo(*(const EngineID*)a)->running_cost;
00296   const int vb = ShipVehInfo(*(const EngineID*)b)->running_cost;
00297   const int r = va - vb;
00298 
00299   if (r == 0) {
00300     /* Use EngineID to sort instead since we want consistent sorting */
00301     return EngineNumberSorter(a, b);
00302   }
00303   return _internal_sort_order ? -r : r;
00304 }
00305 
00306 static int CDECL ShipEngineCapacitySorter(const void *a, const void *b)
00307 {
00308   int va = ShipVehInfo(*(const EngineID*)a)->capacity;
00309   int vb = ShipVehInfo(*(const EngineID*)b)->capacity;
00310   int r = va - vb;
00311 
00312   if (r == 0) {
00313     /* Use EngineID to sort instead since we want consistent sorting */
00314     return EngineNumberSorter(a, b);
00315   }
00316   return _internal_sort_order ? -r : r;
00317 }
00318 
00319 /* Aircraft sorting functions */
00320 
00321 static int CDECL AircraftEngineCostSorter(const void *a, const void *b)
00322 {
00323   const int va = AircraftVehInfo(*(const EngineID*)a)->cost_factor;
00324   const int vb = AircraftVehInfo(*(const EngineID*)b)->cost_factor;
00325   int r = va - vb;
00326 
00327   return _internal_sort_order ? -r : r;
00328 }
00329 
00330 static int CDECL AircraftEngineSpeedSorter(const void *a, const void *b)
00331 {
00332   const int va = AircraftVehInfo(*(const EngineID*)a)->max_speed;
00333   const int vb = AircraftVehInfo(*(const EngineID*)b)->max_speed;
00334   const int r = va - vb;
00335 
00336   if (r == 0) {
00337     /* Use EngineID to sort instead since we want consistent sorting */
00338     return EngineNumberSorter(a, b);
00339   }
00340   return _internal_sort_order ? -r : r;
00341 }
00342 
00343 static int CDECL AircraftEngineRunningCostSorter(const void *a, const void *b)
00344 {
00345   const int va = AircraftVehInfo(*(const EngineID*)a)->running_cost;
00346   const int vb = AircraftVehInfo(*(const EngineID*)b)->running_cost;
00347   const int r = va - vb;
00348 
00349   if (r == 0) {
00350     /* Use EngineID to sort instead since we want consistent sorting */
00351     return EngineNumberSorter(a, b);
00352   }
00353   return _internal_sort_order ? -r : r;
00354 }
00355 
00356 static int CDECL AircraftEngineCargoSorter(const void *a, const void *b)
00357 {
00358   int va = AircraftVehInfo(*(const EngineID*)a)->passenger_capacity;
00359   int vb = AircraftVehInfo(*(const EngineID*)b)->passenger_capacity;
00360   int r = va - vb;
00361 
00362   if (r == 0) {
00363     /* The planes has the same passenger capacity. Check mail capacity instead */
00364     va = AircraftVehInfo(*(const EngineID*)a)->mail_capacity;
00365     vb = AircraftVehInfo(*(const EngineID*)b)->mail_capacity;
00366     r = va - vb;
00367 
00368     if (r == 0) {
00369       /* Use EngineID to sort instead since we want consistent sorting */
00370       return EngineNumberSorter(a, b);
00371     }
00372   }
00373   return _internal_sort_order ? -r : r;
00374 }
00375 
00376 static EngList_SortTypeFunction * const _sorter[][10] = {{
00377   /* Trains */
00378   &EngineNumberSorter,
00379   &TrainEngineCostSorter,
00380   &TrainEngineSpeedSorter,
00381   &TrainEnginePowerSorter,
00382   &EngineIntroDateSorter,
00383   &EngineNameSorter,
00384   &TrainEngineRunningCostSorter,
00385   &TrainEnginePowerVsRunningCostSorter,
00386   &EngineReliabilitySorter,
00387   &TrainEngineCapacitySorter,
00388 }, {
00389   /* Road vehicles */
00390   &EngineNumberSorter,
00391   &RoadVehEngineCostSorter,
00392   &RoadVehEngineSpeedSorter,
00393   &EngineIntroDateSorter,
00394   &EngineNameSorter,
00395   &RoadVehEngineRunningCostSorter,
00396   &EngineReliabilitySorter,
00397   &RoadVehEngineCapacitySorter,
00398 }, {
00399   /* Ships */
00400   &EngineNumberSorter,
00401   &ShipEngineCostSorter,
00402   &ShipEngineSpeedSorter,
00403   &EngineIntroDateSorter,
00404   &EngineNameSorter,
00405   &ShipEngineRunningCostSorter,
00406   &EngineReliabilitySorter,
00407   &ShipEngineCapacitySorter,
00408 }, {
00409   /* Aircraft */
00410   &EngineNumberSorter,
00411   &AircraftEngineCostSorter,
00412   &AircraftEngineSpeedSorter,
00413   &EngineIntroDateSorter,
00414   &EngineNameSorter,
00415   &AircraftEngineRunningCostSorter,
00416   &EngineReliabilitySorter,
00417   &AircraftEngineCargoSorter,
00418 }};
00419 
00420 static const StringID _sort_listing[][11] = {{
00421   /* Trains */
00422   STR_ENGINE_SORT_ENGINE_ID,
00423   STR_ENGINE_SORT_COST,
00424   STR_SORT_BY_MAX_SPEED,
00425   STR_ENGINE_SORT_POWER,
00426   STR_ENGINE_SORT_INTRO_DATE,
00427   STR_SORT_BY_DROPDOWN_NAME,
00428   STR_ENGINE_SORT_RUNNING_COST,
00429   STR_ENGINE_SORT_POWER_VS_RUNNING_COST,
00430   STR_SORT_BY_RELIABILITY,
00431   STR_ENGINE_SORT_CARGO_CAPACITY,
00432   INVALID_STRING_ID
00433 }, {
00434   /* Road vehicles */
00435   STR_ENGINE_SORT_ENGINE_ID,
00436   STR_ENGINE_SORT_COST,
00437   STR_SORT_BY_MAX_SPEED,
00438   STR_ENGINE_SORT_INTRO_DATE,
00439   STR_SORT_BY_DROPDOWN_NAME,
00440   STR_ENGINE_SORT_RUNNING_COST,
00441   STR_SORT_BY_RELIABILITY,
00442   STR_ENGINE_SORT_CARGO_CAPACITY,
00443   INVALID_STRING_ID
00444 }, {
00445   /* Ships */
00446   STR_ENGINE_SORT_ENGINE_ID,
00447   STR_ENGINE_SORT_COST,
00448   STR_SORT_BY_MAX_SPEED,
00449   STR_ENGINE_SORT_INTRO_DATE,
00450   STR_SORT_BY_DROPDOWN_NAME,
00451   STR_ENGINE_SORT_RUNNING_COST,
00452   STR_SORT_BY_RELIABILITY,
00453   STR_ENGINE_SORT_CARGO_CAPACITY,
00454   INVALID_STRING_ID
00455 }, {
00456   /* Aircraft */
00457   STR_ENGINE_SORT_ENGINE_ID,
00458   STR_ENGINE_SORT_COST,
00459   STR_SORT_BY_MAX_SPEED,
00460   STR_ENGINE_SORT_INTRO_DATE,
00461   STR_SORT_BY_DROPDOWN_NAME,
00462   STR_ENGINE_SORT_RUNNING_COST,
00463   STR_SORT_BY_RELIABILITY,
00464   STR_ENGINE_SORT_CARGO_CAPACITY,
00465   INVALID_STRING_ID
00466 }};
00467 
00468 static int DrawCargoCapacityInfo(int x, int y, EngineID engine, VehicleType type, bool refittable)
00469 {
00470   uint16 *cap = GetCapacityOfArticulatedParts(engine, type);
00471 
00472   for (uint c = 0; c < NUM_CARGO; c++) {
00473     if (cap[c] == 0) continue;
00474 
00475     SetDParam(0, c);
00476     SetDParam(1, cap[c]);
00477     SetDParam(2, refittable ? STR_9842_REFITTABLE : STR_EMPTY);
00478     DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00479     y += 10;
00480 
00481     /* Only show as refittable once */
00482     refittable = false;
00483   }
00484 
00485   return y;
00486 }
00487 
00488 /* Draw rail wagon specific details */
00489 static int DrawRailWagonPurchaseInfo(int x, int y, EngineID engine_number, const RailVehicleInfo *rvi)
00490 {
00491   /* Purchase cost */
00492   SetDParam(0, (GetEngineProperty(engine_number, 0x17, rvi->cost_factor) * _price.build_railwagon) >> 8);
00493   DrawString(x, y, STR_PURCHASE_INFO_COST, TC_FROMSTRING);
00494   y += 10;
00495 
00496   /* Wagon weight - (including cargo) */
00497   uint weight = GetEngineProperty(engine_number, 0x16, rvi->weight);
00498   SetDParam(0, weight);
00499   SetDParam(1, (GetCargo(rvi->cargo_type)->weight * GetEngineProperty(engine_number, 0x14, rvi->capacity) >> 4) + weight);
00500   DrawString(x, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT, TC_FROMSTRING);
00501   y += 10;
00502 
00503   /* Wagon speed limit, displayed if above zero */
00504   if (_settings_game.vehicle.wagon_speed_limits) {
00505     uint max_speed = GetEngineProperty(engine_number, 0x09, rvi->max_speed);
00506     if (max_speed > 0) {
00507       SetDParam(0, max_speed * 10 / 16);
00508       DrawString(x, y, STR_PURCHASE_INFO_SPEED, TC_FROMSTRING);
00509       y += 10;
00510     }
00511   }
00512 
00513   /* Running cost */
00514   if (rvi->running_cost_class != 0xFF) {
00515     SetDParam(0, GetEngineProperty(engine_number, 0x0D, rvi->running_cost) * GetPriceByIndex(rvi->running_cost_class) >> 8);
00516     DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00517     y += 10;
00518   }
00519 
00520   return y;
00521 }
00522 
00523 /* Draw locomotive specific details */
00524 static int DrawRailEnginePurchaseInfo(int x, int y, EngineID engine_number, const RailVehicleInfo *rvi)
00525 {
00526   int multihead = (rvi->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
00527   uint weight = GetEngineProperty(engine_number, 0x16, rvi->weight);
00528 
00529   /* Purchase Cost - Engine weight */
00530   SetDParam(0, GetEngineProperty(engine_number, 0x17, rvi->cost_factor) * (_price.build_railvehicle >> 3) >> 5);
00531   SetDParam(1, weight << multihead);
00532   DrawString(x, y, STR_PURCHASE_INFO_COST_WEIGHT, TC_FROMSTRING);
00533   y += 10;
00534 
00535   /* Max speed - Engine power */
00536   SetDParam(0, GetEngineProperty(engine_number, 0x09, rvi->max_speed) * 10 / 16);
00537   SetDParam(1, GetEngineProperty(engine_number, 0x0B, rvi->power));
00538   DrawString(x, y, STR_PURCHASE_INFO_SPEED_POWER, TC_FROMSTRING);
00539   y += 10;
00540 
00541   /* Max tractive effort - not applicable if old acceleration or maglev */
00542   if (_settings_game.vehicle.realistic_acceleration && rvi->railtype != RAILTYPE_MAGLEV) {
00543     SetDParam(0, ((weight << multihead) * 10 * GetEngineProperty(engine_number, 0x1F, rvi->tractive_effort)) / 256);
00544     DrawString(x, y, STR_PURCHASE_INFO_MAX_TE, TC_FROMSTRING);
00545     y += 10;
00546   }
00547 
00548   /* Running cost */
00549   if (rvi->running_cost_class != 0xFF) {
00550     SetDParam(0, GetEngineProperty(engine_number, 0x0D, rvi->running_cost) * GetPriceByIndex(rvi->running_cost_class) >> 8);
00551     DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00552     y += 10;
00553   }
00554 
00555   /* Powered wagons power - Powered wagons extra weight */
00556   if (rvi->pow_wag_power != 0) {
00557     SetDParam(0, rvi->pow_wag_power);
00558     SetDParam(1, rvi->pow_wag_weight);
00559     DrawString(x, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT, TC_FROMSTRING);
00560     y += 10;
00561   };
00562 
00563   return y;
00564 }
00565 
00566 /* Draw road vehicle specific details */
00567 static int DrawRoadVehPurchaseInfo(int x, int y, EngineID engine_number, const RoadVehicleInfo *rvi)
00568 {
00569   bool refittable = (EngInfo(engine_number)->refit_mask != 0);
00570 
00571   /* Purchase cost - Max speed */
00572   SetDParam(0, GetEngineProperty(engine_number, 0x11, rvi->cost_factor) * (_price.roadveh_base >> 3) >> 5);
00573   SetDParam(1, rvi->max_speed * 10 / 32);
00574   DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, TC_FROMSTRING);
00575   y += 10;
00576 
00577   /* Running cost */
00578   SetDParam(0, rvi->running_cost * GetPriceByIndex(rvi->running_cost_class) >> 8);
00579   DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00580   y += 10;
00581 
00582   /* Cargo type + capacity */
00583   return DrawCargoCapacityInfo(x, y, engine_number, VEH_ROAD, refittable);
00584 }
00585 
00586 /* Draw ship specific details */
00587 static int DrawShipPurchaseInfo(int x, int y, EngineID engine_number, const ShipVehicleInfo *svi)
00588 {
00589   /* Purchase cost - Max speed */
00590   SetDParam(0, GetEngineProperty(engine_number, 0x0A, svi->cost_factor) * (_price.ship_base >> 3) >> 5);
00591   SetDParam(1, GetEngineProperty(engine_number, 0x0B, svi->max_speed) * 10 / 32);
00592   DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, TC_FROMSTRING);
00593   y += 10;
00594 
00595   /* Cargo type + capacity */
00596   SetDParam(0, svi->cargo_type);
00597   SetDParam(1, GetEngineProperty(engine_number, 0x0D, svi->capacity));
00598   SetDParam(2, svi->refittable ? STR_9842_REFITTABLE : STR_EMPTY);
00599   DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00600   y += 10;
00601 
00602   /* Running cost */
00603   SetDParam(0, GetEngineProperty(engine_number, 0x0F, svi->running_cost) * _price.ship_running >> 8);
00604   DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00605   y += 10;
00606 
00607   return y;
00608 }
00609 
00610 /* Draw aircraft specific details */
00611 static int DrawAircraftPurchaseInfo(int x, int y, EngineID engine_number, const AircraftVehicleInfo *avi)
00612 {
00613   CargoID cargo;
00614 
00615   /* Purchase cost - Max speed */
00616   SetDParam(0, GetEngineProperty(engine_number, 0x0B, avi->cost_factor) * (_price.aircraft_base >> 3) >> 5);
00617   SetDParam(1, avi->max_speed * 10 / 16);
00618   DrawString(x, y, STR_PURCHASE_INFO_COST_SPEED, TC_FROMSTRING);
00619   y += 10;
00620 
00621   /* Cargo capacity */
00622   cargo = FindFirstRefittableCargo(engine_number);
00623   if (cargo == CT_INVALID || cargo == CT_PASSENGERS) {
00624     SetDParam(0, avi->passenger_capacity);
00625     SetDParam(1, avi->mail_capacity);
00626     DrawString(x, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY, TC_FROMSTRING);
00627   } else {
00628     /* Note, if the default capacity is selected by the refit capacity
00629     * callback, then the capacity shown is likely to be incorrect. */
00630     SetDParam(0, cargo);
00631     SetDParam(1, AircraftDefaultCargoCapacity(cargo, avi));
00632     SetDParam(2, STR_9842_REFITTABLE);
00633     DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00634   }
00635   y += 10;
00636 
00637   /* Running cost */
00638   SetDParam(0, GetEngineProperty(engine_number, 0x0E, avi->running_cost) * _price.aircraft_running >> 8);
00639   DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
00640   y += 10;
00641 
00642   return y;
00643 }
00644 
00652 int DrawVehiclePurchaseInfo(int x, int y, uint w, EngineID engine_number)
00653 {
00654   const Engine *e = GetEngine(engine_number);
00655   YearMonthDay ymd;
00656   ConvertDateToYMD(e->intro_date, &ymd);
00657   bool refitable = false;
00658 
00659   switch (e->type) {
00660     default: NOT_REACHED();
00661     case VEH_TRAIN: {
00662       const RailVehicleInfo *rvi = RailVehInfo(engine_number);
00663       uint capacity = GetEngineProperty(engine_number, 0x14, rvi->capacity);
00664 
00665       refitable = (EngInfo(engine_number)->refit_mask != 0) && (capacity > 0);
00666 
00667       if (rvi->railveh_type == RAILVEH_WAGON) {
00668         y = DrawRailWagonPurchaseInfo(x, y, engine_number, rvi);
00669       } else {
00670         y = DrawRailEnginePurchaseInfo(x, y, engine_number, rvi);
00671       }
00672 
00673       /* Cargo type + capacity, or N/A */
00674       int new_y = DrawCargoCapacityInfo(x, y, engine_number, VEH_TRAIN, refitable);
00675 
00676       if (new_y == y) {
00677         SetDParam(0, CT_INVALID);
00678         SetDParam(2, STR_EMPTY);
00679         DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, TC_FROMSTRING);
00680         y += 10;
00681       } else {
00682         y = new_y;
00683       }
00684       break;
00685     }
00686     case VEH_ROAD:
00687       y = DrawRoadVehPurchaseInfo(x, y, engine_number, RoadVehInfo(engine_number));
00688       refitable = true;
00689       break;
00690     case VEH_SHIP: {
00691       const ShipVehicleInfo *svi = ShipVehInfo(engine_number);
00692       y = DrawShipPurchaseInfo(x, y, engine_number, svi);
00693       refitable = svi->refittable;
00694     } break;
00695     case VEH_AIRCRAFT:
00696       y = DrawAircraftPurchaseInfo(x, y, engine_number, AircraftVehInfo(engine_number));
00697       refitable = true;
00698       break;
00699   }
00700 
00701   /* Draw details, that applies to all types except rail wagons */
00702   if (e->type != VEH_TRAIN || RailVehInfo(engine_number)->railveh_type != RAILVEH_WAGON) {
00703     /* Design date - Life length */
00704     SetDParam(0, ymd.year);
00705     SetDParam(1, e->lifelength);
00706     DrawString(x, y, STR_PURCHASE_INFO_DESIGNED_LIFE, TC_FROMSTRING);
00707     y += 10;
00708 
00709     /* Reliability */
00710     SetDParam(0, e->reliability * 100 >> 16);
00711     DrawString(x, y, STR_PURCHASE_INFO_RELIABILITY, TC_FROMSTRING);
00712     y += 10;
00713   }
00714 
00715   /* Additional text from NewGRF */
00716   y += ShowAdditionalText(x, y, w, engine_number);
00717   if (refitable) y += ShowRefitOptionsList(x, y, w, engine_number);
00718 
00719   return y;
00720 }
00721 
00722 static void DrawVehicleEngine(VehicleType type, int x, int y, EngineID engine, SpriteID pal)
00723 {
00724   switch (type) {
00725     case VEH_TRAIN:    DrawTrainEngine(   x, y, engine, pal); break;
00726     case VEH_ROAD:     DrawRoadVehEngine( x, y, engine, pal); break;
00727     case VEH_SHIP:     DrawShipEngine(    x, y, engine, pal); break;
00728     case VEH_AIRCRAFT: DrawAircraftEngine(x, y, engine, pal); break;
00729     default: NOT_REACHED();
00730   }
00731 }
00732 
00742 void DrawEngineList(VehicleType type, int x, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, int count_location, GroupID selected_group)
00743 {
00744   byte step_size = GetVehicleListHeight(type);
00745   byte x_offset = 0;
00746   byte y_offset = 0;
00747 
00748   assert(max <= eng_list->Length());
00749 
00750   switch (type) {
00751     case VEH_TRAIN:
00752       x++; // train and road vehicles use the same offset, except trains are one more pixel to the right
00753       /* Fallthough */
00754     case VEH_ROAD:
00755       x += 26;
00756       x_offset = 30;
00757       y += 2;
00758       y_offset = 4;
00759       break;
00760     case VEH_SHIP:
00761       x += 35;
00762       x_offset = 40;
00763       y += 7;
00764       y_offset = 3;
00765       break;
00766     case VEH_AIRCRAFT:
00767       x += 27;
00768       x_offset = 33;
00769       y += 7;
00770       y_offset = 3;
00771       break;
00772     default: NOT_REACHED();
00773   }
00774 
00775   uint maxw = r - x - x_offset;
00776 
00777   for (; min < max; min++, y += step_size) {
00778     const EngineID engine = (*eng_list)[min];
00779     /* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
00780     const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine);
00781 
00782     SetDParam(0, engine);
00783     DrawStringTruncated(x + x_offset, y, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK, maxw);
00784     DrawVehicleEngine(type, x, y + y_offset, engine, (count_location != 0 && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company));
00785     if (count_location != 0) {
00786       SetDParam(0, num_engines);
00787       DrawStringRightAligned(count_location, y + (GetVehicleListHeight(type) == 14 ? 3 : 8), STR_TINY_BLACK, TC_FROMSTRING);
00788     }
00789   }
00790 }
00791 
00792 
00793 struct BuildVehicleWindow : Window {
00794   VehicleType vehicle_type;
00795   union {
00796     RailTypeByte railtype;
00797     AirportFTAClass::Flags flags;
00798     RoadTypes roadtypes;
00799   } filter;
00800   bool descending_sort_order;
00801   byte sort_criteria;
00802   bool regenerate_list;
00803   bool listview_mode;
00804   EngineID sel_engine;
00805   EngineID rename_engine;
00806   GUIEngineList eng_list;
00807 
00808   BuildVehicleWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc, tile == 0 ? (int)type : tile)
00809   {
00810     this->vehicle_type = type;
00811     int vlh = GetVehicleListHeight(this->vehicle_type);
00812 
00813     ResizeWindow(this, 0, vlh - 14);
00814     this->resize.step_height = vlh;
00815     this->vscroll.cap = 1;
00816     this->widget[BUILD_VEHICLE_WIDGET_LIST].data = 0x101;
00817 
00818     this->resize.width  = this->width;
00819     this->resize.height = this->height;
00820 
00821     this->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_company;
00822 
00823     this->sel_engine      = INVALID_ENGINE;
00824     this->regenerate_list = false;
00825 
00826     this->sort_criteria         = _last_sort_criteria[type];
00827     this->descending_sort_order = _last_sort_order[type];
00828 
00829     switch (type) {
00830       default: NOT_REACHED();
00831       case VEH_TRAIN:
00832         this->filter.railtype = (tile == 0) ? RAILTYPE_END : GetRailType(tile);
00833         break;
00834       case VEH_ROAD:
00835         this->filter.roadtypes = (tile == 0) ? ROADTYPES_ALL : GetRoadTypes(tile);
00836       case VEH_SHIP:
00837         break;
00838       case VEH_AIRCRAFT:
00839         this->filter.flags =
00840           tile == 0 ? AirportFTAClass::ALL : GetStationByTile(tile)->Airport()->flags;
00841         break;
00842     }
00843     this->SetupWindowStrings(type);
00844 
00845     this->listview_mode = (this->window_number <= VEH_END);
00846     /* If we are just viewing the list of vehicles, we do not need the Build button.
00847      * So we just hide it, and enlarge the Rename buton by the now vacant place. */
00848     if (this->listview_mode) {
00849       this->HideWidget(BUILD_VEHICLE_WIDGET_BUILD);
00850       this->widget[BUILD_VEHICLE_WIDGET_RENAME].left = this->widget[BUILD_VEHICLE_WIDGET_BUILD].left;
00851     } else {
00852       /* Both are visible, adjust the size of each */
00853       ResizeButtons(this, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
00854     }
00855 
00856     this->GenerateBuildList(); // generate the list, since we need it in the next line
00857     /* Select the first engine in the list as default when opening the window */
00858     if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0];
00859 
00860     this->FindWindowPlacementAndResize(desc);
00861   }
00862 
00863   /* Setup widget strings to fit the different types of vehicles */
00864   void SetupWindowStrings(VehicleType type)
00865   {
00866     switch (type) {
00867       default: NOT_REACHED();
00868 
00869       case VEH_TRAIN:
00870         this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = this->listview_mode ? STR_AVAILABLE_TRAINS : STR_JUST_STRING;
00871         this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_8843_TRAIN_VEHICLE_SELECTION;
00872         this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_881F_BUILD_VEHICLE;
00873         this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN;
00874         this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_8820_RENAME;
00875         this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_8845_RENAME_TRAIN_VEHICLE_TYPE;
00876         break;
00877 
00878       case VEH_ROAD:
00879         this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = this->listview_mode ? STR_AVAILABLE_ROAD_VEHICLES : STR_9006_NEW_ROAD_VEHICLES;
00880         this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_9026_ROAD_VEHICLE_SELECTION;
00881         this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_9007_BUILD_VEHICLE;
00882         this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_9027_BUILD_THE_HIGHLIGHTED_ROAD;
00883         this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_9034_RENAME;
00884         this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9035_RENAME_ROAD_VEHICLE_TYPE;
00885         break;
00886 
00887       case VEH_SHIP:
00888         this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = this->listview_mode ? STR_AVAILABLE_SHIPS : STR_9808_NEW_SHIPS;
00889         this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_9825_SHIP_SELECTION_LIST_CLICK;
00890         this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_9809_BUILD_SHIP;
00891         this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_9826_BUILD_THE_HIGHLIGHTED_SHIP;
00892         this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_9836_RENAME;
00893         this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9837_RENAME_SHIP_TYPE;
00894         break;
00895 
00896       case VEH_AIRCRAFT:
00897         this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = this->listview_mode ? STR_AVAILABLE_AIRCRAFT : STR_A005_NEW_AIRCRAFT;
00898         this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_A025_AIRCRAFT_SELECTION_LIST;
00899         this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_A006_BUILD_AIRCRAFT;
00900         this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT;
00901         this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_A037_RENAME;
00902         this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_A038_RENAME_AIRCRAFT_TYPE;
00903         break;
00904     }
00905   }
00906 
00907   /* Figure out what train EngineIDs to put in the list */
00908   void GenerateBuildTrainList()
00909   {
00910     EngineID sel_id = INVALID_ENGINE;
00911     int num_engines = 0;
00912     int num_wagons  = 0;
00913 
00914     this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number);
00915 
00916     this->eng_list.Clear();
00917 
00918     /* Make list of all available train engines and wagons.
00919     * Also check to see if the previously selected engine is still available,
00920     * and if not, reset selection to INVALID_ENGINE. This could be the case
00921     * when engines become obsolete and are removed */
00922     const Engine *e;
00923     FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
00924       EngineID eid = e->index;
00925       const RailVehicleInfo *rvi = &e->u.rail;
00926 
00927       if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
00928       if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
00929 
00930       *this->eng_list.Append() = eid;
00931 
00932       if (rvi->railveh_type != RAILVEH_WAGON) {
00933         num_engines++;
00934       } else {
00935         num_wagons++;
00936       }
00937 
00938       if (eid == this->sel_engine) sel_id = eid;
00939     }
00940 
00941     this->sel_engine = sel_id;
00942 
00943     /* make engines first, and then wagons, sorted by ListPositionOfEngine() */
00944     _internal_sort_order = false;
00945     EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
00946 
00947     /* and then sort engines */
00948     _internal_sort_order = this->descending_sort_order;
00949     EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines);
00950 
00951     /* and finally sort wagons */
00952     EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons);
00953   }
00954 
00955   /* Figure out what road vehicle EngineIDs to put in the list */
00956   void GenerateBuildRoadVehList()
00957   {
00958     EngineID sel_id = INVALID_ENGINE;
00959 
00960     this->eng_list.Clear();
00961 
00962     const Engine *e;
00963     FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
00964       EngineID eid = e->index;
00965       if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
00966       if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
00967       *this->eng_list.Append() = eid;
00968 
00969       if (eid == this->sel_engine) sel_id = eid;
00970     }
00971     this->sel_engine = sel_id;
00972   }
00973 
00974   /* Figure out what ship EngineIDs to put in the list */
00975   void GenerateBuildShipList()
00976   {
00977     EngineID sel_id = INVALID_ENGINE;
00978     this->eng_list.Clear();
00979 
00980     const Engine *e;
00981     FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
00982       EngineID eid = e->index;
00983       if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
00984       *this->eng_list.Append() = eid;
00985 
00986       if (eid == this->sel_engine) sel_id = eid;
00987     }
00988     this->sel_engine = sel_id;
00989   }
00990 
00991   /* Figure out what aircraft EngineIDs to put in the list */
00992   void GenerateBuildAircraftList()
00993   {
00994     EngineID sel_id = INVALID_ENGINE;
00995 
00996     this->eng_list.Clear();
00997 
00998     /* Make list of all available planes.
00999     * Also check to see if the previously selected plane is still available,
01000     * and if not, reset selection to INVALID_ENGINE. This could be the case
01001     * when planes become obsolete and are removed */
01002     const Engine *e;
01003     FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
01004       EngineID eid = e->index;
01005       if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
01006       /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
01007       if (!this->listview_mode && !CanAircraftUseStation(eid, this->window_number)) continue;
01008 
01009       *this->eng_list.Append() = eid;
01010       if (eid == this->sel_engine) sel_id = eid;
01011     }
01012 
01013     this->sel_engine = sel_id;
01014   }
01015 
01016   /* Generate the list of vehicles */
01017   void GenerateBuildList()
01018   {
01019     switch (this->vehicle_type) {
01020       default: NOT_REACHED();
01021       case VEH_TRAIN:
01022         this->GenerateBuildTrainList();
01023         return; // trains should not reach the last sorting
01024       case VEH_ROAD:
01025         this->GenerateBuildRoadVehList();
01026         break;
01027       case VEH_SHIP:
01028         this->GenerateBuildShipList();
01029         break;
01030       case VEH_AIRCRAFT:
01031         this->GenerateBuildAircraftList();
01032         break;
01033     }
01034     _internal_sort_order = this->descending_sort_order;
01035     EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]);
01036   }
01037 
01038   void OnClick(Point pt, int widget)
01039   {
01040     switch (widget) {
01041       case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
01042         this->descending_sort_order ^= true;
01043         _last_sort_order[this->vehicle_type] = this->descending_sort_order;
01044         this->regenerate_list = true;
01045         this->SetDirty();
01046         break;
01047 
01048       case BUILD_VEHICLE_WIDGET_LIST: {
01049         uint i = (pt.y - this->widget[BUILD_VEHICLE_WIDGET_LIST].top) / GetVehicleListHeight(this->vehicle_type) + this->vscroll.pos;
01050         size_t num_items = this->eng_list.Length();
01051         this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE;
01052         this->SetDirty();
01053         break;
01054       }
01055 
01056       case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: // Select sorting criteria dropdown menu
01057         ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
01058         break;
01059 
01060       case BUILD_VEHICLE_WIDGET_BUILD: {
01061         EngineID sel_eng = this->sel_engine;
01062         if (sel_eng != INVALID_ENGINE) {
01063           switch (this->vehicle_type) {
01064             default: NOT_REACHED();
01065             case VEH_TRAIN:
01066               DoCommandP(this->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildLoco,
01067                     CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
01068               break;
01069             case VEH_ROAD:
01070               DoCommandP(this->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
01071               break;
01072             case VEH_SHIP:
01073               DoCommandP(this->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
01074               break;
01075             case VEH_AIRCRAFT:
01076               DoCommandP(this->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
01077               break;
01078           }
01079         }
01080         break;
01081       }
01082 
01083       case BUILD_VEHICLE_WIDGET_RENAME: {
01084         EngineID sel_eng = this->sel_engine;
01085         if (sel_eng != INVALID_ENGINE) {
01086           StringID str = STR_NULL;
01087 
01088           this->rename_engine = sel_eng;
01089           switch (this->vehicle_type) {
01090             default: NOT_REACHED();
01091             case VEH_TRAIN:    str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break;
01092             case VEH_ROAD:     str = STR_9036_RENAME_ROAD_VEHICLE_TYPE;  break;
01093             case VEH_SHIP:     str = STR_9838_RENAME_SHIP_TYPE;          break;
01094             case VEH_AIRCRAFT: str = STR_A039_RENAME_AIRCRAFT_TYPE;      break;
01095           }
01096           SetDParam(0, sel_eng);
01097           ShowQueryString(STR_ENGINE_NAME, str, MAX_LENGTH_ENGINE_NAME_BYTES, MAX_LENGTH_ENGINE_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
01098         }
01099         break;
01100       }
01101     }
01102   }
01103 
01104   virtual void OnInvalidateData(int data)
01105   {
01106     this->regenerate_list = true;
01107   }
01108 
01109   virtual void OnPaint()
01110   {
01111     if (this->regenerate_list) {
01112       this->regenerate_list = false;
01113       this->GenerateBuildList();
01114     }
01115 
01116     uint max = min(this->vscroll.pos + this->vscroll.cap, this->eng_list.Length());
01117 
01118     SetVScrollCount(this, this->eng_list.Length());
01119     if (this->vehicle_type == VEH_TRAIN) {
01120       if (this->filter.railtype == RAILTYPE_END) {
01121         SetDParam(0, STR_ALL_AVAIL_RAIL_VEHICLES);
01122       } else {
01123         const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
01124         SetDParam(0, rti->strings.build_caption);
01125       }
01126     }
01127 
01128     /* Set text of sort by dropdown */
01129     this->widget[BUILD_VEHICLE_WIDGET_SORT_DROPDOWN].data = _sort_listing[this->vehicle_type][this->sort_criteria];
01130 
01131     this->DrawWidgets();
01132 
01133     DrawEngineList(this->vehicle_type, this->widget[BUILD_VEHICLE_WIDGET_LIST].left + 2, this->widget[BUILD_VEHICLE_WIDGET_LIST].right, this->widget[BUILD_VEHICLE_WIDGET_LIST].top + 1, &this->eng_list, this->vscroll.pos, max, this->sel_engine, 0, DEFAULT_GROUP);
01134 
01135     if (this->sel_engine != INVALID_ENGINE) {
01136       const Widget *wi = &this->widget[BUILD_VEHICLE_WIDGET_PANEL];
01137       int text_end = DrawVehiclePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, this->sel_engine);
01138 
01139       if (text_end > wi->bottom) {
01140         this->SetDirty();
01141         ResizeWindowForWidget(this, BUILD_VEHICLE_WIDGET_PANEL, 0, text_end - wi->bottom);
01142         this->SetDirty();
01143       }
01144     }
01145 
01146     this->DrawSortButtonState(BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
01147   }
01148 
01149   virtual void OnDoubleClick(Point pt, int widget)
01150   {
01151     if (widget == BUILD_VEHICLE_WIDGET_LIST) {
01152       /* When double clicking, we want to buy a vehicle */
01153       this->OnClick(pt, BUILD_VEHICLE_WIDGET_BUILD);
01154     }
01155   }
01156 
01157   virtual void