Analysis-Services/AlmToolkit/BismNormalizer/TabularCompare/UI/TreeGridCell.cs
2023-09-28 08:08:39 -07:00

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; }
}
}
}