View Full Version : Accept drop from multiple classes ?
phantomwhale
July 17th, 2011, 13:20
The documentation seems to imply I can do something like this :
<acceptdrop>
<class>critter</class>
<field>*</field>
</acceptdrop>
<acceptdrop>
<class>human</class>
<field>*</field>
</acceptdrop>
However, when I do this, only one of them works ? Is there a way of supporting multiple drop classes using the acceptdrop tag ?
Thanks,
Ben (-PW-)
Sorcerer
July 17th, 2011, 13:39
it should work..but I believe you need to put them all in one <acceptdrop>
<acceptdrop>
<class>critter</class>
<class>human</class>
<field>*</field>
</acceptdrop>
phantomwhale
July 17th, 2011, 14:46
How odd - that doesn't work (only critters drop, humans process through the custom script, but don't appear).
But this does work ?!?
<acceptdrop>
<class>human</class>
<class>critter</class>
<field>*</field>
</acceptdrop>
Switching the order enables both of them to drag and drop !
:confused: :confused: :confused:
Sorcerer
July 17th, 2011, 15:01
i guess it has to do with how your custom script is checking the class and then processing, because otherwise I can't think of any reason why order should matter, the class name is after all just a random tag that we have selected to label our data with.
on the other-hand, if you have a custom "onDrop" script, then as far as I know it will override the acceptdrop tag anyway - unless your script returns nil, at which time it will pass the drop back to the built-in acceptdrop handler.
I have had alot of "fun" in the past trying to get the custom script and the acceptdrop to work in tandem, but the interaction between the two is poor (or maybe its my understanding thats poor...).
phantomwhale
July 18th, 2011, 02:38
Well, the custom onDrop() script goes as follows :
local acceptedTypes = nil
local source = nil
function onInit()
acceptedTypes = acceptdrop[1].class
end
function onDrop(x, y, draginfo)
for _,acceptedType in pairs(acceptedTypes) do
if draginfo.isType(acceptedType) then
source = draginfo.getDatabaseNode()
break
elseif draginfo.isType("shortcut") then
local class = draginfo.getShortcutData()
if class == acceptedType then
source = draginfo.getDatabaseNode()
break
end
end
end
end
function getSource()
local s = source
source = nil
return s
end
So it stores an array of accepted classes, and then on getting an onDrop event, check it against each class to see if it's a drop of that type, or a shortcut type that has that class.
In any event, it stores the target database node in a temporary "source" variable, which is then consumed by the onInit() method on the created class; it calls up to getSource() to obtain it, and in doing so clears the variable. Regardless of what happens, it returns nil to allow the event to pass to the underlying windowlist handler.
More to the point, it doesn't presume any different treatment of each variable type. And equally I have tried with "if draginfo.isType("critter") or draginfo.isType("human")" clauses too - dynamically driving the if clauses from the underlying XML elements was a very late change in the piece.
Like I say, works now, so I'm not going to get too worried about it. But wanted to mark it as odd incase someone else encounters it ! Or in case I finally figure how it is actually something else I've done (which I admit is 98% likely to be the case)...
phantomwhale
July 21st, 2011, 00:25
**deleted theory - it was quite quite wrong**
Moon Wizard
July 21st, 2011, 01:05
The way that the acceptdrop tag is designed to work is as follows:
* If the class tag exists in the acceptdrop tag, then the windowlistcontrol will trigger the creation of a new list entry.
* If a new list entry is created, then each field tag under the acceptdrop tag will be copied from the dropped shortcut to the new list entry. The nodes created will have the same data type and values.
* You can use the '*' value in a field tag to indicate that all nodes of the dropped shortcut should be copied.
* You can interrupt the default behavior (even if acceptdrop defined) if you return true in the onDrop event function for the windowlistcontrol.
More advanced shortcut drops are written by intercepting the objects in the onDrop handler and writing the copy function in LUA.
Cheers,
JPG
phantomwhale
July 21st, 2011, 04:24
Thanks for the reply - from what your saying (and what I'm seeing) if you want to capture drops from TWO different classes, then the XML-tag-only approach doesn't appear to work (it's only using the first class tag value).
It seems that if you drop something of the same class as the windowlist's declared class, that also works, no matter what you've defined in the tags.
E.g. for a windowlist of "critter"s, I can drop "critter" and declare it accepts drop of "human". But if I also want to support a drop of "npc", then I can't seem to get it working with XML tags only.
I have been led to try and do it this way by https://www.fantasygrounds.com/refdoc/windowlist.xcp , which says about the <acceptdrop> tag:
Specify that a "shortcut" drag with the specified windowclass will create a new entry in the list. The definition can contain multiple instances of this element.
Moon Wizard
July 21st, 2011, 07:51
Weird, it's working for me, but perhaps your specific scenario is what is causing the issue.
I tried a few examples in the 3.5E ruleset and they worked.
I modified the windowlist for campaign NPCs:
<acceptdrop>
<class>npc</class>
<class>item</class>
<field>*</field>
</acceptdrop>
With this setup, I tried dropping both "npc" and "item" shortcuts. They both copied the entire database node when dropped on the list.
Then, I tried:
<acceptdrop>
<class>npc</class>
<class>item</class>
<field>name</field>
<field>type</field>
<field>alignment</field>
</acceptdrop>
When I dropped "npc", it copied all 3 fields. When I dropped "item", it copied only name and type, since alignment doesn't exist for item records.
One thing to note is that I do not have an onDrop event function for this windowlistcontrol.
If you do have an onDrop event function, you need to make sure that you are returning nil for the standard processing to occur. If you return true, then the program assumes that your code handled the event. If you return false, then the program assumes you want this control to skip this drop type.
Regards,
JPG
phantomwhale
July 21st, 2011, 13:13
Ok - I removed all the template stuff I'd been using, pulled out all the scripts I needed, and made a basic vanilla windowlist.
And it seems that the ORDER of the class tags is affecting which ones are permitted to be dropped, for instance:
<acceptdrop>
<class>critter</class>
<class>human</class>
<class>npc</class>
<field>*</field>
</acceptdrop>
Only allows critters to be dropped. Whereas
<acceptdrop>
<class>npc</class>
<class>human</class>
<class>critter</class>
<field>*</field>
</acceptdrop>
Allows them all to be dropped ?! :confused:
To prove I'm not mad, I've made a short video showing this in action:
https://www.livestream.com/phantomwhaletv/video?clipId=pla_ae188cf8-17b3-4c85-876a-bf599692d2af
Can anyone replicate this behaviour with existing windowlists in their ruleset ? Or has anyone got any idea's how my ruleset might be pulling off this trick ?!
Thanks,
-PW-
phantomwhale
July 21st, 2011, 14:11
Was going to bypass all the <acceptdrop> stuff and roll my own LUA code... then remembered that the only way to copy formattedtext controls is using the <acceptdrop> tags ! So I guess I've got to get to the bottom of this.
Once I started changing the field from "*" to individual values, the behaviour seemed to change again (only supporting the first class). So lost...
joshuha
July 21st, 2011, 14:49
And you are sure you don't have an onDrop event that is trying to override the acceptdrop?
Zeus
July 21st, 2011, 22:42
With reference to the formattedtextfield I think you should be able to workaround the copy of a formattedtextfield in LUA by copying the underlying bound database node.
The only real challenge with formattedtextfields is if you want to manipulate the value contents. For this, you would have to write your own custom handler in LUA for parsing and manipulating the formattedtext.
With reference to acceptdrop behaviour, I agree with joshua. Make sure your onDrop handler (if you have one) is set to return nil, so that FGII uses standard framework processing for the drop.
Otherwise if set to True, FGII assumes your LUA code will handle the drop (you need to provision for this in your onDrop handler) and if set to False, FGII will skip the default framework processing for the drop type.
Moon Wizard
July 21st, 2011, 23:16
Phantomwhale,
Both your examples in the last post were the same.
I'm thinking that it might be something to do with ordering, given your experience. However, I need an example so that I can debug the issue.
Can you get me an extension or ruleset to do it? You can send to
[email protected]
Cheers,
JPG
phantomwhale
July 21st, 2011, 23:28
If you watch the video example, the onDrop event just does a debug call - no return values. Otherwise the normal handler I use is posted a few posts back, but again, no return values. Apologies - many people kept highlighting that, and I didn't clarify.
Dr Zeuss - that was the bit of the puzzle I was missing late last night - I'd forgotten formattedtext fields could be copied via DB.copyNode (https://www.fantasygrounds.com/refdoc/DB.xcp#copyNode) - I'd, of course, been using getValue() / setValue(). Going to continue down the "roll my own" approach today and see if I can get it working.
phantomwhale
July 21st, 2011, 23:31
Phantomwhale,
Both your examples in the last post were the same.
I'm thinking that it might be something to do with ordering, given your experience. However, I need an example so that I can debug the issue.
Can you get me an extension or ruleset to do it? You can send to
[email protected]
Cheers,
JPG
*Facepalm* copy and paste error late last night - have corrected the examples. Like I say, the video shows it in action.
Will try and bundle something up today and send it over.
StuartW
July 24th, 2011, 06:20
I think the acceptDrop tag was broken a few versions ago. I posted something on it a while back (back in the day when there was no copyNode function, and you had to use acceptDrop to copy formattedtextfields), admittedly buried deep in a thread on CoC (https://www.fantasygrounds.com/forums/showpost.php?p=88755&postcount=13).
Stuart
Moon Wizard
July 25th, 2011, 06:46
I found the cause of phantomwhale's situation.
In v2.7.x, windowlistcontrol objects only support one class tag.
In v2.8, I have allowed multiple class tags to be specified, but the same field tags will be used for all specified classes. (including *, if used)
Regards,
JPG
phantomwhale
July 25th, 2011, 12:33
Well, I wrote me a fancy WindowList that allows mapping of fields to different fields, as well as call out to an "onDropCreate" method if it exists on the window object once it's been created and fully populated. The latter part gets around the window object needing to call back up to the windowlist in the onInit() method, and populate extra fields if required.
Looks a bit like this... (note that it uses a slightly different NodeManger that allows copying from one node name to a different node name)
-- Copyright SmiteWorks USA, LLC., 2010
local tAcceptedTypes = {}
function onInit()
for _,accdrp in pairs(acceptdrop) do
for _,class in pairs(accdrp.class) do
table.insert(tAcceptedTypes, {class = class, fields = accdrp.field or {}, mappedfields = validateMappings(accdrp.map)})
end
end
end
function validateMappings(map)
local tMappedFields = {}
if map then
for _,mapping in pairs(map) do
local sFrom = mapping.from and mapping.from[1]
local sTo = mapping.to and mapping.to[1]
if sFrom and sTo then
table.insert(tMappedFields, {from = sFrom, to = sTo})
end
end
end
return tMappedFields
end
function onDrop(x, y, draginfo)
local tType, nodeSource = nil
for _,acceptedType in pairs(tAcceptedTypes) do
if draginfo.isType(acceptedType.class) then
nodeSource = draginfo.getDatabaseNode()
tType = acceptedType
break
elseif draginfo.isType("shortcut") then
local class = draginfo.getShortcutData()
if class == acceptedType.class then
nodeSource = draginfo.getDatabaseNode()
tType = acceptedType
break
end
end
end
if nodeSource then
local win = createWindow()
local nodeWindow = win.getDatabaseNode()
if tType.fields == 1 and tType.fields[1] == "*" then
for _,nodeFieldSource in pairs(nodeSource.getChildren()) do
NodeManager.copy(nodeFieldSource, nodeWindow)
end
else
for _,sField in pairs(tType.fields) do
local nodeFieldSource = nodeSource.getChild(sField)
if nodeFieldSource then
NodeManager.copy(nodeFieldSource, nodeWindow)
end
end
for _,tMap in pairs(tType.mappedfields) do
local sFrom, sTo = tMap.from, tMap.to
local nodeFieldSource = nodeSource.getChild(sFrom)
if nodeFieldSource then
NodeManager.copy(nodeFieldSource, nodeWindow, sTo)
end
end
end
if win.onDropCreate then
win.onDropCreate(nodeSource)
end
end
-- prevent onDrop event going to underlying windowlist
return true
end
So I'll use that for now :) But good to know the underlying one is fixed too !
Powered by vBulletin® Version 4.2.1 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.