Codefix: Documentation comment in IndustryDirectoryWindow (#13059)
[openttd-github.git] / src / engine_gui.cpp
blob7145b85c5001491dd634c141ecfa42cd7ca7ee82
1 /*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
8 /** @file engine_gui.cpp GUI to show engine related information. */
10 #include "stdafx.h"
11 #include "window_gui.h"
12 #include "engine_base.h"
13 #include "command_func.h"
14 #include "strings_func.h"
15 #include "engine_gui.h"
16 #include "articulated_vehicles.h"
17 #include "vehicle_func.h"
18 #include "company_func.h"
19 #include "rail.h"
20 #include "road.h"
21 #include "settings_type.h"
22 #include "train.h"
23 #include "roadveh.h"
24 #include "ship.h"
25 #include "aircraft.h"
26 #include "engine_cmd.h"
27 #include "zoom_func.h"
29 #include "widgets/engine_widget.h"
31 #include "table/strings.h"
33 #include "safeguards.h"
35 /**
36 * Return the category of an engine.
37 * @param engine Engine to examine.
38 * @return String describing the category ("road veh", "train". "airplane", or "ship") of the engine.
40 StringID GetEngineCategoryName(EngineID engine)
42 const Engine *e = Engine::Get(engine);
43 switch (e->type) {
44 default: NOT_REACHED();
45 case VEH_ROAD:
46 return GetRoadTypeInfo(e->u.road.roadtype)->strings.new_engine;
47 case VEH_AIRCRAFT: return STR_ENGINE_PREVIEW_AIRCRAFT;
48 case VEH_SHIP: return STR_ENGINE_PREVIEW_SHIP;
49 case VEH_TRAIN:
50 return GetRailTypeInfo(e->u.rail.railtype)->strings.new_loco;
54 static constexpr NWidgetPart _nested_engine_preview_widgets[] = {
55 NWidget(NWID_HORIZONTAL),
56 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
57 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE), SetDataTip(STR_ENGINE_PREVIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
58 EndContainer(),
59 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
60 NWidget(NWID_VERTICAL), SetPIP(0, WidgetDimensions::unscaled.vsep_wide, 0), SetPadding(WidgetDimensions::unscaled.modalpopup),
61 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_EP_QUESTION), SetMinimalSize(300, 0), SetFill(1, 0),
62 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(85, WidgetDimensions::unscaled.hsep_wide, 85),
63 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_EP_NO), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
64 NWidget(WWT_PUSHTXTBTN, COLOUR_LIGHT_BLUE, WID_EP_YES), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
65 EndContainer(),
66 EndContainer(),
67 EndContainer(),
70 struct EnginePreviewWindow : Window {
71 int vehicle_space; // The space to show the vehicle image
73 EnginePreviewWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
75 this->InitNested(window_number);
77 /* There is no way to recover the window; so disallow closure via DEL; unless SHIFT+DEL */
78 this->flags |= WF_STICKY;
81 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
83 if (widget != WID_EP_QUESTION) return;
85 /* Get size of engine sprite, on loan from depot_gui.cpp */
86 EngineID engine = this->window_number;
87 EngineImageType image_type = EIT_PURCHASE;
88 uint x, y;
89 int x_offs, y_offs;
91 const Engine *e = Engine::Get(engine);
92 switch (e->type) {
93 default: NOT_REACHED();
94 case VEH_TRAIN: GetTrainSpriteSize( engine, x, y, x_offs, y_offs, image_type); break;
95 case VEH_ROAD: GetRoadVehSpriteSize( engine, x, y, x_offs, y_offs, image_type); break;
96 case VEH_SHIP: GetShipSpriteSize( engine, x, y, x_offs, y_offs, image_type); break;
97 case VEH_AIRCRAFT: GetAircraftSpriteSize(engine, x, y, x_offs, y_offs, image_type); break;
99 this->vehicle_space = std::max<int>(ScaleSpriteTrad(40), y - y_offs);
101 size.width = std::max(size.width, x + std::abs(x_offs));
102 SetDParam(0, GetEngineCategoryName(engine));
103 size.height = GetStringHeight(STR_ENGINE_PREVIEW_MESSAGE, size.width) + WidgetDimensions::scaled.vsep_wide + GetCharacterHeight(FS_NORMAL) + this->vehicle_space;
104 SetDParam(0, engine);
105 size.height += GetStringHeight(GetEngineInfoString(engine), size.width);
108 void DrawWidget(const Rect &r, WidgetID widget) const override
110 if (widget != WID_EP_QUESTION) return;
112 EngineID engine = this->window_number;
113 SetDParam(0, GetEngineCategoryName(engine));
114 int y = DrawStringMultiLine(r, STR_ENGINE_PREVIEW_MESSAGE, TC_FROMSTRING, SA_HOR_CENTER | SA_TOP) + WidgetDimensions::scaled.vsep_wide;
116 SetDParam(0, PackEngineNameDParam(engine, EngineNameContext::PreviewNews));
117 DrawString(r.left, r.right, y, STR_ENGINE_NAME, TC_BLACK, SA_HOR_CENTER);
118 y += GetCharacterHeight(FS_NORMAL);
120 DrawVehicleEngine(r.left, r.right, this->width >> 1, y + this->vehicle_space / 2, engine, GetEnginePalette(engine, _local_company), EIT_PREVIEW);
122 y += this->vehicle_space;
123 DrawStringMultiLine(r.left, r.right, y, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER);
126 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
128 switch (widget) {
129 case WID_EP_YES:
130 Command<CMD_WANT_ENGINE_PREVIEW>::Post(this->window_number);
131 [[fallthrough]];
132 case WID_EP_NO:
133 if (!_shift_pressed) this->Close();
134 break;
138 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
140 if (!gui_scope) return;
142 EngineID engine = this->window_number;
143 if (Engine::Get(engine)->preview_company != _local_company) this->Close();
147 static WindowDesc _engine_preview_desc(
148 WDP_CENTER, nullptr, 0, 0,
149 WC_ENGINE_PREVIEW, WC_NONE,
150 WDF_CONSTRUCTION,
151 _nested_engine_preview_widgets
155 void ShowEnginePreviewWindow(EngineID engine)
157 AllocateWindowDescFront<EnginePreviewWindow>(_engine_preview_desc, engine);
161 * Get the capacity of an engine with articulated parts.
162 * @param engine The engine to get the capacity of.
163 * @return The capacity.
165 uint GetTotalCapacityOfArticulatedParts(EngineID engine)
167 CargoArray cap = GetCapacityOfArticulatedParts(engine);
168 return cap.GetSum<uint>();
171 static StringID GetTrainEngineInfoString(const Engine *e)
173 SetDParam(0, STR_ENGINE_PREVIEW_COST_WEIGHT);
174 SetDParam(1, e->GetCost());
175 SetDParam(2, e->GetDisplayWeight());
177 SetDParam(3, (_settings_game.vehicle.train_acceleration_model != AM_ORIGINAL && GetRailTypeInfo(e->u.rail.railtype)->acceleration_type != 2) ? STR_ENGINE_PREVIEW_SPEED_POWER_MAX_TE : STR_ENGINE_PREVIEW_SPEED_POWER);
178 SetDParam(4, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
179 SetDParam(5, e->GetPower());
180 SetDParam(6, e->GetDisplayMaxTractiveEffort());
182 SetDParam(7, TimerGameEconomy::UsingWallclockUnits() ? STR_ENGINE_PREVIEW_RUNCOST_PERIOD : STR_ENGINE_PREVIEW_RUNCOST_YEAR);
183 SetDParam(8, e->GetRunningCost());
185 SetDParam(9, STR_ENGINE_PREVIEW_CAPACITY);
186 uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
187 SetDParam(10, capacity != 0 ? e->GetDefaultCargoType() : INVALID_CARGO);
188 SetDParam(11, capacity);
190 return STR_ENGINE_PREVIEW_TEXT4;
193 static StringID GetAircraftEngineInfoString(const Engine *e)
195 CargoID cargo = e->GetDefaultCargoType();
196 uint16_t mail_capacity;
197 uint capacity = e->GetDisplayDefaultCapacity(&mail_capacity);
198 uint16_t range = e->GetRange();
200 SetDParam(0, STR_ENGINE_PREVIEW_COST_MAX_SPEED);
201 SetDParam(1, e->GetCost());
202 SetDParam(2, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
204 SetDParam(3, range > 0 ? STR_ENGINE_PREVIEW_TYPE_RANGE : STR_ENGINE_PREVIEW_TYPE);
205 SetDParam(4, e->GetAircraftTypeText());
206 SetDParam(5, range);
208 SetDParam(7, TimerGameEconomy::UsingWallclockUnits() ? STR_ENGINE_PREVIEW_RUNCOST_PERIOD : STR_ENGINE_PREVIEW_RUNCOST_YEAR);
209 SetDParam(8, e->GetRunningCost());
211 SetDParam(9, mail_capacity > 0 ? STR_ENGINE_PREVIEW_CAPACITY_2 : STR_ENGINE_PREVIEW_CAPACITY);
212 SetDParam(10, cargo);
213 SetDParam(11, capacity);
214 SetDParam(12, GetCargoIDByLabel(CT_MAIL));
215 SetDParam(13, mail_capacity);
217 return STR_ENGINE_PREVIEW_TEXT4;
220 static StringID GetRoadVehEngineInfoString(const Engine *e)
222 SetDParam(7, TimerGameEconomy::UsingWallclockUnits() ? STR_ENGINE_PREVIEW_RUNCOST_PERIOD : STR_ENGINE_PREVIEW_RUNCOST_YEAR);
223 SetDParam(8, e->GetRunningCost());
225 SetDParam(9, STR_ENGINE_PREVIEW_CAPACITY);
226 uint capacity = GetTotalCapacityOfArticulatedParts(e->index);
227 SetDParam(10, capacity != 0 ? e->GetDefaultCargoType() : INVALID_CARGO);
228 SetDParam(11, capacity);
230 if (_settings_game.vehicle.roadveh_acceleration_model == AM_ORIGINAL) {
231 SetDParam(0, STR_ENGINE_PREVIEW_COST_MAX_SPEED);
232 SetDParam(1, e->GetCost());
233 SetDParam(2, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
235 return STR_ENGINE_PREVIEW_TEXT3;
236 } else {
237 SetDParam(0, STR_ENGINE_PREVIEW_COST_WEIGHT);
238 SetDParam(1, e->GetCost());
239 SetDParam(2, e->GetDisplayWeight());
241 SetDParam(3, STR_ENGINE_PREVIEW_SPEED_POWER_MAX_TE);
242 SetDParam(4, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
243 SetDParam(5, e->GetPower());
244 SetDParam(6, e->GetDisplayMaxTractiveEffort());
246 return STR_ENGINE_PREVIEW_TEXT4;
250 static StringID GetShipEngineInfoString(const Engine *e)
252 SetDParam(0, STR_ENGINE_PREVIEW_COST_MAX_SPEED);
253 SetDParam(1, e->GetCost());
254 SetDParam(2, PackVelocity(e->GetDisplayMaxSpeed(), e->type));
256 SetDParam(7, TimerGameEconomy::UsingWallclockUnits() ? STR_ENGINE_PREVIEW_RUNCOST_PERIOD : STR_ENGINE_PREVIEW_RUNCOST_YEAR);
257 SetDParam(8, e->GetRunningCost());
259 SetDParam(9, STR_ENGINE_PREVIEW_CAPACITY);
260 SetDParam(10, e->GetDefaultCargoType());
261 SetDParam(11, e->GetDisplayDefaultCapacity());
263 return STR_ENGINE_PREVIEW_TEXT3;
268 * Get a multi-line string with some technical data, describing the engine.
269 * @param engine Engine to describe.
270 * @return String describing the engine.
271 * @post \c DParam array is set up for printing the string.
273 StringID GetEngineInfoString(EngineID engine)
275 const Engine *e = Engine::Get(engine);
277 switch (e->type) {
278 case VEH_TRAIN:
279 return GetTrainEngineInfoString(e);
281 case VEH_ROAD:
282 return GetRoadVehEngineInfoString(e);
284 case VEH_SHIP:
285 return GetShipEngineInfoString(e);
287 case VEH_AIRCRAFT:
288 return GetAircraftEngineInfoString(e);
290 default: NOT_REACHED();
295 * Draw an engine.
296 * @param left Minimum horizontal position to use for drawing the engine
297 * @param right Maximum horizontal position to use for drawing the engine
298 * @param preferred_x Horizontal position to use for drawing the engine.
299 * @param y Vertical position to use for drawing the engine.
300 * @param engine Engine to draw.
301 * @param pal Palette to use for drawing.
303 void DrawVehicleEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type)
305 const Engine *e = Engine::Get(engine);
307 switch (e->type) {
308 case VEH_TRAIN:
309 DrawTrainEngine(left, right, preferred_x, y, engine, pal, image_type);
310 break;
312 case VEH_ROAD:
313 DrawRoadVehEngine(left, right, preferred_x, y, engine, pal, image_type);
314 break;
316 case VEH_SHIP:
317 DrawShipEngine(left, right, preferred_x, y, engine, pal, image_type);
318 break;
320 case VEH_AIRCRAFT:
321 DrawAircraftEngine(left, right, preferred_x, y, engine, pal, image_type);
322 break;
324 default: NOT_REACHED();
329 * Sort all items using quick sort and given 'CompareItems' function
330 * @param el list to be sorted
331 * @param compare function for evaluation of the quicksort
333 void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare)
335 if (el.size() < 2) return;
336 std::sort(el.begin(), el.end(), compare);
340 * Sort selected range of items (on indices @ <begin, begin+num_items-1>)
341 * @param el list to be sorted
342 * @param compare function for evaluation of the quicksort
343 * @param begin start of sorting
344 * @param num_items count of items to be sorted
346 void EngList_SortPartial(GUIEngineList &el, EngList_SortTypeFunction compare, size_t begin, size_t num_items)
348 if (num_items < 2) return;
349 assert(begin < el.size());
350 assert(begin + num_items <= el.size());
351 std::sort(el.begin() + begin, el.begin() + begin + num_items, compare);