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 class styled_widget : public widget
35 {
36  friend class debug_layout_graph;
37 
38 public:
39  /**
40  * Constructor.
41  *
42  * @param builder The builder object with the settings for the object.
43  * @param control_type The type of control to be built.
44  */
46  const std::string& control_type);
47 
48  /**
49  * Sets the members of the styled_widget.
50  *
51  * The map contains named members it can set, controls inheriting from us
52  * can add additional members to set by this function. The following
53  * members can by the following key:
54  * * label_ label
55  * * tooltip_ tooltip
56  * * help_message_ help
57  *
58  *
59  * @param data Map with the key value pairs to set the
60  * members.
61  */
62  virtual void set_members(const widget_item& data);
63 
64  /***** ***** ***** ***** State handling ***** ***** ***** *****/
65 
66  /**
67  * Sets the styled_widget's state.
68  *
69  * Sets the styled_widget in the active state, when inactive a styled_widget can't be
70  * used and doesn't react to events. (Note read-only for a text_box_base is a
71  * different state.)
72  */
73  virtual void set_active(const bool active) = 0;
74 
75  /** Gets the active state of the styled_widget. */
76  virtual bool get_active() const = 0;
77 
78 protected:
79  /** Returns the id of the state.
80  *
81  * The current state is also the index canvases_.
82  */
83  virtual unsigned get_state() const = 0;
84 
85 public:
86  /***** ***** ***** ***** Easy close handling ***** ***** ***** *****/
87 
88  /**
89  * See @ref widget::disable_click_dismiss.
90  *
91  * The default behavior is that a widget blocks easy close, if not it
92  * should override this function.
93  */
94  bool disable_click_dismiss() const override;
95 
96  /** See @ref widget::create_walker. */
97  virtual iteration::walker_ptr create_walker() override;
98 
99  /***** ***** ***** ***** layout functions ***** ***** ***** *****/
100 
101  /**
102  * Gets the minimum size as defined in the config.
103  *
104  * @pre config_ != nullptr
105  *
106  * @returns The size.
107  */
109 
110  /**
111  * Gets the default size as defined in the config.
112  *
113  * @pre config_ != nullptr
114  *
115  * @returns The size.
116  */
118 
119  /**
120  * Gets the best size as defined in the config.
121  *
122  * @pre config_ != nullptr
123  *
124  * @returns The size.
125  */
127 
128  /**
129  * Returns the number of characters per line.
130  *
131  * This value is used to call pango_text::set_characters_per_line
132  * (indirectly).
133  *
134  * @returns The characters per line. This implementation
135  * always returns 0.
136  */
137  virtual unsigned get_characters_per_line() const;
138 
139  /**
140  * Returns whether the label should be link_aware, in
141  * in rendering and in searching for links with get_link.
142  *
143  * This value is used to call pango_text::set_link_aware
144  * (indirectly).
145  *
146  * @returns The link aware status. This impl always
147  * always returns false.
148  */
149  virtual bool get_link_aware() const;
150 
151  /**
152  * Returns the color string to be used with links.
153  *
154  * This value is used to call pango_text::set_link_color
155  * (indirectly).
156  *
157  * @returns The link color string. This impl returns "#ffff00".
158  *
159  */
160  virtual color_t get_link_color() const;
161 
162  /**
163  * See @ref widget::layout_initialize.
164  *
165  * @todo Also handle the tooltip state.
166  * Handle if shrunken_ && use_tooltip_on_label_overflow_.
167  */
168  virtual void layout_initialize(const bool full_initialization) override;
169 
170  /** See @ref widget::request_reduce_width. */
171  virtual void request_reduce_width(const unsigned maximum_width) override;
172 
173  /** See @ref widget::request_reduce_height. */
174  virtual void request_reduce_height(const unsigned maximum_height) override;
175 
176 protected:
177  /** See @ref widget::calculate_best_size. */
178  virtual point calculate_best_size() const override;
179 
180 public:
181  /** See @ref widget::place. */
182  virtual void place(const point& origin, const point& size) override;
183 
184  /***** ***** ***** ***** Inherited ***** ***** ***** *****/
185 
186  /** See @ref widget::find_at. */
187  virtual widget* find_at(const point& coordinate,
188  const bool must_be_active) override;
189 
190  /** See @ref widget::find_at. */
191  virtual const widget* find_at(const point& coordinate,
192  const bool must_be_active) const override;
193 
194  /** See @ref widget::find. */
195  widget* find(const std::string& id, const bool must_be_active) override;
196 
197  /** See @ref widget::find. */
198  const widget* find(const std::string& id,
199  const bool must_be_active) const override;
200 
201  /***** ***** ***** setters / getters for members ***** ****** *****/
203  {
205  }
206 
207  void set_use_tooltip_on_label_overflow(const bool use_tooltip = true)
208  {
209  use_tooltip_on_label_overflow_ = use_tooltip;
210  }
211 
212  const t_string& get_label() const
213  {
214  return label_;
215  }
216 
217  virtual void set_label(const t_string& text);
218 
219  virtual void set_use_markup(bool use_markup);
220 
221  bool get_use_markup() const
222  {
223  return use_markup_;
224  }
225 
226  const t_string& tooltip() const
227  {
228  return tooltip_;
229  }
230 
231  // Note setting the tooltip_ doesn't dirty an object.
233  {
234  tooltip_ = tooltip;
236  }
237 
238  const t_string& help_message() const
239  {
240  return help_message_;
241  }
242 
243  // Note setting the help_message_ doesn't dirty an object.
245  {
247  }
248 
249  // const versions will be added when needed
250  std::vector<canvas>& get_canvases()
251  {
252  return canvases_;
253  }
254 
255  canvas& get_canvas(const unsigned index)
256  {
257  assert(index < canvases_.size());
258  return canvases_[index];
259  }
260 
261  virtual void set_text_alignment(const PangoAlignment text_alignment);
262 
263  PangoAlignment get_text_alignment() const
264  {
265  return text_alignment_;
266  }
267 
268  void set_text_ellipse_mode(const PangoEllipsizeMode ellipse_mode);
269 
270  /**
271  * Get the text's ellipsize mode.
272  *
273  * Note that if can_wrap is true, it override the manual setting.
274  */
275  PangoEllipsizeMode get_text_ellipse_mode() const
276  {
277  return can_wrap() ? PANGO_ELLIPSIZE_NONE : text_ellipse_mode_;
278  }
279 
280 protected:
282  {
283  return config_;
284  }
285 
287  {
288  return config_;
289  }
290 
291  /**
292  * Casts the current resolution definition config to the respective type of a
293  * derived widget.
294  *
295  * @tparam T The definition type to cast to. Should have a `resolution`
296  * subclass or struct derived from resolution_definition.
297  *
298  * @returns A shared_ptr with the newly cast config.
299  */
300  template<typename T>
301  std::shared_ptr<const typename T::resolution> cast_config_to() const
302  {
303  static_assert(std::is_base_of_v<resolution_definition, typename T::resolution>,
304  "Given type's resolution object does not derive from resolution_definition."
305  );
306 
307  return std::static_pointer_cast<const typename T::resolution>(get_config());
308  }
309 
311  {
312  config_ = config;
313  }
314 
315  /***** ***** ***** ***** miscellaneous ***** ***** ***** *****/
316 
317  /**
318  * Updates the canvas(ses).
319  *
320  * This function should be called if either the size of the widget changes
321  * or the text on the widget changes.
322  */
323  virtual void update_canvas();
324 
325  /**
326  * Resolves and returns the text_font_size
327  *
328  * To allow the text_font_size in the widget definition to be a formula,
329  * call this function which will evaluate the formula (caching the result)
330  * and return the value.
331  */
332  unsigned int get_text_font_size() const;
333 
334  /**
335  * Returns the maximum width available for the text.
336  *
337  * This value makes sense after the widget has been given a size, since the
338  * maximum width is based on the width of the widget.
339  */
340  int get_text_maximum_width() const;
341 
342  /**
343  * Returns the maximum height available for the text.
344  *
345  * This value makes sense after the widget has been given a size, since the
346  * maximum height is based on the height of the widget.
347  */
348  int get_text_maximum_height() const;
349 
350 private:
351  /**
352  * The definition is the id of that widget class.
353  *
354  * Eg for a button it [button_definition]id. A button can have multiple
355  * definitions which all look different but for the engine still is a
356  * button.
357  */
358  std::string definition_;
359 
360  /** Contain the non-editable text associated with styled_widget. */
362 
363  /** Use markup for the label? */
365 
366  /**
367  * If the text doesn't fit on the label should the text be used as tooltip?
368  *
369  * This only happens if the tooltip is empty.
370  */
372 
373  /**
374  * Tooltip text.
375  *
376  * The hovering event can cause a small tooltip to be shown, this is the
377  * text to be shown. At the moment the tooltip is a single line of text.
378  */
380 
381  /**
382  * Tooltip text.
383  *
384  * The help event can cause a tooltip to be shown, this is the text to be
385  * shown. At the moment the tooltip is a single line of text.
386  */
388 
389  /**
390  * Contains the pointer to the configuration.
391  *
392  * Every styled_widget has a definition of how it should look, this contains a
393  * pointer to the definition. The definition is resolution dependent, where
394  * the resolution is the size of the Wesnoth application window. Depending
395  * on the resolution widgets can look different, use different fonts.
396  * Windows can use extra scrollbars use abbreviations as text etc.
397  */
399 
400  /**
401  * Contains the evaluated text_font_size from the configuration.
402  *
403  * We want to allow formulas in the value of text_font_size, since the desired
404  * font size can depend on parameters of the screen and window. But we don't
405  * want to have to recompute the value of the formula all the time. This member
406  * variable is the cache for the evaluated font size.
407  */
408  mutable unsigned int cached_text_font_size_ = 0;
409 
410  /**
411  * Holds all canvas objects for a styled_widget.
412  *
413  * A styled_widget can have multiple states, which are defined in the classes
414  * inheriting from us. For every state there is a separate canvas, which is
415  * stored here. When drawing the state is determined and that canvas is
416  * drawn.
417  */
418  std::vector<canvas> canvases_;
419 
420 public:
421  /**
422  * Returns the type of this styled_widget.
423  *
424  * This is used as the control_type parameter for @ref get_control.
425  *
426  * Do note that each widget also must have a public static type() function;
427  * it's use to implement this function. The reason for this system is twofold:
428  *
429  * 1) Due to an oddity in C++, one technically may not call a virtual function
430  * in a derived class's *initializer list*, which we do liberally. Calling
431  * it in the constructor *body* is fine, but doing so in the initializer list
432  * is technically undefined behavior and will give "invalid vptr" errors
433  * under UBSanitizer.
434  *
435  * 2) Having a static type getter allows the type string to be fetched without
436  * constructing an instance of the widget. A good example of this usecase is
437  * in build_single_widget_instance.
438  */
439  virtual const std::string& get_control_type() const = 0;
440 
441 protected:
442  /** See @ref widget::impl_draw_background. */
443  virtual bool impl_draw_background() override;
444 
445  /** See @ref widget::impl_draw_foreground. */
446  virtual bool impl_draw_foreground() override;
447 
448  /** Exposes font::pango_text::get_token, for the text label of this styled_widget */
449  std::string get_label_token(const point & position, const char * delimiters = " \n\r\t") const;
450 
451  std::string get_label_link(const point & position) const;
452 
453 private:
454  /**
455  * Gets the best size for a text.
456  *
457  * @param minimum_size The minimum size of the text.
458  * @param maximum_size The wanted maximum size of the text, if not
459  * possible it's ignored. A value of 0 means
460  * that it's ignored as well.
461  *
462  * @returns The best size.
463  */
464  point get_best_text_size(point minimum_size,
465  point maximum_size = {0, 0}) const;
466 
467  /**
468  * Gets whether a widget can shrink past its optimal size even if it's text-based (such as labels);
469  */
470  virtual bool text_can_shrink()
471  {
472  return false;
473  }
474 
475  /**
476  * Text renderer object used for size calculations.
477  *
478  * Note this is *not* used to actually render any text, only to get the dimensions of the text for
479  * layout purposes. The actual text rendering happens in the canvas. This is kept as a class member
480  * since creating a pango_text object is quite expensive.
481  *
482  * @todo Maybe if still too slow we might also copy this cache to the
483  * canvas so it can reuse our results, but for now it seems fast enough.
484  * Unfortunately that would make the dependency between the classes bigger
485  * as wanted.
486  */
488 
489  /** The maximum width for the text in a styled_widget. */
491 
492  /** The alignment of the text in a styled_widget. */
493  PangoAlignment text_alignment_;
494 
495  /** The ellipsize mode of the text in a styled_widget. */
496  PangoEllipsizeMode text_ellipse_mode_;
497 
498  /** Is the widget smaller as it's best size? */
499  bool shrunken_;
500 
501  /***** ***** ***** signal handlers ***** ****** *****/
502 
504  bool& handled,
505  const point& location);
506 
508  bool& handled,
509  const point& location);
510 
512  bool& handled);
513 };
514 
515 // }---------- BUILDER -----------{
516 
517 
518 namespace implementation
519 {
520 
522 {
523 public:
524  builder_styled_widget(const config& cfg);
525 
526  using builder_widget::build;
527 
528  virtual std::unique_ptr<widget> build(const replacements_map& replacements) const override;
529 
530  /** Parameters for the styled_widget. */
531  std::string definition;
537 };
538 
539 } // namespace implementation
540 
541 // }------------ END --------------
542 
543 } // 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
At the moment two kinds of tips are known:
Definition: tooltip.cpp:42
void set_wants_mouse_hover(const bool hover=true)
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:215
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