Share Your Code

DMC Lib - Drag and Drop

Posted by dmccuskey, Posted on September 15, 2011

GitHub URL: 
http://github.com/dmccuskey/DMC-Corona-Library

dmc_dragdrop is a module which coordinates drag and drop operations in an application. It can be used to implement things like draggable shopping carts or even a vehicle configurator (e.g., engine, weapons, tires, etc).

The module's functionality is based on that of the Adobe Flex Drag Manager, so if you've used that before, then the operation of dmc_dragdrop will be very familiar. Though the module is fully object-oriented, your implementation does not have to be in order to work with it.

Documentation

Quick Guide: http://docs.davidmccuskey.com/display/docs/Quick+Guide+-+dmc_dragdrop

Examples

Here are the current examples located on github: http://github.com/dmccuskey/DMC-Corona-Library. They are located in the folder examples/dmc_dragdrop/.

  • Basic

    This example has a single Drag Initiator and single Drop Target. A version of this example is shown below.

  • OOP

    This object-oriented example has two Drag Initiators and three Drop Targets. It uses the "format" option so the Drop Targets can determine the Drag Operations in which they're interested. The Drop Targets themselves are instances of the object-oriented drop_target.lua.

DMC Corona Library

dmc_dragdrop is the third major component in the DMC Corona Library, a library of modules for programming in Lua and Corona SDK. Like all components in the DMC Corona Library, dmc_dragdrop is built in a classical, object-oriented fashion using dmc_objects. This ensures the code is re-usable, plays nicely with others, and can be easily modified for your needs.

http://developer.anscamobile.com/code/dmc-corona-library

Cheers,
dmc

Example

Here is a simple example, based on the example Basic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
--==============================================================
-- Imports
--==============================================================
 
local DragMgr = require( "dmc_dragdrop" )
 
-- dmc_drag_drop requires dmc_objects and dmc_utils
 
 
--==============================================================
-- Setup a Drag Initiator - areas we drag FROM
--==============================================================
 
local function dragItemTouchHandler( event )
 
        local target = event.target
 
        if event.phase == "began" then
 
                -- now tell the Drag Manager about it
                DragMgr:doDrag( target, event )
        end
 
        return true
end
 
-- this is the Drag Initiator
-- ie, the location from which we start a drag
-- like in this example, it can be a simple Corona display object
--
local dragItem = display.newRect( 0, 0, 75, 75 )
dragItem:setFillColor( 90, 170, 255 )
dragItem.x = 160 ; dragItem.y = 400
 
dragItem:addEventListener( "touch", dragItemTouchHandler )
 
 
 
--==============================================================
-- Setup a Drop Target - areas we drag TO
--==============================================================
 
-- this example is not written object-orientedly.
 
 
--== Some vars for our Drop Target
 
local theScore =  0
local textScore, updateScore
 
 
 
--== Setup Our Drop Target Callbacks
 
local dragStartHandler = function( event )
 
        -- setup feedback - We're a drop target !!
        local o = event.target
        o:setStrokeColor( 255, 50, 50 )
 
        return true
end
local dragEnterHandler = function( event )
 
        -- more visual feedback - Ready to Drop !
        local o = event.target
        o:setFillColor( 170, 225, 170 )
 
        DragMgr:acceptDragDrop()
 
        return true
end
 
--[[
local dragOverHandler = function( event )
        -- this example doesn't do anything here
        return true
end
--]]
 
-- have to declare dragExitHandler ahead
-- since dragDropHandler calls it
--
local dragExitHandler
 
local dragDropHandler = function( event )
 
        -- let's keep track of number of drops on us
        theScore = theScore + 1
        updateScore()
        dragExitHandler( event )
 
        return true
end
dragExitHandler = function( event )
 
        -- undo visual feedback from dragEnter
        local o = event.target
        o:setFillColor( 90, 170, 255 )
 
        return true
end
local dragStopHandler = function( event )
 
        -- undo visual feedback from dragStart
        local o = event.target
        o:setStrokeColor( 180, 180, 180)
 
        return true
end
 
 
 
--== Create Our Drop Target
 
local dropTarget = display.newRect( 0, 0, 125, 125 )
dropTarget:setFillColor( 90, 170, 255 )
dropTarget.x = 160 ; dropTarget.y = 200
 
 
 
--== Tell the Drag Manager about it
 
DragMgr:register( dropTarget, {
        dragStart=dragStartHandler,
        dragEnter=dragEnterHandler,
        --dragOver=dragOverHandler,
        dragDrop=dragDropHandler,
        dragExit=dragExitHandler,
        dragStop=dragStopHandler,
})
 
 
--== Setup Drop Target counter
 
updateScore = function()
        local txt = tostring( theScore )
        textScore.text = txt
        textScore.x = 160 ; textScore.y = 200
end
 
textScore = display.newText( "", 160, 160, native.systemFont, 24 )
textScore:setTextColor( 0, 0, 0, 255 )
textScore:setReferencePoint( display.CenterReferencePoint )
 
updateScore()


Replies

d3mac123
User offline. Last seen 1 day 11 hours ago. Offline
Joined: 12 Feb 2010

Pretty cool stuff here. Few questions (couldn't find the answer checking the demo projects):
- Do I always need to define a drop area or objects can be dropped anywhere, if wanted?
- Related to the above question,is there a way to allow the drag object be dropped anywhere in the screen?
- Can I define boundaries for the dragging (for example maximum 200 pixels right from the original position)?
- Can I define only the drag in 1 axis (for example, object can be moved only in the Y axis)?

thanks a lot!

dmccuskey
User offline. Last seen 1 day 10 hours ago. Offline
Joined: 8 Jul 2011

hey there,

questions 1/2:
- you will always need to define a drop area, though the drop area could potentially be the entire screen, or most of it. (in fact, this was my intended use for the library).

questions 3/4:
- i would suggest to put any drag-limiting functionality (boundaries/axis) into an event listener method attached to the drag proxy - whatever you've chosen that to be (custom or default). this is because dragging happens "all of the time", where as dropping doesn't have to happen at all.

cheers !
david

thedavebaxter
User offline. Last seen 33 min 57 sec ago. Offline
Joined: 12 Jan 2012

Hi,

I want to use your drag drop in a app am trying to develop.

When I stop the drag if the object has been dropped in the destination, I need it to stay there.

Am kinda new to all this, so not sure if this is easy or hard to do.

Dave

dmccuskey
User offline. Last seen 1 day 10 hours ago. Offline
Joined: 8 Jul 2011

Hi Dave,

what you want to do isn't very difficult. i think what you need to keep in mind is that the dragged object (the proxy), isn't intended to be kept around after the drag/drop process is complete, ie, it's a "ghost" object which is nothing more than a simple representation of the "real" object (usually both visually and technically) and its sole purpose is to deliver data to the drop zone.

typically the data is stored in the proxy and is used to reference the real object which the proxy represents. an example of this data could be the ID of a product, a user name, etc. it's usually not a lot of data, perhaps a simple string or number, just as reflected by these examples. the important thing is what the drop handler does with this data.

take an example of a shopping cart - the proxy (which might look like a t-shirt) would contain the product ID of the shirt to be added to the shopping cart. once the proxy is dropped on the shopping cart drop zone, then the drop handler code looks inside of the t-shirt proxy, grabs the product ID, then could check inventory, increment the shopping cart for that product, etc. you can do anything else at this point you wish, including updating the UI.

so what *you'll* want to do inside of the drop handler is grab the proxy data, use it to create a "real" instance of the object that the proxy represents, then place *that* object over your drop area. this way the drag/drop code can still dispose of the proxy like it should and you will have another object/representation to keep around for the display.

HTH,
David

thedavebaxter
User offline. Last seen 33 min 57 sec ago. Offline
Joined: 12 Jan 2012

Cheers David.

Helps a lot.

Dave

mike.n.jacobs
User offline. Last seen 39 weeks 6 days ago. Offline
Joined: 30 Oct 2011

I really like this drag and drop library and it works well. One suggested extension is to allow objects to be unregistered from the drag manager. My game removes the objects and needed to unregister, so I created this extension:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
function dragManager:unregister(obj)
        local registered = {}
        for k,v in pairs(self._registered) do 
                if(k ~= obj) then
                        registered[k] = v
                end
        end
        self._registered = registered
        
        local onDragStart = {}
        local currentOnDragStart = self._onDragStart
        if(currentOnDragStart) then
                for _,item in ipairs(currentOnDragStart) do
                        if(item ~= nil and item ~= obj) then
                                table.insert(onDragStart, item)
                        end
                end
                self._onDragStart = onDragStart
        end
        
        local onDragStop = {}
        local currentOnDragStop = self._onDragStop
        if(currentOnDragStop) then
                for _, item in ipairs(currentOnDragStop) do
                        if(item ~= nil and item ~= obj) then
                                table.insert(onDragStop, item)
                        end
                end
                self._onDragStop = onDragStop
        end
        
end

dmccuskey
User offline. Last seen 1 day 10 hours ago. Offline
Joined: 8 Jul 2011

hi Mike,

i'm glad to know that you're finding this module useful !

and thanks so much for passing along the code to your modification. i'll integrate it into the library as soon as i get a chance.

cheers,
David

jkrassman
User offline. Last seen 1 year 12 weeks ago. Offline
Joined: 4 Aug 2011

Hey, I cant find the dmc_multitouch.lua library anywhere?

I am looking for something that can rotate stuff by multitouch..

Best regards, Joakim

dmccuskey
User offline. Last seen 1 day 10 hours ago. Offline
Joined: 8 Jul 2011

Hi Joakim,

the library is ready, i just haven't had time to post it. i'll work on getting it up on github in the next couple of days. if you would like it sooner, send me an email and i'll zip up and send my working directory for you.

cheers,
dmc

jkrassman
User offline. Last seen 1 year 12 weeks ago. Offline
Joined: 4 Aug 2011

Ahha ok, I thought it was removed for some purpose. I send you an email!

Edited: I can find your email so I put mine here : xxxx@xxxx.xx

Joakim

mike.n.jacobs
User offline. Last seen 39 weeks 6 days ago. Offline
Joined: 30 Oct 2011

What happened to the documentation site? http://docs.davidmccuskey.com/display/docs/Quick+Guide+-+dmc_dragdrop does not work anymore.

dmccuskey
User offline. Last seen 1 day 10 hours ago. Offline
Joined: 8 Jul 2011

apologies for that, my server needed a reboot. it's now up again.

for the future, i have added an automatic check to let me know if it isn't responding.

thank you for letting me know.

dmc