# depot_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: depot_gui.cpp 15723 2009-03-15 15:12:06Z rubidium $ */
    00002
    00005 #include "train.h"
    00006 #include "ship.h"
    00007 #include "aircraft.h"
    00008 #include "gui.h"
    00009 #include "textbuf_gui.h"
    00010 #include "viewport_func.h"
    00011 #include "gfx_func.h"
    00012 #include "command_func.h"
    00013 #include "depot_base.h"
    00014 #include "vehicle_gui.h"
    00015 #include "newgrf_engine.h"
    00016 #include "spritecache.h"
    00017 #include "strings_func.h"
    00018 #include "window_func.h"
    00019 #include "vehicle_func.h"
    00020 #include "company_func.h"
    00021 #include "tilehighlight_func.h"
    00022 #include "window_gui.h"
    00023 #include "vehiclelist.h"
    00024
    00025 #include "table/strings.h"
    00026 #include "table/sprites.h"
    00027
    00028 /*
    00029  * Since all depot window sizes aren't the same, we need to modify sizes a little.
    00030  * It's done with the following arrays of widget indexes. Each of them tells if a widget side should be moved and in what direction.
    00031  * How long they should be moved and for what window types are controlled in ShowDepotWindow()
    00032  */
    00033
    00034 /* Names of the widgets. Keep them in the same order as in the widget array */
    00035 enum DepotWindowWidgets {
    00036   DEPOT_WIDGET_CLOSEBOX = 0,
    00037   DEPOT_WIDGET_CAPTION,
    00038   DEPOT_WIDGET_STICKY,
    00039   DEPOT_WIDGET_SELL,
    00040   DEPOT_WIDGET_SELL_CHAIN,
    00041   DEPOT_WIDGET_SELL_ALL,
    00042   DEPOT_WIDGET_AUTOREPLACE,
    00043   DEPOT_WIDGET_MATRIX,
    00044   DEPOT_WIDGET_V_SCROLL,
    00045   DEPOT_WIDGET_H_SCROLL,
    00046   DEPOT_WIDGET_BUILD,
    00047   DEPOT_WIDGET_CLONE,
    00048   DEPOT_WIDGET_LOCATION,
    00049   DEPOT_WIDGET_VEHICLE_LIST,
    00050   DEPOT_WIDGET_STOP_ALL,
    00051   DEPOT_WIDGET_START_ALL,
    00052   DEPOT_WIDGET_RESIZE,
    00053 };
    00054
    00055 /* Widget array for all depot windows.
    00056  * If a widget is needed in some windows only (like train specific), add it for all windows
    00057  * and use HideWindowWidget in ShowDepotWindow() to remove it in the windows where it should not be
    00058  * Keep the widget numbers in sync with the enum or really bad stuff will happen!!! */
    00059
    00060 /* When adding widgets, place them as you would place them for the ship depot and define how you want it to move in widget_moves[]
    00061  * If you want a widget for one window only, set it to be hidden in ShowDepotWindow() for the windows where you don't want it
    00062  * NOTE: the train only widgets are moved/resized in ShowDepotWindow() so they follow certain other widgets if they are moved to ensure that they stick together.
    00063  *    Changing the size of those here will not have an effect at all. It should be done in ShowDepotWindow()
    00064  */
    00065
    00066 /*
    00067  * Some of the widgets are placed outside the window (negative coordinates).
    00068  * The reason is that they are placed relatively to the matrix and the matrix is just one pixel (in 0, 14).
    00069  * The matrix and the rest of the window will be resized when the size of the boxes is set and then all the widgets will be inside the window.
    00070  */
    00071 static const Widget _depot_widgets[] = {
    00072   {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},            // DEPOT_WIDGET_CLOSEBOX
    00073   {    WWT_CAPTION,  RESIZE_RIGHT,  COLOUR_GREY,    11,    23,     0,    13, 0x0,                 STR_018C_WINDOW_TITLE_DRAG_THIS},  // DEPOT_WIDGET_CAPTION
    00074   {  WWT_STICKYBOX,     RESIZE_LR,  COLOUR_GREY,    24,    35,     0,    13, 0x0,                 STR_STICKY_BUTTON},                // DEPOT_WIDGET_STICKY
    00075
    00076   /* Widgets are set up run-time */
    00077   {     WWT_IMGBTN,    RESIZE_LRB,  COLOUR_GREY,     1,    23,    14,   -32, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_SELL
    00078   {     WWT_IMGBTN,   RESIZE_LRTB,  COLOUR_GREY,     1,    23,   -55,   -32, SPR_SELL_CHAIN_TRAIN,STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP}, // DEPOT_WIDGET_SELL_CHAIN, trains only
    00079   { WWT_PUSHIMGBTN,   RESIZE_LRTB,  COLOUR_GREY,     1,    23,   -31,    -9, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_SELL_ALL
    00080   { WWT_PUSHIMGBTN,   RESIZE_LRTB,  COLOUR_GREY,     1,    23,    -8,    14, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_AUTOREPLACE
    00081
    00082   {     WWT_MATRIX,     RESIZE_RB,  COLOUR_GREY,     0,     0,    14,    14, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_MATRIX
    00083   {  WWT_SCROLLBAR,    RESIZE_LRB,  COLOUR_GREY,    24,    35,    14,    14, 0x0,                 STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DEPOT_WIDGET_V_SCROLL
    00084
    00085   { WWT_HSCROLLBAR,    RESIZE_RTB,  COLOUR_GREY,     0,     0,     3,    14, 0x0,                 STR_HSCROLL_BAR_SCROLLS_LIST},     // DEPOT_WIDGET_H_SCROLL, trains only
    00086
    00087   /* The buttons in the bottom of the window. left and right is not important as they are later resized to be equal in size
    00088    * This calculation is based on right in DEPOT_WIDGET_LOCATION and it presumes left of DEPOT_WIDGET_BUILD is 0            */
    00089   { WWT_PUSHTXTBTN,     RESIZE_TB,  COLOUR_GREY,     0,     0,    15,    26, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_BUILD
    00090   {    WWT_TEXTBTN,     RESIZE_TB,  COLOUR_GREY,     0,     0,    15,    26, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_CLONE
    00091   { WWT_PUSHTXTBTN,    RESIZE_RTB,  COLOUR_GREY,     0,   -12,    15,    26, STR_00E4_LOCATION,   STR_NULL},                         // DEPOT_WIDGET_LOCATION
    00092   { WWT_PUSHTXTBTN,   RESIZE_LRTB,  COLOUR_GREY,   -11,     0,    15,    26, 0x0,                 STR_NULL},                         // DEPOT_WIDGET_VEHICLE_LIST
    00093   { WWT_PUSHIMGBTN,   RESIZE_LRTB,  COLOUR_GREY,     1,    11,    15,    26, SPR_FLAG_VEH_STOPPED,STR_NULL},                         // DEPOT_WIDGET_STOP_ALL
    00094   { WWT_PUSHIMGBTN,   RESIZE_LRTB,  COLOUR_GREY,    12,    23,    15,    26, SPR_FLAG_VEH_RUNNING,STR_NULL},                         // DEPOT_WIDGET_START_ALL
    00095   {  WWT_RESIZEBOX,   RESIZE_LRTB,  COLOUR_GREY,    24,    35,    15,    26, 0x0,                 STR_RESIZE_BUTTON},                // DEPOT_WIDGET_RESIZE
    00096   {   WIDGETS_END},
    00097 };
    00098
    00099
    00100 static const WindowDesc _train_depot_desc(
    00101   WDP_AUTO, WDP_AUTO, 36, 27, 362, 123,
    00102   WC_VEHICLE_DEPOT, WC_NONE,
    00103   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
    00104   _depot_widgets
    00105 );
    00106
    00107 static const WindowDesc _road_depot_desc(
    00108   WDP_AUTO, WDP_AUTO, 36, 27, 316, 97,
    00109   WC_VEHICLE_DEPOT, WC_NONE,
    00110   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
    00111   _depot_widgets
    00112 );
    00113
    00114 static const WindowDesc _ship_depot_desc(
    00115   WDP_AUTO, WDP_AUTO, 36, 27, 306, 99,
    00116   WC_VEHICLE_DEPOT, WC_NONE,
    00117   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
    00118   _depot_widgets
    00119 );
    00120
    00121 static const WindowDesc _aircraft_depot_desc(
    00122   WDP_AUTO, WDP_AUTO, 36, 27, 332, 99,
    00123   WC_VEHICLE_DEPOT, WC_NONE,
    00124   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
    00125   _depot_widgets
    00126 );
    00127
    00128 extern int WagonLengthToPixels(int len);
    00129 extern void DepotSortList(VehicleList *list);
    00130
    00138 void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00139 {
    00140   if (!success) return;
    00141
    00142   const Vehicle *v = GetVehicle(_new_vehicle_id);
    00143
    00144   ShowVehicleViewWindow(v);
    00145 }
    00146
    00147 static void TrainDepotMoveVehicle(const Vehicle *wagon, VehicleID sel, const Vehicle *head)
    00148 {
    00149   const Vehicle *v = GetVehicle(sel);
    00150
    00151   if (v == wagon) return;
    00152
    00153   if (wagon == NULL) {
    00154     if (head != NULL) wagon = GetLastVehicleInChain(head);
    00155   } else  {
    00156     wagon = wagon->Previous();
    00157     if (wagon == NULL) return;
    00158   }
    00159
    00160   if (wagon == v) return;
    00161
    00162   DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_8837_CAN_T_MOVE_VEHICLE));
    00163 }
    00164
    00165 /* Array to hold the block sizes
    00166  * First part is the vehicle type, while the last is 0 = x, 1 = y */
    00167 uint _block_sizes[4][2];
    00168
    00169 /* Array to hold the default resize capacities
    00170  * First part is the vehicle type, while the last is 0 = x, 1 = y */
    00171 const uint _resize_cap[][2] = {
    00172 /* VEH_TRAIN */    {6, 10 * 29},
    00173 /* VEH_ROAD */     {5, 5},
    00174 /* VEH_SHIP */     {3, 3},
    00175 /* VEH_AIRCRAFT */ {3, 4},
    00176 };
    00177
    00178 static void ResizeDefaultWindowSizeForTrains()
    00179 {
    00180   _block_sizes[VEH_TRAIN][0] = 1;
    00181   _block_sizes[VEH_TRAIN][1] = GetVehicleListHeight(VEH_TRAIN);
    00182 }
    00183
    00184 static void ResizeDefaultWindowSizeForRoadVehicles()
    00185 {
    00186   _block_sizes[VEH_ROAD][0] = 56;
    00187   _block_sizes[VEH_ROAD][1] = GetVehicleListHeight(VEH_ROAD);
    00188 }
    00189
    00190 static void ResizeDefaultWindowSize(VehicleType type)
    00191 {
    00192   uint max_width  = 0;
    00193   uint max_height = 0;
    00194
    00195   const Engine *e;
    00196   FOR_ALL_ENGINES_OF_TYPE(e, type) {
    00197     EngineID eid = e->index;
    00198     uint x, y;
    00199
    00200     switch (type) {
    00201       default: NOT_REACHED();
    00202       case VEH_SHIP:     GetShipSpriteSize(    eid, x, y); break;
    00203       case VEH_AIRCRAFT: GetAircraftSpriteSize(eid, x, y); break;
    00204     }
    00205     if (x > max_width)  max_width  = x;
    00206     if (y > max_height) max_height = y;
    00207   }
    00208
    00209   switch (type) {
    00210     default: NOT_REACHED();
    00211     case VEH_SHIP:
    00212       _block_sizes[VEH_SHIP][0] = max(90U, max_width + 20); // we need 20 pixels from the right edge to the sprite
    00213       break;
    00214     case VEH_AIRCRAFT:
    00215       _block_sizes[VEH_AIRCRAFT][0] = max(74U, max_width);
    00216       break;
    00217   }
    00218   _block_sizes[type][1] = max(GetVehicleListHeight(type), max_height);
    00219 }
    00220
    00221 /* Set the size of the blocks in the window so we can be sure that they are big enough for the vehicle sprites in the current game
    00222  * We will only need to call this once for each game */
    00223 void InitDepotWindowBlockSizes()
    00224 {
    00225   ResizeDefaultWindowSizeForTrains();
    00226   ResizeDefaultWindowSizeForRoadVehicles();
    00227   ResizeDefaultWindowSize(VEH_SHIP);
    00228   ResizeDefaultWindowSize(VEH_AIRCRAFT);
    00229 }
    00230
    00231 static void DepotSellAllConfirmationCallback(Window *w, bool confirmed);
    00232 const Sprite *GetAircraftSprite(EngineID engine);
    00233
    00234 struct DepotWindow : Window {
    00235   VehicleID sel;
    00236   VehicleType type;
    00237   bool generate_list;
    00238   VehicleList vehicle_list;
    00239   VehicleList wagon_list;
    00240
    00241   DepotWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc, tile)
    00242   {
    00243     this->sel = INVALID_VEHICLE;
    00244     this->generate_list = true;
    00245
    00246     this->owner = GetTileOwner(tile);
    00247     this->CreateDepotListWindow(type);
    00248
    00249     this->FindWindowPlacementAndResize(desc);
    00250   }
    00251
    00252   ~DepotWindow()
    00253   {
    00254     DeleteWindowById(WC_BUILD_VEHICLE, this->window_number);
    00255   }
    00256
    00263   void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
    00264   {
    00265     byte diff_x = 0, diff_y = 0;
    00266
    00267     int sprite_y = y + this->resize.step_height - GetVehicleListHeight(v->type);
    00268
    00269     switch (v->type) {
    00270       case VEH_TRAIN:
    00271         DrawTrainImage(v, x + 21, sprite_y, this->sel, this->hscroll.cap + 4, this->hscroll.pos);
    00272
    00273         /* Number of wagons relative to a standard length wagon (rounded up) */
    00274         SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
    00275         DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
    00276         break;
    00277
    00278       case VEH_ROAD:     DrawRoadVehImage( v, x + 24, sprite_y, this->sel, 1); break;
    00279       case VEH_SHIP:     DrawShipImage(    v, x + 19, sprite_y - 1, this->sel); break;
    00280       case VEH_AIRCRAFT: {
    00281         const Sprite *spr = GetSprite(v->GetImage(DIR_W), ST_NORMAL);
    00282         DrawAircraftImage(v, x + 12,
    00283                   y + max(spr->height + spr->y_offs - 14, 0), // tall sprites needs an y offset
    00284                   this->sel);
    00285       } break;
    00286       default: NOT_REACHED();
    00287     }
    00288
    00289     if (this->resize.step_height == 14) {
    00290       /* VEH_TRAIN and VEH_ROAD, which are low */
    00291       diff_x = 15;
    00292     } else {
    00293       /* VEH_SHIP and VEH_AIRCRAFT, which are tall */
    00294       diff_y = 12;
    00295     }
    00296
    00297     DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, x + diff_x, y + diff_y);
    00298
    00299     SetDParam(0, v->unitnumber);
    00300     DrawString(x, y + 2, (uint16)(v->max_age - DAYS_IN_LEAP_YEAR) >= v->age ? STR_00E2 : STR_00E3, TC_FROMSTRING);
    00301   }
    00302
    00303   void DrawDepotWindow(Window *w)
    00304   {
    00305     TileIndex tile = this->window_number;
    00306     int x, y, i, maxval;
    00307     uint16 hnum;
    00308
    00309     /* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
    00310     uint16 rows_in_display   = this->widget[DEPOT_WIDGET_MATRIX].data >> 8;
    00311     uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
    00312
    00313     /* setup disabled buttons */
    00314     this->SetWidgetsDisabledState(!IsTileOwner(tile, _local_company),
    00315       DEPOT_WIDGET_STOP_ALL,
    00316       DEPOT_WIDGET_START_ALL,
    00317       DEPOT_WIDGET_SELL,
    00318       DEPOT_WIDGET_SELL_CHAIN,
    00319       DEPOT_WIDGET_SELL_ALL,
    00320       DEPOT_WIDGET_BUILD,
    00321       DEPOT_WIDGET_CLONE,
    00322       DEPOT_WIDGET_AUTOREPLACE,
    00323       WIDGET_LIST_END);
    00324
    00325     /* determine amount of items for scroller */
    00326     if (this->type == VEH_TRAIN) {
    00327       hnum = 8;
    00328       for (uint num = 0; num < this->vehicle_list.Length(); num++) {
    00329         const Vehicle *v = this->vehicle_list[num];
    00330         hnum = max(hnum, v->u.rail.cached_total_length);
    00331       }
    00332       /* Always have 1 empty row, so people can change the setting of the train */
    00333       SetVScrollCount(w, this->vehicle_list.Length() + this->wagon_list.Length() + 1);
    00334       SetHScrollCount(w, WagonLengthToPixels(hnum));
    00335     } else {
    00336       SetVScrollCount(w, (this->vehicle_list.Length() + this->hscroll.cap - 1) / this->hscroll.cap);
    00337     }
    00338
    00339     /* locate the depot struct */
    00340     if (this->type == VEH_AIRCRAFT) {
    00341       SetDParam(0, GetStationIndex(tile)); // Airport name
    00342     } else {
    00343       Depot *depot = GetDepotByTile(tile);
    00344       assert(depot != NULL);
    00345
    00346       SetDParam(0, depot->town_index);
    00347     }
    00348
    00349     w->DrawWidgets();
    00350
    00351     uint16 num = this->vscroll.pos * boxes_in_each_row;
    00352     maxval = min(this->vehicle_list.Length(), num + (rows_in_display * boxes_in_each_row));
    00353
    00354     for (x = 2, y = 15; num < maxval; y += this->resize.step_height, x = 2) { // Draw the rows
    00355       byte i;
    00356
    00357       for (i = 0; i < boxes_in_each_row && num < maxval; i++, num++, x += this->resize.step_width) {
    00358         /* Draw all vehicles in the current row */
    00359         const Vehicle *v = this->vehicle_list[num];
    00360         DrawVehicleInDepot(w, v, x, y);
    00361       }
    00362     }
    00363
    00364     maxval = min(this->vehicle_list.Length() + this->wagon_list.Length(), (this->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
    00365
    00366     /* draw the train wagons, that do not have an engine in front */
    00367     for (; num < maxval; num++, y += 14) {
    00368       const Vehicle *v = this->wagon_list[num - this->vehicle_list.Length()];
    00369       const Vehicle *u;
    00370
    00371       DrawTrainImage(v, x + 50, y, this->sel, this->hscroll.cap - 29, 0);
    00372       DrawString(x, y + 2, STR_8816, TC_FROMSTRING);
    00373
    00374       /* Draw the train counter */
    00375       i = 0;
    00376       u = v;
    00377       do i++; while ((u = u->Next()) != NULL); // Determine length of train
    00378       SetDParam(0, i);                      // Set the counter
    00379       DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
    00380     }
    00381   }
    00382
    00383   struct GetDepotVehiclePtData {
    00384     const Vehicle *head;
    00385     const Vehicle *wagon;
    00386   };
    00387
    00388   enum DepotGUIAction {
    00389     MODE_ERROR,
    00390     MODE_DRAG_VEHICLE,
    00391     MODE_SHOW_VEHICLE,
    00392     MODE_START_STOP,
    00393   };
    00394
    00395   DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, const Vehicle **veh, GetDepotVehiclePtData *d) const
    00396   {
    00397     uint xt, row, xm = 0, ym = 0;
    00398     int pos, skip = 0;
    00399     uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
    00400
    00401     if (this->type == VEH_TRAIN) {
    00402       xt = 0;
    00403       x -= 23;
    00404     } else {
    00405       xt = x / this->resize.step_width;
    00406       xm = x % this->resize.step_width;
    00407       if (xt >= this->hscroll.cap) return MODE_ERROR;
    00408
    00409       ym = (y - 14) % this->resize.step_height;
    00410     }
    00411
    00412     row = (y - 14) / this->resize.step_height;
    00413     if (row >= this->vscroll.cap) return MODE_ERROR;
    00414
    00415     pos = ((row + this->vscroll.pos) * boxes_in_each_row) + xt;
    00416
    00417     if ((int)(this->vehicle_list.Length() + this->wagon_list.Length()) <= pos) {
    00418       if (this->type == VEH_TRAIN) {
    00419         d->head  = NULL;
    00420         d->wagon = NULL;
    00421         return MODE_DRAG_VEHICLE;
    00422       } else {
    00423         return MODE_ERROR; // empty block, so no vehicle is selected
    00424       }
    00425     }
    00426
    00427     if ((int)this->vehicle_list.Length() > pos) {
    00428       *veh = this->vehicle_list[pos];
    00429       skip = this->hscroll.pos;
    00430     } else {
    00431       pos -= this->vehicle_list.Length();
    00432       *veh = this->wagon_list[pos];
    00433       /* free wagons don't have an initial loco. */
    00434       x -= _traininfo_vehicle_width;
    00435     }
    00436
    00437     switch (this->type) {
    00438       case VEH_TRAIN: {
    00439         const Vehicle *v = *veh;
    00440         d->head = d->wagon = v;
    00441
    00442         /* either pressed the flag or the number, but only when it's a loco */
    00443         if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
    00444
    00445         skip = (skip * 8) / _traininfo_vehicle_width;
    00446         x = (x * 8) / _traininfo_vehicle_width;
    00447
    00448         /* Skip vehicles that are scrolled off the list */
    00449         x += skip;
    00450
    00451         /* find the vehicle in this row that was clicked */
    00452         while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->Next();
    00453
    00454         /* if an articulated part was selected, find its parent */
    00455         while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
    00456
    00457         d->wagon = v;
    00458
    00459         return MODE_DRAG_VEHICLE;
    00460         }
    00461         break;
    00462
    00463       case VEH_ROAD:
    00464         if (xm >= 24) return MODE_DRAG_VEHICLE;
    00465         if (xm <= 16) return MODE_SHOW_VEHICLE;
    00466         break;
    00467
    00468       case VEH_SHIP:
    00469         if (xm >= 19) return MODE_DRAG_VEHICLE;
    00470         if (ym <= 10) return MODE_SHOW_VEHICLE;
    00471         break;
    00472
    00473       case VEH_AIRCRAFT:
    00474         if (xm >= 12) return MODE_DRAG_VEHICLE;
    00475         if (ym <= 12) return MODE_SHOW_VEHICLE;
    00476         break;
    00477
    00478       default: NOT_REACHED();
    00479     }
    00480     return MODE_START_STOP;
    00481   }
    00482
    00483   void DepotClick(int x, int y)
    00484   {
    00485     GetDepotVehiclePtData gdvp = { NULL, NULL };
    00486     const Vehicle *v = NULL;
    00487     DepotGUIAction mode = this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp);
    00488
    00489     /* share / copy orders */
    00490     if (_thd.place_mode != VHM_NONE && mode != MODE_ERROR) {
    00491       _place_clicked_vehicle = (this->type == VEH_TRAIN ? gdvp.head : v);
    00492       return;
    00493     }
    00494
    00495     if (this->type == VEH_TRAIN) v = gdvp.wagon;
    00496
    00497     switch (mode) {
    00498       case MODE_ERROR: // invalid
    00499         return;
    00500
    00501       case MODE_DRAG_VEHICLE: { // start dragging of vehicle
    00502         VehicleID sel = this->sel;
    00503
    00504         if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) {
    00505           this->sel = INVALID_VEHICLE;
    00506           TrainDepotMoveVehicle(v, sel, gdvp.head);
    00507         } else if (v != NULL) {
    00508           int image = v->GetImage(DIR_W);
    00509
    00510           this->sel = v->index;
    00511           this->SetDirty();
    00512           SetObjectToPlaceWnd(image, GetVehiclePalette(v), VHM_DRAG, this);
    00513
    00514           switch (v->type) {
    00515             case VEH_TRAIN:
    00516               _cursor.short_vehicle_offset = 16 - v->u.rail.cached_veh_length * 2;
    00517               break;
    00518
    00519             case VEH_ROAD:
    00520               _cursor.short_vehicle_offset = 16 - v->u.road.cached_veh_length * 2;
    00521               break;
    00522
    00523             default:
    00524               _cursor.short_vehicle_offset = 0;
    00525               break;
    00526           }
    00527           _cursor.vehchain = _ctrl_pressed;
    00528         }
    00529       } break;
    00530
    00531       case MODE_SHOW_VEHICLE: // show info window
    00532         ShowVehicleViewWindow(v);
    00533         break;
    00534
    00535       case MODE_START_STOP: { // click start/stop flag
    00536         uint command;
    00537
    00538         switch (this->type) {
    00539           case VEH_TRAIN:    command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN);        break;
    00540           case VEH_ROAD:     command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
    00541           case VEH_SHIP:     command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP);         break;
    00542           case VEH_AIRCRAFT: command = CMD_START_STOP_VEHICLE | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT);     break;
    00543           default: NOT_REACHED(); command = 0;
    00544         }
    00545         DoCommandP(v->tile, v->index, 0, command);
    00546       } break;
    00547
    00548       default: NOT_REACHED();
    00549     }
    00550   }
    00551
    00557   void HandleCloneVehClick(const Vehicle *v, const Window *w)
    00558   {
    00559     uint error_str;
    00560
    00561     if (v == NULL) return;
    00562
    00563     if (!v->IsPrimaryVehicle()) {
    00564       v = v->First();
    00565       /* Do nothing when clicking on a train in depot with no loc attached */
    00566       if (v->type == VEH_TRAIN && !IsFrontEngine(v)) return;
    00567     }
    00568
    00569     switch (v->type) {
    00570       case VEH_TRAIN:    error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
    00571       case VEH_ROAD:     error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE);     break;
    00572       case VEH_SHIP:     error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP);             break;
    00573       case VEH_AIRCRAFT: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT);         break;
    00574       default: return;
    00575     }
    00576
    00577     DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CMD_CLONE_VEHICLE | error_str, CcCloneVehicle);
    00578
    00579     ResetObjectToPlace();
    00580   }
    00581
    00582   void ResizeDepotButtons(Window *w)
    00583   {
    00584     ResizeButtons(w, DEPOT_WIDGET_BUILD, DEPOT_WIDGET_LOCATION);
    00585
    00586     if (this->type == VEH_TRAIN) {
    00587       /* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
    00588        * This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason                                                  */
    00589       this->widget[DEPOT_WIDGET_SELL_CHAIN].top    = ((this->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - this->widget[DEPOT_WIDGET_SELL].top) / 2) + this->widget[DEPOT_WIDGET_SELL].top;
    00590       this->widget[DEPOT_WIDGET_SELL].bottom     = this->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
    00591     }
    00592   }
    00593
    00594   /* Function to set up vehicle specific sprites and strings
    00595    * Only use this if it's the same widget, that's used for more than one vehicle type and it needs different text/sprites
    00596    * Vehicle specific text/sprites, that's in a widget, that's only shown for one vehicle type (like sell whole train) is set in the widget array
    00597    */
    00598   void SetupStringsForDepotWindow(VehicleType type)
    00599   {
    00600     switch (type) {
    00601       default: NOT_REACHED();
    00602
    00603       case VEH_TRAIN:
    00604         this->widget[DEPOT_WIDGET_CAPTION].data      = STR_8800_TRAIN_DEPOT;
    00605         this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
    00606         this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_TRAIN_TIP;
    00607         this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
    00608         this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
    00609
    00610         this->widget[DEPOT_WIDGET_BUILD].data        = STR_8815_NEW_VEHICLES;
    00611         this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
    00612         this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_TRAIN;
    00613         this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_TRAIN_DEPOT_INFO;
    00614
    00615         this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
    00616         this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
    00617         this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
    00618         this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
    00619
    00620         /* Sprites */
    00621         this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_TRAIN;
    00622         this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_TRAIN;
    00623         this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
    00624         break;
    00625
    00626       case VEH_ROAD:
    00627         this->widget[DEPOT_WIDGET_CAPTION].data      = STR_9003_ROAD_VEHICLE_DEPOT;
    00628         this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
    00629         this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_ROADVEH_TIP;
    00630         this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
    00631         this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
    00632
    00633         this->widget[DEPOT_WIDGET_BUILD].data        = STR_9004_NEW_VEHICLES;
    00634         this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9023_BUILD_NEW_ROAD_VEHICLE;
    00635         this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_ROAD_VEHICLE;
    00636         this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
    00637
    00638         this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
    00639         this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
    00640         this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
    00641         this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
    00642
    00643         /* Sprites */
    00644         this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_ROADVEH;
    00645         this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_ROADVEH;
    00646         this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
    00647         break;
    00648
    00649       case VEH_SHIP:
    00650         this->widget[DEPOT_WIDGET_CAPTION].data      = STR_9803_SHIP_DEPOT;
    00651         this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
    00652         this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_SHIP_TIP;
    00653         this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
    00654         this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
    00655
    00656         this->widget[DEPOT_WIDGET_BUILD].data        = STR_9804_NEW_SHIPS;
    00657         this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9820_BUILD_NEW_SHIP;
    00658         this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_SHIP;
    00659         this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_SHIP_DEPOT_INFO;
    00660
    00661         this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
    00662         this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
    00663         this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
    00664         this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
    00665
    00666         /* Sprites */
    00667         this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_SHIP;
    00668         this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_SHIP;
    00669         this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
    00670         break;
    00671
    00672       case VEH_AIRCRAFT:
    00673         this->widget[DEPOT_WIDGET_CAPTION].data      = STR_A002_AIRCRAFT_HANGAR;
    00674         this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
    00675         this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_HANGAR_TIP;
    00676         this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
    00677         this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
    00678
    00679         this->widget[DEPOT_WIDGET_BUILD].data        = STR_A003_NEW_AIRCRAFT;
    00680         this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_A022_BUILD_NEW_AIRCRAFT;
    00681         this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_AIRCRAFT;
    00682         this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
    00683
    00684         this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
    00685         this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
    00686         this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
    00687         this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
    00688
    00689         /* Sprites */
    00690         this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_AIRCRAFT;
    00691         this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_AIRCRAFT;
    00692         this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
    00693         break;
    00694     }
    00695   }
    00696
    00697   void CreateDepotListWindow(VehicleType type)
    00698   {
    00699     this->type = type;
    00700     _backup_orders_tile = 0;
    00701
    00702     assert(IsCompanyBuildableVehicleType(type)); // ensure that we make the call with a valid type
    00703
    00704     /* Resize the window according to the vehicle type */
    00705
    00706     /* Set the number of blocks in each direction */
    00707     this->vscroll.cap = _resize_cap[type][0];
    00708     this->hscroll.cap = _resize_cap[type][1];
    00709
    00710     /* Set the block size */
    00711     this->resize.step_width  = _block_sizes[type][0];
    00712     this->resize.step_height = _block_sizes[type][1];
    00713
    00714     /* Enlarge the window to fit with the selected number of blocks of the selected size */
    00715     ResizeWindow(this,
    00716           _block_sizes[type][0] * this->hscroll.cap,
    00717           _block_sizes[type][1] * this->vscroll.cap);
    00718
    00719     if (type == VEH_TRAIN) {
    00720       /* Make space for the horizontal scrollbar vertically, and the unit
    00721        * number, flag, and length counter horizontally. */
    00722       ResizeWindow(this, 36, 12);
    00723       /* substract the newly added space from the matrix since it was meant for the scrollbar */
    00724       this->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
    00725     }
    00726
    00727     /* Set the minimum window size to the current window size */
    00728     this->resize.width  = this->width;
    00729     this->resize.height = this->height;
    00730
    00731     this->SetupStringsForDepotWindow(type);
    00732
    00733     this->widget[DEPOT_WIDGET_MATRIX].data =
    00734       (this->vscroll.cap * 0x100) // number of rows to draw on the background
    00735       + (type == VEH_TRAIN ? 1 : this->hscroll.cap); // number of boxes in each row. Trains always have just one
    00736
    00737
    00738     this->SetWidgetsHiddenState(type != VEH_TRAIN,
    00739       DEPOT_WIDGET_H_SCROLL,
    00740       DEPOT_WIDGET_SELL_CHAIN,
    00741       WIDGET_LIST_END);
    00742
    00743     ResizeDepotButtons(this);
    00744   }
    00745
    00746   virtual void OnInvalidateData(int data)
    00747   {
    00748     this->generate_list = true;
    00749   }
    00750
    00751   virtual void OnPaint()
    00752   {
    00753     if (this->generate_list) {
    00754       /* Generate the vehicle list
    00755        * It's ok to use the wagon pointers for non-trains as they will be ignored */
    00756       BuildDepotVehicleList(this->type, this->window_number, &this->vehicle_list, &this->wagon_list);
    00757       this->generate_list = false;
    00758       DepotSortList(&this->vehicle_list);
    00759     }
    00760     DrawDepotWindow(this);
    00761   }
    00762
    00763   virtual void OnClick(Point pt, int widget)
    00764   {
    00765     switch (widget) {
    00766       case DEPOT_WIDGET_MATRIX: // List
    00767         this->DepotClick(pt.x, pt.y);
    00768         break;
    00769
    00770       case DEPOT_WIDGET_BUILD: // Build vehicle
    00771         ResetObjectToPlace();
    00772         ShowBuildVehicleWindow(this->window_number, this->type);
    00773         break;
    00774
    00775       case DEPOT_WIDGET_CLONE: // Clone button
    00776         this->InvalidateWidget(DEPOT_WIDGET_CLONE);
    00777         this->ToggleWidgetLoweredState(DEPOT_WIDGET_CLONE);
    00778
    00779         if (this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
    00780           static const CursorID clone_icons[] = {
    00781             SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
    00782             SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
    00783           };
    00784
    00785           _place_clicked_vehicle = NULL;
    00786           SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, VHM_RECT, this);
    00787         } else {
    00788           ResetObjectToPlace();
    00789         }
    00790           break;
    00791
    00792       case DEPOT_WIDGET_LOCATION:
    00793         if (_ctrl_pressed) {
    00794           ShowExtraViewPortWindow(this->window_number);
    00795         } else {
    00796           ScrollMainWindowToTile(this->window_number);
    00797         }
    00798         break;
    00799
    00800       case DEPOT_WIDGET_STOP_ALL:
    00801       case DEPOT_WIDGET_START_ALL:
    00802         DoCommandP(this->window_number, 0, this->type | (widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), CMD_MASS_START_STOP);
    00803         break;
    00804
    00805       case DEPOT_WIDGET_SELL_ALL:
    00806         /* Only open the confimation window if there are anything to sell */
    00807         if (this->vehicle_list.Length() != 0 || this->wagon_list.Length() != 0) {
    00808           static const StringID confirm_captions[] = {
    00809             STR_8800_TRAIN_DEPOT,
    00810             STR_9003_ROAD_VEHICLE_DEPOT,
    00811             STR_9803_SHIP_DEPOT,
    00812             STR_A002_AIRCRAFT_HANGAR
    00813           };
    00814           TileIndex tile = this->window_number;
    00815           byte vehtype = this->type;
    00816
    00817           SetDParam(0, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
    00818           ShowQuery(
    00819             confirm_captions[vehtype],
    00820             STR_DEPOT_SELL_CONFIRMATION_TEXT,
    00821             this,
    00822             DepotSellAllConfirmationCallback
    00823           );
    00824         }
    00825         break;
    00826
    00827       case DEPOT_WIDGET_VEHICLE_LIST:
    00828         ShowVehicleListWindow(GetTileOwner(this->window_number), this->type, (TileIndex)this->window_number);
    00829         break;
    00830
    00831       case DEPOT_WIDGET_AUTOREPLACE:
    00832         DoCommandP(this->window_number, this->type, 0, CMD_DEPOT_MASS_AUTOREPLACE);
    00833         break;
    00834
    00835     }
    00836   }
    00837
    00838   virtual void OnRightClick(Point pt, int widget)
    00839   {
    00840     if (widget != DEPOT_WIDGET_MATRIX) return;
    00841
    00842     GetDepotVehiclePtData gdvp = { NULL, NULL };
    00843     const Vehicle *v = NULL;
    00844     DepotGUIAction mode = this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp);
    00845
    00846     if (this->type == VEH_TRAIN) v = gdvp.wagon;
    00847
    00848     if (v != NULL && mode == MODE_DRAG_VEHICLE) {
    00849       AcceptedCargo capacity, loaded;
    00850       memset(capacity, 0, sizeof(capacity));
    00851       memset(loaded, 0, sizeof(loaded));
    00852
    00853       /* Display info for single (articulated) vehicle, or for whole chain starting with selected vehicle */
    00854       bool whole_chain = (this->type == VEH_TRAIN && _ctrl_pressed);
    00855
    00856       /* loop through vehicle chain and collect cargos */
    00857       uint num = 0;
    00858       for (const Vehicle *w = v; w != NULL; w = w->Next()) {
    00859         if (w->cargo_cap > 0 && w->cargo_type < NUM_CARGO) {
    00860           capacity[w->cargo_type] += w->cargo_cap;
    00861           loaded  [w->cargo_type] += w->cargo.Count();
    00862         }
    00863
    00864         if (w->type == VEH_TRAIN && !EngineHasArticPart(w)) {
    00865           num++;
    00866           if (!whole_chain) break;
    00867         }
    00868       }
    00869
    00870       /* Build tooltipstring */
    00871       static char details[1024];
    00872       details[0] = '\0';
    00873       char *pos = details;
    00874
    00875       for (CargoID cargo_type = 0; cargo_type < NUM_CARGO; cargo_type++) {
    00876         if (capacity[cargo_type] == 0) continue;
    00877
    00878         SetDParam(0, cargo_type);           // {CARGO} #1
    00879         SetDParam(1, loaded[cargo_type]);   // {CARGO} #2
    00880         SetDParam(2, cargo_type);           // {SHORTCARGO} #1
    00881         SetDParam(3, capacity[cargo_type]); // {SHORTCARGO} #2
    00882         pos = GetString(pos, STR_DEPOT_VEHICLE_TOOLTIP_CARGO, lastof(details));
    00883       }
    00884
    00885       /* Show tooltip window */
    00886       uint64 args[2];
    00887       args[0] = (whole_chain ? num : v->engine_type);
    00888       args[1] = (uint64)(size_t)details;
    00889       GuiShowTooltips(whole_chain ? STR_DEPOT_VEHICLE_TOOLTIP_CHAIN : STR_DEPOT_VEHICLE_TOOLTIP, 2, args);
    00890     } else {
    00891       /* Show tooltip help */
    00892       StringID tooltip = INVALID_STRING_ID;
    00893       switch (this->type) {
    00894         case VEH_TRAIN:    tooltip = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR; break;
    00895         case VEH_ROAD:     tooltip = STR_9022_VEHICLES_CLICK_ON_VEHICLE; break;
    00896         case VEH_SHIP:     tooltip = STR_981F_SHIPS_CLICK_ON_SHIP_FOR;   break;
    00897         case VEH_AIRCRAFT: tooltip = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;break;
    00898         default: NOT_REACHED();
    00899       }
    00900       GuiShowTooltips(tooltip);
    00901     }
    00902   }
    00903
    00904
    00905   virtual void OnPlaceObject(Point pt, TileIndex tile)
    00906   {
    00907     const Vehicle *v = CheckMouseOverVehicle();
    00908
    00909     if (v != NULL) HandleCloneVehClick(v, this);
    00910   }
    00911
    00912   virtual void OnPlaceObjectAbort()
    00913   {
    00914     /* abort clone */
    00915     this->RaiseWidget(DEPOT_WIDGET_CLONE);
    00916     this->InvalidateWidget(DEPOT_WIDGET_CLONE);
    00917
    00918     /* abort drag & drop */
    00919     this->sel = INVALID_VEHICLE;
    00920     this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
    00921   };
    00922
    00923   /* check if a vehicle in a depot was clicked.. */
    00924   virtual void OnMouseLoop()
    00925   {
    00926     const Vehicle *v = _place_clicked_vehicle;
    00927
    00928     /* since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button */
    00929     if (v != NULL && this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
    00930       _place_clicked_vehicle = NULL;
    00931       HandleCloneVehClick(v, this);
    00932     }
    00933   }
    00934
    00935   virtual void OnDragDrop(Point pt, int widget)
    00936   {
    00937     switch (widget) {
    00938       case DEPOT_WIDGET_MATRIX: {
    00939         const Vehicle *v = NULL;
    00940         VehicleID sel = this->sel;
    00941
    00942         this->sel = INVALID_VEHICLE;
    00943         this->SetDirty();
    00944
    00945         if (this->type == VEH_TRAIN) {
    00946           GetDepotVehiclePtData gdvp = { NULL, NULL };
    00947
    00948           if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
    00949             sel != INVALID_VEHICLE) {
    00950             if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
    00951               DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
    00952             } else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
    00953               TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
    00954             } else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
    00955               ShowVehicleViewWindow(gdvp.head);
    00956             }
    00957           }
    00958         } else if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
    00959           v != NULL &&
    00960           sel == v->index) {
    00961           ShowVehicleViewWindow(v);
    00962         }
    00963       } break;
    00964
    00965       case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
    00966         if (!this->IsWidgetDisabled(DEPOT_WIDGET_SELL) &&
    00967           this->sel != INVALID_VEHICLE) {
    00968           uint command;
    00969
    00970           if (this->IsWidgetDisabled(widget)) return;
    00971           if (this->sel == INVALID_VEHICLE) return;
    00972
    00973           this->HandleButtonClick(widget);
    00974
    00975           const Vehicle *v = GetVehicle(this->sel);
    00976           this->sel = INVALID_VEHICLE;
    00977           this->SetDirty();
    00978
    00979           int sell_cmd = (v->type == VEH_TRAIN && (widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
    00980
    00981           bool is_engine = (!(v->type == VEH_TRAIN && !IsFrontEngine(v)));
    00982
    00983           if (is_engine) {
    00984             _backup_orders_tile = v->tile;
    00985             BackupVehicleOrders(v);
    00986           }
    00987
    00988           switch (v->type) {
    00989             case VEH_TRAIN:    command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
    00990             case VEH_ROAD:     command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE);       break;
    00991             case VEH_SHIP:     command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP);                   break;
    00992             case VEH_AIRCRAFT: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT);           break;
    00993             default: NOT_REACHED(); command = 0;
    00994           }
    00995
    00996           if (!DoCommandP(v->tile, v->index, sell_cmd, command) && is_engine) _backup_orders_tile = 0;
    00997         }
    00998         break;
    00999       default:
    01000         this->sel = INVALID_VEHICLE;
    01001         this->SetDirty();
    01002     }
    01003     _cursor.vehchain = false;
    01004   }
    01005
    01006   virtual void OnResize(Point new_size, Point delta)
    01007   {
    01008     this->vscroll.cap += delta.y / (int)this->resize.step_height;
    01009     this->hscroll.cap += delta.x / (int)this->resize.step_width;
    01010     this->widget[DEPOT_WIDGET_MATRIX].data = (this->vscroll.cap << 8) + (this->type == VEH_TRAIN ? 1 : this->hscroll.cap);
    01011     ResizeDepotButtons(this);
    01012   }
    01013
    01014   virtual EventState OnCTRLStateChange()
    01015   {
    01016     if (this->sel != INVALID_VEHICLE) {
    01017       _cursor.vehchain = _ctrl_pressed;
    01018       this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
    01019       return ES_HANDLED;
    01020     }
    01021
    01022     return ES_NOT_HANDLED;
    01023   }
    01024 };
    01025
    01026 static void DepotSellAllConfirmationCallback(Window *win, bool confirmed)
    01027 {
    01028   if (confirmed) {
    01029     DepotWindow *w = (DepotWindow*)win;
    01030     TileIndex tile = w->window_number;
    01031     byte vehtype = w->type;
    01032     DoCommandP(tile, vehtype, 0, CMD_DEPOT_SELL_ALL_VEHICLES);
    01033   }
    01034 }
    01035
    01040 void ShowDepotWindow(TileIndex tile, VehicleType type)
    01041 {
    01042   if (BringWindowToFrontById(WC_VEHICLE_DEPOT, tile) != NULL) return;
    01043
    01044   const WindowDesc *desc;
    01045   switch (type) {
    01046     default: NOT_REACHED();
    01047     case VEH_TRAIN:    desc = &_train_depot_desc;    break;
    01048     case VEH_ROAD:     desc = &_road_depot_desc;     break;
    01049     case VEH_SHIP:     desc = &_ship_depot_desc;     break;
    01050     case VEH_AIRCRAFT: desc = &_aircraft_depot_desc; break;
    01051   }
    01052
    01053   new DepotWindow(desc, tile, type);
    01054 }
    01055
    01059 void DeleteDepotHighlightOfVehicle(const Vehicle *v)
    01060 {
    01061   DepotWindow *w;
    01062
    01063   /* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any depots either
    01064    * If that is the case, we can skip looping though the windows and save time
    01065    */
    01066   if (_special_mouse_mode != WSM_DRAGDROP) return;
    01067
    01068   w = dynamic_cast<DepotWindow*>(FindWindowById(WC_VEHICLE_DEPOT, v->tile));
    01069   if (w != NULL) {
    01070     if (w->sel == v->index) ResetObjectToPlace();
    01071   }
    01072 }