The Battle for Wesnoth  1.19.0-dev
styled_widget.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 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 #pragma once
17 
18 #include "font/text.hpp"
19 #include "gui/core/canvas.hpp"
22 #include "gui/widgets/widget.hpp"
23 
24 namespace gui2
25 {
26 
27 // ------------ WIDGET -----------{
28 
29 namespace implementation
30 {
31 struct builder_styled_widget;
32 } // namespace implementation
33 
34 /**
35  * @ingroup GUIWidgetWML
36  *
37  * Base class for all visible items.
38  *
39  * All widgets placed in a cell of a grid have some values in common:
40  * Key |Type |Default |Description
41  * -----------------------------|------------------------------------|---------|-----------
42  * id | @ref guivartype_string "string" |"" |This value is used for the engine to identify 'special' items. This means that for example a text_box can get the proper initial value. This value should be unique or empty. Those special values are documented at the window definition that uses them. NOTE: items starting with an underscore are used for composed widgets and these should be unique per composed widget.
43  * definition | @ref guivartype_string "string" |"default"|The id of the widget definition to use. This way it's possible to select a specific version of the widget e.g. a title label when the label is used as title.
44  * linked_group | @ref guivartype_string "string" |"" |The linked group the control belongs to.
45  * label | @ref guivartype_t_string "t_string"|"" |Most widgets have some text associated with them, this field contain the value of that text. Some widgets use this value for other purposes, this is documented at the widget. E.g. an image uses the filename in this field.
46  * tooltip | @ref guivartype_t_string "t_string"|"" |If you hover over a widget a while (the time it takes can differ per widget) a short help can show up.This defines the text of that message. This field may not be empty when 'help' is set.
47  * help | @ref guivartype_t_string "t_string"|"" |If you hover over a widget and press F10 (or the key the user defined for the help tip) a help message can show up. This help message might be the same as the tooltip but in general (if used) this message should show more help. This defines the text of that message.
48  * use_tooltip_on_label_overflow| @ref guivartype_bool "bool" |true |If the text on the label is truncated and the tooltip is empty the label can be used for the tooltip. If this variable is set to true this will happen.
49  * debug_border_mode | @ref guivartype_unsigned "unsigned"|0 |The mode for showing the debug border. This border shows the area reserved for a widget. This function is only meant for debugging and might not be available in all Wesnoth binaries. Available modes:<ul><li>0 - no border</li><li>1 - 1 pixel border</li><li>2 - floodfill the widget area</li></ul>
50  * debug_border_color | @ref guivartype_color "color" |"" |The color of the debug border.
51  * size_text | @ref guivartype_t_string "t_string"|"" |Sets the minimum width of the widget depending on the text in it. (Note: not implemented yet.)
52  */
53 class styled_widget : public widget
54 {
55  friend class debug_layout_graph;
56 
57 public:
58  /**
59  * Constructor.
60  *
61  * @param builder The builder object with the settings for the object.
62  * @param control_type The type of control to be built.
63  */
65  const std::string& control_type);
66 
67  /**
68  * Sets the members of the styled_widget.
69  *
70  * The map contains named members it can set, controls inheriting from us
71  * can add additional members to set by this function. The following
72  * members can by the following key:
73  * * label_ label
74  * * tooltip_ tooltip
75  * * help_message_ help
76  *
77  *
78  * @param data Map with the key value pairs to set the
79  * members.
80  */
81  virtual void set_members(const widget_item& data);
82 
83  /***** ***** ***** ***** State handling ***** ***** ***** *****/
84 
85  /**
86  * Sets the styled_widget's state.
87  *
88  * Sets the styled_widget in the active state, when inactive a styled_widget can't be
89  * used and doesn't react to events. (Note read-only for a text_box_base is a
90  * different state.)
91  */
92  virtual void set_active(const bool active) = 0;
93 
94  /** Gets the active state of the styled_widget. */
95  virtual bool get_active() const = 0;
96 
97 protected:
98  /** Returns the id of the state.
99  *
100  * The current state is also the index canvases_.
101  */
102  virtual unsigned get_state() const = 0;
103 
104 public:
105  /***** ***** ***** ***** Easy close handling ***** ***** ***** *****/
106 
107  /**
108  * See @ref widget::disable_click_dismiss.
109  *
110  * The default behavior is that a widget blocks easy close, if not it
111  * should override this function.
112  */
113  bool disable_click_dismiss() const override;
114 
115  /** See @ref widget::create_walker. */
116  virtual iteration::walker_ptr create_walker() override;
117 
118  /***** ***** ***** ***** layout functions ***** ***** ***** *****/
119 
120  /**
121  * Gets the minimum size as defined in the config.
122  *
123  * @pre config_ != nullptr
124  *
125  * @returns The size.
126  */
128 
129  /**
130  * Gets the default size as defined in the config.
131  *
132  * @pre config_ != nullptr
133  *
134  * @returns The size.
135  */
137 
138  /**
139  * Gets the best size as defined in the config.
140  *
141  * @pre config_ != nullptr
142  *
143  * @returns The size.
144  */
146 
147  /**
148  * Returns the number of characters per line.
149  *
150  * This value is used to call pango_text::set_characters_per_line
151  * (indirectly).
152  *
153  * @returns The characters per line. This implementation
154  * always returns 0.
155  */
156  virtual unsigned get_characters_per_line() const;
157 
158  /**
159  * Returns whether the label should be link_aware, in
160  * in rendering and in searching for links with get_link.
161  *
162  * This value is used to call pango_text::set_link_aware
163  * (indirectly).
164  *
165  * @returns The link aware status. This impl always
166  * always returns false.
167  */
168  virtual bool get_link_aware() const;
169 
170  /**
171  * Returns the color string to be used with links.
172  *
173  * This value is used to call pango_text::set_link_color
174  * (indirectly).
175  *
176  * @returns The link color string. This impl returns "#ffff00".
177  *
178  */
179  virtual color_t get_link_color() const;
180 
181  /**
182  * See @ref widget::layout_initialize.
183  *
184  * @todo Also handle the tooltip state.
185  * Handle if shrunken_ && use_tooltip_on_label_overflow_.
186  */
187  virtual void layout_initialize(const bool full_initialization) override;
188 
189  /** See @ref widget::request_reduce_width. */
190  virtual void request_reduce_width(const unsigned maximum_width) override;
191 
192  /** See @ref widget::request_reduce_height. */
193  virtual void request_reduce_height(const unsigned maximum_height) override;
194 
195 protected:
196  /** See @ref widget::calculate_best_size. */
197  virtual point calculate_best_size() const override;
198 
199 public:
200  /** See @ref widget::place. */
201  virtual void place(const point& origin, const point& size) override;
202 
203  /***** ***** ***** ***** Inherited ***** ***** ***** *****/
204 
205  /** See @ref widget::find_at. */
206  virtual widget* find_at(const point& coordinate,
207  const bool must_be_active) override;
208 
209  /** See @ref widget::find_at. */
210  virtual const widget* find_at(const point& coordinate,
211  const bool must_be_active) const override;
212 
213  /** See @ref widget::find. */
214  widget* find(const std::string& id, const bool must_be_active) override;
215 
216  /** See @ref widget::find. */
217  const widget* find(const std::string& id,
218  const bool must_be_active) const override;
219 
220  /***** ***** ***** setters / getters for members ***** ****** *****/
222  {
224  }
225 
226  void set_use_tooltip_on_label_overflow(const bool use_tooltip = true)
227  {
228  use_tooltip_on_label_overflow_ = use_tooltip;
229  }
230 
231  const t_string& get_label() const
232  {
233  return label_;
234  }
235 
236  virtual void set_label(const t_string& text);
237 
238  virtual void set_use_markup(bool use_markup);
239 
240  bool get_use_markup() const
241  {
242  return use_markup_;
243  }
244 
245  const t_string& tooltip() const
246  {
247  return tooltip_;
248  }
249 
250  // Note setting the tooltip_ doesn't dirty an object.
252  {
253  tooltip_ = tooltip;
255  }
256 
257  const t_string& help_message() const
258  {
259  return help_message_;
260  }
261 
262  // Note setting the help_message_ doesn't dirty an object.
264  {
266  }
267 
268  // const versions will be added when needed
269  std::vector<canvas>& get_canvases()
270  {
271  return canvases_;
272  }
273 
274  canvas& get_canvas(const unsigned index)
275  {
276  assert(index < canvases_.size());
277  return canvases_[index];
278  }
279 
280  virtual void set_text_alignment(const PangoAlignment text_alignment);
281 
282  PangoAlignment get_text_alignment() const
283  {
284  return text_alignment_;
285  }
286 
287  void set_text_ellipse_mode(const PangoEllipsizeMode ellipse_mode);
288 
289  /**
290  * Get the text's ellipsize mode.
291  *
292  * Note that if can_wrap is true, it override the manual setting.
293  */
294  PangoEllipsizeMode get_text_ellipse_mode() const
295  {
296  return can_wrap() ? PANGO_ELLIPSIZE_NONE : text_ellipse_mode_;
297  }
298 
299 protected:
301  {
302  return config_;
303  }
304 
306  {
307  return config_;
308  }
309 
310  /**
311  * Casts the current resolution definition config to the respective type of a
312  * derived widget.
313  *
314  * @tparam T The definition type to cast to. Should have a `resolution`
315  * subclass or struct derived from resolution_definition.
316  *
317  * @returns A shared_ptr with the newly cast config.
318  */
319  template<typename T>
320  std::shared_ptr<const typename T::resolution> cast_config_to() const
321  {
322  static_assert(std::is_base_of_v<resolution_definition, typename T::resolution>,
323  "Given type's resolution object does not derive from resolution_definition."
324  );
325 
326  return std::static_pointer_cast<const typename T::resolution>(get_config());
327  }
328 
330  {
331  config_ = config;
332  }
333 
334  /***** ***** ***** ***** miscellaneous ***** ***** ***** *****/
335 
336  /**
337  * Updates the canvas(ses).
338  *
339  * This function should be called if either the size of the widget changes
340  * or the text on the widget changes.
341  */
342  virtual void update_canvas();
343 
344  /**
345  * Resolves and returns the text_font_size
346  *
347  * To allow the text_font_size in the widget definition to be a formula,
348  * call this function which will evaluate the formula (caching the result)
349  * and return the value.
350  */
351  unsigned int get_text_font_size() const;
352 
353  /**
354  * Returns the maximum width available for the text.
355  *
356  * This value makes sense after the widget has been given a size, since the
357  * maximum width is based on the width of the widget.
358  */
359  int get_text_maximum_width() const;
360 
361  /**
362  * Returns the maximum height available for the text.
363  *
364  * This value makes sense after the widget has been given a size, since the
365  * maximum height is based on the height of the widget.
366  */
367  int get_text_maximum_height() const;
368 
369 private:
370  /**
371  * The definition is the id of that widget class.
372  *
373  * Eg for a button it [button_definition]id. A button can have multiple
374  * definitions which all look different but for the engine still is a
375  * button.
376  */
377  std::string definition_;
378 
379  /** Contain the non-editable text associated with styled_widget. */
381 
382  /** Use markup for the label? */
384 
385  /**
386  * If the text doesn't fit on the label should the text be used as tooltip?
387  *
388  * This only happens if the tooltip is empty.
389  */
391 
392  /**
393  * Tooltip text.
394  *
395  * The hovering event can cause a small tooltip to be shown, this is the
396  * text to be shown. At the moment the tooltip is a single line of text.
397  */
399 
400  /**
401  * Tooltip text.
402  *
403  * The help event can cause a tooltip to be shown, this is the text to be
404  * shown. At the moment the tooltip is a single line of text.
405  */
407 
408  /**
409  * Contains the pointer to the configuration.
410  *
411  * Every styled_widget has a definition of how it should look, this contains a
412  * pointer to the definition. The definition is resolution dependent, where
413  * the resolution is the size of the Wesnoth application window. Depending
414  * on the resolution widgets can look different, use different fonts.
415  * Windows can use extra scrollbars use abbreviations as text etc.
416  */
418 
419  /**
420  * Contains the evaluated text_font_size from the configuration.
421  *
422  * We want to allow formulas in the value of text_font_size, since the desired
423  * font size can depend on parameters of the screen and window. But we don't
424  * want to have to recompute the value of the formula all the time. This member
425  * variable is the cache for the evaluated font size.
426  */
427  mutable unsigned int cached_text_font_size_ = 0;
428 
429  /**
430  * Holds all canvas objects for a styled_widget.
431  *
432  * A styled_widget can have multiple states, which are defined in the classes
433  * inheriting from us. For every state there is a separate canvas, which is
434  * stored here. When drawing the state is determined and that canvas is
435  * drawn.
436  */
437  std::vector<canvas> canvases_;
438 
439 public:
440  /**
441  * Returns the type of this styled_widget.
442  *
443  * This is used as the control_type parameter for @ref get_control.
444  *
445  * Do note that each widget also must have a public static type() function;
446  * it's use to implement this function. The reason for this system is twofold:
447  *
448  * 1) Due to an oddity in C++, one technically may not call a virtual function
449  * in a derived class's *initializer list*, which we do liberally. Calling
450  * it in the constructor *body* is fine, but doing so in the initializer list
451  * is technically undefined behavior and will give "invalid vptr" errors
452  * under UBSanitizer.
453  *
454  * 2) Having a static type getter allows the type string to be fetched without
455  * constructing an instance of the widget. A good example of this usecase is
456  * in build_single_widget_instance.
457  */
458  virtual const std::string& get_control_type() const = 0;
459 
460 protected:
461  /** See @ref widget::impl_draw_background. */
462  virtual bool impl_draw_background() override;
463 
464  /** See @ref widget::impl_draw_foreground. */
465  virtual bool impl_draw_foreground() override;
466 
467  /** Exposes font::pango_text::get_token, for the text label of this styled_widget */
468  std::string get_label_token(const point & position, const char * delimiters = " \n\r\t") const;
469 
470  std::string get_label_link(const point & position) const;
471 
472 private:
473  /**
474  * Gets the best size for a text.
475  *
476  * @param minimum_size The minimum size of the text.
477  * @param maximum_size The wanted maximum size of the text, if not
478  * possible it's ignored. A value of 0 means
479  * that it's ignored as well.
480  *
481  * @returns The best size.
482  */
483  point get_best_text_size(point minimum_size,
484  point maximum_size = {0, 0}) const;
485 
486  /**
487  * Gets whether a widget can shrink past its optimal size even if it's text-based (such as labels);
488  */
489  virtual bool text_can_shrink()
490  {
491  return false;
492  }
493 
494  /**
495  * Text renderer object used for size calculations.
496  *
497  * Note this is *not* used to actually render any text, only to get the dimensions of the text for
498  * layout purposes. The actual text rendering happens in the canvas. This is kept as a class member
499  * since creating a pango_text object is quite expensive.
500  *
501  * @todo Maybe if still too slow we might also copy this cache to the
502  * canvas so it can reuse our results, but for now it seems fast enough.
503  * Unfortunately that would make the dependency between the classes bigger
504  * as wanted.
505  */
507 
508  /** The maximum width for the text in a styled_widget. */
510 
511  /** The alignment of the text in a styled_widget. */
512  PangoAlignment text_alignment_;
513 
514  /** The ellipsize mode of the text in a styled_widget. */
515  PangoEllipsizeMode text_ellipse_mode_;
516 
517  /** Is the widget smaller as it's best size? */
518  bool shrunken_;
519 
520  /***** ***** ***** signal handlers ***** ****** *****/
521 
523  bool& handled,
524  const point& location);
525 
527  bool& handled,
528  const point& location);
529 
531  bool& handled);
532 };
533 
534 // }---------- BUILDER -----------{
535 
536 
537 namespace implementation
538 {
539 
541 {
542 public:
543  builder_styled_widget(const config& cfg);
544 
545  using builder_widget::build;
546 
547  virtual std::unique_ptr<widget> build(const replacements_map& replacements) const override;
548 
549  /** Parameters for the styled_widget. */
550  std::string definition;
556 };
557 
558 } // namespace implementation
559 
560 // }------------ END --------------
561 
562 } // namespace gui2
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
Text class.
Definition: text.hpp:79
A simple canvas which can be drawn upon.
Definition: canvas.hpp:44
Class to show the tips.
Definition: tooltip.cpp:56
void set_wants_mouse_hover(const bool hover=true)
Base class for all visible items.
void set_use_tooltip_on_label_overflow(const bool use_tooltip=true)
virtual void set_active(const bool active)=0
Sets the styled_widget's state.
const t_string & get_label() const
t_string help_message_
Tooltip text.
virtual widget * find_at(const point &coordinate, const bool must_be_active) override
See widget::find_at.
int text_maximum_width_
The maximum width for the text in a styled_widget.
void set_tooltip(const t_string &tooltip)
bool use_markup_
Use markup for the label?
PangoAlignment get_text_alignment() const
PangoEllipsizeMode text_ellipse_mode_
The ellipsize mode of the text in a styled_widget.
font::pango_text renderer_
Text renderer object used for size calculations.
virtual unsigned get_state() const =0
Returns the id of the state.
point get_config_maximum_size() const
Gets the best size as defined in the config.
std::vector< canvas > & get_canvases()
t_string tooltip_
Tooltip text.
std::string definition_
The definition is the id of that widget class.
const t_string & tooltip() const
bool use_tooltip_on_label_overflow_
If the text doesn't fit on the label should the text be used as tooltip?
bool get_use_tooltip_on_label_overflow() const
int get_text_maximum_width() const
Returns the maximum width available for the text.
virtual unsigned get_characters_per_line() const
Returns the number of characters per line.
point get_config_minimum_size() const
Gets the minimum size as defined in the config.
std::string get_label_link(const point &position) const
int get_text_maximum_height() const
Returns the maximum height available for the text.
void signal_handler_show_helptip(const event::ui_event event, bool &handled, const point &location)
virtual void request_reduce_width(const unsigned maximum_width) override
See widget::request_reduce_width.
virtual void request_reduce_height(const unsigned maximum_height) override
See widget::request_reduce_height.
virtual void layout_initialize(const bool full_initialization) override
See widget::layout_initialize.
virtual void update_canvas()
Updates the canvas(ses).
virtual bool get_link_aware() const
Returns whether the label should be link_aware, in in rendering and in searching for links with get_l...
const t_string & help_message() const
void set_help_message(const t_string &help_message)
point get_config_default_size() const
Gets the default size as defined in the config.
std::vector< canvas > canvases_
Holds all canvas objects for a styled_widget.
PangoEllipsizeMode get_text_ellipse_mode() const
Get the text's ellipsize mode.
virtual color_t get_link_color() const
Returns the color string to be used with links.
void signal_handler_notify_remove_tooltip(const event::ui_event event, bool &handled)
bool shrunken_
Is the widget smaller as it's best size?
friend class debug_layout_graph
PangoAlignment text_alignment_
The alignment of the text in a styled_widget.
virtual void set_members(const widget_item &data)
Sets the members of the styled_widget.
void set_config(resolution_definition_ptr config)
virtual bool impl_draw_background() override
See widget::impl_draw_background.
point get_best_text_size(point minimum_size, point maximum_size={0, 0}) const
Gets the best size for a text.
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
virtual void place(const point &origin, const point &size) override
See widget::place.
virtual void set_text_alignment(const PangoAlignment text_alignment)
virtual bool get_active() const =0
Gets the active state of the styled_widget.
resolution_definition_ptr config_
Contains the pointer to the configuration.
virtual iteration::walker_ptr create_walker() override
See widget::create_walker.
std::shared_ptr< const typename T::resolution > cast_config_to() const
Casts the current resolution definition config to the respective type of a derived widget.
virtual bool impl_draw_foreground() override
See widget::impl_draw_foreground.
std::string get_label_token(const point &position, const char *delimiters=" \n\r\t") const
Exposes font::pango_text::get_token, for the text label of this styled_widget.
bool disable_click_dismiss() const override
See widget::disable_click_dismiss.
virtual void set_label(const t_string &text)
virtual bool text_can_shrink()
Gets whether a widget can shrink past its optimal size even if it's text-based (such as labels);.
void set_text_ellipse_mode(const PangoEllipsizeMode ellipse_mode)
canvas & get_canvas(const unsigned index)
void signal_handler_show_tooltip(const event::ui_event event, bool &handled, const point &location)
styled_widget(const implementation::builder_styled_widget &builder, const std::string &control_type)
Constructor.
virtual void set_use_markup(bool use_markup)
t_string label_
Contain the non-editable text associated with styled_widget.
resolution_definition_ptr get_config()
virtual const std::string & get_control_type() const =0
Returns the type of this styled_widget.
bool get_use_markup() const
virtual point calculate_best_size() const override
See widget::calculate_best_size.
resolution_definition_const_ptr get_config() const
unsigned int get_text_font_size() const
Resolves and returns the text_font_size.
unsigned int cached_text_font_size_
Contains the evaluated text_font_size from the configuration.
Base class for all widgets.
Definition: widget.hpp:53
virtual bool can_wrap() const
Can the widget wrap.
Definition: widget.cpp:216
bool empty() const
Definition: tstring.hpp:186
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:42
Generic file dialog.
std::shared_ptr< resolution_definition > resolution_definition_ptr
std::map< std::string, t_string > widget_item
Definition: widget.hpp:31
std::shared_ptr< const resolution_definition > resolution_definition_const_ptr
Contains the implementation details for lexical_cast and shouldn't be used directly.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::string_view data
Definition: picture.cpp:194
The basic class for representing 8-bit RGB or RGBA colour values.
Definition: color.hpp:59
Contains the info needed to instantiate a widget.
virtual std::unique_ptr< widget > build() const =0
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
std::string definition
Parameters for the styled_widget.
virtual std::unique_ptr< widget > build() const=0
Holds a 2D point.
Definition: point.hpp:25