The Battle for Wesnoth  1.17.21+dev
help.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2023
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Routines for showing the help-dialog.
19  */
20 
21 #define GETTEXT_DOMAIN "wesnoth-help"
22 
23 #include "help/help.hpp"
24 
25 #include "config.hpp" // for config, etc
26 #include "events.hpp" // for draw, pump, etc
27 #include "font/constants.hpp" // for relative_size
28 #include "preferences/game.hpp"
29 #include "game_config_manager.hpp"
30 #include "gettext.hpp" // for _
32 #include "help/help_browser.hpp" // for help_browser
33 #include "help/help_impl.hpp" // for hidden_symbol, toplevel, etc
34 #include "key.hpp" // for CKey
35 #include "log.hpp" // for LOG_STREAM, log_domain
36 #include "sdl/surface.hpp" // for surface
37 #include "show_dialog.hpp" // for dialog_frame, etc
38 #include "terrain/terrain.hpp" // for terrain_type
39 #include "units/unit.hpp" // for unit
40 #include "units/types.hpp" // for unit_type, unit_type_data, etc
41 #include "video.hpp" // for game_canvas_size
42 #include "widgets/button.hpp" // for button
43 
44 #include <cassert> // for assert
45 #include <algorithm> // for min
46 #include <ostream> // for basic_ostream, operator<<, etc
47 #include <vector> // for vector, vector<>::iterator
48 #include <SDL2/SDL.h>
49 
50 
51 static lg::log_domain log_display("display");
52 #define WRN_DP LOG_STREAM(warn, log_display)
53 
54 static lg::log_domain log_help("help");
55 #define ERR_HELP LOG_STREAM(err, log_help)
56 
57 namespace help {
58 /**
59  * Open a help dialog using a specified toplevel.
60  *
61  * This would allow for complete customization of the contents, although not in a
62  * very easy way. It's used as the internal implementation of the other help*
63  * functions.
64  *
65  *@pre The help_manager must already exist; this is different to the functions
66  * declared in help.hpp, which is why this one's declaration is in the .cpp
67  * file. Because this takes a section as an argument, it wouldn't make sense
68  * for it to call ensure_cache_lifecycle() internally - if the help_manager
69  * doesn't already exist, that would likely destroy the referenced object at
70  * the point that this function exited.
71  */
72 void show_with_toplevel(const section &toplevel, const std::string& show_topic="", int xloc=-1, int yloc=-1);
73 
74 
76 {
77  auto cache_lifecycle = ensure_cache_lifecycle();
79 }
80 
82 {
83  auto cache_lifecycle = ensure_cache_lifecycle();
84  help::show_terrain_help(t.id(), t.hide_help());
85 }
86 
88 {
89  auto cache_lifecycle = ensure_cache_lifecycle();
90  std::string var_id = t.get_cfg()["variation_id"].str();
91  if (var_id.empty())
92  var_id = t.get_cfg()["variation_name"].str();
93  bool hide_help = t.hide_help();
94  bool use_variation = false;
95  if (!var_id.empty()) {
96  const unit_type *parent = unit_types.find(t.id());
97  assert(parent);
98  if (hide_help) {
99  hide_help = parent->hide_help();
100  } else {
101  use_variation = true;
102  }
103  }
104 
105  if (use_variation)
106  help::show_variation_help(t.id(), var_id, hide_help);
107  else
108  help::show_unit_help(t.id(), t.show_variations_in_help(), hide_help);
109 }
110 
112 {
113  assert(!game_cfg);
114  assert(cfg);
115  // This is a global rawpointer in the help:: namespace.
116  game_cfg = cfg;
117 }
118 
119 std::unique_ptr<help_manager> ensure_cache_lifecycle()
120 {
121  // The internals of help_manager are that this global raw pointer is
122  // non-null if and only if an instance of help_manager already exists.
123  if(game_cfg)
124  return nullptr;
125  return std::make_unique<help_manager>(&game_config_manager::get()->game_config());
126 }
127 
129 {
130  game_cfg = nullptr;
133  // These last numbers must be reset so that the content is regenerated.
134  // Upon next start.
137 }
138 
139 /**
140  * Open the help browser, show topic with id show_topic.
141  *
142  * If show_topic is the empty string, the default topic will be shown.
143  */
144 void show_help(const std::string& show_topic, int xloc, int yloc)
145 {
146  auto cache_lifecycle = ensure_cache_lifecycle();
147  show_with_toplevel(default_toplevel, show_topic, xloc, yloc);
148 }
149 
150 /**
151  * Open the help browser, show unit with id unit_id.
152  *
153  * If show_topic is the empty string, the default topic will be shown.
154  */
155 void show_unit_help(const std::string& show_topic, bool has_variations, bool hidden, int xloc, int yloc)
156 {
157  auto cache_lifecycle = ensure_cache_lifecycle();
159  hidden_symbol(hidden) + (has_variations ? ".." : "") + unit_prefix + show_topic, xloc, yloc);
160 }
161 
162 /**
163  * Open the help browser, show terrain with id terrain_id.
164  *
165  * If show_topic is the empty string, the default topic will be shown.
166  */
167 void show_terrain_help(const std::string& show_topic, bool hidden, int xloc, int yloc)
168 {
169  auto cache_lifecycle = ensure_cache_lifecycle();
170  show_with_toplevel(default_toplevel, hidden_symbol(hidden) + terrain_prefix + show_topic, xloc, yloc);
171 }
172 
173 /**
174  * Open the help browser, show the variation of the unit matching.
175  */
176 void show_variation_help(const std::string& unit, const std::string &variation, bool hidden, int xloc, int yloc)
177 {
178  auto cache_lifecycle = ensure_cache_lifecycle();
179  show_with_toplevel(default_toplevel, hidden_symbol(hidden) + variation_prefix + unit + "_" + variation, xloc, yloc);
180 }
181 
182 /**
183  * Open a help dialog using a toplevel other than the default.
184  *
185  * This allows for complete customization of the contents, although not in a
186  * very easy way.
187  */
188 void show_with_toplevel(const section &toplevel_sec,
189  const std::string& show_topic,
190  int xloc, int yloc)
191 {
192  const events::event_context dialog_events_context;
193  const gui::dialog_manager manager;
194 
195  point canvas_size = video::game_canvas_size();
196 
197  const int width = std::min<int>(font::relative_size(1200), canvas_size.x - font::relative_size(20));
198  const int height = std::min<int>(font::relative_size(850), canvas_size.y - font::relative_size(150));
199  const int left_padding = font::relative_size(10);
200  const int right_padding = font::relative_size(10);
201  const int top_padding = font::relative_size(10);
202  const int bot_padding = font::relative_size(10);
203 
204  // If not both locations were supplied, put the dialog in the middle
205  // of the screen.
206  if (yloc <= -1 || xloc <= -1) {
207  xloc = canvas_size.x / 2 - width / 2;
208  yloc = canvas_size.y / 2 - height / 2;
209  }
210  std::vector<gui::button*> buttons_ptr;
211  gui::button close_button_(_("Close"));
212  buttons_ptr.push_back(&close_button_);
213 
215  _("Help"), gui::dialog_frame::default_style, &buttons_ptr
216  );
217  f.layout(xloc, yloc, width, height);
218 
219  // Find all unit_types that have not been constructed yet and fill in the information
220  // needed to create the help topics
222 
227  {
228  // More units or terrains encountered, update the contents.
233  }
234  try {
235  help_browser hb(toplevel_sec);
236  hb.set_location(xloc + left_padding, yloc + top_padding);
237  hb.set_width(width - left_padding - right_padding);
238  hb.set_height(height - top_padding - bot_padding);
239  if (!show_topic.empty()) {
240  hb.show_topic(show_topic);
241  }
242  else {
244  }
245  hb.queue_redraw();
246  events::draw();
247  CKey key;
248  for (;;) {
249  events::pump();
251  if (key[SDLK_ESCAPE]) {
252  // Escape quits from the dialog.
253  return;
254  }
255  for (std::vector<gui::button*>::iterator button_it = buttons_ptr.begin();
256  button_it != buttons_ptr.end(); ++button_it) {
257  if ((*button_it)->pressed()) {
258  // There is only one button, close.
259  return;
260  }
261  }
262  // This also rate limits to vsync
263  events::draw();
264  }
265  }
266  catch (const parse_error& e) {
267  ERR_HELP << _("Parse error when parsing help text:") << " " << e.message;
268 #if 0
269  // Displaying in the UI is disabled due to issue #2587
270  std::stringstream msg;
271  msg << _("Parse error when parsing help text:") << " '" << e.message << "'";
273 #endif
274  }
275 }
276 
277 } // End namespace help.
double t
Definition: astarsearch.cpp:65
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:29
static game_config_manager * get()
A class grating read only view to a vector of config objects, viewed as one config with all children ...
A button is a control that can be pushed to start an action or close a dialog.
Definition: button.hpp:52
static const style default_style
Definition: show_dialog.hpp:67
void set_width(int w)
Definition: widget.cpp:98
void set_height(int h)
Definition: widget.cpp:103
virtual void set_location(const SDL_Rect &rect)
Definition: widget.cpp:69
void queue_redraw()
Indicate that the widget should be redrawn.
Definition: widget.cpp:215
A help browser widget.
void show_topic(const std::string &topic_id)
Display the topic with the specified identifier.
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1246
void build_all(unit_type::BUILD_STATUS status)
Makes sure the all unit_types are built to the specified level.
Definition: types.cpp:1288
A single unit type that the player may recruit.
Definition: types.hpp:46
@ HELP_INDEXED
Definition: types.hpp:77
bool hide_help() const
Definition: types.cpp:624
This class represents a single unit of a specific type.
Definition: unit.hpp:134
static std::string _(const char *str)
Definition: gettext.hpp:93
const unit_type & type() const
This unit's type, accounting for gender and variation.
Definition: unit.hpp:356
static lg::log_domain log_display("display")
#define ERR_HELP
Definition: help.cpp:55
static lg::log_domain log_help("help")
Standard logging facilities (interface).
void draw()
Trigger a draw cycle.
Definition: events.cpp:743
void raise_process_event()
Definition: events.cpp:748
void pump()
Process all events currently in the queue.
Definition: events.cpp:478
int relative_size(int size)
Definition: constants.hpp:30
Game configuration data as global variables.
Definition: build_info.cpp:63
const bool & debug
Definition: game_config.cpp:91
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
Definition: help.cpp:57
std::string hidden_symbol(bool hidden)
Definition: help_impl.cpp:1589
std::unique_ptr< help_manager > ensure_cache_lifecycle()
Helper function for any of the show_help functions to control the cache's lifecycle; can also be used...
Definition: help.cpp:119
void show_help(const std::string &show_topic, int xloc, int yloc)
Open the help browser, show topic with id show_topic.
Definition: help.cpp:144
int last_num_encountered_units
Definition: help_impl.cpp:71
const std::string unit_prefix
Definition: help_impl.cpp:88
const std::string variation_prefix
Definition: help_impl.cpp:93
void show_variation_help(const std::string &unit, const std::string &variation, bool hidden, int xloc, int yloc)
Open the help browser, show the variation of the unit matching.
Definition: help.cpp:176
void show_terrain_description(const terrain_type &t)
Definition: help.cpp:81
void show_with_toplevel(const section &toplevel, const std::string &show_topic="", int xloc=-1, int yloc=-1)
Open a help dialog using a specified toplevel.
Definition: help.cpp:188
void show_terrain_help(const std::string &show_topic, bool hidden, int xloc, int yloc)
Open the help browser, show terrain with id terrain_id.
Definition: help.cpp:167
void show_unit_help(const std::string &show_topic, bool has_variations, bool hidden, int xloc, int yloc)
Open the help browser, show unit with id unit_id.
Definition: help.cpp:155
void generate_contents()
Generate the help contents from the configurations given to the manager.
Definition: help_impl.cpp:1528
const std::string terrain_prefix
Definition: help_impl.cpp:89
boost::tribool last_debug_state
Definition: help_impl.cpp:73
help::section default_toplevel
Definition: help_impl.cpp:67
void show_unit_description(const unit &u)
Definition: help.cpp:75
const game_config_view * game_cfg
Definition: help_impl.cpp:65
int last_num_encountered_terrains
Definition: help_impl.cpp:72
help::section hidden_sections
Definition: help_impl.cpp:69
const std::string default_show_topic
Definition: help_impl.cpp:86
std::set< std::string > & encountered_units()
Definition: game.cpp:916
std::set< t_translation::terrain_code > & encountered_terrains()
Definition: game.cpp:921
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
Definition: video.cpp:426
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
This file contains object "key", which is used to store information about keys while annotation parsi...
help_manager(const game_config_view *game_config)
Definition: help.cpp:111
Thrown when the help system fails to parse something.
Definition: help_impl.hpp:214
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:146
Holds a 2D point.
Definition: point.hpp:25
unit_type_data unit_types
Definition: types.cpp:1465
#define e
#define f