!B (Sandbox) (CE-21795) Importing models with multisubmaterials via fbx switches...
[CRYENGINE.git] / Code / Tools / LuaRemoteDebugger / Aga.Controls / Tree / TreeViewAdv.cs
blobd54383148549c6fa529dadc9baecab64f1a43058
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 using System;
4 using System.Collections.Generic;
5 using System.Collections.ObjectModel;
6 using System.ComponentModel;
7 using System.Drawing;
8 using System.Security.Permissions;
9 using System.Threading;
10 using System.Windows.Forms;
11 using System.Collections;
13 using Aga.Controls.Tree.NodeControls;
14 using Aga.Controls.Threading;
17 namespace Aga.Controls.Tree
19 /// <summary>
20 /// Extensible advanced <see cref="TreeView"/> implemented in 100% managed C# code.
21 /// Features: Model/View architecture. Multiple column per node. Ability to select
22 /// multiple tree nodes. Different types of controls for each node column:
23 /// <see cref="CheckBox"/>, Icon, Label... Drag and Drop highlighting. Load on
24 /// demand of nodes. Incremental search of nodes.
25 /// </summary>
26 public partial class TreeViewAdv : Control
28 private const int LeftMargin = 7;
29 internal const int ItemDragSensivity = 4;
30 private readonly int _columnHeaderHeight;
31 private const int DividerWidth = 9;
32 private const int DividerCorrectionGap = -2;
34 private Pen _linePen;
35 private Pen _markPen;
36 private bool _suspendUpdate;
37 private bool _needFullUpdate;
38 private bool _fireSelectionEvent;
39 private NodePlusMinus _plusMinus;
40 private ToolTip _toolTip;
41 private DrawContext _measureContext;
42 private TreeColumn _hotColumn;
43 private IncrementalSearch _search;
44 private List<TreeNodeAdv> _expandingNodes = new List<TreeNodeAdv>();
45 private AbortableThreadPool _threadPool = new AbortableThreadPool();
47 public VScrollBar VScrollBar { get { return _vScrollBar; } }
49 #region Public Events
51 [Category("Action")]
52 public event ItemDragEventHandler ItemDrag;
53 private void OnItemDrag(MouseButtons buttons, object item)
55 if (ItemDrag != null)
56 ItemDrag(this, new ItemDragEventArgs(buttons, item));
59 [Category("Behavior")]
60 public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseClick;
61 private void OnNodeMouseClick(TreeNodeAdvMouseEventArgs args)
63 if (NodeMouseClick != null)
64 NodeMouseClick(this, args);
67 [Category("Behavior")]
68 public event EventHandler<TreeNodeAdvMouseEventArgs> NodeMouseDoubleClick;
69 private void OnNodeMouseDoubleClick(TreeNodeAdvMouseEventArgs args)
71 if (NodeMouseDoubleClick != null)
72 NodeMouseDoubleClick(this, args);
75 [Category("Behavior")]
76 public event EventHandler<TreeColumnEventArgs> ColumnWidthChanged;
77 internal void OnColumnWidthChanged(TreeColumn column)
79 if (ColumnWidthChanged != null)
80 ColumnWidthChanged(this, new TreeColumnEventArgs(column));
83 [Category("Behavior")]
84 public event EventHandler<TreeColumnEventArgs> ColumnReordered;
85 internal void OnColumnReordered(TreeColumn column)
87 if (ColumnReordered != null)
88 ColumnReordered(this, new TreeColumnEventArgs(column));
91 [Category("Behavior")]
92 public event EventHandler<TreeColumnEventArgs> ColumnClicked;
93 internal void OnColumnClicked(TreeColumn column)
95 if (ColumnClicked != null)
96 ColumnClicked(this, new TreeColumnEventArgs(column));
99 [Category("Behavior")]
100 public event EventHandler SelectionChanged;
101 internal void OnSelectionChanged()
103 if (SuspendSelectionEvent)
104 _fireSelectionEvent = true;
105 else
107 _fireSelectionEvent = false;
108 if (SelectionChanged != null)
109 SelectionChanged(this, EventArgs.Empty);
113 [Category("Behavior")]
114 public event EventHandler<TreeViewAdvEventArgs> Collapsing;
115 private void OnCollapsing(TreeNodeAdv node)
117 if (Collapsing != null)
118 Collapsing(this, new TreeViewAdvEventArgs(node));
121 [Category("Behavior")]
122 public event EventHandler<TreeViewAdvEventArgs> Collapsed;
123 private void OnCollapsed(TreeNodeAdv node)
125 if (Collapsed != null)
126 Collapsed(this, new TreeViewAdvEventArgs(node));
129 [Category("Behavior")]
130 public event EventHandler<TreeViewAdvEventArgs> Expanding;
131 private void OnExpanding(TreeNodeAdv node)
133 if (Expanding != null)
134 Expanding(this, new TreeViewAdvEventArgs(node));
137 [Category("Behavior")]
138 public event EventHandler<TreeViewAdvEventArgs> Expanded;
139 private void OnExpanded(TreeNodeAdv node)
141 if (Expanded != null)
142 Expanded(this, new TreeViewAdvEventArgs(node));
145 [Category("Behavior")]
146 public event EventHandler GridLineStyleChanged;
147 private void OnGridLineStyleChanged()
149 if (GridLineStyleChanged != null)
150 GridLineStyleChanged(this, EventArgs.Empty);
153 [Category("Behavior")]
154 public event ScrollEventHandler Scroll;
155 protected virtual void OnScroll(ScrollEventArgs e)
157 if (Scroll != null)
158 Scroll(this, e);
161 [Category("Behavior")]
162 public event EventHandler<TreeViewRowDrawEventArgs> RowDraw;
163 protected virtual void OnRowDraw(PaintEventArgs e, TreeNodeAdv node, DrawContext context, int row, Rectangle rowRect)
165 if (RowDraw != null)
167 TreeViewRowDrawEventArgs args = new TreeViewRowDrawEventArgs(e.Graphics, e.ClipRectangle, node, context, row, rowRect);
168 RowDraw(this, args);
172 /// <summary>
173 /// Fires when control is going to draw. Can be used to change text or back color
174 /// </summary>
175 [Category("Behavior")]
176 public event EventHandler<DrawEventArgs> DrawControl;
178 internal bool DrawControlMustBeFired()
180 return DrawControl != null;
183 internal void FireDrawControl(DrawEventArgs args)
185 OnDrawControl(args);
188 protected virtual void OnDrawControl(DrawEventArgs args)
190 if (DrawControl != null)
191 DrawControl(this, args);
195 [Category("Drag Drop")]
196 public event EventHandler<DropNodeValidatingEventArgs> DropNodeValidating;
197 protected virtual void OnDropNodeValidating(Point point, ref TreeNodeAdv node)
199 if (DropNodeValidating != null)
201 DropNodeValidatingEventArgs args = new DropNodeValidatingEventArgs(point, node);
202 DropNodeValidating(this, args);
203 node = args.Node;
206 #endregion
208 public TreeViewAdv()
210 InitializeComponent();
211 SetStyle(ControlStyles.AllPaintingInWmPaint
212 | ControlStyles.UserPaint
213 | ControlStyles.OptimizedDoubleBuffer
214 | ControlStyles.ResizeRedraw
215 | ControlStyles.Selectable
216 , true);
219 if (Application.RenderWithVisualStyles)
220 _columnHeaderHeight = 20;
221 else
222 _columnHeaderHeight = 17;
224 //BorderStyle = BorderStyle.Fixed3D;
225 _hScrollBar.Height = SystemInformation.HorizontalScrollBarHeight;
226 _vScrollBar.Width = SystemInformation.VerticalScrollBarWidth;
227 _rowLayout = new FixedRowHeightLayout(this, RowHeight);
228 _rowMap = new List<TreeNodeAdv>();
229 _selection = new List<TreeNodeAdv>();
230 _readonlySelection = new ReadOnlyCollection<TreeNodeAdv>(_selection);
231 _columns = new TreeColumnCollection(this);
232 _toolTip = new ToolTip();
234 _measureContext = new DrawContext();
235 _measureContext.Font = Font;
236 _measureContext.Graphics = Graphics.FromImage(new Bitmap(1, 1));
238 Input = new NormalInputState(this);
239 _search = new IncrementalSearch(this);
240 CreateNodes();
241 CreatePens();
243 ArrangeControls();
245 _plusMinus = new NodePlusMinus();
246 _controls = new NodeControlsCollection(this);
248 Font = _font;
249 ExpandingIcon.IconChanged += ExpandingIconChanged;
252 void ExpandingIconChanged(object sender, EventArgs e)
254 if (IsHandleCreated && !IsDisposed)
255 BeginInvoke(new MethodInvoker(DrawIcons));
258 private void DrawIcons()
260 using (Graphics gr = Graphics.FromHwnd(this.Handle))
262 //Apply the same Graphics Transform logic as used in OnPaint.
263 int y = 0;
264 if (UseColumns)
266 y += ColumnHeaderHeight;
267 if (Columns.Count == 0)
268 return;
270 int firstRowY = _rowLayout.GetRowBounds(FirstVisibleRow).Y;
271 y -= firstRowY;
272 gr.ResetTransform();
273 gr.TranslateTransform(-OffsetX, y);
275 DrawContext context = new DrawContext();
276 context.Graphics = gr;
277 for (int i = 0; i < _expandingNodes.Count; i++)
279 foreach (NodeControlInfo item in GetNodeControls(_expandingNodes[i]))
281 if (item.Control is ExpandingIcon)
283 Rectangle bounds = item.Bounds;
284 if (item.Node.Parent == null && UseColumns)
285 bounds.Location = Point.Empty; // display root expanding icon at 0,0
287 context.Bounds = bounds;
288 item.Control.Draw(item.Node, context);
295 #region Public Methods
297 public TreePath GetPath(TreeNodeAdv node)
299 if (node == _root)
300 return TreePath.Empty;
301 else
303 Stack<object> stack = new Stack<object>();
304 while (node != _root && node != null)
306 stack.Push(node.Tag);
307 node = node.Parent;
309 return new TreePath(stack.ToArray());
313 public TreeNodeAdv GetNodeAt(Point point)
315 NodeControlInfo info = GetNodeControlInfoAt(point);
316 return info.Node;
319 public NodeControlInfo GetNodeControlInfoAt(Point point)
321 if (point.X < 0 || point.Y < 0)
322 return NodeControlInfo.Empty;
324 int row = _rowLayout.GetRowAt(point);
325 if (row < RowCount && row >= 0)
326 return GetNodeControlInfoAt(RowMap[row], point);
327 else
328 return NodeControlInfo.Empty;
331 private NodeControlInfo GetNodeControlInfoAt(TreeNodeAdv node, Point point)
333 Rectangle rect = _rowLayout.GetRowBounds(FirstVisibleRow);
334 point.Y += (rect.Y - ColumnHeaderHeight);
335 point.X += OffsetX;
336 foreach (NodeControlInfo info in GetNodeControls(node))
337 if (info.Bounds.Contains(point))
338 return info;
340 if (FullRowSelect)
341 return new NodeControlInfo(null, Rectangle.Empty, node);
342 else
343 return NodeControlInfo.Empty;
346 public void BeginUpdate()
348 _suspendUpdate = true;
349 SuspendSelectionEvent = true;
352 public void EndUpdate()
354 _suspendUpdate = false;
355 if (_needFullUpdate)
356 FullUpdate();
357 else
358 UpdateView();
359 SuspendSelectionEvent = false;
362 public void ExpandAll()
364 _root.ExpandAll();
367 public void CollapseAll()
369 _root.CollapseAll();
372 /// <summary>
373 /// Expand all parent nodes, andd scroll to the specified node
374 /// </summary>
375 public void EnsureVisible(TreeNodeAdv node)
377 if (node == null)
378 throw new ArgumentNullException("node");
380 if (!IsMyNode(node))
381 throw new ArgumentException();
383 TreeNodeAdv parent = node.Parent;
384 while (parent != _root)
386 parent.IsExpanded = true;
387 parent = parent.Parent;
389 ScrollTo(node);
392 /// <summary>
393 /// Make node visible, scroll if needed. All parent nodes of the specified node must be expanded
394 /// </summary>
395 /// <param name="node"></param>
396 public void ScrollTo(TreeNodeAdv node)
398 if (node == null)
399 throw new ArgumentNullException("node");
401 if (!IsMyNode(node))
402 throw new ArgumentException();
404 if (node.Row < 0)
405 CreateRowMap();
407 int row = -1;
409 if (node.Row < FirstVisibleRow)
410 row = node.Row;
411 else
413 int pageStart = _rowLayout.GetRowBounds(FirstVisibleRow).Top;
414 int rowBottom = _rowLayout.GetRowBounds(node.Row).Bottom;
415 if (rowBottom > pageStart + DisplayRectangle.Height - ColumnHeaderHeight)
416 row = _rowLayout.GetFirstRow(node.Row);
419 if (row >= _vScrollBar.Minimum && row <= _vScrollBar.Maximum)
420 _vScrollBar.Value = row;
423 public void ClearSelection()
425 BeginUpdate();
428 ClearSelectionInternal();
430 finally
432 EndUpdate();
436 internal void ClearSelectionInternal()
438 while (Selection.Count > 0)
440 var t = Selection[0];
441 t.IsSelected = false;
442 Selection.Remove(t); //hack
446 #endregion
448 protected override void OnSizeChanged(EventArgs e)
450 ArrangeControls();
451 SafeUpdateScrollBars();
452 base.OnSizeChanged(e);
455 private void ArrangeControls()
457 int hBarSize = _hScrollBar.Height;
458 int vBarSize = _vScrollBar.Width;
459 Rectangle clientRect = ClientRectangle;
461 _hScrollBar.SetBounds(clientRect.X, clientRect.Bottom - hBarSize,
462 clientRect.Width - vBarSize, hBarSize);
464 _vScrollBar.SetBounds(clientRect.Right - vBarSize, clientRect.Y,
465 vBarSize, clientRect.Height - hBarSize);
468 private void SafeUpdateScrollBars()
470 if (InvokeRequired)
471 BeginInvoke(new MethodInvoker(UpdateScrollBars));
472 else
473 UpdateScrollBars();
476 private void UpdateScrollBars()
478 UpdateVScrollBar();
479 UpdateHScrollBar();
480 UpdateVScrollBar();
481 UpdateHScrollBar();
482 _hScrollBar.Width = DisplayRectangle.Width;
483 _vScrollBar.Height = DisplayRectangle.Height;
486 private void UpdateHScrollBar()
488 _hScrollBar.Maximum = ContentWidth;
489 _hScrollBar.LargeChange = Math.Max(DisplayRectangle.Width, 0);
490 _hScrollBar.SmallChange = 5;
491 _hScrollBar.Visible = _hScrollBar.LargeChange < _hScrollBar.Maximum;
492 _hScrollBar.Value = Math.Min(_hScrollBar.Value, _hScrollBar.Maximum - _hScrollBar.LargeChange + 1);
495 private void UpdateVScrollBar()
497 _vScrollBar.Maximum = Math.Max(RowCount - 1, 0);
498 _vScrollBar.LargeChange = _rowLayout.PageRowCount;
499 _vScrollBar.Visible = (RowCount > 0) && (_vScrollBar.LargeChange <= _vScrollBar.Maximum);
500 _vScrollBar.Value = Math.Min(_vScrollBar.Value, _vScrollBar.Maximum - _vScrollBar.LargeChange + 1);
503 protected override CreateParams CreateParams
505 [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
508 CreateParams res = base.CreateParams;
509 switch (BorderStyle)
511 case BorderStyle.FixedSingle:
512 res.Style |= 0x800000;
513 break;
514 case BorderStyle.Fixed3D:
515 res.ExStyle |= 0x200;
516 break;
518 return res;
522 protected override void OnGotFocus(EventArgs e)
524 UpdateView();
525 ChangeInput();
526 base.OnGotFocus(e);
529 protected override void OnFontChanged(EventArgs e)
531 base.OnFontChanged(e);
532 _measureContext.Font = Font;
533 FullUpdate();
536 internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node)
538 if (node == null)
539 yield break;
540 Rectangle rowRect = _rowLayout.GetRowBounds(node.Row);
541 foreach (NodeControlInfo n in GetNodeControls(node, rowRect))
542 yield return n;
545 internal IEnumerable<NodeControlInfo> GetNodeControls(TreeNodeAdv node, Rectangle rowRect)
547 if (node == null)
548 yield break;
550 int y = rowRect.Y;
551 int x = (node.Level - 1) * _indent + LeftMargin;
552 int width = 0;
553 if (node.Row == 0 && ShiftFirstNode)
554 x -= _indent;
555 Rectangle rect = Rectangle.Empty;
557 if (ShowPlusMinus)
559 width = _plusMinus.GetActualSize(node, _measureContext).Width;
560 rect = new Rectangle(x, y, width, rowRect.Height);
561 if (UseColumns && Columns.Count > 0 && Columns[0].Width < rect.Right)
562 rect.Width = Columns[0].Width - x;
564 yield return new NodeControlInfo(_plusMinus, rect, node);
565 x += width;
568 if (!UseColumns)
570 foreach (NodeControl c in NodeControls)
572 Size s = c.GetActualSize(node, _measureContext);
573 if (!s.IsEmpty)
575 width = s.Width;
576 rect = new Rectangle(x, y, width, rowRect.Height);
577 x += rect.Width;
578 yield return new NodeControlInfo(c, rect, node);
582 else
584 int right = 0;
585 foreach (TreeColumn col in Columns)
587 if (col.IsVisible && col.Width > 0)
589 right += col.Width;
590 for (int i = 0; i < NodeControls.Count; i++)
592 NodeControl nc = NodeControls[i];
593 if (nc.ParentColumn == col)
595 Size s = nc.GetActualSize(node, _measureContext);
596 if (!s.IsEmpty)
598 bool isLastControl = true;
599 for (int k = i + 1; k < NodeControls.Count; k++)
600 if (NodeControls[k].ParentColumn == col)
602 isLastControl = false;
603 break;
606 width = right - x;
607 if (!isLastControl)
608 width = s.Width;
609 int maxWidth = Math.Max(0, right - x);
610 rect = new Rectangle(x, y, Math.Min(maxWidth, width), rowRect.Height);
611 x += width;
612 yield return new NodeControlInfo(nc, rect, node);
616 x = right;
622 internal static double Dist(Point p1, Point p2)
624 return Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2));
627 public void FullUpdate()
629 HideEditor();
630 if (InvokeRequired)
631 BeginInvoke(new MethodInvoker(UnsafeFullUpdate));
632 else
633 UnsafeFullUpdate();
636 private void UnsafeFullUpdate()
638 _rowLayout.ClearCache();
639 CreateRowMap();
640 SafeUpdateScrollBars();
641 UpdateView();
642 _needFullUpdate = false;
645 internal void UpdateView()
647 if (!_suspendUpdate)
648 Invalidate(false);
651 internal void UpdateHeaders()
653 Invalidate(new Rectangle(0, 0, Width, ColumnHeaderHeight));
656 internal void UpdateColumns()
658 FullUpdate();
661 private void CreateNodes()
663 Selection.Clear();
664 SelectionStart = null;
665 _root = new TreeNodeAdv(this, null);
666 _root.IsExpanded = true;
667 if (_root.Nodes.Count > 0)
668 CurrentNode = _root.Nodes[0];
669 else
670 CurrentNode = null;
673 internal void ReadChilds(TreeNodeAdv parentNode)
675 ReadChilds(parentNode, false);
678 internal void ReadChilds(TreeNodeAdv parentNode, bool performFullUpdate)
680 if (!parentNode.IsLeaf)
682 parentNode.IsExpandedOnce = true;
683 parentNode.Nodes.Clear();
685 if (Model != null)
687 IEnumerable items = Model.GetChildren(GetPath(parentNode));
688 if (items != null)
689 foreach (object obj in items)
691 AddNewNode(parentNode, obj, -1);
692 if (performFullUpdate)
693 FullUpdate();
697 if (parentNode.AutoExpandOnStructureChanged)
698 parentNode.ExpandAll();
702 private void AddNewNode(TreeNodeAdv parent, object tag, int index)
704 TreeNodeAdv node = new TreeNodeAdv(this, tag);
705 AddNode(parent, index, node);
708 private void AddNode(TreeNodeAdv parent, int index, TreeNodeAdv node)
710 if (index >= 0 && index < parent.Nodes.Count)
711 parent.Nodes.Insert(index, node);
712 else
713 parent.Nodes.Add(node);
715 node.IsLeaf = Model.IsLeaf(GetPath(node));
716 if (node.IsLeaf)
717 node.Nodes.Clear();
718 if (!LoadOnDemand || node.IsExpandedOnce)
719 ReadChilds(node);
722 private struct ExpandArgs
724 public TreeNodeAdv Node;
725 public bool Value;
726 public bool IgnoreChildren;
729 public void AbortBackgroundExpandingThreads()
731 _threadPool.CancelAll(true);
732 for (int i = 0; i < _expandingNodes.Count; i++)
733 _expandingNodes[i].IsExpandingNow = false;
734 _expandingNodes.Clear();
735 Invalidate();
738 internal void SetIsExpanded(TreeNodeAdv node, bool value, bool ignoreChildren)
740 ExpandArgs eargs = new ExpandArgs();
741 eargs.Node = node;
742 eargs.Value = value;
743 eargs.IgnoreChildren = ignoreChildren;
745 if (AsyncExpanding && LoadOnDemand && !_threadPool.IsMyThread(Thread.CurrentThread))
747 WaitCallback wc = delegate(object argument) { SetIsExpanded((ExpandArgs)argument); };
748 _threadPool.QueueUserWorkItem(wc, eargs);
750 else
751 SetIsExpanded(eargs);
754 private void SetIsExpanded(ExpandArgs eargs)
756 bool update = !eargs.IgnoreChildren && !AsyncExpanding;
757 if (update)
758 BeginUpdate();
761 if (IsMyNode(eargs.Node) && eargs.Node.IsExpanded != eargs.Value)
762 SetIsExpanded(eargs.Node, eargs.Value);
764 if (!eargs.IgnoreChildren)
765 SetIsExpandedRecursive(eargs.Node, eargs.Value);
767 finally
769 if (update)
770 EndUpdate();
774 internal void SetIsExpanded(TreeNodeAdv node, bool value)
776 if (Root == node && !value)
777 return; //Can't collapse root node
779 if (value)
781 OnExpanding(node);
782 node.OnExpanding();
784 else
786 OnCollapsing(node);
787 node.OnCollapsing();
790 if (value && !node.IsExpandedOnce)
792 if (AsyncExpanding && LoadOnDemand)
794 AddExpandingNode(node);
795 node.AssignIsExpanded(true);
796 Invalidate();
798 ReadChilds(node, AsyncExpanding);
799 RemoveExpandingNode(node);
801 node.AssignIsExpanded(value);
802 SmartFullUpdate();
804 if (value)
806 OnExpanded(node);
807 node.OnExpanded();
809 else
811 OnCollapsed(node);
812 node.OnCollapsed();
816 private void RemoveExpandingNode(TreeNodeAdv node)
818 node.IsExpandingNow = false;
819 _expandingNodes.Remove(node);
820 if (_expandingNodes.Count <= 0)
821 ExpandingIcon.Stop();
824 private void AddExpandingNode(TreeNodeAdv node)
826 node.IsExpandingNow = true;
827 _expandingNodes.Add(node);
828 ExpandingIcon.Start();
831 internal void SetIsExpandedRecursive(TreeNodeAdv root, bool value)
833 for (int i = 0; i < root.Nodes.Count; i++)
835 TreeNodeAdv node = root.Nodes[i];
836 node.IsExpanded = value;
837 SetIsExpandedRecursive(node, value);
841 private void CreateRowMap()
843 RowMap.Clear();
844 int row = 0;
845 _contentWidth = 0;
846 foreach (TreeNodeAdv node in VisibleNodes)
848 node.Row = row;
849 RowMap.Add(node);
850 if (!UseColumns)
852 _contentWidth = Math.Max(_contentWidth, GetNodeWidth(node));
854 row++;
856 if (UseColumns)
858 _contentWidth = 0;
859 foreach (TreeColumn col in _columns)
860 if (col.IsVisible)
861 _contentWidth += col.Width;
865 private int GetNodeWidth(TreeNodeAdv node)
867 if (node.RightBounds == null)
869 Rectangle res = GetNodeBounds(GetNodeControls(node, Rectangle.Empty));
870 node.RightBounds = res.Right;
872 return node.RightBounds.Value;
875 internal Rectangle GetNodeBounds(TreeNodeAdv node)
877 return GetNodeBounds(GetNodeControls(node));
880 private Rectangle GetNodeBounds(IEnumerable<NodeControlInfo> nodeControls)
882 Rectangle res = Rectangle.Empty;
883 foreach (NodeControlInfo info in nodeControls)
885 if (res == Rectangle.Empty)
886 res = info.Bounds;
887 else
888 res = Rectangle.Union(res, info.Bounds);
890 return res;
893 private void _vScrollBar_ValueChanged(object sender, EventArgs e)
895 FirstVisibleRow = _vScrollBar.Value;
898 private void _hScrollBar_ValueChanged(object sender, EventArgs e)
900 OffsetX = _hScrollBar.Value;
903 private void _vScrollBar_Scroll(object sender, ScrollEventArgs e)
905 OnScroll(e);
908 private void _hScrollBar_Scroll(object sender, ScrollEventArgs e)
910 OnScroll(e);
913 internal void SmartFullUpdate()
915 if (_suspendUpdate)
916 _needFullUpdate = true;
917 else
918 FullUpdate();
921 internal bool IsMyNode(TreeNodeAdv node)
923 if (node == null)
924 return false;
926 if (node.Tree != this)
927 return false;
929 while (node.Parent != null)
930 node = node.Parent;
932 return node == _root;
935 internal void UpdateSelection()
937 bool flag = false;
939 if (!IsMyNode(CurrentNode))
940 CurrentNode = null;
941 if (!IsMyNode(_selectionStart))
942 _selectionStart = null;
944 for (int i = Selection.Count - 1; i >= 0; i--)
945 if (!IsMyNode(Selection[i]))
947 flag = true;
948 Selection.RemoveAt(i);
951 if (flag)
952 OnSelectionChanged();
955 internal void ChangeColumnWidth(TreeColumn column)
957 if (!(_input is ResizeColumnState))
959 FullUpdate();
960 OnColumnWidthChanged(column);
964 public TreeNodeAdv FindNode(TreePath path)
966 return FindNode(path, false);
969 public TreeNodeAdv FindNode(TreePath path, bool readChilds)
971 if (path.IsEmpty())
972 return _root;
973 else
974 return FindNode(_root, path, 0, readChilds);
977 private TreeNodeAdv FindNode(TreeNodeAdv root, TreePath path, int level, bool readChilds)
979 if (!root.IsExpandedOnce && readChilds)
980 ReadChilds(root);
982 for (int i = 0; i < root.Nodes.Count; i++)
984 TreeNodeAdv node = root.Nodes[i];
985 if (node.Tag == path.FullPath[level])
987 if (level == path.FullPath.Length - 1)
988 return node;
989 else
990 return FindNode(node, path, level + 1, readChilds);
993 return null;
996 public TreeNodeAdv FindNodeByTag(object tag)
998 return FindNodeByTag(_root, tag);
1001 private TreeNodeAdv FindNodeByTag(TreeNodeAdv root, object tag)
1003 foreach (TreeNodeAdv node in root.Nodes)
1005 if (node.Tag == tag)
1006 return node;
1007 TreeNodeAdv res = FindNodeByTag(node, tag);
1008 if (res != null)
1009 return res;
1011 return null;
1014 public void SelectAllNodes()
1016 SuspendSelectionEvent = true;
1019 if (SelectionMode == TreeSelectionMode.MultiSameParent)
1021 if (CurrentNode != null)
1023 foreach (TreeNodeAdv n in CurrentNode.Parent.Nodes)
1024 n.IsSelected = true;
1027 else if (SelectionMode == TreeSelectionMode.Multi)
1029 SelectNodes(Root.Nodes);
1032 finally
1034 SuspendSelectionEvent = false;
1038 private void SelectNodes(Collection<TreeNodeAdv> nodes)
1040 foreach (TreeNodeAdv n in nodes)
1042 n.IsSelected = true;
1043 if (n.IsExpanded)
1044 SelectNodes(n.Nodes);
1048 #region ModelEvents
1049 private void BindModelEvents()
1051 _model.NodesChanged += new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
1052 _model.NodesInserted += new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
1053 _model.NodesRemoved += new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
1054 _model.StructureChanged += new EventHandler<TreePathEventArgs>(_model_StructureChanged);
1057 private void UnbindModelEvents()
1059 _model.NodesChanged -= new EventHandler<TreeModelEventArgs>(_model_NodesChanged);
1060 _model.NodesInserted -= new EventHandler<TreeModelEventArgs>(_model_NodesInserted);
1061 _model.NodesRemoved -= new EventHandler<TreeModelEventArgs>(_model_NodesRemoved);
1062 _model.StructureChanged -= new EventHandler<TreePathEventArgs>(_model_StructureChanged);
1065 private void _model_StructureChanged(object sender, TreePathEventArgs e)
1067 if (e.Path == null)
1068 throw new ArgumentNullException();
1070 TreeNodeAdv node = FindNode(e.Path);
1071 if (node != null)
1073 if (node != Root)
1074 node.IsLeaf = Model.IsLeaf(GetPath(node));
1076 var list = new Dictionary<object, object>();
1077 SaveExpandedNodes(node, list);
1078 ReadChilds(node);
1079 RestoreExpandedNodes(node, list);
1081 UpdateSelection();
1082 SmartFullUpdate();
1084 //else
1085 // throw new ArgumentException("Path not found");
1088 private void RestoreExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
1090 if (node.Tag != null && list.ContainsKey(node.Tag))
1092 node.IsExpanded = true;
1093 foreach (var child in node.Children)
1094 RestoreExpandedNodes(child, list);
1098 private void SaveExpandedNodes(TreeNodeAdv node, Dictionary<object, object> list)
1100 if (node.IsExpanded && node.Tag != null)
1102 list.Add(node.Tag, null);
1103 foreach (var child in node.Children)
1104 SaveExpandedNodes(child, list);
1108 private void _model_NodesRemoved(object sender, TreeModelEventArgs e)
1110 TreeNodeAdv parent = FindNode(e.Path);
1111 if (parent != null)
1113 if (e.Indices != null)
1115 List<int> list = new List<int>(e.Indices);
1116 list.Sort();
1117 for (int n = list.Count - 1; n >= 0; n--)
1119 int index = list[n];
1120 if (index >= 0 && index <= parent.Nodes.Count)
1121 parent.Nodes.RemoveAt(index);
1122 else
1123 throw new ArgumentOutOfRangeException("Index out of range");
1126 else
1128 for (int i = parent.Nodes.Count - 1; i >= 0; i--)
1130 for (int n = 0; n < e.Children.Length; n++)
1131 if (parent.Nodes[i].Tag == e.Children[n])
1133 parent.Nodes.RemoveAt(i);
1134 break;
1139 UpdateSelection();
1140 SmartFullUpdate();
1143 private void _model_NodesInserted(object sender, TreeModelEventArgs e)
1145 if (e.Indices == null)
1146 throw new ArgumentNullException("Indices");
1148 TreeNodeAdv parent = FindNode(e.Path);
1149 if (parent != null)
1151 for (int i = 0; i < e.Children.Length; i++)
1152 AddNewNode(parent, e.Children[i], e.Indices[i]);
1154 SmartFullUpdate();
1157 private void _model_NodesChanged(object sender, TreeModelEventArgs e)
1159 TreeNodeAdv parent = FindNode(e.Path);
1160 if (parent != null && parent.IsVisible && parent.IsExpanded)
1162 if (InvokeRequired)
1163 BeginInvoke(new UpdateContentWidthDelegate(ClearNodesSize), e, parent);
1164 else
1165 ClearNodesSize(e, parent);
1166 SmartFullUpdate();
1170 private delegate void UpdateContentWidthDelegate(TreeModelEventArgs e, TreeNodeAdv parent);
1171 private void ClearNodesSize(TreeModelEventArgs e, TreeNodeAdv parent)
1173 if (e.Indices != null)
1175 foreach (int index in e.Indices)
1177 if (index >= 0 && index < parent.Nodes.Count)
1179 TreeNodeAdv node = parent.Nodes[index];
1180 node.Height = node.RightBounds = null;
1182 else
1183 throw new ArgumentOutOfRangeException("Index out of range");
1186 else
1188 foreach (TreeNodeAdv node in parent.Nodes)
1190 foreach (object obj in e.Children)
1191 if (node.Tag == obj)
1193 node.Height = node.RightBounds = null;
1198 #endregion