The Battle for Wesnoth  1.17.0-dev
help_text_area.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2021
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 "game_config.hpp" // for debug
20 #include "font/sdl_ttf_compat.hpp"
21 #include "help/help_impl.hpp" // for parse_error, box_width, etc
22 #include "lexical_cast.hpp"
23 #include "picture.hpp" // for get_image
24 #include "log.hpp" // for LOG_STREAM, log_domain, etc
25 #include "preferences/general.hpp" // for font_scaled
26 #include "sdl/rect.hpp" // for draw_rectangle, etc
27 #include "serialization/parser.hpp" // for read, write
28 #include "video.hpp" // for CVideo
29 
30 #include <algorithm> // for max, min, find_if
31 #include <ostream> // for operator<<, stringstream, etc
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 
44 help_text_area::help_text_area(CVideo &video, const section &toplevel) :
45  gui::scrollarea(video),
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  bg_register(rect);
62  if (shown_topic_)
63  set_items();
64 }
65 
67 {
68  shown_topic_ = &t;
69  set_items();
70  set_dirty(true);
71  DBG_HP << "Showing topic: " << t.id << ": " << t.title << std::endl;
72 }
73 
74 
75 help_text_area::item::item(surface surface, int x, int y, const std::string& _text,
76  const std::string& reference_to, bool _floating,
77  bool _box, ALIGNMENT alignment) :
78  rect(),
79  surf(surface),
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 ? surface->w + box_width * 2 : surface->w;
88  rect.h = box ? surface->h + box_width * 2 : surface->h;
89 }
90 
91 help_text_area::item::item(surface surface, int x, int y, bool _floating,
92  bool _box, ALIGNMENT alignment) :
93  rect(),
94  surf(surface),
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 ? surface->w + box_width * 2 : surface->w;
103  rect.h = box ? surface->h + box_width * 2 : surface->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 =
117  if (surf != nullptr) {
118  add_item(item(surf, 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 (config &child = cfg.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  surface surf = font::pango_render_text(first_part, scaled_font_size, color, font::pango_text::FONT_STYLE(state));
355  if (surf)
356  add_item(item(surf, curr_loc_.first, curr_loc_.second, first_part, ref_dst));
357  }
358  if (parts.size() > 1) {
359 
360  std::string& s = parts.back();
361 
362  const std::string first_word_before = get_first_word(s);
363  const std::string first_word_after = get_first_word(remove_first_space(s));
364  if (get_remaining_width() >= font::pango_line_width(first_word_after, scaled_font_size, font::pango_text::FONT_STYLE(state))
366  < font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
367  // If the removal of the space made this word fit, we
368  // must move down a line, otherwise it will be drawn
369  // without a space at the end of the line.
370  s = remove_first_space(s);
371  down_one_line();
372  }
373  else if (!(font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))
374  < get_remaining_width())) {
375  s = remove_first_space(s);
376  }
377  add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
378 
379  }
380  }
381 }
382 
383 void help_text_area::add_img_item(const std::string& path, const std::string& alignment,
384  const bool floating, const bool box)
385 {
387  if (!surf)
388  return;
389  ALIGNMENT align = str_to_align(alignment);
390  if (align == HERE && floating) {
391  WRN_DP << "Floating image with align HERE, aligning left." << std::endl;
392  align = LEFT;
393  }
394  const int width = surf->w + (box ? box_width * 2 : 0);
395  int xpos;
396  int ypos = curr_loc_.second;
397  int text_width = inner_location().w;
398  switch (align) {
399  case HERE:
400  xpos = curr_loc_.first;
401  break;
402  case LEFT:
403  default:
404  xpos = 0;
405  break;
406  case MIDDLE:
407  xpos = text_width / 2 - width / 2 - (box ? box_width : 0);
408  break;
409  case RIGHT:
410  xpos = text_width - width - (box ? box_width * 2 : 0);
411  break;
412  }
413  if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
414  && (xpos < curr_loc_.first || xpos + width > text_width)) {
415  down_one_line();
416  add_img_item(path, alignment, floating, box);
417  }
418  else {
419  if (!floating) {
420  curr_loc_.first = xpos;
421  }
422  else {
423  ypos = get_y_for_floating_img(width, xpos, ypos);
424  }
425  add_item(item(surf, xpos, ypos, floating, box, align));
426  }
427 }
428 
429 int help_text_area::get_y_for_floating_img(const int width, const int x, const int desired_y)
430 {
431  int min_y = desired_y;
432  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
433  const item& itm = *it;
434  if (itm.floating) {
435  if ((itm.rect.x + itm.rect.w > x && itm.rect.x < x + width)
436  || (itm.rect.x > x && itm.rect.x < x + width)) {
437  min_y = std::max<int>(min_y, itm.rect.y + itm.rect.h);
438  }
439  }
440  }
441  return min_y;
442 }
443 
444 int help_text_area::get_min_x(const int y, const int height)
445 {
446  int min_x = 0;
447  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
448  const item& itm = *it;
449  if (itm.floating) {
450  if (itm.rect.y < y + height && itm.rect.y + itm.rect.h > y && itm.align == LEFT) {
451  min_x = std::max<int>(min_x, itm.rect.w + 5);
452  }
453  }
454  }
455  return min_x;
456 }
457 
458 int help_text_area::get_max_x(const int y, const int height)
459 {
460  int text_width = inner_location().w;
461  int max_x = text_width;
462  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
463  const item& itm = *it;
464  if (itm.floating) {
465  if (itm.rect.y < y + height && itm.rect.y + itm.rect.h > y) {
466  if (itm.align == RIGHT) {
467  max_x = std::min<int>(max_x, text_width - itm.rect.w - 5);
468  } else if (itm.align == MIDDLE) {
469  max_x = std::min<int>(max_x, text_width / 2 - itm.rect.w / 2 - 5);
470  }
471  }
472  }
473  }
474  return max_x;
475 }
476 
478 {
479  items_.push_back(itm);
480  if (!itm.floating) {
481  curr_loc_.first += itm.rect.w;
482  curr_row_height_ = std::max<int>(itm.rect.h, curr_row_height_);
483  contents_height_ = std::max<int>(contents_height_, curr_loc_.second + curr_row_height_);
484  last_row_.push_back(&items_.back());
485  }
486  else {
487  if (itm.align == LEFT) {
488  curr_loc_.first = itm.rect.w + 5;
489  }
490  contents_height_ = std::max<int>(contents_height_, itm.rect.y + itm.rect.h);
491  }
492 }
493 
494 
496 {
497  if (cmp_str == "left") {
498  return LEFT;
499  } else if (cmp_str == "middle") {
500  return MIDDLE;
501  } else if (cmp_str == "right") {
502  return RIGHT;
503  } else if (cmp_str == "here" || cmp_str.empty()) { // Make the empty string be "here" alignment.
504  return HERE;
505  }
506  std::stringstream msg;
507  msg << "Invalid alignment string: '" << cmp_str << "'";
508  throw parse_error(msg.str());
509 }
510 
512 {
513  adjust_last_row();
514  last_row_.clear();
516  curr_row_height_ = min_row_height_;
517  contents_height_ = std::max<int>(curr_loc_.second + curr_row_height_, contents_height_);
518  curr_loc_.first = get_min_x(curr_loc_.second, curr_row_height_);
519 }
520 
522 {
523  for (std::list<item *>::iterator it = last_row_.begin(); it != last_row_.end(); ++it) {
524  item &itm = *(*it);
525  const int gap = curr_row_height_ - itm.rect.h;
526  itm.rect.y += gap / 2;
527  }
528 }
529 
531 {
532  const int total_w = get_max_x(curr_loc_.second, curr_row_height_);
533  return total_w - curr_loc_.first;
534 }
535 
537 {
538  const SDL_Rect& loc = inner_location();
539  bg_restore();
540  surface& screen = video().getSurface();
541  clip_rect_setter clip_rect_set(screen, &loc);
542  for(std::list<item>::const_iterator it = items_.begin(), end = items_.end(); it != end; ++it) {
543  SDL_Rect dst = it->rect;
544  dst.y -= get_position();
545  if (dst.y < static_cast<int>(loc.h) && dst.y + it->rect.h > 0) {
546  dst.x += loc.x;
547  dst.y += loc.y;
548  if (it->box) {
549  for (int i = 0; i < box_width; ++i) {
550  SDL_Rect draw_rect {
551  dst.x,
552  dst.y,
553  it->rect.w - i * 2,
554  it->rect.h - i * 2
555  };
556 
557  // SDL 2.0.10's render batching changes result in the
558  // surface's clipping rectangle being overridden even if
559  // no render clipping rectangle set operaton was queued,
560  // so let's not use the render API to draw the rectangle.
561  SDL_FillRect(screen, &draw_rect, 0);
562  ++dst.x;
563  ++dst.y;
564  }
565  }
566  sdl_blit(it->surf, nullptr, screen, &dst);
567  }
568  }
569 }
570 
571 void help_text_area::scroll(unsigned int)
572 {
573  // Nothing will be done on the actual scroll event. The scroll
574  // position is checked when drawing instead and things drawn
575  // accordingly.
576  set_dirty(true);
577 }
578 
580  return sdl::point_in_rect(x_, y_, item.rect);
581 }
582 
583 std::string help_text_area::ref_at(const int x, const int y)
584 {
585  const int local_x = x - location().x;
586  const int local_y = y - location().y;
587  if (local_y < height() && local_y > 0) {
588  const int cmp_y = local_y + get_position();
589  const std::list<item>::const_iterator it =
590  std::find_if(items_.begin(), items_.end(), item_at(local_x, cmp_y));
591  if (it != items_.end()) {
592  if (!(*it).ref_to.empty()) {
593  return ((*it).ref_to);
594  }
595  }
596  }
597  return "";
598 }
599 
600 } // end namespace help
std::string jump_to(const unsigned pos)
Definition: help_impl.hpp:388
int get_max_x(const int y, const int height=0)
Analogous with get_min_x but return the maximum X.
surface get_image(const image::locator &i_locator, TYPE type)
Caches and returns an image.
Definition: picture.cpp:816
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 (...)
help_text_area(CVideo &video, const section &toplevel)
void set_shown_size(unsigned h)
Definition: scrollarea.cpp:108
virtual void set_inner_location(const SDL_Rect &rect)
const int title_size
Definition: help_impl.cpp:79
Collection of helper functions relating to Pango formatting.
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.
std::string remove_first_space(const std::string &text)
Definition: help_impl.cpp:1420
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:146
int get_remaining_width()
Return the width that remain on the line the current input point is at.
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...
New lexcical_cast header.
Definition: video.hpp:32
Thrown when the help system fails to parse something.
Definition: help_impl.hpp:209
General purpose widgets.
std::list< item * > last_row_
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
void set_scroll_rate(unsigned r)
Definition: scrollarea.cpp:122
const int normal_font_size
Definition: help_impl.cpp:82
void set_items()
Update the vector with the items of the shown topic, creating surfaces for everything and putting thi...
To lexical_cast(From value)
Lexical cast converts one type to another.
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:897
color_t string_to_color(const std::string &cmp_str)
Return the color the string represents.
Definition: help_impl.cpp:1377
#define TRY(name)
Definitions for the interface to Wesnoth Markup Language (WML).
surface & getSurface()
Returns a reference to the framebuffer.
Definition: video.cpp:483
std::string bold(const std::string &s)
Definition: help_impl.hpp:402
topic const * shown_topic_
std::string id
Definition: help_impl.hpp:137
void set_full_size(unsigned h)
Definition: scrollarea.cpp:115
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:764
void set_dirty(bool dirty=true)
Definition: widget.cpp:207
void set_position(unsigned pos)
Definition: scrollarea.cpp:93
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:627
void add_item(const item &itm)
Add an item to the internal list, update the locations and row height.
std::string ref_at(const int x, const int y)
Return the ID that is cross-referenced at the (screen) coordinates x, y.
const SDL_Rect & location() const
Definition: widget.cpp:134
int font_scaled(int size)
Definition: general.cpp:470
virtual void scroll(unsigned int pos)
std::list< item > items_
const section & toplevel_
void bg_register(const SDL_Rect &rect)
Definition: widget.cpp:99
std::string path
Definition: game_config.cpp:39
void handle_ref_cfg(const config &cfg)
const unsigned min_row_height_
const color_t YELLOW_COLOR
void handle_img_cfg(const config &cfg)
const color_t NORMAL_COLOR
#define WRN_DP
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:23
void handle_header_cfg(const config &cfg)
An item that is displayed in the text area.
const int box_width
Definition: help_impl.cpp:81
void handle_italic_cfg(const config &cfg)
void handle_bold_cfg(const config &cfg)
void show_topic(const topic &t)
Display the topic.
void adjust_last_row()
Adjust the heights of the items in the last row to make it look good.
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.
std::size_t i
Definition: function.cpp:967
static map_location::DIRECTION s
SDL_Rect inner_location() const
Definition: scrollarea.cpp:136
std::pair< int, int > curr_loc_
The current input location when creating items.
item(surface surface, int x, int y, const std::string &text="", const std::string &reference_to="", bool floating=false, bool box=false, ALIGNMENT alignment=HERE)
int width() const
Definition: widget.cpp:124
int w
const bool & debug
int height() const
Definition: widget.cpp:129
void bg_restore() const
Definition: widget.cpp:241
static lg::log_domain log_help("help")
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...
CVideo & video() const
Definition: widget.hpp:84
void down_one_line()
Move the current input point to the next line.
std::string jump(const unsigned amount)
Definition: help_impl.hpp:395
Contains the SDL_Rect helper code.
void handle_format_cfg(const config &cfg)
double t
Definition: astarsearch.cpp:65
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:1216
const std::vector< std::string > & parsed_text() const
Definition: help_impl.cpp:388
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:30
surface 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 surface containing the rendered text.
const int title2_size
Definition: help_impl.cpp:80
A topic contains a title, an id and some text.
Definition: help_impl.hpp:112
ALIGNMENT str_to_align(const std::string &s)
Convert a string to an alignment.
bool operator()(const item &) const
#define DBG_HP
#define e
Definition: help.cpp:57
SDL_Rect rect
Relative coordinates of this item.
std::string title
Definition: help_impl.hpp:137
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:32
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
static lg::log_domain log_display("display")
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:1428
int contents_height_
The height of all items in total.
Thrown when a lexical_cast fails.
Transitional API for porting SDL_ttf-based code to Pango.
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
void handle_jump_cfg(const config &cfg)
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:1401
topic_text text
Definition: help_impl.hpp:138
unsigned get_position() const
Definition: scrollarea.cpp:83
const color_t BAD_COLOR
Function object to find an item at the specified coordinates.
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.