OpenTTD Source 20260206-master-g4d4e37dbf1
help_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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "gui.h"
12#include "window_gui.h"
13#include "textfile_gui.h"
14#include "fileio_func.h"
15#include "table/control_codes.h"
16#include "string_func.h"
17#include "openttd.h"
18#include "help_gui.h"
19
20#include "widgets/help_widget.h"
21#include "widgets/misc_widget.h"
22
23#include "table/strings.h"
24
25#include "safeguards.h"
26
27static const std::string README_FILENAME = "README.md";
28static const std::string CHANGELOG_FILENAME = "changelog.md";
29static const std::string KNOWN_BUGS_FILENAME = "known-bugs.md";
30static const std::string LICENSE_FILENAME = "COPYING.md";
31static const std::string FONTS_FILENAME = "fonts.md";
32
33static const std::string WEBSITE_LINK = "https://www.openttd.org/";
34static const std::string WIKI_LINK = "https://wiki.openttd.org/";
35static const std::string BUGTRACKER_LINK = "https://bugs.openttd.org/";
36static const std::string COMMUNITY_LINK = "https://community.openttd.org/";
37
39static constexpr size_t CHANGELOG_VERSIONS_LIMIT = 20;
40
48static std::optional<std::string> FindGameManualFilePath(std::string_view filename, Subdirectory subdir)
49{
50 static const Searchpath searchpaths[] = {
52 };
53
54 for (Searchpath sp : searchpaths) {
55 std::string file_path = FioGetDirectory(sp, subdir);
56 file_path.append(filename);
57 if (FioCheckFileExists(file_path, NO_DIRECTORY)) return file_path;
58 }
59
60 return {};
61}
62
64struct GameManualTextfileWindow : public TextfileWindow {
65 GameManualTextfileWindow(std::string_view filename, Subdirectory subdir) : TextfileWindow(nullptr, TFT_GAME_MANUAL)
66 {
67 this->ConstructWindow();
68
69 /* Mark the content of these files as trusted. */
70 this->trusted = true;
71
73 /* The user could, in theory, have moved the file. So just show an empty window if that is the case. */
74 if (!filepath.has_value()) {
75 return;
76 }
77
78 this->filepath = filepath.value();
80 this->OnClick({ 0, 0 }, WID_TF_WRAPTEXT, 1);
81 }
82
83 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
84 {
85 if (widget == WID_TF_CAPTION) {
86 return GetString(stringid, this->filename);
87 }
88
89 return this->Window::GetWidgetString(widget, stringid);
90 }
91
92 void AfterLoadText() override
93 {
94 if (this->filename == CHANGELOG_FILENAME) {
95 this->link_anchors.clear();
96 this->AfterLoadChangelog();
97 }
99 }
100
107 {
108 uint versions = 0;
109
110 /* Look for lines beginning with ###, they indicate a release name. */
111 for (size_t line_index = 0; line_index < this->lines.size(); ++line_index) {
112 const Line &line = this->lines[line_index];
113 if (!line.text.starts_with("###")) continue;
114
115 if (versions >= CHANGELOG_VERSIONS_LIMIT) {
116 this->lines.resize(line_index - 2);
117 break;
118 }
119
120 ++versions;
121 }
122 }
123};
124
126struct HelpWindow : public Window {
127
128 HelpWindow(WindowDesc &desc, WindowNumber number) : Window(desc)
129 {
130 this->InitNested(number);
131
132 this->EnableTextfileButton(README_FILENAME, BASE_DIR, WID_HW_README);
133 this->EnableTextfileButton(CHANGELOG_FILENAME, BASE_DIR, WID_HW_CHANGELOG);
134 this->EnableTextfileButton(KNOWN_BUGS_FILENAME, BASE_DIR, WID_HW_KNOWN_BUGS);
135 this->EnableTextfileButton(LICENSE_FILENAME, BASE_DIR, WID_HW_LICENSE);
136 this->EnableTextfileButton(FONTS_FILENAME, DOCS_DIR, WID_HW_FONTS);
137 }
138
139 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
140 {
141 switch (widget) {
142 case WID_HW_README:
143 new GameManualTextfileWindow(README_FILENAME, BASE_DIR);
144 break;
145 case WID_HW_CHANGELOG:
146 new GameManualTextfileWindow(CHANGELOG_FILENAME, BASE_DIR);
147 break;
148 case WID_HW_KNOWN_BUGS:
149 new GameManualTextfileWindow(KNOWN_BUGS_FILENAME, BASE_DIR);
150 break;
151 case WID_HW_LICENSE:
152 new GameManualTextfileWindow(LICENSE_FILENAME, BASE_DIR);
153 break;
154 case WID_HW_FONTS:
155 new GameManualTextfileWindow(FONTS_FILENAME, DOCS_DIR);
156 break;
157 case WID_HW_WEBSITE:
158 OpenBrowser(WEBSITE_LINK);
159 break;
160 case WID_HW_WIKI:
161 OpenBrowser(WIKI_LINK);
162 break;
163 case WID_HW_BUGTRACKER:
164 OpenBrowser(BUGTRACKER_LINK);
165 break;
166 case WID_HW_COMMUNITY:
167 OpenBrowser(COMMUNITY_LINK);
168 break;
169 }
170 }
171
172private:
173 void EnableTextfileButton(std::string_view filename, Subdirectory subdir, WidgetID button_widget)
174 {
175 this->GetWidget<NWidgetLeaf>(button_widget)->SetDisabled(!FindGameManualFilePath(filename, subdir).has_value());
176 }
177};
178
179static constexpr std::initializer_list<NWidgetPart> _nested_helpwin_widgets = {
181 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
182 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetStringTip(STR_HELP_WINDOW_CAPTION),
183 EndContainer(),
184
185 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
187 NWidget(WWT_FRAME, COLOUR_DARK_GREEN), SetStringTip(STR_HELP_WINDOW_WEBSITES),
188 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_WEBSITE), SetStringTip(STR_HELP_WINDOW_MAIN_WEBSITE), SetMinimalSize(128, 12), SetFill(1, 0),
189 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_WIKI), SetStringTip(STR_HELP_WINDOW_MANUAL_WIKI), SetMinimalSize(128, 12), SetFill(1, 0),
190 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_BUGTRACKER), SetStringTip(STR_HELP_WINDOW_BUGTRACKER), SetMinimalSize(128, 12), SetFill(1, 0),
191 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_COMMUNITY), SetStringTip(STR_HELP_WINDOW_COMMUNITY), SetMinimalSize(128, 12), SetFill(1, 0),
192 EndContainer(),
193
194 NWidget(WWT_FRAME, COLOUR_DARK_GREEN), SetStringTip(STR_HELP_WINDOW_DOCUMENTS),
195 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_README), SetStringTip(STR_HELP_WINDOW_README), SetMinimalSize(128, 12), SetFill(1, 0),
196 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_CHANGELOG), SetStringTip(STR_HELP_WINDOW_CHANGELOG), SetMinimalSize(128, 12), SetFill(1, 0),
197 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_KNOWN_BUGS),SetStringTip(STR_HELP_WINDOW_KNOWN_BUGS), SetMinimalSize(128, 12), SetFill(1, 0),
198 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_LICENSE), SetStringTip(STR_HELP_WINDOW_LICENSE), SetMinimalSize(128, 12), SetFill(1, 0),
199 NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_FONTS), SetStringTip(STR_HELP_WINDOW_FONTS), SetMinimalSize(128, 12), SetFill(1, 0),
200 EndContainer(),
201 EndContainer(),
202 EndContainer(),
203};
204
205static WindowDesc _helpwin_desc(
206 WDP_CENTER, {}, 0, 0,
207 WC_HELPWIN, WC_NONE,
208 {},
209 _nested_helpwin_widgets
210);
211
212void ShowHelpWindow()
213{
214 AllocateWindowDescFront<HelpWindow>(_helpwin_desc, 0);
215}
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
Control codes that are embedded in the translation strings.
bool FioCheckFileExists(std::string_view filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:121
Functions for standard in/out file operations.
Searchpath
Types of searchpaths OpenTTD might use.
@ SP_SHARED_DIR
Search in the shared directory, like 'Shared Files' under Windows.
@ SP_INSTALLATION_DIR
Search in the installation directory.
@ SP_BINARY_DIR
Search in the directory where the binary resides.
@ SP_WORKING_DIR
Search in the working directory.
@ SP_APPLICATION_BUNDLE_DIR
Search within the application bundle.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
Definition fileio_type.h:88
@ NO_DIRECTORY
A path without any base directory.
@ BASE_DIR
Base directory for all subdirectories.
Definition fileio_type.h:89
@ DOCS_DIR
Subdirectory for documentation.
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 EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
GUI functions that shouldn't be here.
static constexpr size_t CHANGELOG_VERSIONS_LIMIT
Only show the first 20 changelog versions in the textfile viewer.
Definition help_gui.cpp:39
static std::optional< std::string > FindGameManualFilePath(std::string_view filename, Subdirectory subdir)
Find the path to the game manual file.
Definition help_gui.cpp:48
GUI to access manuals and related.
Types related to the help window widgets.
#define Point
Macro that prevents name conflicts between included headers.
Types related to the misc widgets.
@ WID_TF_WRAPTEXT
Whether or not to wrap the text.
Definition misc_widget.h:56
@ WID_TF_CAPTION
The caption of the window.
Definition misc_widget.h:53
Some generic types.
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
Functions related to low-level strings.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Window class displaying the game manual textfile viewer.
Definition help_gui.cpp:64
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
Definition help_gui.cpp:83
void AfterLoadChangelog()
For changelog files, truncate the file after CHANGELOG_VERSIONS_LIMIT versions.
Definition help_gui.cpp:106
void AfterLoadText() override
Post-processing after the text is loaded.
Definition help_gui.cpp:92
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Definition help_gui.cpp:139
std::string text
Contents of the line.
bool trusted
Whether the content is trusted (read: not from content like NewGRFs, etc).
std::vector< Line > lines
text, split into lines in a table with lines.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
virtual void AfterLoadText()
Post-processing after the text is loaded.
std::string filepath
Full path to the filename.
std::vector< Hyperlink > link_anchors
Anchor names of headings that can be linked to.
std::string filename
Filename of the textfile.
virtual void LoadTextfile(const std::string &textfile, Subdirectory dir)
Loads the textfile text from file and setup lines.
High level window description.
Definition window_gui.h:168
Number to differentiate different windows of the same class.
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:507
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1835
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:986
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1825
GUI functions related to textfiles.
@ TFT_GAME_MANUAL
Game manual/documentation file.
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_FRAME
Frame.
Definition widget_type.h:51
Functions, definitions and such used only by the GUI.
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ WDP_CENTER
Center the window.
Definition window_gui.h:145
int WidgetID
Widget ID.
Definition window_type.h:20
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:50