Widgets/Canvas: Add mouse owner system

This commit is contained in:
Jérôme Leclercq
2021-11-28 20:20:30 +01:00
parent db88f0ca0d
commit a29c0b0e63
3 changed files with 128 additions and 53 deletions

View File

@@ -28,6 +28,12 @@ namespace Nz
if (m_hoveredWidget == index)
m_hoveredWidget = InvalidCanvasIndex;
if (m_mouseOwner == index)
{
m_mouseOwner = InvalidCanvasIndex;
m_mouseOwnerButtons.reset();
}
if (m_keyboardOwner == index)
m_keyboardOwner = InvalidCanvasIndex;
@@ -42,6 +48,9 @@ namespace Nz
if (m_hoveredWidget == lastEntryIndex)
m_hoveredWidget = index;
if (m_mouseOwner == lastEntryIndex)
m_mouseOwner = index;
if (m_keyboardOwner == lastEntryIndex)
m_keyboardOwner = index;
}
@@ -51,6 +60,8 @@ namespace Nz
void Canvas::OnEventMouseButtonPressed(const EventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& event)
{
UpdateHoveredWidget(event.x, event.y);
if (m_hoveredWidget != InvalidCanvasIndex)
{
WidgetEntry& hoveredWidget = m_widgetEntries[m_hoveredWidget];
@@ -60,6 +71,9 @@ namespace Nz
hoveredWidget.widget->OnMouseButtonPress(x, y, event.button);
}
SetMouseOwner(m_hoveredWidget);
m_mouseOwnerButtons[event.button] = true;
}
void Canvas::OnEventMouseButtonRelease(const EventHandler* /*eventHandler*/, const WindowEvent::MouseButtonEvent& event)
@@ -73,59 +87,46 @@ namespace Nz
hoveredWidget.widget->OnMouseButtonRelease(x, y, event.button);
}
m_mouseOwnerButtons[event.button] = false;
if (m_mouseOwnerButtons.none())
SetMouseOwner(InvalidCanvasIndex);
UpdateHoveredWidget(event.x, event.y);
}
void Canvas::OnEventMouseEntered(const EventHandler* eventHandler)
{
// Keep previous mouse states but not new ones
for (std::size_t i = 0; i < Mouse::ButtonCount; ++i)
m_mouseOwnerButtons[i] = m_mouseOwnerButtons[i] && Mouse::IsButtonPressed(static_cast<Mouse::Button>(i));
if (m_mouseOwnerButtons.none())
SetMouseOwner(InvalidCanvasIndex);
}
void Canvas::OnEventMouseLeft(const EventHandler* /*eventHandler*/)
{
if (m_hoveredWidget != InvalidCanvasIndex && m_mouseOwner == InvalidCanvasIndex)
{
m_widgetEntries[m_hoveredWidget].widget->OnMouseExit();
m_hoveredWidget = InvalidCanvasIndex;
}
}
void Canvas::OnEventMouseMoved(const EventHandler* /*eventHandler*/, const WindowEvent::MouseMoveEvent& event)
{
std::size_t bestEntry = InvalidCanvasIndex;
float bestEntryArea = std::numeric_limits<float>::infinity();
// Don't update hovered widget while the user doesn't release its mouse
UpdateHoveredWidget(event.x, event.y);
Vector3f mousePos(float(event.x), m_size.y - float(event.y), 0.f);
for (std::size_t i = 0; i < m_widgetEntries.size(); ++i)
if (m_hoveredWidget != InvalidCanvasIndex)
{
const Boxf& box = m_widgetEntries[i].box;
if (box.Contains(mousePos))
{
float area = box.width * box.height;
if (area < bestEntryArea)
{
bestEntry = i;
bestEntryArea = area;
}
}
}
if (bestEntry != InvalidCanvasIndex)
{
if (m_hoveredWidget != bestEntry)
{
if (m_hoveredWidget != InvalidCanvasIndex)
{
WidgetEntry& previouslyHovered = m_widgetEntries[m_hoveredWidget];
previouslyHovered.widget->OnMouseExit();
}
m_hoveredWidget = bestEntry;
m_widgetEntries[m_hoveredWidget].widget->OnMouseEnter();
if (m_cursorController)
m_cursorController->UpdateCursor(Cursor::Get(m_widgetEntries[m_hoveredWidget].cursor));
}
WidgetEntry& hoveredWidget = m_widgetEntries[m_hoveredWidget];
int x = static_cast<int>(std::round(mousePos.x - hoveredWidget.box.x));
int y = static_cast<int>(std::round(mousePos.y - hoveredWidget.box.y));
hoveredWidget.widget->OnMouseMoved(x, y, event.deltaX, event.deltaY);
}
else if (m_hoveredWidget != InvalidCanvasIndex)
{
m_widgetEntries[m_hoveredWidget].widget->OnMouseExit();
m_hoveredWidget = InvalidCanvasIndex;
int x = static_cast<int>(std::round(event.x - hoveredWidget.box.x));
int y = static_cast<int>(std::round(m_size.y - event.y - hoveredWidget.box.y));
if (m_cursorController)
m_cursorController->UpdateCursor(Cursor::Get(SystemCursor::Default));
hoveredWidget.widget->OnMouseMoved(x, y, event.deltaX, -event.deltaY);
}
}
@@ -142,15 +143,6 @@ namespace Nz
}
}
void Canvas::OnEventMouseLeft(const EventHandler* /*eventHandler*/)
{
if (m_hoveredWidget != InvalidCanvasIndex)
{
m_widgetEntries[m_hoveredWidget].widget->OnMouseExit();
m_hoveredWidget = InvalidCanvasIndex;
}
}
void Canvas::OnEventKeyPressed(const EventHandler* eventHandler, const WindowEvent::KeyEvent& event)
{
if (m_keyboardOwner != InvalidCanvasIndex)
@@ -228,4 +220,55 @@ namespace Nz
if (m_keyboardOwner != InvalidCanvasIndex)
m_widgetEntries[m_keyboardOwner].widget->OnTextEdited(event.text, event.length);
}
void Canvas::UpdateHoveredWidget(int x, int y)
{
if (m_mouseOwner != InvalidCanvasIndex)
return;
std::size_t bestEntry = InvalidCanvasIndex;
float bestEntryArea = std::numeric_limits<float>::infinity();
Vector3f mousePos(float(x), m_size.y - float(y), 0.f);
for (std::size_t i = 0; i < m_widgetEntries.size(); ++i)
{
const Boxf& box = m_widgetEntries[i].box;
if (box.Contains(mousePos))
{
float area = box.width * box.height;
if (area < bestEntryArea)
{
bestEntry = i;
bestEntryArea = area;
}
}
}
if (bestEntry != InvalidCanvasIndex)
{
if (m_hoveredWidget != bestEntry)
{
if (m_hoveredWidget != InvalidCanvasIndex)
{
WidgetEntry& previouslyHovered = m_widgetEntries[m_hoveredWidget];
previouslyHovered.widget->OnMouseExit();
}
m_hoveredWidget = bestEntry;
m_widgetEntries[m_hoveredWidget].widget->OnMouseEnter();
if (m_cursorController)
m_cursorController->UpdateCursor(Cursor::Get(m_widgetEntries[m_hoveredWidget].cursor));
}
}
else if (m_hoveredWidget != InvalidCanvasIndex)
{
m_widgetEntries[m_hoveredWidget].widget->OnMouseExit();
m_hoveredWidget = InvalidCanvasIndex;
if (m_cursorController)
m_cursorController->UpdateCursor(Cursor::Get(SystemCursor::Default));
}
}
}