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 }

Generated on Wed Oct 1 17:03:20 2008 for openttd by  doxygen 1.5.6