TreeGridCell.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. //---------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. //
  5. //THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
  6. //KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  7. //IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  8. //PARTICULAR PURPOSE.
  9. //---------------------------------------------------------------------
  10. using System;
  11. using System.Windows.Forms;
  12. using System.Drawing;
  13. using System.Windows.Forms.VisualStyles;
  14. using System.Diagnostics;
  15. namespace AdvancedDataGridView
  16. {
  17. /// <summary>
  18. /// Summary description for TreeGridCell.
  19. /// </summary>
  20. public class TreeGridCell:DataGridViewTextBoxCell
  21. {
  22. private const int INDENT_WIDTH = 20;
  23. private const int INDENT_MARGIN = 5;
  24. private int glyphWidth;
  25. private int calculatedLeftPadding;
  26. internal bool IsSited;
  27. private Padding _previousPadding;
  28. private int _imageWidth = 0, _imageHeight = 0, _imageHeightOffset = 0;
  29. //private Rectangle _lastKnownGlyphRect;
  30. public TreeGridCell()
  31. {
  32. glyphWidth = 15;
  33. calculatedLeftPadding = 0;
  34. this.IsSited = false;
  35. }
  36. public override object Clone()
  37. {
  38. TreeGridCell c = (TreeGridCell)base.Clone();
  39. c.glyphWidth = this.glyphWidth;
  40. c.calculatedLeftPadding = this.calculatedLeftPadding;
  41. return c;
  42. }
  43. internal protected virtual void UnSited()
  44. {
  45. // The row this cell is in is being removed from the grid.
  46. this.IsSited = false;
  47. this.Style.Padding = this._previousPadding;
  48. }
  49. internal protected virtual void Sited()
  50. {
  51. // when we are added to the DGV we can realize our style
  52. this.IsSited = true;
  53. // remember what the previous padding size is so it can be restored when unsiting
  54. this._previousPadding = this.Style.Padding;
  55. this.UpdateStyle();
  56. }
  57. internal protected virtual void UpdateStyle(){
  58. // styles shouldn't be modified when we are not sited.
  59. if (this.IsSited == false) return;
  60. int level = this.Level;
  61. Padding p = this._previousPadding;
  62. Size preferredSize;
  63. using (Graphics g = this.OwningNode._grid.CreateGraphics() ) {
  64. preferredSize =this.GetPreferredSize(g, this.InheritedStyle, this.RowIndex, new Size(0, 0));
  65. }
  66. Image image = this.OwningNode.Image;
  67. if (image != null)
  68. {
  69. // calculate image size
  70. _imageWidth = image.Width+2;
  71. _imageHeight = image.Height+2;
  72. }
  73. else
  74. {
  75. _imageWidth = glyphWidth;
  76. _imageHeight = 0;
  77. }
  78. // TODO: Make this cleaner
  79. if (preferredSize.Height < _imageHeight)
  80. {
  81. this.Style.Padding = new Padding(p.Left + (level * INDENT_WIDTH) + _imageWidth + INDENT_MARGIN,
  82. p.Top + (_imageHeight / 2), p.Right, p.Bottom + (_imageHeight / 2));
  83. _imageHeightOffset = 2;// (_imageHeight - preferredSize.Height) / 2;
  84. }
  85. else
  86. {
  87. this.Style.Padding = new Padding(p.Left + (level * INDENT_WIDTH) + _imageWidth + INDENT_MARGIN,
  88. p.Top , p.Right, p.Bottom );
  89. }
  90. calculatedLeftPadding = ((level - 1) * glyphWidth) + _imageWidth + INDENT_MARGIN;
  91. }
  92. public int Level
  93. {
  94. get
  95. {
  96. TreeGridNode row = this.OwningNode;
  97. if (row != null)
  98. {
  99. return row.Level;
  100. }
  101. else
  102. return -1;
  103. }
  104. }
  105. protected virtual int GlyphMargin
  106. {
  107. get
  108. {
  109. return ((this.Level - 1) * INDENT_WIDTH) + INDENT_MARGIN;
  110. }
  111. }
  112. protected virtual int GlyphOffset
  113. {
  114. get
  115. {
  116. return ((this.Level - 1) * INDENT_WIDTH);
  117. }
  118. }
  119. protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
  120. {
  121. TreeGridNode node = this.OwningNode;
  122. if (node == null) return;
  123. Image image = node.Image;
  124. if (this._imageHeight == 0 && image != null) this.UpdateStyle();
  125. // paint the cell normally
  126. base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
  127. // TODO: Indent width needs to take image size into account
  128. Rectangle glyphRect = new Rectangle(cellBounds.X + this.GlyphMargin, cellBounds.Y, INDENT_WIDTH, cellBounds.Height - 1);
  129. int glyphHalf = glyphRect.Width / 2;
  130. //TODO: This painting code needs to be rehashed to be cleaner
  131. int level = this.Level;
  132. //TODO: Rehash this to take different Imagelayouts into account. This will speed up drawing
  133. // for images of the same size (ImageLayout.None)
  134. if (image != null)
  135. {
  136. Point pp;
  137. if (_imageHeight > cellBounds.Height)
  138. pp = new Point(glyphRect.X + this.glyphWidth, cellBounds.Y + _imageHeightOffset);
  139. else
  140. pp = new Point(glyphRect.X + this.glyphWidth, (cellBounds.Height / 2 - _imageHeight / 2) + cellBounds.Y);
  141. // Graphics container to push/pop changes. This enables us to set clipping when painting
  142. // the cell's image -- keeps it from bleeding outsize of cells.
  143. System.Drawing.Drawing2D.GraphicsContainer gc = graphics.BeginContainer();
  144. {
  145. graphics.SetClip(cellBounds);
  146. graphics.DrawImageUnscaled(image, pp);
  147. }
  148. graphics.EndContainer(gc);
  149. }
  150. // Paint tree lines
  151. if (node._grid.ShowLines)
  152. {
  153. using (Pen linePen = new Pen(SystemBrushes.ControlDark, 1.0f))
  154. {
  155. linePen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
  156. bool isLastSibling = node.IsLastSibling;
  157. bool isFirstSibling = node.IsFirstSibling;
  158. if (node.Level == 1)
  159. {
  160. // the Root nodes display their lines differently
  161. if (isFirstSibling && isLastSibling)
  162. {
  163. // only node, both first and last. Just draw horizontal line
  164. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
  165. }
  166. else if (isLastSibling)
  167. {
  168. // last sibling doesn't draw the line extended below. Paint horizontal then vertical
  169. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
  170. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2);
  171. }
  172. else if (isFirstSibling)
  173. {
  174. // first sibling doesn't draw the line extended above. Paint horizontal then vertical
  175. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
  176. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.X + 4, cellBounds.Bottom);
  177. }
  178. else
  179. {
  180. // normal drawing draws extended from top to bottom. Paint horizontal then vertical
  181. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
  182. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Bottom);
  183. }
  184. }
  185. else
  186. {
  187. if (isLastSibling)
  188. {
  189. // last sibling doesn't draw the line extended below. Paint horizontal then vertical
  190. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
  191. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2);
  192. }
  193. else
  194. {
  195. // normal drawing draws extended from top to bottom. Paint horizontal then vertical
  196. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
  197. graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Bottom);
  198. }
  199. // paint lines of previous levels to the root
  200. TreeGridNode previousNode = node.Parent;
  201. int horizontalStop = (glyphRect.X + 4) - INDENT_WIDTH;
  202. while (!previousNode.IsRoot)
  203. {
  204. if (previousNode.HasChildren && !previousNode.IsLastSibling)
  205. {
  206. // paint vertical line
  207. graphics.DrawLine(linePen, horizontalStop, cellBounds.Top, horizontalStop, cellBounds.Bottom);
  208. }
  209. previousNode = previousNode.Parent;
  210. horizontalStop = horizontalStop - INDENT_WIDTH;
  211. }
  212. }
  213. }
  214. }
  215. if (node.HasChildren || node._grid.VirtualNodes)
  216. {
  217. // Paint node glyphs
  218. if (node.IsExpanded)
  219. node._grid.rOpen.DrawBackground(graphics, new Rectangle(glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, 10, 10));
  220. else
  221. node._grid.rClosed.DrawBackground(graphics, new Rectangle(glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, 10, 10));
  222. }
  223. }
  224. protected override void OnMouseUp(DataGridViewCellMouseEventArgs e)
  225. {
  226. base.OnMouseUp(e);
  227. TreeGridNode node = this.OwningNode;
  228. if (node != null)
  229. node._grid._inExpandCollapseMouseCapture = false;
  230. }
  231. protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
  232. {
  233. if (e.Location.X > this.InheritedStyle.Padding.Left)
  234. {
  235. base.OnMouseDown(e);
  236. }
  237. else
  238. {
  239. // Expand the node
  240. //TODO: Calculate more precise location
  241. TreeGridNode node = this.OwningNode;
  242. if (node != null)
  243. {
  244. node._grid._inExpandCollapseMouseCapture = true;
  245. if (node.IsExpanded)
  246. node.Collapse();
  247. else
  248. node.Expand();
  249. }
  250. }
  251. }
  252. public TreeGridNode OwningNode
  253. {
  254. get { return base.OwningRow as TreeGridNode; }
  255. }
  256. }
  257. public class TreeGridColumn : DataGridViewTextBoxColumn
  258. {
  259. internal Image _defaultNodeImage;
  260. public TreeGridColumn()
  261. {
  262. this.CellTemplate = new TreeGridCell();
  263. }
  264. // Need to override Clone for design-time support.
  265. public override object Clone()
  266. {
  267. TreeGridColumn c = (TreeGridColumn)base.Clone();
  268. c._defaultNodeImage = this._defaultNodeImage;
  269. return c;
  270. }
  271. public Image DefaultNodeImage
  272. {
  273. get { return _defaultNodeImage; }
  274. set { _defaultNodeImage = value; }
  275. }
  276. }
  277. }