The Battle for Wesnoth  1.19.2+dev
help_text_area.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
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 #include "help/help_text_area.hpp"
17 
18 #include "config.hpp" // for config, etc
19 #include "draw.hpp" // for blit, fill
20 #include "font/sdl_ttf_compat.hpp"
21 #include "font/standard_colors.hpp" // for string_to_color
22 #include "game_config.hpp" // for debug
23 #include "help/help_impl.hpp" // for parse_error, box_width, etc
24 #include "lexical_cast.hpp"
25 #include "log.hpp" // for LOG_STREAM, log_domain, etc
26 #include "picture.hpp" // for get_image
27 #include "preferences/preferences.hpp" // for font_scaled
28 #include "sdl/rect.hpp" // for draw_rectangle, etc
29 #include "sdl/texture.hpp" // for texture
30 #include "serialization/parser.hpp" // for read, write
31 
32 #include <algorithm> // for max, min, find_if
33 #include <vector> // for vector, etc
34 
35 static lg::log_domain log_display("display");
36 #define WRN_DP LOG_STREAM(warn, log_display)
37 
38 static lg::log_domain log_help("help");
39 #define ERR_HP LOG_STREAM(err, log_help)
40 #define WRN_HP LOG_STREAM(warn, log_help)
41 #define DBG_HP LOG_STREAM(debug, log_help)
42 
43 namespace help {
44 
46  gui::scrollarea(),
47  items_(),
48  last_row_(),
49  toplevel_(toplevel),
50  shown_topic_(nullptr),
51  title_spacing_(16),
52  curr_loc_(0, 0),
53  min_row_height_(4 + font::get_max_height(normal_font_size)),
54  curr_row_height_(min_row_height_),
55  contents_height_(0)
56 {
57  set_scroll_rate(40);
58 }
59 
60 void help_text_area::set_inner_location(const SDL_Rect& /*rect*/)
61 {
62  if (shown_topic_)
63  set_items();
64 }
65 
67 {
68  shown_topic_ = &t;
69  set_items();
70  queue_redraw();
71  DBG_HP << "Showing topic: " << t.id << ": " << t.title;
72 }
73 
74 
75 help_text_area::item::item(const texture& _tex, int x, int y, const std::string& _text,
76  const std::string& reference_to, bool _floating,
77  bool _box, ALIGNMENT alignment) :
78  rect_(),
79  tex(_tex),
80  text(_text),
81  ref_to(reference_to),
82  floating(_floating), box(_box),
83  align(alignment)
84 {
85  rect_.x = x;
86  rect_.y = y;
87  rect_.w = box ? tex.w() + box_width * 2 : tex.w();
88  rect_.h = box ? tex.h() + box_width * 2 : tex.h();
89 }
90 
91 help_text_area::item::item(const texture& _tex, int x, int y, bool _floating,
92  bool _box, ALIGNMENT alignment) :
93  rect_(),
94  tex(_tex),
95  text(""),
96  ref_to(""),
97  floating(_floating),
98  box(_box), align(alignment)
99 {
100  rect_.x = x;
101  rect_.y = y;
102  rect_.w = box ? tex.w() + box_width * 2 : tex.w();
103  rect_.h = box ? tex.h() + box_width * 2 : tex.h();
104 }
105 
107 {
108  last_row_.clear();
109  items_.clear();
110  curr_loc_.first = 0;
111  curr_loc_.second = 0;
113  // Add the title item.
114  const std::string show_title = font::pango_line_ellipsize(
118  if (tex) {
119  add_item(item(tex, 0, 0, show_title));
120  curr_loc_.second = title_spacing_;
122  down_one_line();
123  }
124  // Parse and add the text.
125  const std::vector<std::string>& parsed_items = shown_topic_->text.parsed_text();
126  std::vector<std::string>::const_iterator it;
127  for (it = parsed_items.begin(); it != parsed_items.end(); ++it) {
128  if (!(*it).empty() && (*it)[0] == '[') {
129  // Should be parsed as WML.
130  try {
131  config cfg;
132  std::istringstream stream(*it);
133  read(cfg, stream);
134 
135 #define TRY(name) do { \
136  if (auto child = cfg.optional_child(#name)) \
137  handle_##name##_cfg(*child); \
138  } while (0)
139 
140  TRY(ref);
141  TRY(img);
142  TRY(bold);
143  TRY(italic);
144  TRY(header);
145  TRY(jump);
146  TRY(format);
147 
148 #undef TRY
149 
150  }
151  catch (config::error& e) {
152  std::stringstream msg;
153  msg << "Error when parsing help markup as WML: '" << e.message << "'";
154  throw parse_error(msg.str());
155  }
156  }
157  else {
158  add_text_item(*it);
159  }
160  }
161  down_one_line(); // End the last line.
162  int h = height();
163  set_position(0);
165  set_shown_size(h);
166 }
167 
169 {
170  const std::string dst = cfg["dst"];
171  const std::string text = cfg["text"];
172  bool force = cfg["force"].to_bool();
173 
174  if (dst.empty()) {
175  std::stringstream msg;
176  msg << "Ref markup must have dst attribute. Please submit a bug"
177  " report if you have not modified the game files yourself. Erroneous config: ";
178  write(msg, cfg);
179  throw parse_error(msg.str());
180  }
181 
182  if (find_topic(toplevel_, dst) == nullptr && !force) {
183  // detect the broken link but quietly silence the hyperlink for normal user
184  add_text_item(text, game_config::debug ? dst : "", true);
185 
186  // FIXME: workaround: if different campaigns define different
187  // terrains, some terrains available in one campaign will
188  // appear in the list of seen terrains, and be displayed in the
189  // help, even if the current campaign does not handle such
190  // terrains. This will lead to the unit page generator creating
191  // invalid references.
192  //
193  // Disabling this is a kludgey workaround until the
194  // encountered_terrains system is fixed
195  //
196  // -- Ayin apr 8 2005
197 #if 0
198  if (game_config::debug) {
199  std::stringstream msg;
200  msg << "Reference to non-existent topic '" << dst
201  << "'. Please submit a bug report if you have not"
202  "modified the game files yourself. Erroneous config: ";
203  write(msg, cfg);
204  throw parse_error(msg.str());
205  }
206 #endif
207  } else {
208  add_text_item(text, dst);
209  }
210 }
211 
213 {
214  const std::string src = cfg["src"];
215  const std::string align = cfg["align"];
216  bool floating = cfg["float"].to_bool();
217  bool box = cfg["box"].to_bool(true);
218  if (src.empty()) {
219  throw parse_error("Img markup must have src attribute.");
220  }
221  add_img_item(src, align, floating, box);
222 }
223 
225 {
226  const std::string text = cfg["text"];
227  if (text.empty()) {
228  throw parse_error("Bold markup must have text attribute.");
229  }
230  add_text_item(text, "", false, -1, true);
231 }
232 
234 {
235  const std::string text = cfg["text"];
236  if (text.empty()) {
237  throw parse_error("Italic markup must have text attribute.");
238  }
239  add_text_item(text, "", false, -1, false, true);
240 }
241 
243 {
244  const std::string text = cfg["text"];
245  if (text.empty()) {
246  throw parse_error("Header markup must have text attribute.");
247  }
248  add_text_item(text, "", false, title2_size, true);
249 }
250 
252 {
253  const std::string amount_str = cfg["amount"];
254  const std::string to_str = cfg["to"];
255  if (amount_str.empty() && to_str.empty()) {
256  throw parse_error("Jump markup must have either a to or an amount attribute.");
257  }
258  unsigned jump_to = curr_loc_.first;
259  if (!amount_str.empty()) {
260  unsigned amount;
261  try {
262  amount = lexical_cast<unsigned, std::string>(amount_str);
263  }
264  catch (bad_lexical_cast&) {
265  throw parse_error("Invalid amount the amount attribute in jump markup.");
266  }
267  jump_to += amount;
268  }
269  if (!to_str.empty()) {
270  unsigned to;
271  try {
272  to = lexical_cast<unsigned, std::string>(to_str);
273  }
274  catch (bad_lexical_cast&) {
275  throw parse_error("Invalid amount in the to attribute in jump markup.");
276  }
277  if (to < jump_to) {
278  down_one_line();
279  }
280  jump_to = to;
281  }
282  if (jump_to != 0 && static_cast<int>(jump_to) <
284 
285  curr_loc_.first = jump_to;
286  }
287 }
288 
290 {
291  const std::string text = cfg["text"];
292  if (text.empty()) {
293  throw parse_error("Format markup must have text attribute.");
294  }
295  bool bold = cfg["bold"].to_bool();
296  bool italic = cfg["italic"].to_bool();
297  int font_size = cfg["font_size"].to_int(normal_font_size);
298  color_t color = font::string_to_color(cfg["color"]);
299  add_text_item(text, "", false, font_size, bold, italic, color);
300 }
301 
302 void help_text_area::add_text_item(const std::string& text, const std::string& ref_dst,
303  bool broken_link, int _font_size, bool bold, bool italic,
304  color_t text_color
305 )
306 {
307  const int font_size = _font_size < 0 ? normal_font_size : _font_size;
308  // font::line_width(), font::get_rendered_text() are not use scaled font inside
309  const int scaled_font_size = prefs::get().font_scaled(font_size);
310  if (text.empty())
311  return;
312  const int remaining_width = get_remaining_width();
313  std::size_t first_word_start = text.find_first_not_of(" ");
314  if (first_word_start == std::string::npos) {
315  first_word_start = 0;
316  }
317  if (text[first_word_start] == '\n') {
318  down_one_line();
319  std::string rest_text = text;
320  rest_text.erase(0, first_word_start + 1);
321  add_text_item(rest_text, ref_dst, broken_link, _font_size, bold, italic, text_color);
322  return;
323  }
324  const std::string first_word = get_first_word(text);
325  int state = font::pango_text::STYLE_NORMAL;
326  state |= bold ? font::pango_text::STYLE_BOLD : 0;
327  state |= italic ? font::pango_text::STYLE_ITALIC : 0;
328  if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
329  && remaining_width < font::pango_line_width(first_word, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
330  // The first word does not fit, and we are not at the start of
331  // the line. Move down.
332  down_one_line();
333  std::string s = remove_first_space(text);
334  add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
335  }
336  else {
337  std::vector<std::string> parts = split_in_width(text, font_size, remaining_width);
338  std::string first_part = parts.front();
339  // Always override the color if we have a cross reference.
340  color_t color;
341  if(ref_dst.empty())
342  color = text_color;
343  else if(broken_link)
344  color = font::BAD_COLOR;
345  else
346  color = font::YELLOW_COLOR;
347 
348  // In split_in_width(), no_break_after() and no_break_before() are used(see marked-up_text.cpp).
349  // Thus, even if there is enough remaining_width for the next word,
350  // sometimes empty string is returned from split_in_width().
351  if (first_part.empty()) {
352  down_one_line();
353  }
354  else {
355  texture tex(font::pango_render_text(first_part,
356  scaled_font_size, color, font::pango_text::FONT_STYLE(state)));
357  if (tex) {
358  add_item(item(tex, curr_loc_.first, curr_loc_.second,
359  first_part, ref_dst));
360  }
361  }
362  if (parts.size() > 1) {
363 
364  std::string& s = parts.back();
365 
366  const std::string first_word_before = get_first_word(s);
367  const std::string first_word_after = get_first_word(remove_first_space(s));
368  if (get_remaining_width() >= font::pango_line_width(first_word_after, scaled_font_size, font::pango_text::FONT_STYLE(state))
370  < font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
371  // If the removal of the space made this word fit, we
372  // must move down a line, otherwise it will be drawn
373  // without a space at the end of the line.
375  down_one_line();
376  }
377  else if (!(font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))
378  < get_remaining_width())) {
380  }
381  add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
382 
383  }
384  }
385 }
386 
387 void help_text_area::add_img_item(const std::string& path, const std::string& alignment,
388  const bool floating, const bool box)
389 {
391  if (!tex)
392  return;
393  ALIGNMENT align = str_to_align(alignment);
394  if (align == HERE && floating) {
395  WRN_DP << "Floating image with align HERE, aligning left.";
396  align = LEFT;
397  }
398  const int width = tex.w() + (box ? box_width * 2 : 0);
399  int xpos;
400  int ypos = curr_loc_.second;
401  int text_width = inner_location().w;
402  switch (align) {
403  case HERE:
404  xpos = curr_loc_.first;
405  break;
406  case LEFT:
407  default:
408  xpos = 0;
409  break;
410  case MIDDLE:
411  xpos = text_width / 2 - width / 2 - (box ? box_width : 0);
412  break;
413  case RIGHT:
414  xpos = text_width - width - (box ? box_width * 2 : 0);
415  break;
416  }
417  if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
418  && (xpos < curr_loc_.first || xpos + width > text_width)) {
419  down_one_line();
420  add_img_item(path, alignment, floating, box);
421  }
422  else {
423  if (!floating) {
424  curr_loc_.first = xpos;
425  }
426  else {
427  ypos = get_y_for_floating_img(width, xpos, ypos);
428  }
429  add_item(item(tex, xpos, ypos, floating, box, align));
430  }
431 }
432 
433 int help_text_area::get_y_for_floating_img(const int width, const int x, const int desired_y)
434 {
435  int min_y = desired_y;
436  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
437  const item& itm = *it;
438  if (itm.floating) {
439  if ((itm.rect_.x + itm.rect_.w > x && itm.rect_.x < x + width)
440  || (itm.rect_.x > x && itm.rect_.x < x + width)) {
441  min_y = std::max<int>(min_y, itm.rect_.y + itm.rect_.h);
442  }
443  }
444  }
445  return min_y;
446 }
447 
448 int help_text_area::get_min_x(const int y, const int height)
449 {
450  int min_x = 0;
451  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
452  const item& itm = *it;
453  if (itm.floating) {
454  if (itm.rect_.y < y + height && itm.rect_.y + itm.rect_.h > y && itm.align == LEFT) {
455  min_x = std::max<int>(min_x, itm.rect_.w + 5);
456  }
457  }
458  }
459  return min_x;
460 }
461 
462 int help_text_area::get_max_x(const int y, const int height)
463 {
464  int text_width = inner_location().w;
465  int max_x = text_width;
466  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
467  const item& itm = *it;
468  if (itm.floating) {
469  if (itm.rect_.y < y + height && itm.rect_.y + itm.rect_.h > y) {
470  if (itm.align == RIGHT) {
471  max_x = std::min<int>(max_x, text_width - itm.rect_.w - 5);
472  } else if (itm.align == MIDDLE) {
473  max_x = std::min<int>(max_x, text_width / 2 - itm.rect_.w / 2 - 5);
474  }
475  }
476  }
477  }
478  return max_x;
479 }
480 
482 {
483  items_.push_back(itm);
484  if (!itm.floating) {
485  curr_loc_.first += itm.rect_.w;
486  curr_row_height_ = std::max<int>(itm.rect_.h, curr_row_height_);
487  contents_height_ = std::max<int>(contents_height_, curr_loc_.second + curr_row_height_);
488  last_row_.push_back(&items_.back());
489  }
490  else {
491  if (itm.align == LEFT) {
492  curr_loc_.first = itm.rect_.w + 5;
493  }
494  contents_height_ = std::max<int>(contents_height_, itm.rect_.y + itm.rect_.h);
495  }
496 }
497 
498 
500 {
501  if (cmp_str == "left") {
502  return LEFT;
503  } else if (cmp_str == "middle") {
504  return MIDDLE;
505  } else if (cmp_str == "right") {
506  return RIGHT;
507  } else if (cmp_str == "here" || cmp_str.empty()) { // Make the empty string be "here" alignment.
508  return HERE;
509  }
510  std::stringstream msg;
511  msg << "Invalid alignment string: '" << cmp_str << "'";
512  throw parse_error(msg.str());
513 }
514 
516 {
517  adjust_last_row();
518  last_row_.clear();
521  contents_height_ = std::max<int>(curr_loc_.second + curr_row_height_, contents_height_);
523 }
524 
526 {
527  for (std::list<item *>::iterator it = last_row_.begin(); it != last_row_.end(); ++it) {
528  item &itm = *(*it);
529  const int gap = curr_row_height_ - itm.rect_.h;
530  itm.rect_.y += gap / 2;
531  }
532 }
533 
535 {
536  const int total_w = get_max_x(curr_loc_.second, curr_row_height_);
537  return total_w - curr_loc_.first;
538 }
539 
541 {
542  const SDL_Rect& loc = inner_location();
543  auto clipper = draw::reduce_clip(loc);
544  for(std::list<item>::const_iterator it = items_.begin(), end = items_.end(); it != end; ++it) {
545  SDL_Rect dst = it->rect_;
546  dst.y -= get_position();
547  if (dst.y < static_cast<int>(loc.h) && dst.y + it->rect_.h > 0) {
548  dst.x += loc.x;
549  dst.y += loc.y;
550  if (it->box) {
551  for (int i = 0; i < box_width; ++i) {
552  SDL_Rect draw_rect {
553  dst.x,
554  dst.y,
555  it->rect_.w - i * 2,
556  it->rect_.h - i * 2
557  };
558  draw::fill(draw_rect, 0, 0, 0, 0);
559  ++dst.x;
560  ++dst.y;
561  }
562  }
563  draw::blit(it->tex, dst);
564  }
565  }
566 }
567 
568 void help_text_area::scroll(unsigned int)
569 {
570  // Nothing will be done on the actual scroll event. The scroll
571  // position is checked when drawing instead and things drawn
572  // accordingly.
573  queue_redraw();
574 }
575 
577  return item.rect_.contains(x_, y_);
578 }
579 
580 std::string help_text_area::ref_at(const int x, const int y)
581 {
582  const int local_x = x - location().x;
583  const int local_y = y - location().y;
584  if (local_y < height() && local_y > 0) {
585  const int cmp_y = local_y + get_position();
586  const std::list<item>::const_iterator it =
587  std::find_if(items_.begin(), items_.end(), item_at(local_x, cmp_y));
588  if (it != items_.end()) {
589  if (!(*it).ref_to.empty()) {
590  return ((*it).ref_to);
591  }
592  }
593  }
594  return "";
595 }
596 
597 } // end namespace help
double t
Definition: astarsearch.cpp:63
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
void set_shown_size(unsigned h)
Definition: scrollarea.cpp:106
unsigned get_position() const
Definition: scrollarea.cpp:81
void set_full_size(unsigned h)
Definition: scrollarea.cpp:113
void set_position(unsigned pos)
Definition: scrollarea.cpp:91
rect inner_location() const
Definition: scrollarea.cpp:134
void set_scroll_rate(unsigned r)
Definition: scrollarea.cpp:120
const rect & location() const
Definition: widget.cpp:123
int width() const
Definition: widget.cpp:113
void queue_redraw()
Indicate that the widget should be redrawn.
Definition: widget.cpp:215
int height() const
Definition: widget.cpp:118
rect rect_
Definition: widget.hpp:99
Function object to find an item at the specified coordinates.
bool operator()(const item &) const
const section & toplevel_
const unsigned min_row_height_
void handle_italic_cfg(const config &cfg)
void handle_img_cfg(const config &cfg)
void add_img_item(const std::string &path, const std::string &alignment, const bool floating, const bool box)
Add an image item with the specified attributes.
int get_min_x(const int y, const int height=0)
Return the least x coordinate at which something of the specified height can be drawn at the specifie...
std::string ref_at(const int x, const int y)
Return the ID that is cross-referenced at the (screen) coordinates x, y.
help_text_area(const section &toplevel)
std::list< item * > last_row_
std::pair< int, int > curr_loc_
The current input location when creating items.
int get_remaining_width()
Return the width that remain on the line the current input point is at.
virtual void set_inner_location(const SDL_Rect &rect)
void show_topic(const topic &t)
Display the topic.
void handle_format_cfg(const config &cfg)
void adjust_last_row()
Adjust the heights of the items in the last row to make it look good.
virtual void scroll(unsigned int pos)
void set_items()
Update the vector with the items of the shown topic, creating surfaces for everything and putting thi...
void handle_bold_cfg(const config &cfg)
void handle_ref_cfg(const config &cfg)
void down_one_line()
Move the current input point to the next line.
ALIGNMENT str_to_align(const std::string &s)
Convert a string to an alignment.
void handle_jump_cfg(const config &cfg)
int get_max_x(const int y, const int height=0)
Analogous with get_min_x but return the maximum X.
void add_item(const item &itm)
Add an item to the internal list, update the locations and row height.
void add_text_item(const std::string &text, const std::string &ref_dst="", bool broken_link=false, int font_size=-1, bool bold=false, bool italic=false, color_t color=font::NORMAL_COLOR)
Add an item with text.
void handle_header_cfg(const config &cfg)
int contents_height_
The height of all items in total.
topic const * shown_topic_
int get_y_for_floating_img(const int width, const int x, const int desired_y)
Find the lowest y coordinate where a floating img of the specified width and at the specified x coord...
std::list< item > items_
const std::vector< std::string > & parsed_text() const
Definition: help_impl.cpp:386
static prefs & get()
int font_scaled(int size)
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:33
int w() const
The draw-space width of the texture, in pixels.
Definition: texture.hpp:105
int h() const
The draw-space height of the texture, in pixels.
Definition: texture.hpp:114
Drawing functions, for drawing things on the screen.
std::size_t i
Definition: function.cpp:968
int w
#define DBG_HP
#define WRN_DP
static lg::log_domain log_display("display")
#define TRY(name)
static lg::log_domain log_help("help")
New lexcical_cast header.
Standard logging facilities (interface).
clip_setter reduce_clip(const SDL_Rect &clip)
Set the clipping area to the intersection of the current clipping area and the given rectangle.
Definition: draw.cpp:502
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Definition: draw.cpp:50
void blit(const texture &tex, const SDL_Rect &dst)
Draws a texture, or part of a texture, at the given location.
Definition: draw.cpp:310
Collection of helper functions relating to Pango formatting.
int get_max_height(unsigned size, font::family_class fclass, pango_text::FONT_STYLE style)
Returns the maximum glyph height of a font, in pixels.
Definition: text.cpp:1180
const color_t YELLOW_COLOR
int pango_line_width(const std::string &line, int font_size, font::pango_text::FONT_STYLE font_style=font::pango_text::STYLE_NORMAL)
Determine the width of a line of text given a certain font size.
std::string pango_line_ellipsize(const std::string &text, int font_size, int max_width, font::pango_text::FONT_STYLE font_style)
If the text exceeds the specified max width, end it with an ellipsis (...)
color_t string_to_color(const std::string &cmp_str)
Return the color the string represents.
const color_t BAD_COLOR
texture pango_render_text(const std::string &text, int size, const color_t &color, font::pango_text::FONT_STYLE style, bool use_markup, int max_width)
Returns a SDL texture containing the rendered text.
const color_t NORMAL_COLOR
std::string path
Definition: filesystem.cpp:89
const bool & debug
Definition: game_config.cpp:92
General purpose widgets.
Definition: help.cpp:53
std::string get_first_word(const std::string &s)
Return the first word in s, not removing any spaces in the start of it.
Definition: help_impl.cpp:1539
std::string bold(const std::string &s)
Definition: help_impl.hpp:403
const int box_width
Definition: help_impl.cpp:80
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:411
const int title2_size
Definition: help_impl.cpp:79
const int normal_font_size
Definition: help_impl.cpp:81
std::string remove_first_space(const std::string &text)
Definition: help_impl.cpp:1531
std::string jump_to(const unsigned pos)
Definition: help_impl.hpp:389
std::vector< std::string > split_in_width(const std::string &s, const int font_size, const unsigned width)
Make a best effort to word wrap s.
Definition: help_impl.cpp:1512
const topic * find_topic(const section &sec, const std::string &id)
Search for the topic with the specified identifier in the section and its subsections.
Definition: help_impl.cpp:1298
std::string jump(const unsigned amount)
Definition: help_impl.hpp:396
const int title_size
Definition: help_impl.cpp:78
texture get_texture(const image::locator &i_locator, TYPE type, bool skip_cache)
Returns an image texture suitable for hardware-accelerated rendering.
Definition: picture.cpp:960
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:109
Contains the SDL_Rect helper code.
Transitional API for porting SDL_ttf-based code to Pango.
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:627
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:764
Thrown when a lexical_cast fails.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
An item that is displayed in the text area.
item(const texture &tex, int x, int y, const std::string &text="", const std::string &reference_to="", bool floating=false, bool box=false, ALIGNMENT alignment=HERE)
rect rect_
Relative coordinates of this item.
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
A topic contains a title, an id and some text.
Definition: help_impl.hpp:113
topic_text text
Definition: help_impl.hpp:138
std::string title
Definition: help_impl.hpp:137
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
Definition: rect.cpp:52
static map_location::DIRECTION s
#define e
#define h