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