Back our Kickstarter Campaign going on Now
  1. #1
    Minty23185Fresh's Avatar
    Join Date
    Dec 2015
    Location
    NV, USA
    Posts
    616
    Blog Entries
    29

    On-Demand (pseudo) dragdata Object

    [Revision posted March 30, 2019, see post 4 for details]

    As I've developed a couple of my extensions there have been times when I wanted a dragdata object when there was no drag and drop operation being performed. I asked and was told by Moon Wizard that there is no way to instantiate my own dragdata object, see this thread. But I can now.

    Initially, I contemplated using a lua table for my pseudo dragdata object embedding both functions and variables in a single table. But self referencing seemed to be an issued: a function in one element of the table accessing a variable in another element. Though I didn't fully explore this, it seems problematic to me. The functions and variables could actually reside in lua script outside the table, but this might present a scope issue. Instead I decided to wrap my pseudo dragdata object in a genericcontrol. Scripting within the control allows local variables and exposed functions.

    Installation
    I have provided my dragdata "object: in a .zip file. Grab the contents of the file, a DDC folder, and drop them into your extension folder at the root level (where your extension.xml file is), as shown here in this screenshot:
    Untitled1.png

    Next add a reference to the pseudo dragdata control's template in your extension.xml file as shown here:
    Code:
       </properties>
    
       <announcement text="My Cool Extension does cool stuff" font="emotefont" />
    
       <base>
          <includefile source="DDC/common/DDC_template_dragdata.xml" />
    In the next post I discuss the reasons why this project might be of interest and utility to the developer.
    In post three I present a short description of the project used to develop and test the pseudo dragdata object.
    And I reserved post four for caveats and enhancements, as they arise.
    Attached Files Attached Files
    Last edited by Minty23185Fresh; March 30th, 2019 at 19:02. Reason: code revisions
    Current Projects:
    5E Druid Wild Shapes Implementor (Extension)
    Local Dice Tower (Extension)
    Community Contributions:
    Catalog of Forum Threads Related to PDF conversion to FG Module
    Field Filters for All Libraries (Extension)
    "A Neophyte Tackles the FG Extension" - A tutorial blog series.

  2. #2
    Minty23185Fresh's Avatar
    Join Date
    Dec 2015
    Location
    NV, USA
    Posts
    616
    Blog Entries
    29

    Understanding When One Might Use This Control

    To the best of my understanding, here is what happens during a drag-drop operation.

    The user grabs an “object” which triggers an event in the system (either FG or OS, I am unsure). The system creates a dragdata object and triggers the onDragStart event handler. The developer has access to the dragdata object through that handler in order to populate it. The user continues to drag the object to the desired destination and then drops it. This triggers the onDrop event handler, another function the developer has access to which provides a means to process the data that the onDragStart function provided via the dragdata object.

    In a project that I am working on, that I'll present as the test case in the following post, I am working in the onDoubleClick() event handler. The user does not drag anything, they click-click. So no dragdata object is created and passed in by system. I don’t have the object and according to Moon Wizard there is no facility to create one. So I wrote a pseudo dragdata object that completely mirrors the dragdata object created by system. Now I can instantiate one and work with it in code where I previously could not. Since it behaves like a dragdata object the obvious destination for the pseudo dragdata object is an onDrop handler. My process starts in an event that doesn’t usually have a dragdata object but ends up where one is required.

    At the risk of being overly redundant, the developer cannot use ruleset code to create a dragdata object. But by using the code provided in this thread they now can create an object that behaves just like the system instantiated dragdata object.

    So why would I want to do something so silly? In the case that I’ve provided there are two paths to the same result. A drag-drop path and a double-click path. All I will do is create my pseudo drag-drop object in the double-click path, populate it then throw it at the onDrop processor. The reason I did this was because it seemed to me that if I had a dragdata object in the double-click path and I sent it down the drag-drop pathway I could accomplish the same desired result with much less ruleset code analyzation and modification.
    Last edited by Minty23185Fresh; March 22nd, 2019 at 00:13. Reason: reorganization

  3. #3
    Minty23185Fresh's Avatar
    Join Date
    Dec 2015
    Location
    NV, USA
    Posts
    616
    Blog Entries
    29

    Development/Test Project and Best Practices

    As mentioned in the previous post to this thread the necessity for an on-demand dragdata object came about from a extension I am working on: the Local Dice Tower Extension (LDTE). Please note though, the current version v0.0.4, does not yet contain the pseudo dragdata object presented here. I have to add other details to LDTE, such as DM options. But the dragdata object has been tested for success.

    LDTE places a mini dice tower on the player's character sheet so that they can drag skill rolls, saving throws, etc. to a local dice tower instead of having to shift windows around to expose the main dice tower on the Fantasy Grounds desktop. A tiny bit of added functionality simply for convenience.

    The dice rolls can be effected in either of two ways, by dragging and dropping or by double clicking. Drag and drop (to the local dice tower) is currently supported but I wanted a way for the DM to enforce dice tower employment for the double click option. When looking at the code in an attempt to effect this, it became readily apparent to me that if I just had the dragdata object that is available in the drag-drop path, things would be easier for me to redirect the double-click path. Having that object available to me in the double-click path would prevent having to work through ruleset code to find where I needed override it to route the throw into the dice tower.

    Here is a small snippet of code from the number_charskilltotal template (~line 566) in the rulesets/5E/campaign/template_char.xml file:
    Code:
        function onDragStart(button, x, y, draginfo)
            return action(draginfo);
        end
    
        function onDoubleClick(x,y)
            return action();
        end
    </script>
    The two paths vary by only two things: the dragdata object "draginfo" and the destination of the data. The drag-drop path uses a dragdata object to carry information to the destination either the chat or the dice tower. The double-click path uses function parameters to carry information to the eventual destination, the chat window. The action function shown above provides a conduit for both pathways, which it collects details about the pc, the skill roll and the dice that need to be thrown. In the drag-drop path it puts that data in the provided draginfo object, in the double-click path it carries the information via function parameter to the eventual destination.

    I have modified the double-click pathway. It now provides my dragdata object to the action() function for data population (just as is done for drag-drop). When the populated object is returned the modified onDoubleClick() function sends the data to the dice tower's on Drop event handler. The two functions now do the same thing. Take a dragdata, get it populated and send it to the desired destination (dice tower) the drag-drop needs the user to physically take the dragdata object to the destination while the double-click programmatically send the object. In the following code snippet I provide my modified onDoubleClick functionality.
    Code:
        function onDoubleClick(x,y)
            local draginfo = window.createControl("DDC_dragdata_control", "DDE_dragdata");
            local bReturn = action(draginfo);
            DiceTowerManager.onDrop(draginfo);
            draginfo.destroy();
            return bReturn;
        end
    </script>
    Best (and only, at the moment) practices:
    In the first line I instantiate my dragdata object. I that to be done at window level, not at the control level (where this code is).
    I save the return value of the actioni() call so that it can be returned to the caller to prevent or encourage system handling of onDoubleClick().
    Recall, from above, if action() has a dragdata object supplied to it, it populates the object and returns it (via the parameter reference).
    In the third line, I send my drag data object to the destination (the equivalent of the user manually dragging to the destination.
    In line four I destroy the object. Other wise more and more objects are constructed and added to the form (as genericcontrols) everytime the user double-clicks.
    And finally return the results to the caller.

    Pretty simple!

    If you have questions please ask. Thanks for your time.
    Last edited by Minty23185Fresh; March 22nd, 2019 at 00:45.

  4. #4
    Minty23185Fresh's Avatar
    Join Date
    Dec 2015
    Location
    NV, USA
    Posts
    616
    Blog Entries
    29

    Revisions and Caveats

    Revisions
    Mar 30, 2019 - version 2 - shortcut and getDatabaseNode fixes
    Mar 21, 2019 - version 1 - original post

    Caveats
    Token Handling:
    As of March 30, 2019 I believe the token fields probably need some work. Looking through the rulesets, setTokenData() seems to be effectively handled but getTokenData() for the builtin dragdata object returns two fields instead of a single string. At the moment I don't know how the builtin dragdata object derives the two fields (prototype and instance) from a single string input field. If I ever need the pseudo dragdata for token handling I'll figure it out then (unless someone provides the information to me before that ).
    Icon Handling:
    As of March 30, 2019 I believe the icon field is not properly handled either. The genericcontrol wrapper for the pseudo dragdata object has a setIcon() function which I suspect will override the pseudo dragdata's setIcon() function (similar to the getDatabaseNode() problem discussed in post #7, below). But this may actually be a moot issue. The entire intent of the pseudo dragdata object is to provide a dragdata object in an "environment" where there is no drag and drop operation (e.g. for a click handler or a keypress handler). In which case a display icon, while dragging, is moot.
    Last edited by Minty23185Fresh; March 30th, 2019 at 19:49.

  5. #5

    Join Date
    Apr 2008
    Location
    Virginia Beach
    Posts
    2,807
    Great work again, Minty! I am certain I will eventually need this (if I can ever find time to get back to FG).

  6. #6
    Minty23185Fresh's Avatar
    Join Date
    Dec 2015
    Location
    NV, USA
    Posts
    616
    Blog Entries
    29
    Thanks Bidmaron. Hopefully someone besides me will find it useful. If not, it was a lot of fun to try to accomplish it.
    Current Projects:
    5E Druid Wild Shapes Implementor (Extension)
    Local Dice Tower (Extension)
    Community Contributions:
    Catalog of Forum Threads Related to PDF conversion to FG Module
    Field Filters for All Libraries (Extension)
    "A Neophyte Tackles the FG Extension" - A tutorial blog series.

  7. #7
    Minty23185Fresh's Avatar
    Join Date
    Dec 2015
    Location
    NV, USA
    Posts
    616
    Blog Entries
    29

    Revision Notes for Version 2

    I had need of the pseudo dragdata object in my Druid Wild Shapes extension - again in a click handler, and again utilizing the ruleset onDragStart() and onDrop() handlers to provide all the functionality I needed in the click handler. (Without having to unnecessarily duplicate a bunch of code).

    In this instance, I had to utilize the shortcut fields of dragdata and noticed small initialization and getShortList() differences between my pseudo dragdata object and the builtin dragdata object. These have been rectified in version 2.

    While exploring the differences that I found with shortcut data, I also noticed some strangeness with get and set database node. The issue turned out to be genericcontrol's context, windowinstance. Recall from post one, the pseudo dragdata object is "wrapped" in a genericcontrol. The context for genericcontrol is windowinstance and windowinstance has a getDatabaseNode() function. The getDatabaseNode() function for the pseudo dragdata object did not override the windowinstance getDatabaseNode() function, so the pseudo dragdata's function never executed. Function substitution/renaming in onInit() remedies this problem and has been added to version 2.
    Current Projects:
    5E Druid Wild Shapes Implementor (Extension)
    Local Dice Tower (Extension)
    Community Contributions:
    Catalog of Forum Threads Related to PDF conversion to FG Module
    Field Filters for All Libraries (Extension)
    "A Neophyte Tackles the FG Extension" - A tutorial blog series.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

Log in

Log in