Page 1 of 1

Manually starting dragging on a DragContainer

Posted: Wed Oct 14, 2009 16:33
by BigG
Hey,

I'm writing an inventory system currently where I have the following problem:

Two inventory slots A and B containing two items (drag container containing a staticImage) 1 and 2

A contains 1
B contains 2

now I'm picking 1 and dragging it to B, which already contains 2. Now I'm dropping 1 into B.
What I want to achieve now is that 1 "replaces" 2, so that B contains 1 and 2 is being dragged automatically now.

I could think off two ways for that:
1) manually firing the dragStart on 2 by some nasty hacks in CEGUI
2) exchanging the icons contained by 1's and 2's DragContainers and somehow dismissing the Dropped event (which would require CEGUI hacks too and even more tricky code on my side)

both of them require some hacky modifications in CEGUI I guess, so I'd be really happy about any advice on this one :)

Greetings,
-BigG

Re: Manually starting dragging on a DragContainer

Posted: Thu Oct 15, 2009 09:14
by CrazyEddie
Hi,

I'm guessing this is with the 'sticky' mode enabled, since it makes no sense otherwise?

It's something I'd not considered actually, but I think it's a useful feature to provide. Due to the internal states that needs to be adjusted to affect such a switch, I think a new function for this purpose can be added (there's no real way of doing it currently without some kind of hack, none of which are really ideal). With the new function in place, I think I would still leave it up to the user code to detect the 'drop' and subsequently call the as yet unnamed function on any existing DragContainer to pick it up (it's more flexible when left to the user to call the function, and saves us from having a thousand 'modes' for all the various options!).

I can try and get this function in for 0.7.1, since it's just a single function to add.

CE.

Re: Manually starting dragging on a DragContainer

Posted: Thu Oct 15, 2009 13:40
by BigG
Thanks for your reply CE!
Yea, having such a function would be really cool :) I had an idea about it, how about if the CEGUI::Window::EventDragDropItemDropped event would have a specialised CEGUI::DragDropEventArgs argument that contains an additional CEGUI::DragContainer pointer to be set by the event handler, which, if set to 0, does nothing, otherwise starts a new drag event with the pointed drag container? This would require only a little amount of work and not even an additional function or anything :)

about your question whether sticky mode is enabled... well it's a tricky one. To actually drag&drop 1 to slot B, it doesn't matter whether it is enabled/being used or not. But as soon as the exchanging takes place, it has to be enabled in any case, as the user is no longer pressing any mouse button yet you need to have the container sticked to the cursor. This is because 1 has now replaced 2 in slot B (the item itself, not only the GUI part of it), so 2 is kind of 'slotless' now and MUST be put into another slot.

-BigG

Re: Manually starting dragging on a DragContainer

Posted: Fri Oct 16, 2009 12:07
by CrazyEddie
Thanks for the suggestions and such. The issue with the event args suggestion is (of course?) that the args struct is const, so you can't set the field from a normally subscribed handler ;)

I think the function is the way we'll go, and basically it will be able to be called at any time - if the container is non-sticky, nothing will happen, otherwise the item will immediately show as attached to the mouse. I'll get this added tomorrow most likely.

CE.

Re: Manually starting dragging on a DragContainer

Posted: Fri Oct 16, 2009 13:10
by BigG
CrazyEddie wrote:Thanks for the suggestions and such. The issue with the event args suggestion is (of course?) that the args struct is const, so you can't set the field from a normally subscribed handler ;)

duh, totally forgot about that xD well yea, I guess a function to manually start drag&drop would be the best way to go then. Thanks for helping me out on this and in advance for the patches :D

-BigG

Re: Manually starting dragging on a DragContainer

Posted: Sat Oct 17, 2009 10:32
by CrazyEddie
This has been added in the stable v0-7 branch as of rev 2321.

There is a new CEGUI::DragContainer::pickUp function (which takes an optional boolean argument that specifies whether to automatically switch the DragContainer to sticky mode, default is false).

I've tested it for a bit in a hacked around version of our Drag&Drop demo and it all works pretty well. With regard to the sticky mode change, in my test I had it off to start with, used the force option on the new function to force it on, then manually reset it again upon the drop notification.

Exactly how you'll use the function will depend on what you're doing currently, but I think you should be able to fathom it out fairly easily ;)

CE.

Re: Manually starting dragging on a DragContainer

Posted: Sat Oct 17, 2009 12:37
by BigG
Thanks again for your support, CE :)
Checking out the branch right now; I will post back after trying around with the new function :D

-BigG


//Edit:
OK, played around with the new function and I got to say that it works as I wanted it :D
Yet I have another question/request xD the DragContainer is always kept in a static offset to the cursor when the cursor moves. This offset is set when the dragging starts, calculated from the current DragContainer position and the current Mouse position (I think). Would it be possible to add a function like CEGUI::DragContainer::setMouseCursorOffset taking a CEGUI::UVector2 as parameter where you can specify that offset overwriting the dynamic calculation if set.The current DragContainer position would the be calculated as CursorPosition + MouseCursorOffset. That would make it possible to, for example, keep the item icon aligned to the cursor's head in my case :) Should not be a big change either :D

Thanks again
- BigG

//Edit2:
I found a small visual bug:
When calling pickUp(), the DragContainer itself stays where it is until you move the mouse, then it all works fine and it is dynamically aligned (as described above) to the mouse. But until then, it stays at its origin position, and then jumps to the cursor as soon as you move the mouse. I don't know if this is a problem in the rendering itself or in the positioning, I'll investigate on that.

Re: Manually starting dragging on a DragContainer

Posted: Sat Oct 17, 2009 19:24
by CrazyEddie
Yeah, I saw that issue too (and chose to ignore it :lol:). Should be a simple fix.

CE.

Re: Manually starting dragging on a DragContainer

Posted: Sat Oct 17, 2009 21:03
by BigG
Hey,

Still couldn't figure out the reason for that bug but I modified the DragContainer class a bit to realise my request about having the DragContainer sticked to the mouse at a fixed offset instead of taking the offset it has when dragging starts. As I do not know how to submit the changes to you, I'll try to do so in this post :D. Feel free to do whatever you want to do with this code :)

CEGUIDragContainer.h
In data, add two protected members:

Code: Select all

      //! true to always position at a fixed offset to the mouse cursor instead of taking the offset
      //  from when dragging started
      bool d_hasFixedMouseOffset;
      //! the fixed mouse offset
      UVector2 d_fixedMouseOffset;


and get/set functions for these:

Code: Select all

      /*!
      \brief
         Set the fixed mouse offset moving mode data
      \param has_offset
         - true to use a fixed offset, false to dynamically calculate it when dragging starts

      \param fixed_offset
         - UVector2 containing the fixed offset relative to the cursor's position
      */
      void setFixedMouseOffset(const bool has_offset, const UVector2& fixed_offset);

      /*!
      \brief
         Retrieve the fixed mouse offset moving mode data
      \param has_offset
         see setFixedMouseOffset
      \param fixed_offset
         see setFixedMouseOffset
      */
      void getFixedMouseOffset(bool& has_offset,UVector2& fixed_offset);


CEGUIDragContainer.cpp
code of the get/set functions:

Code: Select all

void DragContainer::setFixedMouseOffset(const bool has_offset, const UVector2& fixed_offset)
{
   d_hasFixedMouseOffset = has_offset;
   d_fixedMouseOffset = fixed_offset;
}

//----------------------------------------------------------------------------//
void DragContainer::getFixedMouseOffset(bool& has_offset, UVector2& fixed_offset)
{
   has_offset = d_hasFixedMouseOffset;
   fixed_offset = d_fixedMouseOffset;
}


and a small change in void DragContainer::doDragging(const Point& local_mouse) - replace

Code: Select all

offset -= d_dragPoint;

with

Code: Select all

offset -= (d_hasFixedMouseOffset) ? d_fixedMouseOffset : d_dragPoint;


and that's it :D usage is like:

Code: Select all

this->m_IconDragContainer->setFixedMouseOffset(true,CEGUI::UVector2(cegui_absdim(0),cegui_absdim(0)));

which will, for example, position the DragContainer always at the cursor's head :)

Maybe it's worth adding this configuration as property settable in the .layout files too (can DragContainers even be created in .layout files? :shock:)

I must say, I'm still being impressed by the flexibility of this engine :D

Greetings,
-BigG

Re: Manually starting dragging on a DragContainer

Posted: Sun Oct 18, 2009 06:54
by CrazyEddie
I missed the first edit yesterday, which is why I did not respond to it :roll:

It turns out the minor glitch is due to not re/setting the drag point when manually picking up the item. While it's possible to set that in the pickUP function ot the cursor offset used elsewhere, this could lead to issues if, for example, some user code decides to 'pick up' an item when the mouse is nowhere near the item being picked up (the item would then be floating in mid-air far from the mouse cursor). So my solution to this part of the issue will be to instead set the drag point to the centre of the DargContainer.

Following on from the above, your suggestion is then even more valuable since it allows the user to effectively customise the above positioning. I may implemented it as two functions or one function with just the offset, firstly because it makes property processing easier and secondly for consistency reasons with the rest of the API (largely the public getters all return the got value as opposed to setting output variables, so while your code as presented is perfectly reasonable, where possible (and I know we fail at times!) it's preferred to keep a consistent approach).

As you may infer from the above mention of properties, yes it's possible to have a DargContainer in a layout, indeed we take this approach in the drag and drop demo layout ;)

CE.

Re: Manually starting dragging on a DragContainer

Posted: Sun Oct 18, 2009 10:24
by BigG
Wow, didn't think about that cause for the bug :D well, about the way to implement the get/set functions, I came across one problem when only having one get/set function for only the offset: there is no way to determine whether the user actually _wants_ the fixed offset on or off. So you'd either need two functions like DragContainer::setFixedCursorOffset and DragContainer::setNoFixedCursorOffset or, similar my approach, two get/set pairs for both variables.

Anyway, I'm happy to see my work helps to improve CEGUI :)

-BigG

Re: Manually starting dragging on a DragContainer

Posted: Sun Oct 18, 2009 12:57
by CrazyEddie
You are of course correct - although I would have spotted this deliberate mistake before implementing it (honest! ;)). I'll attempt to finish this up later this afternoon.

CE.

Re: Manually starting dragging on a DragContainer

Posted: Sun Oct 18, 2009 16:56
by CrazyEddie
I have added:

functions:
void DragContainer::setFixedDragOffset(const UVector2& offset);
const UVector2& DragContainer::getFixedDragOffset() const;

void DragContainer::setUsingFixedDragOffset(bool enable);
bool DragContainer::isUsingFixedDragOffset() const;

Properties:
FixedDragOffset
UsingFixedDragOffset

I also fixed that issue with the initial position glitch, and also a small bug (not checking whether dragging is even enabled).

CE.

Re: Manually starting dragging on a DragContainer

Posted: Mon Oct 19, 2009 12:39
by BigG
Thumbs up, CE :)
Checking out newest revision now and if I find anything, I'll post back^^

-BigG

//Edit:
It's all working flawlessly as far as I tested it :D thanks again for your help, CE!