The Battle for Wesnoth  1.17.0-dev
styled_widget.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2021
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 string_map& 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_base* 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  */
127  point get_config_minimum_size() const;
128 
129  /**
130  * Gets the default size as defined in the config.
131  *
132  * @pre config_ != nullptr
133  *
134  * @returns The size.
135  */
136  point get_config_default_size() const;
137 
138  /**
139  * Gets the best size as defined in the config.
140  *
141  * @pre config_ != nullptr
142  *
143  * @returns The size.
144  */
145  point get_config_maximum_size() const;
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  {
223  return use_tooltip_on_label_overflow_;
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& label);
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;
254  set_wants_mouse_hover(!tooltip_.empty());
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.
263  void set_help_message(const t_string& help_message)
264  {
265  help_message_ = help_message;
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>(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_and_cast_to.
457  */
458  virtual const std::string& get_control_type() const = 0;
459 
460 protected:
461  /** See @ref widget::impl_draw_background. */
462  virtual void impl_draw_background(surface& frame_buffer,
463  int x_offset,
464  int y_offset) override;
465 
466  /** See @ref widget::impl_draw_foreground. */
467  virtual void impl_draw_foreground(surface& frame_buffer,
468  int x_offset,
469  int y_offset) override;
470 
471  /** Exposes font::pango_text::get_token, for the text label of this styled_widget */
472  std::string get_label_token(const point & position, const char * delimiters = " \n\r\t") const;
473 
474  std::string get_label_link(const point & position) const;
475 
476 private:
477  /**
478  * Gets the best size for a text.
479  *
480  * @param minimum_size The minimum size of the text.
481  * @param maximum_size The wanted maximum size of the text, if not
482  * possible it's ignored. A value of 0 means
483  * that it's ignored as well.
484  *
485  * @returns The best size.
486  */
487  point get_best_text_size(point minimum_size,
488  point maximum_size = {0, 0}) const;
489 
490  /**
491  * Gets whether a widget can shrink past its optimal size even if it's text-based (such as labels);
492  */
493  virtual bool text_can_shrink()
494  {
495  return false;
496  }
497 
498  /**
499  * Text renderer object used for size calculations.
500  *
501  * Note this is *not* used to actually render any text, only to get the dimensions of the text for
502  * layout purposes. The actual text rendering happens in the canvas. This is kept as a class member
503  * since creating a pango_text object is quite expensive.
504  *
505  * @todo Maybe if still too slow we might also copy this cache to the
506  * canvas so it can reuse our results, but for now it seems fast enough.
507  * Unfortunately that would make the dependency between the classes bigger
508  * as wanted.
509  */
511 
512  /** The maximum width for the text in a styled_widget. */
514 
515  /** The alignment of the text in a styled_widget. */
516  PangoAlignment text_alignment_;
517 
518  /** The ellipsize mode of the text in a styled_widget. */
519  PangoEllipsizeMode text_ellipse_mode_;
520 
521  /** Is the widget smaller as it's best size? */
522  bool shrunken_;
523 
524  /***** ***** ***** signal handlers ***** ****** *****/
525 
526  void signal_handler_show_tooltip(const event::ui_event event,
527  bool& handled,
528  const point& location);
529 
530  void signal_handler_show_helptip(const event::ui_event event,
531  bool& handled,
532  const point& location);
533 
534  void signal_handler_notify_remove_tooltip(const event::ui_event event,
535  bool& handled);
536 };
537 
538 // }---------- BUILDER -----------{
539 
540 class styled_widget;
541 
542 namespace implementation
543 {
544 
546 {
547 public:
548  builder_styled_widget(const config& cfg);
549 
550  using builder_widget::build;
551 
552  virtual widget* build(const replacements_map& replacements) const override;
553 
554  /** Parameters for the styled_widget. */
555  std::string definition;
561 };
562 
563 } // namespace implementation
564 
565 // }------------ END --------------
566 
567 } // namespace gui2
Contains the info needed to instantiate a widget.
virtual widget * build() const =0
void set_config(resolution_definition_ptr config)
PangoAlignment get_text_alignment() const
void set_help_message(const t_string &help_message)
bool get_use_markup() const
Base class for all widgets.
Definition: widget.hpp:49
std::shared_ptr< const resolution_definition > resolution_definition_const_ptr
A label displays a text, the text can be wrapped but no scrollbars are provided.
Definition: label.hpp:57
bool shrunken_
Is the widget smaller as it&#39;s best size?
std::string definition_
The definition is the id of that widget class.
virtual bool text_can_shrink()
Gets whether a widget can shrink past its optimal size even if it&#39;s text-based (such as labels);...
Generic file dialog.
Definition: field-fwd.hpp:23
std::string definition
Parameters for the styled_widget.
bool use_tooltip_on_label_overflow_
If the text doesn&#39;t fit on the label should the text be used as tooltip?
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
std::map< std::string, std::shared_ptr< builder_widget > > replacements_map
The replacements type is used to define replacement types.
void set_tooltip(const t_string &tooltip)
t_string tooltip_
Tooltip text.
std::shared_ptr< resolution_definition > resolution_definition_ptr
The walker abstract base class.
Definition: walker.hpp:27
This file contains the canvas object which is the part where the widgets draw (temporally) images on...
std::vector< canvas > & get_canvases()
resolution_definition_const_ptr config() const
A simple canvas which can be drawn upon.
Definition: canvas.hpp:42
resolution_definition_ptr config()
void set_use_tooltip_on_label_overflow(const bool use_tooltip=true)
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...
font::pango_text renderer_
Text renderer object used for size calculations.
std::vector< canvas > canvases_
Holds all canvas objects for a styled_widget.
t_string label_
Contain the non-editable text associated with styled_widget.
t_string help_message_
Tooltip text.
std::map< std::string, t_string > string_map
Definition: widget.hpp:26
PangoEllipsizeMode text_ellipse_mode_
The ellipsize mode of the text in a styled_widget.
Holds a 2D point.
Definition: point.hpp:24
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:72
Base class for all visible items.
bool get_use_tooltip_on_label_overflow() const
Text class.
Definition: text.hpp:75
const t_string & get_label() const
const t_string & tooltip() const
PangoAlignment text_alignment_
The alignment of the text in a styled_widget.
bool use_markup_
Use markup for the label?
PangoEllipsizeMode get_text_ellipse_mode() const
Get the text&#39;s ellipsize mode.
int text_maximum_width_
The maximum width for the text in a styled_widget.
Class to show the tips.
Definition: tooltip.cpp:57
const t_string & help_message() const
point resolution()
Definition: general.cpp:393
std::unique_ptr< window > build(const builder_window::window_resolution &definition)
Builds a window.
map_location coordinate
Contains an x and y coordinate used for starting positions in maps.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
canvas & get_canvas(const unsigned index)
resolution_definition_ptr config_
Contains the pointer to the configuration.
Contains the implementation details for lexical_cast and shouldn&#39;t be used directly.
ui_event
The event send to the dispatcher.
Definition: handler.hpp:48
std::string tooltip
Shown when hovering over an entry in the filter&#39;s drop-down list.
Definition: manager.cpp:219