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