// Copyright (C) Stichting Deltares 2016. All rights preserved.
//
// This file is part of Ringtoets.
//
// Ringtoets is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights preserved.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace Core.Common.Controls.TreeView
{
public static class TreeNodeGraphicExtensions
{
private const int defaultImageWidth = 16;
private const int defaultImageHeight = 16;
private const int spaceBetweenNodeParts = 2;
///
/// Checks if the is on the checkbox of the node
///
/// Node to check for
/// Point to search for
public static bool IsOnCheckBox(this TreeNode node, Point point)
{
var topOffset = (node.Bounds.Height - defaultImageHeight)/2;
var rectangle = new Rectangle(GetCheckBoxLeft(node), node.Bounds.Top + topOffset, defaultImageWidth, defaultImageHeight);
return rectangle.Contains(point);
}
///
/// Draws a tree node using the boundaries of the node
///
/// Node to draw
/// The to use while drawing the node.
/// Graphic to draw on
/// Is node in selected state
public static void DrawNode(this TreeNode node, TreeNodeInfo treeNodeInfo, Graphics graphics, bool selected)
{
if (node.Bounds.Height == 0) // Nothing to draw
{
return;
}
DrawText(graphics, node, treeNodeInfo, selected);
if (treeNodeInfo.CanCheck != null && treeNodeInfo.CanCheck(node.Tag))
{
DrawCheckbox(graphics, node);
}
if (treeNodeInfo.Image != null)
{
DrawImage(graphics, node, treeNodeInfo);
}
}
///
/// Draws a placeholder for the node on the indicated location
///
/// Node to draw the placeholder for
/// Location of the placeholder
/// Graphics to draw on
public static void DrawPlaceHolder(this TreeNode node, PlaceholderLocation location, Graphics graphics)
{
var rightTriangle = node.MakePlaceHoldeTriangle(AnchorStyles.Right, location);
graphics.FillPolygon(Brushes.Black, rightTriangle);
if (location == PlaceholderLocation.Middle)
{
return;
}
var leftTriangle = node.MakePlaceHoldeTriangle(AnchorStyles.Left, location);
graphics.FillPolygon(Brushes.Black, leftTriangle);
var yLine = location == PlaceholderLocation.Top
? node.Bounds.Top
: node.Bounds.Bottom;
graphics.DrawLine(new Pen(Color.Black, 1), new Point(GetCheckBoxLeft(node), yLine), new Point(node.Bounds.Right, yLine));
}
private static Point[] MakePlaceHoldeTriangle(this TreeNode node, AnchorStyles anchor, PlaceholderLocation location)
{
const int placeHolderWidth = 4;
const int placeHolderHeigth = 8;
int xPos, yPos;
var bounds = node.Bounds;
switch (anchor)
{
case AnchorStyles.Left:
xPos = GetCheckBoxLeft(node) - placeHolderWidth;
break;
case AnchorStyles.Right:
xPos = bounds.Right;
break;
default:
return new Point[0];
}
switch (location)
{
case PlaceholderLocation.Top:
yPos = bounds.Top;
break;
case PlaceholderLocation.Bottom:
yPos = bounds.Bottom;
break;
case PlaceholderLocation.Middle:
yPos = bounds.Top + bounds.Height/2;
break;
default:
throw new ArgumentOutOfRangeException("location");
}
return CreateTrianglePoints(new Rectangle(xPos, yPos - placeHolderWidth, placeHolderWidth, placeHolderHeigth), anchor);
}
private static void DrawText(Graphics graphics, TreeNode node, TreeNodeInfo treeNodeInfo, bool selected)
{
if (node.IsEditing && node.IsSelected)
{
return;
}
var bounds = node.Bounds;
var treeView = node.TreeView;
var foreColor = selected && treeView.Focused
? SystemColors.HighlightText
: node.ForeColor != Color.Empty ? node.ForeColor : treeView.ForeColor;
var backgroundColor = selected
? treeView.Focused ? SystemColors.Highlight : Color.FromArgb(255, 232, 232, 232)
: node.BackColor != Color.Empty
? node.BackColor
: treeView.BackColor;
var font = new Font(node.NodeFont ?? treeView.Font, FontStyle.Regular);
var topOffset = (node.Bounds.Height - TextRenderer.MeasureText(node.Text, font).Height)/2;
var startPoint = new Point(GetTextLeft(node, treeNodeInfo), bounds.Top + topOffset);
var drawingBounds = treeView.FullRowSelect
? new Rectangle(0, bounds.Top, treeView.Width, bounds.Height)
: new Rectangle(GetTextLeft(node, treeNodeInfo), bounds.Top, bounds.Width, bounds.Height);
graphics.FillRectangle(new SolidBrush(backgroundColor), drawingBounds);
TextRenderer.DrawText(graphics, node.Text, font, startPoint, foreColor, backgroundColor, TextFormatFlags.Default);
if (selected)
{
ControlPaint.DrawFocusRectangle(graphics, drawingBounds, foreColor, SystemColors.Highlight);
}
}
private static void DrawCheckbox(Graphics graphics, TreeNode node)
{
var topOffset = (node.Bounds.Height - defaultImageHeight)/2;
var imgRect = new Rectangle(GetCheckBoxLeft(node), node.Bounds.Top + topOffset, defaultImageWidth, defaultImageHeight);
if (Application.RenderWithVisualStyles)
{
var point = new Point(imgRect.Left + spaceBetweenNodeParts, imgRect.Top + 2);
CheckBoxRenderer.DrawCheckBox(graphics, point,
node.Checked
? CheckBoxState.CheckedNormal
: CheckBoxState.UncheckedNormal);
}
else
{
ControlPaint.DrawCheckBox(graphics, imgRect,
(node.Checked ? ButtonState.Checked : ButtonState.Normal) |
ButtonState.Flat);
}
}
private static void DrawImage(Graphics graphics, TreeNode node, TreeNodeInfo treeNodeInfo)
{
var image = treeNodeInfo.Image(node.Tag);
var graphicsUnit = GraphicsUnit.Pixel;
var topOffset = (node.Bounds.Height - defaultImageHeight)/2;
var imgRect = new Rectangle(GetImageLeft(node, treeNodeInfo), node.Bounds.Top + topOffset, defaultImageWidth, defaultImageHeight);
graphics.DrawImage(image, imgRect, image.GetBounds(ref graphicsUnit), graphicsUnit);
}
private static int GetCheckBoxLeft(TreeNode node)
{
return node.Bounds.Left - (defaultImageWidth + spaceBetweenNodeParts);
}
private static int GetImageLeft(TreeNode node, TreeNodeInfo treeNodeInfo)
{
var xCheckBox = GetCheckBoxLeft(node);
return treeNodeInfo.CanCheck != null && treeNodeInfo.CanCheck(node.Tag)
? xCheckBox + defaultImageWidth + spaceBetweenNodeParts
: xCheckBox;
}
private static int GetTextLeft(TreeNode node, TreeNodeInfo treeNodeInfo)
{
var xImage = GetImageLeft(node, treeNodeInfo);
return treeNodeInfo.Image != null && treeNodeInfo.Image(node.Tag) != null
? xImage + defaultImageWidth + spaceBetweenNodeParts
: xImage;
}
private static Point[] CreateTrianglePoints(Rectangle bounds, AnchorStyles anchor)
{
switch (anchor)
{
case AnchorStyles.Left:
return new[]
{
new Point(bounds.Left, bounds.Top),
new Point(bounds.Right, bounds.Top + bounds.Height/2),
new Point(bounds.Left, bounds.Top + bounds.Height),
new Point(bounds.Left, bounds.Top)
};
case AnchorStyles.Right:
return new[]
{
new Point(bounds.Right, bounds.Top),
new Point(bounds.Left, bounds.Top + bounds.Height/2),
new Point(bounds.Right, bounds.Top + bounds.Height),
new Point(bounds.Right, bounds.Top)
};
default:
return new Point[0];
}
}
}
}