------ #### ryControls V2.1.2101.1201 - *.[更新]内置的ObjectListView从1.13更新到2.9.1版本,并对主要属性进行汉化。 - *.[修复]修复新版ObjectListView选中项有筛选结果时,筛选结果白色字体看不清的BUG。 - *.[改进]TextBoxEx2默认事件改为TextChanged2。
309 lines
12 KiB
C#
309 lines
12 KiB
C#
/*
|
|
* TreeRenderer - Draw the major column in a TreeListView
|
|
*
|
|
* Author: Phillip Piper
|
|
* Date: 27/06/2015
|
|
*
|
|
* Change log:
|
|
* 2016-07-17 JPP - Added TreeRenderer.UseTriangles and IsShowGlyphs
|
|
* 2015-06-27 JPP - Split out from TreeListView.cs
|
|
*
|
|
*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using System.Windows.Forms.VisualStyles;
|
|
using System.Drawing.Drawing2D;
|
|
|
|
namespace BrightIdeasSoftware {
|
|
|
|
public partial class TreeListView {
|
|
/// <summary>
|
|
/// This class handles drawing the tree structure of the primary column.
|
|
/// </summary>
|
|
public class TreeRenderer : HighlightTextRenderer {
|
|
/// <summary>
|
|
/// Create a TreeRenderer
|
|
/// </summary>
|
|
public TreeRenderer() {
|
|
this.LinePen = new Pen(Color.Blue, 1.0f);
|
|
this.LinePen.DashStyle = DashStyle.Dot;
|
|
}
|
|
|
|
#region Configuration properties
|
|
|
|
/// <summary>
|
|
/// Should the renderer draw glyphs at the expansion points?
|
|
/// </summary>
|
|
/// <remarks>The expansion points will still function to expand/collapse even if this is false.</remarks>
|
|
public bool IsShowGlyphs
|
|
{
|
|
get { return isShowGlyphs; }
|
|
set { isShowGlyphs = value; }
|
|
}
|
|
private bool isShowGlyphs = true;
|
|
|
|
/// <summary>
|
|
/// Should the renderer draw lines connecting siblings?
|
|
/// </summary>
|
|
public bool IsShowLines
|
|
{
|
|
get { return isShowLines; }
|
|
set { isShowLines = value; }
|
|
}
|
|
private bool isShowLines = true;
|
|
|
|
/// <summary>
|
|
/// Return the pen that will be used to draw the lines between branches
|
|
/// </summary>
|
|
public Pen LinePen
|
|
{
|
|
get { return linePen; }
|
|
set { linePen = value; }
|
|
}
|
|
private Pen linePen;
|
|
|
|
/// <summary>
|
|
/// Should the renderer draw triangles as the expansion glyphs?
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This looks best with ShowLines = false
|
|
/// </remarks>
|
|
public bool UseTriangles
|
|
{
|
|
get { return useTriangles; }
|
|
set { useTriangles = value; }
|
|
}
|
|
private bool useTriangles = false;
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Return the branch that the renderer is currently drawing.
|
|
/// </summary>
|
|
private Branch Branch {
|
|
get {
|
|
return this.TreeListView.TreeModel.GetBranch(this.RowObject);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return the TreeListView for which the renderer is being used.
|
|
/// </summary>
|
|
public TreeListView TreeListView {
|
|
get {
|
|
return (TreeListView)this.ListView;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// How many pixels will be reserved for each level of indentation?
|
|
/// </summary>
|
|
public static int PIXELS_PER_LEVEL = 16 + 1;
|
|
|
|
/// <summary>
|
|
/// The real work of drawing the tree is done in this method
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="r"></param>
|
|
public override void Render(System.Drawing.Graphics g, System.Drawing.Rectangle r) {
|
|
this.DrawBackground(g, r);
|
|
|
|
Branch br = this.Branch;
|
|
|
|
Rectangle paddedRectangle = this.ApplyCellPadding(r);
|
|
|
|
Rectangle expandGlyphRectangle = paddedRectangle;
|
|
expandGlyphRectangle.Offset((br.Level - 1) * PIXELS_PER_LEVEL, 0);
|
|
expandGlyphRectangle.Width = PIXELS_PER_LEVEL;
|
|
expandGlyphRectangle.Height = PIXELS_PER_LEVEL;
|
|
expandGlyphRectangle.Y = this.AlignVertically(paddedRectangle, expandGlyphRectangle);
|
|
int expandGlyphRectangleMidVertical = expandGlyphRectangle.Y + (expandGlyphRectangle.Height/2);
|
|
|
|
if (this.IsShowLines)
|
|
this.DrawLines(g, r, this.LinePen, br, expandGlyphRectangleMidVertical);
|
|
|
|
if (br.CanExpand && this.IsShowGlyphs)
|
|
this.DrawExpansionGlyph(g, expandGlyphRectangle, br.IsExpanded);
|
|
|
|
int indent = br.Level * PIXELS_PER_LEVEL;
|
|
paddedRectangle.Offset(indent, 0);
|
|
paddedRectangle.Width -= indent;
|
|
|
|
this.DrawImageAndText(g, paddedRectangle);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw the expansion indicator
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="r"></param>
|
|
/// <param name="isExpanded"></param>
|
|
protected virtual void DrawExpansionGlyph(Graphics g, Rectangle r, bool isExpanded) {
|
|
if (this.UseStyles) {
|
|
this.DrawExpansionGlyphStyled(g, r, isExpanded);
|
|
} else {
|
|
this.DrawExpansionGlyphManual(g, r, isExpanded);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets whether or not we should render using styles
|
|
/// </summary>
|
|
protected virtual bool UseStyles {
|
|
get {
|
|
return !this.IsPrinting && Application.RenderWithVisualStyles;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw the expansion indicator using styles
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="r"></param>
|
|
/// <param name="isExpanded"></param>
|
|
protected virtual void DrawExpansionGlyphStyled(Graphics g, Rectangle r, bool isExpanded) {
|
|
if (this.UseTriangles && this.IsShowLines) {
|
|
using (SolidBrush b = new SolidBrush(GetBackgroundColor())) {
|
|
Rectangle r2 = r;
|
|
r2.Inflate(-2, -2);
|
|
g.FillRectangle(b, r2);
|
|
}
|
|
}
|
|
|
|
VisualStyleRenderer renderer = new VisualStyleRenderer(DecideVisualElement(isExpanded));
|
|
renderer.DrawBackground(g, r);
|
|
}
|
|
|
|
private VisualStyleElement DecideVisualElement(bool isExpanded) {
|
|
string klass = this.UseTriangles ? "Explorer::TreeView" : "TREEVIEW";
|
|
int part = this.UseTriangles && this.IsExpansionHot ? 4 : 2;
|
|
int state = isExpanded ? 2 : 1;
|
|
return VisualStyleElement.CreateElement(klass, part, state);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the mouse over a checkbox in this cell?
|
|
/// </summary>
|
|
protected bool IsExpansionHot {
|
|
get { return this.IsCellHot && this.ListView.HotCellHitLocation == HitTestLocation.ExpandButton; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw the expansion indicator without using styles
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="r"></param>
|
|
/// <param name="isExpanded"></param>
|
|
protected virtual void DrawExpansionGlyphManual(Graphics g, Rectangle r, bool isExpanded) {
|
|
int h = 8;
|
|
int w = 8;
|
|
int x = r.X + 4;
|
|
int y = r.Y + (r.Height / 2) - 4;
|
|
|
|
g.DrawRectangle(new Pen(SystemBrushes.ControlDark), x, y, w, h);
|
|
g.FillRectangle(Brushes.White, x + 1, y + 1, w - 1, h - 1);
|
|
g.DrawLine(Pens.Black, x + 2, y + 4, x + w - 2, y + 4);
|
|
|
|
if (!isExpanded)
|
|
g.DrawLine(Pens.Black, x + 4, y + 2, x + 4, y + h - 2);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Draw the lines of the tree
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="r"></param>
|
|
/// <param name="p"></param>
|
|
/// <param name="br"></param>
|
|
/// <param name="glyphMidVertical"> </param>
|
|
protected virtual void DrawLines(Graphics g, Rectangle r, Pen p, Branch br, int glyphMidVertical) {
|
|
Rectangle r2 = r;
|
|
r2.Width = PIXELS_PER_LEVEL;
|
|
|
|
// Vertical lines have to start on even points, otherwise the dotted line looks wrong.
|
|
// This is only needed if pen is dotted.
|
|
int top = r2.Top;
|
|
//if (p.DashStyle == DashStyle.Dot && (top & 1) == 0)
|
|
// top += 1;
|
|
|
|
// Draw lines for ancestors
|
|
int midX;
|
|
IList<Branch> ancestors = br.Ancestors;
|
|
foreach (Branch ancestor in ancestors) {
|
|
if (!ancestor.IsLastChild && !ancestor.IsOnlyBranch) {
|
|
midX = r2.Left + r2.Width / 2;
|
|
g.DrawLine(p, midX, top, midX, r2.Bottom);
|
|
}
|
|
r2.Offset(PIXELS_PER_LEVEL, 0);
|
|
}
|
|
|
|
// Draw lines for this branch
|
|
midX = r2.Left + r2.Width / 2;
|
|
|
|
// Horizontal line first
|
|
g.DrawLine(p, midX, glyphMidVertical, r2.Right, glyphMidVertical);
|
|
|
|
// Vertical line second
|
|
if (br.IsFirstBranch) {
|
|
if (!br.IsLastChild && !br.IsOnlyBranch)
|
|
g.DrawLine(p, midX, glyphMidVertical, midX, r2.Bottom);
|
|
} else {
|
|
if (br.IsLastChild)
|
|
g.DrawLine(p, midX, top, midX, glyphMidVertical);
|
|
else
|
|
g.DrawLine(p, midX, top, midX, r2.Bottom);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Do the hit test
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="hti"></param>
|
|
/// <param name="x"></param>
|
|
/// <param name="y"></param>
|
|
protected override void HandleHitTest(Graphics g, OlvListViewHitTestInfo hti, int x, int y) {
|
|
Branch br = this.Branch;
|
|
|
|
Rectangle r = this.ApplyCellPadding(this.Bounds);
|
|
if (br.CanExpand) {
|
|
r.Offset((br.Level - 1) * PIXELS_PER_LEVEL, 0);
|
|
r.Width = PIXELS_PER_LEVEL;
|
|
if (r.Contains(x, y)) {
|
|
hti.HitTestLocation = HitTestLocation.ExpandButton;
|
|
return;
|
|
}
|
|
}
|
|
|
|
r = this.Bounds;
|
|
int indent = br.Level * PIXELS_PER_LEVEL;
|
|
r.X += indent;
|
|
r.Width -= indent;
|
|
|
|
// Ignore events in the indent zone
|
|
if (x < r.Left) {
|
|
hti.HitTestLocation = HitTestLocation.Nothing;
|
|
} else {
|
|
this.StandardHitTest(g, hti, r, x, y);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate the edit rect
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="cellBounds"></param>
|
|
/// <param name="item"></param>
|
|
/// <param name="subItemIndex"></param>
|
|
/// <param name="preferredSize"> </param>
|
|
/// <returns></returns>
|
|
protected override Rectangle HandleGetEditRectangle(Graphics g, Rectangle cellBounds, OLVListItem item, int subItemIndex, Size preferredSize) {
|
|
return this.StandardGetEditRectangle(g, cellBounds, preferredSize);
|
|
}
|
|
}
|
|
}
|
|
} |