The Battle for Wesnoth  1.19.0-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 "game_config.hpp" // for debug
22 #include "help/help_impl.hpp" // for parse_error, box_width, etc
23 #include "lexical_cast.hpp"
24 #include "log.hpp" // for LOG_STREAM, log_domain, etc
25 #include "picture.hpp" // for get_image
26 #include "preferences/general.hpp" // for font_scaled
27 #include "sdl/rect.hpp" // for draw_rectangle, etc
28 #include "sdl/texture.hpp" // for texture
29 #include "serialization/parser.hpp" // for read, write
30 
31 #include <algorithm> // for max, min, find_if
32 #include <vector> // for vector, etc
33 
34 static lg::log_domain log_display("display");
35 #define WRN_DP LOG_STREAM(warn, log_display)
36 
37 static lg::log_domain log_help("help");
38 #define ERR_HP LOG_STREAM(err, log_help)
39 #define WRN_HP LOG_STREAM(warn, log_help)
40 #define DBG_HP LOG_STREAM(debug, log_help)
41 
42 namespace help {
43 
45  gui::scrollarea(),
46  items_(),
47  last_row_(),
48  toplevel_(toplevel),
49  shown_topic_(nullptr),
50  title_spacing_(16),
51  curr_loc_(0, 0),
52  min_row_height_(4 + font::get_max_height(normal_font_size)),
53  curr_row_height_(min_row_height_),
54  contents_height_(0)
55 {
56  set_scroll_rate(40);
57 }
58 
59 void help_text_area::set_inner_location(const SDL_Rect& /*rect*/)
60 {
61  if (shown_topic_)
62  set_items();
63 }
64 
66 {
67  shown_topic_ = &t;
68  set_items();
69  queue_redraw();
70  DBG_HP << "Showing topic: " << t.id << ": " << t.title;
71 }
72 
73 
74 help_text_area::item::item(const texture& _tex, int x, int y, const std::string& _text,
75  const std::string& reference_to, bool _floating,
76  bool _box, ALIGNMENT alignment) :
77  rect_(),
78  tex(_tex),
79  text(_text),
80  ref_to(reference_to),
81  floating(_floating), box(_box),
82  align(alignment)
83 {
84  rect_.x = x;
85  rect_.y = y;
86  rect_.w = box ? tex.w() + box_width * 2 : tex.w();
87  rect_.h = box ? tex.h() + box_width * 2 : tex.h();
88 }
89 
90 help_text_area::item::item(const texture& _tex, int x, int y, bool _floating,
91  bool _box, ALIGNMENT alignment) :
92  rect_(),
93  tex(_tex),
94  text(""),
95  ref_to(""),
96  floating(_floating),
97  box(_box), align(alignment)
98 {
99  rect_.x = x;
100  rect_.y = y;
101  rect_.w = box ? tex.w() + box_width * 2 : tex.w();
102  rect_.h = box ? tex.h() + box_width * 2 : tex.h();
103 }
104 
106 {
107  last_row_.clear();
108  items_.clear();
109  curr_loc_.first = 0;
110  curr_loc_.second = 0;
112  // Add the title item.
113  const std::string show_title = font::pango_line_ellipsize(
117  if (tex) {
118  add_item(item(tex, 0, 0, show_title));
119  curr_loc_.second = title_spacing_;
121  down_one_line();
122  }
123  // Parse and add the text.
124  const std::vector<std::string>& parsed_items = shown_topic_->text.parsed_text();
125  std::vector<std::string>::const_iterator it;
126  for (it = parsed_items.begin(); it != parsed_items.end(); ++it) {
127  if (!(*it).empty() && (*it)[0] == '[') {
128  // Should be parsed as WML.
129  try {
130  config cfg;
131  std::istringstream stream(*it);
132  read(cfg, stream);
133 
134 #define TRY(name) do { \
135  if (auto child = cfg.optional_child(#name)) \
136  handle_##name##_cfg(*child); \
137  } while (0)
138 
139  TRY(ref);
140  TRY(img);
141  TRY(bold);
142  TRY(italic);
143  TRY(header);
144  TRY(jump);
145  TRY(format);
146 
147 #undef TRY
148 
149  }
150  catch (config::error& e) {
151  std::stringstream msg;
152  msg << "Error when parsing help markup as WML: '" << e.message << "'";
153  throw parse_error(msg.str());
154  }
155  }
156  else {
157  add_text_item(*it);
158  }
159  }
160  down_one_line(); // End the last line.
161  int h = height();
162  set_position(0);
164  set_shown_size(h);
165 }
166 
168 {
169  const std::string dst = cfg["dst"];
170  const std::string text = cfg["text"];
171  bool force = cfg["force"].to_bool();
172 
173  if (dst.empty()) {
174  std::stringstream msg;
175  msg << "Ref markup must have dst attribute. Please submit a bug"
176  " report if you have not modified the game files yourself. Erroneous config: ";
177  write(msg, cfg);
178  throw parse_error(msg.str());
179  }
180 
181  if (find_topic(toplevel_, dst) == nullptr && !force) {
182  // detect the broken link but quietly silence the hyperlink for normal user
183  add_text_item(text, game_config::debug ? dst : "", true);
184 
185  // FIXME: workaround: if different campaigns define different
186  // terrains, some terrains available in one campaign will
187  // appear in the list of seen terrains, and be displayed in the
188  // help, even if the current campaign does not handle such
189  // terrains. This will lead to the unit page generator creating
190  // invalid references.
191  //
192  // Disabling this is a kludgey workaround until the
193  // encountered_terrains system is fixed
194  //
195  // -- Ayin apr 8 2005
196 #if 0
197  if (game_config::debug) {
198  std::stringstream msg;
199  msg << "Reference to non-existent topic '" << dst
200  << "'. Please submit a bug report if you have not"
201  "modified the game files yourself. Erroneous config: ";
202  write(msg, cfg);
203  throw parse_error(msg.str());
204  }
205 #endif
206  } else {
207  add_text_item(text, dst);
208  }
209 }
210 
212 {
213  const std::string src = cfg["src"];
214  const std::string align = cfg["align"];
215  bool floating = cfg["float"].to_bool();
216  bool box = cfg["box"].to_bool(true);
217  if (src.empty()) {
218  throw parse_error("Img markup must have src attribute.");
219  }
220  add_img_item(src, align, floating, box);
221 }
222 
224 {
225  const std::string text = cfg["text"];
226  if (text.empty()) {
227  throw parse_error("Bold markup must have text attribute.");
228  }
229  add_text_item(text, "", false, -1, true);
230 }
231 
233 {
234  const std::string text = cfg["text"];
235  if (text.empty()) {
236  throw parse_error("Italic markup must have text attribute.");
237  }
238  add_text_item(text, "", false, -1, false, true);
239 }
240 
242 {
243  const std::string text = cfg["text"];
244  if (text.empty()) {
245  throw parse_error("Header markup must have text attribute.");
246  }
247  add_text_item(text, "", false, title2_size, true);
248 }
249 
251 {
252  const std::string amount_str = cfg["amount"];
253  const std::string to_str = cfg["to"];
254  if (amount_str.empty() && to_str.empty()) {
255  throw parse_error("Jump markup must have either a to or an amount attribute.");
256  }
257  unsigned jump_to = curr_loc_.first;
258  if (!amount_str.empty()) {
259  unsigned amount;
260  try {
261  amount = lexical_cast<unsigned, std::string>(amount_str);
262  }
263  catch (bad_lexical_cast&) {
264  throw parse_error("Invalid amount the amount attribute in jump markup.");
265  }
266  jump_to += amount;
267  }
268  if (!to_str.empty()) {
269  unsigned to;
270  try {
271  to = lexical_cast<unsigned, std::string>(to_str);
272  }
273  catch (bad_lexical_cast&) {
274  throw parse_error("Invalid amount in the to attribute in jump markup.");
275  }
276  if (to < jump_to) {
277  down_one_line();
278  }
279  jump_to = to;
280  }
281  if (jump_to != 0 && static_cast<int>(jump_to) <
283 
284  curr_loc_.first = jump_to;
285  }
286 }
287 
289 {
290  const std::string text = cfg["text"];
291  if (text.empty()) {
292  throw parse_error("Format markup must have text attribute.");
293  }
294  bool bold = cfg["bold"].to_bool();
295  bool italic = cfg["italic"].to_bool();
296  int font_size = cfg["font_size"].to_int(normal_font_size);
297  color_t color = help::string_to_color(cfg["color"]);
298  add_text_item(text, "", false, font_size, bold, italic, color);
299 }
300 
301 void help_text_area::add_text_item(const std::string& text, const std::string& ref_dst,
302  bool broken_link, int _font_size, bool bold, bool italic,
303  color_t text_color
304 )
305 {
306  const int font_size = _font_size < 0 ? normal_font_size : _font_size;
307  // font::line_width(), font::get_rendered_text() are not use scaled font inside
308  const int scaled_font_size = preferences::font_scaled(font_size);
309  if (text.empty())
310  return;
311  const int remaining_width = get_remaining_width();
312  std::size_t first_word_start = text.find_first_not_of(" ");
313  if (first_word_start == std::string::npos) {
314  first_word_start = 0;
315  }
316  if (text[first_word_start] == '\n') {
317  down_one_line();
318  std::string rest_text = text;
319  rest_text.erase(0, first_word_start + 1);
320  add_text_item(rest_text, ref_dst, broken_link, _font_size, bold, italic, text_color);
321  return;
322  }
323  const std::string first_word = get_first_word(text);
324  int state = font::pango_text::STYLE_NORMAL;
325  state |= bold ? font::pango_text::STYLE_BOLD : 0;
326  state |= italic ? font::pango_text::STYLE_ITALIC : 0;
327  if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
328  && remaining_width < font::pango_line_width(first_word, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
329  // The first word does not fit, and we are not at the start of
330  // the line. Move down.
331  down_one_line();
332  std::string s = remove_first_space(text);
333  add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
334  }
335  else {
336  std::vector<std::string> parts = split_in_width(text, font_size, remaining_width);
337  std::string first_part = parts.front();
338  // Always override the color if we have a cross reference.
339  color_t color;
340  if(ref_dst.empty())
341  color = text_color;
342  else if(broken_link)
343  color = font::BAD_COLOR;
344  else
345  color = font::YELLOW_COLOR;
346 
347  // In split_in_width(), no_break_after() and no_break_before() are used(see marked-up_text.cpp).
348  // Thus, even if there is enough remaining_width for the next word,
349  // sometimes empty string is returned from split_in_width().
350  if (first_part.empty()) {
351  down_one_line();
352  }
353  else {
354  texture tex(font::pango_render_text(first_part,
355  scaled_font_size, color, font::pango_text::FONT_STYLE(state)));
356  if (tex) {
357  add_item(item(tex, curr_loc_.first, curr_loc_.second,
358  first_part, ref_dst));
359  }
360  }
361  if (parts.size() > 1) {
362 
363  std::string& s = parts.back();
364 
365  const std::string first_word_before = get_first_word(s);
366  const std::string first_word_after = get_first_word(remove_first_space(s));
367  if (get_remaining_width() >= font::pango_line_width(first_word_after, scaled_font_size, font::pango_text::FONT_STYLE(state))
369  < font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
370  // If the removal of the space made this word fit, we
371  // must move down a line, otherwise it will be drawn
372  // without a space at the end of the line.
374  down_one_line();
375  }
376  else if (!(font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))
377  < get_remaining_width())) {
379  }
380  add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
381 
382  }
383  }
384 }
385 
386 void help_text_area::add_img_item(const std::string& path, const std::string& alignment,
387  const bool floating, const bool box)
388 {
390  if (!tex)
391  return;
392  ALIGNMENT align = str_to_align(alignment);
393  if (align == HERE && floating) {
394  WRN_DP << "Floating image with align HERE, aligning left.";
395  align = LEFT;
396  }
397  const int width = tex.w() + (box ? box_width * 2 : 0);
398  int xpos;
399  int ypos = curr_loc_.second;
400  int text_width = inner_location().w;
401  switch (align) {
402  case HERE:
403  xpos = curr_loc_.first;
404  break;
405  case LEFT:
406  default:
407  xpos = 0;
408  break;
409  case MIDDLE:
410  xpos = text_width / 2 - width / 2 - (box ? box_width : 0);
411  break;
412  case RIGHT:
413  xpos = text_width - width - (box ? box_width * 2 : 0);
414  break;
415  }
416  if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
417  && (xpos < curr_loc_.first || xpos + width > text_width)) {
418  down_one_line();
419  add_img_item(path, alignment, floating, box);
420  }
421  else {
422  if (!floating) {
423  curr_loc_.first = xpos;
424  }
425  else {
426  ypos = get_y_for_floating_img(width, xpos, ypos);
427  }
428  add_item(item(tex, xpos, ypos, floating, box, align));
429  }
430 }
431 
432 int help_text_area::get_y_for_floating_img(const int width, const int x, const int desired_y)
433 {
434  int min_y = desired_y;
435  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
436  const item& itm = *it;
437  if (itm.floating) {
438  if ((itm.rect_.x + itm.rect_.w > x && itm.rect_.x < x + width)
439  || (itm.rect_.x > x && itm.rect_.x < x + width)) {
440  min_y = std::max<int>(min_y, itm.rect_.y + itm.rect_.h);
441  }
442  }
443  }
444  return min_y;
445 }
446 
447 int help_text_area::get_min_x(const int y, const int height)
448 {
449  int min_x = 0;
450  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
451  const item& itm = *it;
452  if (itm.floating) {
453  if (itm.rect_.y < y + height && itm.rect_.y + itm.rect_.h > y && itm.align == LEFT) {
454  min_x = std::max<int>(min_x, itm.rect_.w + 5);
455  }
456  }
457  }
458  return min_x;
459 }
460 
461 int help_text_area::get_max_x(const int y, const int height)
462 {
463  int text_width = inner_location().w;
464  int max_x = text_width;
465  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
466  const item& itm = *it;
467  if (itm.floating) {
468  if (itm.rect_.y < y + height && itm.rect_.y + itm.rect_.h > y) {
469  if (itm.align == RIGHT) {
470  max_x = std::min<int>(max_x, text_width - itm.rect_.w - 5);
471  } else if (itm.align == MIDDLE) {
472  max_x = std::min<int>(max_x, text_width / 2 - itm.rect_.w / 2 - 5);
473  }
474  }
475  }
476  }
477  return max_x;
478 }
479 
481 {
482  items_.push_back(itm);
483  if (!itm.floating) {
484  curr_loc_.first += itm.rect_.w;
485  curr_row_height_ = std::max<int>(itm.rect_.h, curr_row_height_);
486  contents_height_ = std::max<int>(contents_height_, curr_loc_.second + curr_row_height_);
487  last_row_.push_back(&items_.back());
488  }
489  else {
490  if (itm.align == LEFT) {
491  curr_loc_.first = itm.rect_.w + 5;
492  }
493  contents_height_ = std::max<int>(contents_height_, itm.rect_.y + itm.rect_.h);
494  }
495 }
496 
497 
499 {
500  if (cmp_str == "left") {
501  return LEFT;
502  } else if (cmp_str == "middle") {
503  return MIDDLE;
504  } else if (cmp_str == "right") {
505  return RIGHT;
506  } else if (cmp_str == "here" || cmp_str.empty()) { // Make the empty string be "here" alignment.
507  return HERE;
508  }
509  std::stringstream msg;
510  msg << "Invalid alignment string: '" << cmp_str << "'";
511  throw parse_error(msg.str());
512 }
513 
515 {
516  adjust_last_row();
517  last_row_.clear();
520  contents_height_ = std::max<int>(curr_loc_.second + curr_row_height_, contents_height_);
522 }
523 
525 {
526  for (std::list<item *>::iterator it = last_row_.begin(); it != last_row_.end(); ++it) {
527  item &itm = *(*it);
528  const int gap = curr_row_height_ - itm.rect_.h;
529  itm.rect_.y += gap / 2;
530  }
531 }
532 
534 {
535  const int total_w = get_max_x(curr_loc_.second, curr_row_height_);
536  return total_w - curr_loc_.first;
537 }
538 
540 {
541  const SDL_Rect& loc = inner_location();
542  auto clipper = draw::reduce_clip(loc);
543  for(std::list<item>::const_iterator it = items_.begin(), end = items_.end(); it != end; ++it) {
544  SDL_Rect dst = it->rect_;
545  dst.y -= get_position();
546  if (dst.y < static_cast<int>(loc.h) && dst.y + it->rect_.h > 0) {
547  dst.x += loc.x;
548  dst.y += loc.y;
549  if (it->box) {
550  for (int i = 0; i < box_width; ++i) {
551  SDL_Rect draw_rect {
552  dst.x,
553  dst.y,
554  it->rect_.w - i * 2,
555  it->rect_.h - i * 2
556  };
557  draw::fill(draw_rect, 0, 0, 0, 0);
558  ++dst.x;
559  ++dst.y;
560  }
561  }
562  draw::blit(it->tex, dst);
563  }
564  }
565 }
566 
567 void help_text_area::scroll(unsigned int)
568 {
569  // Nothing will be done on the actual scroll event. The scroll
570  // position is checked when drawing instead and things drawn
571  // accordingly.
572  queue_redraw();
573 }
574 
576  return item.rect_.contains(x_, y_);
577 }
578 
579 std::string help_text_area::ref_at(const int x, const int y)
580 {
581  const int local_x = x - location().x;
582  const int local_y = y - location().y;
583  if (local_y < height() && local_y > 0) {
584  const int cmp_y = local_y + get_position();
585  const std::list<item>::const_iterator it =
586  std::find_if(items_.begin(), items_.end(), item_at(local_x, cmp_y));
587  if (it != items_.end()) {
588  if (!(*it).ref_to.empty()) {
589  return ((*it).ref_to);
590  }
591  }
592  }
593  return "";
594 }
595 
596 } // 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:384
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:457
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:1007
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 (...)
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:83
const bool & debug
Definition: game_config.cpp:91
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:1501
std::string bold(const std::string &s)
Definition: help_impl.hpp:404
const int box_width
Definition: help_impl.cpp:78
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:412
const int title2_size
Definition: help_impl.cpp:77
const int normal_font_size
Definition: help_impl.cpp:79
std::string remove_first_space(const std::string &text)
Definition: help_impl.cpp:1493
std::string jump_to(const unsigned pos)
Definition: help_impl.hpp:390
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:1474
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:1289
color_t string_to_color(const std::string &cmp_str)
Return the color the string represents.
Definition: help_impl.cpp:1450
std::string jump(const unsigned amount)
Definition: help_impl.hpp:397
const int title_size
Definition: help_impl.cpp:76
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
int font_scaled(int size)
Definition: general.cpp:500
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:212
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:144
A topic contains a title, an id and some text.
Definition: help_impl.hpp:111
topic_text text
Definition: help_impl.hpp:136
std::string title
Definition: help_impl.hpp:135
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