OpenTTD Source  14.0-beta3
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 <http://www.gnu.org/licenses/>.
6  */
7 
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 
19 #include "help_gui.h"
20 #include "widgets/help_widget.h"
21 #include "widgets/misc_widget.h"
22 
23 #include "safeguards.h"
24 
25 static const std::string README_FILENAME = "README.md";
26 static const std::string CHANGELOG_FILENAME = "changelog.txt";
27 static const std::string KNOWN_BUGS_FILENAME = "known-bugs.txt";
28 static const std::string LICENSE_FILENAME = "COPYING.md";
29 
30 static const std::string WEBSITE_LINK = "https://www.openttd.org/";
31 static const std::string WIKI_LINK = "https://wiki.openttd.org/";
32 static const std::string BUGTRACKER_LINK = "https://bugs.openttd.org/";
33 static const std::string COMMUNITY_LINK = "https://community.openttd.org/";
34 
36 static constexpr size_t CHANGELOG_VERSIONS_LIMIT = 20;
37 
44 static std::optional<std::string> FindGameManualFilePath(std::string_view filename)
45 {
46  static const Searchpath searchpaths[] = {
48  };
49 
50  for (Searchpath sp : searchpaths) {
51  auto file_path = FioGetDirectory(sp, BASE_DIR) + filename.data();
52  if (FioCheckFileExists(file_path, NO_DIRECTORY)) return file_path;
53  }
54 
55  return {};
56 }
57 
61  {
62  this->ConstructWindow();
63 
64  /* Mark the content of these files as trusted. */
65  this->trusted = true;
66 
67  auto filepath = FindGameManualFilePath(filename);
68  /* The user could, in theory, have moved the file. So just show an empty window if that is the case. */
69  if (!filepath.has_value()) {
70  return;
71  }
72 
73  this->filepath = filepath.value();
74  this->LoadTextfile(this->filepath, NO_DIRECTORY);
75  this->OnClick({ 0, 0 }, WID_TF_WRAPTEXT, 1);
76  }
77 
78  void SetStringParameters(WidgetID widget) const override
79  {
80  if (widget == WID_TF_CAPTION) {
81  SetDParamStr(0, this->filename);
82  }
83  }
84 
85  void AfterLoadText() override
86  {
87  if (this->filename == CHANGELOG_FILENAME) {
88  this->link_anchors.clear();
89  this->AfterLoadChangelog();
90  if (this->GetWidget<NWidgetStacked>(WID_TF_SEL_JUMPLIST)->SetDisplayedPlane(this->jumplist.empty() ? SZSP_HORIZONTAL : 0)) this->ReInit();
91  } else {
93  }
94  }
95 
102  {
103  /* Look for lines beginning with ---, they indicate that the previous line was a release name. */
104  for (size_t line_index = 0; line_index < this->lines.size(); ++line_index) {
105  const Line &line = this->lines[line_index];
106  if (line.text.find("---", 0) != 0) continue;
107 
108  if (this->jumplist.size() >= CHANGELOG_VERSIONS_LIMIT) {
109  this->lines.resize(line_index - 2);
110  break;
111  }
112 
113  /* Mark the version header with a colour, and add it to the jumplist. */
114  this->lines[line_index - 1].colour = TC_GOLD;
115  this->lines[line_index].colour = TC_GOLD;
116  this->jumplist.push_back(line_index - 1);
117  }
118  }
119 };
120 
122 struct HelpWindow : public Window {
123 
124  HelpWindow(WindowDesc *desc, WindowNumber number) : Window(desc)
125  {
126  this->InitNested(number);
127 
128  this->EnableTextfileButton(README_FILENAME, WID_HW_README);
129  this->EnableTextfileButton(CHANGELOG_FILENAME, WID_HW_CHANGELOG);
130  this->EnableTextfileButton(KNOWN_BUGS_FILENAME, WID_HW_KNOWN_BUGS);
131  this->EnableTextfileButton(LICENSE_FILENAME, WID_HW_LICENSE);
132  }
133 
134  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
135  {
136  switch (widget) {
137  case WID_HW_README:
138  new GameManualTextfileWindow(README_FILENAME);
139  break;
140  case WID_HW_CHANGELOG:
141  new GameManualTextfileWindow(CHANGELOG_FILENAME);
142  break;
143  case WID_HW_KNOWN_BUGS:
144  new GameManualTextfileWindow(KNOWN_BUGS_FILENAME);
145  break;
146  case WID_HW_LICENSE:
147  new GameManualTextfileWindow(LICENSE_FILENAME);
148  break;
149  case WID_HW_WEBSITE:
150  OpenBrowser(WEBSITE_LINK);
151  break;
152  case WID_HW_WIKI:
153  OpenBrowser(WIKI_LINK);
154  break;
155  case WID_HW_BUGTRACKER:
156  OpenBrowser(BUGTRACKER_LINK);
157  break;
158  case WID_HW_COMMUNITY:
159  OpenBrowser(COMMUNITY_LINK);
160  break;
161  }
162  }
163 
164 private:
165  void EnableTextfileButton(std::string_view filename, WidgetID button_widget)
166  {
167  this->GetWidget<NWidgetLeaf>(button_widget)->SetDisabled(!FindGameManualFilePath(filename).has_value());
168  }
169 };
170 
171 static constexpr NWidgetPart _nested_helpwin_widgets[] = {
173  NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
174  NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_HELP_WINDOW_CAPTION, STR_NULL),
175  EndContainer(),
176 
177  NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
179  NWidget(WWT_FRAME, COLOUR_DARK_GREEN), SetDataTip(STR_HELP_WINDOW_WEBSITES, STR_NULL),
180  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_WEBSITE), SetDataTip(STR_HELP_WINDOW_MAIN_WEBSITE, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
181  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_WIKI), SetDataTip(STR_HELP_WINDOW_MANUAL_WIKI, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
182  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_BUGTRACKER), SetDataTip(STR_HELP_WINDOW_BUGTRACKER, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
183  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_COMMUNITY), SetDataTip(STR_HELP_WINDOW_COMMUNITY, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
184  EndContainer(),
185 
186  NWidget(WWT_FRAME, COLOUR_DARK_GREEN), SetDataTip(STR_HELP_WINDOW_DOCUMENTS, STR_NULL),
187  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_README), SetDataTip(STR_HELP_WINDOW_README, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
188  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_CHANGELOG), SetDataTip(STR_HELP_WINDOW_CHANGELOG, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
189  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_KNOWN_BUGS),SetDataTip(STR_HELP_WINDOW_KNOWN_BUGS, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
190  NWidget(WWT_PUSHTXTBTN, COLOUR_GREEN, WID_HW_LICENSE), SetDataTip(STR_HELP_WINDOW_LICENSE, STR_NULL), SetMinimalSize(128, 12), SetFill(1, 0),
191  EndContainer(),
192  EndContainer(),
193  EndContainer(),
194 };
195 
196 static WindowDesc _helpwin_desc(__FILE__, __LINE__,
197  WDP_CENTER, nullptr, 0, 0,
198  WC_HELPWIN, WC_NONE,
199  0,
200  std::begin(_nested_helpwin_widgets), std::end(_nested_helpwin_widgets)
201 );
202 
203 void ShowHelpWindow()
204 {
205  AllocateWindowDescFront<HelpWindow>(&_helpwin_desc, 0);
206 }
SetFill
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition: widget_type.h:1141
WID_TF_CAPTION
@ WID_TF_CAPTION
The caption of the window.
Definition: misc_widget.h:51
CHANGELOG_VERSIONS_LIMIT
static constexpr size_t CHANGELOG_VERSIONS_LIMIT
Only show the first 20 changelog versions in the textfile viewer.
Definition: help_gui.cpp:36
GameManualTextfileWindow::AfterLoadChangelog
void AfterLoadChangelog()
For changelog files, add a jumplist entry for each version.
Definition: help_gui.cpp:101
WWT_CAPTION
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:63
NWID_HORIZONTAL
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:77
Searchpath
Searchpath
Types of searchpaths OpenTTD might use.
Definition: fileio_type.h:132
FindGameManualFilePath
static std::optional< std::string > FindGameManualFilePath(std::string_view filename)
Find the path to the game manual file.
Definition: help_gui.cpp:44
EndContainer
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1151
fileio_func.h
SP_INSTALLATION_DIR
@ SP_INSTALLATION_DIR
Search in the installation directory.
Definition: fileio_type.h:141
HelpWindow
Window class displaying the help window.
Definition: help_gui.cpp:122
SZSP_HORIZONTAL
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
Definition: widget_type.h:468
Window::Window
Window(WindowDesc *desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1757
NWidgetPart
Partial widget specification to allow NWidgets to be written nested.
Definition: widget_type.h:1038
textfile_gui.h
control_codes.h
WindowDesc
High level window description.
Definition: window_gui.h:153
WidgetID
int WidgetID
Widget ID.
Definition: window_type.h:18
window_gui.h
SetPadding
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.
Definition: widget_type.h:1188
BASE_DIR
@ BASE_DIR
Base directory for all subdirectories.
Definition: fileio_type.h:109
WindowNumber
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:732
Window::InitNested
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1747
TextfileWindow::AfterLoadText
virtual void AfterLoadText()
Post-processing after the text is loaded.
Definition: textfile_gui.cpp:496
TextfileWindow::Line
Definition: textfile_gui.h:46
WWT_PUSHTXTBTN
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:110
SP_APPLICATION_BUNDLE_DIR
@ SP_APPLICATION_BUNDLE_DIR
Search within the application bundle.
Definition: fileio_type.h:142
Window::ReInit
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition: window.cpp:953
TextfileWindow::LoadTextfile
virtual void LoadTextfile(const std::string &textfile, Subdirectory dir)
Loads the textfile text from file and setup lines.
Definition: textfile_gui.cpp:765
NWidget
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1258
safeguards.h
GameManualTextfileWindow
Window class displaying the game manual textfile viewer.
Definition: help_gui.cpp:59
SP_SHARED_DIR
@ SP_SHARED_DIR
Search in the shared directory, like 'Shared Files' under Windows.
Definition: fileio_type.h:139
Point
Coordinates of a point in 2D.
Definition: geometry_type.hpp:21
WWT_FRAME
@ WWT_FRAME
Frame.
Definition: widget_type.h:62
stdafx.h
SP_WORKING_DIR
@ SP_WORKING_DIR
Search in the working directory.
Definition: fileio_type.h:134
WC_NONE
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
WID_TF_WRAPTEXT
@ WID_TF_WRAPTEXT
Whether or not to wrap the text.
Definition: misc_widget.h:54
WidgetDimensions::unscaled
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
TextfileWindow::jumplist
std::vector< size_t > jumplist
Table of contents list, line numbers.
Definition: textfile_gui.h:72
WWT_CLOSEBOX
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:71
string_func.h
SP_BINARY_DIR
@ SP_BINARY_DIR
Search in the directory where the binary resides.
Definition: fileio_type.h:140
FioCheckFileExists
bool FioCheckFileExists(const std::string &filename, Subdirectory subdir)
Check whether the given file exists.
Definition: fileio.cpp:126
TextfileWindow::filepath
std::string filepath
Full path to the filename.
Definition: textfile_gui.h:69
SetPIP
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1220
NO_DIRECTORY
@ NO_DIRECTORY
A path without any base directory.
Definition: fileio_type.h:126
WWT_PANEL
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:52
TextfileWindow::lines
std::vector< Line > lines
#text, split into lines in a table with lines.
Definition: textfile_gui.h:71
SetDParamStr
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition: strings.cpp:352
openttd.h
TextfileWindow::trusted
bool trusted
Whether the content is trusted (read: not from content like NewGRFs, etc).
Definition: textfile_gui.h:77
TextfileWindow::link_anchors
std::vector< Hyperlink > link_anchors
Anchor names of headings that can be linked to.
Definition: textfile_gui.h:74
SetMinimalSize
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1097
TFT_GAME_MANUAL
@ TFT_GAME_MANUAL
Game manual/documentation file.
Definition: textfile_type.h:24
TextfileWindow::Line::text
std::string text
Contents of the line.
Definition: textfile_gui.h:49
help_gui.h
help_widget.h
TextfileWindow
Window for displaying a textfile.
Definition: textfile_gui.h:21
gui.h
Window
Data structure for an opened window.
Definition: window_gui.h:267
TextfileWindow::filename
std::string filename
Filename of the textfile.
Definition: textfile_gui.h:68
SetDataTip
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1162
WID_TF_SEL_JUMPLIST
@ WID_TF_SEL_JUMPLIST
Selection to display the jump list or not.
Definition: misc_widget.h:56
WDP_CENTER
@ WDP_CENTER
Center the window.
Definition: window_gui.h:142
GameManualTextfileWindow::AfterLoadText
void AfterLoadText() override
Post-processing after the text is loaded.
Definition: help_gui.cpp:85
misc_widget.h