public override void FreezeChanged(ITab <UIntPtr> nodes) { #if DEBUG MaxListener.PrintToListener("NodeEventCallback > FreezeChanged"); #endif RefreshNodes(nodes); }
public override void DisplayPropertiesChanged(ITab <UIntPtr> nodes) { #if DEBUG MaxListener.PrintToListener("NodeEventCallback > DisplayPropertiesChanged"); #endif RefreshNodes(nodes); }
private void onFilePreSave(Object sender, SystemNotificationObjectEventArgs e) { #if DEBUG MaxListener.PrintToListener("onFilePreSave"); #endif MaxIO.SaveData(ListView, NodeControl); }
private void onSystemPreReset(Object sender, SystemNotificationObjectEventArgs e) { #if DEBUG MaxListener.PrintToListener("onSystemPreReset"); #endif NodeControl.Destroy.ClearSceneTree(); }
public void UnregisterNotification() { GlobalInterface.Instance.UnRegisterNotification(EventProc, null); #if DEBUG MaxListener.PrintToListener(NotificationCode.ToString() + " Notification Unregistered"); #endif }
public override void Deleted(ITab <UIntPtr> nodes) { #if DEBUG MaxListener.PrintToListener("NodeEventCallback > Deleted"); #endif List <BaseTreeNode> deletedNodes = new List <BaseTreeNode>(); for (int i = 0; i < nodes.Count; i++) { UIntPtr nodeHandle = nodes[(IntPtr)i]; List <BaseTreeNode> baseTreeNodes = NodeControl.HandleMap.GetTreeNodesByHandle(nodeHandle); foreach (BaseTreeNode baseTreeNode in baseTreeNodes) { if (baseTreeNode != null) { deletedNodes.Add(baseTreeNode); } } } try { ListView.BeginUpdate(); NodeControl.Destroy.DeleteTreeNodes(deletedNodes); } catch { throw new Exception(); } finally { ListView.EndUpdate(); } }
public void Save(Object sender, FormClosingEventArgs e) { try { // Ensure directory exists. Directory.CreateDirectory(Path.GetDirectoryName(XmlPath)); // Write XML file. new XDocument( new XElement("NestedLayerManager", new XElement("Size", new XElement("Height", MaxForm.Height), new XElement("Width", MaxForm.Width) ), new XElement("Location", new XElement("X", MaxForm.Location.X), new XElement("Y", MaxForm.Location.Y) ) ) ) .Save(XmlPath); } catch { MaxListener.PrintToListener("ERROR: Unable to save XML file"); } }
/// <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 }
public static IAnimatable GetAnimByHandle(UIntPtr handle) { IAnimatable anim = GlobalInterface.Instance.Animatable.GetAnimByHandle(handle); #if DEBUG if (anim == null) { MaxListener.PrintToListener("ERROR: GetAnimByHandle anim is null"); } #endif return(anim); }
public List <BaseTreeNode> GetTreeNodesByHandle(UIntPtr handle) { List <BaseTreeNode> treeNodes = TreeNodeByHandle[handle] as List <BaseTreeNode>; if (treeNodes == null) { treeNodes = new List <BaseTreeNode>(); #if DEBUG MaxListener.PrintToListener("WARNING: GetTreeNodeByHandle returned null"); #endif } return(treeNodes); }
public void Unregister() { if (!IsCallbackRegistered) { return; } GlobalInterface.Instance.ISceneEventManager.UnRegisterCallback(CallbackKey); IsCallbackRegistered = false; #if DEBUG MaxListener.PrintToListener("NodeEventCallback Unregistered"); #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(); } }
private void onLayerCreated(Object sender, SystemNotificationAnimEventArgs e) { #if DEBUG MaxListener.PrintToListener("onLayerCreated"); #endif List <LayerTreeNode> createdNodes = new List <LayerTreeNode>(); foreach (UIntPtr handle in e.Handles) { // TODO: Add handlemap ref to this class. // LayerTreeNode newNode = NodeControl.Create.CreateTreeNode(NlmTreeNode.NodeClass.Layer, handle); LayerTreeNode newNode = new LayerTreeNode(handle, NodeControl.HandleMap); createdNodes.Add(newNode); } ListView.AddObjects(createdNodes); ListView.Sort(ListView.NlmColumns.NameColumn, SortOrder.Ascending); }
private void onLayerDeleted(Object sender, SystemNotificationAnimEventArgs e) { #if DEBUG MaxListener.PrintToListener("onLayerDeleted"); #endif List <BaseTreeNode> deletedNodes = new List <BaseTreeNode>(); foreach (UIntPtr handle in e.Handles) { List <BaseTreeNode> treeNodes = NodeControl.HandleMap.GetTreeNodesByHandle(handle); foreach (BaseTreeNode treeNode in treeNodes) { deletedNodes.Add(treeNode); } } NodeControl.Destroy.DeleteTreeNodes(deletedNodes); }
public void Register() { if (IsCallbackRegistered) { return; } GlobalInterface.Instance.ISceneEventManager.RegisterCallback(this, false, 0, false); CallbackKey = GlobalInterface.Instance.ISceneEventManager.GetKeyByCallback(this); IsCallbackRegistered = true; #if DEBUG MaxListener.PrintToListener("NodeEventCallback Registered"); #endif }
public override void LayerChanged(ITab <UIntPtr> nodes) { #if DEBUG MaxListener.PrintToListener("NodeEventCallback > LayerChanged"); #endif List <BaseTreeNode> deleteNodes = new List <BaseTreeNode>(); List <Tuple <BaseTreeNode, BaseTreeNode> > addNodes = new List <Tuple <BaseTreeNode, BaseTreeNode> >(); for (int i = 0; i < nodes.Count; i++) { UIntPtr maxNodeHandle = nodes[(IntPtr)i]; IINode maxNode = MaxAnimatable.GetAnimByHandle(maxNodeHandle) as IINode; IILayer maxLayer = MaxLayers.GetLayer(maxNode); UIntPtr layerHandle = MaxAnimatable.GetHandleByAnim(maxLayer); // We need to handle the following scenarios: // An object being moved to another layer. // Objects on instances layers moving to uninstanced layers. // Objects on uninstanced layers moving to instanced layers. // The easiest way to do this is to remove old object nodes and create new ones. // This should be pretty fast, and this event should fire relatively rarely, // but it may have to be rethought if it's too slow. // First we remove the old nodes. List <BaseTreeNode> objectTreeNodes = NodeControl.HandleMap.GetTreeNodesByHandle(maxNodeHandle); deleteNodes.AddRange(objectTreeNodes); // Then we add the object node to the new layer. List <BaseTreeNode> layerTreeNodes = NodeControl.HandleMap.GetTreeNodesByHandle(layerHandle); foreach (BaseTreeNode layerTreeNode in layerTreeNodes) { ObjectTreeNode newObjectTreeNode = new ObjectTreeNode(MaxNodes.GetObjectClass(maxNode), maxNodeHandle, NodeControl.HandleMap); addNodes.Add(new Tuple <BaseTreeNode, BaseTreeNode> (newObjectTreeNode, layerTreeNode)); } } // And finally we actually do the update all at once. NodeControl.Destroy.DeleteTreeNodes(deleteNodes); foreach (Tuple <BaseTreeNode, BaseTreeNode> tuple in addNodes) { NodeControl.Parent.AddChild(tuple.Item1, tuple.Item2, false); } // And sort :) ListView.Sort(ListView.NlmColumns.NameColumn, SortOrder.Ascending); }
public NestedLayerManager() { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); ListView = new NlmTreeListView(); SearchBar = new NlmSearchBar(ListView); ButtonPanelLeft = new NlmButtonPanelLeft(ListView); ButtonPanelRight = new NlmButtonPanelRight(ListView); ButtonPanelSide = new NlmButtonPanelSide(ListView); MaxLook.ApplyLook(this); ColumnCount = 3; RowCount = 3; Padding = new Padding(3); Dock = DockStyle.Fill; Controls.Add(ButtonPanelLeft, 1, 0); SetColumnSpan(ButtonPanelLeft, 1); Controls.Add(ButtonPanelRight, 2, 0); Controls.Add(SearchBar, 1, 1); SetColumnSpan(SearchBar, 2); Controls.Add(ButtonPanelSide, 0, 2); Controls.Add(ListView, 1, 2); SetColumnSpan(ListView, 2); RowStyles.Add(new RowStyle(SizeType.Absolute, ButtonPanelLeft.Controls[0].Height + 2)); RowStyles.Add(new RowStyle(SizeType.Absolute, SearchBar.Height + 2)); RowStyles.Add(new RowStyle(SizeType.AutoSize)); ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, ButtonPanelSide.Controls[0].Width + 2)); ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, ButtonPanelLeft.Controls.Count * ButtonPanelLeft.Controls[0].Width)); ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, ButtonPanelRight.Controls.Count * ButtonPanelRight.Controls[0].Width)); ListView.NodeControl.Create.BuildSceneTree(); stopwatch.Stop(); string listenerMessage = "Loaded in " + stopwatch.ElapsedMilliseconds + " milliseconds."; MaxListener.PrintToListener(listenerMessage); }
private void onSystemPostReset(Object sender, SystemNotificationObjectEventArgs e) { #if DEBUG MaxListener.PrintToListener("onSystemPostReset"); #endif try { ListView.BeginUpdate(); NodeControl.Create.BuildSceneTree(); } catch { throw new Exception(); } finally { ListView.EndUpdate(); } }
public void Load() { try { if (File.Exists(XmlPath)) { XDocument xml = XDocument.Load(XmlPath); XElement root = xml.Root; XElement size = root.Element("Size"); if (size != null) { XElement width = size.Element("Width"); XElement height = size.Element("Height"); if (width != null && height != null) { MaxForm.Size = new Size(Convert.ToInt32(width.Value), Convert.ToInt32(height.Value)); } } XElement location = root.Element("Location"); if (location != null) { XElement x = location.Element("X"); XElement y = location.Element("Y"); if (x != null && y != null) { // Setting location does nothing before the form is shown. // And setting location after the form is shown looks like crap. // Thankfully, setting these two properties works :) MaxForm.StartPosition = FormStartPosition.Manual; MaxForm.Left = Convert.ToInt32(x.Value); MaxForm.Top = Convert.ToInt32(y.Value); } } } } catch { MaxListener.PrintToListener("ERROR: Unable to read XML file"); } }
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(); } }
/// <summary> /// Deletes the selected treenodes, including associated max nodes. /// All children of selection are also deleted. /// Max nodes will not be deleted if not all instanced nodes are selected. /// If every layer 0 instance is selected, nothing will happen. /// </summary> public void DeleteSelection() { #if DEBUG System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); #endif ListView.NodeControl.MaxEvents.NodeEvents.Unregister(); ListView.NodeControl.MaxEvents.LayerEvents.LayerDeleted.UnregisterNotification(); // Don't do anything if every single layer 0 is selected. IILayer layer0 = MaxLayers.GetLayer(0); UIntPtr layer0handle = MaxAnimatable.GetHandleByAnim(layer0); List <BaseTreeNode> layerTreeNodes = HandleMap.GetTreeNodesByHandle(layer0handle); if (layerTreeNodes.All(x => NodeQuery.SelectionAndAllChildNodes.Contains(x))) { return; } // Collect the selection IEnumerables to use. HashSet <BaseTreeNode> selectionAndAllChildren = new HashSet <BaseTreeNode> (NodeQuery.SelectionAndAllChildNodes); // Calculate layer and object handles. IEnumerable <UIntPtr> objectHandles = selectionAndAllChildren.Where (x => x is ObjectTreeNode).Cast <ObjectTreeNode>().Select(x => x.Handle); IEnumerable <UIntPtr> layerHandles = selectionAndAllChildren.Where (x => x is LayerTreeNode).Cast <LayerTreeNode>().Select(x => x.Handle); // Delete handles from max. foreach (UIntPtr handle in objectHandles) { List <BaseTreeNode> instances = HandleMap.GetTreeNodesByHandle(handle); if (instances.Count() > 1) { if (!instances.All(x => selectionAndAllChildren.Contains(x))) { continue; } } MaxNodes.DeleteNode(handle); } foreach (UIntPtr handle in layerHandles) { List <BaseTreeNode> instances = HandleMap.GetTreeNodesByHandle(handle); if (instances.Count() > 1) { if (!instances.All(x => selectionAndAllChildren.Contains(x))) { continue; } } MaxLayers.DeleteLayer(handle); } // And now to delete the tree nodes now there are no max nodes. DeleteTreeNodes(selectionAndAllChildren); // The default behaviour of the listview is to maintain selection based on item index. // This is not very desirable, as the selection should be nothing. ListView.SelectedObjects = new Object[] {}; ListView.NodeControl.MaxEvents.LayerEvents.LayerDeleted.RegisterNotification(); ListView.NodeControl.MaxEvents.NodeEvents.Register(); #if DEBUG stopwatch.Stop(); MaxListener.PrintToListener("DeleteSelection completed in: " + stopwatch.ElapsedMilliseconds); #endif }