Simulant  21.12-246
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
widget.h
1 #pragma once
2 
3 #include "../stage_node.h"
4 #include "../../generic/optional.h"
5 #include "../../generic/identifiable.h"
6 #include "../../generic/managed.h"
7 #include "../../generic/range_value.h"
8 #include "ui_config.h"
9 
10 namespace smlt {
11 namespace ui {
12 
13 enum WidgetLayerIndex {
14  WIDGET_LAYER_INDEX_BORDER,
15  WIDGET_LAYER_INDEX_BACKGROUND,
16  WIDGET_LAYER_INDEX_FOREGROUND,
17  WIDGET_LAYER_INDEX_TEXT,
18 };
19 
20 class UIManager;
21 
22 typedef sig::signal<void ()> WidgetPressedSignal;
23 typedef sig::signal<void ()> WidgetReleasedSignal; // Triggered on fingerup, but also on leave
24 typedef sig::signal<void ()> WidgetClickedSignal; // Triggered on fingerup only
25 typedef sig::signal<void ()> WidgetFocusedSignal;
26 typedef sig::signal<void ()> WidgetBlurredSignal;
27 
28 struct ImageRect {
29  UICoord bottom_left;
30  UICoord size;
31 };
32 
33 struct WidgetStyle {
34  /* There are 4 layers: Border, background, foreground and text and
35  * by default all are enabled. Setting any of the colours of these
36  * layers to Colour::NONE will deactivate drawing of the layer
37  * for performance reasons. We track that here */
38  uint8_t active_layers_ = ~0;
39 
40  UInt4 padding_ = {0, 0, 0, 0};
41  Px border_width_ = 1;
42  PackedColour4444 border_colour_ = Colour::BLACK;
43  TextAlignment text_alignment_ = TEXT_ALIGNMENT_CENTER;
44 
45  OverflowType overflow_ = OVERFLOW_TYPE_AUTO;
46 
47  TexturePtr background_image_;
48  ImageRect background_image_rect_;
49 
50  TexturePtr foreground_image_;
51  ImageRect foreground_image_rect_;
52 
53  PackedColour4444 background_colour_ = Colour::WHITE;
54  PackedColour4444 foreground_colour_ = Colour::NONE; //Transparent
55  PackedColour4444 text_colour_ = Colour::BLACK;
56 
57  float opacity_ = 1.0f;
58 
59  MaterialPtr materials_[3] = {nullptr, nullptr, nullptr};
60 };
61 
62 
63 /* Sizing:
64  *
65  * Widgets follow a similar model to the border-box model in CSS. Effectively:
66  *
67  * - If a dimension length has not been defined (e.g. requested_width_ == -1) then
68  * the dimension is calculated as the content size + padding + border.
69  * - If a dimension length has been defined, then the content size is reduced to make
70  * room for the padding and border.
71  *
72  * Content area:
73  *
74  * - The size of the content area varies depending on widget, but for most widgets this
75  * is defined as the area that the text takes to render, unless a fixed size has been
76  * specified and then this would be the requested size without padding or border
77  */
78 
79 class Widget:
80  public TypedDestroyableObject<Widget, UIManager>,
81  public ContainerNode,
82  public generic::Identifiable<WidgetID>,
84  public ChainNameable<Widget> {
85 
86  DEFINE_SIGNAL(WidgetPressedSignal, signal_pressed);
87  DEFINE_SIGNAL(WidgetReleasedSignal, signal_released);
88  DEFINE_SIGNAL(WidgetClickedSignal, signal_clicked);
89  DEFINE_SIGNAL(WidgetFocusedSignal, signal_focused);
90  DEFINE_SIGNAL(WidgetBlurredSignal, signal_blurred);
91 
92 public:
93  typedef std::shared_ptr<Widget> ptr;
94 
95  Widget(UIManager* owner, UIConfig* defaults, std::shared_ptr<WidgetStyle> shared_style=std::shared_ptr<WidgetStyle>());
96  virtual ~Widget();
97 
98  virtual bool init() override;
99  virtual void clean_up() override;
100 
101  void resize(Rem width, Px height);
102  void resize(Px width, Rem height);
103  void resize(Rem width, Rem height);
104  void resize(Px width, Px height);
105 
106  void set_font(const std::string& family=DEFAULT_FONT_FAMILY, Rem size=Rem(1.0f), FontWeight weight=FONT_WEIGHT_NORMAL, FontStyle style=FONT_STYLE_NORMAL);
107  void set_font(const std::string& family=DEFAULT_FONT_FAMILY, Px size=DEFAULT_FONT_SIZE, FontWeight weight=FONT_WEIGHT_NORMAL, FontStyle style=FONT_STYLE_NORMAL);
108 
109  /* Allow creating a double-linked list of widgets for focusing. There is no
110  * global focused widget but there is only one focused widget in a chain
111  */
112  bool is_focused() const;
113  void set_focus_previous(WidgetPtr previous_widget);
114  void set_focus_next(WidgetPtr next_widget);
115  void focus();
116  void blur();
117 
118  WidgetPtr next_in_focus_chain() const;
119  WidgetPtr previous_in_focus_chain() const;
120  void focus_next_in_chain(ChangeFocusBehaviour behaviour = FOCUS_THIS_IF_NONE_FOCUSED);
121  void focus_previous_in_chain(ChangeFocusBehaviour behaviour = FOCUS_THIS_IF_NONE_FOCUSED);
122  WidgetPtr first_in_focus_chain();
123  WidgetPtr last_in_focus_chain();
124  WidgetPtr focused_in_chain();
125 
126  // Manually trigger events
127  void click();
128 
129  void set_text(const unicode& text);
130 
131  void set_text_alignment(TextAlignment alignment);
132  TextAlignment text_alignment() const;
133 
134  void set_border_width(Px x);
135  Px border_width() const;
136 
137  void set_border_colour(const Colour& colour);
138  void set_overflow(OverflowType type);
139 
140  void set_padding(Px x);
141  void set_padding(Px left, Px right, Px bottom, Px top);
142  UInt4 padding() const;
143 
144  virtual bool set_resize_mode(ResizeMode resize_mode);
145 
146  ResizeMode resize_mode() const;
147 
148  bool has_background_image() const;
149 
150  bool has_foreground_image() const;
151 
153  void set_background_image(TexturePtr texture);
154 
156  void set_background_image_source_rect(const UICoord& bottom_left, const UICoord& size);
157 
158  void set_background_colour(const Colour& colour);
159  void set_foreground_colour(const Colour& colour);
160 
162  void set_foreground_image(TexturePtr texture);
163 
165  void set_foreground_image_source_rect(const UICoord& bottom_left, const UICoord& size);
166 
167  void set_text_colour(const Colour& colour);
168 
169  Px requested_width() const;
170  Px requested_height() const;
171 
172  Px content_width() const;
173  Px content_height() const;
174 
178  Px outer_width() const;
179  Px outer_height() const;
180 
181  /*
182  bool is_checked() const; // Widget dependent, returns false if widget has no concept of 'active'
183  bool is_enabled() const; // Widget dependent, returns true if widget has no concept of 'disabled'
184  bool is_hovered() const; // Widget dependent, returns false if widget has no concept of 'hovered'
185  */
186 
187 
188  const AABB& aabb() const override;
189 
190  const unicode& text() const {
191  return text_;
192  }
193 
194  // Probably shouldn't use these directly (designed for UIManager)
195  void fingerdown(uint8_t finger_id);
196  void fingerup(uint8_t finger_id);
197  void fingerenter(uint8_t finger_id);
198  void fingermove(uint8_t finger_id);
199  void fingerleave(uint8_t finger_id);
200  bool is_pressed_by_finger(uint8_t finger_id);
201 
202  /* Releases all presses forcibly, firing signals */
203  void force_release();
204 
205  void set_anchor_point(RangeValue<0, 1> x, RangeValue<0, 1> y);
206  smlt::Vec2 anchor_point() const;
207 
208  void set_opacity(RangeValue<0, 1> alpha);
209 
210  Px line_height() const;
211 public:
212  MaterialPtr border_material() const { return style_->materials_[0]; }
213  MaterialPtr background_material() const { return style_->materials_[1]; }
214  MaterialPtr foreground_material() const { return style_->materials_[2]; }
215 
216 private:
217  void on_render_priority_changed(
218  RenderPriority old_priority, RenderPriority new_priority
219  ) override;
220 
221  bool initialized_ = false;
222 
223  ActorPtr actor_ = nullptr;
224  MeshPtr mesh_ = nullptr;
225 
226 protected:
227  /* Allow sharing a style across composite widgets */
228  void set_style(std::shared_ptr<WidgetStyle> style);
229 
230  friend class Keyboard; // For set_font calls on child widgets
231 
232  UIManager* owner_ = nullptr;
233  FontPtr font_ = nullptr;
234 
235  std::shared_ptr<WidgetStyle> style_;
236 
237  ResizeMode resize_mode_ = RESIZE_MODE_FIT_CONTENT;
238 
239  Px text_width_ = 0;
240  Px text_height_ = 0;
241 
242  Px requested_width_ = -1;
243  Px requested_height_ = -1;
244 
245  Px content_width_ = 0;
246  Px content_height_ = 0;
247 
248  unicode text_;
249 
250  bool is_focused_ = false;
251  WidgetPtr focus_next_ = nullptr;
252  WidgetPtr focus_previous_ = nullptr;
253 
254  /* A normalized vector representing the relative
255  * anchor position for movement (0, 0 == bottom left) */
256  smlt::Vec2 anchor_point_;
257  bool anchor_point_dirty_;
258 
259  uint16_t fingers_down_ = 0;
260 
261  virtual void on_size_changed();
262 
263  /* Only called on construction, it just makes sure that
264  * active_layers_ is in sync with whatever the default layer
265  * colours are. If we change a layer colour we manually alter
266  * the active_layers_ flag from that point on */
267  void _recalc_active_layers();
268 
269  bool border_active() const;
270  bool background_active() const;
271  bool foreground_active() const;
272 
273  struct WidgetBounds {
274  UICoord min;
275  UICoord max;
276 
277  Px width() const { return max.x - min.x; }
278  Px height() const { return max.y - min.y; }
279 
280  bool has_non_zero_area() const {
281  Px w = width();
282  Px h = height();
283  return std::abs(w.value) > 0 && std::abs(h.value) > 0;
284  }
285  };
286 
287  virtual WidgetBounds calculate_background_size(const UIDim& content_dimensions) const;
288  virtual WidgetBounds calculate_foreground_size(const UIDim& content_dimensions) const;
289 
290  virtual UIDim calculate_content_dimensions(Px text_width, Px text_height);
291 
292 
293  void apply_image_rect(SubMeshPtr submesh, TexturePtr image, ImageRect& rect);
294 
295  SubMeshPtr new_rectangle(const std::string& name, WidgetBounds bounds, const smlt::Colour& colour);
296  void clear_mesh();
297 
298  bool is_initialized() const { return initialized_; }
299 
300  MeshPtr mesh() { return mesh_; }
301 
302  void render_text();
303 
304  WidgetPtr focused_in_chain_or_this();
305 
306  void on_transformation_change_attempted() override;
307 
308  void rebuild();
309  virtual void set_font(FontPtr font);
310 
311  virtual void prepare_build() {}
312  virtual void finalize_build() {}
313 };
314 
315 }
316 }
smlt::ui::Keyboard
Definition: keyboard.h:43
smlt::ui::UIManager
Definition: ui_manager.h:54
smlt::PackedColour4444
Definition: colour.h:118
smlt::ui::Widget::set_background_image
void set_background_image(TexturePtr texture)
Definition: widget.cpp:694
smlt::ui::Rem
Definition: ui_config.h:150
smlt::ui::UICoord
Definition: ui_config.h:106
smlt::ui::Widget::set_background_image_source_rect
void set_background_image_source_rect(const UICoord &bottom_left, const UICoord &size)
Definition: widget.cpp:718
smlt
Definition: animation.cpp:25
smlt::ui::Widget
Definition: widget.h:84
smlt::HasMutableRenderPriority
Definition: renderable.h:38
smlt::ui::UIConfig
Definition: ui_config.h:172
smlt::generic::Identifiable
Definition: identifiable.h:26
smlt::ContainerNode
Definition: stage_node.h:288
smlt::RangeValue
Definition: range_value.h:24
smlt::TypedDestroyableObject
Definition: manual_object.h:33
smlt::ui::UInt4
Definition: ui_config.h:130
smlt::ui::Px
Definition: ui_config.h:37
smlt::ui::Widget::set_foreground_image_source_rect
void set_foreground_image_source_rect(const UICoord &bottom_left, const UICoord &size)
Definition: widget.cpp:754
smlt::ui::Widget::set_foreground_image
void set_foreground_image(TexturePtr texture)
Definition: widget.cpp:729
smlt::ChainNameable
Definition: nameable.h:34
smlt::AABB
Definition: aabb.h:22
unicode
Definition: unicode.h:35
smlt::ui::ImageRect
Definition: widget.h:28
smlt::ui::Widget::outer_width
Px outer_width() const
Definition: widget.cpp:818
smlt::default_init_ptr< Widget >
smlt::ui::WidgetStyle
Definition: widget.h:33
smlt::ui::Widget::WidgetBounds
Definition: widget.h:273
smlt::SubMesh
Definition: submesh.h:42
smlt::Colour
Definition: colour.h:29
smlt::ui::UIDim
Definition: ui_config.h:120
smlt::Vec2
Definition: vec2.h:13
smlt::sig::signal< void()>