!B (Sandbox) (CE-21795) Importing models with multisubmaterials via fbx switches...
[CRYENGINE.git] / Code / Tools / Statoscope / Statoscope / CheckboxTreeView.cs
blob6302967a3ede017c912b0849eb349e5f02e3426b
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 using System;
4 using System.Collections;
5 using System.Collections.Generic;
6 using System.Windows.Forms;
8 namespace Statoscope
10 public class CheckboxTreeView : TreeView
12 Stack<Dictionary<TreeNode, CNodeCheckHistoryState>> m_nodeCheckStateUndoStack = new Stack<Dictionary<TreeNode, CNodeCheckHistoryState>>();
13 Stack<Dictionary<TreeNode, CNodeCheckHistoryState>> m_nodeCheckStateRedoStack = new Stack<Dictionary<TreeNode, CNodeCheckHistoryState>>();
15 protected ToolTip m_toolTip;
16 protected bool m_refreshOnTreeNodeChecked = true;
17 bool m_doingUndoNodeCheckReplay = false;
18 bool m_addToCurrentNodeCheckUndoStates = false;
20 public HierarchyTreeNodeCollection TreeNodeHierarchy;
22 public EventHandler HistoryStateListener;
24 public CheckboxTreeView()
26 CheckBoxes = true;
27 PathSeparator = "/";
28 Dock = DockStyle.Fill;
30 TreeNodeHierarchy = new HierarchyTreeNodeCollection(Nodes);
31 m_toolTip = new ToolTip();
32 m_toolTip.InitialDelay = 2000;
33 m_toolTip.ShowAlways = true;
34 m_toolTip.SetToolTip(this,
35 "Right-click: toggle subtree" + Environment.NewLine +
36 "Ctrl-left-click: isolate subtree");
39 private const int WM_LBUTTONDBLCLK = 0x0203;
41 // a hack to get round a bug in the TreeView implementation
42 protected override void WndProc(ref Message m)
44 if (m.Msg == WM_LBUTTONDBLCLK)
46 TreeViewHitTestInfo tvhti = HitTest(new System.Drawing.Point((int)m.LParam));
47 if (tvhti != null && tvhti.Location == TreeViewHitTestLocations.StateImage)
49 m.Result = IntPtr.Zero;
50 return;
53 base.WndProc(ref m);
56 class CNodeCheckHistoryState
58 public bool m_beforeChecked;
59 public bool m_afterChecked;
61 public CNodeCheckHistoryState(bool beforeChecked)
63 m_beforeChecked = beforeChecked;
67 void StartCheckStateBlock()
69 m_nodeCheckStateUndoStack.Push(new Dictionary<TreeNode, CNodeCheckHistoryState>());
70 m_addToCurrentNodeCheckUndoStates = true;
71 m_refreshOnTreeNodeChecked = false;
72 UpdateHistoryStateListeners();
75 void EndCheckStateBlock()
77 m_refreshOnTreeNodeChecked = true;
78 m_addToCurrentNodeCheckUndoStates = false;
81 public class CheckStateScope : IDisposable
83 private readonly CheckboxTreeView CTV;
85 public CheckStateScope(CheckboxTreeView ctv)
87 CTV = ctv;
88 CTV.StartCheckStateBlock();
91 public void Dispose()
93 CTV.EndCheckStateBlock();
97 public CheckStateScope CheckStateBlock()
99 return new CheckStateScope(this);
102 void SetUndoNodeBeforeCheckState(TreeNode node, bool beforeCheckedState)
104 if (!m_doingUndoNodeCheckReplay)
106 m_nodeCheckStateRedoStack.Clear();
108 Dictionary<TreeNode, CNodeCheckHistoryState> currentUndoNodeCheckStates;
110 if (m_addToCurrentNodeCheckUndoStates)
112 currentUndoNodeCheckStates = m_nodeCheckStateUndoStack.Peek();
114 else
116 currentUndoNodeCheckStates = new Dictionary<TreeNode, CNodeCheckHistoryState>();
117 m_nodeCheckStateUndoStack.Push(currentUndoNodeCheckStates);
120 if (!currentUndoNodeCheckStates.ContainsKey(node))
122 currentUndoNodeCheckStates.Add(node, new CNodeCheckHistoryState(beforeCheckedState));
125 UpdateHistoryStateListeners();
129 void SetUndoNodeAfterCheckState(TreeNode node, bool afterCheckedState)
131 if (!m_doingUndoNodeCheckReplay)
133 Dictionary<TreeNode, CNodeCheckHistoryState> currentUndoNodeCheckStates = m_nodeCheckStateUndoStack.Peek();
134 currentUndoNodeCheckStates[node].m_afterChecked = afterCheckedState;
135 UpdateHistoryStateListeners();
139 void UpdateHistoryStateListeners()
141 if (HistoryStateListener != null)
142 HistoryStateListener(this, EventArgs.Empty);
145 public virtual void Undo()
147 m_doingUndoNodeCheckReplay = true;
148 m_refreshOnTreeNodeChecked = false;
150 if (m_nodeCheckStateUndoStack.Count > 0)
152 Dictionary<TreeNode, CNodeCheckHistoryState> topUndoNodeCheckStates = m_nodeCheckStateUndoStack.Pop();
154 foreach (KeyValuePair<TreeNode, CNodeCheckHistoryState> undoNodeCheckStatePair in topUndoNodeCheckStates)
156 TreeNode node = undoNodeCheckStatePair.Key;
157 node.Checked = undoNodeCheckStatePair.Value.m_beforeChecked;
160 m_nodeCheckStateRedoStack.Push(topUndoNodeCheckStates);
161 UpdateHistoryStateListeners();
164 m_refreshOnTreeNodeChecked = true;
165 m_doingUndoNodeCheckReplay = false;
168 public virtual void Redo()
170 m_doingUndoNodeCheckReplay = true;
171 m_refreshOnTreeNodeChecked = false;
173 if (m_nodeCheckStateRedoStack.Count > 0)
175 Dictionary<TreeNode, CNodeCheckHistoryState> topRedoNodeCheckStates = m_nodeCheckStateRedoStack.Pop();
177 foreach (KeyValuePair<TreeNode, CNodeCheckHistoryState> redoNodeCheckStatePair in topRedoNodeCheckStates)
179 TreeNode node = redoNodeCheckStatePair.Key;
180 node.Checked = redoNodeCheckStatePair.Value.m_afterChecked;
183 m_nodeCheckStateUndoStack.Push(topRedoNodeCheckStates);
184 UpdateHistoryStateListeners();
187 m_refreshOnTreeNodeChecked = true;
188 m_doingUndoNodeCheckReplay = false;
191 public virtual void FilterTextChanged(string filterText)
193 m_refreshOnTreeNodeChecked = false;
195 using (CheckStateBlock())
197 if (filterText == "")
199 // check everything
200 foreach (TreeNode node in GetTreeNodeEnumerator(Nodes))
202 node.Checked = true;
205 else
207 foreach (TreeNode node in GetTreeNodeEnumerator(Nodes))
209 if (node.Text.ToUpper().Contains(filterText))
211 node.Checked = true;
213 // check all parent nodes
214 for (TreeNode tn = node; tn != null; tn = tn.Parent)
216 tn.Checked = true;
219 else
221 node.Checked = false;
227 m_refreshOnTreeNodeChecked = true;
230 public int NumUndoStates
232 get { return m_nodeCheckStateUndoStack.Count; }
235 public int NumRedoStates
237 get { return m_nodeCheckStateRedoStack.Count; }
240 // select treeNode in treeView, toggle its check state and set the entire subtree's check state to the new state
241 public void ToggleSubTree(TreeNode treeNode)
243 using (CheckStateBlock())
245 SelectedNode = treeNode;
247 foreach (TreeNode node in GetTreeNodeEnumerator(treeNode.Nodes))
248 node.Checked = !treeNode.Checked;
250 treeNode.Checked = !treeNode.Checked;
254 public void IsolateSubTree(TreeNode treeNode)
256 using (CheckStateBlock())
258 // uncheck everything
259 foreach (TreeNode subNode in GetTreeNodeEnumerator(Nodes))
260 subNode.Checked = false;
262 // check all sub nodes
263 foreach (TreeNode subNode in GetTreeNodeEnumerator(treeNode.Nodes))
264 subNode.Checked = true;
266 // check all parent nodes
267 for (TreeNode tn = treeNode; tn != null; tn = tn.Parent)
268 tn.Checked = true;
272 static IEnumerable<TreeNode> GetTreeNodeEnumerator(TreeNodeCollection nodes)
274 foreach (TreeNode node in nodes)
276 yield return node;
278 foreach (TreeNode subNode in GetTreeNodeEnumerator(node.Nodes))
280 yield return subNode;
285 protected void SelectNode(string[] pathLocations)
287 SelectedNode = TreeNodeHierarchy[pathLocations];
288 Focus();
289 this.PaintNow();
292 protected void SelectNextClosestNode()
294 if (SelectedNode.NextNode != null)
295 SelectedNode = SelectedNode.NextNode;
296 else if (SelectedNode.PrevNode != null)
297 SelectedNode = SelectedNode.PrevNode;
298 else if (SelectedNode.Parent != null)
299 SelectedNode = SelectedNode.Parent;
302 protected override void OnBeforeCheck(TreeViewCancelEventArgs e)
304 base.OnBeforeCheck(e);
305 SetUndoNodeBeforeCheckState(e.Node, e.Node.Checked);
308 protected override void OnAfterCheck(TreeViewEventArgs e)
310 base.OnAfterCheck(e);
311 SetUndoNodeAfterCheckState(e.Node, e.Node.Checked);
314 protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
316 base.OnNodeMouseClick(e);
318 if (e.Button == MouseButtons.Left)
320 if (StatoscopeForm.m_ctrlIsBeingPressed)
322 IsolateSubTree(e.Node);
325 else if (e.Button == MouseButtons.Right)
327 ToggleSubTree(e.Node);
331 protected override void OnItemDrag(ItemDragEventArgs e)
333 base.OnItemDrag(e);
335 TreeNode treeNode = (TreeNode)e.Item;
336 DoDragDrop("/" + treeNode.FullPath, DragDropEffects.Copy);
339 // a convenience for accessing all TreeNodeHierarchy in a hierarchy - a TreeNodeCollection is just the current level
340 public class HierarchyTreeNodeCollection : IEnumerable
342 TreeNodeCollection Nodes;
344 public HierarchyTreeNodeCollection(TreeNodeCollection nodes)
346 Nodes = nodes;
349 public TreeNode this[string path]
353 return this[path.PathLocations()];
357 public TreeNode this[IEnumerable<string> pathLocations]
361 TreeNode node = null;
362 TreeNodeCollection nodes = Nodes;
364 foreach (string location in pathLocations)
366 if (!nodes.ContainsKey(location))
368 return null;
371 node = nodes[location];
372 nodes = node.Nodes;
375 return node;
379 public bool IsChecked(string path)
381 TreeNodeCollection nodes = Nodes;
383 foreach (string location in path.PathLocations())
385 TreeNode node = nodes[location];
386 if (node == null || !node.Checked)
387 return false;
388 nodes = node.Nodes;
391 return true;
394 public IEnumerator GetEnumerator()
396 foreach (TreeNode node in Nodes)
398 yield return node;
400 foreach (TreeNode subNode in GetTreeNodeEnumerator(node.Nodes))
402 yield return subNode;