00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "engine_base.h"
00014 #include "engine_func.h"
00015 #include "station_base.h"
00016 #include "articulated_vehicles.h"
00017 #include "textbuf_gui.h"
00018 #include "command_func.h"
00019 #include "company_func.h"
00020 #include "vehicle_gui.h"
00021 #include "newgrf_engine.h"
00022 #include "newgrf_text.h"
00023 #include "group.h"
00024 #include "strings_func.h"
00025 #include "window_func.h"
00026 #include "date_func.h"
00027 #include "vehicle_func.h"
00028 #include "widgets/dropdown_func.h"
00029 #include "engine_gui.h"
00030 #include "cargotype.h"
00031 #include "core/geometry_func.hpp"
00032
00033 #include "table/strings.h"
00034
00040 uint GetEngineListHeight(VehicleType type)
00041 {
00042 return max<uint>(FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM, GetVehicleHeight(type));
00043 }
00044
00045 enum BuildVehicleWidgets {
00046 BUILD_VEHICLE_WIDGET_CAPTION,
00047 BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING,
00048 BUILD_VEHICLE_WIDGET_SORT_DROPDOWN,
00049 BUILD_VEHICLE_WIDGET_CARGO_FILTER_DROPDOWN,
00050 BUILD_VEHICLE_WIDGET_LIST,
00051 BUILD_VEHICLE_WIDGET_SCROLLBAR,
00052 BUILD_VEHICLE_WIDGET_PANEL,
00053 BUILD_VEHICLE_WIDGET_BUILD,
00054 BUILD_VEHICLE_WIDGET_BUILD_SEL,
00055 BUILD_VEHICLE_WIDGET_RENAME,
00056 BUILD_VEHICLE_WIDGET_END
00057 };
00058
00059 static const NWidgetPart _nested_build_vehicle_widgets[] = {
00060 NWidget(NWID_HORIZONTAL),
00061 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00062 NWidget(WWT_CAPTION, COLOUR_GREY, BUILD_VEHICLE_WIDGET_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00063 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00064 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00065 EndContainer(),
00066 NWidget(WWT_PANEL, COLOUR_GREY),
00067 NWidget(NWID_HORIZONTAL),
00068 NWidget(NWID_VERTICAL),
00069 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER), SetFill(1, 0),
00070 NWidget(NWID_SPACER), SetFill(1, 1),
00071 EndContainer(),
00072 NWidget(NWID_VERTICAL),
00073 NWidget(WWT_DROPDOWN, COLOUR_GREY, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_SORT_CRITERIA),
00074 NWidget(WWT_DROPDOWN, COLOUR_GREY, BUILD_VEHICLE_WIDGET_CARGO_FILTER_DROPDOWN), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_FILTER_CRITERIA),
00075 EndContainer(),
00076 EndContainer(),
00077 EndContainer(),
00078
00079 NWidget(NWID_HORIZONTAL),
00080 NWidget(WWT_MATRIX, COLOUR_GREY, BUILD_VEHICLE_WIDGET_LIST), SetResize(1, 1), SetFill(1, 0), SetDataTip(0x101, STR_NULL), SetScrollbar(BUILD_VEHICLE_WIDGET_SCROLLBAR),
00081 NWidget(NWID_VSCROLLBAR, COLOUR_GREY, BUILD_VEHICLE_WIDGET_SCROLLBAR),
00082 EndContainer(),
00083
00084 NWidget(WWT_PANEL, COLOUR_GREY, BUILD_VEHICLE_WIDGET_PANEL), SetMinimalSize(240, 122), SetResize(1, 0), EndContainer(),
00085
00086 NWidget(NWID_HORIZONTAL),
00087 NWidget(NWID_SELECTION, INVALID_COLOUR, BUILD_VEHICLE_WIDGET_BUILD_SEL),
00088 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BUILD_VEHICLE_WIDGET_BUILD), SetResize(1, 0), SetFill(1, 0),
00089 EndContainer(),
00090 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BUILD_VEHICLE_WIDGET_RENAME), SetResize(1, 0), SetFill(1, 0),
00091 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00092 EndContainer(),
00093 };
00094
00096 static const CargoID CF_ANY = CT_NO_REFIT;
00097 static const CargoID CF_NONE = CT_INVALID;
00098
00099 static bool _internal_sort_order;
00100 static byte _last_sort_criteria[] = {0, 0, 0, 0};
00101 static bool _last_sort_order[] = {false, false, false, false};
00102 static CargoID _last_filter_criteria[] = {CF_ANY, CF_ANY, CF_ANY, CF_ANY};
00103
00110 static int CDECL EngineNumberSorter(const EngineID *a, const EngineID *b)
00111 {
00112 int r = ListPositionOfEngine(*a) - ListPositionOfEngine(*b);
00113
00114 return _internal_sort_order ? -r : r;
00115 }
00116
00123 static int CDECL EngineIntroDateSorter(const EngineID *a, const EngineID *b)
00124 {
00125 const int va = Engine::Get(*a)->intro_date;
00126 const int vb = Engine::Get(*b)->intro_date;
00127 const int r = va - vb;
00128
00129
00130 if (r == 0) return EngineNumberSorter(a, b);
00131 return _internal_sort_order ? -r : r;
00132 }
00133
00140 static int CDECL EngineNameSorter(const EngineID *a, const EngineID *b)
00141 {
00142 static EngineID last_engine[2] = { INVALID_ENGINE, INVALID_ENGINE };
00143 static char last_name[2][64] = { "\0", "\0" };
00144
00145 const EngineID va = *a;
00146 const EngineID vb = *b;
00147
00148 if (va != last_engine[0]) {
00149 last_engine[0] = va;
00150 SetDParam(0, va);
00151 GetString(last_name[0], STR_ENGINE_NAME, lastof(last_name[0]));
00152 }
00153
00154 if (vb != last_engine[1]) {
00155 last_engine[1] = vb;
00156 SetDParam(0, vb);
00157 GetString(last_name[1], STR_ENGINE_NAME, lastof(last_name[1]));
00158 }
00159
00160 int r = strnatcmp(last_name[0], last_name[1]);
00161
00162
00163 if (r == 0) return EngineNumberSorter(a, b);
00164 return _internal_sort_order ? -r : r;
00165 }
00166
00173 static int CDECL EngineReliabilitySorter(const EngineID *a, const EngineID *b)
00174 {
00175 const int va = Engine::Get(*a)->reliability;
00176 const int vb = Engine::Get(*b)->reliability;
00177 const int r = va - vb;
00178
00179
00180 if (r == 0) return EngineNumberSorter(a, b);
00181 return _internal_sort_order ? -r : r;
00182 }
00183
00190 static int CDECL EngineCostSorter(const EngineID *a, const EngineID *b)
00191 {
00192 Money va = Engine::Get(*a)->GetCost();
00193 Money vb = Engine::Get(*b)->GetCost();
00194 int r = ClampToI32(va - vb);
00195
00196
00197 if (r == 0) return EngineNumberSorter(a, b);
00198 return _internal_sort_order ? -r : r;
00199 }
00200
00207 static int CDECL EngineSpeedSorter(const EngineID *a, const EngineID *b)
00208 {
00209 int va = Engine::Get(*a)->GetDisplayMaxSpeed();
00210 int vb = Engine::Get(*b)->GetDisplayMaxSpeed();
00211 int r = va - vb;
00212
00213
00214 if (r == 0) return EngineNumberSorter(a, b);
00215 return _internal_sort_order ? -r : r;
00216 }
00217
00224 static int CDECL EnginePowerSorter(const EngineID *a, const EngineID *b)
00225 {
00226 int va = Engine::Get(*a)->GetPower();
00227 int vb = Engine::Get(*b)->GetPower();
00228 int r = va - vb;
00229
00230
00231 if (r == 0) return EngineNumberSorter(a, b);
00232 return _internal_sort_order ? -r : r;
00233 }
00234
00241 static int CDECL EngineTractiveEffortSorter(const EngineID *a, const EngineID *b)
00242 {
00243 int va = Engine::Get(*a)->GetDisplayMaxTractiveEffort();
00244 int vb = Engine::Get(*b)->GetDisplayMaxTractiveEffort();
00245 int r = va - vb;
00246
00247
00248 if (r == 0) return EngineNumberSorter(a, b);
00249 return _internal_sort_order ? -r : r;
00250 }
00251
00258 static int CDECL EngineRunningCostSorter(const EngineID *a, const EngineID *b)
00259 {
00260 Money va = Engine::Get(*a)->GetRunningCost();
00261 Money vb = Engine::Get(*b)->GetRunningCost();
00262 int r = ClampToI32(va - vb);
00263
00264
00265 if (r == 0) return EngineNumberSorter(a, b);
00266 return _internal_sort_order ? -r : r;
00267 }
00268
00275 static int CDECL EnginePowerVsRunningCostSorter(const EngineID *a, const EngineID *b)
00276 {
00277 const Engine *e_a = Engine::Get(*a);
00278 const Engine *e_b = Engine::Get(*b);
00279
00280
00281
00282
00283
00284
00285
00286 Money va = (e_a->GetRunningCost()) / max(1U, (uint)e_a->GetPower());
00287 Money vb = (e_b->GetRunningCost()) / max(1U, (uint)e_b->GetPower());
00288 int r = ClampToI32(vb - va);
00289
00290
00291 if (r == 0) return EngineNumberSorter(a, b);
00292 return _internal_sort_order ? -r : r;
00293 }
00294
00295
00296
00303 static int CDECL TrainEngineCapacitySorter(const EngineID *a, const EngineID *b)
00304 {
00305 const RailVehicleInfo *rvi_a = RailVehInfo(*a);
00306 const RailVehicleInfo *rvi_b = RailVehInfo(*b);
00307
00308 int va = GetTotalCapacityOfArticulatedParts(*a) * (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
00309 int vb = GetTotalCapacityOfArticulatedParts(*b) * (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1);
00310 int r = va - vb;
00311
00312
00313 if (r == 0) return EngineNumberSorter(a, b);
00314 return _internal_sort_order ? -r : r;
00315 }
00316
00323 static int CDECL TrainEnginesThenWagonsSorter(const EngineID *a, const EngineID *b)
00324 {
00325 int val_a = (RailVehInfo(*a)->railveh_type == RAILVEH_WAGON ? 1 : 0);
00326 int val_b = (RailVehInfo(*b)->railveh_type == RAILVEH_WAGON ? 1 : 0);
00327 int r = val_a - val_b;
00328
00329
00330 if (r == 0) return EngineNumberSorter(a, b);
00331 return _internal_sort_order ? -r : r;
00332 }
00333
00334
00335
00342 static int CDECL RoadVehEngineCapacitySorter(const EngineID *a, const EngineID *b)
00343 {
00344 int va = GetTotalCapacityOfArticulatedParts(*a);
00345 int vb = GetTotalCapacityOfArticulatedParts(*b);
00346 int r = va - vb;
00347
00348
00349 if (r == 0) return EngineNumberSorter(a, b);
00350 return _internal_sort_order ? -r : r;
00351 }
00352
00353
00354
00361 static int CDECL ShipEngineCapacitySorter(const EngineID *a, const EngineID *b)
00362 {
00363 const Engine *e_a = Engine::Get(*a);
00364 const Engine *e_b = Engine::Get(*b);
00365
00366 int va = e_a->GetDisplayDefaultCapacity();
00367 int vb = e_b->GetDisplayDefaultCapacity();
00368 int r = va - vb;
00369
00370
00371 if (r == 0) return EngineNumberSorter(a, b);
00372 return _internal_sort_order ? -r : r;
00373 }
00374
00375
00376
00383 static int CDECL AircraftEngineCargoSorter(const EngineID *a, const EngineID *b)
00384 {
00385 const Engine *e_a = Engine::Get(*a);
00386 const Engine *e_b = Engine::Get(*b);
00387
00388 uint16 mail_a, mail_b;
00389 int va = e_a->GetDisplayDefaultCapacity(&mail_a);
00390 int vb = e_b->GetDisplayDefaultCapacity(&mail_b);
00391 int r = va - vb;
00392
00393 if (r == 0) {
00394
00395 r = mail_a - mail_b;
00396
00397 if (r == 0) {
00398
00399 return EngineNumberSorter(a, b);
00400 }
00401 }
00402 return _internal_sort_order ? -r : r;
00403 }
00404
00405 static EngList_SortTypeFunction * const _sorter[][11] = {{
00406
00407 &EngineNumberSorter,
00408 &EngineCostSorter,
00409 &EngineSpeedSorter,
00410 &EnginePowerSorter,
00411 &EngineTractiveEffortSorter,
00412 &EngineIntroDateSorter,
00413 &EngineNameSorter,
00414 &EngineRunningCostSorter,
00415 &EnginePowerVsRunningCostSorter,
00416 &EngineReliabilitySorter,
00417 &TrainEngineCapacitySorter,
00418 }, {
00419
00420 &EngineNumberSorter,
00421 &EngineCostSorter,
00422 &EngineSpeedSorter,
00423 &EnginePowerSorter,
00424 &EngineTractiveEffortSorter,
00425 &EngineIntroDateSorter,
00426 &EngineNameSorter,
00427 &EngineRunningCostSorter,
00428 &EnginePowerVsRunningCostSorter,
00429 &EngineReliabilitySorter,
00430 &RoadVehEngineCapacitySorter,
00431 }, {
00432
00433 &EngineNumberSorter,
00434 &EngineCostSorter,
00435 &EngineSpeedSorter,
00436 &EngineIntroDateSorter,
00437 &EngineNameSorter,
00438 &EngineRunningCostSorter,
00439 &EngineReliabilitySorter,
00440 &ShipEngineCapacitySorter,
00441 }, {
00442
00443 &EngineNumberSorter,
00444 &EngineCostSorter,
00445 &EngineSpeedSorter,
00446 &EngineIntroDateSorter,
00447 &EngineNameSorter,
00448 &EngineRunningCostSorter,
00449 &EngineReliabilitySorter,
00450 &AircraftEngineCargoSorter,
00451 }};
00452
00453 static const StringID _sort_listing[][12] = {{
00454
00455 STR_SORT_BY_ENGINE_ID,
00456 STR_SORT_BY_COST,
00457 STR_SORT_BY_MAX_SPEED,
00458 STR_SORT_BY_POWER,
00459 STR_SORT_BY_TRACTIVE_EFFORT,
00460 STR_SORT_BY_INTRO_DATE,
00461 STR_SORT_BY_NAME,
00462 STR_SORT_BY_RUNNING_COST,
00463 STR_SORT_BY_POWER_VS_RUNNING_COST,
00464 STR_SORT_BY_RELIABILITY,
00465 STR_SORT_BY_CARGO_CAPACITY,
00466 INVALID_STRING_ID
00467 }, {
00468
00469 STR_SORT_BY_ENGINE_ID,
00470 STR_SORT_BY_COST,
00471 STR_SORT_BY_MAX_SPEED,
00472 STR_SORT_BY_POWER,
00473 STR_SORT_BY_TRACTIVE_EFFORT,
00474 STR_SORT_BY_INTRO_DATE,
00475 STR_SORT_BY_NAME,
00476 STR_SORT_BY_RUNNING_COST,
00477 STR_SORT_BY_POWER_VS_RUNNING_COST,
00478 STR_SORT_BY_RELIABILITY,
00479 STR_SORT_BY_CARGO_CAPACITY,
00480 INVALID_STRING_ID
00481 }, {
00482
00483 STR_SORT_BY_ENGINE_ID,
00484 STR_SORT_BY_COST,
00485 STR_SORT_BY_MAX_SPEED,
00486 STR_SORT_BY_INTRO_DATE,
00487 STR_SORT_BY_NAME,
00488 STR_SORT_BY_RUNNING_COST,
00489 STR_SORT_BY_RELIABILITY,
00490 STR_SORT_BY_CARGO_CAPACITY,
00491 INVALID_STRING_ID
00492 }, {
00493
00494 STR_SORT_BY_ENGINE_ID,
00495 STR_SORT_BY_COST,
00496 STR_SORT_BY_MAX_SPEED,
00497 STR_SORT_BY_INTRO_DATE,
00498 STR_SORT_BY_NAME,
00499 STR_SORT_BY_RUNNING_COST,
00500 STR_SORT_BY_RELIABILITY,
00501 STR_SORT_BY_CARGO_CAPACITY,
00502 INVALID_STRING_ID
00503 }};
00504
00506 static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid)
00507 {
00508 if (cid == CF_ANY) return true;
00509 uint32 refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true);
00510 return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid));
00511 }
00512
00513 static GUIEngineList::FilterFunction * const _filter_funcs[] = {
00514 &CargoFilter,
00515 };
00516
00517 static int DrawCargoCapacityInfo(int left, int right, int y, EngineID engine, bool refittable)
00518 {
00519 CargoArray cap = GetCapacityOfArticulatedParts(engine);
00520
00521 for (CargoID c = 0; c < NUM_CARGO; c++) {
00522 if (cap[c] == 0) continue;
00523
00524 SetDParam(0, c);
00525 SetDParam(1, cap[c]);
00526 SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
00527 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
00528 y += FONT_HEIGHT_NORMAL;
00529
00530
00531 refittable = false;
00532 }
00533
00534 return y;
00535 }
00536
00537
00538 static int DrawRailWagonPurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi)
00539 {
00540 const Engine *e = Engine::Get(engine_number);
00541
00542
00543 SetDParam(0, e->GetCost());
00544 DrawString(left, right, y, STR_PURCHASE_INFO_COST);
00545 y += FONT_HEIGHT_NORMAL;
00546
00547
00548 uint weight = e->GetDisplayWeight();
00549 SetDParam(0, weight);
00550 uint cargo_weight = (e->CanCarryCargo() ? CargoSpec::Get(e->GetDefaultCargoType())->weight * e->GetDisplayDefaultCapacity() >> 4 : 0);
00551 SetDParam(1, cargo_weight + weight);
00552 DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
00553 y += FONT_HEIGHT_NORMAL;
00554
00555
00556 if (_settings_game.vehicle.wagon_speed_limits) {
00557 uint max_speed = e->GetDisplayMaxSpeed();
00558 if (max_speed > 0) {
00559 SetDParam(0, max_speed);
00560 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED);
00561 y += FONT_HEIGHT_NORMAL;
00562 }
00563 }
00564
00565
00566 if (rvi->running_cost_class != INVALID_PRICE) {
00567 SetDParam(0, e->GetRunningCost());
00568 DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
00569 y += FONT_HEIGHT_NORMAL;
00570 }
00571
00572 return y;
00573 }
00574
00575
00576 static int DrawRailEnginePurchaseInfo(int left, int right, int y, EngineID engine_number, const RailVehicleInfo *rvi)
00577 {
00578 const Engine *e = Engine::Get(engine_number);
00579
00580
00581 SetDParam(0, e->GetCost());
00582 SetDParam(1, e->GetDisplayWeight());
00583 DrawString(left, right, y, STR_PURCHASE_INFO_COST_WEIGHT);
00584 y += FONT_HEIGHT_NORMAL;
00585
00586
00587 SetDParam(0, e->GetDisplayMaxSpeed());
00588 SetDParam(1, e->GetPower());
00589 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
00590 y += FONT_HEIGHT_NORMAL;
00591
00592
00593 if (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(rvi->railtype)->acceleration_type != 2) {
00594 SetDParam(0, e->GetDisplayMaxTractiveEffort());
00595 DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
00596 y += FONT_HEIGHT_NORMAL;
00597 }
00598
00599
00600 if (rvi->running_cost_class != INVALID_PRICE) {
00601 SetDParam(0, e->GetRunningCost());
00602 DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
00603 y += FONT_HEIGHT_NORMAL;
00604 }
00605
00606
00607 if (rvi->pow_wag_power != 0) {
00608 SetDParam(0, rvi->pow_wag_power);
00609 SetDParam(1, rvi->pow_wag_weight);
00610 DrawString(left, right, y, STR_PURCHASE_INFO_PWAGPOWER_PWAGWEIGHT);
00611 y += FONT_HEIGHT_NORMAL;
00612 }
00613
00614 return y;
00615 }
00616
00617
00618 static int DrawRoadVehPurchaseInfo(int left, int right, int y, EngineID engine_number)
00619 {
00620 const Engine *e = Engine::Get(engine_number);
00621
00622 if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) {
00623
00624 SetDParam(0, e->GetCost());
00625 DrawString(left, right, y, STR_PURCHASE_INFO_COST);
00626 y += FONT_HEIGHT_NORMAL;
00627
00628
00629 int16 weight = e->GetDisplayWeight();
00630 SetDParam(0, weight);
00631 uint cargo_weight = CargoSpec::Get(e->GetDefaultCargoType())->weight * GetTotalCapacityOfArticulatedParts(engine_number) / 16;
00632 SetDParam(1, cargo_weight + weight);
00633 DrawString(left, right, y, STR_PURCHASE_INFO_WEIGHT_CWEIGHT);
00634 y += FONT_HEIGHT_NORMAL;
00635
00636
00637 SetDParam(0, e->GetDisplayMaxSpeed());
00638 SetDParam(1, e->GetPower());
00639 DrawString(left, right, y, STR_PURCHASE_INFO_SPEED_POWER);
00640 y += FONT_HEIGHT_NORMAL;
00641
00642
00643 SetDParam(0, e->GetDisplayMaxTractiveEffort());
00644 DrawString(left, right, y, STR_PURCHASE_INFO_MAX_TE);
00645 y += FONT_HEIGHT_NORMAL;
00646 } else {
00647
00648 SetDParam(0, e->GetCost());
00649 SetDParam(1, e->GetDisplayMaxSpeed());
00650 DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
00651 y += FONT_HEIGHT_NORMAL;
00652 }
00653
00654
00655 SetDParam(0, e->GetRunningCost());
00656 DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
00657 y += FONT_HEIGHT_NORMAL;
00658
00659 return y;
00660 }
00661
00662
00663 static int DrawShipPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable)
00664 {
00665 const Engine *e = Engine::Get(engine_number);
00666
00667
00668 SetDParam(0, e->GetCost());
00669 SetDParam(1, e->GetDisplayMaxSpeed());
00670 DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
00671 y += FONT_HEIGHT_NORMAL;
00672
00673
00674 SetDParam(0, e->GetDefaultCargoType());
00675 SetDParam(1, e->GetDisplayDefaultCapacity());
00676 SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
00677 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
00678 y += FONT_HEIGHT_NORMAL;
00679
00680
00681 SetDParam(0, e->GetRunningCost());
00682 DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
00683 y += FONT_HEIGHT_NORMAL;
00684
00685 return y;
00686 }
00687
00688
00689 static int DrawAircraftPurchaseInfo(int left, int right, int y, EngineID engine_number, bool refittable)
00690 {
00691 const Engine *e = Engine::Get(engine_number);
00692 CargoID cargo = e->GetDefaultCargoType();
00693
00694
00695 SetDParam(0, e->GetCost());
00696 SetDParam(1, e->GetDisplayMaxSpeed());
00697 DrawString(left, right, y, STR_PURCHASE_INFO_COST_SPEED);
00698 y += FONT_HEIGHT_NORMAL;
00699
00700
00701 uint16 mail_capacity;
00702 uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
00703 if (mail_capacity > 0) {
00704 SetDParam(0, cargo);
00705 SetDParam(1, capacity);
00706 SetDParam(2, CT_MAIL);
00707 SetDParam(3, mail_capacity);
00708 DrawString(left, right, y, STR_PURCHASE_INFO_AIRCRAFT_CAPACITY);
00709 } else {
00710
00711
00712 SetDParam(0, cargo);
00713 SetDParam(1, capacity);
00714 SetDParam(2, refittable ? STR_PURCHASE_INFO_REFITTABLE : STR_EMPTY);
00715 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
00716 }
00717 y += FONT_HEIGHT_NORMAL;
00718
00719
00720 SetDParam(0, e->GetRunningCost());
00721 DrawString(left, right, y, STR_PURCHASE_INFO_RUNNINGCOST);
00722 y += FONT_HEIGHT_NORMAL;
00723
00724 return y;
00725 }
00726
00735 static uint ShowAdditionalText(int left, int right, int y, EngineID engine)
00736 {
00737 uint16 callback = GetVehicleCallback(CBID_VEHICLE_ADDITIONAL_TEXT, 0, 0, engine, NULL);
00738 if (callback == CALLBACK_FAILED) return y;
00739
00740
00741 SetDParam(0, GetGRFStringID(GetEngineGRFID(engine), 0xD000 + callback));
00742 PrepareTextRefStackUsage(0);
00743 uint result = DrawStringMultiLine(left, right, y, INT32_MAX, STR_BLACK_STRING);
00744 StopTextRefStackUsage();
00745 return result;
00746 }
00747
00754 int DrawVehiclePurchaseInfo(int left, int right, int y, EngineID engine_number)
00755 {
00756 const Engine *e = Engine::Get(engine_number);
00757 YearMonthDay ymd;
00758 ConvertDateToYMD(e->intro_date, &ymd);
00759 bool refittable = IsArticulatedVehicleRefittable(engine_number);
00760 bool articulated_cargo = false;
00761
00762 switch (e->type) {
00763 default: NOT_REACHED();
00764 case VEH_TRAIN:
00765 if (e->u.rail.railveh_type == RAILVEH_WAGON) {
00766 y = DrawRailWagonPurchaseInfo(left, right, y, engine_number, &e->u.rail);
00767 } else {
00768 y = DrawRailEnginePurchaseInfo(left, right, y, engine_number, &e->u.rail);
00769 }
00770 articulated_cargo = true;
00771 break;
00772
00773 case VEH_ROAD:
00774 y = DrawRoadVehPurchaseInfo(left, right, y, engine_number);
00775 articulated_cargo = true;
00776 break;
00777
00778 case VEH_SHIP:
00779 y = DrawShipPurchaseInfo(left, right, y, engine_number, refittable);
00780 break;
00781
00782 case VEH_AIRCRAFT:
00783 y = DrawAircraftPurchaseInfo(left, right, y, engine_number, refittable);
00784 break;
00785 }
00786
00787 if (articulated_cargo) {
00788
00789 int new_y = DrawCargoCapacityInfo(left, right, y, engine_number, refittable);
00790
00791 if (new_y == y) {
00792 SetDParam(0, CT_INVALID);
00793 SetDParam(2, STR_EMPTY);
00794 DrawString(left, right, y, STR_PURCHASE_INFO_CAPACITY);
00795 y += FONT_HEIGHT_NORMAL;
00796 } else {
00797 y = new_y;
00798 }
00799 }
00800
00801
00802 if (e->type != VEH_TRAIN || e->u.rail.railveh_type != RAILVEH_WAGON) {
00803
00804 SetDParam(0, ymd.year);
00805 SetDParam(1, e->GetLifeLengthInDays() / DAYS_IN_LEAP_YEAR);
00806 DrawString(left, right, y, STR_PURCHASE_INFO_DESIGNED_LIFE);
00807 y += FONT_HEIGHT_NORMAL;
00808
00809
00810 SetDParam(0, ToPercent16(e->reliability));
00811 DrawString(left, right, y, STR_PURCHASE_INFO_RELIABILITY);
00812 y += FONT_HEIGHT_NORMAL;
00813 }
00814
00815
00816 y = ShowAdditionalText(left, right, y, engine_number);
00817 if (refittable) y = ShowRefitOptionsList(left, right, y, engine_number);
00818
00819 return y;
00820 }
00821
00835 void DrawEngineList(VehicleType type, int l, int r, int y, const GUIEngineList *eng_list, uint16 min, uint16 max, EngineID selected_id, bool show_count, GroupID selected_group)
00836 {
00837 static const int sprite_widths[] = { 60, 60, 76, 67 };
00838 static const int sprite_y_offsets[] = { -1, -1, -2, -2 };
00839
00840
00841 assert((uint)type < lengthof(sprite_widths));
00842 assert_compile(lengthof(sprite_y_offsets) == lengthof(sprite_widths));
00843 assert(max <= eng_list->Length());
00844
00845 bool rtl = _current_text_dir == TD_RTL;
00846 int step_size = GetEngineListHeight(type);
00847 int sprite_width = sprite_widths[type];
00848
00849 int sprite_x = (rtl ? r - sprite_width / 2 : l + sprite_width / 2) - 1;
00850 int sprite_y_offset = sprite_y_offsets[type] + step_size / 2;
00851
00852 int text_left = l + (rtl ? WD_FRAMERECT_LEFT : sprite_width);
00853 int text_right = r - (rtl ? sprite_width : WD_FRAMERECT_RIGHT);
00854
00855 int normal_text_y_offset = (step_size - FONT_HEIGHT_NORMAL) / 2;
00856 int small_text_y_offset = step_size - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1;
00857
00858 for (; min < max; min++, y += step_size) {
00859 const EngineID engine = (*eng_list)[min];
00860
00861 const uint num_engines = GetGroupNumEngines(_local_company, selected_group, engine);
00862
00863 SetDParam(0, engine);
00864 DrawString(text_left, text_right, y + normal_text_y_offset, STR_ENGINE_NAME, engine == selected_id ? TC_WHITE : TC_BLACK);
00865 DrawVehicleEngine(l, r, sprite_x, y + sprite_y_offset, engine, (show_count && num_engines == 0) ? PALETTE_CRASH : GetEnginePalette(engine, _local_company));
00866 if (show_count) {
00867 SetDParam(0, num_engines);
00868 DrawString(text_left, text_right, y + small_text_y_offset, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT);
00869 }
00870 }
00871 }
00872
00873
00874 struct BuildVehicleWindow : Window {
00875 VehicleType vehicle_type;
00876 union {
00877 RailTypeByte railtype;
00878 RoadTypes roadtypes;
00879 } filter;
00880 bool descending_sort_order;
00881 byte sort_criteria;
00882 bool listview_mode;
00883 EngineID sel_engine;
00884 EngineID rename_engine;
00885 GUIEngineList eng_list;
00886 CargoID cargo_filter[NUM_CARGO + 2];
00887 StringID cargo_filter_texts[NUM_CARGO + 3];
00888 byte cargo_filter_criteria;
00889 int details_height;
00890 Scrollbar *vscroll;
00891
00892 BuildVehicleWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window()
00893 {
00894 this->vehicle_type = type;
00895 this->window_number = tile == INVALID_TILE ? (int)type : tile;
00896
00897 this->sel_engine = INVALID_ENGINE;
00898
00899 this->sort_criteria = _last_sort_criteria[type];
00900 this->descending_sort_order = _last_sort_order[type];
00901
00902 switch (type) {
00903 default: NOT_REACHED();
00904 case VEH_TRAIN:
00905 this->filter.railtype = (tile == INVALID_TILE) ? RAILTYPE_END : GetRailType(tile);
00906 break;
00907 case VEH_ROAD:
00908 this->filter.roadtypes = (tile == INVALID_TILE) ? ROADTYPES_ALL : GetRoadTypes(tile);
00909 case VEH_SHIP:
00910 case VEH_AIRCRAFT:
00911 break;
00912 }
00913
00914 this->listview_mode = (this->window_number <= VEH_END);
00915
00916 this->CreateNestedTree(desc);
00917
00918 this->vscroll = this->GetScrollbar(BUILD_VEHICLE_WIDGET_SCROLLBAR);
00919
00920
00921
00922 if (this->listview_mode) this->GetWidget<NWidgetStacked>(BUILD_VEHICLE_WIDGET_BUILD_SEL)->SetDisplayedPlane(SZSP_NONE);
00923
00924 NWidgetCore *widget = this->GetWidget<NWidgetCore>(BUILD_VEHICLE_WIDGET_LIST);
00925 widget->tool_tip = STR_BUY_VEHICLE_TRAIN_LIST_TOOLTIP + type;
00926
00927 widget = this->GetWidget<NWidgetCore>(BUILD_VEHICLE_WIDGET_BUILD);
00928 widget->widget_data = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_BUTTON + type;
00929 widget->tool_tip = STR_BUY_VEHICLE_TRAIN_BUY_VEHICLE_TOOLTIP + type;
00930
00931 widget = this->GetWidget<NWidgetCore>(BUILD_VEHICLE_WIDGET_RENAME);
00932 widget->widget_data = STR_BUY_VEHICLE_TRAIN_RENAME_BUTTON + type;
00933 widget->tool_tip = STR_BUY_VEHICLE_TRAIN_RENAME_TOOLTIP + type;
00934
00935 this->details_height = ((this->vehicle_type == VEH_TRAIN) ? 10 : 9) * FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00936
00937 this->FinishInitNested(desc, tile == INVALID_TILE ? (int)type : tile);
00938
00939 this->owner = (tile != INVALID_TILE) ? GetTileOwner(tile) : _local_company;
00940
00941 this->eng_list.ForceRebuild();
00942 this->GenerateBuildList();
00943
00944 if (this->eng_list.Length() > 0) this->sel_engine = this->eng_list[0];
00945 }
00946
00948 void SetCargoFilterArray()
00949 {
00950 uint filter_items = 0;
00951
00952
00953 this->cargo_filter[filter_items] = CF_ANY;
00954 this->cargo_filter_texts[filter_items] = STR_PURCHASE_INFO_ALL_TYPES;
00955 filter_items++;
00956
00957
00958
00959 if (this->vehicle_type == VEH_TRAIN) {
00960 this->cargo_filter[filter_items] = CF_NONE;
00961 this->cargo_filter_texts[filter_items] = STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE;
00962 filter_items++;
00963 }
00964
00965
00966 const CargoSpec *cs;
00967 FOR_ALL_SORTED_STANDARD_CARGOSPECS(cs) {
00968 this->cargo_filter[filter_items] = cs->Index();
00969 this->cargo_filter_texts[filter_items] = cs->name;
00970 filter_items++;
00971 }
00972
00973
00974 this->cargo_filter_texts[filter_items] = INVALID_STRING_ID;
00975
00976
00977 this->cargo_filter_criteria = 0;
00978
00979
00980 for (uint i = 0; i < filter_items; i++) {
00981 if (this->cargo_filter[i] == _last_filter_criteria[this->vehicle_type]) {
00982 this->cargo_filter_criteria = i;
00983 break;
00984 }
00985 }
00986
00987 this->eng_list.SetFilterFuncs(_filter_funcs);
00988 this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
00989 }
00990
00991 void OnInit()
00992 {
00993 this->SetCargoFilterArray();
00994 }
00995
00997 void FilterEngineList()
00998 {
00999 this->eng_list.Filter(this->cargo_filter[this->cargo_filter_criteria]);
01000 if (0 == this->eng_list.Length()) {
01001 this->sel_engine = INVALID_ENGINE;
01002 } else if (!this->eng_list.Contains(this->sel_engine)) {
01003 this->sel_engine = this->eng_list[0];
01004 }
01005 }
01006
01008 bool FilterSingleEngine(EngineID eid)
01009 {
01010 CargoID filter_type = this->cargo_filter[this->cargo_filter_criteria];
01011 return (filter_type == CF_ANY || CargoFilter(&eid, filter_type));
01012 }
01013
01014
01015 void GenerateBuildTrainList()
01016 {
01017 EngineID sel_id = INVALID_ENGINE;
01018 int num_engines = 0;
01019 int num_wagons = 0;
01020
01021 this->filter.railtype = (this->listview_mode) ? RAILTYPE_END : GetRailType(this->window_number);
01022
01023 this->eng_list.Clear();
01024
01025
01026
01027
01028
01029 const Engine *e;
01030 FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
01031 EngineID eid = e->index;
01032 const RailVehicleInfo *rvi = &e->u.rail;
01033
01034 if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
01035 if (!IsEngineBuildable(eid, VEH_TRAIN, _local_company)) continue;
01036
01037
01038 if (!FilterSingleEngine(eid)) continue;
01039
01040 *this->eng_list.Append() = eid;
01041
01042 if (rvi->railveh_type != RAILVEH_WAGON) {
01043 num_engines++;
01044 } else {
01045 num_wagons++;
01046 }
01047
01048 if (eid == this->sel_engine) sel_id = eid;
01049 }
01050
01051 this->sel_engine = sel_id;
01052
01053
01054 _internal_sort_order = false;
01055 EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
01056
01057
01058 _internal_sort_order = this->descending_sort_order;
01059 EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines);
01060
01061
01062 EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons);
01063 }
01064
01065
01066 void GenerateBuildRoadVehList()
01067 {
01068 EngineID sel_id = INVALID_ENGINE;
01069
01070 this->eng_list.Clear();
01071
01072 const Engine *e;
01073 FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
01074 EngineID eid = e->index;
01075 if (!IsEngineBuildable(eid, VEH_ROAD, _local_company)) continue;
01076 if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
01077 *this->eng_list.Append() = eid;
01078
01079 if (eid == this->sel_engine) sel_id = eid;
01080 }
01081 this->sel_engine = sel_id;
01082 }
01083
01084
01085 void GenerateBuildShipList()
01086 {
01087 EngineID sel_id = INVALID_ENGINE;
01088 this->eng_list.Clear();
01089
01090 const Engine *e;
01091 FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
01092 EngineID eid = e->index;
01093 if (!IsEngineBuildable(eid, VEH_SHIP, _local_company)) continue;
01094 *this->eng_list.Append() = eid;
01095
01096 if (eid == this->sel_engine) sel_id = eid;
01097 }
01098 this->sel_engine = sel_id;
01099 }
01100
01101
01102 void GenerateBuildAircraftList()
01103 {
01104 EngineID sel_id = INVALID_ENGINE;
01105
01106 this->eng_list.Clear();
01107
01108 const Station *st = this->listview_mode ? NULL : Station::GetByTile(this->window_number);
01109
01110
01111
01112
01113
01114 const Engine *e;
01115 FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
01116 EngineID eid = e->index;
01117 if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_company)) continue;
01118
01119 if (!this->listview_mode && !CanVehicleUseStation(eid, st)) continue;
01120
01121 *this->eng_list.Append() = eid;
01122 if (eid == this->sel_engine) sel_id = eid;
01123 }
01124
01125 this->sel_engine = sel_id;
01126 }
01127
01128
01129 void GenerateBuildList()
01130 {
01131 if (!this->eng_list.NeedRebuild()) return;
01132 switch (this->vehicle_type) {
01133 default: NOT_REACHED();
01134 case VEH_TRAIN:
01135 this->GenerateBuildTrainList();
01136 this->eng_list.Compact();
01137 this->eng_list.RebuildDone();
01138 return;
01139 case VEH_ROAD:
01140 this->GenerateBuildRoadVehList();
01141 break;
01142 case VEH_SHIP:
01143 this->GenerateBuildShipList();
01144 break;
01145 case VEH_AIRCRAFT:
01146 this->GenerateBuildAircraftList();
01147 break;
01148 }
01149
01150 this->FilterEngineList();
01151
01152 _internal_sort_order = this->descending_sort_order;
01153 EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]);
01154
01155 this->eng_list.Compact();
01156 this->eng_list.RebuildDone();
01157 }
01158
01159 void OnClick(Point pt, int widget, int click_count)
01160 {
01161 switch (widget) {
01162 case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
01163 this->descending_sort_order ^= true;
01164 _last_sort_order[this->vehicle_type] = this->descending_sort_order;
01165 this->eng_list.ForceRebuild();
01166 this->SetDirty();
01167 break;
01168
01169 case BUILD_VEHICLE_WIDGET_LIST: {
01170 uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, BUILD_VEHICLE_WIDGET_LIST);
01171 size_t num_items = this->eng_list.Length();
01172 this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE;
01173 this->SetDirty();
01174 if (click_count > 1 && !this->listview_mode) this->OnClick(pt, BUILD_VEHICLE_WIDGET_BUILD, 1);
01175 break;
01176 }
01177
01178 case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: {
01179 uint32 hidden_mask = 0;
01180
01181 if (this->vehicle_type == VEH_ROAD &&
01182 _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
01183 SetBit(hidden_mask, 3);
01184 SetBit(hidden_mask, 4);
01185 SetBit(hidden_mask, 8);
01186 }
01187
01188 if (this->vehicle_type == VEH_TRAIN &&
01189 _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
01190 SetBit(hidden_mask, 4);
01191 }
01192 ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, hidden_mask);
01193 break;
01194 }
01195
01196 case BUILD_VEHICLE_WIDGET_CARGO_FILTER_DROPDOWN:
01197 ShowDropDownMenu(this, this->cargo_filter_texts, this->cargo_filter_criteria, BUILD_VEHICLE_WIDGET_CARGO_FILTER_DROPDOWN, 0, 0);
01198 break;
01199
01200 case BUILD_VEHICLE_WIDGET_BUILD: {
01201 EngineID sel_eng = this->sel_engine;
01202 if (sel_eng != INVALID_ENGINE) {
01203 CommandCallback *callback = (this->vehicle_type == VEH_TRAIN && RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildPrimaryVehicle;
01204 DoCommandP(this->window_number, sel_eng, 0, GetCmdBuildVeh(this->vehicle_type), callback);
01205 }
01206 break;
01207 }
01208
01209 case BUILD_VEHICLE_WIDGET_RENAME: {
01210 EngineID sel_eng = this->sel_engine;
01211 if (sel_eng != INVALID_ENGINE) {
01212 this->rename_engine = sel_eng;
01213 SetDParam(0, sel_eng);
01214 ShowQueryString(STR_ENGINE_NAME, STR_QUERY_RENAME_TRAIN_TYPE_CAPTION + this->vehicle_type, MAX_LENGTH_ENGINE_NAME_CHARS, MAX_LENGTH_ENGINE_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
01215 }
01216 break;
01217 }
01218 }
01219 }
01220
01221 virtual void OnInvalidateData(int data)
01222 {
01223
01224 if (this->vehicle_type == VEH_ROAD &&
01225 _settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL &&
01226 this->sort_criteria > 7) {
01227 this->sort_criteria = 0;
01228 _last_sort_criteria[VEH_ROAD] = 0;
01229 }
01230 this->eng_list.ForceRebuild();
01231 }
01232
01233 virtual void SetStringParameters(int widget) const
01234 {
01235 switch (widget) {
01236 case BUILD_VEHICLE_WIDGET_CAPTION:
01237 if (this->vehicle_type == VEH_TRAIN && !this->listview_mode) {
01238 const RailtypeInfo *rti = GetRailTypeInfo(this->filter.railtype);
01239 SetDParam(0, rti->strings.build_caption);
01240 } else {
01241 SetDParam(0, (this->listview_mode ? STR_VEHICLE_LIST_AVAILABLE_TRAINS : STR_BUY_VEHICLE_TRAIN_ALL_CAPTION) + this->vehicle_type);
01242 }
01243 break;
01244
01245 case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:
01246 SetDParam(0, _sort_listing[this->vehicle_type][this->sort_criteria]);
01247 break;
01248
01249 case BUILD_VEHICLE_WIDGET_CARGO_FILTER_DROPDOWN:
01250 SetDParam(0, this->cargo_filter_texts[this->cargo_filter_criteria]);
01251 }
01252 }
01253
01254 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01255 {
01256 switch (widget) {
01257 case BUILD_VEHICLE_WIDGET_LIST:
01258 resize->height = GetEngineListHeight(this->vehicle_type);
01259 size->height = 3 * resize->height;
01260 break;
01261
01262 case BUILD_VEHICLE_WIDGET_PANEL:
01263 size->height = this->details_height;
01264 break;
01265
01266 case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING: {
01267 Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
01268 d.width += padding.width + WD_SORTBUTTON_ARROW_WIDTH * 2;
01269 d.height += padding.height;
01270 *size = maxdim(*size, d);
01271 break;
01272 }
01273 }
01274 }
01275
01276 virtual void DrawWidget(const Rect &r, int widget) const
01277 {
01278 switch (widget) {
01279 case BUILD_VEHICLE_WIDGET_LIST:
01280 DrawEngineList(this->vehicle_type, r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, &this->eng_list, this->vscroll->GetPosition(), min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->eng_list.Length()), this->sel_engine, false, DEFAULT_GROUP);
01281 break;
01282
01283 case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
01284 this->DrawSortButtonState(BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
01285 break;
01286 }
01287 }
01288
01289 virtual void OnPaint()
01290 {
01291 this->GenerateBuildList();
01292 this->vscroll->SetCount(this->eng_list.Length());
01293
01294 this->DrawWidgets();
01295
01296 if (!this->IsShaded()) {
01297 int needed_height = this->details_height;
01298
01299 if (this->sel_engine != INVALID_ENGINE) {
01300 NWidgetBase *nwi = this->GetWidget<NWidgetBase>(BUILD_VEHICLE_WIDGET_PANEL);
01301 int text_end = DrawVehiclePurchaseInfo(nwi->pos_x + WD_FRAMETEXT_LEFT, nwi->pos_x + nwi->current_x - WD_FRAMETEXT_RIGHT,
01302 nwi->pos_y + WD_FRAMERECT_TOP, this->sel_engine);
01303 needed_height = max(needed_height, text_end - (int)nwi->pos_y + WD_FRAMERECT_BOTTOM);
01304 }
01305 if (needed_height != this->details_height) {
01306 int resize = needed_height - this->details_height;
01307 this->details_height = needed_height;
01308 this->ReInit(0, resize);
01309 return;
01310 }
01311 }
01312 }
01313
01314 virtual void OnQueryTextFinished(char *str)
01315 {
01316 if (str == NULL) return;
01317
01318 DoCommandP(0, this->rename_engine, 0, CMD_RENAME_ENGINE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN_TYPE + this->vehicle_type), NULL, str);
01319 }
01320
01321 virtual void OnDropdownSelect(int widget, int index)
01322 {
01323 switch (widget) {
01324 case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN:
01325 if (this->sort_criteria != index) {
01326 this->sort_criteria = index;
01327 _last_sort_criteria[this->vehicle_type] = this->sort_criteria;
01328 this->eng_list.ForceRebuild();
01329 }
01330 break;
01331
01332 case BUILD_VEHICLE_WIDGET_CARGO_FILTER_DROPDOWN:
01333 if (this->cargo_filter_criteria != index) {
01334 this->cargo_filter_criteria = index;
01335 _last_filter_criteria[this->vehicle_type] = this->cargo_filter[this->cargo_filter_criteria];
01336
01337 this->eng_list.SetFilterState(this->cargo_filter[this->cargo_filter_criteria] != CF_ANY);
01338 this->eng_list.ForceRebuild();
01339 }
01340 break;
01341 }
01342 this->SetDirty();
01343 }
01344
01345 virtual void OnResize()
01346 {
01347 this->vscroll->SetCapacityFromWidget(this, BUILD_VEHICLE_WIDGET_LIST);
01348 this->GetWidget<NWidgetCore>(BUILD_VEHICLE_WIDGET_LIST)->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
01349 }
01350 };
01351
01352 static const WindowDesc _build_vehicle_desc(
01353 WDP_AUTO, 240, 268,
01354 WC_BUILD_VEHICLE, WC_NONE,
01355 WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
01356 _nested_build_vehicle_widgets, lengthof(_nested_build_vehicle_widgets)
01357 );
01358
01359 void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
01360 {
01361
01362
01363
01364
01365 uint num = (tile == INVALID_TILE) ? (int)type : tile;
01366
01367 assert(IsCompanyBuildableVehicleType(type));
01368
01369 DeleteWindowById(WC_BUILD_VEHICLE, num);
01370
01371 new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
01372 }