depot_gui.cpp

Go to the documentation of this file.
00001 /* $Id: depot_gui.cpp 16804 2009-07-13 10:16:50Z 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_ERROR_CAN_T_REVERSE_DIRECTION_RAIL_VEHICLE));
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 }

Generated on Wed Jul 15 20:35:58 2009 for OpenTTD by  doxygen 1.5.6