lxgui
gui_frame_renderer.cpp
1 #include "lxgui/gui_frame_renderer.hpp"
2 
3 #include "lxgui/gui_frame.hpp"
4 #include "lxgui/gui_out.hpp"
5 #include "lxgui/utils_range.hpp"
6 #include "lxgui/utils_string.hpp"
7 
8 namespace lxgui::gui {
9 
10 template<typename T>
11 void check_sorted(const T& list) {
12  gui::out << "----------" << std::endl;
13  for (auto iter = list.begin(); iter != list.end(); ++iter) {
14  gui::out << " - " << (*iter)->get_name() << ": "
15  << utils::to_string((*iter)->get_effective_strata()) << ", "
16  << (*iter)->get_level() << std::endl;
17 
18  if (iter != list.begin()) {
19  gui::out << " is greater than last? " << list.comparator()(*(iter - 1), *iter)
20  << std::endl;
21  }
22  }
23  gui::out << "----------" << std::endl;
24 
25  if (!std::is_sorted(list.begin(), list.end(), list.comparator())) {
26  throw gui::exception("frame_renderer", "Frame list not sorted!!");
27  }
28 }
29 
30 struct strata_comparator {
31  bool operator()(strata s1, strata s2) const {
32  using int_type = std::underlying_type_t<strata>;
33  const auto strata_id1 = static_cast<int_type>(s1);
34  const auto strata_id2 = static_cast<int_type>(s2);
35  return strata_id1 < strata_id2;
36  }
37 
38  bool operator()(const frame* f1, strata s2) const {
39  return operator()(f1->get_effective_strata(), s2);
40  }
41 
42  bool operator()(strata s1, const frame* f2) const {
43  return operator()(s1, f2->get_effective_strata());
44  }
45 
46  bool operator()(const frame* f1, const frame* f2) const {
47  return operator()(f1->get_effective_strata(), f2->get_effective_strata());
48  }
49 };
50 
51 bool frame_renderer::frame_comparator::operator()(const frame* f1, const frame* f2) const {
52  using int_type = std::underlying_type_t<strata>;
53  const auto strata_id1 = static_cast<int_type>(f1->get_effective_strata());
54  const auto strata_id2 = static_cast<int_type>(f2->get_effective_strata());
55 
56  if (strata_id1 < strata_id2)
57  return true;
58  if (strata_id1 > strata_id2)
59  return false;
60 
61  const auto level1 = f1->get_level();
62  const auto level2 = f2->get_level();
63 
64  if (level1 < level2)
65  return true;
66  if (level1 > level2)
67  return false;
68 
69  return f1 < f2;
70 }
71 
73  for (std::size_t i = 0; i < strata_list_.size(); ++i) {
74  strata_list_[i].id = static_cast<strata>(i);
75  }
76 }
77 
79  strata_list_[static_cast<std::size_t>(strata_id)].redraw_flag = true;
80 }
81 
82 void frame_renderer::notify_rendered_frame(const utils::observer_ptr<frame>& obj, bool rendered) {
83  if (!obj)
84  return;
85 
86  if (rendered) {
87  auto [iter, inserted] = sorted_frame_list_.insert(obj.get());
88  if (!inserted) {
89  throw gui::exception("frame_renderer", "Frame was already in this renderer");
90  }
91  } else {
92  auto iter = sorted_frame_list_.find(obj.get());
93  if (iter == sorted_frame_list_.end()) {
94  throw gui::exception("frame_renderer", "Could not find frame in this renderer");
95  }
96 
98  }
99 
100  for (std::size_t i = 0; i < strata_list_.size(); ++i) {
101  strata_list_[i].range = get_strata_range_(static_cast<strata>(i));
102  }
103 
104  const auto strata_id = obj->get_effective_strata();
105 
106  frame_list_updated_ = true;
107  notify_strata_needs_redraw(strata_id);
108 }
109 
111  const utils::observer_ptr<frame>& /*obj*/, strata old_strata_id, strata new_strata_id) {
112 
113  std::stable_sort(
115 
116  for (std::size_t i = 0; i < strata_list_.size(); ++i) {
117  strata_list_[i].range = get_strata_range_(static_cast<strata>(i));
118  }
119 
120  frame_list_updated_ = true;
121  notify_strata_needs_redraw(old_strata_id);
122  notify_strata_needs_redraw(new_strata_id);
123 }
124 
125 std::pair<std::size_t, std::size_t> frame_renderer::get_strata_range_(strata strata_id) const {
126  auto range = std::equal_range(
127  sorted_frame_list_.begin(), sorted_frame_list_.end(), strata_id, strata_comparator{});
128 
129  return {range.first - sorted_frame_list_.begin(), range.second - sorted_frame_list_.begin()};
130 }
131 
133  const utils::observer_ptr<frame>& obj, int /*old_level*/, int /*new_level*/) {
134 
135  const auto strata_id = obj->get_effective_strata();
136 
137  auto& strata_obj = strata_list_[static_cast<std::size_t>(strata_id)];
138 
139  auto begin = sorted_frame_list_.begin() + strata_obj.range.first;
140  auto last = sorted_frame_list_.begin() + strata_obj.range.second;
141 
142  std::stable_sort(begin, last, sorted_frame_list_.comparator());
143 
144  frame_list_updated_ = true;
145  notify_strata_needs_redraw(strata_id);
146 }
147 
148 utils::observer_ptr<const frame>
149 frame_renderer::find_topmost_frame(const std::function<bool(const frame&)>& predicate) const {
150  // Iterate through the frames in reverse order from rendering (frame on top goes first)
151  for (const auto* obj : utils::range::reverse(sorted_frame_list_)) {
152  if (obj->is_visible()) {
153  if (auto topmost = obj->find_topmost_frame(predicate))
154  return topmost;
155  }
156  }
157 
158  return nullptr;
159 }
160 
162  auto range = strata_list_[static_cast<std::size_t>(strata_id)].range;
163  auto begin = sorted_frame_list_.begin() + range.first;
164  auto last = sorted_frame_list_.begin() + range.second;
165 
166  if (last != begin) {
167  --last;
168  return (*last)->get_level();
169  }
170 
171  return 0;
172 }
173 
174 void frame_renderer::render_strata_(const strata_data& strata_obj) const {
175  auto begin = sorted_frame_list_.begin() + strata_obj.range.first;
176  auto end = sorted_frame_list_.begin() + strata_obj.range.second;
177 
178  for (auto iter = begin; iter != end; ++iter) {
179  (*iter)->render();
180  }
181 }
182 
184  sorted_frame_list_.clear();
185  frame_list_updated_ = true;
186 }
187 
189  return frame_list_updated_;
190 }
191 
193  frame_list_updated_ = false;
194 }
195 
196 } // namespace lxgui::gui
Exception to be thrown by GUI code.
virtual void notify_strata_changed(const utils::observer_ptr< frame > &obj, strata old_strata_id, strata new_strata_id)
Tells this renderer that a frame has changed strata.
virtual void notify_strata_needs_redraw(strata strata_id)
Tells this renderer that one of its region requires redraw.
int get_highest_level(strata strata_id) const
Returns the highest level on the provided strata.
virtual void notify_level_changed(const utils::observer_ptr< frame > &obj, int old_level, int new_level)
Tells this renderer that a frame has changed level.
void render_strata_(const strata_data &strata_obj) const
std::array< strata_data, num_strata > strata_list_
virtual void notify_rendered_frame(const utils::observer_ptr< frame > &obj, bool rendered)
Tells this renderer that it should (or not) render another frame.
utils::observer_ptr< const frame > find_topmost_frame(const std::function< bool(const frame &)> &predicate) const
Find the top-most frame matching the provided predicate.
std::pair< std::size_t, std::size_t > get_strata_range_(strata strata_id) const
frame_renderer()
Default constructor.
A region that can contain other regions and react to events.
Definition: gui_frame.hpp:255
int get_level() const
Returns this frame's level.
Definition: gui_frame.cpp:727
strata get_effective_strata() const
Returns this frame's effective strata.
Definition: gui_frame.cpp:735
iterator find(const Key &k)
Find an object in this vector by its key. The key can be a copy of the element itself,...
std::pair< iterator, bool > insert(U &&t)
Insert the provided object in the vector, only if no object exists with the same key.
iterator erase(iterator iter)
Erase an element from this vector.
Cmp & comparator()
Return the comparator object.
std::ostream out
void check_sorted(const T &list)
range_impl::reverse_range< T > reverse(T &container)
Reverse traversal.
Definition: utils_range.hpp:50
bool operator()(const frame *f1, const frame *f2) const
Contains frames sorted by level.
Definition: gui_strata.hpp:19
std::pair< std::size_t, std::size_t > range
Definition: gui_strata.hpp:21