Fixed mutation of vectors during iteration.
This commit is contained in:
parent
0a316808a5
commit
484972db30
|
@ -38,6 +38,10 @@ Window::~Window() {
|
|||
}
|
||||
|
||||
void Window::AttachListener(WindowListener* listener) {
|
||||
if (in_listener_loop_) {
|
||||
pending_listener_attaches_.push_back(listener);
|
||||
return;
|
||||
}
|
||||
auto it = std::find(listeners_.begin(), listeners_.end(), listener);
|
||||
if (it != listeners_.end()) {
|
||||
return;
|
||||
|
@ -47,6 +51,10 @@ void Window::AttachListener(WindowListener* listener) {
|
|||
}
|
||||
|
||||
void Window::DetachListener(WindowListener* listener) {
|
||||
if (in_listener_loop_) {
|
||||
pending_listener_detaches_.push_back(listener);
|
||||
return;
|
||||
}
|
||||
auto it = std::find(listeners_.begin(), listeners_.end(), listener);
|
||||
if (it == listeners_.end()) {
|
||||
return;
|
||||
|
@ -54,6 +62,46 @@ void Window::DetachListener(WindowListener* listener) {
|
|||
listeners_.erase(it);
|
||||
}
|
||||
|
||||
void Window::ForEachListener(std::function<void(WindowListener*)> fn) {
|
||||
assert_false(in_listener_loop_);
|
||||
in_listener_loop_ = true;
|
||||
for (auto listener : listeners_) {
|
||||
fn(listener);
|
||||
}
|
||||
in_listener_loop_ = false;
|
||||
while (!pending_listener_attaches_.empty()) {
|
||||
auto listener = pending_listener_attaches_.back();
|
||||
pending_listener_attaches_.pop_back();
|
||||
AttachListener(listener);
|
||||
}
|
||||
while (!pending_listener_detaches_.empty()) {
|
||||
auto listener = pending_listener_detaches_.back();
|
||||
pending_listener_detaches_.pop_back();
|
||||
DetachListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::TryForEachListener(std::function<bool(WindowListener*)> fn) {
|
||||
assert_false(in_listener_loop_);
|
||||
in_listener_loop_ = true;
|
||||
for (auto listener : listeners_) {
|
||||
if (fn(listener)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
in_listener_loop_ = false;
|
||||
while (!pending_listener_attaches_.empty()) {
|
||||
auto listener = pending_listener_attaches_.back();
|
||||
pending_listener_attaches_.pop_back();
|
||||
AttachListener(listener);
|
||||
}
|
||||
while (!pending_listener_detaches_.empty()) {
|
||||
auto listener = pending_listener_detaches_.back();
|
||||
pending_listener_detaches_.pop_back();
|
||||
DetachListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::set_imgui_input_enabled(bool value) {
|
||||
if (value == is_imgui_input_enabled_) {
|
||||
return;
|
||||
|
@ -75,20 +123,14 @@ bool Window::MakeReady() {
|
|||
}
|
||||
|
||||
void Window::OnMainMenuChange() {
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnMainMenuChange();
|
||||
}
|
||||
ForEachListener([](auto listener) { listener->OnMainMenuChange(); });
|
||||
}
|
||||
|
||||
void Window::OnClose() {
|
||||
UIEvent e(this);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnClosing(&e);
|
||||
}
|
||||
ForEachListener([&e](auto listener) { listener->OnClosing(&e); });
|
||||
on_closing(&e);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnClosed(&e);
|
||||
}
|
||||
ForEachListener([&e](auto listener) { listener->OnClosed(&e); });
|
||||
on_closed(&e);
|
||||
}
|
||||
|
||||
|
@ -111,15 +153,11 @@ void Window::Layout() {
|
|||
void Window::Invalidate() {}
|
||||
|
||||
void Window::OnResize(UIEvent* e) {
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnResize(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnResize(e); });
|
||||
}
|
||||
|
||||
void Window::OnLayout(UIEvent* e) {
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnLayout(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnLayout(e); });
|
||||
}
|
||||
|
||||
void Window::OnPaint(UIEvent* e) {
|
||||
|
@ -154,21 +192,15 @@ void Window::OnPaint(UIEvent* e) {
|
|||
ImGui::NewFrame();
|
||||
|
||||
context_->BeginSwap();
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnPainting(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnPainting(e); });
|
||||
on_painting(e);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnPaint(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnPaint(e); });
|
||||
on_paint(e);
|
||||
|
||||
// Flush ImGui buffers before we swap.
|
||||
ImGui::Render();
|
||||
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnPainted(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnPainted(e); });
|
||||
on_painted(e);
|
||||
|
||||
context_->EndSwap();
|
||||
|
@ -180,21 +212,15 @@ void Window::OnPaint(UIEvent* e) {
|
|||
}
|
||||
|
||||
void Window::OnVisible(UIEvent* e) {
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnVisible(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnVisible(e); });
|
||||
}
|
||||
|
||||
void Window::OnHidden(UIEvent* e) {
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnHidden(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnHidden(e); });
|
||||
}
|
||||
|
||||
void Window::OnGotFocus(UIEvent* e) {
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnGotFocus(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnGotFocus(e); });
|
||||
}
|
||||
|
||||
void Window::OnLostFocus(UIEvent* e) {
|
||||
|
@ -202,9 +228,7 @@ void Window::OnLostFocus(UIEvent* e) {
|
|||
modifier_cntrl_pressed_ = false;
|
||||
modifier_alt_pressed_ = false;
|
||||
modifier_super_pressed_ = false;
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnLostFocus(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnLostFocus(e); });
|
||||
}
|
||||
|
||||
void Window::OnKeyPress(KeyEvent* e, bool is_down, bool is_char) {
|
||||
|
@ -232,12 +256,10 @@ void Window::OnKeyDown(KeyEvent* e) {
|
|||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
for (auto listener : listeners_) {
|
||||
TryForEachListener([e](auto listener) {
|
||||
listener->OnKeyDown(e);
|
||||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return e->is_handled();
|
||||
});
|
||||
OnKeyPress(e, true, false);
|
||||
}
|
||||
|
||||
|
@ -246,21 +268,17 @@ void Window::OnKeyUp(KeyEvent* e) {
|
|||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
for (auto listener : listeners_) {
|
||||
TryForEachListener([e](auto listener) {
|
||||
listener->OnKeyUp(e);
|
||||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return e->is_handled();
|
||||
});
|
||||
OnKeyPress(e, false, false);
|
||||
}
|
||||
|
||||
void Window::OnKeyChar(KeyEvent* e) {
|
||||
OnKeyPress(e, true, true);
|
||||
on_key_char(e);
|
||||
for (auto listener : listeners_) {
|
||||
listener->OnKeyChar(e);
|
||||
}
|
||||
ForEachListener([e](auto listener) { listener->OnKeyChar(e); });
|
||||
OnKeyPress(e, false, true);
|
||||
}
|
||||
|
||||
|
@ -269,12 +287,10 @@ void Window::OnMouseDown(MouseEvent* e) {
|
|||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
for (auto listener : listeners_) {
|
||||
TryForEachListener([e](auto listener) {
|
||||
listener->OnMouseDown(e);
|
||||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return e->is_handled();
|
||||
});
|
||||
}
|
||||
|
||||
void Window::OnMouseMove(MouseEvent* e) {
|
||||
|
@ -282,12 +298,10 @@ void Window::OnMouseMove(MouseEvent* e) {
|
|||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
for (auto listener : listeners_) {
|
||||
TryForEachListener([e](auto listener) {
|
||||
listener->OnMouseMove(e);
|
||||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return e->is_handled();
|
||||
});
|
||||
}
|
||||
|
||||
void Window::OnMouseUp(MouseEvent* e) {
|
||||
|
@ -295,12 +309,10 @@ void Window::OnMouseUp(MouseEvent* e) {
|
|||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
for (auto listener : listeners_) {
|
||||
TryForEachListener([e](auto listener) {
|
||||
listener->OnMouseUp(e);
|
||||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return e->is_handled();
|
||||
});
|
||||
}
|
||||
|
||||
void Window::OnMouseWheel(MouseEvent* e) {
|
||||
|
@ -308,12 +320,10 @@ void Window::OnMouseWheel(MouseEvent* e) {
|
|||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
for (auto listener : listeners_) {
|
||||
TryForEachListener([e](auto listener) {
|
||||
listener->OnMouseWheel(e);
|
||||
if (e->is_handled()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return e->is_handled();
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
|
|
|
@ -112,6 +112,9 @@ class Window {
|
|||
protected:
|
||||
Window(Loop* loop, const std::wstring& title);
|
||||
|
||||
void ForEachListener(std::function<void(WindowListener*)> fn);
|
||||
void TryForEachListener(std::function<bool(WindowListener*)> fn);
|
||||
|
||||
virtual bool MakeReady();
|
||||
|
||||
virtual bool OnCreate();
|
||||
|
@ -164,7 +167,10 @@ class Window {
|
|||
bool modifier_super_pressed_ = false;
|
||||
|
||||
// All currently-attached listeners that get event notifications.
|
||||
bool in_listener_loop_ = false;
|
||||
std::vector<WindowListener*> listeners_;
|
||||
std::vector<WindowListener*> pending_listener_attaches_;
|
||||
std::vector<WindowListener*> pending_listener_detaches_;
|
||||
};
|
||||
|
||||
} // namespace ui
|
||||
|
|
Loading…
Reference in New Issue