The Battle for Wesnoth  1.19.0-dev
canvas.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2007 - 2024
3  by Mark de Wever <koraq@xs4all.nl>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  * Implementation of canvas.hpp.
19  */
20 
21 #define GETTEXT_DOMAIN "wesnoth-lib"
22 
23 #include "gui/core/canvas.hpp"
25 
26 #include "draw.hpp"
27 #include "draw_manager.hpp"
28 #include "font/text.hpp"
29 #include "formatter.hpp"
30 #include "gettext.hpp"
32 #include "gui/core/log.hpp"
33 #include "gui/widgets/helper.hpp"
34 #include "picture.hpp"
35 #include "sdl/point.hpp"
36 #include "sdl/rect.hpp"
37 #include "sdl/texture.hpp"
38 #include "sdl/utils.hpp" // blur_surface
39 #include "video.hpp" // read_pixels_low_res, only used for blurring
40 #include "wml_exception.hpp"
41 
42 namespace gui2
43 {
44 
45 /***** ***** ***** ***** ***** LINE ***** ***** ***** ***** *****/
46 
48  : shape(cfg)
49  , x1_(cfg["x1"])
50  , y1_(cfg["y1"])
51  , x2_(cfg["x2"])
52  , y2_(cfg["y2"])
53  , color_(cfg["color"])
54  , thickness_(cfg["thickness"])
55 {
56  const std::string& debug = (cfg["debug"]);
57  if(!debug.empty()) {
58  DBG_GUI_P << "Line: found debug message '" << debug << "'.";
59  }
60 }
61 
63 {
64  /**
65  * @todo formulas are now recalculated every draw cycle which is a bit silly
66  * unless there has been a resize. So to optimize we should use an extra
67  * flag or do the calculation in a separate routine.
68  */
69 
70  const unsigned x1 = x1_(variables);
71  const unsigned y1 = y1_(variables);
72  const unsigned x2 = x2_(variables);
73  const unsigned y2 = y2_(variables);
74 
75  DBG_GUI_D << "Line: draw from " << x1 << ',' << y1 << " to " << x2 << ',' << y2 << ".";
76 
77  // @todo FIXME respect the thickness.
78 
79  draw::line(x1, y1, x2, y2, color_(variables));
80 }
81 
82 /***** ***** ***** ***** ***** Rectangle ***** ***** ***** ***** *****/
83 
85  : rect_bounded_shape(cfg)
86  , border_thickness_(cfg["border_thickness"])
87  , border_color_(cfg["border_color"], color_t::null_color())
88  , fill_color_(cfg["fill_color"], color_t::null_color())
89 {
90  // Check if a raw color string evaluates to a null color.
91  if(!border_color_.has_formula() && border_color_().null()) {
93  }
94 
95  const std::string& debug = (cfg["debug"]);
96  if(!debug.empty()) {
97  DBG_GUI_P << "Rectangle: found debug message '" << debug << "'.";
98  }
99 }
100 
102 {
103  const int x = x_(variables);
104  const int y = y_(variables);
105  const int w = w_(variables);
106  const int h = h_(variables);
107 
108  const color_t fill_color = fill_color_(variables);
109 
110  // Fill the background, if applicable
111  if(!fill_color.null()) {
112  DBG_GUI_D << "fill " << fill_color;
113  draw::set_color(fill_color);
114 
115  const SDL_Rect area {
116  x + border_thickness_,
117  y + border_thickness_,
118  w - (border_thickness_ * 2),
119  h - (border_thickness_ * 2)
120  };
121 
122  draw::fill(area);
123  }
124 
125  const color_t border_color = border_color_(variables);
126 
127  // Draw the border
128  draw::set_color(border_color);
129  DBG_GUI_D << "border thickness " << border_thickness_
130  << ", colour " << border_color;
131  for(int i = 0; i < border_thickness_; ++i) {
132  const SDL_Rect dimensions {
133  x + i,
134  y + i,
135  w - (i * 2),
136  h - (i * 2)
137  };
138 
139  draw::rect(dimensions);
140  }
141 }
142 
143 /***** ***** ***** ***** ***** Rounded Rectangle ***** ***** ***** ***** *****/
144 
146  : rect_bounded_shape(cfg)
147  , r_(cfg["corner_radius"])
148  , border_thickness_(cfg["border_thickness"])
149  , border_color_(cfg["border_color"], color_t::null_color())
150  , fill_color_(cfg["fill_color"], color_t::null_color())
151 {
152  // Check if a raw color string evaluates to a null color.
153  if(!border_color_.has_formula() && border_color_().null()) {
154  border_thickness_ = 0;
155  }
156 
157  const std::string& debug = (cfg["debug"]);
158  if(!debug.empty()) {
159  DBG_GUI_P << "Rounded Rectangle: found debug message '" << debug << "'.";
160  }
161 }
162 
164 {
165  const int x = x_(variables);
166  const int y = y_(variables);
167  const int w = w_(variables);
168  const int h = h_(variables);
169  const int r = r_(variables);
170 
171  DBG_GUI_D << "Rounded Rectangle: draw from " << x << ',' << y << " width " << w << " height " << h << ".";
172 
173  const color_t fill_color = fill_color_(variables);
174 
175  // Fill the background, if applicable
176  if(!fill_color.null() && w && h) {
177  draw::set_color(fill_color);
178 
179  draw::fill(rect{x + r, y + border_thickness_, w - r * 2, r - border_thickness_ + 1});
180  draw::fill(rect{x + border_thickness_, y + r + 1, w - border_thickness_ * 2, h - r * 2});
181  draw::fill(rect{x + r, y - r + h + 1, w - r * 2, r - border_thickness_});
182 
183  draw::disc(x + r, y + r, r, 0xc0);
184  draw::disc(x + w - r, y + r, r, 0x03);
185  draw::disc(x + r, y + h - r, r, 0x30);
186  draw::disc(x + w - r, y + h - r, r, 0x0c);
187  }
188 
189  const color_t border_color = border_color_(variables);
190 
191  // Draw the border
192  draw::set_color(border_color);
193 
194  for(int i = 0; i < border_thickness_; ++i) {
195  draw::line(x + r, y + i, x + w - r, y + i);
196  draw::line(x + r, y + h - i, x + w - r, y + h - i);
197 
198  draw::line(x + i, y + r, x + i, y + h - r);
199  draw::line(x + w - i, y + r, x + w - i, y + h - r);
200 
201  draw::circle(x + r, y + r, r - i, 0xc0);
202  draw::circle(x + w - r, y + r, r - i, 0x03);
203  draw::circle(x + r, y + h - r, r - i, 0x30);
204  draw::circle(x + w - r, y + h - r, r - i, 0x0c);
205  }
206 }
207 
208 /***** ***** ***** ***** ***** CIRCLE ***** ***** ***** ***** *****/
209 
211  : shape(cfg)
212  , x_(cfg["x"])
213  , y_(cfg["y"])
214  , radius_(cfg["radius"])
215  , border_color_(cfg["border_color"])
216  , fill_color_(cfg["fill_color"])
217  , border_thickness_(cfg["border_thickness"].to_int(1))
218 {
219  const std::string& debug = (cfg["debug"]);
220  if(!debug.empty()) {
221  DBG_GUI_P << "Circle: found debug message '" << debug << "'.";
222  }
223 }
224 
226 {
227  /**
228  * @todo formulas are now recalculated every draw cycle which is a bit
229  * silly unless there has been a resize. So to optimize we should use an
230  * extra flag or do the calculation in a separate routine.
231  */
232 
233  const int x = x_(variables);
234  const int y = y_(variables);
235  const unsigned radius = radius_(variables);
236 
237  DBG_GUI_D << "Circle: drawn at " << x << ',' << y << " radius " << radius << ".";
238 
239  const color_t fill_color = fill_color_(variables);
240  if(!fill_color.null() && radius) {
241  draw::disc(x, y, radius, fill_color);
242  }
243 
244  const color_t border_color = border_color_(variables);
245  for(unsigned int i = 0; i < border_thickness_; i++) {
246  draw::circle(x, y, radius - i, border_color);
247  }
248 }
249 
250 /***** ***** ***** ***** ***** IMAGE ***** ***** ***** ***** *****/
251 
253  : shape(cfg)
254  , x_(cfg["x"])
255  , y_(cfg["y"])
256  , w_(cfg["w"])
257  , h_(cfg["h"])
258  , image_name_(cfg["name"])
259  , resize_mode_(get_resize_mode(cfg["resize_mode"]))
260  , mirror_(cfg.get_old_attribute("mirror", "vertical_mirror", "image"))
261  , actions_formula_(cfg["actions"], &functions)
262 {
263  const std::string& debug = (cfg["debug"]);
264  if(!debug.empty()) {
265  DBG_GUI_P << "Image: found debug message '" << debug << "'.";
266  }
267 }
268 
269 void image_shape::dimension_validation(unsigned value, const std::string& name, const std::string& key)
270 {
271  const int as_int = static_cast<int>(value);
272 
273  VALIDATE_WITH_DEV_MESSAGE(as_int >= 0, _("Image doesn't fit on canvas."),
274  formatter() << "Image '" << name << "', " << key << " = " << as_int << "."
275  );
276 }
277 
279 {
280  DBG_GUI_D << "Image: draw.";
281 
282  /**
283  * @todo formulas are now recalculated every draw cycle which is a bit
284  * silly unless there has been a resize. So to optimize we should use an
285  * extra flag or do the calculation in a separate routine.
286  */
287  const std::string& name = image_name_(variables);
288 
289  if(name.empty()) {
290  DBG_GUI_D << "Image: formula returned no value, will not be drawn.";
291  return;
292  }
293 
294  // Texture filtering mode must be set on texture creation,
295  // so check whether we need smooth scaling or not here.
299  {
301  }
303 
304  if(!tex) {
305  ERR_GUI_D << "Image: '" << name << "' not found and won't be drawn.";
306  return;
307  }
308 
309  wfl::map_formula_callable local_variables(variables);
310  local_variables.add("image_original_width", wfl::variant(tex.w()));
311  local_variables.add("image_original_height", wfl::variant(tex.h()));
312 
313  int w = w_(local_variables);
314  dimension_validation(w, name, "w");
315 
316  int h = h_(local_variables);
317  dimension_validation(h, name, "h");
318 
319  local_variables.add("image_width", wfl::variant(w ? w : tex.w()));
320  local_variables.add("image_height", wfl::variant(h ? h : tex.h()));
321 
322  const int x = x_(local_variables);
323  const int y = y_(local_variables);
324 
325  // used in gui/dialogs/story_viewer.cpp
326  local_variables.add("clip_x", wfl::variant(x));
327  local_variables.add("clip_y", wfl::variant(y));
328 
329  // Execute the provided actions for this context.
330  wfl::variant(variables.fake_ptr()).execute_variant(actions_formula_.evaluate(local_variables));
331 
332  // If w or h is 0, assume it means the whole image.
333  if (!w) { w = tex.w(); }
334  if (!h) { h = tex.h(); }
335 
336  const SDL_Rect dst_rect { x, y, w, h };
337 
338  // What to do with the image depends on whether we need to tile it or not.
339  switch(resize_mode_) {
340  case resize_mode::tile:
341  draw::tiled(tex, dst_rect, false, mirror_(variables));
342  break;
344  draw::tiled(tex, dst_rect, true, mirror_(variables));
345  break;
347  draw::tiled_highres(tex, dst_rect, false, mirror_(variables));
348  break;
350  // Stretching is identical to scaling in terms of handling.
351  // Is this intended? That's what previous code was doing.
352  case resize_mode::scale:
353  // Filtering mode is set on texture creation above.
354  // Handling is otherwise identical to sharp scaling.
356  if(mirror_(variables)) {
357  draw::flipped(tex, dst_rect);
358  } else {
359  draw::blit(tex, dst_rect);
360  }
361  break;
362  default:
363  ERR_GUI_D << "Image: unrecognized resize mode.";
364  break;
365  }
366 }
367 
369 {
370  if(resize_mode == "tile") {
371  return resize_mode::tile;
372  } else if(resize_mode == "tile_center") {
374  } else if(resize_mode == "tile_highres") {
376  } else if(resize_mode == "stretch") {
377  return resize_mode::stretch;
378  } else if(resize_mode == "scale_sharp") {
380  } else if(resize_mode == "scale") {
381  return resize_mode::scale;
382  } else {
383  if(!resize_mode.empty()) {
384  ERR_GUI_E << "Invalid resize mode '" << resize_mode << "' falling back to 'scale'.";
385  }
386 
387  // Linear scaling just looks horrible as a default, especially on HDPI screens, and even
388  // for some non-pixel art (the logo, for example). Nearest-neighbor isn't perfect for those
389  // usecases, but it's definitely better, in my opinion.
390  //
391  // -- vultraz, 2022-08-20
393  }
394 }
395 
396 /***** ***** ***** ***** ***** TEXT ***** ***** ***** ***** *****/
397 
399  : rect_bounded_shape(cfg)
400  , font_family_(font::str_to_family_class(cfg["font_family"]))
401  , font_size_(cfg["font_size"])
402  , font_style_(decode_font_style(cfg["font_style"]))
403  , text_alignment_(cfg["text_alignment"])
404  , color_(cfg["color"])
405  , text_(cfg["text"])
406  , text_markup_(cfg["text_markup"], false)
407  , link_aware_(cfg["text_link_aware"], false)
408  , link_color_(cfg["text_link_color"], color_t::from_hex_string("ffff00"))
409  , maximum_width_(cfg["maximum_width"], -1)
410  , characters_per_line_(cfg["text_characters_per_line"])
411  , maximum_height_(cfg["maximum_height"], -1)
412  , highlight_start_(cfg["highlight_start"], 0)
413  , highlight_end_(cfg["highlight_end"], 0)
414  , highlight_color_(cfg["highlight_color"], color_t::from_hex_string("215380"))
415  , outline_(cfg["outline"], false)
416 {
417  if(!font_size_.has_formula()) {
418  VALIDATE(font_size_(), _("Text has a font size of 0."));
419  }
420 
421  const std::string& debug = (cfg["debug"]);
422  if(!debug.empty()) {
423  DBG_GUI_P << "Text: found debug message '" << debug << "'.";
424  }
425 }
426 
428 {
429  assert(variables.has_key("text"));
430 
431  // We first need to determine the size of the text which need the rendered
432  // text. So resolve and render the text first and then start to resolve
433  // the other formulas.
434  const t_string text = text_(variables);
435 
436  if(text.empty()) {
437  DBG_GUI_D << "Text: no text to render, leave.";
438  return;
439  }
440 
441  font::pango_text& text_renderer = font::get_text_renderer();
442 
443  text_renderer.set_highlight_area(highlight_start_(variables), highlight_end_(variables), highlight_color_(variables));
444 
445  text_renderer
446  .set_link_aware(link_aware_(variables))
447  .set_link_color(link_color_(variables))
448  .set_text(text, text_markup_(variables));
449 
450  text_renderer.set_family_class(font_family_)
451  .set_font_size(font_size_(variables))
453  .set_alignment(text_alignment_(variables))
454  .set_foreground_color(color_(variables))
455  .set_maximum_width(maximum_width_(variables))
456  .set_maximum_height(maximum_height_(variables), true)
457  .set_ellipse_mode(variables.has_key("text_wrap_mode")
458  ? static_cast<PangoEllipsizeMode>(variables.query_value("text_wrap_mode").as_int())
459  : PANGO_ELLIPSIZE_END)
461  .set_add_outline(outline_(variables));
462 
463  wfl::map_formula_callable local_variables(variables);
464  const auto [tw, th] = text_renderer.get_size();
465 
466  // Translate text width and height back to draw-space, rounding up.
467  local_variables.add("text_width", wfl::variant(tw));
468  local_variables.add("text_height", wfl::variant(th));
469 
470  const int x = x_(local_variables);
471  const int y = y_(local_variables);
472  const int w = w_(local_variables);
473  const int h = h_(local_variables);
474  rect dst_rect{x, y, w, h};
475 
476  texture tex = text_renderer.render_and_get_texture();
477  if(!tex) {
478  DBG_GUI_D << "Text: Rendering '" << text << "' resulted in an empty canvas, leave.";
479  return;
480  }
481 
482  dst_rect.w = std::min(dst_rect.w, tex.w());
483  dst_rect.h = std::min(dst_rect.h, tex.h());
484 
485  draw::blit(tex, dst_rect);
486 }
487 
488 /***** ***** ***** ***** ***** CANVAS ***** ***** ***** ***** *****/
489 
491  : shapes_()
492  , blur_depth_(0)
493  , blur_region_(sdl::empty_rect)
494  , deferred_(false)
495  , w_(0)
496  , h_(0)
497  , variables_()
498  , functions_()
499 {
500 }
501 
503  : shapes_(std::move(c.shapes_))
504  , blur_depth_(c.blur_depth_)
505  , blur_region_(c.blur_region_)
506  , deferred_(c.deferred_)
507  , w_(c.w_)
508  , h_(c.h_)
509  , variables_(c.variables_)
510  , functions_(c.functions_)
511 {
512 }
513 
514 // It would be better if the blur effect was managed at a higher level.
515 // But for now this works and should be both general and robust.
516 bool canvas::update_blur(const rect& screen_region, bool force)
517 {
518  if(!blur_depth_) {
519  // No blurring needed.
520  return true;
521  }
522 
523  if(screen_region != blur_region_) {
524  DBG_GUI_D << "blur region changed from " << blur_region_
525  << " to " << screen_region;
526  // something has changed. regenerate the texture.
528  blur_region_ = screen_region;
529  }
530 
531  if(blur_texture_ && !force) {
532  // We already made the blur. It's expensive, so don't do it again.
533  return true;
534  }
535 
536  // To blur what is underneath us, it must already be rendered somewhere.
537  // This is okay for sub-elements of an opaque window (panels on the main
538  // title screen for example) as the window will already have rendered
539  // its background to the render buffer before we get here.
540  // If however we are blurring elements behind the window, such as if
541  // the window itself is translucent (objectives popup), or it is
542  // transparent with a translucent element (character dialogue),
543  // then we need to render what will be behind it before capturing that
544  // and rendering a blur.
545  // We could use the previous render frame, but there could well have been
546  // another element there last frame such as a popup window which we
547  // don't want to be part of the blur.
548  // The stable solution is to render in multiple passes,
549  // so that is what we shall do.
550 
551  // For the first pass, this element and its children are not rendered.
552  if(!deferred_) {
553  DBG_GUI_D << "Deferring blur at " << screen_region;
554  deferred_ = true;
556  return false;
557  }
558 
559  // For the second pass we read the result of the first pass at
560  // this widget's location, and blur it.
561  DBG_GUI_D << "Blurring " << screen_region << " depth " << blur_depth_;
562  rect read_region = screen_region;
563  auto setter = draw::set_render_target({});
564  surface s = video::read_pixels_low_res(&read_region);
567  deferred_ = false;
568  return true;
569 }
570 
572 {
574 }
575 
577 {
578  // This early-return has to come before the `validate(rect.w <= w_)` check, as during the boost_unit_tests execution
579  // the debug_clock widget will have no shapes, 0x0 size, yet be given a larger rect to draw.
580  if(shapes_.empty()) {
581  DBG_GUI_D << "Canvas: empty (no shapes to draw).";
582  return;
583  }
584 
585  if(deferred_) {
586  // We will draw next frame.
587  return;
588  }
589 
590  // Draw blurred background.
591  // TODO: hwaccel - this should be able to be removed at some point with shaders
592  if(blur_depth_ && blur_texture_) {
593  DBG_GUI_D << "blitting blur size " << blur_texture_.draw_size();
595  }
596 
597  // Draw items
598  for(auto& shape : shapes_) {
599  const lg::scope_logger inner_scope_logging_object__{log_gui_draw, "Canvas: draw shape."};
601  }
602 }
603 
604 void canvas::parse_cfg(const config& cfg)
605 {
606  log_scope2(log_gui_parse, "Canvas: parsing config.");
607 
608  for(const auto shape : cfg.all_children_range())
609  {
610  const std::string& type = shape.key;
611  const config& data = shape.cfg;
612 
613  DBG_GUI_P << "Canvas: found shape of the type " << type << ".";
614 
615  if(type == "line") {
616  shapes_.emplace_back(std::make_unique<line_shape>(data));
617  } else if(type == "rectangle") {
618  shapes_.emplace_back(std::make_unique<rectangle_shape>(data));
619  } else if(type == "round_rectangle") {
620  shapes_.emplace_back(std::make_unique<round_rectangle_shape>(data));
621  } else if(type == "circle") {
622  shapes_.emplace_back(std::make_unique<circle_shape>(data));
623  } else if(type == "image") {
624  shapes_.emplace_back(std::make_unique<image_shape>(data, functions_));
625  } else if(type == "text") {
626  shapes_.emplace_back(std::make_unique<text_shape>(data));
627  } else if(type == "pre_commit") {
628 
629  /* note this should get split if more preprocessing is used. */
630  for(const auto function : data.all_children_range())
631  {
632 
633  if(function.key == "blur") {
634  blur_depth_ = function.cfg["depth"];
635  } else {
636  ERR_GUI_P << "Canvas: found a pre commit function"
637  << " of an invalid type " << type << ".";
638  }
639  }
640 
641  } else {
642  ERR_GUI_P << "Canvas: found a shape of an invalid type " << type
643  << ".";
644  }
645  }
646 }
647 
649 {
651  variables_.add("width", wfl::variant(w_));
652  variables_.add("height", wfl::variant(h_));
653 }
654 
656 {
657  w_ = size.x;
658  h_ = size.y;
660 }
661 
662 void canvas::clear_shapes(const bool force)
663 {
664  if(force) {
665  shapes_.clear();
666  } else {
667  auto conditional = [](const std::unique_ptr<shape>& s)->bool { return !s->immutable(); };
668 
669  auto iter = std::remove_if(shapes_.begin(), shapes_.end(), conditional);
670  shapes_.erase(iter, shapes_.end());
671  }
672 }
673 
674 /***** ***** ***** ***** ***** SHAPE ***** ***** ***** ***** *****/
675 
676 } // namespace gui2
std::size_t w_
#define debug(x)
This file contains the canvas object which is the part where the widgets draw (temporally) images on.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:887
Text class.
Definition: text.hpp:79
pango_text & set_font_style(const FONT_STYLE font_style)
Definition: text.cpp:424
void set_highlight_area(const unsigned start_offset, const unsigned end_offset, const color_t &color)
Mark a specific portion of text for highlighting.
Definition: text.hpp:308
point get_size()
Returns the size of the text, in drawing coordinates.
Definition: text.cpp:157
pango_text & set_characters_per_line(const unsigned characters_per_line)
Definition: text.cpp:459
pango_text & set_foreground_color(const color_t &color)
Definition: text.cpp:434
pango_text & set_family_class(font::family_class fclass)
Definition: text.cpp:402
pango_text & set_add_outline(bool do_add)
Definition: text.cpp:557
pango_text & set_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
Definition: text.cpp:495
pango_text & set_alignment(const PangoAlignment alignment)
Definition: text.cpp:515
pango_text & set_font_size(unsigned font_size)
Definition: text.cpp:412
pango_text & set_link_aware(bool b)
Definition: text.cpp:538
bool set_text(const std::string &text, const bool markedup)
Sets the text to render.
Definition: text.cpp:345
pango_text & set_maximum_height(int height, bool multiline)
Definition: text.cpp:470
pango_text & set_maximum_width(int width)
Definition: text.cpp:443
texture render_and_get_texture()
Returns the cached texture, or creates a new one otherwise.
Definition: text.cpp:112
pango_text & set_link_color(const color_t &color)
Definition: text.cpp:547
std::ostringstream wrapper.
Definition: formatter.hpp:40
Abstract base class for all other shapes.
Definition: canvas.hpp:53
virtual void draw(wfl::map_formula_callable &variables)=0
Draws the canvas.
A simple canvas which can be drawn upon.
Definition: canvas.hpp:44
texture blur_texture_
Blurred background texture.
Definition: canvas.hpp:173
bool deferred_
Whether we have deferred rendering so we can capture for blur.
Definition: canvas.hpp:179
wfl::action_function_symbol_table functions_
Action function definitions for the canvas.
Definition: canvas.hpp:191
void clear_shapes(const bool force)
Definition: canvas.cpp:662
unsigned blur_depth_
The depth of the blur to use in the pre committing.
Definition: canvas.hpp:170
wfl::map_formula_callable variables_
The variables of the canvas.
Definition: canvas.hpp:188
bool update_blur(const rect &screen_region, const bool force=false)
Update the background blur texture, if relevant and necessary.
Definition: canvas.cpp:516
rect blur_region_
The region of the screen we have blurred (if any).
Definition: canvas.hpp:176
void parse_cfg(const config &cfg)
Parses a config object.
Definition: canvas.cpp:604
void queue_reblur()
Clear the cached blur texture, forcing it to regenerate.
Definition: canvas.cpp:571
std::vector< std::unique_ptr< shape > > shapes_
Vector with the shapes to draw.
Definition: canvas.hpp:160
unsigned w_
The full width of the canvas.
Definition: canvas.hpp:182
void update_size_variables()
Update WFL size variables.
Definition: canvas.cpp:648
unsigned h_
The full height of the canvas.
Definition: canvas.hpp:185
void draw()
Draw the canvas' shapes onto the screen.
Definition: canvas.cpp:576
void set_size(const point &size)
Definition: canvas.cpp:655
typed_formula< color_t > border_color_
The border color of the circle.
typed_formula< unsigned > x_
The center x coordinate of the circle.
typed_formula< unsigned > radius_
The radius of the circle.
unsigned int border_thickness_
The border thickness of the circle.
circle_shape(const config &cfg)
Constructor.
Definition: canvas.cpp:210
typed_formula< color_t > fill_color_
The fill color of the circle.
typed_formula< unsigned > y_
The center y coordinate of the circle.
void draw(wfl::map_formula_callable &variables) override
Draws the canvas.
Definition: canvas.cpp:225
typed_formula< std::string > image_name_
Name of the image.
resize_mode
Determines the way an image will be resized.
typed_formula< unsigned > w_
The width of the image.
resize_mode get_resize_mode(const std::string &resize_mode)
Converts a string to a resize mode.
Definition: canvas.cpp:368
typed_formula< unsigned > x_
The x coordinate of the image.
static void dimension_validation(unsigned value, const std::string &name, const std::string &key)
Definition: canvas.cpp:269
typed_formula< unsigned > y_
The y coordinate of the image.
typed_formula< unsigned > h_
The height of the image.
resize_mode resize_mode_
The resize mode for an image.
wfl::formula actions_formula_
typed_formula< bool > mirror_
Mirror the image over the vertical axis.
void draw(wfl::map_formula_callable &variables) override
Draws the canvas.
Definition: canvas.cpp:278
image_shape(const config &cfg, wfl::action_function_symbol_table &functions)
Constructor.
Definition: canvas.cpp:252
typed_formula< color_t > color_
The color of the line.
typed_formula< unsigned > x1_
The start x coordinate of the line.
typed_formula< unsigned > y1_
The start y coordinate of the line.
typed_formula< unsigned > x2_
The end x coordinate of the line.
line_shape(const config &cfg)
Constructor.
Definition: canvas.cpp:47
typed_formula< unsigned > y2_
The end y coordinate of the line.
void draw(wfl::map_formula_callable &variables) override
Draws the canvas.
Definition: canvas.cpp:62
Class holding common attribute names (for WML) and common implementation (in C++) for shapes placed w...
typed_formula< int > x_
The x coordinate of the rectangle.
typed_formula< int > w_
The width of the rectangle.
typed_formula< int > y_
The y coordinate of the rectangle.
typed_formula< int > h_
The height of the rectangle.
rectangle_shape(const config &cfg)
Constructor.
Definition: canvas.cpp:84
int border_thickness_
Border thickness.
typed_formula< color_t > fill_color_
The border color of the rectangle.
void draw(wfl::map_formula_callable &variables) override
Draws the canvas.
Definition: canvas.cpp:101
typed_formula< color_t > border_color_
The border color of the rectangle.
typed_formula< color_t > border_color_
The border color of the rounded rectangle.
void draw(wfl::map_formula_callable &variables) override
Draws the canvas.
Definition: canvas.cpp:163
typed_formula< int > r_
The radius of the corners.
round_rectangle_shape(const config &cfg)
Constructor.
Definition: canvas.cpp:145
int border_thickness_
Border thickness.
typed_formula< color_t > fill_color_
The border color of the rounded rectangle.
font::pango_text::FONT_STYLE font_style_
The style of the text.
text_shape(const config &cfg)
Constructor.
Definition: canvas.cpp:398
typed_formula< bool > outline_
Whether to apply a text outline.
typed_formula< color_t > color_
The color of the text.
typed_formula< int > maximum_height_
The maximum height for the text.
typed_formula< bool > link_aware_
The link aware switch of the text.
typed_formula< PangoAlignment > text_alignment_
The alignment of the text.
typed_formula< color_t > highlight_color_
The color to be used for highlighting.
font::family_class font_family_
The text font family.
typed_formula< color_t > link_color_
The link color of the text.
typed_formula< int > maximum_width_
The maximum width for the text.
void draw(wfl::map_formula_callable &variables) override
Draws the canvas.
Definition: canvas.cpp:427
typed_formula< int > highlight_end_
typed_formula< int > highlight_start_
Start and end offsets for highlight.
typed_formula< unsigned > font_size_
The font size of the text.
unsigned characters_per_line_
The number of characters per line.
typed_formula< t_string > text_
The text to draw.
typed_formula< bool > text_markup_
The text markup switch of the text.
bool has_formula() const
Determine whether the class contains a formula.
Generic locator abstracting the location of an image.
Definition: picture.hpp:63
bool empty() const
Definition: tstring.hpp:186
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
void reset()
Releases ownership of the managed texture and resets the ptr to null.
Definition: texture.cpp:208
point draw_size() const
The size of the texture in draw-space.
Definition: texture.hpp:122
int h() const
The draw-space height of the texture, in pixels.
Definition: texture.hpp:114
formula_callable_ptr fake_ptr()
Definition: callable.hpp:42
variant query_value(const std::string &key) const
Definition: callable.hpp:50
bool has_key(const std::string &key) const
Definition: callable.hpp:82
static variant evaluate(const const_formula_ptr &f, const formula_callable &variables, formula_debugger *fdb=nullptr, variant default_res=variant(0))
Definition: formula.hpp:40
map_formula_callable & add(const std::string &key, const variant &value)
Definition: callable.hpp:253
variant execute_variant(const variant &to_exec)
Definition: variant.cpp:653
int as_int() const
Definition: variant.cpp:291
Drawing functions, for drawing things on the screen.
std::size_t i
Definition: function.cpp:968
int w
static std::string _(const char *str)
Definition: gettext.hpp:93
Define the common log macros for the gui toolkit.
#define ERR_GUI_P
Definition: log.hpp:69
#define DBG_GUI_P
Definition: log.hpp:66
#define ERR_GUI_D
Definition: log.hpp:32
#define ERR_GUI_E
Definition: log.hpp:38
#define DBG_GUI_D
Definition: log.hpp:29
#define log_scope2(domain, description)
Definition: log.hpp:275
void request_extra_render_pass()
Request an extra render pass.
render_target_setter set_render_target(const texture &t)
Set the given texture as the active render target.
Definition: draw.cpp:616
void circle(int x, int y, int r, const color_t &c, uint8_t octants=0xff)
Draw a circle of the given colour.
Definition: draw.cpp:208
void tiled(const texture &tex, const SDL_Rect &dst, bool centered=false, bool mirrored=false)
Tile a texture to fill a region.
Definition: draw.cpp:369
void disc(int x, int y, int r, const color_t &c, uint8_t octants=0xff)
Draw a solid disc of the given colour.
Definition: draw.cpp:250
void set_color(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Set the drawing colour.
Definition: draw.cpp:100
void flipped(const texture &tex, const SDL_Rect &dst, bool flip_h=true, bool flip_v=false)
Draws a texture, or part of a texture, at the given location, also mirroring/flipping the texture hor...
Definition: draw.cpp:340
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
void tiled_highres(const texture &tex, const SDL_Rect &dst, bool centered=false, bool mirrored=false)
Tile a texture to fill a region.
Definition: draw.cpp:397
void rect(const SDL_Rect &rect)
Draw a rectangle.
Definition: draw.cpp:150
void line(int from_x, int from_y, int to_x, int to_y)
Draw a line.
Definition: draw.cpp:180
Collection of helper functions relating to Pango formatting.
pango_text & get_text_renderer()
Returns a reference to a static pango_text object.
Definition: text.cpp:1001
family_class str_to_family_class(const std::string &str)
Generic file dialog.
void get_screen_size_variables(wfl::map_formula_callable &variable)
Gets a formula object with the screen size.
Definition: helper.cpp:94
lg::log_domain log_gui_draw("gui/draw")
Definition: log.hpp:28
font::pango_text::FONT_STYLE decode_font_style(const std::string &style)
Converts a font style string to a font style.
Definition: helper.cpp:32
lg::log_domain log_gui_parse("gui/parse")
Definition: log.hpp:65
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:959
scale_quality
Definition: picture.hpp:234
constexpr const SDL_Rect empty_rect
Definition: rect.hpp:30
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
surface read_pixels_low_res(SDL_Rect *r)
The same as read_pixels, but returns a low-resolution surface suitable for use with the old drawing s...
Definition: video.cpp:620
std::string_view data
Definition: picture.cpp:194
int x2_
Definition: pump.cpp:132
int y1_
Definition: pump.cpp:132
int x1_
Definition: pump.cpp:132
int y2_
Definition: pump.cpp:132
Contains the SDL_Rect helper code.
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
constexpr bool null() const
Definition: color.hpp:186
Holds a 2D point.
Definition: point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:47
mock_char c
static map_location::DIRECTION s
surface blur_surface(const surface &surf, int depth)
Cross-fades a surface.
Definition: utils.cpp:1167
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define VALIDATE_WITH_DEV_MESSAGE(cond, message, dev_message)
#define VALIDATE(cond, message)
The macro to use for the validation of WML.
#define h