aboutsummaryrefslogtreecommitdiff
path: root/guilib
diff options
context:
space:
mode:
authorjmarshallnz <jmarshallnz@svn>2010-01-09 09:05:41 +0000
committerjmarshallnz <jmarshallnz@svn>2010-01-09 09:05:41 +0000
commit8bd9964d8a756ac92149efe980e2616f8f2e5c4a (patch)
tree3e09129bec0c4c533d7d5fd1592faceca358dbb8 /guilib
parentf2508d4a464540428c7c0f293b356b5a5d1003b4 (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.cpp32
-rw-r--r--guilib/GUIControl.h34
-rw-r--r--guilib/GUIControlGroup.cpp32
-rw-r--r--guilib/GUIControlGroup.h2
-rw-r--r--guilib/GUIControlGroupList.cpp46
-rw-r--r--guilib/GUIControlGroupList.h3
-rw-r--r--guilib/GUIWindow.cpp83
-rw-r--r--guilib/GUIWindow.h1
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);