314 lines
10 KiB
C#
314 lines
10 KiB
C#
|
using System;
|
||
|
using System.Windows.Forms;
|
||
|
using System.Drawing;
|
||
|
using System.Windows.Forms.VisualStyles;
|
||
|
using System.Diagnostics;
|
||
|
|
||
|
namespace BismNormalizer.TabularCompare.UI
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Summary description for TreeGridCell.
|
||
|
/// </summary>
|
||
|
public class TreeGridCell:DataGridViewTextBoxCell
|
||
|
{
|
||
|
private const int INDENT_WIDTH = 20;
|
||
|
private const int INDENT_MARGIN = 5;
|
||
|
private int glyphWidth;
|
||
|
private int calculatedLeftPadding;
|
||
|
internal bool IsSited;
|
||
|
private Padding _previousPadding;
|
||
|
private int _imageWidth = 0, _imageHeight = 0, _imageHeightOffset = 0;
|
||
|
|
||
|
public TreeGridCell()
|
||
|
{
|
||
|
glyphWidth = 15;
|
||
|
calculatedLeftPadding = 0;
|
||
|
this.IsSited = false;
|
||
|
|
||
|
}
|
||
|
|
||
|
public override object Clone()
|
||
|
{
|
||
|
TreeGridCell c = (TreeGridCell)base.Clone();
|
||
|
|
||
|
c.glyphWidth = this.glyphWidth;
|
||
|
c.calculatedLeftPadding = this.calculatedLeftPadding;
|
||
|
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
internal protected virtual void UnSited()
|
||
|
{
|
||
|
// The row this cell is in is being removed from the grid.
|
||
|
this.IsSited = false;
|
||
|
this.Style.Padding = this._previousPadding;
|
||
|
}
|
||
|
|
||
|
internal protected virtual void Sited()
|
||
|
{
|
||
|
// when we are added to the DGV we can realize our style
|
||
|
this.IsSited = true;
|
||
|
|
||
|
// remember what the previous padding size is so it can be restored when unsiting
|
||
|
this._previousPadding = this.Style.Padding;
|
||
|
|
||
|
this.UpdateStyle();
|
||
|
}
|
||
|
|
||
|
internal protected virtual void UpdateStyle(){
|
||
|
// styles shouldn't be modified when we are not sited.
|
||
|
if (this.IsSited == false) return;
|
||
|
|
||
|
int level = this.Level;
|
||
|
|
||
|
Padding p = this._previousPadding;
|
||
|
Size preferredSize;
|
||
|
|
||
|
using (Graphics g = this.OwningNode._grid.CreateGraphics() ) {
|
||
|
preferredSize =this.GetPreferredSize(g, this.InheritedStyle, this.RowIndex, new Size(0, 0));
|
||
|
}
|
||
|
|
||
|
Image image = this.OwningNode.Image;
|
||
|
|
||
|
if (image != null)
|
||
|
{
|
||
|
// calculate image size
|
||
|
_imageWidth = image.Width+2;
|
||
|
_imageHeight = image.Height+2;
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_imageWidth = glyphWidth;
|
||
|
_imageHeight = 0;
|
||
|
}
|
||
|
|
||
|
//Commented out after found KPI Lake performance issue
|
||
|
//// TO_DO: Make this cleaner
|
||
|
//if (preferredSize.Height < _imageHeight)
|
||
|
//{
|
||
|
|
||
|
// this.Style.Padding = new Padding(p.Left + (level * INDENT_WIDTH) + _imageWidth + INDENT_MARGIN,
|
||
|
// p.Top + (_imageHeight / 2), p.Right, p.Bottom + (_imageHeight / 2));
|
||
|
// _imageHeightOffset = 2;// (_imageHeight - preferredSize.Height) / 2;
|
||
|
//}
|
||
|
//else
|
||
|
//{
|
||
|
// this.Style.Padding = new Padding(p.Left + (level * INDENT_WIDTH) + _imageWidth + INDENT_MARGIN,
|
||
|
// p.Top , p.Right, p.Bottom );
|
||
|
|
||
|
//}
|
||
|
|
||
|
calculatedLeftPadding = ((level - 1) * glyphWidth) + _imageWidth + INDENT_MARGIN;
|
||
|
}
|
||
|
|
||
|
public int Level
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
TreeGridNode row = this.OwningNode;
|
||
|
if (row != null)
|
||
|
{
|
||
|
return row.Level;
|
||
|
}
|
||
|
else
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
protected virtual int GlyphMargin => ((this.Level - 1) * INDENT_WIDTH) + INDENT_MARGIN;
|
||
|
|
||
|
protected virtual int GlyphOffset => ((this.Level - 1) * INDENT_WIDTH);
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
|
||
|
TreeGridNode node = this.OwningNode;
|
||
|
if (node == null) return;
|
||
|
|
||
|
Image image = node.Image;
|
||
|
|
||
|
if (this._imageHeight == 0 && image != null) this.UpdateStyle();
|
||
|
|
||
|
// paint the cell normally
|
||
|
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
|
||
|
|
||
|
float dpiFactor = Utils.GetDpiFactor();
|
||
|
int scaleBack = (dpiFactor > 1 ? Convert.ToInt32(dpiFactor) : 0);
|
||
|
|
||
|
// TO_DO: Indent width needs to take image size into account
|
||
|
Rectangle glyphRect = new Rectangle(cellBounds.X + this.GlyphMargin - scaleBack, cellBounds.Y - scaleBack, INDENT_WIDTH, cellBounds.Height - 1);
|
||
|
int glyphHalf = glyphRect.Width / 2;
|
||
|
|
||
|
//TO_DO: This painting code needs to be rehashed to be cleaner
|
||
|
int level = this.Level;
|
||
|
|
||
|
//TO_DO: Rehash this to take different Imagelayouts into account. This will speed up drawing
|
||
|
// for images of the same size (ImageLayout.None)
|
||
|
if (image != null)
|
||
|
{
|
||
|
Point pp;
|
||
|
if (_imageHeight > cellBounds.Height)
|
||
|
pp = new Point(glyphRect.X + this.glyphWidth, cellBounds.Y + _imageHeightOffset);
|
||
|
else
|
||
|
pp = new Point(glyphRect.X + this.glyphWidth, (cellBounds.Height / 2 - _imageHeight / 2) + cellBounds.Y);
|
||
|
|
||
|
// Graphics container to push/pop changes. This enables us to set clipping when painting
|
||
|
// the cell's image -- keeps it from bleeding outsize of cells.
|
||
|
System.Drawing.Drawing2D.GraphicsContainer gc = graphics.BeginContainer();
|
||
|
{
|
||
|
graphics.SetClip(cellBounds);
|
||
|
graphics.DrawImageUnscaled(image, pp);
|
||
|
}
|
||
|
graphics.EndContainer(gc);
|
||
|
}
|
||
|
|
||
|
// Paint tree lines
|
||
|
if (node._grid.ShowLines)
|
||
|
{
|
||
|
using (Pen linePen = new Pen(SystemBrushes.ControlDark, 1.0f))
|
||
|
{
|
||
|
linePen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
|
||
|
bool isLastSibling = node.IsLastSibling;
|
||
|
bool isFirstSibling = node.IsFirstSibling;
|
||
|
if (node.Level == 1)
|
||
|
{
|
||
|
// the Root nodes display their lines differently
|
||
|
if (isFirstSibling && isLastSibling)
|
||
|
{
|
||
|
// only node, both first and last. Just draw horizontal line
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
|
||
|
}
|
||
|
else if (isLastSibling)
|
||
|
{
|
||
|
// last sibling doesn't draw the line extended below. Paint horizontal then vertical
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2);
|
||
|
}
|
||
|
else if (isFirstSibling)
|
||
|
{
|
||
|
// first sibling doesn't draw the line extended above. Paint horizontal then vertical
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.X + 4, cellBounds.Bottom);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// normal drawing draws extended from top to bottom. Paint horizontal then vertical
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Bottom);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (isLastSibling)
|
||
|
{
|
||
|
// last sibling doesn't draw the line extended below. Paint horizontal then vertical
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// normal drawing draws extended from top to bottom. Paint horizontal then vertical
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top + cellBounds.Height / 2, glyphRect.Right, cellBounds.Top + cellBounds.Height / 2);
|
||
|
graphics.DrawLine(linePen, glyphRect.X + 4, cellBounds.Top, glyphRect.X + 4, cellBounds.Bottom);
|
||
|
}
|
||
|
|
||
|
// paint lines of previous levels to the root
|
||
|
TreeGridNode previousNode = node.Parent;
|
||
|
int horizontalStop = (glyphRect.X + 4) - INDENT_WIDTH;
|
||
|
|
||
|
while (!previousNode.IsRoot)
|
||
|
{
|
||
|
if (previousNode.HasChildren && !previousNode.IsLastSibling)
|
||
|
{
|
||
|
// paint vertical line
|
||
|
graphics.DrawLine(linePen, horizontalStop, cellBounds.Top, horizontalStop, cellBounds.Bottom);
|
||
|
}
|
||
|
previousNode = previousNode.Parent;
|
||
|
horizontalStop = horizontalStop - INDENT_WIDTH;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Commented out after found KPI Lake performance issue
|
||
|
// if (dpiFactor > 1) dpiFactor = dpiFactor * HighDPIUtils.PrimaryFudgeFactor;
|
||
|
// float size = 10 * dpiFactor;
|
||
|
|
||
|
//if (node.HasChildren || node._grid.VirtualNodes)
|
||
|
//{
|
||
|
// if (((TreeGridView)this.DataGridView).ImageList.Images.Count > 0)
|
||
|
// {
|
||
|
// // Paint node glyphs
|
||
|
// if (node.IsExpanded)
|
||
|
// {
|
||
|
// graphics.DrawImage(((TreeGridView)this.DataGridView).ImageList.Images[10], glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, size, size);
|
||
|
// }
|
||
|
// else
|
||
|
// {
|
||
|
// graphics.DrawImage(((TreeGridView)this.DataGridView).ImageList.Images[9], glyphRect.X, glyphRect.Y + (glyphRect.Height / 2) - 4, size, size);
|
||
|
// }
|
||
|
// }
|
||
|
//}
|
||
|
|
||
|
|
||
|
}
|
||
|
protected override void OnMouseUp(DataGridViewCellMouseEventArgs e)
|
||
|
{
|
||
|
base.OnMouseUp(e);
|
||
|
|
||
|
TreeGridNode node = this.OwningNode;
|
||
|
if (node != null)
|
||
|
node._grid._inExpandCollapseMouseCapture = false;
|
||
|
}
|
||
|
protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
|
||
|
{
|
||
|
if (e.Location.X > this.InheritedStyle.Padding.Left)
|
||
|
{
|
||
|
base.OnMouseDown(e);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Expand the node
|
||
|
//TO_DO: Calculate more precise location
|
||
|
TreeGridNode node = this.OwningNode;
|
||
|
if (node != null)
|
||
|
{
|
||
|
node._grid._inExpandCollapseMouseCapture = true;
|
||
|
if (node.IsExpanded)
|
||
|
node.Collapse();
|
||
|
else
|
||
|
node.Expand();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
public TreeGridNode OwningNode => base.OwningRow as TreeGridNode;
|
||
|
}
|
||
|
|
||
|
public class TreeGridColumn : DataGridViewTextBoxColumn
|
||
|
{
|
||
|
internal Image _defaultNodeImage;
|
||
|
|
||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
|
||
|
public TreeGridColumn()
|
||
|
{
|
||
|
this.CellTemplate = new TreeGridCell();
|
||
|
}
|
||
|
|
||
|
// Need to override Clone for design-time support.
|
||
|
public override object Clone()
|
||
|
{
|
||
|
TreeGridColumn c = (TreeGridColumn)base.Clone();
|
||
|
c._defaultNodeImage = this._defaultNodeImage;
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
public Image DefaultNodeImage
|
||
|
{
|
||
|
get { return _defaultNodeImage; }
|
||
|
set { _defaultNodeImage = value; }
|
||
|
}
|
||
|
}
|
||
|
}
|