lxgui
gui_button.cpp
1 #include "lxgui/gui_button.hpp"
2 
3 #include "lxgui/gui_alive_checker.hpp"
4 #include "lxgui/gui_font_string.hpp"
5 #include "lxgui/gui_frame.hpp"
6 #include "lxgui/gui_manager.hpp"
7 #include "lxgui/gui_out.hpp"
8 #include "lxgui/gui_region_tpl.hpp"
9 #include "lxgui/gui_texture.hpp"
10 
11 namespace lxgui::gui {
12 
13 button::button(utils::control_block& block, manager& mgr, const frame_core_attributes& attr) :
14  frame(block, mgr, attr) {
15 
16  initialize_(*this, attr);
17 
18  enable_mouse();
20 }
21 
22 std::string button::serialize(const std::string& tab) const {
23  return base::serialize(tab);
24 }
25 
26 bool button::can_use_script(const std::string& script_name) const {
27  return base::can_use_script(script_name) || script_name == "OnClick" ||
28  script_name == "OnEnable" || script_name == "OnDisable";
29 }
30 
31 void button::fire_script(const std::string& script_name, const event_data& data) {
32  alive_checker checker(*this);
33  base::fire_script(script_name, data);
34  if (!checker.is_alive())
35  return;
36 
37  if (!is_enabled())
38  return;
39 
40  if (script_name == "OnEnter")
41  highlight();
42 
43  if (script_name == "OnLeave") {
44  unlight();
45 
46  if (state_ == state::down)
47  release();
48  }
49 
50  bool try_handle_click = false;
51  if (script_name == "OnMouseDown" || script_name == "OnMouseUp" ||
52  script_name == "OnDoubleClick") {
53 
54  try_handle_click = true;
55 
56  // If reacting to a "mouse up" event, only handle as a click if
57  // the mouse was pressed down on this button.
58  if (script_name == "OnMouseUp" && !data.get<bool>(5)) {
59  try_handle_click = false;
60  }
61  }
62 
63  if (try_handle_click) {
64  const input::mouse_button button_id = data.get<input::mouse_button>(0);
65  const input::mouse_button_event event_id =
66  script_name == "OnMouseDown" ? input::mouse_button_event::down
67  : script_name == "OnMouseUp" ? input::mouse_button_event::up
69 
70  if (is_button_clicks_enabled_(button_id)) {
71  if (event_id == input::mouse_button_event::down)
72  push();
73  else if (event_id == input::mouse_button_event::up)
74  release();
75  }
76 
77  float mx = data.get<float>(2);
78  float my = data.get<float>(3);
79 
80  click_(button_id, event_id, mx, my);
81  if (!checker.is_alive())
82  return;
83  }
84 }
85 
86 void button::copy_from(const region& obj) {
87  base::copy_from(obj);
88 
89  const button* button_obj = down_cast<button>(&obj);
90  if (!button_obj)
91  return;
92 
93  this->set_text(button_obj->get_text());
94 
95  if (const texture* other_texture = button_obj->get_normal_texture().get()) {
97  attr.name = other_texture->get_raw_name();
98  attr.inheritance = {button_obj->get_normal_texture()};
99 
100  auto tex =
101  this->create_layered_region<texture>(other_texture->get_draw_layer(), std::move(attr));
102 
103  if (tex) {
104  tex->set_manually_inherited(true);
105  tex->notify_loaded();
106  this->set_normal_texture(tex);
107  }
108  }
109 
110  if (const texture* other_texture = button_obj->get_pushed_texture().get()) {
112  attr.name = other_texture->get_raw_name();
113  attr.inheritance = {button_obj->get_pushed_texture()};
114 
115  auto tex =
116  this->create_layered_region<texture>(other_texture->get_draw_layer(), std::move(attr));
117 
118  if (tex) {
119  tex->set_manually_inherited(true);
120  tex->notify_loaded();
121  this->set_pushed_texture(tex);
122  }
123  }
124 
125  if (const texture* other_texture = button_obj->get_highlight_texture().get()) {
127  attr.name = other_texture->get_raw_name();
128  attr.inheritance = {button_obj->get_highlight_texture()};
129 
130  auto tex =
131  this->create_layered_region<texture>(other_texture->get_draw_layer(), std::move(attr));
132 
133  if (tex) {
134  tex->set_manually_inherited(true);
135  tex->notify_loaded();
136  this->set_highlight_texture(tex);
137  }
138  }
139 
140  if (const texture* other_texture = button_obj->get_disabled_texture().get()) {
142  attr.name = other_texture->get_raw_name();
143  attr.inheritance = {button_obj->get_disabled_texture()};
144 
145  auto tex =
146  this->create_layered_region<texture>(other_texture->get_draw_layer(), std::move(attr));
147 
148  if (tex) {
149  tex->set_manually_inherited(true);
150  tex->notify_loaded();
151  this->set_disabled_texture(tex);
152  }
153  }
154 
155  if (const font_string* other_text = button_obj->get_normal_text().get()) {
157  attr.name = other_text->get_raw_name();
158  attr.inheritance = {button_obj->get_normal_text()};
159 
160  auto fstr =
161  this->create_layered_region<font_string>(other_text->get_draw_layer(), std::move(attr));
162 
163  if (fstr) {
164  fstr->set_manually_inherited(true);
165  fstr->notify_loaded();
166  this->set_normal_text(fstr);
167  }
168  }
169 
170  if (const font_string* other_text = button_obj->get_highlight_text().get()) {
172  attr.name = other_text->get_raw_name();
173  attr.inheritance = {button_obj->get_highlight_text()};
174 
175  auto fstr =
176  this->create_layered_region<font_string>(other_text->get_draw_layer(), std::move(attr));
177 
178  if (fstr) {
179  fstr->set_manually_inherited(true);
180  fstr->notify_loaded();
181  this->set_highlight_text(fstr);
182  }
183  }
184 
185  if (const font_string* other_text = button_obj->get_disabled_text().get()) {
187  attr.name = other_text->get_raw_name();
188  attr.inheritance = {button_obj->get_disabled_text()};
189 
190  auto fstr =
191  this->create_layered_region<font_string>(other_text->get_draw_layer(), std::move(attr));
192 
193  if (fstr) {
194  fstr->set_manually_inherited(true);
195  fstr->notify_loaded();
196  this->set_disabled_text(fstr);
197  }
198  }
199 
200  this->set_pushed_text_offset(button_obj->get_pushed_text_offset());
201 
202  if (!button_obj->is_enabled())
203  this->disable();
204 }
205 
206 void button::set_text(const utils::ustring& content) {
207  content_ = content;
208 
209  if (normal_text_)
210  normal_text_->set_text(content);
211 
212  if (highlight_text_)
213  highlight_text_->set_text(content);
214 
215  if (disabled_text_)
216  disabled_text_->set_text(content);
217 }
218 
219 const utils::ustring& button::get_text() const {
220  return content_;
221 }
222 
223 void button::set_normal_texture(utils::observer_ptr<texture> tex) {
224  normal_texture_ = std::move(tex);
225  if (!normal_texture_)
226  return;
227 
228  normal_texture_->set_shown(state_ == state::up);
229 }
230 
231 void button::set_pushed_texture(utils::observer_ptr<texture> tex) {
232  pushed_texture_ = std::move(tex);
233  if (!pushed_texture_)
234  return;
235 
236  pushed_texture_->set_shown(state_ == state::down);
237 }
238 
239 void button::set_disabled_texture(utils::observer_ptr<texture> tex) {
240  disabled_texture_ = std::move(tex);
241  if (!disabled_texture_)
242  return;
243 
245 }
246 
247 void button::set_highlight_texture(utils::observer_ptr<texture> tex) {
248  highlight_texture_ = std::move(tex);
249  if (!highlight_texture_)
250  return;
251 
253 }
254 
255 void button::set_normal_text(utils::observer_ptr<font_string> fstr) {
257  current_font_string_ = fstr;
258 
259  normal_text_ = std::move(fstr);
260  if (!normal_text_)
261  return;
262 
263  normal_text_->set_shown(state_ == state::up);
264  normal_text_->set_text(content_);
265 }
266 
267 void button::set_highlight_text(utils::observer_ptr<font_string> fstr) {
269  current_font_string_ = fstr;
270 
271  highlight_text_ = std::move(fstr);
272  if (!highlight_text_)
273  return;
274 
275  highlight_text_->set_shown(is_highlighted_);
276  highlight_text_->set_text(content_);
277 }
278 
279 void button::set_disabled_text(utils::observer_ptr<font_string> fstr) {
281  current_font_string_ = fstr;
282 
283  disabled_text_ = std::move(fstr);
284  if (!disabled_text_)
285  return;
286 
287  disabled_text_->set_shown(state_ == state::disabled);
288  disabled_text_->set_text(content_);
289 }
290 
292  if (!is_enabled())
293  return;
294 
296  if (disabled_texture_) {
297  if (normal_texture_)
298  normal_texture_->hide();
299  if (pushed_texture_)
300  pushed_texture_->hide();
301 
302  disabled_texture_->show();
303  } else {
304  if (normal_texture_)
305  normal_texture_->show();
306  if (pushed_texture_)
307  pushed_texture_->hide();
308  }
309 
310  if (disabled_text_) {
311  if (normal_text_)
312  normal_text_->hide();
313 
314  disabled_text_->show();
316  } else {
317  if (normal_text_)
318  normal_text_->show();
319 
321  }
322 
323  unlight();
324 
325  fire_script("OnDisable");
326 }
327 
329  if (is_enabled())
330  return;
331 
332  state_ = state::up;
333  if (disabled_texture_) {
334  if (normal_texture_)
335  normal_texture_->show();
336  if (pushed_texture_)
337  pushed_texture_->hide();
338 
339  disabled_texture_->hide();
340  } else {
341  if (normal_texture_)
342  normal_texture_->show();
343  if (pushed_texture_)
344  pushed_texture_->hide();
345  }
346 
347  if (normal_text_)
348  normal_text_->show();
349 
351 
352  if (disabled_text_)
353  disabled_text_->hide();
354 
355  fire_script("OnEnable");
356 }
357 
358 bool button::is_enabled() const {
359  return state_ != state::disabled;
360 }
361 
362 void button::push() {
363  if (!is_enabled())
364  return;
365 
366  if (pushed_texture_) {
367  pushed_texture_->show();
368  if (normal_texture_)
369  normal_texture_->hide();
370  }
371 
372  if (highlight_text_)
374  if (normal_text_)
375  normal_text_->set_offset(pushed_text_offset_);
376 
378 }
379 
381  if (!is_enabled())
382  return;
383 
384  if (pushed_texture_) {
385  pushed_texture_->hide();
386  if (normal_texture_)
387  normal_texture_->show();
388  }
389 
390  if (highlight_text_)
391  highlight_text_->set_offset(vector2f(0, 0));
392  if (normal_text_)
393  normal_text_->set_offset(vector2f(0, 0));
394 
395  state_ = state::up;
396 }
397 
398 void button::click(const std::string& mouse_event) {
399  auto mouse_event_id = input::get_mouse_button_and_event_from_codename(mouse_event);
400  if (!mouse_event_id.has_value()) {
401  return;
402  }
403 
404  click(mouse_event_id.value().first, mouse_event_id.value().second);
405 }
406 
409  click_(button_id, button_event, center.x, center.y);
410 }
411 
413  input::mouse_button button_id, input::mouse_button_event button_event, float mx, float my) {
414 
415  if (!is_button_clicks_enabled(button_id, button_event)) {
416  return;
417  }
418 
419  std::string event_name =
420  std::string{input::get_mouse_button_and_event_codename(button_id, button_event)};
421 
422  event_data new_data;
423  new_data.add(static_cast<std::underlying_type_t<input::mouse_button>>(button_id));
424  new_data.add(static_cast<std::underlying_type_t<input::mouse_button_event>>(button_event));
425  new_data.add(event_name);
426  new_data.add(mx);
427  new_data.add(my);
428  fire_script("OnClick", new_data);
429 }
430 
432  if (is_highlighted_)
433  return;
434 
435  if (highlight_texture_) {
436  highlight_texture_->show();
437  }
438 
439  if (highlight_text_) {
441  current_font_string_->hide();
443  current_font_string_->show();
444  }
445 
446  is_highlighted_ = true;
447 }
448 
451  return;
452 
453  if (highlight_texture_) {
454  highlight_texture_->hide();
455  }
456 
457  if (highlight_text_) {
459  current_font_string_->hide();
460 
461  switch (state_) {
465  }
466 
468  current_font_string_->show();
469  }
470 
471  is_highlighted_ = false;
472 }
473 
475  return state_;
476 }
477 
479  highlight();
480  is_highlight_locked_ = true;
481 }
482 
484  if (!is_mouse_in_frame_)
485  unlight();
486 
487  is_highlight_locked_ = false;
488 }
489 
491  pushed_text_offset_ = offset;
493 }
494 
496  return pushed_text_offset_;
497 }
498 
499 void button::enable_button_clicks(const std::string& mouse_state) {
500  reg_click_list_.insert(mouse_state);
501 }
502 
504  input::mouse_button button_id, input::mouse_button_event button_event) {
505  reg_click_list_.insert(
506  std::string{input::get_mouse_button_and_event_codename(button_id, button_event)});
507 }
508 
509 void button::disable_button_clicks(const std::string& mouse_state) {
510  reg_click_list_.erase(mouse_state);
511 }
512 
514  input::mouse_button button_id, input::mouse_button_event button_event) {
515  reg_click_list_.erase(
516  std::string{input::get_mouse_button_and_event_codename(button_id, button_event)});
517 }
518 
520  reg_click_list_.clear();
521 }
522 
523 bool button::is_button_clicks_enabled(const std::string& mouse_event) const {
524  return reg_click_list_.find(mouse_event) != reg_click_list_.end();
525 }
526 
528  input::mouse_button button_id, input::mouse_button_event button_event) const {
530  button_id, button_event)}) != reg_click_list_.end();
531 }
532 
534  auto button_name = input::get_mouse_button_codename(button_id);
535  for (const auto& click : reg_click_list_) {
536  if (click.find(button_name) == 0) {
537  return true;
538  }
539  }
540 
541  return false;
542 }
543 
544 const std::vector<std::string>& button::get_type_list_() const {
545  return get_type_list_impl_<button>();
546 }
547 
548 } // namespace lxgui::gui
Utility class for safe checking of region validity.
bool is_alive() const
Check if the wrapped region is still alive.
A frame with a button that can be clicked.
Definition: gui_button.hpp:52
const utils::observer_ptr< font_string > & get_normal_text()
Returns this button's normal text.
Definition: gui_button.hpp:172
bool is_button_clicks_enabled(const std::string &mouse_event) const
Checks if this button can generate OnClick events when a specific mouse event occurs over the button.
Definition: gui_button.cpp:523
void enable_button_clicks(const std::string &mouse_event)
Make this button generate OnClick events when a specific mouse event occurs over the button.
Definition: gui_button.cpp:499
const utils::observer_ptr< texture > & get_pushed_texture()
Returns this button's pushed texture.
Definition: gui_button.hpp:124
void set_highlight_text(utils::observer_ptr< font_string > fstr)
Sets this button's highlight text.
Definition: gui_button.cpp:267
void set_normal_texture(utils::observer_ptr< texture > tex)
Sets this button's normal texture.
Definition: gui_button.cpp:223
utils::observer_ptr< texture > highlight_texture_
Definition: gui_button.hpp:490
void click(const std::string &mouse_event)
Handle a mouse click over this button.
Definition: gui_button.cpp:398
void set_pushed_texture(utils::observer_ptr< texture > tex)
Sets this button's pushed texture.
Definition: gui_button.cpp:231
utils::observer_ptr< texture > disabled_texture_
Definition: gui_button.hpp:489
void set_disabled_texture(utils::observer_ptr< texture > tex)
Sets this button's disabled texture.
Definition: gui_button.cpp:239
state get_button_state() const
Returns this button's state.
Definition: gui_button.cpp:474
std::string serialize(const std::string &tab) const override
Prints all relevant information about this region in a string.
Definition: gui_button.cpp:22
bool is_button_clicks_enabled_(input::mouse_button button_id) const
Definition: gui_button.cpp:533
utils::observer_ptr< font_string > current_font_string_
Definition: gui_button.hpp:495
std::set< std::string > reg_click_list_
Definition: gui_button.hpp:499
virtual void disable()
Disables this button.
Definition: gui_button.cpp:291
void set_highlight_texture(utils::observer_ptr< texture > tex)
Sets this button's highlight texture.
Definition: gui_button.cpp:247
utils::observer_ptr< font_string > normal_text_
Definition: gui_button.hpp:492
virtual void click_(input::mouse_button button_id, input::mouse_button_event button_event, float mx, float my)
Definition: gui_button.cpp:412
bool is_enabled() const
Checks if this button is enabled.
Definition: gui_button.cpp:358
virtual void highlight()
Highlights this button.
Definition: gui_button.cpp:431
const utils::ustring & get_text() const
Returns this button's text.
Definition: gui_button.cpp:219
utils::observer_ptr< font_string > disabled_text_
Definition: gui_button.hpp:494
virtual void release()
Releases this button.
Definition: gui_button.cpp:380
virtual void enable()
Enables this button.
Definition: gui_button.cpp:328
void lock_highlight()
Locks this button's highlighting.
Definition: gui_button.cpp:478
button(utils::control_block &block, manager &mgr, const frame_core_attributes &attr)
Constructor.
Definition: gui_button.cpp:13
void disable_button_clicks()
Stop this button from generating OnClick events.
Definition: gui_button.cpp:519
void set_text(const utils::ustring &content)
Sets this button's text.
Definition: gui_button.cpp:206
void copy_from(const region &obj) override
Copies a region's parameters into this button (inheritance).
Definition: gui_button.cpp:86
const utils::observer_ptr< font_string > & get_highlight_text()
Returns this button's highlight text.
Definition: gui_button.hpp:188
const std::vector< std::string > & get_type_list_() const override
Definition: gui_button.cpp:544
void set_pushed_text_offset(const vector2f &offset)
Sets this button's pushed text offset.
Definition: gui_button.cpp:490
void set_disabled_text(utils::observer_ptr< font_string > fstr)
Sets this button's disabled text.
Definition: gui_button.cpp:279
utils::ustring content_
Definition: gui_button.hpp:485
utils::observer_ptr< font_string > highlight_text_
Definition: gui_button.hpp:493
utils::observer_ptr< texture > pushed_texture_
Definition: gui_button.hpp:488
vector2f pushed_text_offset_
Definition: gui_button.hpp:497
const utils::observer_ptr< texture > & get_highlight_texture()
Returns this button's highlight texture.
Definition: gui_button.hpp:156
const utils::observer_ptr< texture > & get_normal_texture()
Returns this button's normal texture.
Definition: gui_button.hpp:108
void set_normal_text(utils::observer_ptr< font_string > fstr)
Sets this button's normal text.
Definition: gui_button.cpp:255
virtual void push()
Pushed this button.
Definition: gui_button.cpp:362
const utils::observer_ptr< texture > & get_disabled_texture()
Returns this button's disabled texture.
Definition: gui_button.hpp:140
bool can_use_script(const std::string &script_name) const override
Returns 'true' if this button can use a script.
Definition: gui_button.cpp:26
const vector2f & get_pushed_text_offset() const
Returns this button's pushed text offset.
Definition: gui_button.cpp:495
void unlock_highlight()
Unlocks this button's highlighting.
Definition: gui_button.cpp:483
virtual void unlight()
Unlights this button.
Definition: gui_button.cpp:449
void fire_script(const std::string &script_name, const event_data &data=event_data{}) override
Calls a script.
Definition: gui_button.cpp:31
const utils::observer_ptr< font_string > & get_disabled_text()
Returns this button's disabled text.
Definition: gui_button.hpp:204
utils::observer_ptr< texture > normal_texture_
Definition: gui_button.hpp:487
Stores a variable number of arguments for an event.
const utils::variant & get(std::size_t index) const
Returns a parameter of this event.
void add(T &&value)
Adds a parameter to this event.
A layered_region that can draw text on the screen.
A region that can contain other regions and react to events.
Definition: gui_frame.hpp:255
std::string serialize(const std::string &tab) const override
Prints all relevant information about this region in a string.
Definition: gui_frame.cpp:84
void copy_from(const region &obj) override
Copies a region's parameters into this frame (inheritance).
Definition: gui_frame.cpp:195
void enable_mouse()
Marks this frame as able to receive mouse input (click & move).
Definition: gui_frame.hpp:372
virtual void fire_script(const std::string &script_name, const event_data &data=event_data{})
Calls a script.
Definition: gui_frame.cpp:1105
void notify_renderer_need_redraw() override
Notifies the renderer of this region that it needs to be redrawn.
Definition: gui_frame.cpp:1481
virtual bool can_use_script(const std::string &script_name) const
Returns 'true' if this frame can use a script.
Definition: gui_frame.cpp:183
Manages the user interface.
Definition: gui_manager.hpp:44
The base class of all elements in the GUI.
Definition: gui_region.hpp:161
void initialize_(T &self, const region_core_attributes &attr)
Set up function to call in all derived class constructors.
vector2f get_center() const
Returns the position of this region's center.
Definition: gui_region.cpp:341
A layered_region that can draw images and colored rectangles.
Definition: gui_texture.hpp:23
vector2< float > vector2f
Holds 2D coordinates (as floats)
std::optional< std::pair< mouse_button, mouse_button_event > > get_mouse_button_and_event_from_codename(std::string_view button_and_event_name)
Returns a mouse button and a button event ID from a string formatted as "<button>:<event>".
Definition: input_keys.cpp:72
std::string_view get_mouse_button_codename(mouse_button button_id)
Returns a standard English name for the provided mouse button.
Definition: input_keys.cpp:7
std::string_view get_mouse_button_and_event_codename(mouse_button button_id, mouse_button_event button_event)
Returns a standard Engilsh name for the provided mouse button and event.
Definition: input_keys.cpp:44
Struct holding all the core information about a frame necessary for its creation.
Struct holding all the core information about a region necessary for its creation.
std::vector< utils::observer_ptr< const region > > inheritance