Widgets/Canvas: Add mouse owner system
This commit is contained in:
parent
db88f0ca0d
commit
a29c0b0e63
|
|
@ -11,6 +11,7 @@
|
|||
#include <Nazara/Platform/EventHandler.hpp>
|
||||
#include <Nazara/Widgets/BaseWidget.hpp>
|
||||
#include <entt/entity/registry.hpp>
|
||||
#include <bitset>
|
||||
|
||||
namespace Nz
|
||||
{
|
||||
|
|
@ -36,8 +37,10 @@ namespace Nz
|
|||
|
||||
protected:
|
||||
inline void ClearKeyboardOwner(std::size_t canvasIndex);
|
||||
inline void ClearMouseOwner(std::size_t canvasIndex);
|
||||
|
||||
inline bool IsKeyboardOwner(std::size_t canvasIndex) const;
|
||||
inline bool IsMouseOwner(std::size_t canvasIndex) const;
|
||||
|
||||
inline void NotifyWidgetBoxUpdate(std::size_t index);
|
||||
inline void NotifyWidgetCursorUpdate(std::size_t index);
|
||||
|
|
@ -45,20 +48,25 @@ namespace Nz
|
|||
std::size_t RegisterWidget(BaseWidget* widget);
|
||||
|
||||
inline void SetKeyboardOwner(std::size_t canvasIndex);
|
||||
inline void SetMouseOwner(std::size_t canvasIndex);
|
||||
|
||||
void UnregisterWidget(std::size_t index);
|
||||
|
||||
private:
|
||||
void OnEventMouseButtonPressed(const EventHandler* eventHandler, const WindowEvent::MouseButtonEvent& event);
|
||||
void OnEventMouseButtonRelease(const EventHandler* eventHandler, const WindowEvent::MouseButtonEvent& event);
|
||||
void OnEventMouseEntered(const EventHandler* eventHandler);
|
||||
void OnEventMouseLeft(const EventHandler* eventHandler);
|
||||
void OnEventMouseMoved(const EventHandler* eventHandler, const WindowEvent::MouseMoveEvent& event);
|
||||
|
||||
void OnEventMouseWheelMoved(const EventHandler* eventHandler, const WindowEvent::MouseWheelEvent& event);
|
||||
void OnEventKeyPressed(const EventHandler* eventHandler, const WindowEvent::KeyEvent& event);
|
||||
void OnEventKeyReleased(const EventHandler* eventHandler, const WindowEvent::KeyEvent& event);
|
||||
void OnEventTextEntered(const EventHandler* eventHandler, const WindowEvent::TextEvent& event);
|
||||
void OnEventTextEdited(const EventHandler* eventHandler, const WindowEvent::EditEvent& event);
|
||||
|
||||
void UpdateHoveredWidget(int x, int y);
|
||||
|
||||
struct WidgetEntry
|
||||
{
|
||||
BaseWidget* widget;
|
||||
|
|
@ -70,6 +78,7 @@ namespace Nz
|
|||
NazaraSlot(EventHandler, OnKeyReleased, m_keyReleasedSlot);
|
||||
NazaraSlot(EventHandler, OnMouseButtonPressed, m_mouseButtonPressedSlot);
|
||||
NazaraSlot(EventHandler, OnMouseButtonReleased, m_mouseButtonReleasedSlot);
|
||||
NazaraSlot(EventHandler, OnMouseEntered, m_mouseEnteredSlot);
|
||||
NazaraSlot(EventHandler, OnMouseLeft, m_mouseLeftSlot);
|
||||
NazaraSlot(EventHandler, OnMouseMoved, m_mouseMovedSlot);
|
||||
NazaraSlot(EventHandler, OnMouseWheelMoved, m_mouseWheelMovedSlot);
|
||||
|
|
@ -78,8 +87,10 @@ namespace Nz
|
|||
|
||||
CursorControllerHandle m_cursorController;
|
||||
UInt32 m_renderMask;
|
||||
std::bitset<Mouse::ButtonCount> m_mouseOwnerButtons;
|
||||
std::size_t m_keyboardOwner;
|
||||
std::size_t m_hoveredWidget;
|
||||
std::size_t m_mouseOwner;
|
||||
std::vector<WidgetEntry> m_widgetEntries;
|
||||
entt::registry& m_registry;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ namespace Nz
|
|||
m_renderMask(renderMask),
|
||||
m_keyboardOwner(InvalidCanvasIndex),
|
||||
m_hoveredWidget(InvalidCanvasIndex),
|
||||
m_mouseOwner(InvalidCanvasIndex),
|
||||
m_registry(registry),
|
||||
m_cursorController(cursorController)
|
||||
{
|
||||
|
|
@ -26,6 +27,7 @@ namespace Nz
|
|||
m_keyReleasedSlot.Connect(eventHandler.OnKeyReleased, this, &Canvas::OnEventKeyReleased);
|
||||
m_mouseButtonPressedSlot.Connect(eventHandler.OnMouseButtonPressed, this, &Canvas::OnEventMouseButtonPressed);
|
||||
m_mouseButtonReleasedSlot.Connect(eventHandler.OnMouseButtonReleased, this, &Canvas::OnEventMouseButtonRelease);
|
||||
m_mouseEnteredSlot.Connect(eventHandler.OnMouseEntered, this, &Canvas::OnEventMouseEntered);
|
||||
m_mouseLeftSlot.Connect(eventHandler.OnMouseLeft, this, &Canvas::OnEventMouseLeft);
|
||||
m_mouseMovedSlot.Connect(eventHandler.OnMouseMoved, this, &Canvas::OnEventMouseMoved);
|
||||
m_mouseWheelMovedSlot.Connect(eventHandler.OnMouseWheelMoved, this, &Canvas::OnEventMouseWheelMoved);
|
||||
|
|
@ -63,11 +65,22 @@ namespace Nz
|
|||
SetKeyboardOwner(InvalidCanvasIndex);
|
||||
}
|
||||
|
||||
inline void Canvas::ClearMouseOwner(std::size_t canvasIndex)
|
||||
{
|
||||
if (m_mouseOwner == canvasIndex)
|
||||
SetMouseOwner(InvalidCanvasIndex);
|
||||
}
|
||||
|
||||
inline bool Canvas::IsKeyboardOwner(std::size_t canvasIndex) const
|
||||
{
|
||||
return m_keyboardOwner == canvasIndex;
|
||||
}
|
||||
|
||||
inline bool Canvas::IsMouseOwner(std::size_t canvasIndex) const
|
||||
{
|
||||
return m_mouseOwner == canvasIndex;
|
||||
}
|
||||
|
||||
inline void Canvas::NotifyWidgetBoxUpdate(std::size_t index)
|
||||
{
|
||||
WidgetEntry& entry = m_widgetEntries[index];
|
||||
|
|
@ -100,6 +113,14 @@ namespace Nz
|
|||
m_widgetEntries[m_keyboardOwner].widget->OnFocusReceived();
|
||||
}
|
||||
}
|
||||
|
||||
inline void Canvas::SetMouseOwner(std::size_t canvasIndex)
|
||||
{
|
||||
if (m_mouseOwner != canvasIndex)
|
||||
{
|
||||
m_mouseOwner = canvasIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <Nazara/Widgets/DebugOff.hpp>
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue