using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Windows.Forms; using System.Drawing; using System.Runtime.InteropServices; using Toolbox.Library.Forms; namespace Toolbox.Library { public abstract class TreeNodeCustom : TreeNode { public virtual void OnClick(TreeView treeview) { } public virtual void OnMouseLeftClick(TreeView treeview) { } public virtual void OnMouseRightClick(TreeView treeview) { } public virtual void OnDoubleMouseClick(TreeView treeview) { } public TreeNodeCustom() { } } public class TreeNodeFile : TreeNodeCustom { public bool CanDelete { set { if (value == true) { if (ContextMenuStrip == null) ContextMenuStrip = new STContextMenuStrip(); ContextMenuStrip.Items.Add(new STToolStipMenuItem("Delete", null, Delete, Keys.Control | Keys.Delete)); } } } public virtual UserControl GetEditor() { return new STUserControl() { Dock = DockStyle.Fill }; } public virtual void FillEditor(UserControl control) { } public override void OnClick(TreeView treeview) { var Editor = GetEditor(); Editor.Dock = DockStyle.Fill; var ActiveEditor = LibraryGUI.GetActiveContent(Editor.GetType()); if (ActiveEditor != null) Editor = ActiveEditor; else LibraryGUI.LoadEditor(Editor); FillEditor(Editor); } public TreeNodeFile() { } public TreeNodeFile(string text) { Text = text; } private void Delete(object sender, EventArgs args) { var editor = LibraryGUI.GetObjectEditor(); if (editor != null) { editor.ResetControls(); } } public virtual void OnAfterAdded() //After added to treeview { } } public class TreeViewCustom : TreeView { private readonly Dictionary _treeNodes = new Dictionary(); public List TextureIcons = new List(); public List SingleTextureIcons = new List(); public TreeViewCustom() { ReloadImages(); BackColor = FormThemes.BaseTheme.FormBackColor; ForeColor = FormThemes.BaseTheme.FormForeColor; } public static ImageList imgList = new ImageList(); public void AddImage(Image image) { imgList.Images.Add(image); } private Thread Thread; public void ReloadTextureIcons(bool CanAbortThread) { if (Thread != null && Thread.IsAlive && CanAbortThread) Thread.Abort(); Thread = new Thread((ThreadStart)(() => { for (int i = 0; i < TextureIcons.Count; i++) { foreach (TreeNode node in TextureIcons[i].IconTextureList) { if (node is STGenericTexture) { var image = ((STGenericTexture)node).GetBitmap(); if (image != null) AddImageOnThread(image, node); } } } for (int i = 0; i < SingleTextureIcons.Count; i++) { if (SingleTextureIcons[i] == null || SingleTextureIcons[i].IconTexture == null) continue; var image = SingleTextureIcons[i].IconTexture.GetBitmap(); if (image != null) AddImageOnThread(image, SingleTextureIcons[i].IconTexture); } })); Thread.Start(); } public void ReloadTextureIcons(List textureIcons, bool CanAbortThread) { if (Thread != null && Thread.IsAlive && CanAbortThread) Thread.Abort(); this.BeginUpdate(); Thread = new Thread((ThreadStart)(() => { List treeNodes = new List(); List imageIcons = new List(); foreach (TreeNode node in textureIcons) { if (node is STGenericTexture) { try { var image = ((STGenericTexture)node).GetBitmap(); if (image != null) { image = ((STGenericTexture)node).GetComponentBitmap(image); imageIcons.Add(image); treeNodes.Add(node); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } for (int i = 0; i < treeNodes.Count; i++) { AddImageOnThread(i, treeNodes[i]); } if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { this.ImageList.Images.AddRange(imageIcons.ToArray()); }); } for (int i = 0; i < treeNodes.Count; i++) imageIcons[i].Dispose(); imageIcons.Clear(); treeNodes.Clear(); textureIcons.Clear(); if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { this.EndUpdate(); }); } })); Thread.Start(); } public void ReloadTextureIcons(ISingleTextureIconLoader textureIcon, Image image) { if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { ReloadTextureIcons(textureIcon.IconTexture, image); }); } else { ReloadTextureIcons(textureIcon.IconTexture, image); } } private void ReloadTextureIcons(TreeNode node, Image image) { image = BitmapExtension.Resize(image, this.ImageList.ImageSize); if (node.ImageIndex != -1 && node.ImageIndex < this.ImageList.Images.Count) this.ImageList.Images[node.ImageIndex] = image; else { node.ImageIndex = this.ImageList.Images.Count; node.SelectedImageIndex = node.ImageIndex; this.ImageList.Images.Add(image); } this.Refresh(); } public void ReloadTextureIcons(ISingleTextureIconLoader textureIcon, bool CanAbortThread) { if (Thread != null && Thread.IsAlive && CanAbortThread) Thread.Abort(); Thread = new Thread((ThreadStart)(() => { try { var image = textureIcon.IconTexture.GetBitmap(); image = textureIcon.IconTexture.GetComponentBitmap(image); AddImageOnThread(image, textureIcon.IconTexture); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } })); Thread.Start(); } public void ReloadTextureIcons(ITextureIconLoader textureIconList) { if (Thread != null && Thread.IsAlive) Thread.Abort(); this.BeginUpdate(); Thread = new Thread((ThreadStart)(() => { List treeNodes = new List(); List imageIcons = new List(); foreach (TreeNode node in textureIconList.IconTextureList) { if (node is STGenericTexture) { try { var image = ((STGenericTexture)node).GetBitmap(); if (image != null) { image = ((STGenericTexture)node).GetComponentBitmap(image); treeNodes.Add(node); imageIcons.Add(image); } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } for (int i = 0; i < treeNodes.Count; i++) { AddImageOnThread(i, treeNodes[i]); } if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { this.ImageList.Images.AddRange(imageIcons.ToArray()); }); } for (int i = 0; i < treeNodes.Count; i++) imageIcons[i].Dispose(); imageIcons.Clear(); treeNodes.Clear(); if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { this.EndUpdate(); }); } })); Thread.Start(); } public void AddImageOnThread(Image image, TreeNode node) { if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { // Running on the UI thread node.ImageIndex = this.ImageList.Images.Count; node.SelectedImageIndex = node.ImageIndex; imgList.Images.Add(image); image.Dispose(); }); } } public void AddImageOnThread(int index, TreeNode node) { if (this.InvokeRequired) { this.Invoke((MethodInvoker)delegate { // Running on the UI thread node.ImageIndex = this.ImageList.Images.Count + index; node.SelectedImageIndex = node.ImageIndex; }); } } public void ReloadImages(int Width = 22, int Height = 22) { imgList = new ImageList(); imgList.ColorDepth = ColorDepth.Depth32Bit; imgList.ImageSize = new Size(Width, Height); imgList.Images.Add("folder", Properties.Resources.Folder); imgList.Images.Add("resource", Properties.Resources.Folder); imgList.Images.Add("Texture", Properties.Resources.Texture); imgList.Images.Add("fileBlank", Properties.Resources.FileBlank); imgList.Images.Add("bfres", Properties.Resources.Bfres); imgList.Images.Add("byaml", Properties.Resources.Byaml); imgList.Images.Add("aamp", Properties.Resources.Aamp); imgList.Images.Add("bntx", Properties.Resources.Bntx); imgList.Images.Add("bfsha", Properties.Resources.Bfsha); imgList.Images.Add("bnsh", Properties.Resources.Bnsh); imgList.Images.Add("mesh", Properties.Resources.mesh); imgList.Images.Add("skeletonAnimation", Properties.Resources.skeletonAnimation); imgList.Images.Add("bone", Properties.Resources.Bone); imgList.Images.Add("bfwav", Properties.Resources.Music1); imgList.Images.Add("bfstp", Properties.Resources.Music2); imgList.Images.Add("material", Properties.Resources.materialSphere); imgList.Images.Add("model", Properties.Resources.model); imgList.Images.Add("folder", Properties.Resources.skeleton); imgList.Images.Add("TextureMaterialMap", Properties.Resources.TextureMaterialMap); imgList.Images.Add("MetaInfo", Properties.Resources.MetaInfo); imgList.Images.Add("MaterialTranslucent", Properties.Resources.materialSphereTranslucent); imgList.Images.Add("MaterialTransparent", Properties.Resources.materialSphereTransparent); //Data types imgList.Images.Add("bool", Properties.Resources.IconBool); imgList.Images.Add("buffer", Properties.Resources.IconBuffer); imgList.Images.Add("curve", Properties.Resources.IconCurve); imgList.Images.Add("float", Properties.Resources.IconFloat); imgList.Images.Add("int", Properties.Resources.IconInt); imgList.Images.Add("list", Properties.Resources.IconList); imgList.Images.Add("object", Properties.Resources.IconObject); imgList.Images.Add("vec2", Properties.Resources.IconVec2); imgList.Images.Add("vec3", Properties.Resources.IconVec3); imgList.Images.Add("vec4", Properties.Resources.IconVec4); Bitmap bmp = new Bitmap(Width, Height); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.Transparent); imgList.Images.Add("empty", bmp); this.ImageList = imgList; } /// /// Load the TreeView with items. /// /// Item type /// Collection of items /// Function to parse Id value from item object /// Function to parse parentId value from item object /// Function to parse display name /// value from item object. This is used as node text. public void LoadItems(IEnumerable items, Func getId, Func getParentId, Func getDisplayName) { // Clear view and internal dictionary Nodes.Clear(); _treeNodes.Clear(); // Load internal dictionary with nodes foreach (var item in items) { var id = getId(item); var displayName = getDisplayName(item); var node = new TreeNode { Name = id.ToString(), Text = displayName, Tag = item }; _treeNodes.Add(getId(item), node); } // Create hierarchy and load into view foreach (var id in _treeNodes.Keys) { var node = GetNode(id); var obj = (T)node.Tag; var parentId = getParentId(obj); if (parentId.HasValue) { var parentNode = GetNode(parentId.Value); parentNode.Nodes.Add(node); } else { Nodes.Add(node); } } } /// /// Retrieve TreeNode by Id. /// Useful when you want to select a specific node. /// /// Item id public TreeNode GetNode(int id) { return _treeNodes[id]; } } public static class TreeViewExtensions { public static IEnumerable Collect(TreeNodeCollection nodes) { foreach (TreeNode node in nodes) { yield return node; foreach (var child in Collect(node.Nodes)) yield return child; } } private const int TVIF_STATE = 0x8; private const int TVIS_STATEIMAGEMASK = 0xF000; private const int TV_FIRST = 0x1100; private const int TVM_SETITEM = TV_FIRST + 63; [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Auto)] private struct TVITEM { public int mask; public IntPtr hItem; public int state; public int stateMask; [MarshalAs(UnmanagedType.LPTStr)] public string lpszText; public int cchTextMax; public int iImage; public int iSelectedImage; public int cChildren; public IntPtr lParam; } [DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, ref TVITEM lParam); /// /// Hides the checkbox for the specified node on a TreeView control. /// public static void HideCheckBox(this TreeNode node) { TVITEM tvi = new TVITEM(); tvi.hItem = node.Handle; tvi.mask = TVIF_STATE; tvi.stateMask = TVIS_STATEIMAGEMASK; tvi.state = 0; SendMessage(node.TreeView.Handle, TVM_SETITEM, IntPtr.Zero, ref tvi); } } }