OpenTTD Source 20250524-master-gc366e6a48e
bootstrap_gui.cpp
Go to the documentation of this file.
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 */
7
10#include "stdafx.h"
11#include "base_media_base.h"
12#include "base_media_graphics.h"
13#include "blitter/factory.hpp"
14#include "error_func.h"
15
16#if defined(WITH_FREETYPE) || defined(WITH_UNISCRIBE) || defined(WITH_COCOA)
17
19#include "error.h"
20#include "fontcache.h"
21#include "gfx_func.h"
22#include "network/network.h"
24#include "openttd.h"
25#include "strings_func.h"
27#include "window_func.h"
28
30
31#include "table/strings.h"
32
33#include "safeguards.h"
34
36static constexpr NWidgetPart _background_widgets[] = {
37 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1),
39};
40
45 WDP_MANUAL, {}, 0, 0,
49);
50
53public:
55 {
56 this->InitNested(0);
58 ResizeWindow(this, _screen.width, _screen.height);
59 }
60
61 void DrawWidget(const Rect &r, WidgetID) const override
62 {
63 GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE);
64 GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER);
65 }
66};
67
71 NWidget(WWT_CAPTION, COLOUR_GREY, WID_BEM_CAPTION), SetStringTip(STR_MISSING_GRAPHICS_ERROR_TITLE),
75 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BEM_QUIT), SetStringTip(STR_MISSING_GRAPHICS_ERROR_QUIT), SetFill(1, 0),
77};
78
81 WDP_CENTER, {}, 0, 0,
85);
86
89public:
91 {
92 this->InitNested(1);
93 }
94
95 void Close([[maybe_unused]] int data = 0) override
96 {
97 _exit_game = true;
98 this->Window::Close();
99 }
100
101 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
102 {
103 if (widget == WID_BEM_MESSAGE) {
104 size = GetStringBoundingBox(STR_MISSING_GRAPHICS_ERROR);
107 }
108 }
109
110 void DrawWidget(const Rect &r, WidgetID widget) const override
111 {
112 if (widget == WID_BEM_MESSAGE) {
113 DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_ERROR, TC_FROMSTRING, SA_CENTER);
114 }
115 }
116
117 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
118 {
119 if (widget == WID_BEM_QUIT) {
120 _exit_game = true;
121 }
122 }
123};
124
127 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
128 NWidget(WWT_PANEL, COLOUR_GREY),
130 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_BAR), SetFill(1, 0),
131 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
132 EndContainer(),
133 EndContainer(),
134};
135
138 WDP_CENTER, {}, 0, 0,
142);
143
144
147public:
152
153 void Close([[maybe_unused]] int data = 0) override
154 {
155 /* If we are not set to exit the game, it means the bootstrap failed. */
156 if (!_exit_game) {
158 }
160 }
161
163 {
164 /* We have completed downloading. We can trigger finding the right set now. */
166
167 /* And continue going into the menu. */
168 _game_mode = GM_MENU;
169
170 /* _exit_game is used to break out of the outer video driver's MainLoop. */
171 _exit_game = true;
172 this->Close();
173 }
174};
175
179 NWidget(WWT_CAPTION, COLOUR_GREY), SetStringTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
180 EndContainer(),
183 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_YES), SetStringTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD),
184 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_NO), SetStringTip(STR_MISSING_GRAPHICS_NO_QUIT),
185 EndContainer(),
186};
187
190 WDP_CENTER, {}, 0, 0,
194);
195
199
200public:
207
209 void Close([[maybe_unused]] int data = 0) override
210 {
212 this->Window::Close();
213 }
214
215 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
216 {
217 /* We cache the button size. This is safe as no reinit can happen here. */
218 if (this->button_size.width == 0) {
219 this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT));
222 }
223
224 switch (widget) {
226 /* The question is twice as wide as the buttons, and determine the height based on the width. */
227 size.width = this->button_size.width * 2;
228 size.height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size.width - WidgetDimensions::scaled.frametext.Horizontal()) + WidgetDimensions::scaled.frametext.Vertical();
229 break;
230
231 case WID_BAFD_YES:
232 case WID_BAFD_NO:
233 size = this->button_size;
234 break;
235 }
236 }
237
238 void DrawWidget(const Rect &r, WidgetID widget) const override
239 {
240 if (widget != WID_BAFD_QUESTION) return;
241
242 DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.frametext), STR_MISSING_GRAPHICS_SET_MESSAGE, TC_FROMSTRING, SA_CENTER);
243 }
244
245 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
246 {
247 switch (widget) {
248 case WID_BAFD_YES:
249 /* We got permission to connect! Yay! */
251 break;
252
253 case WID_BAFD_NO:
254 _exit_game = true;
255 break;
256
257 default:
258 break;
259 }
260 }
261
262 void OnConnect(bool success) override
263 {
264 if (!success) {
265 UserError("Failed to connect to content server. Please acquire a graphics set for OpenTTD. See section 1.4 of README.md.");
266 /* _exit_game is used to break out of the outer video driver's MainLoop. */
267 _exit_game = true;
268 this->Close();
269 return;
270 }
271
272 /* Once connected, request the metadata. */
274 }
275
276 void OnReceiveContentInfo(const ContentInfo &ci) override
277 {
278 /* And once the meta data is received, start downloading it. */
281 this->Close();
282 }
283};
284
285#endif /* defined(WITH_FREETYPE) */
286
287#if defined(__EMSCRIPTEN__)
288# include <emscripten.h>
289# include "network/network.h"
291# include "openttd.h"
292# include "video/video_driver.hpp"
293
294class BootstrapEmscripten : public ContentCallback {
295 bool downloading = false;
296 uint total_files = 0;
297 uint total_bytes = 0;
298 uint downloaded_bytes = 0;
299
300public:
301 BootstrapEmscripten()
302 {
305 }
306
307 ~BootstrapEmscripten()
308 {
310 }
311
312 void OnConnect(bool success) override
313 {
314 if (!success) {
315 EM_ASM({ if (window["openttd_bootstrap_failed"]) openttd_bootstrap_failed(); });
316 return;
317 }
318
319 /* Once connected, request the metadata. */
321 }
322
323 void OnReceiveContentInfo(const ContentInfo &ci) override
324 {
325 if (this->downloading) return;
326
327 /* And once the metadata is received, start downloading it. */
329 _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
330 this->downloading = true;
331
332 EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
333 }
334
335 void OnDownloadProgress(const ContentInfo &, int bytes) override
336 {
337 /* A negative value means we are resetting; for example, when retrying or using a fallback. */
338 if (bytes < 0) {
339 this->downloaded_bytes = 0;
340 } else {
341 this->downloaded_bytes += bytes;
342 }
343
344 EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
345 }
346
347 void OnDownloadComplete(ContentID) override
348 {
349 /* _exit_game is used to break out of the outer video driver's MainLoop. */
350 _exit_game = true;
351
352 delete this;
353 }
354};
355#endif /* __EMSCRIPTEN__ */
356
364{
365 if (BaseGraphics::GetUsedSet() != nullptr) return true;
366
367 /* No user interface, bail out with an error. */
368 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
369
370 /* If there is no network or no non-sprite font, then there is nothing we can do. Go straight to failure. */
371#if defined(__EMSCRIPTEN__) || (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA)
372 if (!_network_available) goto failure;
373
374 /* First tell the game we're bootstrapping. */
375 _game_mode = GM_BOOTSTRAP;
376
377#if defined(__EMSCRIPTEN__)
378 new BootstrapEmscripten();
379#else
380 /* Initialise the font cache. */
382 /* Next "force" finding a suitable non-sprite font as the local font is missing. */
384
385 /* Initialise the palette. The biggest step is 'faking' some recolour sprites.
386 * This way the mauve and gray colours work and we can show the user interface. */
387 GfxInitPalettes();
388 static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
389 for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
390 for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
391 SetColourGradient(i, j, offsets[i] + j);
392 }
393 }
394
395 /* Finally ask the question. */
398#endif /* __EMSCRIPTEN__ */
399
400 /* Process the user events. */
402
403 /* _exit_game is used to get out of the video driver's main loop.
404 * In case GM_BOOTSTRAP is still set we did not exit it via the
405 * "download complete" event, so it was a manual exit. Obey it. */
406 _exit_game = _game_mode == GM_BOOTSTRAP;
407 if (_exit_game) return false;
408
409 /* Try to probe the graphics. Should work this time. */
410 if (!BaseGraphics::SetSet(nullptr)) goto failure;
411
412 /* Finally we can continue heading for the menu. */
413 _game_mode = GM_MENU;
414 return true;
415#endif
416
417 /* Failure to get enough working to get a graphics set. */
418failure:
419 UserError("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 1.4 of README.md.");
420 return false;
421}
Generic functions for replacing base data (graphics, sounds).
Generic functions for replacing base graphics data.
static constexpr NWidgetPart _background_widgets[]
Widgets for the background window to prevent smearing.
static constexpr NWidgetPart _bootstrap_query_widgets[]
The widgets for the query.
static WindowDesc _bootstrap_query_desc(WDP_CENTER, {}, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, WindowDefaultFlag::NoClose, _bootstrap_query_widgets)
The window description for the query.
static WindowDesc _bootstrap_download_status_window_desc(WDP_CENTER, {}, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, {WindowDefaultFlag::Modal, WindowDefaultFlag::NoClose}, _nested_bootstrap_download_status_window_widgets)
Window description for the download window.
static constexpr NWidgetPart _nested_bootstrap_errmsg_widgets[]
Nested widgets for the error window.
static WindowDesc _background_desc(WDP_MANUAL, {}, 0, 0, WC_BOOTSTRAP, WC_NONE, WindowDefaultFlag::NoClose, _background_widgets)
Window description for the background window to prevent smearing.
bool HandleBootstrap()
Handle all procedures for bootstrapping OpenTTD without a base graphics set.
static constexpr NWidgetPart _nested_bootstrap_download_status_window_widgets[]
Nested widgets for the download window.
static WindowDesc _bootstrap_errmsg_desc(WDP_CENTER, {}, 0, 0, WC_BOOTSTRAP, WC_NONE, {WindowDefaultFlag::Modal, WindowDefaultFlag::NoClose}, _nested_bootstrap_errmsg_widgets)
Window description for the error window.
Types related to the bootstrap widgets.
@ WID_BAFD_QUESTION
The question whether to download.
@ WID_BAFD_NO
An negative answer to the question.
@ WID_BAFD_YES
An affirmative answer to the question.
@ WID_BB_BACKGROUND
Background of the window.
@ WID_BEM_MESSAGE
Error message.
@ WID_BEM_QUIT
Quit button.
@ WID_BEM_CAPTION
Caption of the window.
constexpr Timpl & Reset()
Reset all bits.
static const GraphicsSet * GetUsedSet()
Return the used set.
static uint FindSets()
Do the scan for files.
static bool SetSet(const GraphicsSet *set)
Set the set to be used.
Base window for showing the download status of content.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:136
The window for the query.
void OnConnect(bool success) override
Callback for when the connection has finished.
Dimension button_size
The dimension of the button.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnReceiveContentInfo(const ContentInfo &ci) override
We received a content info.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void Close(int data=0) override
Stop listening to the content client events.
BootstrapAskForDownloadWindow()
Start listening to the content client events.
The background for the game.
void DrawWidget(const Rect &r, WidgetID) const override
Draw the contents of a nested widget.
The window for a failed bootstrap.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void DownloadSelectedContent(uint &files, uint &bytes, bool fallback=false)
Actually begin downloading the content we selected.
void RemoveCallback(ContentCallback *cb)
Remove a callback.
void Select(ContentID cid)
Select a specific content id.
void RequestContentList(ContentType type)
Request the content list for the given type.
void AddCallback(ContentCallback *cb)
Add a callback to this class.
void Connect()
Connect with the content server.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
virtual void MainLoop()=0
Perform the actual drawing.
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:41
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
Functions related to errors.
Error reporting related functions.
Factory to 'query' all available blitters.
Functions to read fonts from files and cache them.
void InitializeUnicodeGlyphMap()
Initialize the glyph map.
Definition fontcache.h:158
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:705
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:887
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:115
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:775
Functions related to the gfx engine.
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:393
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:341
@ FILLRECT_OPAQUE
Fill rectangle with a single colour.
Definition gfx_type.h:340
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
bool _network_available
is network mode available?
Definition network.cpp:69
Basic functions/variables used all over the place.
ClientNetworkContentSocketHandler _network_content_client
The client we use to connect to the server.
Part of the network protocol handling content distribution.
User interface for downloading files.
@ WID_NCDS_PROGRESS_TEXT
Text explaining what is happening.
@ WID_NCDS_PROGRESS_BAR
Simple progress bar.
Some generic types.
void SetColourGradient(Colours colour, ColourShade shade, uint8_t palette_index)
Set colour gradient palette index.
Definition palette.cpp:399
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
void CheckForMissingGlyphs(bool base_font, MissingGlyphSearcher *searcher)
Check whether the currently loaded language pack uses characters that the currently loaded font does ...
Definition strings.cpp:2353
Functions related to OTTD's strings.
Window for showing the download status of content.
BootstrapContentDownloadStatusWindow()
Simple call the constructor of the superclass.
void OnDownloadComplete(ContentID) override
We have finished downloading a file.
void Close(int data=0) override
Hide the window and all its child windows, and mark them for a later deletion.
Callbacks for notifying others about incoming data.
virtual void OnDownloadProgress(const ContentInfo &ci, int bytes)
We have progress in the download of a file.
virtual void OnReceiveContentInfo(const ContentInfo &ci)
We received a content info.
virtual void OnDownloadComplete(ContentID cid)
We have finished downloading a file.
virtual void OnConnect(bool success)
Callback for when the connection has finished.
Container for all important information about a piece of content.
ContentID id
Unique (server side) ID for the content.
Dimensions (a width and height) of a rectangle in 2D.
Partial widget specification to allow NWidgets to be written nested.
Coordinates of a point in 2D.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
High level window description.
Definition window_gui.h:167
Data structure for an opened window.
Definition window_gui.h:273
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1091
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1791
WindowFlags flags
Window flags.
Definition window_gui.h:300
uint32_t ContentID
Unique identifier for the content.
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
Base of all video drivers.
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:67
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:53
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:69
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition window.cpp:2067
Window functions not directly related to making/drawing windows.
@ NoClose
This window can't be interactively closed.
@ Modal
The window is a modal child of some other window, meaning the parent is 'inactive'.
@ WhiteBorder
Window white border counter bit mask.
@ WDP_CENTER
Center the window.
Definition window_gui.h:145
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
Definition window_gui.h:143
int WidgetID
Widget ID.
Definition window_type.h:20
@ WN_CONFIRM_POPUP_QUERY_BOOTSTRAP
Query popup confirm for bootstrap.
Definition window_type.h:35
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:47
@ WC_CONFIRM_POPUP_QUERY
Popup with confirm question; Window numbers:
@ WC_BOOTSTRAP
Bootstrap; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers: