00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "debug.h"
00015 #include "company_func.h"
00016 #include "gui.h"
00017 #include "window_gui.h"
00018 #include "textbuf_gui.h"
00019 #include "command_func.h"
00020 #include "vehicle_gui.h"
00021 #include "vehicle_gui_base.h"
00022 #include "viewport_func.h"
00023 #include "gfx_func.h"
00024 #include "newgrf_engine.h"
00025 #include "newgrf_text.h"
00026 #include "waypoint_base.h"
00027 #include "roadveh.h"
00028 #include "train.h"
00029 #include "aircraft.h"
00030 #include "depot_base.h"
00031 #include "group_gui.h"
00032 #include "strings_func.h"
00033 #include "window_func.h"
00034 #include "vehicle_func.h"
00035 #include "autoreplace_gui.h"
00036 #include "string_func.h"
00037 #include "widgets/dropdown_func.h"
00038 #include "timetable.h"
00039 #include "vehiclelist.h"
00040 #include "articulated_vehicles.h"
00041 #include "cargotype.h"
00042 #include "spritecache.h"
00043
00044 #include "table/sprites.h"
00045 #include "table/strings.h"
00046
00047 Sorting _sorting;
00048
00049 static GUIVehicleList::SortFunction VehicleNumberSorter;
00050 static GUIVehicleList::SortFunction VehicleNameSorter;
00051 static GUIVehicleList::SortFunction VehicleAgeSorter;
00052 static GUIVehicleList::SortFunction VehicleProfitThisYearSorter;
00053 static GUIVehicleList::SortFunction VehicleProfitLastYearSorter;
00054 static GUIVehicleList::SortFunction VehicleCargoSorter;
00055 static GUIVehicleList::SortFunction VehicleReliabilitySorter;
00056 static GUIVehicleList::SortFunction VehicleMaxSpeedSorter;
00057 static GUIVehicleList::SortFunction VehicleModelSorter;
00058 static GUIVehicleList::SortFunction VehicleValueSorter;
00059 static GUIVehicleList::SortFunction VehicleLengthSorter;
00060 static GUIVehicleList::SortFunction VehicleTimeToLiveSorter;
00061 static GUIVehicleList::SortFunction VehicleTimetableDelaySorter;
00062
00063 GUIVehicleList::SortFunction * const BaseVehicleListWindow::vehicle_sorter_funcs[] = {
00064 &VehicleNumberSorter,
00065 &VehicleNameSorter,
00066 &VehicleAgeSorter,
00067 &VehicleProfitThisYearSorter,
00068 &VehicleProfitLastYearSorter,
00069 &VehicleCargoSorter,
00070 &VehicleReliabilitySorter,
00071 &VehicleMaxSpeedSorter,
00072 &VehicleModelSorter,
00073 &VehicleValueSorter,
00074 &VehicleLengthSorter,
00075 &VehicleTimeToLiveSorter,
00076 &VehicleTimetableDelaySorter,
00077 };
00078
00079 const StringID BaseVehicleListWindow::vehicle_sorter_names[] = {
00080 STR_SORT_BY_NUMBER,
00081 STR_SORT_BY_NAME,
00082 STR_SORT_BY_AGE,
00083 STR_SORT_BY_PROFIT_THIS_YEAR,
00084 STR_SORT_BY_PROFIT_LAST_YEAR,
00085 STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
00086 STR_SORT_BY_RELIABILITY,
00087 STR_SORT_BY_MAX_SPEED,
00088 STR_SORT_BY_MODEL,
00089 STR_SORT_BY_VALUE,
00090 STR_SORT_BY_LENGTH,
00091 STR_SORT_BY_LIFE_TIME,
00092 STR_SORT_BY_TIMETABLE_DELAY,
00093 INVALID_STRING_ID
00094 };
00095
00096 void BaseVehicleListWindow::BuildVehicleList(Owner owner, uint16 index, uint16 window_type)
00097 {
00098 if (!this->vehicles.NeedRebuild()) return;
00099
00100 DEBUG(misc, 3, "Building vehicle list for company %d at station %d", owner, index);
00101
00102 GenerateVehicleSortList(&this->vehicles, this->vehicle_type, owner, index, window_type);
00103
00104 uint unitnumber = 0;
00105 for (const Vehicle **v = this->vehicles.Begin(); v != this->vehicles.End(); v++) {
00106 unitnumber = max<uint>(unitnumber, (*v)->unitnumber);
00107 }
00108
00109
00110
00111
00112 if (unitnumber >= 1000) {
00113 this->unitnumber_digits = 4;
00114 } else if (unitnumber >= 100) {
00115 this->unitnumber_digits = 3;
00116 } else {
00117 this->unitnumber_digits = 2;
00118 }
00119
00120 this->vehicles.RebuildDone();
00121 this->vscroll.SetCount(this->vehicles.Length());
00122 }
00123
00124
00125 static const Vehicle *_last_vehicle[2] = { NULL, NULL };
00126
00127 void BaseVehicleListWindow::SortVehicleList()
00128 {
00129 if (this->vehicles.Sort()) return;
00130
00131
00132 _last_vehicle[0] = _last_vehicle[1] = NULL;
00133 }
00134
00135 void DepotSortList(VehicleList *list)
00136 {
00137 if (list->Length() < 2) return;
00138 QSortT(list->Begin(), list->Length(), &VehicleNumberSorter);
00139 }
00140
00142 static void DrawVehicleProfitButton(const Vehicle *v, int x, int y)
00143 {
00144 SpriteID pal;
00145
00146
00147 if (v->age <= DAYS_IN_YEAR * 2) {
00148 pal = PALETTE_TO_GREY;
00149 } else if (v->GetDisplayProfitLastYear() < 0) {
00150 pal = PALETTE_TO_RED;
00151 } else if (v->GetDisplayProfitLastYear() < 10000) {
00152 pal = PALETTE_TO_YELLOW;
00153 } else {
00154 pal = PALETTE_TO_GREEN;
00155 }
00156 DrawSprite(SPR_BLOT, pal, x, y);
00157 }
00158
00160 static const int MAX_REFIT_CYCLE = 16;
00161
00169 byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for)
00170 {
00171 const Engine *e_from = Engine::Get(v_from->engine_type);
00172 const Engine *e_for = Engine::Get(v_for->engine_type);
00173
00174
00175 if (!e_from->CanCarryCargo() || !e_for->CanCarryCargo()) return 0;
00176
00177 if (!HasBit(e_from->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX) ||
00178 !HasBit(e_for->info.callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) {
00179
00180 return 0;
00181 }
00182
00183
00184 if (!HasBit(e_for->info.refit_mask, v_from->cargo_type)) return 0;
00185
00186 StringID expected_string = GetCargoSubtypeText(v_from);
00187
00188 CargoID old_cargo_type = v_for->cargo_type;
00189 byte old_cargo_subtype = v_for->cargo_subtype;
00190 byte ret_refit_cyc = 0;
00191
00192
00193 v_for->cargo_type = v_from->cargo_type;
00194
00195
00196 for (byte refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE; refit_cyc++) {
00197 v_for->cargo_subtype = refit_cyc;
00198
00199
00200 v_for->First()->InvalidateNewGRFCache();
00201 v_for->InvalidateNewGRFCache();
00202 uint16 callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v_for->engine_type, v_for);
00203
00204 if (callback == 0xFF) callback = CALLBACK_FAILED;
00205 if (callback == CALLBACK_FAILED) break;
00206
00207 if (GetCargoSubtypeText(v_for) != expected_string) continue;
00208
00209
00210 ret_refit_cyc = refit_cyc;
00211 break;
00212 }
00213
00214
00215 v_for->cargo_type = old_cargo_type;
00216 v_for->cargo_subtype = old_cargo_subtype;
00217
00218
00219 v_for->First()->InvalidateNewGRFCache();
00220 v_for->InvalidateNewGRFCache();
00221
00222 return ret_refit_cyc;
00223 }
00224
00225 struct RefitOption {
00226 CargoID cargo;
00227 byte subtype;
00228 uint16 value;
00229 EngineID engine;
00230 };
00231
00232 struct RefitList {
00233 uint num_lines;
00234 RefitOption *items;
00235 };
00236
00237 static RefitList *BuildRefitList(const Vehicle *v)
00238 {
00239 uint max_lines = 256;
00240 RefitOption *refit = CallocT<RefitOption>(max_lines);
00241 RefitList *list = CallocT<RefitList>(1);
00242 Vehicle *u = const_cast<Vehicle *>(v);
00243 uint num_lines = 0;
00244 uint i;
00245
00246 do {
00247 const Engine *e = Engine::Get(u->engine_type);
00248 uint32 cmask = e->info.refit_mask;
00249 byte callback_mask = e->info.callback_mask;
00250
00251
00252 if (u->cargo_cap == 0) continue;
00253
00254
00255 for (CargoID cid = 0; cid < NUM_CARGO && num_lines < max_lines; cid++) {
00256
00257 if (!HasBit(cmask, cid)) continue;
00258
00259
00260 if (HasBit(callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) {
00261
00262
00263 CargoID temp_cargo = u->cargo_type;
00264 byte temp_subtype = u->cargo_subtype;
00265 byte refit_cyc;
00266
00267 u->cargo_type = cid;
00268
00269 for (refit_cyc = 0; refit_cyc < MAX_REFIT_CYCLE && num_lines < max_lines; refit_cyc++) {
00270 bool duplicate = false;
00271 uint16 callback;
00272
00273 u->cargo_subtype = refit_cyc;
00274
00275
00276 u->First()->InvalidateNewGRFCache();
00277 u->InvalidateNewGRFCache();
00278 callback = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, u->engine_type, u);
00279
00280 if (callback == 0xFF) callback = CALLBACK_FAILED;
00281 if (refit_cyc != 0 && callback == CALLBACK_FAILED) break;
00282
00283
00284 for (i = 0; i < num_lines && !duplicate; i++) {
00285 if (refit[i].cargo == cid && refit[i].value == callback) duplicate = true;
00286 }
00287
00288 if (duplicate) continue;
00289
00290 refit[num_lines].cargo = cid;
00291 refit[num_lines].subtype = refit_cyc;
00292 refit[num_lines].value = callback;
00293 refit[num_lines].engine = u->engine_type;
00294 num_lines++;
00295 }
00296
00297
00298 u->cargo_type = temp_cargo;
00299 u->cargo_subtype = temp_subtype;
00300
00301
00302 u->First()->InvalidateNewGRFCache();
00303 u->InvalidateNewGRFCache();
00304 } else {
00305
00306 bool duplicate = false;
00307
00308 for (i = 0; i < num_lines && !duplicate; i++) {
00309 if (refit[i].cargo == cid && refit[i].value == CALLBACK_FAILED) duplicate = true;
00310 }
00311
00312 if (!duplicate) {
00313 refit[num_lines].cargo = cid;
00314 refit[num_lines].subtype = 0;
00315 refit[num_lines].value = CALLBACK_FAILED;
00316 refit[num_lines].engine = INVALID_ENGINE;
00317 num_lines++;
00318 }
00319 }
00320 }
00321 } while ((v->type == VEH_TRAIN || v->type == VEH_ROAD) && (u = u->Next()) != NULL && num_lines < max_lines);
00322
00323 list->num_lines = num_lines;
00324 list->items = refit;
00325
00326 return list;
00327 }
00328
00337 static void DrawVehicleRefitWindow(const RefitList *list, int sel, uint pos, uint rows, uint delta, const Rect &r)
00338 {
00339 uint y = r.top + WD_MATRIX_TOP;
00340
00341 for (uint i = pos; i < pos + rows && i < list->num_lines; i++) {
00342 TextColour colour = (sel == (int)i) ? TC_WHITE : TC_BLACK;
00343 RefitOption *refit = &list->items[i];
00344
00345
00346 SetDParam(0, CargoSpec::Get(refit->cargo)->name);
00347
00348
00349 if (refit->value != CALLBACK_FAILED) {
00350 SetDParam(1, GetGRFStringID(GetEngineGRFID(refit->engine), 0xD000 + refit->value));
00351 DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y, STR_JUST_STRING_SPACE_STRING, colour);
00352 } else {
00353 DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y, STR_JUST_STRING, colour);
00354 }
00355
00356 y += delta;
00357 }
00358 }
00359
00361 enum VehicleRefitWidgets {
00362 VRW_CAPTION,
00363 VRW_SELECTHEADER,
00364 VRW_MATRIX,
00365 VRW_SCROLLBAR,
00366 VRW_INFOPANEL,
00367 VRW_REFITBUTTON,
00368 };
00369
00371 struct RefitWindow : public Window {
00372 int sel;
00373 RefitOption *cargo;
00374 RefitList *list;
00375 uint length;
00376 VehicleOrderID order;
00377
00378 RefitWindow(const WindowDesc *desc, const Vehicle *v, VehicleOrderID order) : Window()
00379 {
00380 this->CreateNestedTree(desc);
00381
00382 this->GetWidget<NWidgetCore>(VRW_SELECTHEADER)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type;
00383 this->GetWidget<NWidgetCore>(VRW_MATRIX)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type;
00384 NWidgetCore *nwi = this->GetWidget<NWidgetCore>(VRW_REFITBUTTON);
00385 nwi->widget_data = STR_REFIT_TRAIN_REFIT_BUTTON + v->type;
00386 nwi->tool_tip = STR_REFIT_TRAIN_REFIT_TOOLTIP + v->type;
00387
00388 this->FinishInitNested(desc, v->index);
00389 this->owner = v->owner;
00390
00391 this->order = order;
00392 this->sel = -1;
00393 this->list = BuildRefitList(v);
00394 if (v->type == VEH_TRAIN) this->length = CountVehiclesInChain(v);
00395 this->vscroll.SetCount(this->list->num_lines);
00396 }
00397
00398 ~RefitWindow()
00399 {
00400 free(this->list->items);
00401 free(this->list);
00402 }
00403
00404 virtual void OnPaint()
00405 {
00406 Vehicle *v = Vehicle::Get(this->window_number);
00407
00408 if (v->type == VEH_TRAIN) {
00409 uint length = CountVehiclesInChain(v);
00410
00411 if (length != this->length) {
00412
00413 free(this->list->items);
00414 free(this->list);
00415 this->list = BuildRefitList(v);
00416 this->length = length;
00417 }
00418 }
00419
00420 this->vscroll.SetCount(this->list->num_lines);
00421
00422 this->cargo = (this->sel >= 0 && this->sel < (int)this->list->num_lines) ? &this->list->items[this->sel] : NULL;
00423 this->DrawWidgets();
00424 }
00425
00426 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00427 {
00428 switch (widget) {
00429 case VRW_MATRIX:
00430 resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
00431 size->height = resize->height * 8;
00432 break;
00433 }
00434 }
00435
00436 virtual void SetStringParameters(int widget) const
00437 {
00438 if (widget == VRW_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index);
00439 }
00440
00441 virtual void DrawWidget(const Rect &r, int widget) const
00442 {
00443 switch (widget) {
00444 case VRW_MATRIX:
00445 DrawVehicleRefitWindow(this->list, this->sel, this->vscroll.GetPosition(), this->vscroll.GetCapacity(), this->resize.step_height, r);
00446 break;
00447
00448 case VRW_INFOPANEL:
00449 if (this->cargo != NULL) {
00450 Vehicle *v = Vehicle::Get(this->window_number);
00451 CommandCost cost = DoCommand(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8, DC_QUERY_COST, GetCmdRefitVeh(v->type));
00452 if (CmdSucceeded(cost)) {
00453 SetDParam(0, this->cargo->cargo);
00454 SetDParam(1, _returned_refit_capacity);
00455 SetDParam(2, cost.GetCost());
00456 DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT,
00457 r.top + WD_FRAMERECT_TOP, r.bottom - WD_FRAMERECT_BOTTOM, STR_REFIT_NEW_CAPACITY_COST_OF_REFIT);
00458 }
00459 }
00460 break;
00461 }
00462 }
00463
00464 virtual void OnDoubleClick(Point pt, int widget)
00465 {
00466 if (widget == VRW_MATRIX) this->OnClick(pt, VRW_REFITBUTTON);
00467 }
00468
00469 virtual void OnClick(Point pt, int widget)
00470 {
00471 switch (widget) {
00472 case VRW_MATRIX: {
00473 int y = pt.y - this->GetWidget<NWidgetBase>(VRW_MATRIX)->pos_y;
00474 if (y >= 0) {
00475 this->sel = (y / (int)this->resize.step_height) + this->vscroll.GetPosition();
00476 this->SetDirty();
00477 }
00478 break;
00479 }
00480
00481 case VRW_REFITBUTTON:
00482 if (this->cargo != NULL) {
00483 const Vehicle *v = Vehicle::Get(this->window_number);
00484
00485 if (this->order == INVALID_VEH_ORDER_ID) {
00486 if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8, GetCmdRefitVeh(v))) delete this;
00487 } else {
00488 if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8 | this->order << 16, CMD_ORDER_REFIT)) delete this;
00489 }
00490 }
00491 break;
00492 }
00493 }
00494
00495 virtual void OnResize()
00496 {
00497 this->vscroll.SetCapacityFromWidget(this, VRW_MATRIX);
00498 this->GetWidget<NWidgetCore>(VRW_MATRIX)->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00499 }
00500 };
00501
00502 static const NWidgetPart _nested_vehicle_refit_widgets[] = {
00503 NWidget(NWID_HORIZONTAL),
00504 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00505 NWidget(WWT_CAPTION, COLOUR_GREY, VRW_CAPTION), SetDataTip(STR_REFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00506 EndContainer(),
00507 NWidget(WWT_TEXTBTN, COLOUR_GREY, VRW_SELECTHEADER), SetDataTip(STR_REFIT_TITLE, STR_NULL), SetResize(1, 0),
00508
00509 NWidget(NWID_HORIZONTAL),
00510 NWidget(WWT_MATRIX, COLOUR_GREY, VRW_MATRIX), SetMinimalSize(228, 112), SetResize(1, 14), SetFill(1, 1), SetDataTip(0x801, STR_NULL),
00511 NWidget(WWT_SCROLLBAR, COLOUR_GREY, VRW_SCROLLBAR),
00512 EndContainer(),
00513 NWidget(WWT_PANEL, COLOUR_GREY, VRW_INFOPANEL), SetMinimalTextLines(2, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 0), EndContainer(),
00514 NWidget(NWID_HORIZONTAL),
00515 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VRW_REFITBUTTON), SetFill(1, 0), SetResize(1, 0),
00516 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00517 EndContainer(),
00518 };
00519
00520 static const WindowDesc _vehicle_refit_desc(
00521 WDP_AUTO, 240, 174,
00522 WC_VEHICLE_REFIT, WC_VEHICLE_VIEW,
00523 WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
00524 _nested_vehicle_refit_widgets, lengthof(_nested_vehicle_refit_widgets)
00525 );
00526
00532 void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order, Window *parent)
00533 {
00534 DeleteWindowById(WC_VEHICLE_REFIT, v->index);
00535 RefitWindow *w = new RefitWindow(&_vehicle_refit_desc, v, order);
00536 w->parent = parent;
00537 }
00538
00540 uint ShowRefitOptionsList(int left, int right, int y, EngineID engine)
00541 {
00542
00543 uint32 cmask = GetUnionOfArticulatedRefitMasks(engine, false);
00544
00545 uint32 lmask = _cargo_mask;
00546 char string[512];
00547 char *b = string;
00548
00549
00550 if (CountBits(cmask) <= 1) return y;
00551
00552 b = InlineString(b, STR_PURCHASE_INFO_REFITTABLE_TO);
00553
00554 if (cmask == lmask) {
00555
00556 b = InlineString(b, STR_PURCHASE_INFO_ALL_TYPES);
00557 } else {
00558
00559
00560 if (CountBits(cmask ^ lmask) < CountBits(cmask)) {
00561 cmask ^= lmask;
00562 b = InlineString(b, STR_PURCHASE_INFO_ALL_BUT);
00563 }
00564
00565 bool first = true;
00566
00567
00568 for (CargoID cid = 0; cid < NUM_CARGO; cid++) {
00569 if (!HasBit(cmask, cid)) continue;
00570
00571 if (b >= lastof(string) - (2 + 2 * 4)) break;
00572
00573 if (!first) b = strecpy(b, ", ", lastof(string));
00574 first = false;
00575
00576 b = InlineString(b, CargoSpec::Get(cid)->name);
00577 }
00578 }
00579
00580
00581 *b = '\0';
00582
00583
00584 assert(b < endof(string));
00585
00586 SetDParamStr(0, string);
00587 return DrawStringMultiLine(left, right, y, INT32_MAX, STR_JUST_RAW_STRING);
00588 }
00589
00591 StringID GetCargoSubtypeText(const Vehicle *v)
00592 {
00593 if (HasBit(EngInfo(v->engine_type)->callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) {
00594 uint16 cb = GetVehicleCallback(CBID_VEHICLE_CARGO_SUFFIX, 0, 0, v->engine_type, v);
00595 if (cb != CALLBACK_FAILED) {
00596 return GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + cb);
00597 }
00598 }
00599 return STR_EMPTY;
00600 }
00601
00603 static int CDECL VehicleNumberSorter(const Vehicle * const *a, const Vehicle * const *b)
00604 {
00605 return (*a)->unitnumber - (*b)->unitnumber;
00606 }
00607
00609 static int CDECL VehicleNameSorter(const Vehicle * const *a, const Vehicle * const *b)
00610 {
00611 static char last_name[2][64];
00612
00613 if (*a != _last_vehicle[0]) {
00614 _last_vehicle[0] = *a;
00615 SetDParam(0, (*a)->index);
00616 GetString(last_name[0], STR_VEHICLE_NAME, lastof(last_name[0]));
00617 }
00618
00619 if (*b != _last_vehicle[1]) {
00620 _last_vehicle[1] = *b;
00621 SetDParam(0, (*b)->index);
00622 GetString(last_name[1], STR_VEHICLE_NAME, lastof(last_name[1]));
00623 }
00624
00625 int r = strcmp(last_name[0], last_name[1]);
00626 return (r != 0) ? r : VehicleNumberSorter(a, b);
00627 }
00628
00630 static int CDECL VehicleAgeSorter(const Vehicle * const *a, const Vehicle * const *b)
00631 {
00632 int r = (*a)->age - (*b)->age;
00633 return (r != 0) ? r : VehicleNumberSorter(a, b);
00634 }
00635
00637 static int CDECL VehicleProfitThisYearSorter(const Vehicle * const *a, const Vehicle * const *b)
00638 {
00639 int r = ClampToI32((*a)->GetDisplayProfitThisYear() - (*b)->GetDisplayProfitThisYear());
00640 return (r != 0) ? r : VehicleNumberSorter(a, b);
00641 }
00642
00644 static int CDECL VehicleProfitLastYearSorter(const Vehicle * const *a, const Vehicle * const *b)
00645 {
00646 int r = ClampToI32((*a)->GetDisplayProfitLastYear() - (*b)->GetDisplayProfitLastYear());
00647 return (r != 0) ? r : VehicleNumberSorter(a, b);
00648 }
00649
00651 static int CDECL VehicleCargoSorter(const Vehicle * const *a, const Vehicle * const *b)
00652 {
00653 const Vehicle *v;
00654 CargoArray diff;
00655
00656
00657 for (v = *a; v != NULL; v = v->Next()) diff[v->cargo_type] += v->cargo_cap;
00658 for (v = *b; v != NULL; v = v->Next()) diff[v->cargo_type] -= v->cargo_cap;
00659
00660 int r = 0;
00661 for (CargoID i = 0; i < NUM_CARGO; i++) {
00662 r = diff[i];
00663 if (r != 0) break;
00664 }
00665
00666 return (r != 0) ? r : VehicleNumberSorter(a, b);
00667 }
00668
00670 static int CDECL VehicleReliabilitySorter(const Vehicle * const *a, const Vehicle * const *b)
00671 {
00672 int r = (*a)->reliability - (*b)->reliability;
00673 return (r != 0) ? r : VehicleNumberSorter(a, b);
00674 }
00675
00677 static int CDECL VehicleMaxSpeedSorter(const Vehicle * const *a, const Vehicle * const *b)
00678 {
00679 int r = 0;
00680 if ((*a)->type == VEH_TRAIN && (*b)->type == VEH_TRAIN) {
00681 r = Train::From(*a)->tcache.cached_max_speed - Train::From(*b)->tcache.cached_max_speed;
00682 } else {
00683 r = (*a)->max_speed - (*b)->max_speed;
00684 }
00685 return (r != 0) ? r : VehicleNumberSorter(a, b);
00686 }
00687
00689 static int CDECL VehicleModelSorter(const Vehicle * const *a, const Vehicle * const *b)
00690 {
00691 int r = (*a)->engine_type - (*b)->engine_type;
00692 return (r != 0) ? r : VehicleNumberSorter(a, b);
00693 }
00694
00696 static int CDECL VehicleValueSorter(const Vehicle * const *a, const Vehicle * const *b)
00697 {
00698 const Vehicle *u;
00699 Money diff = 0;
00700
00701 for (u = *a; u != NULL; u = u->Next()) diff += u->value;
00702 for (u = *b; u != NULL; u = u->Next()) diff -= u->value;
00703
00704 int r = ClampToI32(diff);
00705 return (r != 0) ? r : VehicleNumberSorter(a, b);
00706 }
00707
00709 static int CDECL VehicleLengthSorter(const Vehicle * const *a, const Vehicle * const *b)
00710 {
00711 int r = 0;
00712 switch ((*a)->type) {
00713 case VEH_TRAIN:
00714 r = Train::From(*a)->tcache.cached_total_length - Train::From(*b)->tcache.cached_total_length;
00715 break;
00716
00717 case VEH_ROAD: {
00718 const RoadVehicle *u;
00719 for (u = RoadVehicle::From(*a); u != NULL; u = u->Next()) r += u->rcache.cached_veh_length;
00720 for (u = RoadVehicle::From(*b); u != NULL; u = u->Next()) r -= u->rcache.cached_veh_length;
00721 } break;
00722
00723 default: NOT_REACHED();
00724 }
00725 return (r != 0) ? r : VehicleNumberSorter(a, b);
00726 }
00727
00729 static int CDECL VehicleTimeToLiveSorter(const Vehicle * const *a, const Vehicle * const *b)
00730 {
00731 int r = ClampToI32(((*a)->max_age - (*a)->age) - ((*b)->max_age - (*b)->age));
00732 return (r != 0) ? r : VehicleNumberSorter(a, b);
00733 }
00734
00736 static int CDECL VehicleTimetableDelaySorter(const Vehicle * const *a, const Vehicle * const *b)
00737 {
00738 int r = (*a)->lateness_counter - (*b)->lateness_counter;
00739 return (r != 0) ? r : VehicleNumberSorter(a, b);
00740 }
00741
00742 void InitializeGUI()
00743 {
00744 MemSetT(&_sorting, 0);
00745 }
00746
00753 static inline void ChangeVehicleWindow(WindowClass window_class, VehicleID from_index, VehicleID to_index)
00754 {
00755 Window *w = FindWindowById(window_class, from_index);
00756 if (w != NULL) {
00757 w->window_number = to_index;
00758 if (w->viewport != NULL) w->viewport->follow_vehicle = to_index;
00759 if (to_index != INVALID_VEHICLE) w->InvalidateData();
00760 }
00761 }
00762
00768 void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index)
00769 {
00770 ChangeVehicleWindow(WC_VEHICLE_VIEW, from_index, to_index);
00771 ChangeVehicleWindow(WC_VEHICLE_ORDERS, from_index, to_index);
00772 ChangeVehicleWindow(WC_VEHICLE_REFIT, from_index, to_index);
00773 ChangeVehicleWindow(WC_VEHICLE_DETAILS, from_index, to_index);
00774 ChangeVehicleWindow(WC_VEHICLE_TIMETABLE, from_index, to_index);
00775 }
00776
00777 enum VehicleListWindowWidgets {
00778 VLW_WIDGET_CAPTION,
00779 VLW_WIDGET_SORT_ORDER,
00780 VLW_WIDGET_SORT_BY_PULLDOWN,
00781 VLW_WIDGET_LIST,
00782 VLW_WIDGET_SCROLLBAR,
00783 VLW_WIDGET_HIDE_BUTTONS,
00784 VLW_WIDGET_AVAILABLE_VEHICLES,
00785 VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
00786 VLW_WIDGET_STOP_ALL,
00787 VLW_WIDGET_START_ALL,
00788 };
00789
00790 static const NWidgetPart _nested_vehicle_list[] = {
00791 NWidget(NWID_HORIZONTAL),
00792 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00793 NWidget(WWT_CAPTION, COLOUR_GREY, VLW_WIDGET_CAPTION),
00794 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00795 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00796 EndContainer(),
00797
00798 NWidget(NWID_HORIZONTAL),
00799 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLW_WIDGET_SORT_ORDER), SetMinimalSize(81, 12), SetFill(0, 1), SetDataTip(STR_BUTTON_SORT_BY, STR_TOOLTIP_SORT_ORDER),
00800 NWidget(WWT_DROPDOWN, COLOUR_GREY, VLW_WIDGET_SORT_BY_PULLDOWN), SetMinimalSize(167, 12), SetFill(0, 1), SetDataTip(0x0, STR_TOOLTIP_SORT_CRITERIAP),
00801 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(12, 12), SetFill(1, 1), SetResize(1, 0),
00802 EndContainer(),
00803 EndContainer(),
00804
00805 NWidget(NWID_HORIZONTAL),
00806 NWidget(WWT_MATRIX, COLOUR_GREY, VLW_WIDGET_LIST), SetMinimalSize(248, 0), SetFill(1, 0),
00807 NWidget(WWT_SCROLLBAR, COLOUR_GREY, VLW_WIDGET_SCROLLBAR),
00808 EndContainer(),
00809
00810 NWidget(NWID_HORIZONTAL),
00811 NWidget(NWID_SELECTION, INVALID_COLOUR, VLW_WIDGET_HIDE_BUTTONS),
00812 NWidget(NWID_HORIZONTAL),
00813 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLW_WIDGET_AVAILABLE_VEHICLES), SetMinimalSize(106, 12), SetFill(0, 1),
00814 SetDataTip(0x0, STR_VEHICLE_LIST_AVAILABLE_ENGINES_TOOLTIP),
00815 NWidget(WWT_DROPDOWN, COLOUR_GREY, VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN), SetMinimalSize(118, 12), SetFill(0, 1),
00816 SetDataTip(STR_VEHICLE_LIST_MANAGE_LIST, STR_VEHICLE_LIST_MANAGE_LIST_TOOLTIP),
00817 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VLW_WIDGET_STOP_ALL), SetMinimalSize(12, 12), SetFill(0, 1),
00818 SetDataTip(SPR_FLAG_VEH_STOPPED, STR_VEHICLE_LIST_MASS_STOP_LIST_TOOLTIP),
00819 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VLW_WIDGET_START_ALL), SetMinimalSize(12, 12), SetFill(0, 1),
00820 SetDataTip(SPR_FLAG_VEH_RUNNING, STR_VEHICLE_LIST_MASS_START_LIST_TOOLTIP),
00821 NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(0, 12), SetResize(1, 0), SetFill(1, 1), EndContainer(),
00822 EndContainer(),
00823
00824 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(),
00825 EndContainer(),
00826 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00827 EndContainer(),
00828 };
00829
00830 static void DrawSmallOrderList(const Vehicle *v, int left, int right, int y, VehicleOrderID start = 0)
00831 {
00832 const Order *order = v->GetOrder(start);
00833 if (order == NULL) return;
00834
00835 int i = 0;
00836 VehicleOrderID oid = start;
00837
00838 do {
00839 if (oid == v->cur_order_index) DrawString(left, right, y, STR_TINY_RIGHT_ARROW, TC_BLACK);
00840
00841 if (order->IsType(OT_GOTO_STATION)) {
00842 SetDParam(0, order->GetDestination());
00843 DrawString(left + 6, right - 6, y, STR_TINY_BLACK_STATION);
00844
00845 y += FONT_HEIGHT_SMALL;
00846 if (++i == 4) break;
00847 }
00848
00849 oid++;
00850 order = order->next;
00851 if (order == NULL) {
00852 order = v->orders.list->GetFirstOrder();
00853 oid = 0;
00854 }
00855 } while (oid != start);
00856 }
00857
00867 static void DrawVehicleImage(const Vehicle *v, int left, int right, int y, VehicleID selection, int skip)
00868 {
00869 switch (v->type) {
00870 case VEH_TRAIN: DrawTrainImage(Train::From(v), left, right, y, selection, skip); break;
00871 case VEH_ROAD: DrawRoadVehImage(v, left, right, y, selection); break;
00872 case VEH_SHIP: DrawShipImage(v, left, right, y, selection); break;
00873 case VEH_AIRCRAFT: DrawAircraftImage(v, left, right, y, selection); break;
00874 default: NOT_REACHED();
00875 }
00876 }
00877
00884 uint GetVehicleListHeight(VehicleType type, uint divisor)
00885 {
00886
00887 uint base = GetVehicleHeight(type) + 2 * FONT_HEIGHT_SMALL;
00888
00889 if (type >= VEH_SHIP) base = max(base, 5U * FONT_HEIGHT_SMALL);
00890
00891 if (divisor == 1) return base;
00892
00893
00894 uint rem = base % divisor;
00895 return base + (rem == 0 ? 0 : divisor - rem);
00896 }
00897
00904 void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int line_height, const Rect &r) const
00905 {
00906 int left = r.left + WD_MATRIX_LEFT;
00907 int right = r.right - WD_MATRIX_RIGHT;
00908 int width = right - left;
00909 bool rtl = _dynlang.text_dir == TD_RTL;
00910
00911 int text_offset = GetDigitWidth() * this->unitnumber_digits + WD_FRAMERECT_RIGHT;
00912 int text_left = left + (rtl ? 0 : text_offset);
00913 int text_right = right - (rtl ? text_offset : 0);
00914
00915 bool show_orderlist = vehicle_type >= VEH_SHIP;
00916 int orderlist_left = left + (rtl ? 0 : max(100 + text_offset, width / 2));
00917 int orderlist_right = right - (rtl ? max(100 + text_offset, width / 2) : 0);
00918
00919 int image_left = (rtl && show_orderlist) ? orderlist_right : text_left;
00920 int image_right = (!rtl && show_orderlist) ? orderlist_left : text_right;
00921
00922 int vehicle_button_x = rtl ? right - 8 : left;
00923
00924 int y = r.top;
00925 uint max = min(this->vscroll.GetPosition() + this->vscroll.GetCapacity(), this->vehicles.Length());
00926 for (uint i = this->vscroll.GetPosition(); i < max; ++i) {
00927 const Vehicle *v = this->vehicles[i];
00928 StringID str;
00929
00930 SetDParam(0, v->GetDisplayProfitThisYear());
00931 SetDParam(1, v->GetDisplayProfitLastYear());
00932
00933 DrawVehicleImage(v, image_left, image_right, y + FONT_HEIGHT_SMALL - 1, selected_vehicle, 0);
00934 DrawString(text_left, text_right, y + line_height - FONT_HEIGHT_SMALL - WD_FRAMERECT_BOTTOM - 1, STR_VEHICLE_LIST_PROFIT_THIS_YEAR_LAST_YEAR);
00935
00936 if (v->name != NULL) {
00937
00938 SetDParam(0, v->index);
00939 DrawString(text_left, text_right, y, STR_TINY_BLACK_VEHICLE);
00940 } else if (v->group_id != DEFAULT_GROUP) {
00941
00942 SetDParam(0, v->group_id);
00943 DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK);
00944 }
00945
00946 if (show_orderlist) DrawSmallOrderList(v, orderlist_left, orderlist_right, y, v->cur_order_index);
00947
00948 if (v->IsInDepot()) {
00949 str = STR_BLUE_COMMA;
00950 } else {
00951 str = (v->age > v->max_age - DAYS_IN_LEAP_YEAR) ? STR_RED_COMMA : STR_BLACK_COMMA;
00952 }
00953
00954 SetDParam(0, v->unitnumber);
00955 DrawString(left, right, y + 2, str);
00956
00957 DrawVehicleProfitButton(v, vehicle_button_x, y + FONT_HEIGHT_NORMAL + 3);
00958
00959 y += line_height;
00960 }
00961 }
00962
00972 struct VehicleListWindow : public BaseVehicleListWindow {
00973 private:
00975 enum ButtonPlanes {
00976 BP_SHOW_BUTTONS,
00977 BP_HIDE_BUTTONS,
00978 };
00979
00980 public:
00981 VehicleListWindow(const WindowDesc *desc, WindowNumber window_number) : BaseVehicleListWindow()
00982 {
00983 uint16 window_type = window_number & VLW_MASK;
00984 CompanyID company = (CompanyID)GB(window_number, 0, 8);
00985
00986 this->vehicle_type = (VehicleType)GB(window_number, 11, 5);
00987
00988
00989
00990
00991 switch (this->vehicle_type) {
00992 case VEH_TRAIN: this->sorting = &_sorting.train; break;
00993 case VEH_ROAD: this->sorting = &_sorting.roadveh; break;
00994 case VEH_SHIP: this->sorting = &_sorting.ship; break;
00995 case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break;
00996 default: NOT_REACHED();
00997 }
00998
00999 this->vehicles.SetListing(*this->sorting);
01000 this->vehicles.ForceRebuild();
01001 this->vehicles.NeedResort();
01002 this->BuildVehicleList(company, GB(window_number, 16, 16), window_type);
01003 this->SortVehicleList();
01004
01005 this->CreateNestedTree(desc);
01006
01007
01008 this->GetWidget<NWidgetCore>(VLW_WIDGET_LIST)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vehicle_type;
01009 this->GetWidget<NWidgetCore>(VLW_WIDGET_AVAILABLE_VEHICLES)->widget_data = STR_VEHICLE_LIST_AVAILABLE_TRAINS + this->vehicle_type;
01010
01011 if (window_type == VLW_SHARED_ORDERS) {
01012 this->GetWidget<NWidgetCore>(VLW_WIDGET_CAPTION)->widget_data = STR_VEHICLE_LIST_SHARED_ORDERS_LIST_CAPTION;
01013 } else {
01014 this->GetWidget<NWidgetCore>(VLW_WIDGET_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vehicle_type;
01015 }
01016
01017 this->FinishInitNested(desc, window_number);
01018 this->owner = company;
01019
01020 if (this->vehicle_type == VEH_TRAIN) ResizeWindow(this, 65, 0);
01021 }
01022
01023 ~VehicleListWindow()
01024 {
01025 *this->sorting = this->vehicles.GetListing();
01026 }
01027
01028 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01029 {
01030 if (widget != VLW_WIDGET_LIST) return;
01031
01032 resize->width = 0;
01033 resize->height = GetVehicleListHeight(this->vehicle_type, 1);
01034
01035 switch (this->vehicle_type) {
01036 case VEH_TRAIN:
01037 resize->width = 1;
01038
01039 case VEH_ROAD:
01040 size->height = 6 * resize->height;
01041 break;
01042 case VEH_SHIP:
01043 case VEH_AIRCRAFT:
01044 size->height = 4 * resize->height;
01045 break;
01046 default: NOT_REACHED();
01047 }
01048 }
01049
01050 virtual void SetStringParameters(int widget) const
01051 {
01052 if (widget != VLW_WIDGET_CAPTION) return;
01053
01054 const uint16 index = GB(this->window_number, 16, 16);
01055 switch (this->window_number & VLW_MASK) {
01056 case VLW_SHARED_ORDERS:
01057 if (this->vehicles.Length() == 0) {
01058
01059
01060 NOT_REACHED();
01061 }
01062 SetDParam(0, this->vscroll.GetCount());
01063 break;
01064
01065 case VLW_STANDARD:
01066 SetDParam(0, STR_COMPANY_NAME);
01067 SetDParam(1, index);
01068 SetDParam(2, this->vscroll.GetCount());
01069 break;
01070
01071 case VLW_WAYPOINT_LIST:
01072 SetDParam(0, STR_WAYPOINT_NAME);
01073 SetDParam(1, index);
01074 SetDParam(2, this->vscroll.GetCount());
01075 break;
01076
01077 case VLW_STATION_LIST:
01078 SetDParam(0, STR_STATION_NAME);
01079 SetDParam(1, index);
01080 SetDParam(2, this->vscroll.GetCount());
01081 break;
01082
01083 case VLW_DEPOT_LIST:
01084 SetDParam(0, STR_DEPOT_TRAIN_CAPTION + this->vehicle_type);
01085 if (this->vehicle_type == VEH_AIRCRAFT) {
01086 SetDParam(1, index);
01087 } else {
01088 SetDParam(1, Depot::Get(index)->town_index);
01089 }
01090 SetDParam(2, this->vscroll.GetCount());
01091 break;
01092 default: NOT_REACHED();
01093 }
01094 }
01095
01096 virtual void DrawWidget(const Rect &r, int widget) const
01097 {
01098 switch (widget) {
01099 case VLW_WIDGET_SORT_ORDER:
01100
01101 this->DrawSortButtonState(widget, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
01102 break;
01103
01104 case VLW_WIDGET_LIST:
01105 this->DrawVehicleListItems(INVALID_VEHICLE, this->resize.step_height, r);
01106 break;
01107 }
01108 }
01109
01110 virtual void OnPaint()
01111 {
01112 const uint16 window_type = this->window_number & VLW_MASK;
01113
01114 this->BuildVehicleList(this->owner, GB(this->window_number, 16, 16), window_type);
01115 this->SortVehicleList();
01116
01117 if (this->vehicles.Length() == 0) HideDropDownMenu(this);
01118
01119
01120
01121 int plane_to_show = (this->owner == _local_company) ? BP_SHOW_BUTTONS : BP_HIDE_BUTTONS;
01122 NWidgetStacked *nwi = this->GetWidget<NWidgetStacked>(VLW_WIDGET_HIDE_BUTTONS);
01123 if (plane_to_show != nwi->shown_plane) {
01124 nwi->SetDisplayedPlane(plane_to_show);
01125 nwi->SetDirty(this);
01126 }
01127 if (this->owner == _local_company) {
01128 this->SetWidgetDisabledState(VLW_WIDGET_AVAILABLE_VEHICLES, window_type != VLW_STANDARD);
01129 this->SetWidgetsDisabledState(this->vehicles.Length() == 0,
01130 VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN,
01131 VLW_WIDGET_STOP_ALL,
01132 VLW_WIDGET_START_ALL,
01133 WIDGET_LIST_END);
01134 }
01135
01136
01137 this->GetWidget<NWidgetCore>(VLW_WIDGET_SORT_BY_PULLDOWN)->widget_data = this->vehicle_sorter_names[this->vehicles.SortType()];
01138
01139 this->DrawWidgets();
01140 }
01141
01142 virtual void OnClick(Point pt, int widget)
01143 {
01144 switch (widget) {
01145 case VLW_WIDGET_SORT_ORDER:
01146 this->vehicles.ToggleSortOrder();
01147 this->SetDirty();
01148 break;
01149
01150 case VLW_WIDGET_SORT_BY_PULLDOWN:
01151 ShowDropDownMenu(this, this->vehicle_sorter_names, this->vehicles.SortType(), VLW_WIDGET_SORT_BY_PULLDOWN, 0,
01152 (this->vehicle_type == VEH_TRAIN || this->vehicle_type == VEH_ROAD) ? 0 : (1 << 10));
01153 return;
01154
01155 case VLW_WIDGET_LIST: {
01156 uint32 id_v = (pt.y - this->GetWidget<NWidgetBase>(VLW_WIDGET_LIST)->pos_y) / this->resize.step_height;
01157 const Vehicle *v;
01158
01159 if (id_v >= this->vscroll.GetCapacity()) return;
01160
01161 id_v += this->vscroll.GetPosition();
01162
01163 if (id_v >= this->vehicles.Length()) return;
01164
01165 v = this->vehicles[id_v];
01166
01167 ShowVehicleViewWindow(v);
01168 } break;
01169
01170 case VLW_WIDGET_AVAILABLE_VEHICLES:
01171 ShowBuildVehicleWindow(INVALID_TILE, this->vehicle_type);
01172 break;
01173
01174 case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN: {
01175 static StringID action_str[] = {
01176 STR_VEHICLE_LIST_REPLACE_VEHICLES,
01177 STR_VEHICLE_LIST_SEND_FOR_SERVICING,
01178 STR_NULL,
01179 INVALID_STRING_ID
01180 };
01181
01182 static const StringID depot_name[] = {
01183 STR_VEHICLE_LIST_SEND_TRAIN_TO_DEPOT,
01184 STR_VEHICLE_LIST_SEND_ROAD_VEHICLE_TO_DEPOT,
01185 STR_VEHICLE_LIST_SEND_SHIP_TO_DEPOT,
01186 STR_VEHICLE_LIST_SEND_AIRCRAFT_TO_HANGAR
01187 };
01188
01189
01190 action_str[2] = depot_name[this->vehicle_type];
01191 ShowDropDownMenu(this, action_str, 0, VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN, 0, (this->window_number & VLW_MASK) == VLW_STANDARD ? 0 : 1);
01192 break;
01193 }
01194
01195 case VLW_WIDGET_STOP_ALL:
01196 case VLW_WIDGET_START_ALL:
01197 DoCommandP(0, GB(this->window_number, 16, 16),
01198 (this->window_number & VLW_MASK) | (1 << 6) | (widget == VLW_WIDGET_START_ALL ? (1 << 5) : 0) | this->vehicle_type, CMD_MASS_START_STOP);
01199 break;
01200 }
01201 }
01202
01203 virtual void OnDropdownSelect(int widget, int index)
01204 {
01205 switch (widget) {
01206 case VLW_WIDGET_SORT_BY_PULLDOWN:
01207 this->vehicles.SetSortType(index);
01208 break;
01209 case VLW_WIDGET_MANAGE_VEHICLES_DROPDOWN:
01210 assert(this->vehicles.Length() != 0);
01211
01212 switch (index) {
01213 case 0:
01214 ShowReplaceGroupVehicleWindow(DEFAULT_GROUP, this->vehicle_type);
01215 break;
01216 case 1:
01217 DoCommandP(0, GB(this->window_number, 16, 16) ,
01218 (this->window_number & VLW_MASK) | DEPOT_MASS_SEND | DEPOT_SERVICE, GetCmdSendToDepot(this->vehicle_type));
01219 break;
01220 case 2:
01221 DoCommandP(0, GB(this->window_number, 16, 16) ,
01222 (this->window_number & VLW_MASK) | DEPOT_MASS_SEND, GetCmdSendToDepot(this->vehicle_type));
01223 break;
01224
01225 default: NOT_REACHED();
01226 }
01227 break;
01228 default: NOT_REACHED();
01229 }
01230 this->SetDirty();
01231 }
01232
01233 virtual void OnTick()
01234 {
01235 if (_pause_mode != PM_UNPAUSED) return;
01236 if (this->vehicles.NeedResort()) {
01237 StationID station = ((this->window_number & VLW_MASK) == VLW_STATION_LIST) ? GB(this->window_number, 16, 16) : INVALID_STATION;
01238
01239 DEBUG(misc, 3, "Periodic resort %d list company %d at station %d", this->vehicle_type, this->owner, station);
01240 this->SetDirty();
01241 }
01242 }
01243
01244 virtual void OnResize()
01245 {
01246 this->vscroll.SetCapacityFromWidget(this, VLW_WIDGET_LIST);
01247 this->GetWidget<NWidgetCore>(VLW_WIDGET_LIST)->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
01248 }
01249
01250 virtual void OnInvalidateData(int data)
01251 {
01252 if (HasBit(data, 15) && (this->window_number & VLW_MASK) == VLW_SHARED_ORDERS) {
01253 SB(this->window_number, 16, 16, GB(data, 16, 16));
01254 this->vehicles.ForceRebuild();
01255 return;
01256 }
01257
01258 if (data == 0) {
01259 this->vehicles.ForceRebuild();
01260 } else {
01261 this->vehicles.ForceResort();
01262 }
01263 }
01264 };
01265
01266 static WindowDesc _vehicle_list_desc(
01267 WDP_AUTO, 260, 246,
01268 WC_INVALID, WC_NONE,
01269 WDF_UNCLICK_BUTTONS,
01270 _nested_vehicle_list, lengthof(_nested_vehicle_list)
01271 );
01272
01273 static void ShowVehicleListWindowLocal(CompanyID company, uint16 VLW_flag, VehicleType vehicle_type, uint16 unique_number)
01274 {
01275 if (!Company::IsValidID(company)) return;
01276
01277 _vehicle_list_desc.cls = GetWindowClassForVehicleType(vehicle_type);
01278 WindowNumber num = (unique_number << 16) | (vehicle_type << 11) | VLW_flag | company;
01279 AllocateWindowDescFront<VehicleListWindow>(&_vehicle_list_desc, num);
01280 }
01281
01282 void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type)
01283 {
01284
01285
01286
01287
01288
01289 if ((_settings_client.gui.advanced_vehicle_list > (uint)(company != _local_company)) != _ctrl_pressed) {
01290 ShowCompanyGroup(company, vehicle_type);
01291 } else {
01292 ShowVehicleListWindowLocal(company, VLW_STANDARD, vehicle_type, company);
01293 }
01294 }
01295
01296 void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, const Waypoint *wp)
01297 {
01298 if (wp == NULL) return;
01299 ShowVehicleListWindowLocal(company, VLW_WAYPOINT_LIST, vehicle_type, wp->index);
01300 }
01301
01302 void ShowVehicleListWindow(const Vehicle *v)
01303 {
01304 ShowVehicleListWindowLocal(v->owner, VLW_SHARED_ORDERS, v->type, v->FirstShared()->index);
01305 }
01306
01307 void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, StationID station)
01308 {
01309 ShowVehicleListWindowLocal(company, VLW_STATION_LIST, vehicle_type, station);
01310 }
01311
01312 void ShowVehicleListWindow(CompanyID company, VehicleType vehicle_type, TileIndex depot_tile)
01313 {
01314 uint16 depot_airport_index;
01315
01316 if (vehicle_type == VEH_AIRCRAFT) {
01317 depot_airport_index = GetStationIndex(depot_tile);
01318 } else {
01319 depot_airport_index = GetDepotIndex(depot_tile);
01320 }
01321 ShowVehicleListWindowLocal(company, VLW_DEPOT_LIST, vehicle_type, depot_airport_index);
01322 }
01323
01324
01325
01326
01328 enum VehicleDetailsWindowWidgets {
01329 VLD_WIDGET_CAPTION,
01330 VLD_WIDGET_RENAME_VEHICLE,
01331 VLD_WIDGET_TOP_DETAILS,
01332 VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
01333 VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
01334 VLD_WIDGET_SERVICING_INTERVAL,
01335 VLD_WIDGET_MIDDLE_DETAILS,
01336 VLD_WIDGET_MATRIX,
01337 VLD_WIDGET_SCROLLBAR,
01338 VLD_WIDGET_DETAILS_CARGO_CARRIED,
01339 VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
01340 VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
01341 VLD_WIDGET_DETAILS_TOTAL_CARGO,
01342 };
01343
01344 assert_compile(VLD_WIDGET_DETAILS_CARGO_CARRIED == VLD_WIDGET_DETAILS_CARGO_CARRIED + TDW_TAB_CARGO );
01345 assert_compile(VLD_WIDGET_DETAILS_TRAIN_VEHICLES == VLD_WIDGET_DETAILS_CARGO_CARRIED + TDW_TAB_INFO );
01346 assert_compile(VLD_WIDGET_DETAILS_CAPACITY_OF_EACH == VLD_WIDGET_DETAILS_CARGO_CARRIED + TDW_TAB_CAPACITY);
01347 assert_compile(VLD_WIDGET_DETAILS_TOTAL_CARGO == VLD_WIDGET_DETAILS_CARGO_CARRIED + TDW_TAB_TOTALS );
01348
01350 static const NWidgetPart _nested_nontrain_vehicle_details_widgets[] = {
01351 NWidget(NWID_HORIZONTAL),
01352 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01353 NWidget(WWT_CAPTION, COLOUR_GREY, VLD_WIDGET_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01354 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLD_WIDGET_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL ),
01355 NWidget(WWT_SHADEBOX, COLOUR_GREY),
01356 NWidget(WWT_STICKYBOX, COLOUR_GREY),
01357 EndContainer(),
01358 NWidget(WWT_PANEL, COLOUR_GREY, VLD_WIDGET_TOP_DETAILS), SetMinimalSize(405, 42), SetResize(1, 0), EndContainer(),
01359 NWidget(WWT_PANEL, COLOUR_GREY, VLD_WIDGET_MIDDLE_DETAILS), SetMinimalSize(405, 45), SetResize(1, 0), EndContainer(),
01360 NWidget(NWID_HORIZONTAL),
01361 NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, VLD_WIDGET_DECREASE_SERVICING_INTERVAL), SetFill(0, 1),
01362 SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP),
01363 NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, VLD_WIDGET_INCREASE_SERVICING_INTERVAL), SetFill(0, 1),
01364 SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_INCREASE_SERVICING_INTERVAL_TOOLTIP),
01365 NWidget(WWT_PANEL, COLOUR_GREY, VLD_WIDGET_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(),
01366 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
01367 EndContainer(),
01368 };
01369
01371 static const NWidgetPart _nested_train_vehicle_details_widgets[] = {
01372 NWidget(NWID_HORIZONTAL),
01373 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01374 NWidget(WWT_CAPTION, COLOUR_GREY, VLD_WIDGET_CAPTION), SetDataTip(STR_VEHICLE_DETAILS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01375 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLD_WIDGET_RENAME_VEHICLE), SetMinimalSize(40, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_VEHICLE_NAME_BUTTON, STR_NULL ),
01376 NWidget(WWT_SHADEBOX, COLOUR_GREY),
01377 NWidget(WWT_STICKYBOX, COLOUR_GREY),
01378 EndContainer(),
01379 NWidget(WWT_PANEL, COLOUR_GREY, VLD_WIDGET_TOP_DETAILS), SetResize(1, 0), SetMinimalSize(405, 42), EndContainer(),
01380 NWidget(NWID_HORIZONTAL),
01381 NWidget(WWT_MATRIX, COLOUR_GREY, VLD_WIDGET_MATRIX), SetResize(1, 1), SetMinimalSize(393, 45), SetDataTip(0x701, STR_NULL), SetFill(1, 0),
01382 NWidget(WWT_SCROLLBAR, COLOUR_GREY, VLD_WIDGET_SCROLLBAR),
01383 EndContainer(),
01384 NWidget(NWID_HORIZONTAL),
01385 NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, VLD_WIDGET_DECREASE_SERVICING_INTERVAL), SetFill(0, 1),
01386 SetDataTip(AWV_DECREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP),
01387 NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, VLD_WIDGET_INCREASE_SERVICING_INTERVAL), SetFill(0, 1),
01388 SetDataTip(AWV_INCREASE, STR_VEHICLE_DETAILS_DECREASE_SERVICING_INTERVAL_TOOLTIP),
01389 NWidget(WWT_PANEL, COLOUR_GREY, VLD_WIDGET_SERVICING_INTERVAL), SetFill(1, 1), SetResize(1, 0), EndContainer(),
01390 EndContainer(),
01391 NWidget(NWID_HORIZONTAL),
01392 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLD_WIDGET_DETAILS_CARGO_CARRIED), SetMinimalSize(96, 12),
01393 SetDataTip(STR_VEHICLE_DETAIL_TAB_CARGO, STR_VEHICLE_DETAILS_TRAIN_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
01394 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLD_WIDGET_DETAILS_TRAIN_VEHICLES), SetMinimalSize(99, 12),
01395 SetDataTip(STR_VEHICLE_DETAIL_TAB_INFORMATION, STR_VEHICLE_DETAILS_TRAIN_INFORMATION_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
01396 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLD_WIDGET_DETAILS_CAPACITY_OF_EACH), SetMinimalSize(99, 12),
01397 SetDataTip(STR_VEHICLE_DETAIL_TAB_CAPACITIES, STR_VEHICLE_DETAILS_TRAIN_CAPACITIES_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
01398 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, VLD_WIDGET_DETAILS_TOTAL_CARGO), SetMinimalSize(99, 12),
01399 SetDataTip(STR_VEHICLE_DETAIL_TAB_TOTAL_CARGO, STR_VEHICLE_DETAILS_TRAIN_TOTAL_CARGO_TOOLTIP), SetFill(1, 0), SetResize(1, 0),
01400 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
01401 EndContainer(),
01402 };
01403
01404
01405 extern int GetTrainDetailsWndVScroll(VehicleID veh_id, TrainDetailsWindowTabs det_tab);
01406 extern void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_pos, uint16 vscroll_cap, TrainDetailsWindowTabs det_tab);
01407 extern void DrawRoadVehDetails(const Vehicle *v, int left, int right, int y);
01408 extern void DrawShipDetails(const Vehicle *v, int left, int right, int y);
01409 extern void DrawAircraftDetails(const Aircraft *v, int left, int right, int y);
01410
01412 struct VehicleDetailsWindow : Window {
01413 TrainDetailsWindowTabs tab;
01414
01416 VehicleDetailsWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
01417 {
01418 this->InitNested(desc, window_number);
01419
01420 const Vehicle *v = Vehicle::Get(this->window_number);
01421
01422 this->GetWidget<NWidgetCore>(VLD_WIDGET_RENAME_VEHICLE)->tool_tip = STR_VEHICLE_DETAILS_TRAIN_RENAME + v->type;
01423
01424 this->owner = v->owner;
01425 this->tab = TDW_TAB_CARGO;
01426 }
01427
01428 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01429 {
01430 switch (widget) {
01431 case VLD_WIDGET_TOP_DETAILS: {
01432 Dimension dim = { 0, 0 };
01433 size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
01434
01435 for (uint i = 0; i < 4; i++) SetDParam(i, INT16_MAX);
01436 static const StringID info_strings[] = {
01437 STR_VEHICLE_INFO_MAX_SPEED,
01438 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED,
01439 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE,
01440 STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR,
01441 STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS
01442 };
01443 for (uint i = 0; i < lengthof(info_strings); i++) {
01444 dim = maxdim(dim, GetStringBoundingBox(info_strings[i]));
01445 }
01446 SetDParam(0, STR_VEHICLE_INFO_AGE);
01447 dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_AGE_RUNNING_COST_YR));
01448 size->width = dim.width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01449 } break;
01450
01451 case VLD_WIDGET_MIDDLE_DETAILS: {
01452 const Vehicle *v = Vehicle::Get(this->window_number);
01453 switch (v->type) {
01454 case VEH_ROAD:
01455 if (RoadVehicle::From(v)->HasArticulatedPart()) {
01456
01457 size->height = WD_FRAMERECT_TOP + 15 + 3 * FONT_HEIGHT_NORMAL + 2 + WD_FRAMERECT_BOTTOM;
01458
01459 for (const Vehicle *u = v; u != NULL; u = u->Next()) {
01460 if (u->cargo_cap != 0) size->height += FONT_HEIGHT_NORMAL + 1;
01461 }
01462 } else {
01463 size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM;
01464 }
01465 break;
01466
01467 case VEH_SHIP:
01468 size->height = WD_FRAMERECT_TOP + 4 * FONT_HEIGHT_NORMAL + 3 + WD_FRAMERECT_BOTTOM;
01469 break;
01470
01471 case VEH_AIRCRAFT:
01472 size->height = WD_FRAMERECT_TOP + 5 * FONT_HEIGHT_NORMAL + 4 + WD_FRAMERECT_BOTTOM;
01473 break;
01474
01475 default:
01476 NOT_REACHED();
01477 }
01478 break;
01479 }
01480
01481 case VLD_WIDGET_MATRIX:
01482 resize->height = WD_MATRIX_TOP + FONT_HEIGHT_NORMAL + WD_MATRIX_BOTTOM;
01483 size->height = 4 * resize->height;
01484 break;
01485
01486 case VLD_WIDGET_SERVICING_INTERVAL:
01487 SetDParam(0, 9999);
01488 SetDParam(1, MAX_YEAR * DAYS_IN_YEAR);
01489 size->width = max(GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT).width, GetStringBoundingBox(STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS).width) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01490 size->height = WD_FRAMERECT_TOP + FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM;
01491 break;
01492 }
01493 }
01494
01496 static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type, CompanyID company_id)
01497 {
01498 const VehicleDefaultSettings *vds = &Company::Get(company_id)->settings.vehicle;
01499 switch (vehicle_type) {
01500 default: NOT_REACHED();
01501 case VEH_TRAIN: return vds->servint_trains != 0;
01502 case VEH_ROAD: return vds->servint_roadveh != 0;
01503 case VEH_SHIP: return vds->servint_ships != 0;
01504 case VEH_AIRCRAFT: return vds->servint_aircraft != 0;
01505 }
01506 }
01507
01519 static void DrawVehicleDetails(const Vehicle *v, int left, int right, int y, int vscroll_pos, uint vscroll_cap, TrainDetailsWindowTabs det_tab)
01520 {
01521 switch (v->type) {
01522 case VEH_TRAIN: DrawTrainDetails(Train::From(v), left, right, y, vscroll_pos, vscroll_cap, det_tab); break;
01523 case VEH_ROAD: DrawRoadVehDetails(v, left, right, y); break;
01524 case VEH_SHIP: DrawShipDetails(v, left, right, y); break;
01525 case VEH_AIRCRAFT: DrawAircraftDetails(Aircraft::From(v), left, right, y); break;
01526 default: NOT_REACHED();
01527 }
01528 }
01529
01530 virtual void SetStringParameters(int widget) const
01531 {
01532 if (widget == VLD_WIDGET_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index);
01533 }
01534
01535 virtual void DrawWidget(const Rect &r, int widget) const
01536 {
01537 const Vehicle *v = Vehicle::Get(this->window_number);
01538
01539 switch (widget) {
01540 case VLD_WIDGET_TOP_DETAILS: {
01541 int y = r.top + WD_FRAMERECT_TOP;
01542
01543
01544 SetDParam(1, v->age / DAYS_IN_LEAP_YEAR);
01545 SetDParam(0, (v->age + DAYS_IN_YEAR < v->max_age) ? STR_VEHICLE_INFO_AGE : STR_VEHICLE_INFO_AGE_RED);
01546 SetDParam(2, v->max_age / DAYS_IN_LEAP_YEAR);
01547 SetDParam(3, v->GetDisplayRunningCost());
01548 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_AGE_RUNNING_COST_YR);
01549 y += FONT_HEIGHT_NORMAL;
01550
01551
01552 switch (v->type) {
01553 case VEH_TRAIN:
01554 SetDParam(2, v->GetDisplayMaxSpeed());
01555 SetDParam(1, Train::From(v)->tcache.cached_power);
01556 SetDParam(0, Train::From(v)->tcache.cached_weight);
01557 SetDParam(3, Train::From(v)->tcache.cached_max_te / 1000);
01558 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, (_settings_game.vehicle.train_acceleration_model != TAM_ORIGINAL && Train::From(v)->railtype != RAILTYPE_MAGLEV) ?
01559 STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE : STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED);
01560 break;
01561
01562 case VEH_ROAD:
01563 case VEH_SHIP:
01564 case VEH_AIRCRAFT:
01565 SetDParam(0, v->GetDisplayMaxSpeed());
01566 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_MAX_SPEED);
01567 break;
01568
01569 default: NOT_REACHED();
01570 }
01571 y += FONT_HEIGHT_NORMAL;
01572
01573
01574 SetDParam(0, v->GetDisplayProfitThisYear());
01575 SetDParam(1, v->GetDisplayProfitLastYear());
01576 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR);
01577 y += FONT_HEIGHT_NORMAL;
01578
01579
01580 SetDParam(0, ToPercent16(v->reliability));
01581 SetDParam(1, v->breakdowns_since_last_service);
01582 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_RELIABILITY_BREAKDOWNS);
01583 break;
01584 }
01585
01586 case VLD_WIDGET_MATRIX:
01587
01588 DrawVehicleDetails(v, r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, r.top + WD_MATRIX_TOP, this->vscroll.GetPosition(), this->vscroll.GetCapacity(), this->tab);
01589 break;
01590
01591 case VLD_WIDGET_MIDDLE_DETAILS: {
01592
01593 bool rtl = _dynlang.text_dir == TD_RTL;
01594 uint sprite_width = max<uint>(GetSprite(v->GetImage(rtl ? DIR_E : DIR_W), ST_NORMAL)->width, 70U) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01595
01596 uint text_left = r.left + (rtl ? 0 : sprite_width);
01597 uint text_right = r.right - (rtl ? sprite_width : 0);
01598
01599 uint sprite_left = rtl ? text_right : r.left;
01600 uint sprite_right = rtl ? r.right : text_left;
01601
01602 DrawVehicleImage(v, sprite_left + WD_FRAMERECT_LEFT, sprite_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, INVALID_VEHICLE, 0);
01603 DrawVehicleDetails(v, text_left + WD_FRAMERECT_LEFT, text_right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, this->vscroll.GetPosition(), this->vscroll.GetCapacity(), this->tab);
01604 } break;
01605
01606 case VLD_WIDGET_SERVICING_INTERVAL:
01607
01608 SetDParam(0, v->service_interval);
01609 SetDParam(1, v->date_of_last_service);
01610 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + (r.bottom - r.top + 1 - FONT_HEIGHT_NORMAL) / 2,
01611 Company::Get(v->owner)->settings.vehicle.servint_ispercent ? STR_VEHICLE_DETAILS_SERVICING_INTERVAL_PERCENT : STR_VEHICLE_DETAILS_SERVICING_INTERVAL_DAYS);
01612 break;
01613 }
01614 }
01615
01617 virtual void OnPaint()
01618 {
01619 const Vehicle *v = Vehicle::Get(this->window_number);
01620
01621 this->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_company);
01622
01623 if (v->type == VEH_TRAIN) {
01624 this->DisableWidget(this->tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
01625 this->vscroll.SetCount(GetTrainDetailsWndVScroll(v->index, this->tab));
01626 }
01627
01628
01629 this->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type, v->owner),
01630 VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
01631 VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
01632 WIDGET_LIST_END);
01633
01634 this->DrawWidgets();
01635 }
01636
01637 virtual void OnClick(Point pt, int widget)
01638 {
01639 switch (widget) {
01640 case VLD_WIDGET_RENAME_VEHICLE: {
01641 const Vehicle *v = Vehicle::Get(this->window_number);
01642 SetDParam(0, v->index);
01643 ShowQueryString(STR_VEHICLE_NAME, STR_QUERY_RENAME_TRAIN_CAPTION + v->type,
01644 MAX_LENGTH_VEHICLE_NAME_BYTES, MAX_LENGTH_VEHICLE_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
01645 } break;
01646
01647 case VLD_WIDGET_INCREASE_SERVICING_INTERVAL:
01648 case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: {
01649 int mod = _ctrl_pressed ? 5 : 10;
01650 const Vehicle *v = Vehicle::Get(this->window_number);
01651
01652 mod = (widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
01653 mod = GetServiceIntervalClamped(mod + v->service_interval, v->owner);
01654 if (mod == v->service_interval) return;
01655
01656 DoCommandP(v->tile, v->index, mod, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_SERVICING));
01657 } break;
01658
01659 case VLD_WIDGET_DETAILS_CARGO_CARRIED:
01660 case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
01661 case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
01662 case VLD_WIDGET_DETAILS_TOTAL_CARGO:
01663 this->SetWidgetsDisabledState(false,
01664 VLD_WIDGET_DETAILS_CARGO_CARRIED,
01665 VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
01666 VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
01667 VLD_WIDGET_DETAILS_TOTAL_CARGO,
01668 widget,
01669 WIDGET_LIST_END);
01670
01671 this->tab = (TrainDetailsWindowTabs)(widget - VLD_WIDGET_DETAILS_CARGO_CARRIED);
01672 this->SetDirty();
01673 break;
01674 }
01675 }
01676
01677 virtual void OnQueryTextFinished(char *str)
01678 {
01679 if (str == NULL) return;
01680
01681 DoCommandP(0, this->window_number, 0, CMD_RENAME_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_RENAME_TRAIN + Vehicle::Get(this->window_number)->type), NULL, str);
01682 }
01683
01684 virtual void OnResize()
01685 {
01686 NWidgetCore *nwi = this->GetWidget<NWidgetCore>(VLD_WIDGET_MATRIX);
01687 if (nwi != NULL) {
01688 this->vscroll.SetCapacityFromWidget(this, VLD_WIDGET_MATRIX);
01689 nwi->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
01690 }
01691 }
01692 };
01693
01695 static const WindowDesc _train_vehicle_details_desc(
01696 WDP_AUTO, 405, 178,
01697 WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
01698 WDF_UNCLICK_BUTTONS,
01699 _nested_train_vehicle_details_widgets, lengthof(_nested_train_vehicle_details_widgets)
01700 );
01701
01703 static const WindowDesc _nontrain_vehicle_details_desc(
01704 WDP_AUTO, 405, 113,
01705 WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
01706 WDF_UNCLICK_BUTTONS,
01707 _nested_nontrain_vehicle_details_widgets, lengthof(_nested_nontrain_vehicle_details_widgets)
01708 );
01709
01711 static void ShowVehicleDetailsWindow(const Vehicle *v)
01712 {
01713 DeleteWindowById(WC_VEHICLE_ORDERS, v->index, false);
01714 DeleteWindowById(WC_VEHICLE_TIMETABLE, v->index, false);
01715 AllocateWindowDescFront<VehicleDetailsWindow>((v->type == VEH_TRAIN) ? &_train_vehicle_details_desc : &_nontrain_vehicle_details_desc, v->index);
01716 }
01717
01718
01719
01720
01722 static const NWidgetPart _nested_vehicle_view_widgets[] = {
01723 NWidget(NWID_HORIZONTAL),
01724 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01725 NWidget(WWT_CAPTION, COLOUR_GREY, VVW_WIDGET_CAPTION), SetDataTip(STR_VEHICLE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01726 NWidget(WWT_SHADEBOX, COLOUR_GREY),
01727 NWidget(WWT_STICKYBOX, COLOUR_GREY),
01728 EndContainer(),
01729 NWidget(NWID_HORIZONTAL),
01730 NWidget(WWT_PANEL, COLOUR_GREY),
01731 NWidget(WWT_INSET, COLOUR_GREY), SetPadding(2, 2, 2, 2),
01732 NWidget(NWID_VIEWPORT, INVALID_COLOUR, VVW_WIDGET_VIEWPORT), SetMinimalSize(226, 84), SetResize(1, 1), SetPadding(1, 1, 1, 1),
01733 EndContainer(),
01734 EndContainer(),
01735 NWidget(NWID_VERTICAL),
01736 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_CENTER_MAIN_VIEH), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_CENTRE_VIEW_VEHICLE, 0x0 ),
01737 NWidget(NWID_SELECTION, INVALID_COLOUR, VVW_WIDGET_SELECT_DEPOT_CLONE),
01738 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_GOTO_DEPOT), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 , 0x0 ),
01739 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_CLONE_VEH), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(0x0 , 0x0 ),
01740 EndContainer(),
01741
01742 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_FORCE_PROCEED), SetMinimalSize(18, 18), SetFill(1, 1),
01743 SetDataTip(SPR_IGNORE_SIGNALS, STR_VEHICLE_VIEW_TRAIN_IGNORE_SIGNAL_TOOLTIP),
01744 NWidget(NWID_SELECTION, INVALID_COLOUR, VVW_WIDGET_SELECT_REFIT_TURN),
01745 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_REFIT_VEH), SetMinimalSize(18, 18), SetFill(1, 1), SetDataTip(SPR_REFIT_VEHICLE, 0x0 ),
01746 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_TURN_AROUND), SetMinimalSize(18, 18), SetFill(1, 1),
01747 SetDataTip(SPR_FORCE_VEHICLE_TURN, STR_VEHICLE_VIEW_ROAD_VEHICLE_REVERSE_TOOLTIP),
01748 EndContainer(),
01749 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_SHOW_ORDERS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_ORDERS, 0x0 ),
01750 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, VVW_WIDGET_SHOW_DETAILS), SetFill(1, 1), SetMinimalSize(18, 18), SetDataTip(SPR_SHOW_VEHICLE_DETAILS, 0x0 ),
01751 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetMinimalSize(18, 0), SetResize(0, 1), EndContainer(),
01752 EndContainer(),
01753 EndContainer(),
01754 NWidget(NWID_HORIZONTAL),
01755 NWidget(WWT_PUSHBTN, COLOUR_GREY, VVW_WIDGET_START_STOP_VEH), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM), SetResize(1, 0), SetFill(1, 0),
01756 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
01757 EndContainer(),
01758 };
01759
01761 static const WindowDesc _vehicle_view_desc(
01762 WDP_AUTO, 250, 116,
01763 WC_VEHICLE_VIEW, WC_NONE,
01764 WDF_UNCLICK_BUTTONS,
01765 _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets)
01766 );
01767
01771 static const WindowDesc _train_view_desc(
01772 WDP_AUTO, 250, 134,
01773 WC_VEHICLE_VIEW, WC_NONE,
01774 WDF_UNCLICK_BUTTONS,
01775 _nested_vehicle_view_widgets, lengthof(_nested_vehicle_view_widgets)
01776 );
01777
01778
01779
01780
01781 assert_compile(VEH_TRAIN == 0);
01782 assert_compile(VEH_ROAD == 1);
01783 assert_compile(VEH_SHIP == 2);
01784 assert_compile(VEH_AIRCRAFT == 3);
01785
01787 static const ZoomLevel _vehicle_view_zoom_levels[] = {
01788 ZOOM_LVL_TRAIN,
01789 ZOOM_LVL_ROADVEH,
01790 ZOOM_LVL_SHIP,
01791 ZOOM_LVL_AIRCRAFT,
01792 };
01793
01794
01795 static const int VV_INITIAL_VIEWPORT_WIDTH = 226;
01796 static const int VV_INITIAL_VIEWPORT_HEIGHT = 84;
01797 static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102;
01798
01800 enum VehicleCommandTranslation {
01801 VCT_CMD_START_STOP = 0,
01802 VCT_CMD_CLONE_VEH,
01803 VCT_CMD_TURN_AROUND,
01804 };
01805
01807 static const uint32 _vehicle_command_translation_table[][4] = {
01808 {
01809 CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_TRAIN),
01810 CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE),
01811 CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_SHIP),
01812 CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_AIRCRAFT)
01813 },
01814 {
01815 CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN),
01816 CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_ROAD_VEHICLE),
01817 CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_SHIP),
01818 CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_AIRCRAFT)
01819 },
01820 {
01821 CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_TRAIN),
01822 CMD_TURN_ROADVEH | CMD_MSG(STR_ERROR_CAN_T_MAKE_ROAD_VEHICLE_TURN),
01823 0xffffffff,
01824 0xffffffff
01825 },
01826 };
01827
01829 static bool IsVehicleRefitable(const Vehicle *v)
01830 {
01831 if (!v->IsStoppedInDepot()) return false;
01832
01833 do {
01834 if (IsEngineRefittable(v->engine_type)) return true;
01835 } while ((v->type == VEH_TRAIN || v->type == VEH_ROAD) && (v = v->Next()) != NULL);
01836
01837 return false;
01838 }
01839
01841 struct VehicleViewWindow : Window {
01842 private:
01844 enum PlaneSelections {
01845 SEL_DC_GOTO_DEPOT,
01846 SEL_DC_CLONE,
01847
01848 SEL_RT_REFIT,
01849 SEL_RT_TURN_AROUND,
01850
01851 SEL_DC_BASEPLANE = SEL_DC_GOTO_DEPOT,
01852 SEL_RT_BASEPLANE = SEL_RT_REFIT,
01853 };
01854
01858 void SelectPlane(PlaneSelections plane)
01859 {
01860 switch (plane) {
01861 case SEL_DC_GOTO_DEPOT:
01862 case SEL_DC_CLONE:
01863 this->GetWidget<NWidgetStacked>(VVW_WIDGET_SELECT_DEPOT_CLONE)->SetDisplayedPlane(plane - SEL_DC_BASEPLANE);
01864 break;
01865
01866 case SEL_RT_REFIT:
01867 case SEL_RT_TURN_AROUND:
01868 this->GetWidget<NWidgetStacked>(VVW_WIDGET_SELECT_REFIT_TURN)->SetDisplayedPlane(plane - SEL_RT_BASEPLANE);
01869 break;
01870
01871 default:
01872 NOT_REACHED();
01873 }
01874 }
01875
01876 public:
01877 VehicleViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
01878 {
01879 this->CreateNestedTree(desc);
01880
01881
01882 static const SpriteID vehicle_view_goto_depot_sprites[] = {
01883 SPR_SEND_TRAIN_TODEPOT,
01884 SPR_SEND_ROADVEH_TODEPOT,
01885 SPR_SEND_SHIP_TODEPOT,
01886 SPR_SEND_AIRCRAFT_TODEPOT,
01887 };
01888 const Vehicle *v = Vehicle::Get(window_number);
01889 this->GetWidget<NWidgetCore>(VVW_WIDGET_GOTO_DEPOT)->widget_data = vehicle_view_goto_depot_sprites[v->type];
01890
01891
01892 static const SpriteID vehicle_view_clone_sprites[] = {
01893 SPR_CLONE_TRAIN,
01894 SPR_CLONE_ROADVEH,
01895 SPR_CLONE_SHIP,
01896 SPR_CLONE_AIRCRAFT,
01897 };
01898 this->GetWidget<NWidgetCore>(VVW_WIDGET_CLONE_VEH)->widget_data = vehicle_view_clone_sprites[v->type];
01899
01900 switch (v->type) {
01901 case VEH_TRAIN:
01902 this->GetWidget<NWidgetCore>(VVW_WIDGET_TURN_AROUND)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REVERSE_TOOLTIP;
01903 break;
01904
01905 case VEH_ROAD:
01906 break;
01907
01908 case VEH_SHIP:
01909 case VEH_AIRCRAFT:
01910 this->SelectPlane(SEL_RT_REFIT);
01911 break;
01912
01913 default: NOT_REACHED();
01914 }
01915 this->FinishInitNested(desc, window_number);
01916 this->owner = v->owner;
01917 this->GetWidget<NWidgetViewport>(VVW_WIDGET_VIEWPORT)->InitializeViewport(this, this->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]);
01918
01919 this->GetWidget<NWidgetCore>(VVW_WIDGET_START_STOP_VEH)->tool_tip = STR_VEHICLE_VIEW_TRAIN_STATE_START_STOP_TOOLTIP + v->type;
01920 this->GetWidget<NWidgetCore>(VVW_WIDGET_CENTER_MAIN_VIEH)->tool_tip = STR_VEHICLE_VIEW_TRAIN_LOCATION_TOOLTIP + v->type;
01921 this->GetWidget<NWidgetCore>(VVW_WIDGET_REFIT_VEH)->tool_tip = STR_VEHICLE_VIEW_TRAIN_REFIT_TOOLTIP + v->type;
01922 this->GetWidget<NWidgetCore>(VVW_WIDGET_GOTO_DEPOT)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SEND_TO_DEPOT_TOOLTIP + v->type;
01923 this->GetWidget<NWidgetCore>(VVW_WIDGET_SHOW_ORDERS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_ORDERS_TOOLTIP + v->type;
01924 this->GetWidget<NWidgetCore>(VVW_WIDGET_SHOW_DETAILS)->tool_tip = STR_VEHICLE_VIEW_TRAIN_SHOW_DETAILS_TOOLTIP + v->type;
01925 this->GetWidget<NWidgetCore>(VVW_WIDGET_CLONE_VEH)->tool_tip = STR_VEHICLE_VIEW_CLONE_TRAIN_INFO + v->type;
01926 }
01927
01928 ~VehicleViewWindow()
01929 {
01930 DeleteWindowById(WC_VEHICLE_ORDERS, this->window_number, false);
01931 DeleteWindowById(WC_VEHICLE_REFIT, this->window_number, false);
01932 DeleteWindowById(WC_VEHICLE_DETAILS, this->window_number, false);
01933 DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number, false);
01934 }
01935
01936 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01937 {
01938 const Vehicle *v = Vehicle::Get(this->window_number);
01939 switch (widget) {
01940 case VVW_WIDGET_FORCE_PROCEED:
01941 if (v->type != VEH_TRAIN) {
01942 size->height = 0;
01943 size->width = 0;
01944 } break;
01945
01946 case VVW_WIDGET_VIEWPORT:
01947 size->width = VV_INITIAL_VIEWPORT_WIDTH;
01948 size->height = (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT;
01949 break;
01950 }
01951 }
01952
01953 virtual void OnPaint()
01954 {
01955 const Vehicle *v = Vehicle::Get(this->window_number);
01956 bool is_localcompany = v->owner == _local_company;
01957 bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
01958
01959 this->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localcompany);
01960 this->SetWidgetDisabledState(VVW_WIDGET_REFIT_VEH, !refitable_and_stopped_in_depot || !is_localcompany);
01961 this->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localcompany);
01962
01963 if (v->type == VEH_TRAIN) {
01964 this->SetWidgetLoweredState(VVW_WIDGET_FORCE_PROCEED, Train::From(v)->force_proceed == 2);
01965 this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localcompany);
01966 this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localcompany);
01967 }
01968
01969 this->DrawWidgets();
01970 }
01971
01972 virtual void SetStringParameters(int widget) const
01973 {
01974 if (widget != VVW_WIDGET_CAPTION) return;
01975
01976 const Vehicle *v = Vehicle::Get(this->window_number);
01977 SetDParam(0, v->index);
01978 }
01979
01980 virtual void DrawWidget(const Rect &r, int widget) const
01981 {
01982 if (widget != VVW_WIDGET_START_STOP_VEH) return;
01983
01984 const Vehicle *v = Vehicle::Get(this->window_number);
01985 StringID str;
01986 if (v->vehstatus & VS_CRASHED) {
01987 str = STR_VEHICLE_STATUS_CRASHED;
01988 } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) {
01989 str = STR_VEHICLE_STATUS_BROKEN_DOWN;
01990 } else if (v->vehstatus & VS_STOPPED) {
01991 if (v->type == VEH_TRAIN) {
01992 if (v->cur_speed == 0) {
01993 if (Train::From(v)->tcache.cached_power == 0) {
01994 str = STR_VEHICLE_STATUS_TRAIN_NO_POWER;
01995 } else {
01996 str = STR_VEHICLE_STATUS_STOPPED;
01997 }
01998 } else {
01999 SetDParam(0, v->GetDisplaySpeed());
02000 str = STR_VEHICLE_STATUS_TRAIN_STOPPING + _settings_client.gui.vehicle_speed;
02001 }
02002 } else {
02003 str = STR_VEHICLE_STATUS_STOPPED;
02004 }
02005 } else if (v->type == VEH_TRAIN && HasBit(Train::From(v)->flags, VRF_TRAIN_STUCK) && !v->current_order.IsType(OT_LOADING)) {
02006 str = STR_VEHICLE_STATUS_TRAIN_STUCK;
02007 } else {
02008 switch (v->current_order.GetType()) {
02009 case OT_GOTO_STATION: {
02010 SetDParam(0, v->current_order.GetDestination());
02011 SetDParam(1, v->GetDisplaySpeed());
02012 str = STR_VEHICLE_STATUS_HEADING_FOR_STATION + _settings_client.gui.vehicle_speed;
02013 } break;
02014
02015 case OT_GOTO_DEPOT: {
02016 if (v->type == VEH_AIRCRAFT) {
02017
02018 SetDParam(0, v->current_order.GetDestination());
02019 SetDParam(1, v->GetDisplaySpeed());
02020 } else {
02021 Depot *depot = Depot::Get(v->current_order.GetDestination());
02022 SetDParam(0, depot->town_index);
02023 SetDParam(1, v->GetDisplaySpeed());
02024 }
02025 if (v->current_order.GetDepotActionType() & ODATFB_HALT) {
02026 str = STR_VEHICLE_STATUS_HEADING_FOR_TRAIN_DEPOT + 2 * v->type + _settings_client.gui.vehicle_speed;
02027 } else {
02028 str = STR_VEHICLE_STATUS_HEADING_FOR_TRAIN_DEPOT_SERVICE + 2 * v->type + _settings_client.gui.vehicle_speed;
02029 }
02030 } break;
02031
02032 case OT_LOADING:
02033 str = STR_VEHICLE_STATUS_LOADING_UNLOADING;
02034 break;
02035
02036 case OT_GOTO_WAYPOINT: {
02037 assert(v->type == VEH_TRAIN || v->type == VEH_SHIP);
02038 SetDParam(0, v->current_order.GetDestination());
02039 str = STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT + _settings_client.gui.vehicle_speed;
02040 SetDParam(1, v->GetDisplaySpeed());
02041 break;
02042 }
02043
02044 case OT_LEAVESTATION:
02045 if (v->type != VEH_AIRCRAFT) {
02046 str = STR_VEHICLE_STATUS_LEAVING;
02047 break;
02048 }
02049
02050
02051 default:
02052 if (v->GetNumOrders() == 0) {
02053 str = STR_VEHICLE_STATUS_NO_ORDERS + _settings_client.gui.vehicle_speed;
02054 SetDParam(0, v->GetDisplaySpeed());
02055 } else {
02056 str = STR_EMPTY;
02057 }
02058 break;
02059 }
02060 }
02061
02062
02063 DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP);
02064 DrawString(r.left + WD_FRAMERECT_LEFT + 6, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_FROMSTRING, SA_CENTER);
02065 }
02066
02067 virtual void OnClick(Point pt, int widget)
02068 {
02069 const Vehicle *v = Vehicle::Get(this->window_number);
02070
02071 switch (widget) {
02072 case VVW_WIDGET_START_STOP_VEH:
02073 DoCommandP(v->tile, v->index, 0,
02074 _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type]);
02075 break;
02076 case VVW_WIDGET_CENTER_MAIN_VIEH: {
02077 const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
02078
02079 if (_ctrl_pressed && mainwindow->viewport->zoom == ZOOM_LVL_NORMAL) {
02080 mainwindow->viewport->follow_vehicle = v->index;
02081 } else {
02082 ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos);
02083 }
02084 } break;
02085
02086 case VVW_WIDGET_GOTO_DEPOT:
02087 DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, GetCmdSendToDepot(v));
02088 break;
02089 case VVW_WIDGET_REFIT_VEH:
02090 ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID, this);
02091 break;
02092 case VVW_WIDGET_SHOW_ORDERS:
02093 if (_ctrl_pressed) {
02094 ShowTimetableWindow(v);
02095 } else {
02096 ShowOrdersWindow(v);
02097 }
02098 break;
02099 case VVW_WIDGET_SHOW_DETAILS:
02100 ShowVehicleDetailsWindow(v);
02101 break;
02102 case VVW_WIDGET_CLONE_VEH:
02103 DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0,
02104 _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type],
02105 CcCloneVehicle);
02106 break;
02107 case VVW_WIDGET_TURN_AROUND:
02108 assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
02109 DoCommandP(v->tile, v->index, 0,
02110 _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]);
02111 break;
02112 case VVW_WIDGET_FORCE_PROCEED:
02113 assert(v->type == VEH_TRAIN);
02114 DoCommandP(v->tile, v->index, 0, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_ERROR_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
02115 break;
02116 }
02117 }
02118
02119 virtual void OnResize()
02120 {
02121 if (this->viewport != NULL) {
02122 NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(VVW_WIDGET_VIEWPORT);
02123 nvp->UpdateViewportCoordinates(this);
02124 }
02125 }
02126
02127 virtual void OnTick()
02128 {
02129 const Vehicle *v = Vehicle::Get(this->window_number);
02130 bool veh_stopped = v->IsStoppedInDepot();
02131
02132
02133
02134
02135 PlaneSelections plane = veh_stopped ? SEL_DC_CLONE : SEL_DC_GOTO_DEPOT;
02136 NWidgetStacked *nwi = this->GetWidget<NWidgetStacked>(VVW_WIDGET_SELECT_DEPOT_CLONE);
02137 if (nwi->shown_plane + SEL_DC_BASEPLANE != plane) {
02138 this->SelectPlane(plane);
02139 this->SetWidgetDirty(VVW_WIDGET_SELECT_DEPOT_CLONE);
02140 }
02141
02142 if (v->type == VEH_ROAD || v->type == VEH_TRAIN) {
02143 PlaneSelections plane = veh_stopped ? SEL_RT_REFIT : SEL_RT_TURN_AROUND;
02144 NWidgetStacked *nwi = this->GetWidget<NWidgetStacked>(VVW_WIDGET_SELECT_REFIT_TURN);
02145 if (nwi->shown_plane + SEL_RT_BASEPLANE != plane) {
02146 this->SelectPlane(plane);
02147 this->SetWidgetDirty(VVW_WIDGET_SELECT_REFIT_TURN);
02148 }
02149 }
02150 }
02151 };
02152
02153
02155 void ShowVehicleViewWindow(const Vehicle *v)
02156 {
02157 AllocateWindowDescFront<VehicleViewWindow>((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index);
02158 }
02159
02160 void StopGlobalFollowVehicle(const Vehicle *v)
02161 {
02162 Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
02163 if (w != NULL && w->viewport->follow_vehicle == v->index) {
02164 ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos, true);
02165 w->viewport->follow_vehicle = INVALID_VEHICLE;
02166 }
02167 }