Simulant  21.12-1292
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
widget.h
1 #pragma once
2 
3 #include "../../generic/identifiable.h"
4 #include "../../generic/managed.h"
5 #include "../../generic/optional.h"
6 #include "../../generic/range_value.h"
7 #include "../stage_node.h"
8 #include "ui_config.h"
9 
10 namespace smlt {
11 namespace ui {
12 
13 /* We implicitly convert Px and float to int */
14 struct WidgetImpl {
15  static optional<ParamValue> coerce_to_int(any in) {
16  try {
17  ParamValue ret = any_cast<int>(in);
18  return ret;
19  } catch(bad_any_cast&) {
20  any result = in;
21  try {
22  auto px = any_cast<Px>(in);
23  result = (int)px.value;
24  } catch(bad_any_cast&) {
25  try {
26  float f = any_cast<float>(in);
27  return ParamValue(f);
28  } catch(bad_any_cast&) {
29  return no_value;
30  }
31  }
32  return no_value;
33  }
34  }
35 };
36 
37 } // namespace ui
38 } // namespace smlt
39 
40 #define S_DEFINE_CORE_WIDGET_PROPERTIES(klass) \
41  _S_DEFINE_STAGE_NODE_PARAM(10000, klass, "width", int, -1, \
42  "The width of the widget"); \
43  _S_DEFINE_STAGE_NODE_PARAM(10001, klass, "height", int, -1, \
44  "The height of the widget"); \
45  _S_DEFINE_STAGE_NODE_PARAM(10002, klass, "theme", smlt::ui::UIConfig, \
46  smlt::ui::UIConfig(), \
47  "The theme to use for this widget"); \
48  _S_DEFINE_STAGE_NODE_PARAM( \
49  10003, klass, "shared_style", smlt::ui::WidgetStylePtr, \
50  smlt::ui::WidgetStylePtr(), "A shared style to use for this widget")
51 
52 namespace smlt {
53 namespace ui {
54 
55 enum WidgetLayerIndex {
56  WIDGET_LAYER_INDEX_BORDER,
57  WIDGET_LAYER_INDEX_BACKGROUND,
58  WIDGET_LAYER_INDEX_FOREGROUND,
59  WIDGET_LAYER_INDEX_TEXT,
60 };
61 
62 class UIManager;
63 
64 typedef sig::signal<void()> WidgetPressedSignal;
65 typedef sig::signal<void()>
66  WidgetReleasedSignal; // Triggered on fingerup, but also on leave
67 typedef sig::signal<void()> WidgetClickedSignal; // Triggered on fingerup only
68 typedef sig::signal<void()> WidgetFocusedSignal;
69 typedef sig::signal<void()> WidgetBlurredSignal;
70 
71 struct ImageRect {
72  UICoord bottom_left;
73  UICoord size;
74 };
75 
76 struct WidgetStyle {
77  /* There are 4 layers: Border, background, foreground and text and
78  * by default all are enabled. Setting any of the colors of these
79  * layers to Color::none() will deactivate drawing of the layer
80  * for performance reasons. We track that here */
81  uint8_t active_layers_ = ~0;
82 
83  UInt4 padding_ = {Px(), Px(), Px(), Px()};
84  Px border_radius_ = Px(0);
85  Px border_width_ = Px(1);
86  PackedColor4444 border_color_ = Color::black();
87  TextAlignment text_alignment_ = TEXT_ALIGNMENT_CENTER;
88 
89  OverflowType overflow_ = OVERFLOW_TYPE_AUTO;
90 
91  TexturePtr background_image_;
92  ImageRect background_image_rect_;
93 
94  TexturePtr foreground_image_;
95  ImageRect foreground_image_rect_;
96 
97  PackedColor4444 background_color_ = Color::white();
98  PackedColor4444 foreground_color_ = Color::none(); // Transparent
99  PackedColor4444 text_color_ = Color::black();
100 
101  float opacity_ = 1.0f;
102 
103  MaterialPtr materials_[3] = {nullptr, nullptr, nullptr};
104 };
105 
106 typedef std::shared_ptr<WidgetStyle> WidgetStylePtr;
107 
108 /* Sizing:
109  *
110  * Widgets follow a similar model to the border-box model in CSS.
111  * Effectively:
112  *
113  * - If a dimension length has not been defined (e.g. requested_width_ ==
114  * -1) then the dimension is calculated as the content size + padding +
115  * border.
116  * - If a dimension length has been defined, then the content size is
117  * reduced to make room for the padding and border.
118  *
119  * Content area:
120  *
121  * - The size of the content area varies depending on widget, but for most
122  * widgets this is defined as the area that the text takes to render, unless
123  * a fixed size has been specified and then this would be the requested size
124  * without padding or border
125  */
126 
127 class Widget:
128  public ContainerNode,
130  public ChainNameable<Widget> {
131 
132  DEFINE_SIGNAL(WidgetPressedSignal, signal_pressed);
133  DEFINE_SIGNAL(WidgetReleasedSignal, signal_released);
134  DEFINE_SIGNAL(WidgetClickedSignal, signal_clicked);
135  DEFINE_SIGNAL(WidgetFocusedSignal, signal_focused);
136  DEFINE_SIGNAL(WidgetBlurredSignal, signal_blurred);
137 
138 public:
139  typedef std::shared_ptr<Widget> ptr;
140 
141  Widget(Scene* owner, StageNodeType type);
142  virtual ~Widget();
143 
144  virtual bool on_init() override;
145  virtual void on_clean_up() override;
146 
147  bool on_create(Params params) override;
148 
149  void resize(Rem width, Px height);
150  void resize(Px width, Rem height);
151  void resize(Rem width, Rem height);
152  void resize(Px width, Px height);
153 
154  void set_font(const std::string& family = DEFAULT_FONT_FAMILY,
155  Rem size = Rem(1.0f), FontWeight weight = FONT_WEIGHT_NORMAL,
156  FontStyle style = FONT_STYLE_NORMAL);
157  void set_font(const std::string& family = DEFAULT_FONT_FAMILY,
158  Px size = DEFAULT_FONT_SIZE,
159  FontWeight weight = FONT_WEIGHT_NORMAL,
160  FontStyle style = FONT_STYLE_NORMAL);
161 
162  // You probably don't want this one
163  virtual void set_font(FontPtr font);
164 
165  /* Allow creating a double-linked list of widgets for focusing. There is
166  * no global focused widget but there is only one focused widget in a
167  * chain
168  */
169  bool is_focused() const;
170  void set_focus_previous(WidgetPtr previous_widget);
171  void set_focus_next(WidgetPtr next_widget);
172  void focus();
173  void blur();
174 
175  WidgetPtr next_in_focus_chain() const;
176  WidgetPtr previous_in_focus_chain() const;
177  void focus_next_in_chain(
178  ChangeFocusBehaviour behaviour = FOCUS_THIS_IF_NONE_FOCUSED);
179  void focus_previous_in_chain(
180  ChangeFocusBehaviour behaviour = FOCUS_THIS_IF_NONE_FOCUSED);
181  WidgetPtr first_in_focus_chain();
182  WidgetPtr last_in_focus_chain();
183  WidgetPtr focused_in_chain();
184 
185  // Manually trigger events
186  void click();
187 
188  void set_text(const unicode& text);
189 
190  void set_text_alignment(TextAlignment alignment);
191  TextAlignment text_alignment() const;
192 
193  void set_border_width(Px x);
194  Px border_width() const;
195 
196  void set_border_radius(Px x);
197  Px border_radius() const;
198 
199  void set_border_color(const Color& color);
200  void set_overflow(OverflowType type);
201 
202  void set_padding(Px x);
203  void set_padding(Px left, Px right, Px bottom, Px top);
204  UInt4 padding() const;
205 
206  virtual bool set_resize_mode(ResizeMode resize_mode);
207 
208  ResizeMode resize_mode() const;
209  WrapMode wrap_mode() const {
210  return wrap_mode_;
211  }
212  void set_wrap_mode(WrapMode mode) {
213  wrap_mode_ = mode;
214  }
215 
216  bool has_background_image() const;
217 
218  bool has_foreground_image() const;
219 
221  void set_background_image(TexturePtr texture);
222 
226  void set_background_image_source_rect(const UICoord& bottom_left,
227  const UICoord& size);
228 
229  void set_background_color(const Color& color);
230  void set_foreground_color(const Color& color);
231 
233  void set_foreground_image(TexturePtr texture);
234 
238  void set_foreground_image_source_rect(const UICoord& bottom_left,
239  const UICoord& size);
240 
241  void set_text_color(const Color& color);
242 
243  Px requested_width() const;
244  Px requested_height() const;
245 
246  Px content_width() const;
247  Px content_height() const;
248 
252  Px outer_width() const;
253  Px outer_height() const;
254 
255  /*
256  bool is_checked() const; // Widget dependent, returns false if widget
257  has no concept of 'active' bool is_enabled() const; // Widget dependent,
258  returns true if widget has no concept of 'disabled' bool is_hovered()
259  const; // Widget dependent, returns false if widget has no concept of
260  'hovered'
261  */
262 
263  const AABB& aabb() const override;
264 
265  const unicode& text() const {
266  return calc_text();
267  }
268 
269  // Probably shouldn't use these directly (designed for UIManager)
270  void fingerdown(uint8_t finger_id);
271  void fingerup(uint8_t finger_id);
272  void fingerenter(uint8_t finger_id);
273  void fingermove(uint8_t finger_id);
274  void fingerleave(uint8_t finger_id);
275  bool is_pressed_by_finger(uint8_t finger_id);
276  bool is_pressed() const;
277 
278  /* Releases all presses forcibly, firing signals */
279  void force_release();
280 
281  void set_anchor_point(RangeValue<0, 1> x, RangeValue<0, 1> y);
282  smlt::Vec2 anchor_point() const;
283 
284  void set_opacity(RangeValue<0, 1> alpha);
285 
286  Px line_height() const;
287 
288  void set_precedence(int16_t precedence);
289 
290  int16_t precedence() const;
291 
292 public:
293  MaterialPtr border_material() const {
294  return style_->materials_[0];
295  }
296  MaterialPtr background_material() const {
297  return style_->materials_[1];
298  }
299  MaterialPtr foreground_material() const {
300  return style_->materials_[2];
301  }
302 
303 private:
304  virtual const unicode& calc_text() const {
305  return text_;
306  }
307 
308  void on_render_priority_changed(RenderPriority old_priority,
309  RenderPriority new_priority) override;
310 
311  bool initialized_ = false;
312 
313  ActorPtr actor_ = nullptr;
314 
315 protected:
316  MeshPtr mesh_ = nullptr;
317 
318  /* Allow sharing a style across composite widgets */
319  void set_style(std::shared_ptr<WidgetStyle> style);
320 
321  friend class Keyboard; // For set_font calls on child widgets
322 
323  UIConfig theme_;
324  FontPtr font_ = nullptr;
325 
326  std::shared_ptr<WidgetStyle> style_;
327 
328  ResizeMode resize_mode_ = RESIZE_MODE_FIT_CONTENT;
329  WrapMode wrap_mode_ = WRAP_MODE_WORD;
330 
331  Px text_width_ = Px(0);
332  Px text_height_ = Px(0);
333 
334  Px requested_width_ = Px(-1);
335  Px requested_height_ = Px(-1);
336 
337  Px content_width_ = Px(0);
338  Px content_height_ = Px(0);
339 
340  unicode text_;
341 
342  bool is_focused_ = false;
343  WidgetPtr focus_next_ = nullptr;
344  WidgetPtr focus_previous_ = nullptr;
345 
346  /* A normalized vector representing the relative
347  * anchor position for movement (0, 0 == bottom left) */
348  smlt::Vec2 anchor_point_;
349  bool anchor_point_dirty_ = true;
350 
351  uint16_t fingers_down_ = 0;
352 
353  virtual void on_size_changed();
354 
355  /* Only called on construction, it just makes sure that
356  * active_layers_ is in sync with whatever the default layer
357  * colors are. If we change a layer color we manually alter
358  * the active_layers_ flag from that point on */
359  void _recalc_active_layers();
360 
361  bool border_active() const;
362  bool background_active() const;
363  bool foreground_active() const;
364 
365  struct WidgetBounds {
366  UICoord min;
367  UICoord max;
368 
369  Px width() const {
370  return max.x - min.x;
371  }
372  Px height() const {
373  return max.y - min.y;
374  }
375 
376  bool has_non_zero_area() const {
377  Px w = width();
378  Px h = height();
379  return std::abs(w.value) > 0 && std::abs(h.value) > 0;
380  }
381  };
382 
383  virtual WidgetBounds
384  calculate_background_size(const UIDim& content_dimensions) const;
385  virtual WidgetBounds
386  calculate_foreground_size(const UIDim& content_dimensions) const;
387 
388  virtual UIDim calculate_content_dimensions(Px text_width, Px text_height);
389 
390  void apply_image_rect(SubMeshPtr submesh, TexturePtr image,
391  ImageRect& rect);
392 
393  SubMeshPtr new_rectangle(const std::string& name, WidgetBounds bounds,
394  const smlt::Color& color, const Px& border_radius,
395  const Vec2* uvs = nullptr, float z_offset = 0.0f);
396  void clear_mesh();
397 
398  bool is_initialized() const {
399  return initialized_;
400  }
401 
402  MeshPtr mesh() {
403  return mesh_;
404  }
405 
406  virtual void render_text();
407  virtual void render_border(const WidgetBounds& border_bounds);
408  virtual void render_background(const WidgetBounds& background_bounds);
409  virtual void render_foreground(const WidgetBounds& foreground_bounds);
410 
411  WidgetPtr focused_in_chain_or_this();
412 
413  void on_transformation_change_attempted() override;
414 
415  void rebuild();
416 
417  virtual void prepare_build() {}
418  virtual void finalize_render() {}
419  virtual void finalize_build() {}
420  virtual bool pre_set_text(const unicode&) {
421  return true;
422  }
423 
424  void build_text_submeshes();
425 
426  FontPtr load_or_get_font(const std::string& family, const Px& size,
427  const FontWeight& weight, const FontStyle& style);
428 
429 private:
430  MaterialPtr find_or_create_material(const char* name);
431 
432  FontPtr _load_or_get_font(AssetManager* assets, AssetManager* shared_assets,
433  const std::string& familyc, const Px& sizec,
434  const FontWeight& weight, const FontStyle& style);
435 };
436 
437 } // namespace ui
438 } // namespace smlt
smlt::Actor
Definition: actor.h:53
smlt::ui::Keyboard
Definition: keyboard.h:46
smlt::v1::bad_any_cast
Definition: any.h:129
smlt::ui::WidgetImpl
Definition: widget.h:14
smlt::ui::Widget::set_background_image
void set_background_image(TexturePtr texture)
Definition: widget.cpp:990
smlt::ui::Rem
Definition: ui_config.h:222
smlt::ui::UICoord
Definition: ui_config.h:178
smlt::ui::Widget::set_background_image_source_rect
void set_background_image_source_rect(const UICoord &bottom_left, const UICoord &size)
Definition: widget.cpp:1015
smlt::v1::any
Definition: any.h:136
smlt::Params
Definition: params.h:44
smlt
Definition: animation.cpp:25
smlt::ui::Widget
Definition: widget.h:130
smlt::HasMutableRenderPriority
Definition: renderable.h:38
smlt::Scene
Definition: scene.h:94
smlt::Color
Definition: color.h:32
smlt::ui::UIConfig
Definition: ui_config.h:246
smlt::ContainerNode
Definition: stage_node.h:1040
smlt::RangeValue
Definition: range_value.h:24
smlt::PackedColor4444
Definition: color.h:219
smlt::ui::UInt4
Definition: ui_config.h:202
smlt::ui::Px
Definition: ui_config.h:42
smlt::optional< ParamValue >
smlt::ui::Widget::set_foreground_image_source_rect
void set_foreground_image_source_rect(const UICoord &bottom_left, const UICoord &size)
Definition: widget.cpp:1054
smlt::ui::Widget::set_foreground_image
void set_foreground_image(TexturePtr texture)
Definition: widget.cpp:1028
smlt::ChainNameable
Definition: nameable.h:34
smlt::AABB
Definition: aabb.h:22
unicode
Definition: unicode.h:36
smlt::ui::ImageRect
Definition: widget.h:71
smlt::ui::Widget::outer_width
Px outer_width() const
Definition: widget.cpp:1120
smlt::ui::WidgetStyle
Definition: widget.h:76
smlt::ui::Widget::WidgetBounds
Definition: widget.h:365
smlt::SubMesh
Definition: submesh.h:42
smlt::ui::UIDim
Definition: ui_config.h:192
smlt::Vec2
Definition: vec2.h:16
smlt::sig::signal< void()>