engine_gui.cpp

Go to the documentation of this file.
00001 /* $Id: engine_gui.cpp 23740 2012-01-03 21:32:51Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "window_gui.h"
00014 #include "engine_base.h"
00015 #include "command_func.h"
00016 #include "strings_func.h"
00017 #include "engine_gui.h"
00018 #include "articulated_vehicles.h"
00019 #include "vehicle_func.h"
00020 #include "company_func.h"
00021 #include "rail.h"
00022 #include "settings_type.h"
00023 
00024 #include "widgets/engine_widget.h"
00025 
00026 #include "table/strings.h"
00027 
00033 StringID GetEngineCategoryName(EngineID engine)
00034 {
00035   const Engine *e = Engine::Get(engine);
00036   switch (e->type) {
00037     default: NOT_REACHED();
00038     case VEH_ROAD:              return STR_ENGINE_PREVIEW_ROAD_VEHICLE;
00039     case VEH_AIRCRAFT:          return STR_ENGINE_PREVIEW_AIRCRAFT;
00040     case VEH_SHIP:              return STR_ENGINE_PREVIEW_SHIP;
00041     case VEH_TRAIN:
00042       return GetRailTypeInfo(e->u.rail.railtype)->strings.new_loco;
00043   }
00044 }
00045 
00046 static const NWidgetPart _nested_engine_preview_widgets[] = {
00047   NWidget(NWID_HORIZONTAL),
00048     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
00049     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_ENGINE_PREVIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00050   EndContainer(),
00051   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
00052     NWidget(WWT_EMPTY, INVALID_COLOUR, WID_EP_QUESTION), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0),
00053     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, 10, 85),
00054       NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_EP_NO), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
00055       NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_EP_YES), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
00056     EndContainer(),
00057     NWidget(NWID_SPACER), SetMinimalSize(0, 8),
00058   EndContainer(),
00059 };
00060 
00061 struct EnginePreviewWindow : Window {
00062   static const int VEHICLE_SPACE = 40; // The space to show the vehicle image
00063 
00064   EnginePreviewWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
00065   {
00066     this->InitNested(desc, window_number);
00067   }
00068 
00069   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00070   {
00071     if (widget != WID_EP_QUESTION) return;
00072 
00073     EngineID engine = this->window_number;
00074     SetDParam(0, GetEngineCategoryName(engine));
00075     size->height = GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, size->width) + WD_PAR_VSEP_WIDE + FONT_HEIGHT_NORMAL + VEHICLE_SPACE;
00076     SetDParam(0, engine);
00077     size->height += GetStringHeight(GetEngineInfoString(engine), size->width);
00078   }
00079 
00080   virtual void DrawWidget(const Rect &r, int widget) const
00081   {
00082     if (widget != WID_EP_QUESTION) return;
00083 
00084     EngineID engine = this->window_number;
00085     SetDParam(0, GetEngineCategoryName(engine));
00086     int y = r.top + GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, r.right - r.top + 1);
00087     y = DrawStringMultiLine(r.left, r.right, r.top, y, STR_ENGINE_PREVIEW_MESSAGE, TC_FROMSTRING, SA_CENTER) + WD_PAR_VSEP_WIDE;
00088 
00089     SetDParam(0, engine);
00090     DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_ENGINE_NAME, TC_BLACK, SA_HOR_CENTER);
00091     y += FONT_HEIGHT_NORMAL;
00092 
00093     DrawVehicleEngine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, this->width >> 1, y + VEHICLE_SPACE / 2, engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW);
00094 
00095     y += VEHICLE_SPACE;
00096     DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER);
00097   }
00098 
00099   virtual void OnClick(Point pt, int widget, int click_count)
00100   {
00101     switch (widget) {
00102       case WID_EP_YES:
00103         DoCommandP(0, this->window_number, 0, CMD_WANT_ENGINE_PREVIEW);
00104         /* FALL THROUGH */
00105       case WID_EP_NO:
00106         delete this;
00107         break;
00108     }
00109   }
00110 };
00111 
00112 static const WindowDesc _engine_preview_desc(
00113   WDP_CENTER, 0, 0,
00114   WC_ENGINE_PREVIEW, WC_NONE,
00115   WDF_CONSTRUCTION,
00116   _nested_engine_preview_widgets, lengthof(_nested_engine_preview_widgets)
00117 );
00118 
00119 
00120 void ShowEnginePreviewWindow(EngineID engine)
00121 {
00122   AllocateWindowDescFront<EnginePreviewWindow>(&_engine_preview_desc, engine);
00123 }
00124 
00130 uint GetTotalCapacityOfArticulatedParts(EngineID engine)
00131 {
00132   uint total = 0;
00133 
00134   CargoArray cap = GetCapacityOfArticulatedParts(engine);
00135   for (CargoID c = 0; c < NUM_CARGO; c++) {
00136     total += cap[c];
00137   }
00138 
00139   return total;
00140 }
00141 
00142 static StringID GetTrainEngineInfoString(const Engine *e)
00143 {
00144   SetDParam(0, e->GetCost());
00145   SetDParam(2, e->GetDisplayMaxSpeed());
00146   SetDParam(3, e->GetPower());
00147   SetDParam(1, e->GetDisplayWeight());
00148   SetDParam(7, e->GetDisplayMaxTractiveEffort());
00149 
00150   SetDParam(4, e->GetRunningCost());
00151 
00152   uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
00153   if (capacity != 0) {
00154     SetDParam(5, e->GetDefaultCargoType());
00155     SetDParam(6, capacity);
00156   } else {
00157     SetDParam(5, CT_INVALID);
00158   }
00159   return (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(e->u.rail.railtype)->acceleration_type != 2) ? STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE : STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER;
00160 }
00161 
00162 static StringID GetAircraftEngineInfoString(const Engine *e)
00163 {
00164   CargoID cargo = e->GetDefaultCargoType();
00165   uint16 mail_capacity;
00166   uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
00167   uint16 range = e->GetRange();
00168 
00169   SetDParam(0, e->GetCost());
00170   SetDParam(1, e->GetDisplayMaxSpeed());
00171   SetDParam(2, cargo);
00172   SetDParam(3, capacity);
00173   SetDParam(7, range);
00174 
00175   if (mail_capacity > 0) {
00176     SetDParam(4, CT_MAIL);
00177     SetDParam(5, mail_capacity);
00178     SetDParam(6, e->GetRunningCost());
00179     return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_CAPACITY_RUNCOST;
00180   } else {
00181     SetDParam(4, e->GetRunningCost());
00182     return range > 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_RANGE_CAPACITY_RUNCOST : STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
00183   }
00184 }
00185 
00186 static StringID GetRoadVehEngineInfoString(const Engine *e)
00187 {
00188   if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
00189     SetDParam(0, e->GetCost());
00190     SetDParam(1, e->GetDisplayMaxSpeed());
00191     uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
00192     if (capacity != 0) {
00193       SetDParam(2, e->GetDefaultCargoType());
00194       SetDParam(3, capacity);
00195     } else {
00196       SetDParam(2, CT_INVALID);
00197     }
00198     SetDParam(4, e->GetRunningCost());
00199     return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
00200   } else {
00201     SetDParam(0, e->GetCost());
00202     SetDParam(2, e->GetDisplayMaxSpeed());
00203     SetDParam(3, e->GetPower());
00204     SetDParam(1, e->GetDisplayWeight());
00205     SetDParam(7, e->GetDisplayMaxTractiveEffort());
00206 
00207     SetDParam(4, e->GetRunningCost());
00208 
00209     uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
00210     if (capacity != 0) {
00211       SetDParam(5, e->GetDefaultCargoType());
00212       SetDParam(6, capacity);
00213     } else {
00214       SetDParam(5, CT_INVALID);
00215     }
00216     return STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE;
00217   }
00218 }
00219 
00220 static StringID GetShipEngineInfoString(const Engine *e)
00221 {
00222   SetDParam(0, e->GetCost());
00223   SetDParam(1, e->GetDisplayMaxSpeed());
00224   SetDParam(2, e->GetDefaultCargoType());
00225   SetDParam(3, e->GetDisplayDefaultCapacity());
00226   SetDParam(4, e->GetRunningCost());
00227   return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAPACITY_RUNCOST;
00228 }
00229 
00230 
00237 StringID GetEngineInfoString(EngineID engine)
00238 {
00239   const Engine *e = Engine::Get(engine);
00240 
00241   switch (e->type) {
00242     case VEH_TRAIN:
00243       return GetTrainEngineInfoString(e);
00244 
00245     case VEH_ROAD:
00246       return GetRoadVehEngineInfoString(e);
00247 
00248     case VEH_SHIP:
00249       return GetShipEngineInfoString(e);
00250 
00251     case VEH_AIRCRAFT:
00252       return GetAircraftEngineInfoString(e);
00253 
00254     default: NOT_REACHED();
00255   }
00256 }
00257 
00267 void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
00268 {
00269   const Engine *e = Engine::Get(engine);
00270 
00271   switch (e->type) {
00272     case VEH_TRAIN:
00273       DrawTrainEngine(left, right, preferred_x, y, engine, pal, image_type);
00274       break;
00275 
00276     case VEH_ROAD:
00277       DrawRoadVehEngine(left, right, preferred_x, y, engine, pal, image_type);
00278       break;
00279 
00280     case VEH_SHIP:
00281       DrawShipEngine(left, right, preferred_x, y, engine, pal, image_type);
00282       break;
00283 
00284     case VEH_AIRCRAFT:
00285       DrawAircraftEngine(left, right, preferred_x, y, engine, pal, image_type);
00286       break;
00287 
00288     default: NOT_REACHED();
00289   }
00290 }
00291 
00297 void EngList_Sort(GUIEngineList *el, EngList_SortTypeFunction compare)
00298 {
00299   uint size = el->Length();
00300   /* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems)
00301    * generally, do not sort if there are less than 2 items */
00302   if (size < 2) return;
00303   QSortT(el->Begin(), size, compare);
00304 }
00305 
00313 void EngList_SortPartial(GUIEngineList *el, EngList_SortTypeFunction compare, uint begin, uint num_items)
00314 {
00315   if (num_items < 2) return;
00316   assert(begin < el->Length());
00317   assert(begin + num_items <= el->Length());
00318   QSortT(el->Get(begin), num_items, compare);
00319 }
00320