diff options
author | jmarshallnz <jmarshallnz@svn> | 2010-01-09 09:05:41 +0000 |
---|---|---|
committer | jmarshallnz <jmarshallnz@svn> | 2010-01-09 09:05:41 +0000 |
commit | 8bd9964d8a756ac92149efe980e2616f8f2e5c4a (patch) | |
tree | 3e09129bec0c4c533d7d5fd1592faceca358dbb8 /guilib | |
parent | f2508d4a464540428c7c0f293b356b5a5d1003b4 (diff) |
changed: Improved mouse event handling - we now pass events down through the control structure, giving better context for the performed event. Allows groups to react if their children don't.
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@26577 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'guilib')
-rw-r--r-- | guilib/GUIControl.cpp | 32 | ||||
-rw-r--r-- | guilib/GUIControl.h | 34 | ||||
-rw-r--r-- | guilib/GUIControlGroup.cpp | 32 | ||||
-rw-r--r-- | guilib/GUIControlGroup.h | 2 | ||||
-rw-r--r-- | guilib/GUIControlGroupList.cpp | 46 | ||||
-rw-r--r-- | guilib/GUIControlGroupList.h | 3 | ||||
-rw-r--r-- | guilib/GUIWindow.cpp | 83 | ||||
-rw-r--r-- | guilib/GUIWindow.h | 1 |
8 files changed, 134 insertions, 99 deletions
diff --git a/guilib/GUIControl.cpp b/guilib/GUIControl.cpp index 6bc24acdc5..d2ea947cfa 100644 --- a/guilib/GUIControl.cpp +++ b/guilib/GUIControl.cpp @@ -510,6 +510,38 @@ bool CGUIControl::HitTest(const CPoint &point) const return m_hitRect.PtInRect(point); } +bool CGUIControl::SendMouseEvent(const CPoint &point, const CMouseEvent &event) +{ + childPoint = point; + if (!CanFocusFromPoint(point, childPoint)) + return false; + + bool handled = OnMouseOver(childPoint); + if (OnMouseEvent(childPoint, event)) + return true; + return handled; +} + +bool CGUIControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event) +{ + switch (event.m_id) + { + case ACTION_MOUSE_LEFT_CLICK: + return OnMouseClick(MOUSE_LEFT_BUTTON, point); + case ACTION_MOUSE_DOUBLE_CLICK: + return OnMouseDoubleClick(MOUSE_LEFT_BUTTON, point); + case ACTION_MOUSE_RIGHT_CLICK: + return OnMouseClick(MOUSE_RIGHT_BUTTON, point); + case ACTION_MOUSE_MIDDLE_CLICK: + return OnMouseClick(MOUSE_MIDDLE_BUTTON, point); + case ACTION_MOUSE_DRAG: + return OnMouseDrag(CPoint(event.m_offsetX, event.m_offsetY), point); + case ACTION_MOUSE_WHEEL: + return OnMouseWheel(event.m_wheel, point); + } + return false; +} + // override this function to implement custom mouse behaviour bool CGUIControl::OnMouseOver(const CPoint &point) { diff --git a/guilib/GUIControl.h b/guilib/GUIControl.h index 267d9a3609..68608f259d 100644 --- a/guilib/GUIControl.h +++ b/guilib/GUIControl.h @@ -37,6 +37,7 @@ class CGUIListItem; // forward class CAction; +class CMouseEvent; enum ORIENTATION { HORIZONTAL = 0, VERTICAL }; @@ -130,8 +131,18 @@ public: virtual bool OnMouseDoubleClick(int button, const CPoint &point) { return false; }; /// \brief Called when the mouse wheel has moved whilst over the control. Default implementation does nothing virtual bool OnMouseWheel(char wheel, const CPoint &point) { return false; }; - /// \brief Used to test whether the pointer location (fPosX, fPosY) is inside the control. For mouse events. - virtual bool HitTest(const CPoint &point) const; + + /*! \brief React to a mouse event + + Mouse events are sent from the window to all controls, and each control can react based on the event + and location of the event. + + \param point the location in skin coordinates from the upper left corner of the parent control. + \param event the mouse event to perform + \return true if the control has handled this event, false otherwise + \sa HitTest, CanFocusFromPoint, CMouseEvent + */ + virtual bool SendMouseEvent(const CPoint &point, const CMouseEvent &event); /*! \brief Test whether we can focus a control from a point on screen \param point the location in skin coordinates from the upper left corner of the parent control. @@ -147,6 +158,13 @@ public: */ virtual void UnfocusFromPoint(const CPoint &point); + /*! \brief Used to test whether the point is inside a control. + \param point location to test + \return true if the point is inside the bounds of this control. + \sa SetHitRect + */ + virtual bool HitTest(const CPoint &point) const; + virtual bool OnMessage(CGUIMessage& message); virtual int GetID(void) const; void SetID(int id) { m_controlID = id; }; @@ -277,6 +295,18 @@ public: virtual void DumpTextureUse() {}; #endif protected: + /*! \brief Perform a mouse action + + Mouse actions are sent from the window to all controls, and each control can react based on the event + and location of the actions. + + \param point the location in skin coordinates from the upper left corner of the parent control. + \param event the mouse event to perform + \return true if the control has handled this event, false otherwise + \sa SendMouseEvent, HitTest, CanFocusFromPoint, CMouseEvent + */ + virtual bool OnMouseEvent(const CPoint &point, const CMouseEvent &event); + virtual void UpdateColors(); virtual void Animate(unsigned int currentTime); virtual bool CheckAnimation(ANIMATION_TYPE animType); diff --git a/guilib/GUIControlGroup.cpp b/guilib/GUIControlGroup.cpp index 42848a9668..663d88fce7 100644 --- a/guilib/GUIControlGroup.cpp +++ b/guilib/GUIControlGroup.cpp @@ -357,22 +357,28 @@ bool CGUIControlGroup::HasAnimation(ANIMATION_TYPE animType) return false; } -void CGUIControlGroup::GetControlsFromPoint(const CPoint &point, vector< std::pair<CGUIControl *, CPoint> > &controls) const +bool CGUIControlGroup::SendMouseEvent(const CPoint &point, const CMouseEvent &event) { - if (!CGUIControl::CanFocus()) - return; - CPoint controlCoords(point); - m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y); - controlCoords -= GetPosition(); - for (crControls it = m_children.rbegin(); it != m_children.rend(); ++it) + // transform our position into child coordinates + CPoint childPoint(point); + m_transform.InverseTransformPosition(childPoint.x, childPoint.y); + childPoint -= GetPosition(); + + if (CanFocus()) { - CGUIControl *child = *it; - CPoint childCoords; - if (child->IsGroup()) - ((CGUIControlGroup *)child)->GetControlsFromPoint(controlCoords, controls); - else if (child->CanFocusFromPoint(controlCoords, childCoords)) - controls.push_back(make_pair(child, childCoords)); + // run through our controls in reverse order (so that last rendered is checked first) + for (crControls i = m_children.rbegin(); i != m_children.rend(); ++i) + { + CGUIControl *child = *i; + if (child->SendMouseEvent(childPoint, event)) + { // we've handled the action, and/or have focused an item + return true; + } + } } + // if we get here we haven't handled the event and thus do not have focus + m_focusedControl = 0; + return false; } void CGUIControlGroup::UnfocusFromPoint(const CPoint &point) diff --git a/guilib/GUIControlGroup.h b/guilib/GUIControlGroup.h index e55393b657..b108812d0b 100644 --- a/guilib/GUIControlGroup.h +++ b/guilib/GUIControlGroup.h @@ -51,7 +51,7 @@ public: virtual void DynamicResourceAlloc(bool bOnOff); virtual bool CanFocus() const; - virtual void GetControlsFromPoint(const CPoint &point, std::vector< std::pair<CGUIControl *, CPoint> > &controls) const; + virtual bool SendMouseEvent(const CPoint &point, const CMouseEvent &event); virtual void UnfocusFromPoint(const CPoint &point); virtual void SetInitialVisibility(); diff --git a/guilib/GUIControlGroupList.cpp b/guilib/GUIControlGroupList.cpp index 4670af2afc..ce5bd2f651 100644 --- a/guilib/GUIControlGroupList.cpp +++ b/guilib/GUIControlGroupList.cpp @@ -311,31 +311,39 @@ void CGUIControlGroupList::ScrollTo(float offset) m_scrollSpeed = (m_scrollOffset - m_offset) / m_scrollTime; } -void CGUIControlGroupList::GetControlsFromPoint(const CPoint &point, std::vector< std::pair<CGUIControl *, CPoint> > &controls) const +bool CGUIControlGroupList::SendMouseEvent(const CPoint &point, const CMouseEvent &event) { - if (!CGUIControl::CanFocus()) return; - float pos = 0; - CPoint controlCoords(point); - m_transform.InverseTransformPosition(controlCoords.x, controlCoords.y); - float alignOffset = GetAlignOffset(); - for (ciControls it = m_children.begin(); it != m_children.end(); ++it) + // transform our position into child coordinates + CPoint childPoint(point); + m_transform.InverseTransformPosition(childPoint.x, childPoint.y); + if (CanFocus()) { - CGUIControl *child = *it; - if (child->IsVisible()) + // run through our controls in reverse order (so that last rendered is checked first) + float pos = 0; + float alignOffset = GetAlignOffset(); + for (ciControls i = m_children.begin(); i != m_children.end(); ++i) { - if (pos + Size(child) > m_offset && pos < m_offset + Size()) - { // we're on screen - float offsetX = m_orientation == VERTICAL ? m_posX : m_posX + alignOffset + pos - m_offset; - float offsetY = m_orientation == VERTICAL ? m_posY + alignOffset + pos - m_offset : m_posY; - CPoint childCoords; - if (child->IsGroup()) - ((CGUIControlGroup *)child)->GetControlsFromPoint(controlCoords - CPoint(offsetX, offsetY), controls); - else if (child->CanFocusFromPoint(controlCoords - CPoint(offsetX, offsetY), childCoords)) - controls.push_back(std::make_pair(child, childCoords)); + CGUIControl *child = *i; + if (child->IsVisible()) + { + if (pos + Size(child) > m_offset && pos < m_offset + Size()) + { // we're on screen + float offsetX = m_orientation == VERTICAL ? m_posX : m_posX + alignOffset + pos - m_offset; + float offsetY = m_orientation == VERTICAL ? m_posY + alignOffset + pos - m_offset : m_posY; + if (child->SendMouseEvent(childPoint - CPoint(offsetX, offsetY), event)) + { // we've handled the action, and/or have focused an item + return true; + } + } + pos += Size(child) + m_itemGap; } - pos += Size(child) + m_itemGap; } } + // if we get here we none of our children want the event, but we may want it. + if (HitTest(point) && OnMouseEvent(point, event)) + return true; + m_focusedControl = 0; + return false; } void CGUIControlGroupList::UnfocusFromPoint(const CPoint &point) diff --git a/guilib/GUIControlGroupList.h b/guilib/GUIControlGroupList.h index bb34960ae8..b40bf407a6 100644 --- a/guilib/GUIControlGroupList.h +++ b/guilib/GUIControlGroupList.h @@ -41,7 +41,8 @@ public: virtual void Render(); virtual bool OnMessage(CGUIMessage& message); - virtual void GetControlsFromPoint(const CPoint &point, std::vector< std::pair<CGUIControl *, CPoint> > &controls) const; + + virtual bool SendMouseEvent(const CPoint &point, const CMouseEvent &event); virtual void UnfocusFromPoint(const CPoint &point); virtual void AddControl(CGUIControl *control, int position = -1); diff --git a/guilib/GUIWindow.cpp b/guilib/GUIWindow.cpp index cfe25dd881..1d046e65c6 100644 --- a/guilib/GUIWindow.cpp +++ b/guilib/GUIWindow.cpp @@ -368,43 +368,32 @@ bool CGUIWindow::OnMouseAction() CPoint mousePoint(g_Mouse.GetLocation()); g_graphicsContext.InvertFinalCoords(mousePoint.x, mousePoint.y); - bool bHandled = false; - // check if we have exclusive access - if (g_Mouse.GetExclusiveWindowID() == GetID() && IsValidControl(g_Mouse.GetExclusiveControl())) - { // we have exclusive access to the mouse... - HandleMouse((CGUIControl *)g_Mouse.GetExclusiveControl(), mousePoint + g_Mouse.GetExclusiveOffset()); - return true; - } - - // run through the controls, and unfocus all those that aren't under the pointer, - // and find which ones are under the pointer UnfocusFromPoint(mousePoint); - vector< pair<CGUIControl *, CPoint> > controls; - GetControlsFromPoint(mousePoint, controls); - bool controlUnderPointer(false); - for (vector< pair<CGUIControl *, CPoint> >::iterator i = controls.begin(); i != controls.end(); ++i) - { - CGUIControl *child = i->first; - controlUnderPointer = child->OnMouseOver(i->second); - bHandled = HandleMouse(child, i->second); - if (bHandled || controlUnderPointer) - break; - } - if (!bHandled) - { // haven't handled this action - call the window message handlers - bHandled = OnMouse(mousePoint); - } - // and unfocus everything otherwise - if (!controlUnderPointer) - m_focusedControl = 0; + // create the mouse event + CMouseEvent *event = NULL; + if (g_Mouse.bClick[MOUSE_LEFT_BUTTON]) + event = new CMouseEvent(ACTION_MOUSE_LEFT_CLICK); + else if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON]) + event = new CMouseEvent(ACTION_MOUSE_RIGHT_CLICK); + else if (g_Mouse.bClick[MOUSE_MIDDLE_BUTTON]) + event = new CMouseEvent(ACTION_MOUSE_MIDDLE_CLICK); + else if (g_Mouse.bDoubleClick[MOUSE_LEFT_BUTTON]) + event = new CMouseEvent(ACTION_MOUSE_DOUBLE_CLICK); + else if (g_Mouse.bHold[MOUSE_LEFT_BUTTON] && g_Mouse.HasMoved(true)) + event = new CMouseEvent(ACTION_MOUSE_DRAG, 0, g_Mouse.GetLastMove().x, g_Mouse.GetLastMove().y); + else if (g_Mouse.GetWheel()) + event = new CMouseEvent(ACTION_MOUSE_WHEEL, g_Mouse.GetWheel()); + else + event = new CMouseEvent(0); // mouse move only + + if (SendMouseEvent(mousePoint, *event)) + return true; - return bHandled; + // unhandled + return OnMouse(mousePoint); } -// Handles any mouse actions that are not handled by a control -// default is to go back a window on a right click. -// This function should be overridden for other windows bool CGUIWindow::OnMouse(const CPoint &point) { if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON]) @@ -416,36 +405,6 @@ bool CGUIWindow::OnMouse(const CPoint &point) return false; } -bool CGUIWindow::HandleMouse(CGUIControl *pControl, const CPoint &point) -{ - if (g_Mouse.bClick[MOUSE_LEFT_BUTTON]) - { // Left click - return pControl->OnMouseClick(MOUSE_LEFT_BUTTON, point); - } - else if (g_Mouse.bClick[MOUSE_RIGHT_BUTTON]) - { // Right click - return pControl->OnMouseClick(MOUSE_RIGHT_BUTTON, point); - } - else if (g_Mouse.bClick[MOUSE_MIDDLE_BUTTON]) - { // Middle click - return pControl->OnMouseClick(MOUSE_MIDDLE_BUTTON, point); - } - else if (g_Mouse.bDoubleClick[MOUSE_LEFT_BUTTON]) - { // Left double click - return pControl->OnMouseDoubleClick(MOUSE_LEFT_BUTTON, point); - } - else if (g_Mouse.bHold[MOUSE_LEFT_BUTTON] && g_Mouse.HasMoved(true)) - { // Mouse Drag - return pControl->OnMouseDrag(g_Mouse.GetLastMove(), point); - } - else if (g_Mouse.GetWheel()) - { // Mouse wheel - return pControl->OnMouseWheel(g_Mouse.GetWheel(), point); - } - // no mouse stuff done other than movement - return false; -} - /// \brief Called on window open. /// * Restores the control state(s) /// * Sets initial visibility of controls diff --git a/guilib/GUIWindow.h b/guilib/GUIWindow.h index 8b84d2a106..7fecbac2a2 100644 --- a/guilib/GUIWindow.h +++ b/guilib/GUIWindow.h @@ -98,7 +98,6 @@ public: virtual bool OnAction(const CAction &action); virtual bool OnMouse(const CPoint &point); - bool HandleMouse(CGUIControl *pControl, const CPoint &point); bool OnMove(int fromControl, int moveAction); virtual bool OnMessage(CGUIMessage& message); |