The Battle for Wesnoth  1.19.7+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_view id, const bool must_be_active) override;
196 
197  /** See @ref widget::find. */
198  const widget* find(const std::string_view id, const bool must_be_active) const override;
199 
200  /***** ***** ***** setters / getters for members ***** ****** *****/
202  {
204  }
205 
206  void set_use_tooltip_on_label_overflow(const bool use_tooltip = true)
207  {
208  use_tooltip_on_label_overflow_ = use_tooltip;
209  }
210 
211  const t_string& get_label() const
212  {
213  return label_;
214  }
215 
216  virtual void set_label(const t_string& text);
217 
218  virtual void set_use_markup(bool use_markup);
219 
220  bool get_use_markup() const
221  {
222  return use_markup_;
223  }
224 
225  const t_string& tooltip() const
226  {
227  return tooltip_;
228  }
229 
230  // Note setting the tooltip_ doesn't dirty an object.
232  {
233  tooltip_ = tooltip;
235  }
236 
237  const t_string& help_message() const
238  {
239  return help_message_;
240  }
241 
242  // Note setting the help_message_ doesn't dirty an object.
244  {
246  }
247 
248  // const versions will be added when needed
249  std::vector<canvas>& get_canvases()
250  {
251  return canvases_;
252  }
253 
254  canvas& get_canvas(const unsigned index)
255  {
256  assert(index < canvases_.size());
257  return canvases_[index];
258  }
259 
260  virtual void set_text_alignment(const PangoAlignment text_alignment);
261 
262  PangoAlignment get_text_alignment() const
263  {
264  return text_alignment_;
265  }
266 
267  void set_text_ellipse_mode(const PangoEllipsizeMode ellipse_mode);
268 
269  /**
270  * Get the text's ellipsize mode.
271  *
272  * Note that if can_wrap is true, it override the manual setting.
273  */
274  PangoEllipsizeMode get_text_ellipse_mode() const
275  {
276  return can_wrap() ? PANGO_ELLIPSIZE_NONE : text_ellipse_mode_;
277  }
278 
279 protected:
281  {
282  return config_;
283  }
284 
286  {
287  return config_;
288  }
289 
290  /**
291  * Casts the current resolution definition config to the respective type of a
292  * derived widget.
293  *
294  * @tparam T The definition type to cast to. Should have a `resolution`
295  * subclass or struct derived from resolution_definition.
296  *
297  * @returns A shared_ptr with the newly cast config.
298  */
299  template<typename T>
300  std::shared_ptr<const typename T::resolution> cast_config_to() const
301  {
302  static_assert(std::is_base_of_v<resolution_definition, typename T::resolution>,
303  "Given type's resolution object does not derive from resolution_definition."
304  );
305 
306  return std::static_pointer_cast<const typename T::resolution>(get_config());
307  }
308 
310  {
311  config_ = std::move(config);
312  }
313 
314  /***** ***** ***** ***** miscellaneous ***** ***** ***** *****/
315 
316  /**
317  * Updates the canvas(ses).
318  *
319  * This function should be called if either the size of the widget changes
320  * or the text on the widget changes.
321  */
322  virtual void update_canvas();
323 
324  /**
325  * Resolves and returns the text_font_size
326  *
327  * To allow the text_font_size in the widget definition to be a formula,
328  * call this function which will evaluate the formula (caching the result)
329  * and return the value.
330  */
331  unsigned int get_text_font_size() const;
332 
333  /**
334  * Returns the maximum width available for the text.
335  *
336  * This value makes sense after the widget has been given a size, since the
337  * maximum width is based on the width of the widget.
338  */
339  int get_text_maximum_width() const;
340 
341  /**
342  * Returns the maximum height available for the text.
343  *
344  * This value makes sense after the widget has been given a size, since the
345  * maximum height is based on the height of the widget.
346  */
347  int get_text_maximum_height() const;
348 
349 public:
350  /**
351  * Set how wide the text can become. If the text is bigger
352  * than this limit, it gets wrapped
353  */
354  void set_text_maximum_width(int max_width) {
355  if (max_width > 0) {
356  text_maximum_width_ = max_width;
357  }
358  }
359 
360 private:
361  /**
362  * The definition is the id of that widget class.
363  *
364  * Eg for a button it [button_definition]id. A button can have multiple
365  * definitions which all look different but for the engine still is a
366  * button.
367  */
368  std::string definition_;
369 
370  /** Contain the non-editable text associated with styled_widget. */
372 
373  /** Use markup for the label? */
375 
376  /**
377  * If the text doesn't fit on the label should the text be used as tooltip?
378  *
379  * This only happens if the tooltip is empty.
380  */
382 
383  /**
384  * Tooltip text.
385  *
386  * The hovering event can cause a small tooltip to be shown, this is the
387  * text to be shown. At the moment the tooltip is a single line of text.
388  */
390 
391  /**
392  * Tooltip text.
393  *
394  * The help event can cause a tooltip to be shown, this is the text to be
395  * shown. At the moment the tooltip is a single line of text.
396  */
398 
399  /**
400  * Contains the pointer to the configuration.
401  *
402  * Every styled_widget has a definition of how it should look, this contains a
403  * pointer to the definition. The definition is resolution dependent, where
404  * the resolution is the size of the Wesnoth application window. Depending
405  * on the resolution widgets can look different, use different fonts.
406  * Windows can use extra scrollbars use abbreviations as text etc.
407  */
409 
410  /**
411  * Contains the evaluated text_font_size from the configuration.
412  *
413  * We want to allow formulas in the value of text_font_size, since the desired
414  * font size can depend on parameters of the screen and window. But we don't
415  * want to have to recompute the value of the formula all the time. This member
416  * variable is the cache for the evaluated font size.
417  */
418  mutable unsigned int cached_text_font_size_ = 0;
419 
420  /**
421  * Holds all canvas objects for a styled_widget.
422  *
423  * A styled_widget can have multiple states, which are defined in the classes
424  * inheriting from us. For every state there is a separate canvas, which is
425  * stored here. When drawing the state is determined and that canvas is
426  * drawn.
427  */
428  std::vector<canvas> canvases_;
429 
430 public:
431  /**
432  * Returns the type of this styled_widget.
433  *
434  * This is used as the control_type parameter for @ref get_control.
435  *
436  * Do note that each widget also must have a public static type() function;
437  * it's use to implement this function. The reason for this system is twofold:
438  *
439  * 1) Due to an oddity in C++, one technically may not call a virtual function
440  * in a derived class's *initializer list*, which we do liberally. Calling
441  * it in the constructor *body* is fine, but doing so in the initializer list
442  * is technically undefined behavior and will give "invalid vptr" errors
443  * under UBSanitizer.
444  *
445  * 2) Having a static type getter allows the type string to be fetched without
446  * constructing an instance of the widget. A good example of this usecase is
447  * in build_single_widget_instance.
448  */
449  virtual const std::string& get_control_type() const = 0;
450 
451 protected:
452  /** See @ref widget::impl_draw_background. */
453  virtual bool impl_draw_background() override;
454 
455  /** See @ref widget::impl_draw_foreground. */
456  virtual bool impl_draw_foreground() override;
457 
458  /** Exposes font::pango_text::get_token, for the text label of this styled_widget */
459  std::string get_label_token(const point & position, const char * delimiters = " \n\r\t") const;
460 
461  std::string get_label_link(const point & position) const;
462 
463 private:
464  /**
465  * Gets the best size for a text.
466  *
467  * @param minimum_size The minimum size of the text.
468  * @param maximum_size The wanted maximum size of the text, if not
469  * possible it's ignored. A value of 0 means
470  * that it's ignored as well.
471  *
472  * @returns The best size.
473  */
474  point get_best_text_size(point minimum_size,
475  point maximum_size = {0, 0}) const;
476 
477  /**
478  * Gets whether a widget can shrink past its optimal size even if it's text-based (such as labels);
479  */
480  virtual bool text_can_shrink()
481  {
482  return false;
483  }
484 
485  /**
486  * Text renderer object used for size calculations.
487  *
488  * Note this is *not* used to actually render any text, only to get the dimensions of the text for
489  * layout purposes. The actual text rendering happens in the canvas. This is kept as a class member
490  * since creating a pango_text object is quite expensive.
491  *
492  * @todo Maybe if still too slow we might also copy this cache to the
493  * canvas so it can reuse our results, but for now it seems fast enough.
494  * Unfortunately that would make the dependency between the classes bigger
495  * as wanted.
496  */
498 
499  /** The maximum width for the text in a styled_widget. */
501 
502  /** The alignment of the text in a styled_widget. */
503  PangoAlignment text_alignment_;
504 
505  /** The ellipsize mode of the text in a styled_widget. */
506  PangoEllipsizeMode text_ellipse_mode_;
507 
508  /** Is the widget smaller as it's best size? */
509  bool shrunken_;
510 
511  /***** ***** ***** signal handlers ***** ****** *****/
512 
514  bool& handled,
515  const point& location);
516 
518  bool& handled,
519  const point& location);
520 
522  bool& handled);
523 };
524 
525 // }---------- BUILDER -----------{
526 
527 class styled_widget;
528 
529 namespace implementation
530 {
531 
533 {
534 public:
535  builder_styled_widget(const config& cfg);
536 
537  using builder_widget::build;
538 
539  virtual std::unique_ptr<widget> build(const replacements_map& replacements) const override;
540 
541  /** Parameters for the styled_widget. */
542  std::string definition;
548 };
549 
550 } // namespace implementation
551 
552 // }------------ END --------------
553 
554 } // 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:172
Text class.
Definition: text.hpp:79
A simple canvas which can be drawn upon.
Definition: canvas.hpp:45
At the moment two kinds of tips are known:
Definition: tooltip.cpp:41
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?
widget * find(const std::string_view id, const bool must_be_active) override
See widget::find.
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.
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.
void set_text_maximum_width(int max_width)
Set how wide the text can become.
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:55
virtual bool can_wrap() const
Can the widget wrap.
Definition: widget.cpp:225
bool empty() const
Definition: tstring.hpp:194
ui_event
The event sent to the dispatcher.
Definition: handler.hpp:115
std::unique_ptr< class walker_base > walker_ptr
Definition: widget.hpp:44
Generic file dialog.
std::shared_ptr< resolution_definition > resolution_definition_ptr
std::map< std::string, t_string > widget_item
Definition: widget.hpp:33
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 size(std::string_view str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
Definition: unicode.cpp:70
std::string_view data
Definition: picture.cpp:178
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