# depot_gui.cpp

Go to the documentation of this file.

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