/// <summary> /// Deletes the selected treenodes, but does not delete associated max nodes. /// All children need to be provided, otherwise the child nodes will not be removed from the HandleMap. /// </summary> /// <param name="treeNodes"></param> public void DeleteTreeNodes(IEnumerable <BaseTreeNode> treeNodes) { #if DEBUG System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); #endif List <BaseTreeNode> rootNodes = new List <BaseTreeNode>(); HashSet <BaseTreeNode> refreshNodes = new HashSet <BaseTreeNode>(); // Delete nodes in NLM foreach (BaseTreeNode treeNode in treeNodes) { // Instead of removing each branch node independently, append to array. // We can then remove them all at the same time, which is way quicker. if (treeNode.Parent == null) { rootNodes.Add(treeNode); } else { treeNode.Parent.Children.Remove(treeNode); // Instead of refreshing each node independently, append to array. // We can then refresh all objects at the same time which is way quicker. if (!refreshNodes.Contains(treeNode.Parent) && !treeNodes.Any(x => treeNode.IsAncestor(x))) { refreshNodes.Add(treeNode.Parent); } treeNode.Parent = null; } // Remove anim handle / treenode link from map. // Note: // Using if (x is y) is creating a cast, which is doubling the casting. // Instead, casting once and checking for null is used. // Continue is used to avoid unnecessary casting. ObjectTreeNode objectTreeNode = treeNode as ObjectTreeNode; if (objectTreeNode != null) { HandleMap.RemoveTreeNodeFromHandle(objectTreeNode, objectTreeNode.Handle); continue; } LayerTreeNode layerTreeNode = treeNode as LayerTreeNode; if (layerTreeNode != null) { HandleMap.RemoveTreeNodeFromHandle(layerTreeNode, layerTreeNode.Handle); continue; } } // Work through the appended arrays and remove / refresh. ListView.RemoveObjects(rootNodes); ListView.RefreshObjects(refreshNodes.ToList()); #if DEBUG stopwatch.Stop(); MaxListener.PrintToListener("DeleteTreeNodes completed in: " + stopwatch.ElapsedMilliseconds); #endif }
private void onNodeCreated(object sender, SystemNotificationAnimEventArgs e) { #if DEBUG MaxListener.PrintToListener("onNodeCreated"); #endif try { ListView.BeginUpdate(); List <BaseTreeNode> refreshNodes = new List <BaseTreeNode>(); foreach (UIntPtr handle in e.Handles) { IAnimatable anim = MaxAnimatable.GetAnimByHandle(handle); if (anim == null) { return; } IINode node = anim as IINode; IILayer layer = MaxLayers.GetLayer(node); UIntPtr layerHandle = MaxAnimatable.GetHandleByAnim(layer); ObjectTreeNode.ObjectClass objectClass = MaxNodes.GetObjectClass(node); List <BaseTreeNode> layerTreeNodes = NodeControl.HandleMap.GetTreeNodesByHandle(layerHandle); foreach (BaseTreeNode layerTreeNode in layerTreeNodes) { ObjectTreeNode objectTreeNode = new ObjectTreeNode(objectClass, handle, NodeControl.HandleMap); NodeControl.Parent.AddChild(objectTreeNode, layerTreeNode, false); if (!refreshNodes.Contains(layerTreeNode)) { refreshNodes.Add(layerTreeNode); } } } MaxListener.PrintToListener(refreshNodes.Count.ToString()); ListView.RefreshObjects(refreshNodes); ListView.Sort(ListView.NlmColumns.NameColumn, SortOrder.Ascending); } catch { throw new Exception(); } finally { ListView.EndUpdate(); } }
public static void onCreateFolderAddSelection(Object sender, ClickEventArgs e) { NlmTreeListView listView = e.ListView; IEnumerable <BaseTreeNode> selection = listView.SelectedObjects.Cast <BaseTreeNode>(); onCreateFolder(sender, e); FolderTreeNode folderTreeNode = listView.SelectedObject as FolderTreeNode; if (folderTreeNode != null) { IEnumerable <BaseTreeNode> layerFolderSelection = selection .Where(x => x is LayerTreeNode || x is FolderTreeNode) .Where(x => !folderTreeNode.IsAncestor(x)); IEnumerable <BaseTreeNode> refreshNodes = layerFolderSelection .Where(x => x.Parent != null) .Select(x => x.Parent); listView.NodeControl.Parent.MoveTreeNodes(layerFolderSelection, folderTreeNode); listView.RefreshObjects(refreshNodes.ToList()); listView.RefreshObject(folderTreeNode); } }
private void onSystemPostMerge(Object sender, SystemNotificationObjectEventArgs e) { #if DEBUG MaxListener.PrintToListener("onSystemPostMerge"); #endif try { ListView.BeginUpdate(); // Collect existing layer and folder nodes. IEnumerable <FolderTreeNode> existingFolderNodes = NodeControl.Query.FolderNodes; IEnumerable <LayerTreeNode> existingLayerNodes = NodeControl.Query.LayerNodes; // Unfortunately no event is fired for nodes that are added to layers that already exist. // For this reason we need to refresh the children in every layer. NodeControl.Create.AddMissingChildObjects(existingLayerNodes); ListView.RefreshObjects(existingLayerNodes.ToList()); // After merge, get all new layers that need to be added to NLM. // Old layers are collected because no notification happens for nodes added to existing layers :/ List <IILayer> newLayers = new List <IILayer>(); foreach (IILayer layer in MaxLayers.Layers) { UIntPtr handle = MaxAnimatable.GetHandleByAnim(layer as IAnimatable); if (!NodeControl.HandleMap.ContainsHandle(handle)) { newLayers.Add(layer); } } // Check each new layer for any folder data saved on the attribute. // If any data exists, append it ot folderDataList. List <BaseTreeNode> treeNodeList = new List <BaseTreeNode>(); List <FolderData> folderDataList = new List <FolderData>(); foreach (IILayer layer in newLayers) { List <FolderData> parentFolders = MaxIO.LoadParentFolderData(layer as IAnimatable, ListView); if (parentFolders != null) { foreach (FolderData folderData in parentFolders) { if (!folderDataList.Contains(folderData)) { folderDataList.Add(folderData); } } } } // We only add new folders, so build a hashtable of already existing folder nodes. // This hashtable is passed to the Build methods, which checks before creating a new node. Hashtable folderNodeIdMap = new Hashtable(); foreach (FolderTreeNode folderNode in existingFolderNodes) { folderNodeIdMap.Add(folderNode.ID, folderNode); } // Build new folder and layer nodes, and append them to the treeNodeList. NodeControl.Create.BuildFolderNodes(treeNodeList, folderDataList, folderNodeIdMap); NodeControl.Create.BuildLayerAndObjectNodes(treeNodeList, newLayers, folderNodeIdMap); // Finally, add the new objects. ListView.AddObjects(treeNodeList); } catch { throw new Exception(); } finally { ListView.EndUpdate(); } }
public Boolean Click(OlvListViewHitTestInfo hti) { if (hti.ColumnIndex > 0) { if (hti.Column == ListView.NlmColumns.ColorColumn) { // Should the check states be changed on the selection, or on an item outside of selection. // If inside selection, suppress change in selection by returning true. // If outside selection, change the single item and return false. if (hti.Item.Selected) { NlmMaxColorPicker colorPicker = new NlmMaxColorPicker(hti, true, ListView); colorPicker.ShowModeless(); return(true); } else { NlmMaxColorPicker colorPicker = new NlmMaxColorPicker(hti, false, ListView); colorPicker.ShowModeless(); // Returning false annoyingly pushes the window to the back. // TODO: Somehow make this dialog modal, or at least parented to 3ds Max, and sort out the focus issue. return(true); } } if (hti.Column == ListView.NlmColumns.CurrentColumn) { BaseTreeNode treeNode = hti.RowObject as BaseTreeNode; if (treeNode is LayerTreeNode) { ListView.BeginUpdate(); hti.Column.PutValue(treeNode, true); ListView.EndUpdate(); } return(hti.Item.Selected); } else { Boolean htiItemSelected = hti.Item.Selected; INLMColumn column = hti.Column as INLMColumn; // Should the check states be changed on the selection, or on an item outside of selection. // If inside selection, suppress change in selection by returning true. // If outside selection, change the single item and return false. if (htiItemSelected) { column.AspectEngine.ToggleCheckStates(hti.RowObject); ListView.RefreshObjects(ListView.SelectedObjects); } else { column.AspectEngine.ToggleCheckState(hti.RowObject); ListView.RefreshObject(hti.RowObject); } MaxUI.RedrawViewportsNow(); return(htiItemSelected); } } return(false); // Returning true means selection does not change, returning false means it does. }