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