[UI] Fix ClearInput not called in ImGuiDrawer after deferred dialog removal
Also cleanup the code involved in dialog registration, and update the explanation of why dialog removal is delayed until the end of drawing (the original was written back when window listener and UI drawer callback registration during the execution of the callbacks was deferred, but that was wrong as that might result in execution of callbacks belonging to now-deleted objects).
This commit is contained in:
parent
a37b57ca8d
commit
778333b1b5
|
@ -62,11 +62,11 @@ void ImGuiDrawer::AddDialog(ImGuiDialog* dialog) {
|
||||||
dialogs_.cend()) {
|
dialogs_.cend()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (dialog_loop_next_index_ == SIZE_MAX && dialogs_.empty()) {
|
if (dialogs_.empty() && !IsDrawingDialogs()) {
|
||||||
// First dialog added. dialog_loop_next_index_ == SIZE_MAX is also checked
|
// First dialog added. !IsDrawingDialogs() is also checked because in a
|
||||||
// because in a situation of removing the only dialog, then adding a dialog,
|
// situation of removing the only dialog, then adding a dialog, from within
|
||||||
// from within a dialog's Draw function, the removal would not cause the
|
// a dialog's Draw function, re-registering the ImGuiDrawer may result in
|
||||||
// listener and the drawer to be removed (it's deferred in this case).
|
// ImGui being drawn multiple times in the current frame.
|
||||||
window_->AddInputListener(this, z_order_);
|
window_->AddInputListener(this, z_order_);
|
||||||
if (presenter_) {
|
if (presenter_) {
|
||||||
presenter_->AddUIDrawerFromUIThread(this, z_order_);
|
presenter_->AddUIDrawerFromUIThread(this, z_order_);
|
||||||
|
@ -81,7 +81,7 @@ void ImGuiDrawer::RemoveDialog(ImGuiDialog* dialog) {
|
||||||
if (it == dialogs_.cend()) {
|
if (it == dialogs_.cend()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (dialog_loop_next_index_ != SIZE_MAX) {
|
if (IsDrawingDialogs()) {
|
||||||
// Actualize the next dialog index after the erasure from the vector.
|
// Actualize the next dialog index after the erasure from the vector.
|
||||||
size_t existing_index = size_t(std::distance(dialogs_.cbegin(), it));
|
size_t existing_index = size_t(std::distance(dialogs_.cbegin(), it));
|
||||||
if (dialog_loop_next_index_ > existing_index) {
|
if (dialog_loop_next_index_ > existing_index) {
|
||||||
|
@ -89,17 +89,7 @@ void ImGuiDrawer::RemoveDialog(ImGuiDialog* dialog) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dialogs_.erase(it);
|
dialogs_.erase(it);
|
||||||
if (dialog_loop_next_index_ == SIZE_MAX && dialogs_.empty()) {
|
DetachIfLastDialogRemoved();
|
||||||
if (presenter_) {
|
|
||||||
presenter_->RemoveUIDrawerFromUIThread(this);
|
|
||||||
}
|
|
||||||
window_->RemoveInputListener(this);
|
|
||||||
// Clear all input since no input will be received anymore, and when the
|
|
||||||
// drawer becomes active again, it'd have an outdated input state otherwise
|
|
||||||
// which will be persistent until new events actualize individual input
|
|
||||||
// properties.
|
|
||||||
ClearInput();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiDrawer::Initialize() {
|
void ImGuiDrawer::Initialize() {
|
||||||
|
@ -301,7 +291,7 @@ void ImGuiDrawer::Draw(UIDrawContext& ui_draw_context) {
|
||||||
|
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
assert_true(dialog_loop_next_index_ == SIZE_MAX);
|
assert_true(!IsDrawingDialogs());
|
||||||
dialog_loop_next_index_ = 0;
|
dialog_loop_next_index_ = 0;
|
||||||
while (dialog_loop_next_index_ < dialogs_.size()) {
|
while (dialog_loop_next_index_ < dialogs_.size()) {
|
||||||
dialogs_[dialog_loop_next_index_++]->Draw();
|
dialogs_[dialog_loop_next_index_++]->Draw();
|
||||||
|
@ -319,11 +309,11 @@ void ImGuiDrawer::Draw(UIDrawContext& ui_draw_context) {
|
||||||
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dialogs_.empty()) {
|
// Detaching is deferred if the last dialog is removed during drawing, perform
|
||||||
// All dialogs have removed themselves during the draw, detach.
|
// it now if needed.
|
||||||
presenter_->RemoveUIDrawerFromUIThread(this);
|
DetachIfLastDialogRemoved();
|
||||||
window_->RemoveInputListener(this);
|
|
||||||
} else {
|
if (!dialogs_.empty()) {
|
||||||
// Repaint (and handle input) continuously if still active.
|
// Repaint (and handle input) continuously if still active.
|
||||||
presenter_->RequestUIPaintFromUIThread();
|
presenter_->RequestUIPaintFromUIThread();
|
||||||
}
|
}
|
||||||
|
@ -557,5 +547,24 @@ void ImGuiDrawer::SwitchToPhysicalMouseAndUpdateMousePosition(
|
||||||
UpdateMousePosition(float(e.x()), float(e.y()));
|
UpdateMousePosition(float(e.x()), float(e.y()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImGuiDrawer::DetachIfLastDialogRemoved() {
|
||||||
|
// IsDrawingDialogs() is also checked because in a situation of removing the
|
||||||
|
// only dialog, then adding a dialog, from within a dialog's Draw function,
|
||||||
|
// re-registering the ImGuiDrawer may result in ImGui being drawn multiple
|
||||||
|
// times in the current frame.
|
||||||
|
if (!dialogs_.empty() || IsDrawingDialogs()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (presenter_) {
|
||||||
|
presenter_->RemoveUIDrawerFromUIThread(this);
|
||||||
|
}
|
||||||
|
window_->RemoveInputListener(this);
|
||||||
|
// Clear all input since no input will be received anymore, and when the
|
||||||
|
// drawer becomes active again, it'd have an outdated input state otherwise
|
||||||
|
// which will be persistent until new events actualize individual input
|
||||||
|
// properties.
|
||||||
|
ClearInput();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -74,6 +74,9 @@ class ImGuiDrawer : public WindowInputListener, public UIDrawer {
|
||||||
void UpdateMousePosition(float x, float y);
|
void UpdateMousePosition(float x, float y);
|
||||||
void SwitchToPhysicalMouseAndUpdateMousePosition(const MouseEvent& e);
|
void SwitchToPhysicalMouseAndUpdateMousePosition(const MouseEvent& e);
|
||||||
|
|
||||||
|
bool IsDrawingDialogs() const { return dialog_loop_next_index_ != SIZE_MAX; }
|
||||||
|
void DetachIfLastDialogRemoved();
|
||||||
|
|
||||||
Window* window_;
|
Window* window_;
|
||||||
size_t z_order_;
|
size_t z_order_;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue