00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "train.h"
00013 #include "ship.h"
00014 #include "aircraft.h"
00015 #include "roadveh.h"
00016 #include "gui.h"
00017 #include "textbuf_gui.h"
00018 #include "viewport_func.h"
00019 #include "gfx_func.h"
00020 #include "command_func.h"
00021 #include "depot_base.h"
00022 #include "vehicle_gui.h"
00023 #include "newgrf_engine.h"
00024 #include "spritecache.h"
00025 #include "strings_func.h"
00026 #include "window_func.h"
00027 #include "vehicle_func.h"
00028 #include "company_func.h"
00029 #include "tilehighlight_func.h"
00030 #include "window_gui.h"
00031 #include "vehiclelist.h"
00032 #include "infrastructure_func.h"
00033
00034 #include "table/strings.h"
00035 #include "table/sprites.h"
00036
00037
00038
00039
00040
00041
00042
00043
00044 enum DepotWindowWidgets {
00045 DEPOT_WIDGET_CAPTION,
00046 DEPOT_WIDGET_SELL,
00047 DEPOT_WIDGET_SELL_CHAIN,
00048 DEPOT_WIDGET_SELL_ALL,
00049 DEPOT_WIDGET_AUTOREPLACE,
00050 DEPOT_WIDGET_MATRIX,
00051 DEPOT_WIDGET_V_SCROLL,
00052 DEPOT_WIDGET_H_SCROLL,
00053 DEPOT_WIDGET_BUILD,
00054 DEPOT_WIDGET_CLONE,
00055 DEPOT_WIDGET_LOCATION,
00056 DEPOT_WIDGET_VEHICLE_LIST,
00057 DEPOT_WIDGET_STOP_ALL,
00058 DEPOT_WIDGET_START_ALL,
00059 };
00060
00062 static const NWidgetPart _nested_train_depot_widgets[] = {
00063 NWidget(NWID_HORIZONTAL),
00064 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00065 NWidget(WWT_CAPTION, COLOUR_GREY, DEPOT_WIDGET_CAPTION),
00066 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00067 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00068 EndContainer(),
00069 NWidget(NWID_HORIZONTAL),
00070 NWidget(NWID_VERTICAL),
00071 NWidget(WWT_MATRIX, COLOUR_GREY, DEPOT_WIDGET_MATRIX), SetDataTip(0x0, STR_NULL), SetResize(1, 1),
00072 NWidget(WWT_HSCROLLBAR, COLOUR_GREY, DEPOT_WIDGET_H_SCROLL),
00073 EndContainer(),
00074 NWidget(NWID_VERTICAL),
00075 NWidget(WWT_IMGBTN, COLOUR_GREY, DEPOT_WIDGET_SELL), SetDataTip(0x0, STR_NULL), SetResize(0, 1), SetFill(0, 1),
00076 NWidget(WWT_IMGBTN, COLOUR_GREY, DEPOT_WIDGET_SELL_CHAIN), SetDataTip(SPR_SELL_CHAIN_TRAIN, STR_DEPOT_DRAG_WHOLE_TRAIN_TO_SELL_TOOLTIP), SetResize(0, 1), SetFill(0, 1),
00077 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, DEPOT_WIDGET_SELL_ALL), SetDataTip(0x0, STR_NULL),
00078 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, DEPOT_WIDGET_AUTOREPLACE), SetDataTip(0x0, STR_NULL),
00079 EndContainer(),
00080 NWidget(WWT_SCROLLBAR, COLOUR_GREY, DEPOT_WIDGET_V_SCROLL),
00081 EndContainer(),
00082 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00083 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, DEPOT_WIDGET_BUILD), SetDataTip(0x0, STR_NULL), SetFill(1, 1), SetResize(1, 0),
00084 NWidget(WWT_TEXTBTN, COLOUR_GREY, DEPOT_WIDGET_CLONE), SetDataTip(0x0, STR_NULL), SetFill(1, 1), SetResize(1, 0),
00085 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, DEPOT_WIDGET_LOCATION), SetDataTip(STR_BUTTON_LOCATION, STR_NULL), SetFill(1, 1), SetResize(1, 0),
00086 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, DEPOT_WIDGET_VEHICLE_LIST), SetDataTip(0x0, STR_NULL), SetFill(0, 1),
00087 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, DEPOT_WIDGET_STOP_ALL), SetDataTip(SPR_FLAG_VEH_STOPPED, STR_NULL), SetFill(0, 1),
00088 NWidget(WWT_PUSHIMGBTN, COLOUR_GREY, DEPOT_WIDGET_START_ALL), SetDataTip(SPR_FLAG_VEH_RUNNING, STR_NULL), SetFill(0, 1),
00089 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
00090 EndContainer(),
00091 };
00092
00093 static const WindowDesc _train_depot_desc(
00094 WDP_AUTO, 362, 123,
00095 WC_VEHICLE_DEPOT, WC_NONE,
00096 WDF_UNCLICK_BUTTONS,
00097 _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
00098 );
00099
00100 static const WindowDesc _road_depot_desc(
00101 WDP_AUTO, 316, 97,
00102 WC_VEHICLE_DEPOT, WC_NONE,
00103 WDF_UNCLICK_BUTTONS,
00104 _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
00105 );
00106
00107 static const WindowDesc _ship_depot_desc(
00108 WDP_AUTO, 306, 99,
00109 WC_VEHICLE_DEPOT, WC_NONE,
00110 WDF_UNCLICK_BUTTONS,
00111 _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
00112 );
00113
00114 static const WindowDesc _aircraft_depot_desc(
00115 WDP_AUTO, 332, 99,
00116 WC_VEHICLE_DEPOT, WC_NONE,
00117 WDF_UNCLICK_BUTTONS,
00118 _nested_train_depot_widgets, lengthof(_nested_train_depot_widgets)
00119 );
00120
00121 extern void DepotSortList(VehicleList *list);
00122
00130 void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2)
00131 {
00132 if (!success) return;
00133
00134 const Vehicle *v = Vehicle::Get(_new_vehicle_id);
00135
00136 ShowVehicleViewWindow(v);
00137 }
00138
00139 static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Vehicle *head)
00140 {
00141 const Vehicle *v = Vehicle::Get(sel);
00142
00143 if (v == wagon) return;
00144
00145 if (wagon == NULL) {
00146 if (head != NULL) wagon = head->Last();
00147 } else {
00148 wagon = wagon->Previous();
00149 if (wagon == NULL) return;
00150 }
00151
00152 if (wagon == v) return;
00153
00154 DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_MOVE_VEHICLE));
00155 }
00156
00159 static Dimension _base_block_sizes[4];
00160
00161 static void InitBlocksizeForShipAircraft(VehicleType type)
00162 {
00163 uint max_width = 0;
00164 uint max_height = 0;
00165
00166 const Engine *e;
00167 FOR_ALL_ENGINES_OF_TYPE(e, type) {
00168 EngineID eid = e->index;
00169 uint x, y;
00170
00171 switch (type) {
00172 default: NOT_REACHED();
00173 case VEH_SHIP: GetShipSpriteSize( eid, x, y); break;
00174 case VEH_AIRCRAFT: GetAircraftSpriteSize(eid, x, y); break;
00175 }
00176 if (x > max_width) max_width = x;
00177 if (y > max_height) max_height = y;
00178 }
00179
00180 switch (type) {
00181 default: NOT_REACHED();
00182 case VEH_SHIP:
00183 _base_block_sizes[VEH_SHIP].width = max(76U, max_width);
00184 break;
00185 case VEH_AIRCRAFT:
00186 _base_block_sizes[VEH_AIRCRAFT].width = max(67U, max_width);
00187 break;
00188 }
00189 _base_block_sizes[type].height = max(GetVehicleHeight(type), max_height);
00190 }
00191
00194 void InitDepotWindowBlockSizes()
00195 {
00196 _base_block_sizes[VEH_TRAIN].width = 0;
00197 _base_block_sizes[VEH_TRAIN].height = GetVehicleHeight(VEH_TRAIN);
00198
00199 _base_block_sizes[VEH_ROAD].width = 32;
00200 _base_block_sizes[VEH_ROAD].height = GetVehicleHeight(VEH_ROAD);
00201
00202 InitBlocksizeForShipAircraft(VEH_SHIP);
00203 InitBlocksizeForShipAircraft(VEH_AIRCRAFT);
00204 }
00205
00206 static void DepotSellAllConfirmationCallback(Window *w, bool confirmed);
00207 const Sprite *GetAircraftSprite(EngineID engine);
00208
00209 struct DepotWindow : Window {
00210 VehicleID sel;
00211 VehicleType type;
00212 bool generate_list;
00213 VehicleList vehicle_list;
00214 VehicleList wagon_list;
00215
00216 DepotWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window()
00217 {
00218 assert(IsCompanyBuildableVehicleType(type));
00219
00220 this->sel = INVALID_VEHICLE;
00221 this->generate_list = true;
00222 this->type = type;
00223
00224 this->CreateNestedTree(desc);
00225 this->SetupWidgetData(type);
00226 this->FinishInitNested(desc, tile);
00227
00228 this->owner = GetTileOwner(tile);
00229 _backup_orders_tile = 0;
00230
00231 }
00232
00233 ~DepotWindow()
00234 {
00235 DeleteWindowById(WC_BUILD_VEHICLE, this->window_number);
00236 }
00237
00244 void DrawVehicleInDepot(const Vehicle *v, int left, int right, int y) const
00245 {
00246 bool free_wagon = false;
00247 int sprite_y = y + (this->resize.step_height - GetVehicleHeight(v->type)) / 2;
00248
00249 bool rtl = _dynlang.text_dir == TD_RTL;
00250 int image_left = rtl ? left + this->count_width : left + this->header_width;
00251 int image_right = rtl ? right - this->header_width : right - this->count_width;
00252
00253 switch (v->type) {
00254 case VEH_TRAIN: {
00255 const Train *u = Train::From(v);
00256 free_wagon = u->IsFreeWagon();
00257
00258 uint x_space = free_wagon ? TRAININFO_DEFAULT_VEHICLE_WIDTH : 0;
00259 DrawTrainImage(u, image_left + (rtl ? 0 : x_space), image_right - (rtl ? x_space : 0), sprite_y - 1, this->sel, free_wagon ? 0 : this->hscroll.GetPosition());
00260
00261
00262 SetDParam(0, (u->tcache.cached_total_length + 7) / 8);
00263 DrawString(rtl ? left + WD_FRAMERECT_LEFT : right - this->count_width, rtl ? left + this->count_width : right - WD_FRAMERECT_RIGHT, y + (this->resize.step_height - FONT_HEIGHT_SMALL) / 2, STR_TINY_BLACK_COMA, TC_FROMSTRING, SA_RIGHT);
00264 break;
00265 }
00266
00267 case VEH_ROAD: DrawRoadVehImage( v, image_left, image_right, sprite_y, this->sel); break;
00268 case VEH_SHIP: DrawShipImage( v, image_left, image_right, sprite_y, this->sel); break;
00269 case VEH_AIRCRAFT: {
00270 const Sprite *spr = GetSprite(v->GetImage(DIR_W), ST_NORMAL);
00271 DrawAircraftImage(v, image_left, image_right,
00272 y + max(spr->height + spr->y_offs - 14, 0),
00273 this->sel);
00274 } break;
00275 default: NOT_REACHED();
00276 }
00277
00278 uint diff_x, diff_y;
00279 if (v->type == VEH_TRAIN || v->type == VEH_ROAD) {
00280
00281 diff_x = this->flag_width + WD_FRAMERECT_LEFT;
00282 diff_y = (this->resize.step_height - this->flag_height) / 2 - 2;
00283 } else {
00284
00285 diff_x = WD_FRAMERECT_LEFT;
00286 diff_y = FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL;
00287 }
00288 int text_left = rtl ? right - this->header_width - 1 : left + diff_x;
00289 int text_right = rtl ? right - diff_x : left + this->header_width - 1;
00290
00291 if (free_wagon) {
00292 DrawString(text_left, text_right, y + 2, STR_DEPOT_NO_ENGINE);
00293 } else {
00294 DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, rtl ? right - this->flag_width : left + WD_FRAMERECT_LEFT, y + diff_y);
00295
00296 SetDParam(0, v->unitnumber);
00297 DrawString(text_left, text_right, y + 2, (uint16)(v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? STR_BLACK_COMMA : STR_RED_COMMA);
00298 }
00299 }
00300
00301 void DrawWidget(const Rect &r, int widget) const
00302 {
00303 if (widget != DEPOT_WIDGET_MATRIX) return;
00304
00305 bool rtl = _dynlang.text_dir == TD_RTL;
00306
00307
00308 uint16 mat_data = this->GetWidget<NWidgetCore>(DEPOT_WIDGET_MATRIX)->widget_data;
00309 uint16 rows_in_display = GB(mat_data, MAT_ROW_START, MAT_ROW_BITS);
00310 uint16 boxes_in_each_row = GB(mat_data, MAT_COL_START, MAT_COL_BITS);
00311
00312 uint16 num = this->vscroll.GetPosition() * boxes_in_each_row;
00313 int maxval = min(this->vehicle_list.Length(), num + (rows_in_display * boxes_in_each_row));
00314 int y;
00315 for (y = r.top + 1; num < maxval; y += this->resize.step_height) {
00316 for (byte i = 0; i < boxes_in_each_row && num < maxval; i++, num++) {
00317
00318 const Vehicle *v = this->vehicle_list[num];
00319 if (boxes_in_each_row == 1) {
00320 this->DrawVehicleInDepot(v, r.left, r.right, y);
00321 } else {
00322 int x = r.left + (rtl ? (boxes_in_each_row - i - 1) : i) * this->resize.step_width;
00323 this->DrawVehicleInDepot(v, x, x + this->resize.step_width - 1, y);
00324 }
00325 }
00326 }
00327
00328 maxval = min(this->vehicle_list.Length() + this->wagon_list.Length(), (this->vscroll.GetPosition() * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
00329
00330
00331 for (; num < maxval; num++, y += this->resize.step_height) {
00332 const Vehicle *v = this->wagon_list[num - this->vehicle_list.Length()];
00333 this->DrawVehicleInDepot(v, r.left, r.right, y);
00334 }
00335 }
00336
00337 void SetStringParameters(int widget) const
00338 {
00339 if (widget != DEPOT_WIDGET_CAPTION) return;
00340
00341
00342 TileIndex tile = this->window_number;
00343 if (this->type == VEH_AIRCRAFT) {
00344 SetDParam(0, GetStationIndex(tile));
00345 } else {
00346 Depot *depot = Depot::GetByTile(tile);
00347 assert(depot != NULL);
00348
00349 SetDParam(0, depot->town_index);
00350 }
00351 }
00352
00353 struct GetDepotVehiclePtData {
00354 const Vehicle *head;
00355 const Vehicle *wagon;
00356 };
00357
00358 enum DepotGUIAction {
00359 MODE_ERROR,
00360 MODE_DRAG_VEHICLE,
00361 MODE_SHOW_VEHICLE,
00362 MODE_START_STOP,
00363 };
00364
00365 DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const
00366 {
00367 const NWidgetCore *matrix_widget = this->GetWidget<NWidgetCore>(DEPOT_WIDGET_MATRIX);
00368
00369 if (_dynlang.text_dir == TD_RTL) x = matrix_widget->current_x - x;
00370
00371 uint xt = 0, xm = 0, ym = 0;
00372 if (this->type == VEH_TRAIN) {
00373 xm = x;
00374 } else {
00375 xt = x / this->resize.step_width;
00376 xm = x % this->resize.step_width;
00377 if (xt >= this->hscroll.GetCapacity()) return MODE_ERROR;
00378 }
00379 ym = y % this->resize.step_height;
00380
00381 uint row = y / this->resize.step_height;
00382 if (row >= this->vscroll.GetCapacity()) return MODE_ERROR;
00383
00384 uint boxes_in_each_row = GB(matrix_widget->widget_data, MAT_COL_START, MAT_COL_BITS);
00385 uint pos = ((row + this->vscroll.GetPosition()) * boxes_in_each_row) + xt;
00386
00387 if (this->vehicle_list.Length() + this->wagon_list.Length() <= pos) {
00388
00389 if (this->type == VEH_TRAIN) {
00390
00391 d->head = NULL;
00392 d->wagon = NULL;
00393 return MODE_DRAG_VEHICLE;
00394 } else {
00395 return MODE_ERROR;
00396 }
00397 }
00398
00399 bool wagon = false;
00400 if (this->vehicle_list.Length() > pos) {
00401 *veh = this->vehicle_list[pos];
00402
00403 x += this->hscroll.GetPosition();
00404 } else {
00405 pos -= this->vehicle_list.Length();
00406 *veh = this->wagon_list[pos];
00407
00408 x -= VEHICLEINFO_FULL_VEHICLE_WIDTH;
00409 wagon = true;
00410 }
00411
00412 const Train *v = NULL;
00413 if (this->type == VEH_TRAIN) {
00414 v = Train::From(*veh);
00415 d->head = d->wagon = v;
00416 }
00417
00418 if (xm <= this->header_width) {
00419 switch (this->type) {
00420 case VEH_TRAIN:
00421 if (wagon) return MODE_ERROR;
00422 case VEH_ROAD:
00423 if (xm <= this->flag_width) return MODE_START_STOP;
00424 break;
00425
00426 case VEH_SHIP:
00427 case VEH_AIRCRAFT:
00428 if (xm <= this->flag_width && ym >= (uint)(FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL)) return MODE_START_STOP;
00429 break;
00430
00431 default: NOT_REACHED();
00432 }
00433 return MODE_SHOW_VEHICLE;
00434 }
00435
00436 if (this->type != VEH_TRAIN) return MODE_DRAG_VEHICLE;
00437
00438
00439 if (xm >= matrix_widget->current_x - this->count_width) return wagon ? MODE_ERROR : MODE_SHOW_VEHICLE;
00440
00441
00442 x -= this->header_width;
00443
00444
00445 for (; v != NULL; v = v->Next()) {
00446 x -= v->GetDisplayImageWidth();
00447 if (x < 0) break;
00448 }
00449
00450 d->wagon = (v != NULL ? v->GetFirstEnginePart() : NULL);
00451
00452 return MODE_DRAG_VEHICLE;
00453 }
00454
00459 void DepotClick(int x, int y)
00460 {
00461 GetDepotVehiclePtData gdvp = { NULL, NULL };
00462 const Vehicle *v = NULL;
00463 DepotGUIAction mode = this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp);
00464
00465
00466 if (_thd.place_mode != HT_NONE && mode != MODE_ERROR) {
00467 _place_clicked_vehicle = (this->type == VEH_TRAIN ? gdvp.head : v);
00468 return;
00469 }
00470
00471 if (this->type == VEH_TRAIN) v = gdvp.wagon;
00472
00473 switch (mode) {
00474 case MODE_ERROR:
00475 return;
00476
00477 case MODE_DRAG_VEHICLE: {
00478 VehicleID sel = this->sel;
00479
00480 if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) {
00481 this->sel = INVALID_VEHICLE;
00482 TrainDepotMoveVehicle(v, sel, gdvp.head);
00483 } else if (v != NULL) {
00484 int image = v->GetImage(DIR_W);
00485
00486 this->sel = v->index;
00487 this->SetDirty();
00488 SetObjectToPlaceWnd(image, GetVehiclePalette(v), HT_DRAG, this);
00489
00490 switch (v->type) {
00491 case VEH_TRAIN:
00492 _cursor.short_vehicle_offset = 16 - Train::From(v)->tcache.cached_veh_length * 2;
00493 break;
00494
00495 case VEH_ROAD:
00496 _cursor.short_vehicle_offset = 16 - RoadVehicle::From(v)->rcache.cached_veh_length * 2;
00497 break;
00498
00499 default:
00500 _cursor.short_vehicle_offset = 0;
00501 break;
00502 }
00503 _cursor.vehchain = _ctrl_pressed;
00504 }
00505 } break;
00506
00507 case MODE_SHOW_VEHICLE:
00508 ShowVehicleViewWindow(v);
00509 break;
00510
00511 case MODE_START_STOP: {
00512 uint command;
00513
00514 switch (this->type) {
00515 case VEH_TRAIN: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_TRAIN); break;
00516 case VEH_ROAD: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_ROAD_VEHICLE); break;
00517 case VEH_SHIP: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_SHIP); break;
00518 case VEH_AIRCRAFT: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_STOP_START_AIRCRAFT); break;
00519 default: NOT_REACHED();
00520 }
00521 DoCommandP(v->tile, v->index, 0, command);
00522 } break;
00523
00524 default: NOT_REACHED();
00525 }
00526 }
00527
00532 void HandleCloneVehClick(const Vehicle *v)
00533 {
00534 if (v == NULL || !IsCompanyBuildableVehicleType(v)) return;
00535
00536 if (!v->IsPrimaryVehicle()) {
00537 v = v->First();
00538
00539 if (v->type == VEH_TRAIN && !Train::From(v)->IsFrontEngine()) return;
00540 }
00541
00542 DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CMD_CLONE_VEHICLE | CMD_MSG(STR_ERROR_CAN_T_BUY_TRAIN + v->type), CcCloneVehicle);
00543
00544 ResetObjectToPlace();
00545 }
00546
00547
00548
00549
00550
00551 void SetupWidgetData(VehicleType type)
00552 {
00553 if (type != VEH_TRAIN) this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL_CHAIN)->fill_y = 0;
00554
00555 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_CAPTION)->widget_data = STR_DEPOT_TRAIN_CAPTION + type;
00556 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_STOP_ALL)->tool_tip = STR_DEPOT_MASS_STOP_DEPOT_TRAIN_TOOLTIP + type;
00557 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_START_ALL)->tool_tip = STR_DEPOT_MASS_START_DEPOT_TRAIN_TOOLTIP + type;
00558 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL)->tool_tip = STR_DEPOT_TRAIN_SELL_TOOLTIP + type;
00559 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL_ALL)->tool_tip = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TOOLTIP + type;
00560
00561 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_BUILD)->SetDataTip(STR_DEPOT_TRAIN_NEW_VEHICLES_BUTTON + type, STR_DEPOT_TRAIN_NEW_VEHICLES_TOOLTIP + type);
00562 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_CLONE)->SetDataTip(STR_DEPOT_CLONE_TRAIN + type, STR_DEPOT_CLONE_TRAIN_DEPOT_INFO + type);
00563
00564 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_LOCATION)->tool_tip = STR_DEPOT_TRAIN_LOCATION_TOOLTIP + type;
00565 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_VEHICLE_LIST)->tool_tip = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TOOLTIP + type;
00566 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_AUTOREPLACE)->tool_tip = STR_DEPOT_AUTOREPLACE_TRAIN_TOOLTIP + type;
00567
00568 switch (type) {
00569 default: NOT_REACHED();
00570
00571 case VEH_TRAIN:
00572 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_VEHICLE_LIST)->widget_data = STR_TRAIN;
00573
00574
00575 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL)->widget_data = SPR_SELL_TRAIN;
00576 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL_ALL)->widget_data = SPR_SELL_ALL_TRAIN;
00577 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_AUTOREPLACE)->widget_data = SPR_REPLACE_TRAIN;
00578 break;
00579
00580 case VEH_ROAD:
00581 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_VEHICLE_LIST)->widget_data = STR_LORRY;
00582
00583
00584 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL)->widget_data = SPR_SELL_ROADVEH;
00585 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL_ALL)->widget_data = SPR_SELL_ALL_ROADVEH;
00586 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_AUTOREPLACE)->widget_data = SPR_REPLACE_ROADVEH;
00587 break;
00588
00589 case VEH_SHIP:
00590 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_VEHICLE_LIST)->widget_data = STR_SHIP;
00591
00592
00593 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL)->widget_data = SPR_SELL_SHIP;
00594 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL_ALL)->widget_data = SPR_SELL_ALL_SHIP;
00595 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_AUTOREPLACE)->widget_data = SPR_REPLACE_SHIP;
00596 break;
00597
00598 case VEH_AIRCRAFT:
00599 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_VEHICLE_LIST)->widget_data = STR_PLANE;
00600
00601
00602 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL)->widget_data = SPR_SELL_AIRCRAFT;
00603 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_SELL_ALL)->widget_data = SPR_SELL_ALL_AIRCRAFT;
00604 this->GetWidget<NWidgetCore>(DEPOT_WIDGET_AUTOREPLACE)->widget_data = SPR_REPLACE_AIRCRAFT;
00605 break;
00606 }
00607 }
00608
00609 uint count_width;
00610 uint header_width;
00611 uint flag_width;
00612 uint flag_height;
00613
00614 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00615 {
00616 switch (widget) {
00617 case DEPOT_WIDGET_SELL_CHAIN:
00618 case DEPOT_WIDGET_H_SCROLL:
00619
00620 if (this->type != VEH_TRAIN) {
00621 size->height = 0;
00622 resize->height = 0;
00623 }
00624 break;
00625
00626 case DEPOT_WIDGET_MATRIX: {
00627 uint min_height = 0;
00628
00629 if (this->type == VEH_TRAIN) {
00630 SetDParam(0, 100);
00631 this->count_width = GetStringBoundingBox(STR_TINY_BLACK_COMA).width + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00632 } else {
00633 this->count_width = 0;
00634 }
00635
00636 Dimension unumber = { GetDigitWidth() * 4, FONT_HEIGHT_NORMAL };
00637 const Sprite *spr = GetSprite(SPR_FLAG_VEH_STOPPED, ST_NORMAL);
00638 this->flag_width = spr->width + WD_FRAMERECT_RIGHT;
00639 this->flag_height = spr->height;
00640
00641 if (this->type == VEH_TRAIN || this->type == VEH_ROAD) {
00642 min_height = max<uint>(unumber.height + WD_MATRIX_TOP, spr->height);
00643 this->header_width = unumber.width + this->flag_width + WD_FRAMERECT_LEFT;
00644 } else {
00645 min_height = unumber.height + spr->height + WD_MATRIX_TOP + WD_PAR_VSEP_NORMAL + WD_MATRIX_BOTTOM;
00646 this->header_width = max<uint>(unumber.width, this->flag_width) + WD_FRAMERECT_RIGHT;
00647 }
00648 int base_width = this->count_width + this->header_width;
00649
00650 resize->height = max(_base_block_sizes[this->type].height, min_height);
00651 if (this->type == VEH_TRAIN) {
00652 resize->width = 1;
00653 size->width = base_width + 2 * 29;
00654 size->height = resize->height * 6;
00655 } else {
00656 resize->width = base_width + _base_block_sizes[this->type].width;
00657 size->width = resize->width * (this->type == VEH_ROAD ? 5 : 3);
00658 size->height = resize->height * (this->type == VEH_ROAD ? 5 : 3);
00659 }
00660 fill->width = resize->width;
00661 fill->height = resize->height;
00662 } break;
00663 }
00664 }
00665
00666 virtual void OnInvalidateData(int data)
00667 {
00668 this->generate_list = true;
00669 }
00670
00671 virtual void OnPaint()
00672 {
00673 if (this->generate_list) {
00674
00675
00676 BuildDepotVehicleList(this->type, this->window_number, &this->vehicle_list, &this->wagon_list);
00677 this->generate_list = false;
00678 DepotSortList(&this->vehicle_list);
00679 }
00680
00681
00682 if (this->type == VEH_TRAIN) {
00683 uint max_width = VEHICLEINFO_FULL_VEHICLE_WIDTH;
00684 for (uint num = 0; num < this->vehicle_list.Length(); num++) {
00685 uint width = 0;
00686 for (const Train *v = Train::From(this->vehicle_list[num]); v != NULL; v = v->Next()) {
00687 width += v->GetDisplayImageWidth();
00688 }
00689 max_width = max(max_width, width);
00690 }
00691
00692 this->vscroll.SetCount(this->vehicle_list.Length() + this->wagon_list.Length() + 1);
00693 this->hscroll.SetCount(max_width);
00694 } else {
00695 this->vscroll.SetCount((this->vehicle_list.Length() + this->hscroll.GetCapacity() - 1) / this->hscroll.GetCapacity());
00696 }
00697
00698
00699 TileIndex tile = this->window_number;
00700 this->SetWidgetsDisabledState(!(Company::IsValidID(_local_company) && IsInfraTileUsageAllowed(tile, _local_company, this->type)),
00701 DEPOT_WIDGET_STOP_ALL,
00702 DEPOT_WIDGET_START_ALL,
00703 DEPOT_WIDGET_SELL,
00704 DEPOT_WIDGET_SELL_CHAIN,
00705 DEPOT_WIDGET_SELL_ALL,
00706 DEPOT_WIDGET_BUILD,
00707 DEPOT_WIDGET_CLONE,
00708 DEPOT_WIDGET_AUTOREPLACE,
00709 WIDGET_LIST_END);
00710
00711 this->DrawWidgets();
00712 }
00713
00714 virtual void OnClick(Point pt, int widget)
00715 {
00716 switch (widget) {
00717 case DEPOT_WIDGET_MATRIX: {
00718 NWidgetBase *nwi = this->GetWidget<NWidgetBase>(DEPOT_WIDGET_MATRIX);
00719 this->DepotClick(pt.x - nwi->pos_x, pt.y - nwi->pos_y);
00720 break;
00721 }
00722
00723 case DEPOT_WIDGET_BUILD:
00724 ResetObjectToPlace();
00725 ShowBuildVehicleWindow(this->window_number, this->type);
00726 break;
00727
00728 case DEPOT_WIDGET_CLONE:
00729 this->SetWidgetDirty(DEPOT_WIDGET_CLONE);
00730 this->ToggleWidgetLoweredState(DEPOT_WIDGET_CLONE);
00731
00732 if (this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
00733 static const CursorID clone_icons[] = {
00734 SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
00735 SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
00736 };
00737
00738 _place_clicked_vehicle = NULL;
00739 SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, HT_RECT, this);
00740 } else {
00741 ResetObjectToPlace();
00742 }
00743 break;
00744
00745 case DEPOT_WIDGET_LOCATION:
00746 if (_ctrl_pressed) {
00747 ShowExtraViewPortWindow(this->window_number);
00748 } else {
00749 ScrollMainWindowToTile(this->window_number);
00750 }
00751 break;
00752
00753 case DEPOT_WIDGET_STOP_ALL:
00754 case DEPOT_WIDGET_START_ALL:
00755 DoCommandP(this->window_number, 0, this->type | (widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), CMD_MASS_START_STOP);
00756 break;
00757
00758 case DEPOT_WIDGET_SELL_ALL:
00759
00760 if (this->vehicle_list.Length() != 0 || this->wagon_list.Length() != 0) {
00761 TileIndex tile = this->window_number;
00762 byte vehtype = this->type;
00763
00764 SetDParam(0, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : Depot::GetByTile(tile)->town_index);
00765 ShowQuery(
00766 STR_DEPOT_TRAIN_CAPTION + vehtype,
00767 STR_DEPOT_SELL_CONFIRMATION_TEXT,
00768 this,
00769 DepotSellAllConfirmationCallback
00770 );
00771 }
00772 break;
00773
00774 case DEPOT_WIDGET_VEHICLE_LIST:
00775 ShowVehicleListWindow(GetTileOwner(this->window_number), this->type, (TileIndex)this->window_number);
00776 break;
00777
00778 case DEPOT_WIDGET_AUTOREPLACE:
00779 DoCommandP(this->window_number, this->type, 0, CMD_DEPOT_MASS_AUTOREPLACE);
00780 break;
00781
00782 }
00783 }
00784
00785 virtual void OnRightClick(Point pt, int widget)
00786 {
00787 if (widget != DEPOT_WIDGET_MATRIX) return;
00788
00789 GetDepotVehiclePtData gdvp = { NULL, NULL };
00790 const Vehicle *v = NULL;
00791 NWidgetBase *nwi = this->GetWidget<NWidgetBase>(DEPOT_WIDGET_MATRIX);
00792 DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp);
00793
00794 if (this->type == VEH_TRAIN) v = gdvp.wagon;
00795
00796 if (v != NULL && mode == MODE_DRAG_VEHICLE) {
00797 CargoArray capacity, loaded;
00798
00799
00800 bool whole_chain = (this->type == VEH_TRAIN && _ctrl_pressed);
00801
00802
00803 uint num = 0;
00804 for (const Vehicle *w = v; w != NULL; w = w->Next()) {
00805 if (w->cargo_cap > 0 && w->cargo_type < NUM_CARGO) {
00806 capacity[w->cargo_type] += w->cargo_cap;
00807 loaded [w->cargo_type] += w->cargo.Count();
00808 }
00809
00810 if (w->type == VEH_TRAIN && !Train::From(w)->HasArticulatedPart()) {
00811 num++;
00812 if (!whole_chain) break;
00813 }
00814 }
00815
00816
00817 static char details[1024];
00818 details[0] = '\0';
00819 char *pos = details;
00820
00821 for (CargoID cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
00822 if (capacity[cargo_type] == 0) continue;
00823
00824 SetDParam(0, cargo_type);
00825 SetDParam(1, loaded[cargo_type]);
00826 SetDParam(2, cargo_type);
00827 SetDParam(3, capacity[cargo_type]);
00828 pos = GetString(pos, STR_DEPOT_VEHICLE_TOOLTIP_CARGO, lastof(details));
00829 }
00830
00831
00832 uint64 args[2];
00833 args[0] = (whole_chain ? num : v->engine_type);
00834 args[1] = (uint64)(size_t)details;
00835 GuiShowTooltips(whole_chain ? STR_DEPOT_VEHICLE_TOOLTIP_CHAIN : STR_DEPOT_VEHICLE_TOOLTIP, 2, args);
00836 } else {
00837
00838 GuiShowTooltips(STR_DEPOT_TRAIN_LIST_TOOLTIP + this->type);
00839 }
00840 }
00841
00842
00843 virtual void OnPlaceObject(Point pt, TileIndex tile)
00844 {
00845 const Vehicle *v = CheckMouseOverVehicle();
00846
00847 if (v != NULL) this->HandleCloneVehClick(v);
00848 }
00849
00850 virtual void OnPlaceObjectAbort()
00851 {
00852
00853 this->RaiseWidget(DEPOT_WIDGET_CLONE);
00854 this->SetWidgetDirty(DEPOT_WIDGET_CLONE);
00855
00856
00857 this->sel = INVALID_VEHICLE;
00858 this->SetWidgetDirty(DEPOT_WIDGET_MATRIX);
00859 };
00860
00861
00862 virtual void OnMouseLoop()
00863 {
00864 const Vehicle *v = _place_clicked_vehicle;
00865
00866
00867 if (v != NULL && this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
00868 _place_clicked_vehicle = NULL;
00869 this->HandleCloneVehClick(v);
00870 }
00871 }
00872
00873 virtual void OnDragDrop(Point pt, int widget)
00874 {
00875 switch (widget) {
00876 case DEPOT_WIDGET_MATRIX: {
00877 const Vehicle *v = NULL;
00878 VehicleID sel = this->sel;
00879
00880 this->sel = INVALID_VEHICLE;
00881 this->SetDirty();
00882
00883 NWidgetBase *nwi = this->GetWidget<NWidgetBase>(DEPOT_WIDGET_MATRIX);
00884 if (this->type == VEH_TRAIN) {
00885 GetDepotVehiclePtData gdvp = { NULL, NULL };
00886
00887 if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, &gdvp) == MODE_DRAG_VEHICLE && sel != INVALID_VEHICLE) {
00888 if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
00889 DoCommandP(Vehicle::Get(sel)->tile, Vehicle::Get(sel)->index, true,
00890 CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE));
00891 } else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
00892 TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
00893 } else if (gdvp.head != NULL && Train::From(gdvp.head)->IsFrontEngine()) {
00894 ShowVehicleViewWindow(gdvp.head);
00895 }
00896 }
00897 } else if (this->GetVehicleFromDepotWndPt(pt.x - nwi->pos_x, pt.y - nwi->pos_y, &v, NULL) == MODE_DRAG_VEHICLE && v != NULL && sel == v->index) {
00898 ShowVehicleViewWindow(v);
00899 }
00900 } break;
00901
00902 case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN: {
00903 if (this->IsWidgetDisabled(widget)) return;
00904 if (this->sel == INVALID_VEHICLE) return;
00905
00906 this->HandleButtonClick(widget);
00907
00908 const Vehicle *v = Vehicle::Get(this->sel);
00909 this->sel = INVALID_VEHICLE;
00910 this->SetDirty();
00911
00912 int sell_cmd = (v->type == VEH_TRAIN && (widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
00913
00914 bool is_engine = (v->type != VEH_TRAIN || Train::From(v)->IsFrontEngine());
00915
00916 if (is_engine) {
00917 _backup_orders_tile = v->tile;
00918 BackupVehicleOrders(v);
00919 }
00920
00921 if (!DoCommandP(v->tile, v->index, sell_cmd, GetCmdSellVeh(v->type)) && is_engine) _backup_orders_tile = 0;
00922 } break;
00923
00924 default:
00925 this->sel = INVALID_VEHICLE;
00926 this->SetDirty();
00927 }
00928 _cursor.vehchain = false;
00929 }
00930
00931 virtual void OnTimeout()
00932 {
00933 if (!this->IsWidgetDisabled(DEPOT_WIDGET_SELL)) {
00934 this->RaiseWidget(DEPOT_WIDGET_SELL);
00935 this->SetWidgetDirty(DEPOT_WIDGET_SELL);
00936 }
00937 if (this->nested_array[DEPOT_WIDGET_SELL] != NULL && !this->IsWidgetDisabled(DEPOT_WIDGET_SELL_CHAIN)) {
00938 this->RaiseWidget(DEPOT_WIDGET_SELL_CHAIN);
00939 this->SetWidgetDirty(DEPOT_WIDGET_SELL_CHAIN);
00940 }
00941 }
00942
00943 virtual void OnResize()
00944 {
00945 NWidgetCore *nwi = this->GetWidget<NWidgetCore>(DEPOT_WIDGET_MATRIX);
00946 this->vscroll.SetCapacityFromWidget(this, DEPOT_WIDGET_MATRIX);
00947 if (this->type == VEH_TRAIN) {
00948 this->hscroll.SetCapacity(nwi->current_x - this->header_width - this->count_width);
00949 nwi->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00950 } else {
00951 this->hscroll.SetCapacityFromWidget(this, DEPOT_WIDGET_MATRIX);
00952 nwi->widget_data = (this->vscroll.GetCapacity() << MAT_ROW_START) + (this->hscroll.GetCapacity() << MAT_COL_START);
00953 }
00954 }
00955
00956 virtual EventState OnCTRLStateChange()
00957 {
00958 if (this->sel != INVALID_VEHICLE) {
00959 _cursor.vehchain = _ctrl_pressed;
00960 this->SetWidgetDirty(DEPOT_WIDGET_MATRIX);
00961 return ES_HANDLED;
00962 }
00963
00964 return ES_NOT_HANDLED;
00965 }
00966 };
00967
00968 static void DepotSellAllConfirmationCallback(Window *win, bool confirmed)
00969 {
00970 if (confirmed) {
00971 DepotWindow *w = (DepotWindow*)win;
00972 TileIndex tile = w->window_number;
00973 byte vehtype = w->type;
00974 DoCommandP(tile, vehtype, 0, CMD_DEPOT_SELL_ALL_VEHICLES);
00975 }
00976 }
00977
00982 void ShowDepotWindow(TileIndex tile, VehicleType type)
00983 {
00984 if (BringWindowToFrontById(WC_VEHICLE_DEPOT, tile) != NULL) return;
00985
00986 const WindowDesc *desc;
00987 switch (type) {
00988 default: NOT_REACHED();
00989 case VEH_TRAIN: desc = &_train_depot_desc; break;
00990 case VEH_ROAD: desc = &_road_depot_desc; break;
00991 case VEH_SHIP: desc = &_ship_depot_desc; break;
00992 case VEH_AIRCRAFT: desc = &_aircraft_depot_desc; break;
00993 }
00994
00995 new DepotWindow(desc, tile, type);
00996 }
00997
01001 void DeleteDepotHighlightOfVehicle(const Vehicle *v)
01002 {
01003 DepotWindow *w;
01004
01005
01006
01007
01008 if (_special_mouse_mode != WSM_DRAGDROP) return;
01009
01010 w = dynamic_cast<DepotWindow*>(FindWindowById(WC_VEHICLE_DEPOT, v->tile));
01011 if (w != NULL) {
01012 if (w->sel == v->index) ResetObjectToPlace();
01013 }
01014 }