The Battle for Wesnoth  1.15.13+dev
help_text_area.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "help/help_text_area.hpp"
16 
17 #include "config.hpp" // for config, etc
18 #include "game_config.hpp" // for debug
19 #include "font/sdl_ttf_compat.hpp"
20 #include "help/help_impl.hpp" // for parse_error, box_width, etc
21 #include "lexical_cast.hpp"
22 #include "picture.hpp" // for get_image
23 #include "log.hpp" // for LOG_STREAM, log_domain, etc
24 #include "preferences/general.hpp" // for font_scaled
25 #include "sdl/rect.hpp" // for draw_rectangle, etc
26 #include "serialization/parser.hpp" // for read, write
27 #include "video.hpp" // for CVideo
28 
29 #include <algorithm> // for max, min, find_if
30 #include <ostream> // for operator<<, stringstream, etc
31 #include <vector> // for vector, etc
32 
33 static lg::log_domain log_display("display");
34 #define WRN_DP LOG_STREAM(warn, log_display)
35 
36 static lg::log_domain log_help("help");
37 #define ERR_HP LOG_STREAM(err, log_help)
38 #define WRN_HP LOG_STREAM(warn, log_help)
39 #define DBG_HP LOG_STREAM(debug, log_help)
40 
41 namespace help {
42 
43 help_text_area::help_text_area(CVideo &video, const section &toplevel) :
44  gui::scrollarea(video),
45  items_(),
46  last_row_(),
47  toplevel_(toplevel),
48  shown_topic_(nullptr),
49  title_spacing_(16),
50  curr_loc_(0, 0),
51  min_row_height_(4 + font::get_max_height(normal_font_size)),
52  curr_row_height_(min_row_height_),
53  contents_height_(0)
54 {
55  set_scroll_rate(40);
56 }
57 
58 void help_text_area::set_inner_location(const SDL_Rect& rect)
59 {
60  bg_register(rect);
61  if (shown_topic_)
62  set_items();
63 }
64 
66 {
67  shown_topic_ = &t;
68  set_items();
69  set_dirty(true);
70  DBG_HP << "Showing topic: " << t.id << ": " << t.title << std::endl;
71 }
72 
73 
74 help_text_area::item::item(surface surface, int x, int y, const std::string& _text,
75  const std::string& reference_to, bool _floating,
76  bool _box, ALIGNMENT alignment) :
77  rect(),
78  surf(surface),
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 ? surface->w + box_width * 2 : surface->w;
87  rect.h = box ? surface->h + box_width * 2 : surface->h;
88 }
89 
90 help_text_area::item::item(surface surface, int x, int y, bool _floating,
91  bool _box, ALIGNMENT alignment) :
92  rect(),
93  surf(surface),
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 ? surface->w + box_width * 2 : surface->w;
102  rect.h = box ? surface->h + box_width * 2 : surface->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 =
116  if (surf != nullptr) {
117  add_item(item(surf, 0, 0, show_title));
118  curr_loc_.second = title_spacing_;
120  down_one_line();
121  }
122  // Parse and add the text.
123  const std::vector<std::string>& parsed_items = shown_topic_->text.parsed_text();
124  std::vector<std::string>::const_iterator it;
125  for (it = parsed_items.begin(); it != parsed_items.end(); ++it) {
126  if (!(*it).empty() && (*it)[0] == '[') {
127  // Should be parsed as WML.
128  try {
129  config cfg;
130  std::istringstream stream(*it);
131  read(cfg, stream);
132 
133 #define TRY(name) do { \
134  if (config &child = cfg.child(#name)) \
135  handle_##name##_cfg(child); \
136  } while (0)
137 
138  TRY(ref);
139  TRY(img);
140  TRY(bold);
141  TRY(italic);
142  TRY(header);
143  TRY(jump);
144  TRY(format);
145 
146 #undef TRY
147 
148  }
149  catch (config::error& e) {
150  std::stringstream msg;
151  msg << "Error when parsing help markup as WML: '" << e.message << "'";
152  throw parse_error(msg.str());
153  }
154  }
155  else {
156  add_text_item(*it);
157  }
158  }
159  down_one_line(); // End the last line.
160  int h = height();
161  set_position(0);
163  set_shown_size(h);
164 }
165 
167 {
168  const std::string dst = cfg["dst"];
169  const std::string text = cfg["text"];
170  bool force = cfg["force"].to_bool();
171 
172  if (dst.empty()) {
173  std::stringstream msg;
174  msg << "Ref markup must have dst attribute. Please submit a bug"
175  " report if you have not modified the game files yourself. Erroneous config: ";
176  write(msg, cfg);
177  throw parse_error(msg.str());
178  }
179 
180  if (find_topic(toplevel_, dst) == nullptr && !force) {
181  // detect the broken link but quietly silence the hyperlink for normal user
182  add_text_item(text, game_config::debug ? dst : "", true);
183 
184  // FIXME: workaround: if different campaigns define different
185  // terrains, some terrains available in one campaign will
186  // appear in the list of seen terrains, and be displayed in the
187  // help, even if the current campaign does not handle such
188  // terrains. This will lead to the unit page generator creating
189  // invalid references.
190  //
191  // Disabling this is a kludgey workaround until the
192  // encountered_terrains system is fixed
193  //
194  // -- Ayin apr 8 2005
195 #if 0
196  if (game_config::debug) {
197  std::stringstream msg;
198  msg << "Reference to non-existent topic '" << dst
199  << "'. Please submit a bug report if you have not"
200  "modified the game files yourself. Erroneous config: ";
201  write(msg, cfg);
202  throw parse_error(msg.str());
203  }
204 #endif
205  } else {
206  add_text_item(text, dst);
207  }
208 }
209 
211 {
212  const std::string src = cfg["src"];
213  const std::string align = cfg["align"];
214  bool floating = cfg["float"].to_bool();
215  bool box = cfg["box"].to_bool(true);
216  if (src.empty()) {
217  throw parse_error("Img markup must have src attribute.");
218  }
219  add_img_item(src, align, floating, box);
220 }
221 
223 {
224  const std::string text = cfg["text"];
225  if (text.empty()) {
226  throw parse_error("Bold markup must have text attribute.");
227  }
228  add_text_item(text, "", false, -1, true);
229 }
230 
232 {
233  const std::string text = cfg["text"];
234  if (text.empty()) {
235  throw parse_error("Italic markup must have text attribute.");
236  }
237  add_text_item(text, "", false, -1, false, true);
238 }
239 
241 {
242  const std::string text = cfg["text"];
243  if (text.empty()) {
244  throw parse_error("Header markup must have text attribute.");
245  }
246  add_text_item(text, "", false, title2_size, true);
247 }
248 
250 {
251  const std::string amount_str = cfg["amount"];
252  const std::string to_str = cfg["to"];
253  if (amount_str.empty() && to_str.empty()) {
254  throw parse_error("Jump markup must have either a to or an amount attribute.");
255  }
256  unsigned jump_to = curr_loc_.first;
257  if (!amount_str.empty()) {
258  unsigned amount;
259  try {
260  amount = lexical_cast<unsigned, std::string>(amount_str);
261  }
262  catch (bad_lexical_cast&) {
263  throw parse_error("Invalid amount the amount attribute in jump markup.");
264  }
265  jump_to += amount;
266  }
267  if (!to_str.empty()) {
268  unsigned to;
269  try {
270  to = lexical_cast<unsigned, std::string>(to_str);
271  }
272  catch (bad_lexical_cast&) {
273  throw parse_error("Invalid amount in the to attribute in jump markup.");
274  }
275  if (to < jump_to) {
276  down_one_line();
277  }
278  jump_to = to;
279  }
280  if (jump_to != 0 && static_cast<int>(jump_to) <
282 
283  curr_loc_.first = jump_to;
284  }
285 }
286 
288 {
289  const std::string text = cfg["text"];
290  if (text.empty()) {
291  throw parse_error("Format markup must have text attribute.");
292  }
293  bool bold = cfg["bold"].to_bool();
294  bool italic = cfg["italic"].to_bool();
295  int font_size = cfg["font_size"].to_int(normal_font_size);
296  color_t color = help::string_to_color(cfg["color"]);
297  add_text_item(text, "", false, font_size, bold, italic, color);
298 }
299 
300 void help_text_area::add_text_item(const std::string& text, const std::string& ref_dst,
301  bool broken_link, int _font_size, bool bold, bool italic,
302  color_t text_color
303 )
304 {
305  const int font_size = _font_size < 0 ? normal_font_size : _font_size;
306  // font::line_width(), font::get_rendered_text() are not use scaled font inside
307  const int scaled_font_size = preferences::font_scaled(font_size);
308  if (text.empty())
309  return;
310  const int remaining_width = get_remaining_width();
311  std::size_t first_word_start = text.find_first_not_of(" ");
312  if (first_word_start == std::string::npos) {
313  first_word_start = 0;
314  }
315  if (text[first_word_start] == '\n') {
316  down_one_line();
317  std::string rest_text = text;
318  rest_text.erase(0, first_word_start + 1);
319  add_text_item(rest_text, ref_dst, broken_link, _font_size, bold, italic, text_color);
320  return;
321  }
322  const std::string first_word = get_first_word(text);
323  int state = font::pango_text::STYLE_NORMAL;
324  state |= bold ? font::pango_text::STYLE_BOLD : 0;
325  state |= italic ? font::pango_text::STYLE_ITALIC : 0;
326  if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
327  && remaining_width < font::pango_line_width(first_word, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
328  // The first word does not fit, and we are not at the start of
329  // the line. Move down.
330  down_one_line();
331  std::string s = remove_first_space(text);
332  add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
333  }
334  else {
335  std::vector<std::string> parts = split_in_width(text, font_size, remaining_width);
336  std::string first_part = parts.front();
337  // Always override the color if we have a cross reference.
338  color_t color;
339  if(ref_dst.empty())
340  color = text_color;
341  else if(broken_link)
342  color = font::BAD_COLOR;
343  else
344  color = font::YELLOW_COLOR;
345 
346  // In split_in_width(), no_break_after() and no_break_before() are used(see marked-up_text.cpp).
347  // Thus, even if there is enough remaining_width for the next word,
348  // sometimes empty string is returned from split_in_width().
349  if (first_part.empty()) {
350  down_one_line();
351  }
352  else {
353  surface surf = font::pango_render_text(first_part, scaled_font_size, color, font::pango_text::FONT_STYLE(state));
354  if (surf)
355  add_item(item(surf, curr_loc_.first, curr_loc_.second, first_part, ref_dst));
356  }
357  if (parts.size() > 1) {
358 
359  std::string& s = parts.back();
360 
361  const std::string first_word_before = get_first_word(s);
362  const std::string first_word_after = get_first_word(remove_first_space(s));
363  if (get_remaining_width() >= font::pango_line_width(first_word_after, scaled_font_size, font::pango_text::FONT_STYLE(state))
365  < font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
366  // If the removal of the space made this word fit, we
367  // must move down a line, otherwise it will be drawn
368  // without a space at the end of the line.
369  s = remove_first_space(s);
370  down_one_line();
371  }
372  else if (!(font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))
373  < get_remaining_width())) {
374  s = remove_first_space(s);
375  }
376  add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
377 
378  }
379  }
380 }
381 
382 void help_text_area::add_img_item(const std::string& path, const std::string& alignment,
383  const bool floating, const bool box)
384 {
386  if (!surf)
387  return;
388  ALIGNMENT align = str_to_align(alignment);
389  if (align == HERE && floating) {
390  WRN_DP << "Floating image with align HERE, aligning left." << std::endl;
391  align = LEFT;
392  }
393  const int width = surf->w + (box ? box_width * 2 : 0);
394  int xpos;
395  int ypos = curr_loc_.second;
396  int text_width = inner_location().w;
397  switch (align) {
398  case HERE:
399  xpos = curr_loc_.first;
400  break;
401  case LEFT:
402  default:
403  xpos = 0;
404  break;
405  case MIDDLE:
406  xpos = text_width / 2 - width / 2 - (box ? box_width : 0);
407  break;
408  case RIGHT:
409  xpos = text_width - width - (box ? box_width * 2 : 0);
410  break;
411  }
412  if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
413  && (xpos < curr_loc_.first || xpos + width > text_width)) {
414  down_one_line();
415  add_img_item(path, alignment, floating, box);
416  }
417  else {
418  if (!floating) {
419  curr_loc_.first = xpos;
420  }
421  else {
422  ypos = get_y_for_floating_img(width, xpos, ypos);
423  }
424  add_item(item(surf, xpos, ypos, floating, box, align));
425  }
426 }
427 
428 int help_text_area::get_y_for_floating_img(const int width, const int x, const int desired_y)
429 {
430  int min_y = desired_y;
431  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
432  const item& itm = *it;
433  if (itm.floating) {
434  if ((itm.rect.x + itm.rect.w > x && itm.rect.x < x + width)
435  || (itm.rect.x > x && itm.rect.x < x + width)) {
436  min_y = std::max<int>(min_y, itm.rect.y + itm.rect.h);
437  }
438  }
439  }
440  return min_y;
441 }
442 
443 int help_text_area::get_min_x(const int y, const int height)
444 {
445  int min_x = 0;
446  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
447  const item& itm = *it;
448  if (itm.floating) {
449  if (itm.rect.y < y + height && itm.rect.y + itm.rect.h > y && itm.align == LEFT) {
450  min_x = std::max<int>(min_x, itm.rect.w + 5);
451  }
452  }
453  }
454  return min_x;
455 }
456 
457 int help_text_area::get_max_x(const int y, const int height)
458 {
459  int text_width = inner_location().w;
460  int max_x = text_width;
461  for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
462  const item& itm = *it;
463  if (itm.floating) {
464  if (itm.rect.y < y + height && itm.rect.y + itm.rect.h > y) {
465  if (itm.align == RIGHT) {
466  max_x = std::min<int>(max_x, text_width - itm.rect.w - 5);
467  } else if (itm.align == MIDDLE) {
468  max_x = std::min<int>(max_x, text_width / 2 - itm.rect.w / 2 - 5);
469  }
470  }
471  }
472  }
473  return max_x;
474 }
475 
477 {
478  items_.push_back(itm);
479  if (!itm.floating) {
480  curr_loc_.first += itm.rect.w;
481  curr_row_height_ = std::max<int>(itm.rect.h, curr_row_height_);
482  contents_height_ = std::max<int>(contents_height_, curr_loc_.second + curr_row_height_);
483  last_row_.push_back(&items_.back());
484  }
485  else {
486  if (itm.align == LEFT) {
487  curr_loc_.first = itm.rect.w + 5;
488  }
489  contents_height_ = std::max<int>(contents_height_, itm.rect.y + itm.rect.h);
490  }
491 }
492 
493 
495 {
496  if (cmp_str == "left") {
497  return LEFT;
498  } else if (cmp_str == "middle") {
499  return MIDDLE;
500  } else if (cmp_str == "right") {
501  return RIGHT;
502  } else if (cmp_str == "here" || cmp_str.empty()) { // Make the empty string be "here" alignment.
503  return HERE;
504  }
505  std::stringstream msg;
506  msg << "Invalid alignment string: '" << cmp_str << "'";
507  throw parse_error(msg.str());
508 }
509 
511 {
512  adjust_last_row();
513  last_row_.clear();
515  curr_row_height_ = min_row_height_;
516  contents_height_ = std::max<int>(curr_loc_.second + curr_row_height_, contents_height_);
517  curr_loc_.first = get_min_x(curr_loc_.second, curr_row_height_);
518 }
519 
521 {
522  for (std::list<item *>::iterator it = last_row_.begin(); it != last_row_.end(); ++it) {
523  item &itm = *(*it);
524  const int gap = curr_row_height_ - itm.rect.h;
525  itm.rect.y += gap / 2;
526  }
527 }
528 
530 {
531  const int total_w = get_max_x(curr_loc_.second, curr_row_height_);
532  return total_w - curr_loc_.first;
533 }
534 
536 {
537  const SDL_Rect& loc = inner_location();
538  bg_restore();
539  surface& screen = video().getSurface();
540  clip_rect_setter clip_rect_set(screen, &loc);
541  for(std::list<item>::const_iterator it = items_.begin(), end = items_.end(); it != end; ++it) {
542  SDL_Rect dst = it->rect;
543  dst.y -= get_position();
544  if (dst.y < static_cast<int>(loc.h) && dst.y + it->rect.h > 0) {
545  dst.x += loc.x;
546  dst.y += loc.y;
547  if (it->box) {
548  for (int i = 0; i < box_width; ++i) {
549  SDL_Rect draw_rect {
550  dst.x,
551  dst.y,
552  it->rect.w - i * 2,
553  it->rect.h - i * 2
554  };
555 
556  // SDL 2.0.10's render batching changes result in the
557  // surface's clipping rectangle being overridden even if
558  // no render clipping rectangle set operaton was queued,
559  // so let's not use the render API to draw the rectangle.
560  SDL_FillRect(screen, &draw_rect, 0);
561  ++dst.x;
562  ++dst.y;
563  }
564  }
565  sdl_blit(it->surf, nullptr, screen, &dst);
566  }
567  }
568 }
569 
570 void help_text_area::scroll(unsigned int)
571 {
572  // Nothing will be done on the actual scroll event. The scroll
573  // position is checked when drawing instead and things drawn
574  // accordingly.
575  set_dirty(true);
576 }
577 
579  return sdl::point_in_rect(x_, y_, item.rect);
580 }
581 
582 std::string help_text_area::ref_at(const int x, const int y)
583 {
584  const int local_x = x - location().x;
585  const int local_y = y - location().y;
586  if (local_y < height() && local_y > 0) {
587  const int cmp_y = local_y + get_position();
588  const std::list<item>::const_iterator it =
589  std::find_if(items_.begin(), items_.end(), item_at(local_x, cmp_y));
590  if (it != items_.end()) {
591  if (!(*it).ref_to.empty()) {
592  return ((*it).ref_to);
593  }
594  }
595  }
596  return "";
597 }
598 
599 } // end namespace help
std::string jump_to(const unsigned pos)
Definition: help_impl.hpp:387
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:815
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:107
virtual void set_inner_location(const SDL_Rect &rect)
const int title_size
Definition: help_impl.cpp:78
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:145
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:31
Thrown when the help system fails to parse something.
Definition: help_impl.hpp:208
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:109
void set_scroll_rate(unsigned r)
Definition: scrollarea.cpp:121
const int normal_font_size
Definition: help_impl.cpp:81
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:896
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:482
std::string bold(const std::string &s)
Definition: help_impl.hpp:401
topic const * shown_topic_
std::string id
Definition: help_impl.hpp:136
void set_full_size(unsigned h)
Definition: scrollarea.cpp:114
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
Definition: parser.cpp:763
void set_dirty(bool dirty=true)
Definition: widget.cpp:207
void set_position(unsigned pos)
Definition: scrollarea.cpp:92
void read(config &cfg, std::istream &in, abstract_validator *validator)
Definition: parser.cpp:626
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:464
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:38
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:22
void handle_header_cfg(const config &cfg)
An item that is displayed in the text area.
const int box_width
Definition: help_impl.cpp:80
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:940
static map_location::DIRECTION s
SDL_Rect inner_location() const
Definition: scrollarea.cpp:135
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:83
void down_one_line()
Move the current input point to the next line.
std::string jump(const unsigned amount)
Definition: help_impl.hpp:394
Contains the SDL_Rect helper code.
void handle_format_cfg(const config &cfg)
double t
Definition: astarsearch.cpp:64
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:387
Standard logging facilities (interface).
std::string message
Definition: exceptions.hpp:29
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:79
A topic contains a title, an id and some text.
Definition: help_impl.hpp:111
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:56
SDL_Rect rect
Relative coordinates of this item.
std::string title
Definition: help_impl.hpp:136
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:31
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:59
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:24
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:137
unsigned get_position() const
Definition: scrollarea.cpp:82
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.