Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

[Drag&Drop] Let CGUIControls be drop targets #2826

Open
wants to merge 4 commits into from

6 participants

@Fice

Here is my first part of my Drag&Drop stuff.
It let's skinners add a action to all CGUIControls (excepts Containers like Panels.). This ondrop action will be executed when the user drags a listitem on it.

I also made a skin change, that shows the dragged items icon under the mouse. Doesn't look bad, but I guess a skinner could improve on that.

@Fice

Updated

  • removed the cherry-pick, because it's now in trunk
  • made the changes suggested by @pieh
  • fixed a bug where the mouse became invisible when you pressed a button during drag&drop
  • also the dragged item should now always be the selected item
@jenkins4xbmc
Collaborator

Is this PR ment to be tested by jenkins?

@Fice

probably not that useful right now. someone first needs to add GUIDragAndDropManager.h/cpp to the project files (i only did the xcode changes)

@Fice

Just rebased, and I removed the exemplary "Throw away: Button example" commit as this should not hit mainline

@Fice

Sry for the absence, but temperatures where too high and motivation too low... I should be back on track now.

@jmarshallnz mentioned three issues:
a) Reordering of the if statements for performance reasons... DONE
b) Decoupling of GUIControls from DragAndDropManager... DONE, they now communicate via messages

@MartijnKaijser

@Fice can you rebase?

@Fice

Done

@MartijnKaijser

jenkins build this please
code comments @jmarshallnz ?

@MartijnKaijser

@Fice this fails to build on all platforms.

@Fice

2 reasons:
a) only updated the xcode project before... Now all project files should be up-to-date
b) I made my most favorite git mistake again: forgot git add xbmc/guilib/GUIDragAndDropManager.h xbmc/guilib/GUIDragAndDropManager.cpp duh

just compiled on osx again, and it worked here. So let's ask jenkins again?

@Memphiz
Owner

jenkins build this please

@MartijnKaijser

failed

@Fice

malformed xml in the vc project: (hopefully) FIXED... Dont have VS, so I can only hope it's correct now
wrong uppercase letter in an #include: FIXED

@MartijnKaijser

jenkins build this please

addons/skin.confluence/720p/Pointer.xml
@@ -23,14 +23,28 @@
<height>32</height>
<texture>pointer-focus.png</texture>
</control>
- <control type="image" id="3">
- <description>Pointer Drag Image</description>
- <posx>0</posx>
- <posy>0</posy>
- <width>32</width>
- <height>32</height>
- <texture>pointer-focus-drag.png</texture>
- </control>
+ <control type="group" id="3">
@MartijnKaijser Owner

these should be tabs and not spaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
xbmc/guilib/GUIDragAndDropManager.h
@@ -0,0 +1,87 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://www.xbmc.org
@MartijnKaijser Owner

Copyright (C) 2013 Team XBMC
http://xbmc.org

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
xbmc/guilib/GUIDragAndDropManager.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2005-2013 Team XBMC
+ * http://www.xbmc.org
@MartijnKaijser Owner

Copyright (C) 2013 Team XBMC
http://xbmc.org

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Fice

Added an extra commit that changes all tabs to spaces in Pointer.xml.
Copyright notice updated as well

@Montellese
Owner

skin XML files use tabs not spaces because it reduces the size of the files which makes the loading faster. So in case you changed all tabs to spaces you should have changed all spaces to tabs. There should already be tabs everywhere except maybe where you changed something yourself.

@MartijnKaijser

i fixed all files in confluence this weekend so there shouldn't be any spaces left

@Fice

I only knew about the "1 tab = 2 spaces" convention in the code, so I figured that's what Martijn meant... I have removed the last commit again and changed the spaces to tabs in the original skin change.

@jmarshallnz
Owner

By the looks some squashing is in order. Squash any fixups into the original commit.

@Fice

squashed everything (except the skin change) into the first commit, as they were all fixes.

@MartijnKaijser

@Fice
seems you will need to do another rebase

@jmarshallnz
all good for you to pull it in this window?

@Fice

rebased

@Fice
  • Comments are fixed and some minor cosmetics (even found another notifie ;))
  • made defines for m_state == 1/2/3.... I haven't looked to closely enough into the MouseEvent code to know if m_state always means the same for all the different MouseEvents.
@Fice

ACK to the rest

@Fice

Pushed:

  • all the minors are done.
  • DragAndDropManager doesn't know what the current drop target is, or what the element is, where dragging started. Instead the Controls listen to the DRAG_HOVER and DRAG_STOP events and deal with them...
@Montellese Montellese was assigned
@jmarshallnz jmarshallnz was assigned
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
10 XBMC.xcodeproj/project.pbxproj
@@ -28,6 +28,9 @@
0E3036EC1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */; };
0E3036ED1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */; };
0E3036EE1760F68A00D93596 /* FavouritesDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */; };
+ 0E831D28176645EF00886828 /* GUIDragAndDropManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E831D26176645EF00886828 /* GUIDragAndDropManager.cpp */; };
+ 0E831D29176645EF00886828 /* GUIDragAndDropManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E831D26176645EF00886828 /* GUIDragAndDropManager.cpp */; };
+ 0E831D2A176645EF00886828 /* GUIDragAndDropManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0E831D26176645EF00886828 /* GUIDragAndDropManager.cpp */; };
183FDF8A11AF0B0500B81E9C /* PluginSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 183FDF8811AF0B0500B81E9C /* PluginSource.cpp */; };
18404DA61396C31B00863BBA /* SlingboxLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 18404DA51396C31B00863BBA /* SlingboxLib.a */; };
1840B74D13993D8A007C848B /* JSONVariantParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1840B74B13993D8A007C848B /* JSONVariantParser.cpp */; };
@@ -3174,6 +3177,8 @@
0E30286C1759FCC200D93596 /* SettingsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsManager.h; sourceTree = "<group>"; };
0E3036EA1760F68A00D93596 /* FavouritesDirectory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FavouritesDirectory.cpp; sourceTree = "<group>"; };
0E3036EB1760F68A00D93596 /* FavouritesDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FavouritesDirectory.h; sourceTree = "<group>"; };
+ 0E831D26176645EF00886828 /* GUIDragAndDropManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIDragAndDropManager.cpp; sourceTree = "<group>"; };
+ 0E831D27176645EF00886828 /* GUIDragAndDropManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIDragAndDropManager.h; sourceTree = "<group>"; };
18308CB41303370800AA309E /* stat_utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stat_utf8.h; sourceTree = "<group>"; };
18308CB51303370800AA309E /* stdio_utf8.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stdio_utf8.h; sourceTree = "<group>"; };
183FDF8811AF0B0500B81E9C /* PluginSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PluginSource.cpp; sourceTree = "<group>"; };
@@ -5773,6 +5778,8 @@
18B7C70C1294222D009E7A26 /* GUIControlProfiler.h */,
18B7C7671294222E009E7A26 /* GUIDialog.cpp */,
18B7C70D1294222D009E7A26 /* GUIDialog.h */,
+ 0E831D26176645EF00886828 /* GUIDragAndDropManager.cpp */,
+ 0E831D27176645EF00886828 /* GUIDragAndDropManager.h */,
18B7C7681294222E009E7A26 /* GUIEditControl.cpp */,
18B7C70E1294222D009E7A26 /* GUIEditControl.h */,
18B7C7691294222E009E7A26 /* GUIFadeLabelControl.cpp */,
@@ -10594,6 +10601,7 @@
F59EED7E17AD5174005BB7C6 /* ApplicationPlayer.cpp in Sources */,
DF29668017B2B04300DF10F9 /* SettingRequirement.cpp in Sources */,
DF28DF4D17B8379E0077F41A /* ProfilesOperations.cpp in Sources */,
+ 0E831D28176645EF00886828 /* GUIDragAndDropManager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -11621,6 +11629,7 @@
F59EED8017AD5174005BB7C6 /* ApplicationPlayer.cpp in Sources */,
DF29668217B2B04300DF10F9 /* SettingRequirement.cpp in Sources */,
DF28DF4F17B8379E0077F41A /* ProfilesOperations.cpp in Sources */,
+ 0E831D2A176645EF00886828 /* GUIDragAndDropManager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -12650,6 +12659,7 @@
F59EED7F17AD5174005BB7C6 /* ApplicationPlayer.cpp in Sources */,
DF29668117B2B04300DF10F9 /* SettingRequirement.cpp in Sources */,
DF28DF4E17B8379E0077F41A /* ProfilesOperations.cpp in Sources */,
+ 0E831D29176645EF00886828 /* GUIDragAndDropManager.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
30 addons/skin.confluence/720p/Pointer.xml
@@ -23,14 +23,28 @@
<height>32</height>
<texture>pointer-focus.png</texture>
</control>
- <control type="image" id="3">
- <description>Pointer Drag Image</description>
- <posx>0</posx>
- <posy>0</posy>
- <width>32</width>
- <height>32</height>
- <texture>pointer-focus-drag.png</texture>
- </control>
+ <control type="group" id="3">
+ <control type="image">
+ <description>Pointer Drag Image</description>
+ <posx>0</posx>
+ <posy>0</posy>
+ <width>32</width>
+ <height>32</height>
+ <texture>pointer-focus-drag.png</texture>
+ </control>
+ <control type="image">
+ <visible>!isempty(listitem.icon)</visible>
+ <posx>20</posx>
+ <posy>20</posy>
+ <width>64</width>
+ <height>64</height>
+ <aspectratio align="center">keep</aspectratio>
+ <fadetime>IconCrossfadeTime</fadetime>
+ <texture>$INFO[listitem.icon]</texture>
+ <bordertexture border="8">ThumbShadow.png</bordertexture>
+ <bordersize>8</bordersize>
+ </control>
+ </control>
<control type="image" id="4">
<description>Pointer Click Image</description>
<posx>0</posx>
View
2  project/VS2010Express/XBMC.vcxproj
@@ -621,6 +621,7 @@
<ClCompile Include="..\..\xbmc\guilib\GUIControlGroupList.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIControlProfiler.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIDialog.cpp" />
+ <ClCompile Include="..\..\xbmc\guilib\GUIDragAndDropManager.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIEditControl.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFadeLabelControl.cpp" />
<ClCompile Include="..\..\xbmc\guilib\GUIFixedListContainer.cpp" />
@@ -2138,6 +2139,7 @@
<ClInclude Include="..\..\xbmc\guilib\GUIControlGroupList.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIControlProfiler.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIDialog.h" />
+ <ClInclude Include="..\..\xbmc\guilib\GUIDragAndDropManager.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIEditControl.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFadeLabelControl.h" />
<ClInclude Include="..\..\xbmc\guilib\GUIFixedListContainer.h" />
View
6 project/VS2010Express/XBMC.vcxproj.filters
@@ -828,6 +828,9 @@
<ClCompile Include="..\..\xbmc\guilib\GUIDialog.cpp">
<Filter>guilib</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\guilib\GUIDragAndDropManager.cpp">
+ <Filter>guilib</Filter>
+ </ClCompile>
<ClCompile Include="..\..\xbmc\MediaSource.cpp" />
<ClCompile Include="..\..\xbmc\MediaSource.cpp" />
<ClCompile Include="..\..\xbmc\MediaSource.cpp" />
@@ -3735,6 +3738,9 @@
<ClInclude Include="..\..\xbmc\guilib\GUIDialog.h">
<Filter>guilib</Filter>
</ClInclude>
+ <ClCompile Include="..\..\xbmc\guilib\GUIDragAndDropManager.h">
+ <Filter>guilib</Filter>
+ </ClCompile>
<ClInclude Include="..\..\xbmc\music\karaoke\cdgdata.h">
<Filter>music\karaoke</Filter>
</ClInclude>
View
3  xbmc/Application.cpp
@@ -347,6 +347,8 @@
#include "utils/Environment.h"
#endif
+#include "guilib/GUIDragAndDropManager.h"
+
using namespace std;
using namespace ADDON;
using namespace XFILE;
@@ -1860,6 +1862,7 @@ void CApplication::LoadSkin(const SkinPtr& skin)
g_windowManager.AddMsgTarget(&g_infoManager);
g_windowManager.AddMsgTarget(&g_fontManager);
g_windowManager.AddMsgTarget(&CStereoscopicsManager::Get());
+ g_windowManager.AddMsgTarget(&g_dragAndDropManager);
g_windowManager.SetCallback(*this);
g_windowManager.Initialize();
CTextureCache::Get().Initialize();
View
38 xbmc/guilib/GUIBaseContainer.cpp
@@ -60,6 +60,7 @@ CGUIBaseContainer::CGUIBaseContainer(int parentID, int controlID, float posX, fl
m_cacheItems = preloadItems;
m_scrollItemsPerFrame = 0.0f;
m_type = VIEW_TYPE_NONE;
+ m_bDragStart = false;
}
CGUIBaseContainer::~CGUIBaseContainer(void)
@@ -447,6 +448,9 @@ bool CGUIBaseContainer::OnMessage(CGUIMessage& message)
return true;
}
}
+ if (message.GetMessage() == GUI_MSG_NOTIFY_ALL && message.GetParam1() == GUI_DND_STOP && m_bDragStart)
+ DragStop();
+
return CGUIControl::OnMessage(message);
}
@@ -648,7 +652,8 @@ CGUIListItemLayout *CGUIBaseContainer::GetFocusedLayout() const
bool CGUIBaseContainer::OnMouseOver(const CPoint &point)
{
// select the item under the pointer
- SelectItemFromPoint(point - CPoint(m_posX, m_posY));
+ if (!m_bDragStart) //only if we are not where the dragging started
+ SelectItemFromPoint(point - CPoint(m_posX, m_posY));
return CGUIControl::OnMouseOver(point);
}
@@ -709,9 +714,33 @@ EVENT_RESULT CGUIBaseContainer::OnMouseEvent(const CPoint &point, const CMouseEv
ScrollToOffset(toOffset);
return EVENT_RESULT_HANDLED;
}
+ else if (event.m_id == ACTION_MOUSE_DRAG)
+ {
+ if (event.m_state == MOUSE_EVENT_START && HitTest(point))
+ {
+ int selected = GetItemPositionFromPoint(point - CPoint(GetXPosition(), GetYPosition()));
+ if (selected >= 0 && selected < (int)m_items.size())
+ {
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetParentID(), 0, GUI_DND_ITEM_START, 0, m_items[selected]);
+ g_windowManager.SendMessage(msg);
+ m_bDragStart = true;
+ }
+
+ return EVENT_RESULT_HANDLED;
+ }
+ }
return EVENT_RESULT_UNHANDLED;
}
+void CGUIBaseContainer::DragStop()
+{
+ m_bDragStart = false;
+}
+
+void CGUIBaseContainer::DraggedAway()
+{
+}
+
bool CGUIBaseContainer::OnClick(int actionID)
{
int subItem = 0;
@@ -1227,13 +1256,20 @@ void CGUIBaseContainer::GetCacheOffsets(int &cacheBefore, int &cacheAfter)
void CGUIBaseContainer::SetCursor(int cursor)
{
+ if (m_bDragStart)
+ return;
m_cursor = cursor;
}
void CGUIBaseContainer::SetOffset(int offset)
{
if (m_offset != offset)
+ {
MarkDirtyRegion();
+ if (m_bDragStart)
+ //We want to keep the dragged item selected, so adjust the cursor
+ m_cursor = (m_cursor + m_offset) - offset;
+ }
m_offset = offset;
}
View
10 xbmc/guilib/GUIBaseContainer.h
@@ -84,6 +84,9 @@ class CGUIBaseContainer : public IGUIContainer
\param offset CPoint holding the offset in skin coordinates.
*/
void SetRenderOffset(const CPoint &offset);
+
+ virtual void DraggedAway();
+ virtual void DragStop();
#ifdef _DEBUG
virtual void DumpTextureUse();
@@ -188,6 +191,11 @@ class CGUIBaseContainer : public IGUIContainer
\sa GetItemOffset
*/
inline int GetOffset() const { return m_offset; };
+ /*! \brief Returns the array index of the item being hovered
+ \param point - current mouse position
+ \return the position in the list of the hovered item
+ */
+ virtual int GetItemPositionFromPoint(const CPoint& point) { return GetCursorFromPoint(point) + GetItemOffset(); }
/*! \brief Returns the index of the first visible item
returns the first visible item. This will always be in the range of available items. Use GetOffset() to retrieve the first visible row in the list.
\sa GetOffset
@@ -201,6 +209,8 @@ class CGUIBaseContainer : public IGUIContainer
CStopWatch m_scrollTimer;
CStopWatch m_lastScrollStartTimer;
CStopWatch m_pageChangeTimer;
+
+ bool m_bDragStart; //true if the user is currently dragging and it started on this item
// letter match searching
CStopWatch m_matchTimer;
View
2  xbmc/guilib/GUIButtonControl.cpp
@@ -272,7 +272,7 @@ EVENT_RESULT CGUIButtonControl::OnMouseEvent(const CPoint &point, const CMouseEv
OnAction(CAction(ACTION_SELECT_ITEM));
return EVENT_RESULT_HANDLED;
}
- return EVENT_RESULT_UNHANDLED;
+ return CGUIControl::OnMouseEvent(point, event);
}
CStdString CGUIButtonControl::GetDescription() const
View
78 xbmc/guilib/GUIControl.cpp
@@ -360,6 +360,13 @@ bool CGUIControl::OnMessage(CGUIMessage& message)
return true;
}
}
+ if (message.GetMessage() == GUI_MSG_NOTIFY_ALL)
+ {
+ if (message.GetParam1() == GUI_DND_HOVER && message.GetPointer()!=this && m_dropTarget)
+ DraggedAway();
+ else if (message.GetParam1() == GUI_DND_STOP && m_dropTarget)
+ DragStop();
+ }
return false;
}
@@ -473,11 +480,22 @@ void CGUIControl::SetNavigationActions(const CGUIAction &up, const CGUIAction &d
const CGUIAction &left, const CGUIAction &right,
const CGUIAction &back, bool replace)
{
- if (!m_actionLeft.HasAnyActions() || replace) m_actionLeft = left;
- if (!m_actionRight.HasAnyActions() || replace) m_actionRight = right;
- if (!m_actionUp.HasAnyActions() || replace) m_actionUp = up;
- if (!m_actionDown.HasAnyActions() || replace) m_actionDown = down;
- if (!m_actionBack.HasAnyActions() || replace) m_actionBack = back;
+ if (!m_actionLeft.HasAnyActions() || replace)
+ m_actionLeft = left;
+ if (!m_actionRight.HasAnyActions() || replace)
+ m_actionRight = right;
+ if (!m_actionUp.HasAnyActions() || replace)
+ m_actionUp = up;
+ if (!m_actionDown.HasAnyActions() || replace)
+ m_actionDown = down;
+ if (!m_actionBack.HasAnyActions() || replace)
+ m_actionBack = back;
+}
+
+void CGUIControl::SetDropAction(const CGUIAction& drop, bool replace)
+{
+ if (!m_actionDrop.HasAnyActions() || replace)
+ m_actionDrop = drop;
}
void CGUIControl::SetNavigationAction(int direction, const CGUIAction &action, bool replace /*= true*/)
@@ -580,6 +598,50 @@ EVENT_RESULT CGUIControl::SendMouseEvent(const CPoint &point, const CMouseEvent
return (handled && (event.m_id == ACTION_MOUSE_MOVE)) ? EVENT_RESULT_HANDLED : EVENT_RESULT_UNHANDLED;
}
+EVENT_RESULT CGUIControl::OnMouseEvent(const CPoint &point, const CMouseEvent &event)
+{
+ if (event.m_id == ACTION_MOUSE_DRAG)
+ {
+ if (!IsVisible() || !event.m_dndInfo || !HitTest(point) || !IsDropable())
+ return EVENT_RESULT_UNHANDLED;
+
+ if (event.m_state == MOUSE_EVENT_IN_PROGRESS)
+ {
+ //Set us as drop target
+ if (!m_dropTarget)
+ {
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetParentID(), 0, GUI_DND_HOVER);
+ msg.SetPointer(this);
+ g_windowManager.SendMessage(msg);
+ m_dropTarget = true;
+ }
+ return EVENT_RESULT_HANDLED;
+ }
+ if (event.m_state == MOUSE_EVENT_STOP)
+ {
+ m_actionDrop.ExecuteActions(GetID(), GetParentID());
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetParentID(), 0, GUI_DND_STOP);
+ g_windowManager.SendMessage(msg);
+ DragStop();
+ return EVENT_RESULT_HANDLED;
+ }
+ }
+
+ return EVENT_RESULT_UNHANDLED;
+};
+
+void CGUIControl::DraggedAway()
+{
+ CGUIMessage msg(GUI_MSG_LOSTFOCUS, GetParentID(), GetID());
+ OnMessage(msg);
+ m_dropTarget = false;
+}
+
+void CGUIControl::DragStop()
+{
+ m_dropTarget = false;
+}
+
// override this function to implement custom mouse behaviour
bool CGUIControl::OnMouseOver(const CPoint &point)
{
@@ -946,6 +1008,12 @@ void CGUIControl::SaveStates(vector<CControlState> &states)
// empty for now - do nothing with the majority of controls
}
+
+bool CGUIControl::IsDropable() const
+{
+ return m_actionDrop.HasActionsMeetingCondition();
+}
+
void CGUIControl::SetHitRect(const CRect &rect)
{
m_hitRect = rect;
View
18 xbmc/guilib/GUIControl.h
@@ -129,7 +129,7 @@ class CGUIControl
\return EVENT_RESULT corresponding to whether the control handles this event
\sa SendMouseEvent, HitTest, CanFocusFromPoint, CMouseEvent
*/
- virtual EVENT_RESULT OnMouseEvent(const CPoint &point, const CMouseEvent &event) { return EVENT_RESULT_UNHANDLED; };
+ virtual EVENT_RESULT OnMouseEvent(const CPoint &point, const CMouseEvent &event);
/*! \brief Unfocus the control if the given point on screen is not within it's boundary
\param point the location in transformed skin coordinates from the upper left corner of the parent control.
@@ -196,6 +196,7 @@ class CGUIControl
const CGUIAction &left, const CGUIAction &right,
const CGUIAction &back, bool replace = true);
void SetNavigationAction(int direction, const CGUIAction &action, bool replace = true);
+ void SetDropAction(const CGUIAction& drop, bool replace = true);
int GetControlIdUp() const { return m_actionUp.GetNavigation(); };
int GetControlIdDown() const { return m_actionDown.GetNavigation(); };
int GetControlIdLeft() const { return m_actionLeft.GetNavigation(); };
@@ -240,6 +241,18 @@ class CGUIControl
void SetParentControl(CGUIControl *control) { m_parentControl = control; };
CGUIControl *GetParentControl(void) const { return m_parentControl; };
virtual void SaveStates(std::vector<CControlState> &states);
+
+ /*! \brief responsible for deciding if the currently dragged intem can be dropped on this control
+ \result true, if the item can be dropped here */
+ virtual bool IsDropable() const;
+ /*! \brief Automatically called when this item has previously been hovered during drag&drop but not anymore
+ */
+ virtual void DraggedAway();
+ /*! Called when dragging stopped. This function will be called on the CGUIControl* where the dragging started,
+ as well as on the item where the user dropped.
+ */
+ virtual void DragStop();
+
enum GUICONTROLTYPES {
GUICONTROL_UNKNOWN,
@@ -321,6 +334,7 @@ class CGUIControl
CGUIAction m_actionBack;
CGUIAction m_actionNext;
CGUIAction m_actionPrev;
+ CGUIAction m_actionDrop;
float m_posX;
float m_posY;
@@ -360,6 +374,8 @@ class CGUIControl
bool m_controlIsDirty;
CRect m_renderRegion; // In screen coordinates
+
+ bool m_dropTarget; //If true, we are currently the target of a drag&drop operation
};
#endif
View
4 xbmc/guilib/GUIControlFactory.cpp
@@ -581,7 +581,7 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
float width = 0, height = 0;
float minHeight = 0, minWidth = 0;
- CGUIAction leftActions, rightActions, upActions, downActions, backActions, nextActions, prevActions;
+ CGUIAction leftActions, rightActions, upActions, downActions, backActions, nextActions, prevActions, dropActions;
int pageControl = 0;
CGUIInfoColor colorDiffuse(0xFFFFFFFF);
@@ -777,6 +777,7 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
GetActions(pControlNode, "onunfocus", unfocusActions);
focusActions.m_sendThreadMessages = unfocusActions.m_sendThreadMessages = true;
GetActions(pControlNode, "altclick", altclickActions);
+ GetActions(pControlNode, "ondrop", dropActions);
CStdString infoString;
if (XMLUtils::GetString(pControlNode, "info", infoString))
@@ -1334,6 +1335,7 @@ CGUIControl* CGUIControlFactory::Create(int parentID, const CRect &rect, TiXmlEl
control->SetAnimations(animations);
control->SetColorDiffuse(colorDiffuse);
control->SetNavigationActions(upActions, downActions, leftActions, rightActions, backActions);
+ control->SetDropAction(dropActions);
control->SetPulseOnSelect(bPulse);
if (hasCamera)
control->SetCamera(camera);
View
68 xbmc/guilib/GUIDragAndDropManager.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "GUIDragAndDropManager.h"
+#include "input/MouseStat.h"
+#include "FileItem.h"
+#include "utils/Variant.h"
+
+
+void CGUIDragAndDropManager::DraggingStart(CGUIListItemPtr draggedFileItem, int windowID)
+{
+ DraggingStop();
+ m_dndInfo = boost::shared_ptr<DragAndDropInfo>(new DragAndDropInfo());
+ m_dndInfo->m_dragStartWindowID = windowID;
+ m_dndInfo->m_draggedFileItem = draggedFileItem;
+ g_Mouse.SetState(MOUSE_STATE_DRAG);
+ if (m_dndInfo->m_draggedFileItem)
+ m_dndInfo->m_draggedFileItem->SetProperty(ITEM_IS_DRAGGED_FLAG, true);
+}
+
+void CGUIDragAndDropManager::DraggingStop()
+{
+ if (m_dndInfo)
+ {
+ if (m_dndInfo->m_draggedFileItem)
+ m_dndInfo->m_draggedFileItem->ClearProperty(ITEM_IS_DRAGGED_FLAG);
+
+ m_dndInfo = boost::shared_ptr<DragAndDropInfo>();
+ }
+ g_Mouse.SetState(MOUSE_STATE_NORMAL);
+}
+
+bool CGUIDragAndDropManager::OnMessage(CGUIMessage& message)
+{
+ if (message.GetMessage() != GUI_MSG_NOTIFY_ALL)
+ return false;
+
+ if (message.GetParam1() == GUI_DND_ITEM_START)
+ {
+ DraggingStart(message.GetItem(), message.GetSenderId());
+ return true;
+ }
+ if (message.GetParam1() == GUI_DND_STOP)
+ {
+ DraggingStop();
+ return true;
+ }
+ return false;
+}
+
+CGUIDragAndDropManager g_dragAndDropManager;
View
49 xbmc/guilib/GUIDragAndDropManager.h
@@ -0,0 +1,49 @@
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+#include "GUIListItem.h"
+#include "GUIMessage.h"
+#include "Key.h"
+#include "IMsgTargetCallback.h"
+#include "boost/shared_ptr.hpp"
+
+class CGUIControl;
+
+
+
+class CGUIDragAndDropManager : public IMsgTargetCallback
+{
+public:
+ CGUIDragAndDropManager() {}
+ ~CGUIDragAndDropManager() {}
+ virtual bool OnMessage(CGUIMessage& message);
+ /*! \brief Returns all the stored drag and drop Info
+ \sa DragAndDropInfo
+ */
+ inline boost::shared_ptr<DragAndDropInfo> GetMessageInfo() { return m_dndInfo; }
+
+protected:
+ void DraggingStart(CGUIListItemPtr draggedFileItem, int windowID);
+ void DraggingStop();
+
+ boost::shared_ptr<DragAndDropInfo> m_dndInfo;
+};
+
+extern CGUIDragAndDropManager g_dragAndDropManager;
View
2  xbmc/guilib/GUIListItem.h
@@ -33,6 +33,8 @@
#include <map>
#include <string>
+#define ITEM_IS_DRAGGED_FLAG "isdragged"
+
// Forward
class CGUIListItemLayout;
class CArchive;
View
7 xbmc/guilib/GUIMessage.h
@@ -133,6 +133,13 @@
#define GUI_MSG_WINDOW_LOAD 43
+/*
+ Drag&Drop Messages
+ */
+#define GUI_DND_HOVER 44 //Used to notify that a new GUIElement is now the drag&drop target
+#define GUI_DND_ITEM_START 45
+#define GUI_DND_STOP 46
+
#define GUI_MSG_USER 1000
/*!
View
4 xbmc/guilib/GUIMoverControl.cpp
@@ -147,12 +147,12 @@ EVENT_RESULT CGUIMoverControl::OnMouseEvent(const CPoint &point, const CMouseEve
{
if (event.m_id == ACTION_MOUSE_DRAG)
{
- if (event.m_state == 1)
+ if (event.m_state == MOUSE_EVENT_START)
{ // grab exclusive access
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
SendWindowMessage(msg);
}
- else if (event.m_state == 3)
+ else if (event.m_state == MOUSE_EVENT_STOP)
{ // release exclusive access
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
SendWindowMessage(msg);
View
4 xbmc/guilib/GUIResizeControl.cpp
@@ -135,12 +135,12 @@ EVENT_RESULT CGUIResizeControl::OnMouseEvent(const CPoint &point, const CMouseEv
{
if (event.m_id == ACTION_MOUSE_DRAG)
{
- if (event.m_state == 1)
+ if (event.m_state == MOUSE_EVENT_START)
{ // grab exclusive access
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
SendWindowMessage(msg);
}
- else if (event.m_state == 3)
+ else if (event.m_state == MOUSE_EVENT_STOP)
{ // release exclusive access
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
SendWindowMessage(msg);
View
4 xbmc/guilib/GUIScrollBarControl.cpp
@@ -306,12 +306,12 @@ EVENT_RESULT CGUIScrollBar::OnMouseEvent(const CPoint &point, const CMouseEvent
{
if (event.m_id == ACTION_MOUSE_DRAG)
{
- if (event.m_state == 1)
+ if (event.m_state == MOUSE_EVENT_START)
{ // we want exclusive access
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
SendWindowMessage(msg);
}
- else if (event.m_state == 3)
+ else if (event.m_state == MOUSE_EVENT_STOP)
{ // we're done with exclusive access
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
SendWindowMessage(msg);
View
4 xbmc/guilib/GUISliderControl.cpp
@@ -530,13 +530,13 @@ EVENT_RESULT CGUISliderControl::OnMouseEvent(const CPoint &point, const CMouseEv
{
m_dragging = true;
bool guessSelector = false;
- if (event.m_state == 1)
+ if (event.m_state == MOUSE_EVENT_START)
{ // grab exclusive access
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, GetID(), GetParentID());
SendWindowMessage(msg);
guessSelector = true;
}
- else if (event.m_state == 3)
+ else if (event.m_state == MOUSE_EVENT_STOP)
{ // release exclusive access
m_dragging = false;
CGUIMessage msg(GUI_MSG_EXCLUSIVE_MOUSE, 0, GetParentID());
View
2  xbmc/guilib/GUIVideoControl.cpp
@@ -93,7 +93,7 @@ EVENT_RESULT CGUIVideoControl::OnMouseEvent(const CPoint &point, const CMouseEve
g_windowManager.ActivateWindow(WINDOW_VIDEO_PLAYLIST);
return EVENT_RESULT_HANDLED;
}
- return EVENT_RESULT_UNHANDLED;
+ return CGUIControl::OnMouseEvent(point, event);;
}
bool CGUIVideoControl::CanFocus() const
View
24 xbmc/guilib/GUIWindow.cpp
@@ -29,6 +29,7 @@
#ifdef PRE_SKIN_VERSION_9_10_COMPATIBILITY
#include "GUIEditControl.h"
#endif
+#include "GUIDragAndDropManager.h"
#include "addons/Skin.h"
#include "GUIInfoManager.h"
@@ -451,7 +452,7 @@ EVENT_RESULT CGUIWindow::OnMouseAction(const CAction &action)
g_graphicsContext.InvertFinalCoords(mousePoint.x, mousePoint.y);
// create the mouse event
- CMouseEvent event(action.GetID(), action.GetHoldTime(), action.GetAmount(2), action.GetAmount(3));
+ CMouseEvent event(action.GetID(), action.GetHoldTime(), action.GetAmount(2), action.GetAmount(3), g_dragAndDropManager.GetMessageInfo());
if (m_exclusiveMouseControl)
{
CGUIControl *child = (CGUIControl *)GetControl(m_exclusiveMouseControl);
@@ -473,6 +474,27 @@ EVENT_RESULT CGUIWindow::OnMouseEvent(const CPoint &point, const CMouseEvent &ev
{ // no control found to absorb this click - go to previous menu
return OnAction(CAction(ACTION_PREVIOUS_MENU)) ? EVENT_RESULT_HANDLED : EVENT_RESULT_UNHANDLED;
}
+ if (event.m_id == ACTION_MOUSE_DRAG)
+ { // if no one feels responsible for the drag events,
+ // we should notify the info handler and the current hovered element about that
+ if (event.m_state == MOUSE_EVENT_IN_PROGRESS)
+ {
+ if (event.m_dndInfo != NULL && !m_dropTarget) // We no longer have a drop target
+ {
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetParentID(), 0, GUI_DND_HOVER);
+ // We notify that no one is the drag target right now, via a NULL pointer in msg
+ g_windowManager.SendMessage(msg);
+ m_dropTarget = true;
+ }
+ return EVENT_RESULT_HANDLED;
+ }
+ if (event.m_state == MOUSE_EVENT_STOP)
+ {
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL, GetParentID(), 0, GUI_DND_STOP);
+ g_windowManager.SendMessage(msg);
+ return EVENT_RESULT_HANDLED;
+ }
+ }
return EVENT_RESULT_UNHANDLED;
}
View
19 xbmc/guilib/Key.h
@@ -29,6 +29,7 @@
*/
#include "utils/StdString.h"
+#include <boost/shared_ptr.hpp>
// Reserved 0 - 255
// XBIRRemote.h
@@ -365,6 +366,10 @@
#define ICON_TYPE_WEATHER 107
#define ICON_TYPE_SETTINGS 109
+#define MOUSE_EVENT_START 1
+#define MOUSE_EVENT_IN_PROGRESS 2
+#define MOUSE_EVENT_STOP 3
+
class CKey;
/*!
@@ -435,6 +440,16 @@ class CAction
wchar_t m_unicode;
};
+ //forwards for DragAndDropInfo
+class CGUIControl;
+class CGUIListItem; typedef boost::shared_ptr<CGUIListItem> CGUIListItemPtr;
+
+struct DragAndDropInfo
+{
+ int m_dragStartWindowID;
+ CGUIListItemPtr m_draggedFileItem;
+};
+
/*!
\ingroup actionkeys, mouse
\brief Simple class for mouse events
@@ -442,7 +457,8 @@ class CAction
class CMouseEvent
{
public:
- CMouseEvent(int actionID, int state = 0, float offsetX = 0, float offsetY = 0)
+ CMouseEvent(int actionID, int state = 0, float offsetX = 0, float offsetY = 0, boost::shared_ptr<DragAndDropInfo> dndInfo = boost::shared_ptr<DragAndDropInfo>())
+ : m_dndInfo(dndInfo)
{
m_id = actionID;
m_state = state;
@@ -454,6 +470,7 @@ class CMouseEvent
int m_state;
float m_offsetX;
float m_offsetY;
+ boost::shared_ptr<DragAndDropInfo> m_dndInfo;
};
/*!
View
1  xbmc/guilib/Makefile.in
@@ -19,6 +19,7 @@ SRCS += GUIControlGroup.cpp
SRCS += GUIControlGroupList.cpp
SRCS += GUIControlProfiler.cpp
SRCS += GUIDialog.cpp
+SRCS += GUIDragAndDropManager.cpp
SRCS += GUIEditControl.cpp
SRCS += GUIFadeLabelControl.cpp
SRCS += GUIFixedListContainer.cpp
View
11 xbmc/input/MouseStat.cpp
@@ -23,6 +23,7 @@
#include "settings/Setting.h"
#include "utils/TimeUtils.h"
#include "windowing/WindowingFactory.h"
+#include "guilib/GUIDragAndDropManager.h"
CMouseStat::CMouseStat()
{
@@ -191,6 +192,10 @@ void CMouseStat::SetResolution(int maxX, int maxY, float speedX, float speedY)
void CMouseStat::SetActive(bool active /*=true*/)
{
m_lastActiveTime = CTimeUtils::GetFrameTime();
+
+ if (!active && m_pointerState == MOUSE_STATE_DRAG)
+ return; //keep the mouse visible, because we're dragging (even if told otherwise)
+
m_mouseState.active = active;
// we show the OS mouse if:
// 1. The mouse is active (it has been moved) AND
@@ -200,9 +205,13 @@ void CMouseStat::SetActive(bool active /*=true*/)
}
// IsActive - returns true if we have been active in the last MOUSE_ACTIVE_LENGTH period
+// it will always return true while dragging
bool CMouseStat::IsActive()
{
- if (m_mouseState.active && (CTimeUtils::GetFrameTime() - m_lastActiveTime > MOUSE_ACTIVE_LENGTH))
+
+ if (m_mouseState.active &&
+ (CTimeUtils::GetFrameTime() - m_lastActiveTime > MOUSE_ACTIVE_LENGTH) &&
+ !(m_pointerState == MOUSE_STATE_DRAG))
SetActive(false);
return (m_mouseState.active && IsEnabled());
}
Something went wrong with that request. Please try again.