Symphony Of Empires
ui.cpp
Go to the documentation of this file.
1 // Symphony of Empires
2 // Copyright (C) 2021, Symphony of Empires contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // eng3d/ui/ui.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include <cstdlib>
26 #include <cstring>
27 #include <string>
28 #include <algorithm>
29 
30 #ifdef E3D_TARGET_WINDOWS
31 # include <windows.h>
32 #endif
33 #ifdef E3D_BACKEND_OPENGL
34 # include <GL/glew.h>
35 # include <GL/gl.h>
36 #elif defined E3D_BACKEND_GLES
37 # include <GLES3/gl3.h>
38 #endif
39 #include <glm/vec2.hpp>
40 
41 #include <tbb/blocked_range.h>
42 #include <tbb/concurrent_vector.h>
43 #include <tbb/parallel_for.h>
44 #include <tbb/combinable.h>
45 
46 #include "eng3d/ui/ui.hpp"
47 #include "eng3d/ui/label.hpp"
48 #include "eng3d/ui/window.hpp"
49 #include "eng3d/ui/text.hpp"
50 #include "eng3d/ui/button.hpp"
51 #include "eng3d/ui/tooltip.hpp"
52 #include "eng3d/ui/widget.hpp"
53 #include "eng3d/ui/slider.hpp"
54 #include "eng3d/ui/input.hpp"
55 #include "eng3d/ui/scrollbar.hpp"
56 #include "eng3d/texture.hpp"
57 #include "eng3d/rectangle.hpp"
58 #include "eng3d/state.hpp"
59 #include "eng3d/utils.hpp"
60 #include "eng3d/primitive.hpp"
61 #include "eng3d/log.hpp"
62 
65  : s{ _s }
66 {
67  s.reload_shaders();
68 
69  if(g_ui_context != nullptr)
70  CXX_THROW(std::runtime_error, "UI context already constructed");
71  g_ui_context = this;
72 
73  default_font = s.ttf_man.load(s.package_man.get_unique("fonts/Poppins/Poppins-SemiBold.ttf"));
74  if(default_font.get() == nullptr)
75  CXX_THROW(std::runtime_error, "Can't open font");
76  widgets.reserve(8192);
77 
78  foreground = s.tex_man.load(s.package_man.get_unique("gfx/button2.png"));
79  background = s.tex_man.load(s.package_man.get_unique("gfx/window_background.png"));
80  window_top = s.tex_man.load(s.package_man.get_unique("gfx/window_top3.png"));
81  button = s.tex_man.load(s.package_man.get_unique("gfx/button2.png"));
82  tooltip_tex = s.tex_man.load(s.package_man.get_unique("gfx/tooltip.png"));
83  piechart_overlay = s.tex_man.load(s.package_man.get_unique("gfx/piechart.png"));
84  border_tex = s.tex_man.load(s.package_man.get_unique("gfx/border2.png"));
85  button_border = s.tex_man.load(s.package_man.get_unique("gfx/border_sharp2.png"));
86  cursor_tex = s.tex_man.load(s.package_man.get_unique("gfx/cursor_b.png"));
87 
88  // Shader used for orthogonally drawing the objects on the 2D plane
89  obj_shader = std::make_unique<Eng3D::OpenGL::Program>();
90  {
91  obj_shader->attach_shader(*s.builtin_shaders["vs_2d"]);
92  obj_shader->attach_shader(*s.builtin_shaders["fs_2d"]);
93  obj_shader->link();
94  }
95 
96  piechart_shader = std::make_unique<Eng3D::OpenGL::Program>();
97  {
98  piechart_shader->attach_shader(*s.builtin_shaders["vs_piechart"]);
99  piechart_shader->attach_shader(*s.builtin_shaders["fs_piechart"]);
100  piechart_shader->link();
101  }
102 }
103 
105 
106 }
107 
109  // Not already here
110  if(std::find_if(widgets.cbegin(), widgets.cend(), [widget](const auto& e) { return e.get() == widget; }) != widgets.cend())
111  return;
112  widgets.push_back(std::unique_ptr<UI::Widget>(widget));
113 }
114 
116  auto it = std::find_if(widgets.begin(), widgets.end(), [widget](const auto& e) { return e.get() == widget; });
117  widgets.erase(it);
118 }
119 
122  // Remove all widgets
123  for(auto& widget : widgets) {
124  if(widget.get() == this->tooltip_widget || !widget->managed) continue;
125  widget->kill();
126  }
127  this->use_tooltip(nullptr, { 0, 0 });
128 }
129 
130 void UI::Context::clear_dead_recursive(UI::Widget& w) {
131  bool changed = false;
132  for(size_t i = 0; i < w.children.size(); i++) {
133  if(w.children[i]->dead) {
134  w.children.erase(w.children.begin() + i);
135  i--;
136  changed = true;
137  } else if(w.children[i]->dead_child) {
138  this->clear_dead_recursive(*w.children[i].get());
139  w.children[i]->dead_child = false;
140  }
141  }
142  if(changed) w.need_recalc = true;
143 }
144 
147  for(size_t i = 0; i < widgets.size(); i++) {
148  if(widgets[i]->dead) {
149  widgets.erase(widgets.begin() + i);
150  i--;
151  } else if(widgets[i]->dead_child) {
152  this->clear_dead_recursive(*widgets[i].get());
153  widgets[i]->dead_child = false;
154  }
155  }
156 
157  if(this->tooltip_widget)
158  this->clear_dead_recursive(*this->tooltip_widget);
159 }
160 
165 void UI::Context::set_eval(UI::Widget& widget, bool eval) {
166  if(eval == widget.is_eval) return;
167  if(eval) {
168  // From no-eval to evaluable
169  auto it = std::find_if(this->no_eval_widgets.begin(), this->no_eval_widgets.end(), [&widget](const auto& e) { return e.get() == &widget; });
170  assert(it != this->no_eval_widgets.end());
171  this->widgets.push_back(std::move(*it));
172  this->no_eval_widgets.erase(it);
173  } else {
174  // From evaluable to no-eval
175  auto it = std::find_if(this->widgets.begin(), this->widgets.end(), [&widget](const auto& e) { return e.get() == &widget; });
176  assert(it != this->widgets.end());
177  this->no_eval_widgets.push_back(std::move(*it));
178  this->widgets.erase(it);
179  }
180  widget.is_eval = eval;
181 }
182 
183 void UI::Context::prompt(const std::string& title, const std::string& text) {
184  std::scoped_lock lock(prompt_queue_mutex);
185  this->prompt_queue.emplace_back(title, text);
186 }
187 
188 glm::ivec2 UI::Context::get_pos(Widget& w, glm::ivec2 offset) {
189  glm::ivec2 pos{ w.x, w.y };
190  glm::ivec2 screen_size{ width, height };
191  glm::ivec2 parent_size{ 0, 0 };
192  if(w.parent != nullptr)
193  parent_size = glm::ivec2{ w.parent->width, w.parent->height };
194 
195  switch(w.origin) {
196  case UI::Origin::CENTER:
197  pos += offset;
198  pos += parent_size / 2;
199  break;
201  pos += offset;
202  pos.y += parent_size.y / 2;
203  break;
205  pos += offset;
206  pos.y += parent_size.y / 2;
207  pos.x += parent_size.x;
208  break;
210  pos += offset;
211  break;
213  pos += offset;
214  pos.x += parent_size.x / 2;
215  break;
217  pos += offset;
218  pos.x += parent_size.x;
219  break;
221  pos += offset;
222  pos.y += parent_size.y;
223  break;
225  pos += offset;
226  pos.y += parent_size.y;
227  pos.x += parent_size.x / 2;
228  break;
230  pos += offset;
231  pos += parent_size;
232  break;
234  pos += screen_size / 2;
235  break;
237  pos.y += screen_size.y / 2;
238  break;
240  pos.y += screen_size.y / 2;
241  pos.x += screen_size.x;
242  break;
244  break;
246  pos.x += screen_size.x / 2;
247  break;
249  pos.x += screen_size.x;
250  break;
252  pos.y += screen_size.y;
253  break;
255  pos.y += screen_size.y;
256  pos.x += screen_size.x / 2;
257  break;
259  pos += screen_size;
260  break;
261  }
262  return pos;
263 }
264 
265 void UI::Context::resize(int _width, int _height) {
266  this->width = _width;
267  this->height = _height;
268  glViewport(0, 0, this->width, this->height);
269 
270  this->projection = glm::ortho(0.f, static_cast<float>(this->width), static_cast<float>(this->height), 0.f, 0.f, 1.f);
271  this->view = glm::mat4(1.f);
272  this->model = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, 0.f));
273 }
274 
275 void UI::Context::set_cursor_pos(glm::ivec2 pos) {
276  this->cursor_pos = pos;
277 }
278 
279 void UI::Context::render_recursive(Widget& w, Eng3D::Rect viewport, glm::ivec2 offset) {
280  // Only render widgets that are shown and only render widget that have a width and height
281  if(!w.is_render || !w.width || !w.height) {
282  w.is_hover = false;
283  return;
284  }
285 
286  if(w.need_recalc) {
287  w.recalc_child_pos();
288  w.need_recalc = false;
289  }
290 
291  if(w.is_fullscreen) {
292  w.width = width;
293  w.height = height;
294  }
295 
296  glm::ivec2 size{ w.width, w.height };
297  // Get the widget origin relative to the parent or screen
298  offset = this->get_pos(w, offset);
299  Eng3D::Rect local_viewport{ offset, size };
300  // Set the viewport to the intersection of the parents and currents widgets viewport
301  local_viewport = local_viewport.intersection(Eng3D::Rect(0, 0, width, height));
302  if(!w.parent || w.parent->type != UI::WidgetType::GROUP)
303  local_viewport = viewport.intersection(local_viewport);
304  viewport = local_viewport;
305 
306  local_viewport.offset(-offset);
307  if(local_viewport.width() > 0 && local_viewport.height() > 0) {
308  obj_shader->set_uniform("model", glm::translate(model, glm::vec3(offset, 0.f))); // Offset the widget start pos
309  piechart_shader->set_uniform("model", glm::translate(model, glm::vec3(offset, 0.f)));
310  w.on_render(*this, local_viewport); // Render the widget, only render what's inside the viewport
311  if(w.on_update) w.on_update(w);
312  for(auto& child : w.children) {
313  child->is_clickable = (w.on_click || w.is_clickable) && w.is_hover;
314  if((viewport.size().x <= 0 || viewport.size().y <= 0) && !child->is_float)
315  continue;
316 
317  this->render_recursive(*child, viewport, offset);
318  }
319  }
320 }
321 
324  this->model = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, 0.f));
325 
326  glActiveTexture(GL_TEXTURE0);
327 
328  this->obj_shader->use();
329  this->obj_shader->set_uniform("projection", this->projection);
330  this->obj_shader->set_uniform("view", this->view);
331  this->obj_shader->set_uniform("model", this->model);
332 
333  Eng3D::Rect viewport(0, 0, width, height);
334  for(auto& widget : this->widgets)
335  this->render_recursive(*widget.get(), viewport, glm::vec2(0.f));
336  if(tooltip_widget != nullptr)
337  this->render_recursive(*tooltip_widget, viewport, glm::vec2(0.f));
338 
339  // Display the cursor
340  obj_shader->set_uniform("diffuse_color", glm::vec4(1.f));
341  obj_shader->set_texture(0, "diffuse_map", *cursor_tex);
342  obj_shader->set_uniform("model", glm::translate(glm::mat4(1.f), glm::vec3(cursor_pos, 0.f)));
343  auto cursor_quad = Eng3D::Square(0.f, 0.f, 32.f, 32.f);
344  cursor_quad.draw();
345 }
346 
347 // Too expensive
348 void UI::Context::clear_hover_recursive(Widget& w) {
349  w.is_hover = false;
350  for(auto& child : w.children)
351  clear_hover_recursive(*child);
352 }
353 
354 static inline bool is_inside_transparent(const UI::Widget& w, glm::ivec2 mouse_pos, glm::ivec2 offset) {
355  if(w.current_texture != nullptr) {
356  glm::ivec2 tex_size{ w.current_texture->width, w.current_texture->height };
357  glm::ivec2 tex_pos = ((mouse_pos - offset) * tex_size) / glm::ivec2(w.width, w.height);
358  const Eng3D::Rect tex_rect{ glm::ivec2(0), tex_size };
359  if(tex_rect.contains(mouse_pos)) {
360  const uint32_t argb = w.current_texture->get_pixel(tex_pos.x, tex_pos.y).get_value();
361  if(((argb >> 24) & 0xff) == 0) return true;
362  }
363  }
364  return false;
365 }
366 
367 bool UI::Context::check_hover_recursive(UI::Widget& w, glm::ivec2 mouse_pos, glm::ivec2 offset) {
368  offset = this->get_pos(w, offset);
369 
370  w.is_hover = hover_update;
371  if(!w.is_render || !w.width || !w.height)
372  return false;
373 
374  const Eng3D::Rect r(offset.x, offset.y, w.width, w.height);
375  if(!r.contains(mouse_pos)) {
376  w.is_hover = false;
377  } else if(w.is_transparent) {
378  if(is_inside_transparent(w, mouse_pos, offset))
379  w.is_hover = false;
380  }
381 
382  bool consumed_hover = w.is_hover && w.type != UI::WidgetType::GROUP;
383  if(w.is_hover) {
384  if(w.on_hover) w.on_hover(w, mouse_pos, offset);
385 
386  if (!w.tooltip && w.tooltip_creator)
387  w.tooltip = w.tooltip_creator();
388 
389  if(w.tooltip != nullptr) {
390  this->tooltip_widget = w.tooltip;
391  this->tooltip_widget->set_pos(offset.x, offset.y, w.width, w.height, width, height);
392  }
393 
394  for(auto& child : w.children)
395  consumed_hover |= check_hover_recursive(*child, mouse_pos, offset);
396  }
397  return consumed_hover;
398 }
399 
400 bool UI::Context::check_hover(glm::ivec2 mouse_pos) {
401  hover_update++;
402 // if(is_drag) {
403 // /// @todo Is this really better?
404 // #ifdef E3D_TARGET_WINDOWS
405 // SetCapture(GetActiveWindow());
406 // #endif
407 // // Drag vector
408 // const glm::ivec2 drag = mouse_pos - glm::ivec2(this->drag_x, this->drag_y);
409 // const auto offset = this->get_pos(*dragged_widget, glm::ivec2(0));
410 // const glm::ivec2 diff = drag - offset;
411 // assert(dragged_widget->on_drag != nullptr);
412 // dragged_widget->on_drag(*dragged_widget, drag);
413 // return true;
414 // }
415 
416  bool is_hover = false;
417  tooltip_widget = nullptr;
418  for(const auto& widget : reverse(widgets)) {
419  is_hover |= check_hover_recursive(*widget, mouse_pos, glm::ivec2(0));
420  if(is_hover) return is_hover;
421  }
422  return is_hover;
423 }
424 
425 UI::ClickState UI::Context::check_click_recursive(
426  UI::Widget& w,
427  glm::ivec2 mouse_pos,
428  glm::ivec2 offset,
429  UI::ClickState click_state,
430  bool clickable,
431  bool mouse_pressed)
432 {
433  offset = this->get_pos(w, offset);
434  if(click_state != UI::ClickState::NOT_CLICKED)
435  clickable = true;
436 
437  // Widget must be displayed
438  if(!w.is_render) {
439  clickable = false;
441  }
442 
443  // Click must be within the widget's box if it's not a group
444  if(w.type != UI::WidgetType::GROUP) {
445  const Eng3D::Rect r(offset.x, offset.y, w.width, w.height);
446  if(!r.contains(mouse_pos)) {
447  clickable = false;
448  } else if(w.is_transparent) {
449  if(is_inside_transparent(w, mouse_pos, offset))
450  clickable = false;
451  }
452  }
453 
454  for(auto& child : w.children) {
455  auto new_click_state = check_click_recursive(*child, mouse_pos, offset, click_state, clickable, mouse_pressed);
456  if (click_state < new_click_state)
457  click_state = new_click_state;
458  }
459  bool click_consumed = click_state == UI::ClickState::HANDLED;
460 
461  // Non-clickable group widgets are only taken in account
462  if(w.type == UI::WidgetType::GROUP && (!w.on_click || !w.on_drag))
463  clickable = false;
464 
465  // Call on_click_outside if on_click has been used or widget isn't hit by click
466  if(w.on_click_outside && (!clickable || click_consumed))
467  w.on_click_outside(w);
468 
469  // Call on_click if on_click hasnt been used and widget is hit by click
470  if((w.on_click || w.on_drag) && clickable && !click_consumed) {
471  if (mouse_pressed) {
472  if(w.type == UI::WidgetType::SLIDER) {
473  auto* wc = static_cast<UI::Slider*>(&w);
474  wc->set_value((static_cast<float>(std::abs(mouse_pos.x - offset.x)) / static_cast<float>(wc->width)) * wc->max);
475  }
476  if (w.on_click)
477  mouse_pressed_widget = &w;
478  if (w.on_drag) {
479  on_drag = w.on_drag;
480  // Call the function a first time to allow it to save it's start values
481  on_drag(mouse_pos, mouse_pos);
482  }
483  } else {
484  // Note. If the widget at address 'mouse_pressed_widget' is removed while the mouse is pressed
485  // and another widget get the same address and position it's on_click will be called instead.
486  // But we will not worry about this unlikely event
487  if (mouse_pressed_widget == &w)
488  w.on_click(w);
489  }
491  }
492 
493  if(click_state == UI::ClickState::NOT_CLICKED && clickable)
494  click_state = UI::ClickState::NOT_HANDLED;
495  return click_state;
496 }
497 
498 bool UI::Context::check_click(glm::ivec2 mouse_pos) {
499  this->start_drag_mouse_position = mouse_pos;
500 #ifdef E3D_TARGET_WINDOWS
501  SetCapture(GetActiveWindow());
502 #endif
503 
504  auto click_state = UI::ClickState::NOT_CLICKED;
505  int click_wind_index = -1;
506 
507  bool is_click = false;
508  for(int i = widgets.size() - 1; i >= 0; i--) {
509  click_state = check_click_recursive(*widgets[i].get(), mouse_pos, glm::ivec2(0), click_state, true, true);
510  // Ignore further clicks, prevents clicking causing clicks on elements behind
511  if(click_state != UI::ClickState::NOT_CLICKED) {
512  is_click = true;
513  // Set the index of the current window to move it to front
514  click_wind_index = i;
515  break;
516  }
517  }
518 
519  if(click_wind_index != -1) {
520  // Only movable and UI::WidgetType::WINDOWS are able to move to the top
521  auto& window = *widgets[click_wind_index].get();
522  if(window.type == UI::WidgetType::WINDOW && !window.is_pinned) {
523  auto it = widgets.begin() + click_wind_index;
524  std::rotate(it, it + 1, widgets.end());
525  }
526  }
527  return is_click;
528 }
529 
530 bool UI::Context::check_mouse_released(glm::ivec2 mouse_pos) {
531  if (on_drag)
532  on_drag = nullptr;
533 
534 #ifdef E3D_TARGET_WINDOWS
535  // Release the mouse once we no longer drag anything
536  ReleaseCapture();
537 #endif
538 
539  auto click_state = UI::ClickState::NOT_CLICKED;
540 
541  bool is_click = false;
542  for(auto& widget : reverse(widgets)) {
543  click_state = check_click_recursive(*widget, mouse_pos, glm::ivec2(0), click_state, true, false);
544  // Ignore further clicks, prevents clicking causing clicks on elements behind
545  if(click_state != UI::ClickState::NOT_CLICKED) {
546  is_click = true;
547  break;
548  }
549  }
550  mouse_pressed_widget = nullptr;
551 
552  return is_click;
553 }
554 
555 void UI::Context::check_drag(glm::ivec2 mouse_pos) {
556  if (on_drag)
557  on_drag(start_drag_mouse_position, mouse_pos);
558 }
559 
560 bool check_text_input_recursive(UI::Widget& widget, const char* _input) {
561  if(widget.type == UI::WidgetType::INPUT) {
562  auto& c_widget = static_cast<UI::Input&>(widget);
563  if(c_widget.is_selected) c_widget.on_textinput(c_widget, _input);
564  return true;
565  }
566 
567  for(const auto& children : widget.children)
568  if(check_text_input_recursive(*children, _input))
569  return true;
570  return false;
571 }
572 
573 bool UI::Context::check_text_input(const char* _input) {
574  for(const auto& widget : widgets)
575  if(check_text_input_recursive(*widget.get(), _input))
576  return true;
577  return false;
578 }
579 
580 void UI::Context::use_tooltip(UI::Tooltip* tooltip, glm::ivec2 pos) {
581  this->tooltip_widget = tooltip;
582  if(this->tooltip_widget != nullptr)
583  this->tooltip_widget->set_pos(pos.x, pos.y, tooltip->width, tooltip->height, width, height);
584 }
585 
586 bool UI::Context::check_wheel_recursive(UI::Widget& w, glm::ivec2 mouse_pos, glm::ivec2 offset, int y) {
587  offset = get_pos(w, offset);
588 
589  // Widget must be shown
590  if(!w.is_render) return false;
591 
592  const Eng3D::Rect r = Eng3D::Rect(offset.x, offset.y, w.width, w.height);
593  if(!r.contains(mouse_pos)) {
594  return false;
595  } else if(w.is_transparent) {
596  if(is_inside_transparent(w, mouse_pos, offset))
597  return false;
598  }
599 
600  // When we check the children they shall return non-zero if they are a group/window
601  // We will only select the most-front children that is either a G/W - this is done
602  // because when we call this function we will return 1 if the children is a G/W
603  // otherwise we will return 0, which will be ignored in this for loop
604  //
605  // In short: If any of our children are scrolled by the mouse we will not receive
606  // the scrolling instructions - only the front child will
607  UI::Scrollbar* scrollbar = nullptr;
608  bool scrolled = false;
609  for(auto& children : w.children) {
610  if(children->type == UI::WidgetType::SCROLLBAR)
611  scrollbar = static_cast<UI::Scrollbar*>(children.get());
612  scrolled = check_wheel_recursive(*children, mouse_pos, offset, y);
613  if(scrolled) break;
614  }
615 
616  if(w.is_scroll) {
617  w.scroll(y);
618  if(scrollbar != nullptr)
619  scrollbar->update_thumb();
620  scrolled = true;
621  }
622  return scrolled;
623 }
624 
625 bool UI::Context::check_wheel(glm::ivec2 mouse_pos, int y) {
626  for(auto& widget : reverse(widgets))
627  if(check_wheel_recursive(*widget, mouse_pos, glm::ivec2(0), y))
628  return true;
629  return false;
630 }
631 
636  for(auto& widget : reverse(widgets))
637  do_tick_recursive(*widget);
638 }
639 
640 int UI::Context::do_tick_recursive(Widget& w) {
641  if(w.on_each_tick) w.on_each_tick(w);
642  for(auto& child : w.children)
643  do_tick_recursive(*child);
644  return 1;
645 }
std::shared_ptr< Eng3D::IO::Asset::Base > get_unique(const Eng3D::IO::Path &path)
Obtaining an unique asset means the "first-found" policy applies.
Definition: io.cpp:146
void reload_shaders()
Definition: state.cpp:365
Eng3D::TrueType::Manager ttf_man
Definition: state.hpp:127
Eng3D::TextureManager tex_man
Definition: state.hpp:124
Eng3D::IO::PackageManager package_man
Definition: state.hpp:122
std::shared_ptr< Eng3D::Texture > load(const std::string &path, TextureOptions options=default_options)
Finds a texture in the list of a texture manager if the texture is already in the list we load the sa...
Definition: texture.cpp:432
std::shared_ptr< Eng3D::TrueType::Font > load(std::shared_ptr< Eng3D::IO::Asset::Base > asset)
Definition: ttf.cpp:58
The UI context that handles all the ui widgets.
Definition: ui.hpp:63
std::shared_ptr< Eng3D::Texture > cursor_tex
Definition: ui.hpp:155
std::shared_ptr< Eng3D::Texture > button_border
Definition: ui.hpp:154
void set_eval(UI::Widget &widget, bool eval)
Moves a widget from evaluable to non-evaluable making a widget non-evaluable has side effects,...
Definition: ui.cpp:165
std::shared_ptr< Eng3D::Texture > foreground
Definition: ui.hpp:147
Context()=delete
std::shared_ptr< Eng3D::TrueType::Font > default_font
Definition: ui.hpp:157
~Context()
Definition: ui.cpp:104
std::shared_ptr< Eng3D::Texture > tooltip_tex
Definition: ui.hpp:151
void render_all()
Render all widgets.
Definition: ui.cpp:323
void use_tooltip(Tooltip *tooltip, glm::ivec2 pos)
Definition: ui.cpp:580
void do_tick()
Will call on_tick on all widgets.
Definition: ui.cpp:635
std::shared_ptr< Eng3D::Texture > button
Definition: ui.hpp:150
bool check_mouse_released(glm::ivec2 mouse_pos)
Release the dragging of the widget.
Definition: ui.cpp:530
std::unique_ptr< Eng3D::OpenGL::Program > obj_shader
Definition: ui.hpp:159
std::shared_ptr< Eng3D::Texture > background
Definition: ui.hpp:148
void remove_widget(UI::Widget *widget)
Definition: ui.cpp:115
void prompt(const std::string &title, const std::string &text)
Definition: ui.cpp:183
std::shared_ptr< Eng3D::Texture > piechart_overlay
Definition: ui.hpp:152
void resize(const int width, const int height)
Definition: ui.cpp:265
bool check_text_input(const char *input)
Will give keyboard input to Input Widget if one is selected.
Definition: ui.cpp:573
void check_drag(glm::ivec2 mouse_pos)
Check for on_drag events, will move Window widgets with is_pinned = false.
Definition: ui.cpp:555
bool check_wheel(glm::ivec2 mouse_pos, int y)
Check if the mouse is above a widget and scroll widget.
Definition: ui.cpp:625
std::unique_ptr< Eng3D::OpenGL::Program > piechart_shader
Definition: ui.hpp:160
std::shared_ptr< Eng3D::Texture > window_top
Definition: ui.hpp:149
void add_widget(UI::Widget *widget)
Definition: ui.cpp:108
bool check_hover(glm::ivec2 mouse_pos)
Check for on_hover events If the mouse is above a widget call the widgets on_hover or show its toolti...
Definition: ui.cpp:400
bool check_click(glm::ivec2 mouse_pos)
Check for on_click events. Check if the mouse is above a widget and call the widgets on_click if poss...
Definition: ui.cpp:498
void clear()
Removes all widgets.
Definition: ui.cpp:121
void clear_dead()
Removes all widgets that have been killed.
Definition: ui.cpp:146
std::shared_ptr< Eng3D::Texture > border_tex
Definition: ui.hpp:153
void set_cursor_pos(glm::ivec2 pos)
Definition: ui.cpp:275
Input widget for keyboard inputs.
Definition: input.hpp:34
std::function< void(UI::Input &, const char *)> on_textinput
Definition: input.hpp:45
void set_value(const float _value)
Scrollbar widget.
Definition: scrollbar.hpp:43
void update_thumb()
Updates the thumb position in respect to the current scroll positioning of the parent.
Definition: scrollbar.cpp:98
Slider widget.
Definition: slider.hpp:38
Tooltip widget, used entirely for hovering purpouses, don't use any other widget for hovering unless ...
Definition: tooltip.hpp:38
void set_pos(int x, int y, int width, int height, int screen_width, int screen_height)
Definition: tooltip.cpp:72
The master widget all the other widgets inherit from, do not use directly instead use one of the many...
Definition: widget.hpp:176
std::function< void(UI::Widget &)> on_click
Definition: widget.hpp:350
std::function< void(UI::Widget &)> on_update
Definition: widget.hpp:349
void scroll(int y)
Scrolls all the children of this widget by a factor of y.
Definition: widget.cpp:497
UI::Origin origin
Definition: widget.hpp:318
std::function< void(UI::Widget &, glm::ivec2 mouse_pos, glm::ivec2 widget_pos)> on_hover
Definition: widget.hpp:354
bool is_scroll
Definition: widget.hpp:306
std::function< void(glm::ivec2 mouse_pos, glm::ivec2 mouse_delta)> on_drag
Definition: widget.hpp:348
std::vector< std::unique_ptr< UI::Widget > > children
Definition: widget.hpp:315
std::function< UI::Tooltip *()> tooltip_creator
Definition: widget.hpp:344
size_t width
Definition: widget.hpp:325
std::function< void(UI::Widget &)> on_click_outside
Definition: widget.hpp:351
bool is_fullscreen
Definition: widget.hpp:310
virtual void on_render(Context &, Eng3D::Rect viewport)
Definition: widget.cpp:229
std::shared_ptr< Eng3D::Texture > current_texture
Definition: widget.hpp:327
bool is_transparent
Definition: widget.hpp:311
std::function< void(UI::Widget &)> on_each_tick
Definition: widget.hpp:352
size_t height
Definition: widget.hpp:325
uint32_t is_hover
Definition: widget.hpp:308
UI::Tooltip * tooltip
Definition: widget.hpp:343
bool is_render
Definition: widget.hpp:303
UI::WidgetType type
Definition: widget.hpp:320
UI::Widget * parent
Definition: widget.hpp:314
@ LOWER_MIDDLE_SCREEN
@ MIDDLE_RIGHT_SCREEN
@ UPPER_MIDDLE_SCREEN
@ UPPER_RIGHT_SCREEN
@ MIDDLE_LEFT_SCREEN
@ LOWER_RIGHT_SCREEN
std::string translate(const std::string_view str)
Definition: string.cpp:76
struct Rectangle Rect
Definition: rectangle.hpp:176
Context * g_ui_context
Definition: ui.cpp:63
ClickState
Definition: ui.hpp:51
constexpr glm::vec2 size() const
Obtains the current size of the rectangle.
Definition: rectangle.hpp:68
constexpr Rectangle intersection(const Rectangle &rect) const
Obtains the intersection rectangle from two other rectangles R1 and R2.
Definition: rectangle.hpp:157
constexpr void offset(glm::vec2 offset)
Offset the rectangle by the given parameter.
Definition: rectangle.hpp:118
constexpr bool contains(glm::vec2 pos) const
Checks if the point is contains the point.
Definition: rectangle.hpp:134
bool check_text_input_recursive(UI::Widget &widget, const char *_input)
Definition: ui.cpp:560
Range< It > reverse(ORange &&originalRange)
Definition: utils.hpp:115
#define CXX_THROW(class,...)
Definition: utils.hpp:98