Sdk: Fix segfault when deleting hovered widget

This commit is contained in:
Jérôme Leclercq 2017-10-06 14:12:18 +02:00
parent 1f48ec4099
commit be8cc08ba9
5 changed files with 63 additions and 48 deletions

View File

@ -80,7 +80,7 @@ namespace Ndk
}; };
protected: protected:
EntityHandle CreateEntity(); const EntityHandle& CreateEntity();
void DestroyEntity(Entity* entity); void DestroyEntity(Entity* entity);
virtual void Layout(); virtual void Layout();
void InvalidateNode() override; void InvalidateNode() override;

View File

@ -39,7 +39,7 @@ namespace Ndk
std::size_t RegisterWidget(BaseWidget* widget); std::size_t RegisterWidget(BaseWidget* widget);
inline void SetKeyboardOwner(BaseWidget* widget); inline void SetKeyboardOwner(std::size_t canvasIndex);
void UnregisterWidget(std::size_t index); void UnregisterWidget(std::size_t index);
@ -67,10 +67,10 @@ namespace Ndk
NazaraSlot(Nz::EventHandler, OnMouseLeft, m_mouseLeftSlot); NazaraSlot(Nz::EventHandler, OnMouseLeft, m_mouseLeftSlot);
NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot); NazaraSlot(Nz::EventHandler, OnTextEntered, m_textEnteredSlot);
std::size_t m_keyboardOwner;
std::size_t m_hoveredWidget;
std::vector<WidgetBox> m_widgetBoxes; std::vector<WidgetBox> m_widgetBoxes;
Nz::CursorControllerHandle m_cursorController; Nz::CursorControllerHandle m_cursorController;
const WidgetBox* m_hoveredWidget;
BaseWidget* m_keyboardOwner;
WorldHandle m_world; WorldHandle m_world;
}; };
} }

View File

@ -8,9 +8,9 @@
namespace Ndk namespace Ndk
{ {
inline Canvas::Canvas(WorldHandle world, Nz::EventHandler& eventHandler, Nz::CursorControllerHandle cursorController) : inline Canvas::Canvas(WorldHandle world, Nz::EventHandler& eventHandler, Nz::CursorControllerHandle cursorController) :
m_hoveredWidget(InvalidCanvasIndex),
m_keyboardOwner(InvalidCanvasIndex),
m_cursorController(cursorController), m_cursorController(cursorController),
m_hoveredWidget(nullptr),
m_keyboardOwner(nullptr),
m_world(std::move(world)) m_world(std::move(world))
{ {
m_canvas = this; m_canvas = this;
@ -61,12 +61,12 @@ namespace Ndk
WidgetBox& entry = m_widgetBoxes[index]; WidgetBox& entry = m_widgetBoxes[index];
entry.cursor = entry.widget->GetCursor(); entry.cursor = entry.widget->GetCursor();
if (m_cursorController && m_hoveredWidget == &entry) if (m_cursorController && m_hoveredWidget == index)
m_cursorController->UpdateCursor(Nz::Cursor::Get(entry.cursor)); m_cursorController->UpdateCursor(Nz::Cursor::Get(entry.cursor));
} }
inline void Ndk::Canvas::SetKeyboardOwner(BaseWidget* widget) inline void Canvas::SetKeyboardOwner(std::size_t canvasIndex)
{ {
m_keyboardOwner = widget; m_keyboardOwner = canvasIndex;
} }
} }

View File

@ -87,7 +87,7 @@ namespace Ndk
void BaseWidget::GrabKeyboard() void BaseWidget::GrabKeyboard()
{ {
m_canvas->SetKeyboardOwner(this); m_canvas->SetKeyboardOwner(m_canvasIndex);
} }
void BaseWidget::SetBackgroundColor(const Nz::Color& color) void BaseWidget::SetBackgroundColor(const Nz::Color& color)
@ -133,9 +133,9 @@ namespace Ndk
} }
} }
EntityHandle BaseWidget::CreateEntity() const Ndk::EntityHandle& BaseWidget::CreateEntity()
{ {
EntityHandle newEntity = m_world->CreateEntity(); const EntityHandle& newEntity = m_world->CreateEntity();
newEntity->Enable(m_visible); newEntity->Enable(m_visible);
m_entities.emplace_back(newEntity); m_entities.emplace_back(newEntity);

View File

@ -28,18 +28,25 @@ namespace Ndk
{ {
WidgetBox& entry = m_widgetBoxes[index]; WidgetBox& entry = m_widgetBoxes[index];
if (m_hoveredWidget == &entry) if (m_hoveredWidget == index)
m_hoveredWidget = nullptr; m_hoveredWidget = InvalidCanvasIndex;
if (m_keyboardOwner == entry.widget) if (m_keyboardOwner == index)
m_keyboardOwner = nullptr; m_keyboardOwner = InvalidCanvasIndex;
if (m_widgetBoxes.size() > 1U) if (m_widgetBoxes.size() > 1U)
{ {
WidgetBox& lastEntry = m_widgetBoxes.back(); WidgetBox& lastEntry = m_widgetBoxes.back();
std::size_t lastEntryIndex = m_widgetBoxes.size() - 1;
entry = std::move(lastEntry); entry = std::move(lastEntry);
entry.widget->UpdateCanvasIndex(index); entry.widget->UpdateCanvasIndex(index);
if (m_hoveredWidget == lastEntryIndex)
m_hoveredWidget = index;
if (m_keyboardOwner == lastEntryIndex)
m_keyboardOwner = index;
} }
m_widgetBoxes.pop_back(); m_widgetBoxes.pop_back();
@ -47,70 +54,78 @@ namespace Ndk
void Canvas::OnEventMouseButtonPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent& event) void Canvas::OnEventMouseButtonPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent& event)
{ {
if (m_hoveredWidget) if (m_hoveredWidget != InvalidCanvasIndex)
{ {
int x = static_cast<int>(std::round(event.x - m_hoveredWidget->box.x)); WidgetBox& hoveredWidget = m_widgetBoxes[m_hoveredWidget];
int y = static_cast<int>(std::round(event.y - m_hoveredWidget->box.y));
m_hoveredWidget->widget->OnMouseButtonPress(x, y, event.button); int x = static_cast<int>(std::round(event.x - hoveredWidget.box.x));
int y = static_cast<int>(std::round(event.y - hoveredWidget.box.y));
hoveredWidget.widget->OnMouseButtonPress(x, y, event.button);
} }
} }
void Canvas::OnEventMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent & event) void Canvas::OnEventMouseButtonRelease(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseButtonEvent & event)
{ {
if (m_hoveredWidget) if (m_hoveredWidget != InvalidCanvasIndex)
{ {
int x = static_cast<int>(std::round(event.x - m_hoveredWidget->box.x)); WidgetBox& hoveredWidget = m_widgetBoxes[m_hoveredWidget];
int y = static_cast<int>(std::round(event.y - m_hoveredWidget->box.y));
m_hoveredWidget->widget->OnMouseButtonRelease(x, y, event.button); int x = static_cast<int>(std::round(event.x - hoveredWidget.box.x));
int y = static_cast<int>(std::round(event.y - hoveredWidget.box.y));
hoveredWidget.widget->OnMouseButtonRelease(x, y, event.button);
} }
} }
void Canvas::OnEventMouseMoved(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseMoveEvent& event) void Canvas::OnEventMouseMoved(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::MouseMoveEvent& event)
{ {
const WidgetBox* bestEntry = nullptr; std::size_t bestEntry = InvalidCanvasIndex;
float bestEntryArea = std::numeric_limits<float>::infinity(); float bestEntryArea = std::numeric_limits<float>::infinity();
Nz::Vector3f mousePos(float(event.x), float(event.y), 0.f); Nz::Vector3f mousePos(float(event.x), float(event.y), 0.f);
for (const WidgetBox& entry : m_widgetBoxes) for (std::size_t i = 0; i < m_widgetBoxes.size(); ++i)
{ {
const Nz::Boxf& box = entry.box; const Nz::Boxf& box = m_widgetBoxes[i].box;
if (box.Contains(mousePos)) if (box.Contains(mousePos))
{ {
float area = box.width * box.height; float area = box.width * box.height;
if (area < bestEntryArea) if (area < bestEntryArea)
{ {
bestEntry = &entry; bestEntry = i;
bestEntryArea = area; bestEntryArea = area;
} }
} }
} }
if (bestEntry) if (bestEntry != InvalidCanvasIndex)
{ {
if (m_hoveredWidget != bestEntry) if (m_hoveredWidget != bestEntry)
{ {
if (m_hoveredWidget) if (m_hoveredWidget != InvalidCanvasIndex)
m_hoveredWidget->widget->OnMouseExit(); {
WidgetBox& previouslyHovered = m_widgetBoxes[m_hoveredWidget];
previouslyHovered.widget->OnMouseExit();
}
m_hoveredWidget = bestEntry; m_hoveredWidget = bestEntry;
m_hoveredWidget->widget->OnMouseEnter(); m_widgetBoxes[m_hoveredWidget].widget->OnMouseEnter();
if (m_cursorController) if (m_cursorController)
m_cursorController->UpdateCursor(Nz::Cursor::Get(m_hoveredWidget->cursor)); m_cursorController->UpdateCursor(Nz::Cursor::Get(m_widgetBoxes[m_hoveredWidget].cursor));
} }
int x = static_cast<int>(std::round(event.x - m_hoveredWidget->box.x)); WidgetBox& hoveredWidget = m_widgetBoxes[m_hoveredWidget];
int y = static_cast<int>(std::round(event.y - m_hoveredWidget->box.y));
bestEntry->widget->OnMouseMoved(x, y, event.deltaX, event.deltaY); int x = static_cast<int>(std::round(event.x - hoveredWidget.box.x));
int y = static_cast<int>(std::round(event.y - hoveredWidget.box.y));
hoveredWidget.widget->OnMouseMoved(x, y, event.deltaX, event.deltaY);
} }
else if (m_hoveredWidget) else if (m_hoveredWidget != InvalidCanvasIndex)
{ {
m_hoveredWidget->widget->OnMouseExit(); m_widgetBoxes[m_hoveredWidget].widget->OnMouseExit();
m_hoveredWidget = nullptr; m_hoveredWidget = InvalidCanvasIndex;
if (m_cursorController) if (m_cursorController)
m_cursorController->UpdateCursor(Nz::Cursor::Get(Nz::SystemCursor_Default)); m_cursorController->UpdateCursor(Nz::Cursor::Get(Nz::SystemCursor_Default));
@ -119,28 +134,28 @@ namespace Ndk
void Canvas::OnEventMouseLeft(const Nz::EventHandler* /*eventHandler*/) void Canvas::OnEventMouseLeft(const Nz::EventHandler* /*eventHandler*/)
{ {
if (m_hoveredWidget) if (m_hoveredWidget != InvalidCanvasIndex)
{ {
m_hoveredWidget->widget->OnMouseExit(); m_widgetBoxes[m_hoveredWidget].widget->OnMouseExit();
m_hoveredWidget = nullptr; m_hoveredWidget = InvalidCanvasIndex;
} }
} }
void Canvas::OnEventKeyPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event) void Canvas::OnEventKeyPressed(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event)
{ {
if (m_keyboardOwner) if (m_keyboardOwner != InvalidCanvasIndex)
m_keyboardOwner->OnKeyPressed(event); m_widgetBoxes[m_hoveredWidget].widget->OnKeyPressed(event);
} }
void Canvas::OnEventKeyReleased(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event) void Canvas::OnEventKeyReleased(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::KeyEvent& event)
{ {
if (m_keyboardOwner) if (m_keyboardOwner != InvalidCanvasIndex)
m_keyboardOwner->OnKeyReleased(event); m_widgetBoxes[m_hoveredWidget].widget->OnKeyReleased(event);
} }
void Canvas::OnEventTextEntered(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::TextEvent& event) void Canvas::OnEventTextEntered(const Nz::EventHandler* /*eventHandler*/, const Nz::WindowEvent::TextEvent& event)
{ {
if (m_keyboardOwner) if (m_keyboardOwner != InvalidCanvasIndex)
m_keyboardOwner->OnTextEntered(event.character, event.repeated); m_widgetBoxes[m_hoveredWidget].widget->OnTextEntered(event.character, event.repeated);
} }
} }