{"action":"created","issue":{"url":"https://api.github.com/repos/SonyWWS/ATF/issues/46","labels_url":"https://api.github.com/repos/SonyWWS/ATF/issues/46/labels{/name}","comments_url":"https://api.github.com/repos/SonyWWS/ATF/issues/46/comments","events_url":"https://api.github.com/repos/SonyWWS/ATF/issues/46/events","html_url":"https://github.com/SonyWWS/ATF/pull/46","id":116629166,"number":46,"title":"TreeControl user re-ordering support","user":{"login":"Ron2","id":2474161,"avatar_url":"https://avatars.githubusercontent.com/u/2474161?v=3","gravatar_id":"","url":"https://api.github.com/users/Ron2","html_url":"https://github.com/Ron2","followers_url":"https://api.github.com/users/Ron2/followers","following_url":"https://api.github.com/users/Ron2/following{/other_user}","gists_url":"https://api.github.com/users/Ron2/gists{/gist_id}","starred_url":"https://api.github.com/users/Ron2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ron2/subscriptions","organizations_url":"https://api.github.com/users/Ron2/orgs","repos_url":"https://api.github.com/users/Ron2/repos","events_url":"https://api.github.com/users/Ron2/events{/privacy}","received_events_url":"https://api.github.com/users/Ron2/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-11-12T20:04:19Z","updated_at":"2015-11-12T20:47:19Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/SonyWWS/ATF/pulls/46","html_url":"https://github.com/SonyWWS/ATF/pull/46","diff_url":"https://github.com/SonyWWS/ATF/pull/46.diff","patch_url":"https://github.com/SonyWWS/ATF/pull/46.patch"},"body":"If a TreeControl’s ShowDragBetweenCue is set to true, and if the\ncontext can be adapted to the new interface, IOrderedInsertionContext,\nthen the user will be allowed to re-order nodes by dragging. Also,\nobjects can be dragged into a specific location within a tree, like\nwhen dragging from the palette."},"comment":{"url":"https://api.github.com/repos/SonyWWS/ATF/issues/comments/156229238","html_url":"https://github.com/SonyWWS/ATF/pull/46#issuecomment-156229238","issue_url":"https://api.github.com/repos/SonyWWS/ATF/issues/46","id":156229238,"user":{"login":"Ron2","id":2474161,"avatar_url":"https://avatars.githubusercontent.com/u/2474161?v=3","gravatar_id":"","url":"https://api.github.com/users/Ron2","html_url":"https://github.com/Ron2","followers_url":"https://api.github.com/users/Ron2/followers","following_url":"https://api.github.com/users/Ron2/following{/other_user}","gists_url":"https://api.github.com/users/Ron2/gists{/gist_id}","starred_url":"https://api.github.com/users/Ron2/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Ron2/subscriptions","organizations_url":"https://api.github.com/users/Ron2/orgs","repos_url":"https://api.github.com/users/Ron2/repos","events_url":"https://api.github.com/users/Ron2/events{/privacy}","received_events_url":"https://api.github.com/users/Ron2/received_events","type":"User","site_admin":false},"created_at":"2015-11-12T20:47:18Z","updated_at":"2015-11-12T20:47:18Z","body":"Here's the implementation of IOrderedInsertionContext that works in one version of LevelEditor:\r\n```C#\r\n#region IOrderedInsertionContext Members\r\n\r\n/// <summary>\r\n/// Returns true if 'item' can be inserted.</summary>\r\n/// <param name=\"parent\">The object that will become the parent of the inserted object.\r\n/// GameContext requires this to not be null.</param>\r\n/// <param name=\"before\">The object that is immediately before the inserted object.\r\n/// Can be null to indicate that the inserted item should become the first child.</param>\r\n/// <param name=\"item\">The item to be inserted</param>\r\n/// <returns>True iff 'item' can be successfully inserted</returns>\r\nbool IOrderedInsertionContext.CanInsert(object parent, object before, object itemDataObject)\r\n{\r\n    // We can't let the root be replaced, so we will require 'parent' to be valid.\r\n    var parentNode = parent.As<DomNode>();\r\n    if (parentNode == null)\r\n        return false;\r\n    var beforeNode = before.As<DomNode>();\r\n\r\n    // Convert from the DragEventArgs data to DomNodes.\r\n    IEnumerable<object> items = Util.ConvertData(itemDataObject, false);\r\n    var insertNodes = new List<DomNode>();\r\n    foreach (object item in items)\r\n    {\r\n        DomNode insertNode = item as DomNode;\r\n        if (insertNode != null)\r\n            insertNodes.Add(insertNode);\r\n    }\r\n    if (insertNodes.Count == 0)\r\n        return false;\r\n\r\n    // If the user has selected multiple nodes and some of those nodes are children of other\r\n    //  selected nodes, remove the children from our list. This preserves the hierarchy. This\r\n    //  behavior is like the Mac OS X Finder, for example.\r\n    insertNodes = new List<DomNode>(DomNode.GetRoots(insertNodes));\r\n\r\n    // Find a compatible ChildInfo (from the parent) for each inserted DomNode.\r\n    // The order of the ChildInfos determines the order that the Project Lister displays items.\r\n    // This code assumes that TreeControl gives us the nodes to insert in the same order that\r\n    //  they're being displayed (and not in the order that the user happened to do the multi-\r\n    //  select.)\r\n    // So, we can step through the ChildInfos and 'insertNodes', from beginning to end.\r\n    var childInfos = new List<ChildInfo>(insertNodes.Count);\r\n    {\r\n        bool foundFirst = false; // Find the first ChildInfo that matches 'beforeNode'.\r\n        int i = 0;\r\n        foreach (ChildInfo info in parentNode.Type.Children)\r\n        {\r\n            if (!foundFirst)\r\n            {\r\n                if (beforeNode == null)\r\n                    foundFirst = true;\r\n                else if (info.Type.IsAssignableFrom(beforeNode.Type))\r\n                    foundFirst = true;\r\n                else\r\n                    continue;\r\n            }\r\n            while (info.Type.IsAssignableFrom(insertNodes[i].Type))\r\n            {\r\n                childInfos.Add(info);\r\n                i++;\r\n                if (i == insertNodes.Count)\r\n                    break;\r\n            }\r\n            if (i == insertNodes.Count)\r\n                break;\r\n        }\r\n        if (childInfos.Count != insertNodes.Count)\r\n            return false;\r\n    }\r\n\r\n    // Do a sanity check on the DomNode hierarchy.\r\n    for(int i = 0; i < insertNodes.Count; i++)\r\n    {\r\n        DomNode insertNode = insertNodes[i];\r\n        ChildInfo childInfo = childInfos[i];\r\n\r\n        // We can only currently insert into a list.\r\n        if (!childInfo.IsList)\r\n            return false;\r\n\r\n        // Avoid useless inserts.\r\n        if (parentNode == insertNode || beforeNode == insertNode)\r\n            return false;\r\n\r\n        // We can't insert a node into itself or a descendant of itself.\r\n        if (parentNode.IsDescendantOf(insertNode))\r\n            return false;\r\n                    \r\n        // Make sure that itemNode is compatible with the parent's ChildInfo.\r\n        if (!childInfo.Type.IsAssignableFrom(insertNode.Type))\r\n            return false;\r\n    }\r\n    return true;\r\n}\r\n\r\n/// <summary>\r\n/// Inserts 'item' into the set of objects at the desired position. Will only be called\r\n/// if CanInsert() returns true.</summary>\r\n/// <param name=\"parent\">The object that will become the parent of the inserted object.</param>\r\n/// <param name=\"before\">The object that is immediately before the inserted object.\r\n/// Can be null to indicate that the inserted item should become the first child.</param>\r\n/// <param name=\"item\">The item to be inserted.</param>\r\nvoid IOrderedInsertionContext.Insert(object parent, object before, object itemDataObject)\r\n{\r\n    var parentNode = parent.Cast<DomNode>();\r\n    var beforeNode = before.As<DomNode>();\r\n\r\n    // Convert to DomNodes.\r\n    IEnumerable<object> items = Util.ConvertData(itemDataObject, false);\r\n    var insertNodes = new List<DomNode>();\r\n    foreach (object item in items)\r\n    {\r\n        DomNode insertNode = item as DomNode;\r\n        if (insertNode != null)\r\n            insertNodes.Add(insertNode);\r\n    }\r\n\r\n    // If the user has selected multiple nodes and some of those nodes are children of other\r\n    //  selected nodes, remove the children from our list. This preserves the hierarchy. This\r\n    //  behavior is like the Mac OS X Finder, for example.\r\n    insertNodes = new List<DomNode>(DomNode.GetRoots(insertNodes));\r\n\r\n    // Remove the DomNodes from their parents before calculating the insertion index.\r\n    foreach (DomNode insertNode in insertNodes)\r\n        insertNode.RemoveFromParent();\r\n\r\n    // Find a compatible ChildInfo (from the parent) for each inserted DomNode.\r\n    // The order of the ChildInfos determines the order that the Project Lister displays items,\r\n    //  so we need to step through the ChildInfos and match inserted DomNodes at the same time.\r\n    var childInfos = new List<ChildInfo>(insertNodes.Count);\r\n    {\r\n        bool foundFirst = false;\r\n        int i = 0;\r\n        foreach (ChildInfo info in parentNode.Type.Children)\r\n        {\r\n            if (!foundFirst)\r\n            {\r\n                if (beforeNode == null)\r\n                    foundFirst = true;\r\n                else if (info.Type.IsAssignableFrom(beforeNode.Type))\r\n                    foundFirst = true;\r\n                else\r\n                    continue;\r\n            }\r\n            while (info.Type.IsAssignableFrom(insertNodes[i].Type))\r\n            {\r\n                childInfos.Add(info);\r\n                i++;\r\n                if (i == insertNodes.Count)\r\n                    break;\r\n            }\r\n            if (i == insertNodes.Count)\r\n                break;\r\n        }\r\n    }\r\n\r\n    // Insert the previously removed DomNodes, using the correct ChildInfo.\r\n    int insertionIndex;\r\n    if (beforeNode == null)\r\n        insertionIndex = 0;\r\n    else\r\n    {\r\n        IList<DomNode> childList = parentNode.GetChildList(childInfos[0]);\r\n        insertionIndex = childList.IndexOf(beforeNode) + 1;\r\n    }\r\n    ChildInfo priorInfo = childInfos[0];\r\n    for (int i = 0; i < insertNodes.Count; i++)\r\n    {\r\n        DomNode insertNode = insertNodes[i];\r\n        ChildInfo info = childInfos[i];\r\n        if (info != priorInfo)\r\n        {\r\n            priorInfo = info;\r\n            insertionIndex = 0;\r\n        }\r\n        IList<DomNode> childList = parentNode.GetChildList(info);\r\n        childList.Insert(insertionIndex, insertNode);\r\n        insertionIndex++;\r\n    }\r\n}\r\n\r\n#endregion\r\n```"}}