The Battle for Wesnoth  1.15.1+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 /** Base class for all visible items. */
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
43  * object.
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 string_map& 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_base* 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  */
108  point get_config_minimum_size() const;
109 
110  /**
111  * Gets the default size as defined in the config.
112  *
113  * @pre config_ != nullptr
114  *
115  * @returns The size.
116  */
117  point get_config_default_size() const;
118 
119  /**
120  * Gets the best size as defined in the config.
121  *
122  * @pre config_ != nullptr
123  *
124  * @returns The size.
125  */
126  point get_config_maximum_size() const;
127 
128  /**
129  * Returns the number of characters per line.
130  *
131  * This value is used to call @ref 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 @ref 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 @ref 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  {
204  return use_tooltip_on_label_overflow_;
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& label);
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;
235  set_wants_mouse_hover(!tooltip_.empty());
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.
244  void set_help_message(const t_string& help_message)
245  {
246  help_message_ = help_message;
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<resolution_definition, typename T::resolution>::value,
304  "Given type's resolution object does not derive from resolution_definition."
305  );
306 
307  return std::static_pointer_cast<const typename T::resolution>(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  * Returns the maximum width available for the text.
327  *
328  * This value makes sense after the widget has been given a size, since the
329  * maximum width is based on the width of the widget.
330  */
331  int get_text_maximum_width() const;
332 
333  /**
334  * Returns the maximum height available for the text.
335  *
336  * This value makes sense after the widget has been given a size, since the
337  * maximum height is based on the height of the widget.
338  */
339  int get_text_maximum_height() const;
340 
341 private:
342  /**
343  * The definition is the id of that widget class.
344  *
345  * Eg for a button it [button_definition]id. A button can have multiple
346  * definitions which all look different but for the engine still is a
347  * button.
348  */
349  std::string definition_;
350 
351  /** Contain the non-editable text associated with styled_widget. */
353 
354  /** Use markup for the label? */
356 
357  /**
358  * If the text doesn't fit on the label should the text be used as tooltip?
359  *
360  * This only happens if the tooltip is empty.
361  */
363 
364  /**
365  * Tooltip text.
366  *
367  * The hovering event can cause a small tooltip to be shown, this is the
368  * text to be shown. At the moment the tooltip is a single line of text.
369  */
371 
372  /**
373  * Tooltip text.
374  *
375  * The help event can cause a tooltip to be shown, this is the text to be
376  * shown. At the moment the tooltip is a single line of text.
377  */
379 
380  /**
381  * Contains the pointer to the configuration.
382  *
383  * Every styled_widget has a definition of how it should look, this contains a
384  * pointer to the definition. The definition is resolution dependent, where
385  * the resolution is the size of the Wesnoth application window. Depending
386  * on the resolution widgets can look different, use different fonts.
387  * Windows can use extra scrollbars use abbreviations as text etc.
388  */
390 
391  /**
392  * Holds all canvas objects for a styled_widget.
393  *
394  * A styled_widget can have multiple states, which are defined in the classes
395  * inheriting from us. For every state there is a separate canvas, which is
396  * stored here. When drawing the state is determined and that canvas is
397  * drawn.
398  */
399  std::vector<canvas> canvases_;
400 
401 public:
402  /**
403  * Returns the type of this styled_widget.
404  *
405  * This is used as the control_type parameter for @ref get_control.
406  *
407  * Do note that each widget also must have a public static type() function;
408  * it's use to implement this function. The reason for this system is twofold:
409  *
410  * 1) Due to an oddity in C++, one technically may not call a virtual function
411  * in a derived class's *initializer list*, which we do liberally. Calling
412  * it in the constructor *body* is fine, but doing so in the initializer list
413  * is technically undefined behavior and will give "invalid vptr" errors
414  * under UBSanitizer.
415  *
416  * 2) Having a static type getter allows the type string to be fetched without
417  * constructing an instance of the widget. A good example of this usecase is
418  * in @ref build_single_widget_and_cast_to.
419  */
420  virtual const std::string& get_control_type() const = 0;
421 
422 protected:
423  /** See @ref widget::impl_draw_background. */
424  virtual void impl_draw_background(surface& frame_buffer,
425  int x_offset,
426  int y_offset) override;
427 
428  /** See @ref widget::impl_draw_foreground. */
429  virtual void impl_draw_foreground(surface& frame_buffer,
430  int x_offset,
431  int y_offset) override;
432 
433  /** Exposes font::pango_text::get_token, for the text label of this styled_widget */
434  std::string get_label_token(const point & position, const char * delimiters = " \n\r\t") const;
435 
436  std::string get_label_link(const point & position) const;
437 
438 private:
439  /**
440  * Gets the best size for a text.
441  *
442  * @param minimum_size The minimum size of the text.
443  * @param maximum_size The wanted maximum size of the text, if not
444  * possible it's ignored. A value of 0 means
445  * that it's ignored as well.
446  *
447  * @returns The best size.
448  */
449  point get_best_text_size(point minimum_size,
450  point maximum_size = {0, 0}) const;
451 
452  /**
453  * Gets whether a widget can shrink past its optimal size even if it's text-based (such as labels);
454  */
455  virtual bool text_can_shrink()
456  {
457  return false;
458  }
459 
460  /**
461  * Text renderer object used for size calculations.
462  *
463  * Note this is *not* used to actually render any text, only to get the dimensions of the text for
464  * layout purposes. The actual text rendering happens in the canvas. This is kept as a class member
465  * since creating a pango_text object is quite expensive.
466  *
467  * @todo Maybe if still too slow we might also copy this cache to the
468  * canvas so it can reuse our results, but for now it seems fast enough.
469  * Unfortunately that would make the dependency between the classes bigger
470  * as wanted.
471  */
473 
474  /** The maximum width for the text in a styled_widget. */
476 
477  /** The alignment of the text in a styled_widget. */
478  PangoAlignment text_alignment_;
479 
480  /** The ellipsize mode of the text in a styled_widget. */
481  PangoEllipsizeMode text_ellipse_mode_;
482 
483  /** Is the widget smaller as it's best size? */
484  bool shrunken_;
485 
486  /***** ***** ***** signal handlers ***** ****** *****/
487 
488  void signal_handler_show_tooltip(const event::ui_event event,
489  bool& handled,
490  const point& location);
491 
492  void signal_handler_show_helptip(const event::ui_event event,
493  bool& handled,
494  const point& location);
495 
496  void signal_handler_notify_remove_tooltip(const event::ui_event event,
497  bool& handled);
498 };
499 
500 // }---------- BUILDER -----------{
501 
502 class styled_widget;
503 
504 namespace implementation
505 {
506 
508 {
509 public:
510  builder_styled_widget(const config& cfg);
511 
512  using builder_widget::build;
513 
514  virtual widget* build(const replacements_map& replacements) const override;
515 
516  /** Parameters for the styled_widget. */
517  std::string definition;
523 };
524 
525 } // namespace implementation
526 
527 // }------------ END --------------
528 
529 } // 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:47
std::shared_ptr< const resolution_definition > resolution_definition_const_ptr
Label showing a text.
Definition: label.hpp:32
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.
window * build(const builder_window::window_resolution *definition)
Builds a window.
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:24
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
bool find(E event, F functor)
Tests whether an event handler is available.
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:71
const t_string & help_message() const
point resolution()
Definition: general.cpp:373
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:92
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:55