OpenTTD Source 20241224-master-gf74b0cf984
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 "blitter/factory.hpp"
13#include "error_func.h"
14
15#if defined(WITH_FREETYPE) || defined(WITH_UNISCRIBE) || defined(WITH_COCOA)
16
18#include "error.h"
19#include "fontcache.h"
20#include "gfx_func.h"
21#include "network/network.h"
23#include "openttd.h"
24#include "strings_func.h"
26#include "window_func.h"
27
29
30#include "table/strings.h"
31
32#include "safeguards.h"
33
35static constexpr NWidgetPart _background_widgets[] = {
36 NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1),
38};
39
44 WDP_MANUAL, nullptr, 0, 0,
48);
49
52public:
54 {
55 this->InitNested(0);
57 ResizeWindow(this, _screen.width, _screen.height);
58 }
59
60 void DrawWidget(const Rect &r, WidgetID) const override
61 {
62 GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE);
63 GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER);
64 }
65};
66
70 NWidget(WWT_CAPTION, COLOUR_GREY, WID_BEM_CAPTION), SetDataTip(STR_MISSING_GRAPHICS_ERROR_TITLE, STR_NULL),
74 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BEM_QUIT), SetDataTip(STR_MISSING_GRAPHICS_ERROR_QUIT, STR_NULL), SetFill(1, 0),
76};
77
80 WDP_CENTER, nullptr, 0, 0,
84);
85
88public:
90 {
91 this->InitNested(1);
92 }
93
94 void Close([[maybe_unused]] int data = 0) override
95 {
96 _exit_game = true;
97 this->Window::Close();
98 }
99
101 {
102 if (widget == WID_BEM_MESSAGE) {
106 }
107 }
108
109 void DrawWidget(const Rect &r, WidgetID widget) const override
110 {
111 if (widget == WID_BEM_MESSAGE) {
113 }
114 }
115
116 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
117 {
118 if (widget == WID_BEM_QUIT) {
119 _exit_game = true;
120 }
121 }
122};
123
126 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
127 NWidget(WWT_PANEL, COLOUR_GREY),
129 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_BAR), SetFill(1, 0),
130 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_NCDS_PROGRESS_TEXT), SetFill(1, 0), SetMinimalSize(350, 0),
131 EndContainer(),
132 EndContainer(),
133};
134
137 WDP_CENTER, nullptr, 0, 0,
141);
142
143
146public:
151
152 void Close([[maybe_unused]] int data = 0) override
153 {
154 /* If we are not set to exit the game, it means the bootstrap failed. */
155 if (!_exit_game) {
157 }
159 }
160
162 {
163 /* We have completed downloading. We can trigger finding the right set now. */
165
166 /* And continue going into the menu. */
167 _game_mode = GM_MENU;
168
169 /* _exit_game is used to break out of the outer video driver's MainLoop. */
170 _exit_game = true;
171 this->Close();
172 }
173};
174
178 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
179 EndContainer(),
182 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_YES), SetDataTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD, STR_NULL),
183 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_NO), SetDataTip(STR_MISSING_GRAPHICS_NO_QUIT, STR_NULL),
184 EndContainer(),
185};
186
189 WDP_CENTER, nullptr, 0, 0,
193);
194
198
199public:
206
208 void Close([[maybe_unused]] int data = 0) override
209 {
211 this->Window::Close();
212 }
213
215 {
216 /* We cache the button size. This is safe as no reinit can happen here. */
217 if (this->button_size.width == 0) {
219 this->button_size.width += WidgetDimensions::scaled.frametext.Horizontal();
220 this->button_size.height += WidgetDimensions::scaled.frametext.Vertical();
221 }
222
223 switch (widget) {
225 /* The question is twice as wide as the buttons, and determine the height based on the width. */
226 size.width = this->button_size.width * 2;
228 break;
229
230 case WID_BAFD_YES:
231 case WID_BAFD_NO:
232 size = this->button_size;
233 break;
234 }
235 }
236
237 void DrawWidget(const Rect &r, WidgetID widget) const override
238 {
239 if (widget != WID_BAFD_QUESTION) return;
240
242 }
243
244 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
245 {
246 switch (widget) {
247 case WID_BAFD_YES:
248 /* We got permission to connect! Yay! */
250 break;
251
252 case WID_BAFD_NO:
253 _exit_game = true;
254 break;
255
256 default:
257 break;
258 }
259 }
260
261 void OnConnect(bool success) override
262 {
263 if (!success) {
264 UserError("Failed to connect to content server. Please acquire a graphics set for OpenTTD. See section 1.4 of README.md.");
265 /* _exit_game is used to break out of the outer video driver's MainLoop. */
266 _exit_game = true;
267 this->Close();
268 return;
269 }
270
271 /* Once connected, request the metadata. */
273 }
274
275 void OnReceiveContentInfo(const ContentInfo *ci) override
276 {
277 /* And once the meta data is received, start downloading it. */
280 this->Close();
281 }
282};
283
284#endif /* defined(WITH_FREETYPE) */
285
286#if defined(__EMSCRIPTEN__)
287# include <emscripten.h>
288# include "network/network.h"
290# include "openttd.h"
291# include "video/video_driver.hpp"
292
293class BootstrapEmscripten : public ContentCallback {
294 bool downloading = false;
295 uint total_files = 0;
296 uint total_bytes = 0;
297 uint downloaded_bytes = 0;
298
299public:
300 BootstrapEmscripten()
301 {
304 }
305
306 ~BootstrapEmscripten()
307 {
309 }
310
311 void OnConnect(bool success) override
312 {
313 if (!success) {
314 EM_ASM({ if (window["openttd_bootstrap_failed"]) openttd_bootstrap_failed(); });
315 return;
316 }
317
318 /* Once connected, request the metadata. */
320 }
321
322 void OnReceiveContentInfo(const ContentInfo *ci) override
323 {
324 if (this->downloading) return;
325
326 /* And once the metadata is received, start downloading it. */
328 _network_content_client.DownloadSelectedContent(this->total_files, this->total_bytes);
329 this->downloading = true;
330
331 EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
332 }
333
334 void OnDownloadProgress(const ContentInfo *, int bytes) override
335 {
336 /* A negative value means we are resetting; for example, when retrying or using a fallback. */
337 if (bytes < 0) {
338 this->downloaded_bytes = 0;
339 } else {
340 this->downloaded_bytes += bytes;
341 }
342
343 EM_ASM({ if (window["openttd_bootstrap"]) openttd_bootstrap($0, $1); }, this->downloaded_bytes, this->total_bytes);
344 }
345
346 void OnDownloadComplete(ContentID) override
347 {
348 /* _exit_game is used to break out of the outer video driver's MainLoop. */
349 _exit_game = true;
350
351 delete this;
352 }
353};
354#endif /* __EMSCRIPTEN__ */
355
363{
364 if (BaseGraphics::GetUsedSet() != nullptr) return true;
365
366 /* No user interface, bail out with an error. */
367 if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
368
369 /* If there is no network or no non-sprite font, then there is nothing we can do. Go straight to failure. */
370#if defined(__EMSCRIPTEN__) || (defined(_WIN32) && defined(WITH_UNISCRIBE)) || (defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(__APPLE__))) || defined(WITH_COCOA)
371 if (!_network_available) goto failure;
372
373 /* First tell the game we're bootstrapping. */
374 _game_mode = GM_BOOTSTRAP;
375
376#if defined(__EMSCRIPTEN__)
377 new BootstrapEmscripten();
378#else
379 /* Initialise the font cache. */
381 /* Next "force" finding a suitable non-sprite font as the local font is missing. */
383
384 /* Initialise the palette. The biggest step is 'faking' some recolour sprites.
385 * This way the mauve and gray colours work and we can show the user interface. */
386 GfxInitPalettes();
387 static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
388 for (Colours i = COLOUR_BEGIN; i != COLOUR_END; i++) {
389 for (ColourShade j = SHADE_BEGIN; j < SHADE_END; j++) {
390 SetColourGradient(i, j, offsets[i] + j);
391 }
392 }
393
394 /* Finally ask the question. */
397#endif /* __EMSCRIPTEN__ */
398
399 /* Process the user events. */
401
402 /* _exit_game is used to get out of the video driver's main loop.
403 * In case GM_BOOTSTRAP is still set we did not exit it via the
404 * "download complete" event, so it was a manual exit. Obey it. */
405 _exit_game = _game_mode == GM_BOOTSTRAP;
406 if (_exit_game) return false;
407
408 /* Try to probe the graphics. Should work this time. */
409 if (!BaseGraphics::SetSet({})) goto failure;
410
411 /* Finally we can continue heading for the menu. */
412 _game_mode = GM_MENU;
413 return true;
414#endif
415
416 /* Failure to get enough working to get a graphics set. */
417failure:
418 UserError("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 1.4 of README.md.");
419 return false;
420}
Generic functions for replacing base data (graphics, sounds).
#define CLRBITS(x, y)
Clears several bits in a variable.
static constexpr NWidgetPart _background_widgets[]
Widgets for the background window to prevent smearing.
static WindowDesc _bootstrap_download_status_window_desc(WDP_CENTER, nullptr, 0, 0, WC_NETWORK_STATUS_WINDOW, WC_NONE, WDF_MODAL|WDF_NO_CLOSE, _nested_bootstrap_download_status_window_widgets)
Window description for the download window.
static constexpr NWidgetPart _bootstrap_query_widgets[]
The widgets for the query.
static constexpr NWidgetPart _nested_bootstrap_errmsg_widgets[]
Nested widgets for the error window.
static WindowDesc _bootstrap_errmsg_desc(WDP_CENTER, nullptr, 0, 0, WC_BOOTSTRAP, WC_NONE, WDF_MODAL|WDF_NO_CLOSE, _nested_bootstrap_errmsg_widgets)
Window description for the error window.
static WindowDesc _background_desc(WDP_MANUAL, nullptr, 0, 0, WC_BOOTSTRAP, WC_NONE, WDF_NO_CLOSE, _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 WindowDesc _bootstrap_query_desc(WDP_CENTER, nullptr, 0, 0, WC_CONFIRM_POPUP_QUERY, WC_NONE, WDF_NO_CLOSE, _bootstrap_query_widgets)
The window description for the query.
static constexpr NWidgetPart _nested_bootstrap_download_status_window_widgets[]
Nested widgets for the download 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.
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:138
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:43
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:28
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:96
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:704
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:851
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:114
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:774
Functions related to the gfx engine.
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:353
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
Definition gfx_type.h:299
@ FILLRECT_OPAQUE
Fill rectangle with a single colour.
Definition gfx_type.h:298
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 SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data 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:67
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:325
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:2291
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 OnDownloadComplete(ContentID cid)
We have finished downloading a file.
virtual void OnConnect(bool success)
Callback for when the connection has finished.
virtual void OnReceiveContentInfo(const ContentInfo *ci)
We received a content info.
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:159
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:1047
ResizeInfo resize
Resize information.
Definition window_gui.h:314
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:977
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1746
WindowFlags flags
Window flags.
Definition window_gui.h:300
@ CONTENT_TYPE_BASE_GRAPHICS
The content consists of base graphics.
ContentID
Unique identifier for the content.
Base of all video drivers.
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:75
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:50
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:61
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:77
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:48
void ResizeWindow(Window *w, int delta_x, int delta_y, bool clamp_to_screen, bool schedule_resize)
Resize the window.
Definition window.cpp:2022
Window functions not directly related to making/drawing windows.
@ WF_WHITE_BORDER
Window white border counter bit mask.
Definition window_gui.h:236
@ WDF_NO_CLOSE
This window can't be interactively closed.
Definition window_gui.h:206
@ WDF_MODAL
The window is a modal child of some other window, meaning the parent is 'inactive'.
Definition window_gui.h:204
@ WDP_CENTER
Center the window.
Definition window_gui.h:148
@ WDP_MANUAL
Manually align the window (so no automatic location finding)
Definition window_gui.h:146
int WidgetID
Widget ID.
Definition window_type.h:18
@ WN_CONFIRM_POPUP_QUERY_BOOTSTRAP
Query popup confirm for bootstrap.
Definition window_type.h:33
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:45
@ WC_CONFIRM_POPUP_QUERY
Popup with confirm question; Window numbers:
@ WC_BOOTSTRAP
Bootstrap; Window numbers:
@ WC_NETWORK_STATUS_WINDOW
Network status window; Window numbers: