4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file engine_gui.cpp GUI to show engine related information. */
13 #include "window_gui.h"
14 #include "engine_base.h"
15 #include "command_func.h"
16 #include "strings_func.h"
17 #include "engine_gui.h"
18 #include "articulated_vehicles.h"
19 #include "vehicle_func.h"
20 #include "company_func.h"
22 #include "settings_type.h"
28 #include "widgets/engine_widget.h"
30 #include "table/strings.h"
32 #include "safeguards.h"
35 * Return the category of an engine.
36 * @param engine Engine to examine.
37 * @return String describing the category ("road veh", "train". "airplane", or "ship") of the engine.
39 StringID
GetEngineCategoryName(EngineID engine
)
41 const Engine
*e
= Engine::Get(engine
);
43 default: NOT_REACHED();
44 case VEH_ROAD
: return STR_ENGINE_PREVIEW_ROAD_VEHICLE
;
45 case VEH_AIRCRAFT
: return STR_ENGINE_PREVIEW_AIRCRAFT
;
46 case VEH_SHIP
: return STR_ENGINE_PREVIEW_SHIP
;
48 return GetRailTypeInfo(e
->u
.rail
.railtype
)->strings
.new_loco
;
52 static const NWidgetPart _nested_engine_preview_widgets
[] = {
53 NWidget(NWID_HORIZONTAL
),
54 NWidget(WWT_CLOSEBOX
, COLOUR_LIGHT_BLUE
),
55 NWidget(WWT_CAPTION
, COLOUR_LIGHT_BLUE
), SetDataTip(STR_ENGINE_PREVIEW_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
57 NWidget(WWT_PANEL
, COLOUR_LIGHT_BLUE
),
58 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_EP_QUESTION
), SetMinimalSize(300, 0), SetPadding(8, 8, 8, 8), SetFill(1, 0),
59 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
), SetPIP(85, 10, 85),
60 NWidget(WWT_PUSHTXTBTN
, COLOUR_LIGHT_BLUE
, WID_EP_NO
), SetDataTip(STR_QUIT_NO
, STR_NULL
), SetFill(1, 0),
61 NWidget(WWT_PUSHTXTBTN
, COLOUR_LIGHT_BLUE
, WID_EP_YES
), SetDataTip(STR_QUIT_YES
, STR_NULL
), SetFill(1, 0),
63 NWidget(NWID_SPACER
), SetMinimalSize(0, 8),
67 struct EnginePreviewWindow
: Window
{
68 int vehicle_space
; // The space to show the vehicle image
70 EnginePreviewWindow(WindowDesc
*desc
, WindowNumber window_number
) : Window(desc
)
72 this->InitNested(window_number
);
74 /* There is no way to recover the window; so disallow closure via DEL; unless SHIFT+DEL */
75 this->flags
|= WF_STICKY
;
78 virtual void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
)
80 if (widget
!= WID_EP_QUESTION
) return;
82 /* Get size of engine sprite, on loan from depot_gui.cpp */
83 EngineID engine
= this->window_number
;
84 EngineImageType image_type
= EIT_PURCHASE
;
88 const Engine
*e
= Engine::Get(engine
);
90 default: NOT_REACHED();
91 case VEH_TRAIN
: GetTrainSpriteSize( engine
, x
, y
, x_offs
, y_offs
, image_type
); break;
92 case VEH_ROAD
: GetRoadVehSpriteSize( engine
, x
, y
, x_offs
, y_offs
, image_type
); break;
93 case VEH_SHIP
: GetShipSpriteSize( engine
, x
, y
, x_offs
, y_offs
, image_type
); break;
94 case VEH_AIRCRAFT
: GetAircraftSpriteSize(engine
, x
, y
, x_offs
, y_offs
, image_type
); break;
96 this->vehicle_space
= max
<int>(40, y
- y_offs
);
98 size
->width
= max(size
->width
, x
- x_offs
);
99 SetDParam(0, GetEngineCategoryName(engine
));
100 size
->height
= GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE
, size
->width
) + WD_PAR_VSEP_WIDE
+ FONT_HEIGHT_NORMAL
+ this->vehicle_space
;
101 SetDParam(0, engine
);
102 size
->height
+= GetStringHeight(GetEngineInfoString(engine
), size
->width
);
105 virtual void DrawWidget(const Rect
&r
, int widget
) const
107 if (widget
!= WID_EP_QUESTION
) return;
109 EngineID engine
= this->window_number
;
110 SetDParam(0, GetEngineCategoryName(engine
));
111 int y
= r
.top
+ GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE
, r
.right
- r
.top
+ 1);
112 y
= DrawStringMultiLine(r
.left
, r
.right
, r
.top
, y
, STR_ENGINE_PREVIEW_MESSAGE
, TC_FROMSTRING
, SA_CENTER
) + WD_PAR_VSEP_WIDE
;
114 SetDParam(0, engine
);
115 DrawString(r
.left
+ WD_FRAMERECT_LEFT
, r
.right
- WD_FRAMERECT_RIGHT
, y
, STR_ENGINE_NAME
, TC_BLACK
, SA_HOR_CENTER
);
116 y
+= FONT_HEIGHT_NORMAL
;
118 DrawVehicleEngine(r
.left
+ WD_FRAMERECT_LEFT
, r
.right
- WD_FRAMERECT_RIGHT
, this->width
>> 1, y
+ this->vehicle_space
/ 2, engine
, GetEnginePalette(engine
, _local_company
), EIT_PREVIEW
);
120 y
+= this->vehicle_space
;
121 DrawStringMultiLine(r
.left
+ WD_FRAMERECT_LEFT
, r
.right
- WD_FRAMERECT_RIGHT
, y
, r
.bottom
, GetEngineInfoString(engine
), TC_FROMSTRING
, SA_CENTER
);
124 virtual void OnClick(Point pt
, int widget
, int click_count
)
128 DoCommandP(0, this->window_number
, 0, CMD_WANT_ENGINE_PREVIEW
);
131 if (!_shift_pressed
) delete this;
136 virtual void OnInvalidateData(int data
= 0, bool gui_scope
= true)
138 if (!gui_scope
) return;
140 EngineID engine
= this->window_number
;
141 if (Engine::Get(engine
)->preview_company
!= _local_company
) delete this;
145 static WindowDesc
_engine_preview_desc(
146 WDP_CENTER
, "engine_preview", 0, 0,
147 WC_ENGINE_PREVIEW
, WC_NONE
,
149 _nested_engine_preview_widgets
, lengthof(_nested_engine_preview_widgets
)
153 void ShowEnginePreviewWindow(EngineID engine
)
155 AllocateWindowDescFront
<EnginePreviewWindow
>(&_engine_preview_desc
, engine
);
159 * Get the capacity of an engine with articulated parts.
160 * @param engine The engine to get the capacity of.
161 * @return The capacity.
163 uint
GetTotalCapacityOfArticulatedParts(EngineID engine
)
165 CargoArray cap
= GetCapacityOfArticulatedParts(engine
);
166 return cap
.GetSum
<uint
>();
169 static StringID
GetTrainEngineInfoString(const Engine
*e
)
171 SetDParam(0, e
->GetCost());
172 SetDParam(2, e
->GetDisplayMaxSpeed());
173 SetDParam(3, e
->GetPower());
174 SetDParam(1, e
->GetDisplayWeight());
175 SetDParam(7, e
->GetDisplayMaxTractiveEffort());
177 SetDParam(4, e
->GetRunningCost());
179 uint capacity
= GetTotalCapacityOfArticulatedParts(e
->index
);
181 SetDParam(5, e
->GetDefaultCargoType());
182 SetDParam(6, capacity
);
184 SetDParam(5, CT_INVALID
);
186 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
;
189 static StringID
GetAircraftEngineInfoString(const Engine
*e
)
191 CargoID cargo
= e
->GetDefaultCargoType();
192 uint16 mail_capacity
;
193 uint capacity
= e
->GetDisplayDefaultCapacity(&mail_capacity
);
194 uint16 range
= e
->GetRange();
197 SetDParam(i
++, e
->GetCost());
198 SetDParam(i
++, e
->GetDisplayMaxSpeed());
199 SetDParam(i
++, e
->GetAircraftTypeText());
200 if (range
> 0) SetDParam(i
++, range
);
201 SetDParam(i
++, cargo
);
202 SetDParam(i
++, capacity
);
204 if (mail_capacity
> 0) {
205 SetDParam(i
++, CT_MAIL
);
206 SetDParam(i
++, mail_capacity
);
207 SetDParam(i
++, e
->GetRunningCost());
208 return range
> 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_RANGE_CAP_CAP_RUNCOST
: STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_CAP_CAP_RUNCOST
;
210 SetDParam(i
++, e
->GetRunningCost());
211 return range
> 0 ? STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_RANGE_CAP_RUNCOST
: STR_ENGINE_PREVIEW_COST_MAX_SPEED_TYPE_CAP_RUNCOST
;
215 static StringID
GetRoadVehEngineInfoString(const Engine
*e
)
217 if (_settings_game
.vehicle
.roadveh_acceleration_model
== AM_ORIGINAL
) {
218 SetDParam(0, e
->GetCost());
219 SetDParam(1, e
->GetDisplayMaxSpeed());
220 uint capacity
= GetTotalCapacityOfArticulatedParts(e
->index
);
222 SetDParam(2, e
->GetDefaultCargoType());
223 SetDParam(3, capacity
);
225 SetDParam(2, CT_INVALID
);
227 SetDParam(4, e
->GetRunningCost());
228 return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST
;
230 SetDParam(0, e
->GetCost());
231 SetDParam(2, e
->GetDisplayMaxSpeed());
232 SetDParam(3, e
->GetPower());
233 SetDParam(1, e
->GetDisplayWeight());
234 SetDParam(7, e
->GetDisplayMaxTractiveEffort());
236 SetDParam(4, e
->GetRunningCost());
238 uint capacity
= GetTotalCapacityOfArticulatedParts(e
->index
);
240 SetDParam(5, e
->GetDefaultCargoType());
241 SetDParam(6, capacity
);
243 SetDParam(5, CT_INVALID
);
245 return STR_ENGINE_PREVIEW_COST_WEIGHT_SPEED_POWER_MAX_TE
;
249 static StringID
GetShipEngineInfoString(const Engine
*e
)
251 SetDParam(0, e
->GetCost());
252 SetDParam(1, e
->GetDisplayMaxSpeed());
253 SetDParam(2, e
->GetDefaultCargoType());
254 SetDParam(3, e
->GetDisplayDefaultCapacity());
255 SetDParam(4, e
->GetRunningCost());
256 return STR_ENGINE_PREVIEW_COST_MAX_SPEED_CAP_RUNCOST
;
261 * Get a multi-line string with some technical data, describing the engine.
262 * @param engine Engine to describe.
263 * @return String describing the engine.
264 * @post \c DParam array is set up for printing the string.
266 StringID
GetEngineInfoString(EngineID engine
)
268 const Engine
*e
= Engine::Get(engine
);
272 return GetTrainEngineInfoString(e
);
275 return GetRoadVehEngineInfoString(e
);
278 return GetShipEngineInfoString(e
);
281 return GetAircraftEngineInfoString(e
);
283 default: NOT_REACHED();
289 * @param left Minimum horizontal position to use for drawing the engine
290 * @param right Maximum horizontal position to use for drawing the engine
291 * @param preferred_x Horizontal position to use for drawing the engine.
292 * @param y Vertical position to use for drawing the engine.
293 * @param engine Engine to draw.
294 * @param pal Palette to use for drawing.
296 void DrawVehicleEngine(int left
, int right
, int preferred_x
, int y
, EngineID engine
, PaletteID pal
, EngineImageType image_type
)
298 const Engine
*e
= Engine::Get(engine
);
302 DrawTrainEngine(left
, right
, preferred_x
, y
, engine
, pal
, image_type
);
306 DrawRoadVehEngine(left
, right
, preferred_x
, y
, engine
, pal
, image_type
);
310 DrawShipEngine(left
, right
, preferred_x
, y
, engine
, pal
, image_type
);
314 DrawAircraftEngine(left
, right
, preferred_x
, y
, engine
, pal
, image_type
);
317 default: NOT_REACHED();
322 * Sort all items using quick sort and given 'CompareItems' function
323 * @param el list to be sorted
324 * @param compare function for evaluation of the quicksort
326 void EngList_Sort(GUIEngineList
*el
, EngList_SortTypeFunction compare
)
328 uint size
= el
->Length();
329 /* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems)
330 * generally, do not sort if there are less than 2 items */
331 if (size
< 2) return;
332 QSortT(el
->Begin(), size
, compare
);
336 * Sort selected range of items (on indices @ <begin, begin+num_items-1>)
337 * @param el list to be sorted
338 * @param compare function for evaluation of the quicksort
339 * @param begin start of sorting
340 * @param num_items count of items to be sorted
342 void EngList_SortPartial(GUIEngineList
*el
, EngList_SortTypeFunction compare
, uint begin
, uint num_items
)
344 if (num_items
< 2) return;
345 assert(begin
< el
->Length());
346 assert(begin
+ num_items
<= el
->Length());
347 QSortT(el
->Get(begin
), num_items
, compare
);