mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-05 17:40:39 +00:00
57a1988755
* When jumping between draws the tables are rebuilt which destroys any vertical scrolling, so we save/restore it which means the same row will be at the top of the view. If there are fewer resources it'll just be as scrolled down as possible.
1363 lines
40 KiB
C#
1363 lines
40 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Design;
|
|
using System.Windows.Forms;
|
|
using System.ComponentModel;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Forms.VisualStyles;
|
|
|
|
// Taken from http://www.codeproject.com/Articles/23746/TreeView-with-Columns with minor tweaks
|
|
// and fixes for my purposes.
|
|
namespace TreelistView
|
|
{
|
|
[Designer(typeof(TreeListViewDesigner))]
|
|
public class TreeListView : Control, ISupportInitialize
|
|
{
|
|
public event TreeViewEventHandler AfterSelect;
|
|
protected virtual void OnAfterSelect(Node node)
|
|
{
|
|
raiseAfterSelect(node);
|
|
}
|
|
protected virtual void raiseAfterSelect(Node node)
|
|
{
|
|
if (AfterSelect != null && node != null)
|
|
AfterSelect(this, new TreeViewEventArgs(null));
|
|
}
|
|
|
|
public delegate void NotifyBeforeExpandHandler(Node node, bool isExpanding);
|
|
public event NotifyBeforeExpandHandler NotifyBeforeExpand;
|
|
public virtual void OnNotifyBeforeExpand(Node node, bool isExpanding)
|
|
{
|
|
raiseNotifyBeforeExpand(node, isExpanding);
|
|
}
|
|
protected virtual void raiseNotifyBeforeExpand(Node node, bool isExpanding)
|
|
{
|
|
if (NotifyBeforeExpand != null)
|
|
NotifyBeforeExpand(node, isExpanding);
|
|
}
|
|
|
|
public delegate void NotifyAfterHandler(Node node, bool isExpanding);
|
|
public event NotifyAfterHandler NotifyAfterExpand;
|
|
public virtual void OnNotifyAfterExpand(Node node, bool isExpanded)
|
|
{
|
|
raiseNotifyAfterExpand(node, isExpanded);
|
|
}
|
|
protected virtual void raiseNotifyAfterExpand(Node node, bool isExpanded)
|
|
{
|
|
if (NotifyAfterExpand != null)
|
|
NotifyAfterExpand(node, isExpanded);
|
|
}
|
|
|
|
public delegate void NodeDoubleClickedHandler(Node node);
|
|
public event NodeDoubleClickedHandler NodeDoubleClicked;
|
|
public virtual void OnNodeDoubleClicked(Node node)
|
|
{
|
|
raiseNodeDoubleClicked(node);
|
|
}
|
|
protected virtual void raiseNodeDoubleClicked(Node node)
|
|
{
|
|
if (NodeDoubleClicked != null)
|
|
NodeDoubleClicked(node);
|
|
}
|
|
|
|
public delegate void NodeClickedHandler(Node node);
|
|
public event NodeClickedHandler NodeClicked;
|
|
public virtual void OnNodeClicked(Node node)
|
|
{
|
|
raiseNodeClicked(node);
|
|
}
|
|
protected virtual void raiseNodeClicked(Node node)
|
|
{
|
|
if (NodeClicked != null)
|
|
NodeClicked(node);
|
|
}
|
|
|
|
TreeListViewNodes m_nodes;
|
|
TreeListColumnCollection m_columns;
|
|
TreeList.RowSetting m_rowSetting;
|
|
TreeList.ViewSetting m_viewSetting;
|
|
|
|
Color m_GridLineColour = SystemColors.Control;
|
|
Image m_SelectedImage = null;
|
|
|
|
[Category("Columns")]
|
|
[Browsable(true)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public TreeListColumnCollection Columns
|
|
{
|
|
get { return m_columns; }
|
|
}
|
|
|
|
[Category("Options")]
|
|
[Browsable(true)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public TreeList.CollumnSetting ColumnsOptions
|
|
{
|
|
get { return m_columns.Options; }
|
|
}
|
|
|
|
[Category("Options")]
|
|
[Browsable(true)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public TreeList.RowSetting RowOptions
|
|
{
|
|
get { return m_rowSetting; }
|
|
}
|
|
|
|
[Category("Options")]
|
|
[Browsable(true)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public TreeList.ViewSetting ViewOptions
|
|
{
|
|
get { return m_viewSetting; }
|
|
}
|
|
|
|
[Category("Behavior")]
|
|
[DefaultValue(typeof(bool), "True")]
|
|
public bool MultiSelect
|
|
{
|
|
get { return m_multiSelect; }
|
|
set { m_multiSelect = value; }
|
|
}
|
|
|
|
[Category("Behavior")]
|
|
[DefaultValue(typeof(int), "0")]
|
|
public int TreeColumn
|
|
{
|
|
get { return m_treeColumn; }
|
|
set { m_treeColumn = value; }
|
|
}
|
|
|
|
[Category("Behavior")]
|
|
[DefaultValue(typeof(bool), "False")]
|
|
public bool AlwaysDisplayVScroll
|
|
{
|
|
get { return m_vScrollAlways; }
|
|
set { m_vScrollAlways = value; }
|
|
}
|
|
|
|
[Category("Behavior")]
|
|
[DefaultValue(typeof(bool), "False")]
|
|
public bool AlwaysDisplayHScroll
|
|
{
|
|
get { return m_hScrollAlways; }
|
|
set { m_hScrollAlways = value; }
|
|
}
|
|
|
|
[Category("Appearance")]
|
|
[DefaultValue(typeof(Image), null)]
|
|
public Image SelectedImage
|
|
{
|
|
get { return m_SelectedImage; }
|
|
set { m_SelectedImage = value; }
|
|
}
|
|
|
|
[DefaultValue(typeof(Color), "Window")]
|
|
public new Color BackColor
|
|
{
|
|
get { return base.BackColor; }
|
|
set { base.BackColor = value; }
|
|
}
|
|
|
|
[Category("Appearance")]
|
|
[DefaultValue(typeof(Color), "Control")]
|
|
public Color GridLineColour
|
|
{
|
|
get { return m_GridLineColour; }
|
|
set { m_GridLineColour = value; }
|
|
}
|
|
|
|
//[Browsable(false)]
|
|
public TreeListViewNodes Nodes
|
|
{
|
|
get { return m_nodes; }
|
|
}
|
|
public TreeListView()
|
|
{
|
|
this.DoubleBuffered = true;
|
|
this.BackColor = SystemColors.Window;
|
|
this.TabStop = true;
|
|
|
|
m_rowPainter = new RowPainter();
|
|
m_cellPainter = new CellPainter(this);
|
|
|
|
m_nodes = new TreeListViewNodes(this);
|
|
m_rowSetting = new TreeList.RowSetting(this);
|
|
m_viewSetting = new TreeList.ViewSetting(this);
|
|
m_columns = new TreeListColumnCollection(this);
|
|
AddScrollBars();
|
|
}
|
|
public void RecalcLayout()
|
|
{
|
|
if (m_firstVisibleNode == null)
|
|
m_firstVisibleNode = Nodes.FirstNode;
|
|
if (Nodes.Count == 0)
|
|
m_firstVisibleNode = null;
|
|
|
|
UpdateScrollBars();
|
|
m_columns.RecalcVisibleColumsRect();
|
|
UpdateScrollBars();
|
|
m_columns.RecalcVisibleColumsRect();
|
|
|
|
int vscroll = VScrollValue();
|
|
if (vscroll == 0)
|
|
m_firstVisibleNode = Nodes.FirstNode;
|
|
else
|
|
m_firstVisibleNode = NodeCollection.GetNextNode(Nodes.FirstNode, vscroll);
|
|
Invalidate();
|
|
}
|
|
void AddScrollBars()
|
|
{
|
|
// I was not able to get the wanted behavior by using ScrollableControl with AutoScroll enabled.
|
|
// horizontal scrolling is ok to do it by pixels, but for vertical I want to maintain the headers
|
|
// and only scroll the rows.
|
|
// I was not able to manually overwrite the vscroll bar handling to get this behavior, instead I opted for
|
|
// custom implementation of scrollbars
|
|
|
|
// to get the 'filler' between hscroll and vscroll I dock scroll + filler in a panel
|
|
m_hScroll = new HScrollBar();
|
|
m_hScroll.Scroll += new ScrollEventHandler(OnHScroll);
|
|
m_hScroll.Dock = DockStyle.Fill;
|
|
|
|
m_vScroll = new VScrollBar();
|
|
m_vScroll.Scroll += new ScrollEventHandler(OnVScroll);
|
|
m_vScroll.Dock = DockStyle.Right;
|
|
|
|
m_hScrollFiller = new Panel();
|
|
m_hScrollFiller.BackColor = Color.Transparent;
|
|
m_hScrollFiller.Size = new Size(m_vScroll.Width-1, m_hScroll.Height);
|
|
m_hScrollFiller.Dock = DockStyle.Right;
|
|
|
|
Controls.Add(m_vScroll);
|
|
|
|
m_hScrollPanel = new Panel();
|
|
m_hScrollPanel.Height = m_hScroll.Height;
|
|
m_hScrollPanel.Dock = DockStyle.Bottom;
|
|
m_hScrollPanel.Controls.Add(m_hScroll);
|
|
m_hScrollPanel.Controls.Add(m_hScrollFiller);
|
|
Controls.Add(m_hScrollPanel);
|
|
}
|
|
|
|
VScrollBar m_vScroll;
|
|
HScrollBar m_hScroll;
|
|
Panel m_hScrollFiller;
|
|
Panel m_hScrollPanel;
|
|
bool m_multiSelect = true;
|
|
int m_treeColumn = 0;
|
|
bool m_vScrollAlways = false;
|
|
bool m_hScrollAlways = false;
|
|
Node m_firstVisibleNode = null;
|
|
|
|
RowPainter m_rowPainter;
|
|
CellPainter m_cellPainter;
|
|
[Browsable(false)]
|
|
public CellPainter CellPainter
|
|
{
|
|
get { return m_cellPainter; }
|
|
set { m_cellPainter = value; }
|
|
}
|
|
|
|
TreeListColumn m_resizingColumn;
|
|
int m_resizingColumnScrollOffset;
|
|
int m_resizingColumnLeft;
|
|
|
|
TreeListColumn m_movingColumn;
|
|
|
|
NodesSelection m_nodesSelection = new NodesSelection();
|
|
Node m_focusedNode = null;
|
|
|
|
[Browsable(false)]
|
|
public NodesSelection NodesSelection
|
|
{
|
|
get { return m_nodesSelection; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
public Node SelectedNode
|
|
{
|
|
get { return m_nodesSelection.Count == 0 ? FocusedNode : m_nodesSelection[0]; }
|
|
}
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public Node FocusedNode
|
|
{
|
|
get { return m_focusedNode; }
|
|
set
|
|
{
|
|
Node curNode = FocusedNode;
|
|
if (object.ReferenceEquals(curNode, value))
|
|
return;
|
|
if (MultiSelect == false)
|
|
NodesSelection.Clear();
|
|
|
|
int oldrow = NodeCollection.GetVisibleNodeIndex(curNode);
|
|
int newrow = NodeCollection.GetVisibleNodeIndex(value);
|
|
|
|
m_focusedNode = value;
|
|
OnAfterSelect(value);
|
|
InvalidateRow(oldrow);
|
|
InvalidateRow(newrow);
|
|
EnsureVisible(m_focusedNode);
|
|
}
|
|
}
|
|
public void EnsureVisible(Node node)
|
|
{
|
|
int screenvisible = MaxVisibleRows() - 1;
|
|
int visibleIndex = NodeCollection.GetVisibleNodeIndex(node);
|
|
if (visibleIndex < VScrollValue())
|
|
{
|
|
SetVScrollValue(visibleIndex);
|
|
}
|
|
if (visibleIndex > VScrollValue() + screenvisible)
|
|
{
|
|
SetVScrollValue(visibleIndex - screenvisible);
|
|
}
|
|
}
|
|
public Node CalcHitNode(Point mousepoint)
|
|
{
|
|
if (!ClientRectangle.Contains(mousepoint))
|
|
return null;
|
|
|
|
int hitrow = CalcHitRow(mousepoint);
|
|
if (hitrow < 0)
|
|
return null;
|
|
return NodeCollection.GetNextNode(m_firstVisibleNode, hitrow);
|
|
}
|
|
public Node GetHitNode()
|
|
{
|
|
return CalcHitNode(PointToClient(Control.MousePosition));
|
|
}
|
|
public TreelistView.HitInfo CalcColumnHit(Point mousepoint)
|
|
{
|
|
return Columns.CalcHitInfo(mousepoint, HScrollValue());
|
|
}
|
|
public bool HitTestScrollbar(Point mousepoint)
|
|
{
|
|
if (m_hScroll.Visible && mousepoint.Y >= ClientRectangle.Height - m_hScroll.Height)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
protected override void OnSizeChanged(EventArgs e)
|
|
{
|
|
base.OnSizeChanged(e);
|
|
if (ClientRectangle.Width > 0 && ClientRectangle.Height > 0)
|
|
{
|
|
Columns.RecalcVisibleColumsRect();
|
|
UpdateScrollBars();
|
|
Columns.RecalcVisibleColumsRect();
|
|
}
|
|
}
|
|
protected override void OnVisibleChanged(EventArgs e)
|
|
{
|
|
base.OnVisibleChanged(e);
|
|
RecalcLayout();
|
|
}
|
|
protected virtual void BeforeShowContextMenu()
|
|
{
|
|
}
|
|
protected void InvalidateRow(int absoluteRowIndex)
|
|
{
|
|
int visibleRowIndex = absoluteRowIndex - VScrollValue();
|
|
Rectangle r = CalcRowRectangle(visibleRowIndex);
|
|
if (r != Rectangle.Empty)
|
|
{
|
|
r.Inflate(1,1);
|
|
Invalidate(r);
|
|
}
|
|
}
|
|
|
|
void OnVScroll(object sender, ScrollEventArgs e)
|
|
{
|
|
int diff = e.NewValue - e.OldValue;
|
|
//assumedScrollPos += diff;
|
|
if (e.NewValue == 0)
|
|
{
|
|
m_firstVisibleNode = Nodes.FirstNode;
|
|
diff = 0;
|
|
}
|
|
m_firstVisibleNode = NodeCollection.GetNextNode(m_firstVisibleNode, diff);
|
|
Invalidate();
|
|
}
|
|
void OnHScroll(object sender, ScrollEventArgs e)
|
|
{
|
|
Invalidate();
|
|
}
|
|
public void SetVScrollValue(int value)
|
|
{
|
|
if (value < 0)
|
|
value = 0;
|
|
int max = m_vScroll.Maximum - m_vScroll.LargeChange + 1;
|
|
if (value > max)
|
|
value = max;
|
|
|
|
if ((value >= 0 && value <= max) && (value != m_vScroll.Value))
|
|
{
|
|
ScrollEventArgs e = new ScrollEventArgs(ScrollEventType.ThumbPosition, m_vScroll.Value, value, ScrollOrientation.VerticalScroll);
|
|
// setting the scroll value does not cause a Scroll event
|
|
m_vScroll.Value = value;
|
|
// so we have to fake it
|
|
OnVScroll(m_vScroll, e);
|
|
}
|
|
}
|
|
public int VScrollValue()
|
|
{
|
|
if (m_vScroll.Visible == false)
|
|
return 0;
|
|
return m_vScroll.Value;
|
|
}
|
|
int HScrollValue()
|
|
{
|
|
if (m_hScroll.Visible == false)
|
|
return 0;
|
|
return m_hScroll.Value;
|
|
}
|
|
void UpdateScrollBars()
|
|
{
|
|
if (ClientRectangle.Width < 0)
|
|
return;
|
|
int maxvisiblerows = MaxVisibleRows();
|
|
int totalrows = Nodes.VisibleNodeCount;
|
|
m_vScroll.SmallChange = 1;
|
|
m_vScroll.LargeChange = Math.Max(1, maxvisiblerows);
|
|
m_vScroll.Enabled = true;
|
|
m_vScroll.Minimum = 0;
|
|
m_vScroll.Maximum = Math.Max(1,totalrows - 1);
|
|
if (maxvisiblerows >= totalrows)
|
|
{
|
|
m_vScroll.Visible = false;
|
|
SetVScrollValue(0);
|
|
|
|
if (m_vScrollAlways)
|
|
{
|
|
m_vScroll.Visible = true;
|
|
m_vScroll.Enabled = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_vScroll.Visible = true;
|
|
|
|
int maxscrollvalue = m_vScroll.Maximum - m_vScroll.LargeChange;
|
|
if (maxscrollvalue < m_vScroll.Value)
|
|
SetVScrollValue(maxscrollvalue);
|
|
}
|
|
|
|
m_hScroll.Enabled = true;
|
|
if (ClientRectangle.Width > MinWidth())
|
|
{
|
|
m_hScrollPanel.Visible = false;
|
|
m_hScroll.Value = 0;
|
|
|
|
if (m_hScrollAlways)
|
|
{
|
|
m_hScroll.Enabled = false;
|
|
m_hScrollPanel.Visible = true;
|
|
m_hScroll.Minimum = 0;
|
|
m_hScroll.Maximum = 0;
|
|
m_hScroll.SmallChange = 1;
|
|
m_hScroll.LargeChange = 1;
|
|
m_hScrollFiller.Visible = m_vScroll.Visible;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_hScroll.Minimum = 0;
|
|
m_hScroll.Maximum = Math.Max(1, MinWidth());
|
|
m_hScroll.SmallChange = 5;
|
|
m_hScroll.LargeChange = Math.Max(1, ClientRectangle.Width);
|
|
m_hScrollFiller.Visible = m_vScroll.Visible;
|
|
m_hScrollPanel.Visible = true;
|
|
}
|
|
}
|
|
int m_hotrow = -1;
|
|
int CalcHitRow(Point mousepoint)
|
|
{
|
|
if (mousepoint.Y <= Columns.Options.HeaderHeight)
|
|
return -1;
|
|
return (mousepoint.Y - Columns.Options.HeaderHeight) / RowOptions.ItemHeight;
|
|
}
|
|
int VisibleRowToYPoint(int visibleRowIndex)
|
|
{
|
|
return Columns.Options.HeaderHeight + (visibleRowIndex * RowOptions.ItemHeight);
|
|
}
|
|
Rectangle CalcRowRectangle(int visibleRowIndex)
|
|
{
|
|
Rectangle r = ClientRectangle;
|
|
r.Y = VisibleRowToYPoint(visibleRowIndex);
|
|
if (r.Top < Columns.Options.HeaderHeight || r.Top > ClientRectangle.Height)
|
|
return Rectangle.Empty;
|
|
r.Height = RowOptions.ItemHeight;
|
|
return r;
|
|
}
|
|
|
|
void MultiSelectAdd(Node clickedNode, Keys modifierKeys)
|
|
{
|
|
if (Control.ModifierKeys == Keys.None)
|
|
{
|
|
foreach (Node node in NodesSelection)
|
|
{
|
|
int newrow = NodeCollection.GetVisibleNodeIndex(node);
|
|
InvalidateRow(newrow);
|
|
}
|
|
NodesSelection.Clear();
|
|
NodesSelection.Add(clickedNode);
|
|
}
|
|
if (Control.ModifierKeys == Keys.Shift)
|
|
{
|
|
if (NodesSelection.Count == 0)
|
|
NodesSelection.Add(clickedNode);
|
|
else
|
|
{
|
|
int startrow = NodeCollection.GetVisibleNodeIndex(NodesSelection[0]);
|
|
int currow = NodeCollection.GetVisibleNodeIndex(clickedNode);
|
|
if (currow > startrow)
|
|
{
|
|
Node startingNode = NodesSelection[0];
|
|
NodesSelection.Clear();
|
|
foreach (Node node in NodeCollection.ForwardNodeIterator(startingNode, clickedNode, true))
|
|
NodesSelection.Add(node);
|
|
Invalidate();
|
|
}
|
|
if (currow < startrow)
|
|
{
|
|
Node startingNode = NodesSelection[0];
|
|
NodesSelection.Clear();
|
|
foreach (Node node in NodeCollection.ReverseNodeIterator(startingNode, clickedNode, true))
|
|
NodesSelection.Add(node);
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
if (Control.ModifierKeys == Keys.Control)
|
|
{
|
|
if (NodesSelection.Contains(clickedNode))
|
|
NodesSelection.Remove(clickedNode);
|
|
else
|
|
NodesSelection.Add(clickedNode);
|
|
}
|
|
InvalidateRow(NodeCollection.GetVisibleNodeIndex(clickedNode));
|
|
FocusedNode = clickedNode;
|
|
}
|
|
internal event MouseEventHandler AfterResizingColumn;
|
|
protected override void OnMouseClick(MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
Point mousePoint = new Point(e.X, e.Y);
|
|
Node clickedNode = CalcHitNode(mousePoint);
|
|
if (clickedNode != null && Columns.Count > 0)
|
|
{
|
|
int clickedRow = CalcHitRow(mousePoint);
|
|
Rectangle glyphRect = Rectangle.Empty;
|
|
if (m_treeColumn >= 0)
|
|
glyphRect = GetPlusMinusRectangle(clickedNode, Columns[m_treeColumn], clickedRow);
|
|
if (clickedNode.HasChildren && glyphRect != Rectangle.Empty && glyphRect.Contains(mousePoint))
|
|
clickedNode.Expanded = !clickedNode.Expanded;
|
|
|
|
var columnHit = CalcColumnHit(mousePoint);
|
|
|
|
if (glyphRect == Rectangle.Empty && columnHit.Column != null &&
|
|
columnHit.Column.Index == m_treeColumn && GetNodeBitmap(clickedNode) != null)
|
|
{
|
|
OnNodeClicked(clickedNode);
|
|
}
|
|
|
|
if (MultiSelect)
|
|
{
|
|
MultiSelectAdd(clickedNode, Control.ModifierKeys);
|
|
}
|
|
else
|
|
FocusedNode = clickedNode;
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
FocusedNode = null;
|
|
NodesSelection.Clear();
|
|
}*/
|
|
}
|
|
base.OnMouseClick(e);
|
|
}
|
|
protected override void OnMouseMove(MouseEventArgs e)
|
|
{
|
|
base.OnMouseMove(e);
|
|
|
|
if (m_movingColumn != null)
|
|
{
|
|
m_movingColumn.Moving = true;
|
|
Cursor = Cursors.SizeAll;
|
|
|
|
var idx = m_movingColumn.VisibleIndex;
|
|
if (idx + 1 < Columns.VisibleColumns.Length)
|
|
{
|
|
var nextcol = Columns.VisibleColumns[idx + 1];
|
|
if (nextcol.CalculatedRect.X + (nextcol.CalculatedRect.Width * 3) / 4 < e.X)
|
|
{
|
|
Columns.SetVisibleIndex(m_movingColumn, idx + 1);
|
|
}
|
|
}
|
|
if (idx - 1 >= 0)
|
|
{
|
|
var prevcol = Columns.VisibleColumns[idx - 1];
|
|
if (prevcol.CalculatedRect.Right - (prevcol.CalculatedRect.Width * 3) / 4 > e.X)
|
|
{
|
|
Columns.SetVisibleIndex(m_movingColumn, idx - 1);
|
|
}
|
|
}
|
|
|
|
Columns.RecalcVisibleColumsRect(true);
|
|
Invalidate();
|
|
return;
|
|
}
|
|
if (m_resizingColumn != null)
|
|
{
|
|
// if we've clicked on an autosize column, actually resize the next one along.
|
|
if (m_resizingColumn.AutoSize)
|
|
{
|
|
if (Columns.VisibleColumns.Length > m_resizingColumn.VisibleIndex + 1)
|
|
{
|
|
TreeListColumn realResizeColumn = Columns.VisibleColumns[m_resizingColumn.VisibleIndex + 1];
|
|
|
|
int right = realResizeColumn.CalculatedRect.Right - m_resizingColumnScrollOffset;
|
|
int width = right - e.X;
|
|
if (width < 10)
|
|
width = 10;
|
|
|
|
bool resize = true;
|
|
|
|
if (Columns.VisibleColumns.Length > realResizeColumn.VisibleIndex + 1)
|
|
if (Columns.VisibleColumns[realResizeColumn.VisibleIndex + 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width)
|
|
resize = false;
|
|
|
|
if (realResizeColumn.VisibleIndex > 1)
|
|
if (Columns.VisibleColumns[realResizeColumn.VisibleIndex - 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width)
|
|
resize = false;
|
|
|
|
if (resize)
|
|
{
|
|
realResizeColumn.Width = width;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int left = m_resizingColumnLeft;
|
|
int width = e.X - left;
|
|
if (width < 10)
|
|
width = 10;
|
|
|
|
bool resize = true;
|
|
|
|
if (Columns.VisibleColumns.Length > m_resizingColumn.VisibleIndex + 1)
|
|
if (Columns.VisibleColumns[m_resizingColumn.VisibleIndex + 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width)
|
|
resize = false;
|
|
|
|
if (m_resizingColumn.internalIndex > 1)
|
|
if (Columns.VisibleColumns[m_resizingColumn.VisibleIndex - 1].CalculatedRect.Width <= 10 && m_resizingColumn.Width < width)
|
|
resize = false;
|
|
|
|
if (resize)
|
|
m_resizingColumn.Width = width;
|
|
}
|
|
|
|
Columns.RecalcVisibleColumsRect(true);
|
|
Invalidate();
|
|
return;
|
|
}
|
|
|
|
TreeListColumn hotcol = null;
|
|
TreelistView.HitInfo info = Columns.CalcHitInfo(new Point(e.X, e.Y), HScrollValue());
|
|
if ((int)(info.HitType & HitInfo.eHitType.kColumnHeader) > 0)
|
|
hotcol = info.Column;
|
|
|
|
Node clickedNode = CalcHitNode(new Point(e.X, e.Y));
|
|
|
|
if ((int)(info.HitType & HitInfo.eHitType.kColumnHeaderResize) > 0)
|
|
Cursor = Cursors.VSplit;
|
|
else if (info.Column != null && info.Column.Index == m_treeColumn && GetNodeBitmap(clickedNode) != null && m_viewSetting.HoverHandTreeColumn)
|
|
Cursor = Cursors.Hand;
|
|
else
|
|
Cursor = Cursors.Arrow;
|
|
|
|
if (GetHoverNodeBitmap(clickedNode) != null &&
|
|
GetNodeBitmap(clickedNode) != GetHoverNodeBitmap(clickedNode))
|
|
Invalidate();
|
|
|
|
SetHotColumn(hotcol, true);
|
|
|
|
int vScrollOffset = VScrollValue();
|
|
|
|
int newhotrow = -1;
|
|
if (hotcol == null)
|
|
{
|
|
int row = (e.Y - Columns.Options.HeaderHeight) / RowOptions.ItemHeight;
|
|
newhotrow = row + vScrollOffset;
|
|
}
|
|
if (newhotrow != m_hotrow)
|
|
{
|
|
InvalidateRow(m_hotrow);
|
|
m_hotrow = newhotrow;
|
|
InvalidateRow(m_hotrow);
|
|
}
|
|
}
|
|
protected override void OnMouseLeave(EventArgs e)
|
|
{
|
|
base.OnMouseLeave(e);
|
|
SetHotColumn(null, false);
|
|
Cursor = Cursors.Arrow;
|
|
Invalidate();
|
|
}
|
|
protected override void OnMouseWheel(MouseEventArgs e)
|
|
{
|
|
int value = m_vScroll.Value - (e.Delta * SystemInformation.MouseWheelScrollLines / 120);
|
|
if (m_vScroll.Visible)
|
|
SetVScrollValue(value);
|
|
base.OnMouseWheel(e);
|
|
}
|
|
protected override void OnMouseDown(MouseEventArgs e)
|
|
{
|
|
this.Focus();
|
|
if (e.Button == MouseButtons.Right)
|
|
{
|
|
Point mousePoint = new Point(e.X, e.Y);
|
|
Node clickedNode = CalcHitNode(mousePoint);
|
|
if (clickedNode != null)
|
|
{
|
|
// if multi select the selection is cleard if clicked node is not in selection
|
|
if (MultiSelect)
|
|
{
|
|
if (NodesSelection.Contains(clickedNode) == false)
|
|
MultiSelectAdd(clickedNode, Control.ModifierKeys);
|
|
}
|
|
FocusedNode = clickedNode;
|
|
Invalidate();
|
|
}
|
|
BeforeShowContextMenu();
|
|
}
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
TreelistView.HitInfo info = Columns.CalcHitInfo(new Point(e.X, e.Y), HScrollValue());
|
|
if ((int)(info.HitType & HitInfo.eHitType.kColumnHeaderResize) > 0)
|
|
{
|
|
m_resizingColumn = info.Column;
|
|
m_resizingColumnScrollOffset = HScrollValue();
|
|
m_resizingColumnLeft = m_resizingColumn.CalculatedRect.Left - m_resizingColumnScrollOffset;
|
|
return;
|
|
}
|
|
if ((int)(info.HitType & HitInfo.eHitType.kColumnHeader) > 0 && m_viewSetting.UserRearrangeableColumns)
|
|
{
|
|
m_movingColumn = info.Column;
|
|
return;
|
|
}
|
|
}
|
|
base.OnMouseDown(e);
|
|
}
|
|
protected override void OnMouseUp(MouseEventArgs e)
|
|
{
|
|
if (m_resizingColumn != null)
|
|
{
|
|
m_resizingColumn = null;
|
|
Columns.RecalcVisibleColumsRect();
|
|
UpdateScrollBars();
|
|
Invalidate();
|
|
if (AfterResizingColumn != null)
|
|
AfterResizingColumn(this, e);
|
|
}
|
|
if (m_movingColumn != null)
|
|
{
|
|
m_movingColumn.Moving = false;
|
|
m_movingColumn = null;
|
|
Cursor = Cursors.Arrow;
|
|
Columns.RecalcVisibleColumsRect();
|
|
UpdateScrollBars();
|
|
Invalidate();
|
|
}
|
|
base.OnMouseUp(e);
|
|
}
|
|
protected override void OnMouseDoubleClick(MouseEventArgs e)
|
|
{
|
|
base.OnMouseDoubleClick(e);
|
|
Point mousePoint = new Point(e.X, e.Y);
|
|
Node clickedNode = CalcHitNode(mousePoint);
|
|
if (clickedNode != null && clickedNode.HasChildren)
|
|
clickedNode.Expanded = !clickedNode.Expanded;
|
|
if (clickedNode != null)
|
|
OnNodeDoubleClicked(clickedNode);
|
|
}
|
|
|
|
// Somewhere I read that it could be risky to do any handling in GetFocus / LostFocus.
|
|
// The reason is that it will throw exception incase you make a call which recreates the windows handle (e.g.
|
|
// change the border style. Instead one should always use OnEnter and OnLeave instead. That is why I'm using
|
|
// OnEnter and OnLeave instead, even though I'm only doing Invalidate.
|
|
protected override void OnEnter(EventArgs e)
|
|
{
|
|
base.OnEnter(e);
|
|
Invalidate();
|
|
}
|
|
protected override void OnLeave(EventArgs e)
|
|
{
|
|
base.OnLeave(e);
|
|
Invalidate();
|
|
}
|
|
|
|
protected override void OnLostFocus(EventArgs e)
|
|
{
|
|
base.OnLostFocus(e);
|
|
Invalidate();
|
|
}
|
|
|
|
void SetHotColumn(TreeListColumn col, bool ishot)
|
|
{
|
|
int scrolloffset = HScrollValue();
|
|
if (col != m_hotColumn)
|
|
{
|
|
if (m_hotColumn != null)
|
|
{
|
|
m_hotColumn.ishot = false;
|
|
Rectangle r = m_hotColumn.CalculatedRect;
|
|
r.X -= scrolloffset;
|
|
Invalidate(r);
|
|
}
|
|
m_hotColumn = col;
|
|
if (m_hotColumn != null)
|
|
{
|
|
m_hotColumn.ishot = ishot;
|
|
Rectangle r = m_hotColumn.CalculatedRect;
|
|
r.X -= scrolloffset;
|
|
Invalidate(r);
|
|
}
|
|
}
|
|
}
|
|
internal int RowHeaderWidth()
|
|
{
|
|
if (RowOptions.ShowHeader)
|
|
return RowOptions.HeaderWidth;
|
|
return 0;
|
|
}
|
|
int MinWidth()
|
|
{
|
|
return RowHeaderWidth() + Columns.ColumnsWidth;
|
|
}
|
|
int MaxVisibleRows(out int remainder)
|
|
{
|
|
remainder = 0;
|
|
if (ClientRectangle.Height < 0)
|
|
return 0;
|
|
int height = ClientRectangle.Height - Columns.Options.HeaderHeight;
|
|
//return (int) Math.Ceiling((double)(ClientRectangle.Height - Columns.HeaderHeight) / (double)Nodes.ItemHeight);
|
|
remainder = (ClientRectangle.Height - Columns.Options.HeaderHeight) % RowOptions.ItemHeight ;
|
|
return Math.Max(0, (ClientRectangle.Height - Columns.Options.HeaderHeight) / RowOptions.ItemHeight);
|
|
}
|
|
int MaxVisibleRows()
|
|
{
|
|
int unused;
|
|
return MaxVisibleRows(out unused);
|
|
}
|
|
public void BeginUpdate()
|
|
{
|
|
m_nodes.BeginUpdate();
|
|
}
|
|
public void EndUpdate()
|
|
{
|
|
m_nodes.EndUpdate();
|
|
RecalcLayout();
|
|
Invalidate();
|
|
}
|
|
protected override CreateParams CreateParams
|
|
{
|
|
get
|
|
{
|
|
const int WS_BORDER = 0x00800000;
|
|
const int WS_EX_CLIENTEDGE = 0x00000200;
|
|
CreateParams p = base.CreateParams;
|
|
p.Style &= ~(int)WS_BORDER;
|
|
p.ExStyle &= ~(int)WS_EX_CLIENTEDGE;
|
|
switch (ViewOptions.BorderStyle)
|
|
{
|
|
case BorderStyle.Fixed3D:
|
|
p.ExStyle |= (int)WS_EX_CLIENTEDGE;
|
|
break;
|
|
case BorderStyle.FixedSingle:
|
|
p.Style |= (int)WS_BORDER;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return p;
|
|
}
|
|
}
|
|
|
|
TreeListColumn m_hotColumn = null;
|
|
|
|
object GetDataDesignMode(Node node, TreeListColumn column)
|
|
{
|
|
string id = string.Empty;
|
|
while (node != null)
|
|
{
|
|
id = node.Owner.GetNodeIndex(node).ToString() + ":" + id;
|
|
node = node.Parent;
|
|
}
|
|
return "<temp>" + id;
|
|
}
|
|
protected virtual object GetData(Node node, TreeListColumn column)
|
|
{
|
|
if (node[column.Index] != null)
|
|
return node[column.Index];
|
|
return null;
|
|
}
|
|
public new Rectangle ClientRectangle
|
|
{
|
|
get
|
|
{
|
|
Rectangle r = base.ClientRectangle;
|
|
if (m_vScroll.Visible)
|
|
r.Width -= m_vScroll.Width+1;
|
|
if (m_hScroll.Visible)
|
|
r.Height -= m_hScroll.Height+1;
|
|
return r;
|
|
}
|
|
}
|
|
|
|
protected virtual TreelistView.TreeList.TextFormatting GetFormatting(TreelistView.Node node, TreelistView.TreeListColumn column)
|
|
{
|
|
return column.CellFormat;
|
|
}
|
|
protected virtual void PaintCellPlusMinus(Graphics dc, Rectangle glyphRect, Node node, TreeListColumn column)
|
|
{
|
|
CellPainter.PaintCellPlusMinus(dc, glyphRect, node, column, GetFormatting(node, column));
|
|
}
|
|
protected virtual void PaintCellBackground(Graphics dc, Rectangle cellRect, Node node, TreeListColumn column)
|
|
{
|
|
if (this.DesignMode)
|
|
CellPainter.PaintCellBackground(dc, cellRect, node, column, GetFormatting(node, column), GetDataDesignMode(node, column));
|
|
else
|
|
CellPainter.PaintCellBackground(dc, cellRect, node, column, GetFormatting(node, column), GetData(node, column));
|
|
}
|
|
protected virtual void PaintCellText(Graphics dc, Rectangle cellRect, Node node, TreeListColumn column)
|
|
{
|
|
if (this.DesignMode)
|
|
CellPainter.PaintCellText(dc, cellRect, node, column, GetFormatting(node, column), GetDataDesignMode(node, column));
|
|
else
|
|
CellPainter.PaintCellText(dc, cellRect, node, column, GetFormatting(node, column), GetData(node, column));
|
|
}
|
|
protected virtual void PaintImage(Graphics dc, Rectangle imageRect, Node node, Image image)
|
|
{
|
|
if (image != null)
|
|
dc.DrawImage(image, imageRect.X, imageRect.Y, imageRect.Width, imageRect.Height);
|
|
}
|
|
protected virtual void PaintNode(Graphics dc, Rectangle rowRect, Node node, TreeListColumn[] visibleColumns, int visibleRowIndex)
|
|
{
|
|
CellPainter.DrawSelectionBackground(dc, rowRect, node);
|
|
foreach (TreeListColumn col in visibleColumns)
|
|
{
|
|
if (col.CalculatedRect.Right - HScrollValue() < RowHeaderWidth())
|
|
continue;
|
|
|
|
Rectangle cellRect = rowRect;
|
|
cellRect.X = col.CalculatedRect.X - HScrollValue();
|
|
cellRect.Width = col.CalculatedRect.Width;
|
|
|
|
dc.SetClip(cellRect);
|
|
|
|
if (col.Index == m_treeColumn)
|
|
{
|
|
int lineindet = 10;
|
|
// add left margin
|
|
cellRect.X += Columns.Options.LeftMargin;
|
|
cellRect.Width -= Columns.Options.LeftMargin;
|
|
|
|
// add indent size
|
|
int indentSize = GetIndentSize(node) + 5;
|
|
cellRect.X += indentSize;
|
|
cellRect.Width -= indentSize;
|
|
if (ViewOptions.ShowLine)
|
|
PaintLines(dc, cellRect, node);
|
|
cellRect.X += lineindet;
|
|
cellRect.Width -= lineindet;
|
|
|
|
Rectangle glyphRect = GetPlusMinusRectangle(node, col, visibleRowIndex);
|
|
|
|
if (!ViewOptions.ShowLine && !ViewOptions.ShowPlusMinus)
|
|
{
|
|
cellRect.X -= (lineindet + 5);
|
|
cellRect.Width += (lineindet + 5);
|
|
}
|
|
|
|
Point mousePoint = PointToClient(Cursor.Position);
|
|
Node hoverNode = CalcHitNode(mousePoint);
|
|
|
|
Image icon = hoverNode != null && hoverNode == node ? GetHoverNodeBitmap(node) : GetNodeBitmap(node);
|
|
|
|
if (icon == null &&
|
|
(NodesSelection.Contains(node) || FocusedNode == node)
|
|
)
|
|
{
|
|
icon = SelectedImage;
|
|
}
|
|
|
|
Rectangle plusminusRect = glyphRect;
|
|
|
|
PaintCellBackground(dc, cellRect, node, col);
|
|
|
|
if (icon != null)
|
|
{
|
|
// center the image vertically
|
|
glyphRect.Y = cellRect.Y + (cellRect.Height / 2) - (icon.Height / 2);
|
|
glyphRect.X = cellRect.X;
|
|
glyphRect.Width = icon.Width;
|
|
glyphRect.Height = icon.Height;
|
|
|
|
PaintImage(dc, glyphRect, node, icon);
|
|
cellRect.X += (glyphRect.Width + 2);
|
|
cellRect.Width -= (glyphRect.Width + 2);
|
|
}
|
|
|
|
PaintCellText(dc, cellRect, node, col);
|
|
|
|
if (plusminusRect != Rectangle.Empty && ViewOptions.ShowPlusMinus)
|
|
PaintCellPlusMinus(dc, plusminusRect, node, col);
|
|
}
|
|
else
|
|
{
|
|
PaintCellBackground(dc, cellRect, node, col);
|
|
PaintCellText(dc, cellRect, node, col);
|
|
}
|
|
|
|
dc.ResetClip();
|
|
}
|
|
}
|
|
protected virtual void PaintLines(Graphics dc, Rectangle cellRect, Node node)
|
|
{
|
|
Pen pen = new Pen(Color.Gray);
|
|
pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
|
|
|
|
int halfPoint = cellRect.Top + (cellRect.Height / 2);
|
|
// line should start from center at first root node
|
|
if (node.Parent == null && node.PrevSibling == null)
|
|
{
|
|
cellRect.Y += (cellRect.Height / 2);
|
|
cellRect.Height -= (cellRect.Height / 2);
|
|
}
|
|
if (node.NextSibling != null || node.HasChildren) // draw full height line
|
|
dc.DrawLine(pen, cellRect.X, cellRect.Top, cellRect.X, cellRect.Bottom);
|
|
else
|
|
dc.DrawLine(pen, cellRect.X, cellRect.Top, cellRect.X, halfPoint);
|
|
dc.DrawLine(pen, cellRect.X, halfPoint, cellRect.X + 10, halfPoint);
|
|
|
|
// now draw the lines for the parents sibling
|
|
Node parent = node.Parent;
|
|
while (parent != null)
|
|
{
|
|
cellRect.X -= ViewOptions.Indent;
|
|
dc.DrawLine(pen, cellRect.X, cellRect.Top, cellRect.X, cellRect.Bottom);
|
|
parent = parent.Parent;
|
|
}
|
|
|
|
pen.Dispose();
|
|
}
|
|
protected virtual int GetIndentSize(Node node)
|
|
{
|
|
int indent = 0;
|
|
Node parent = node.Parent;
|
|
while (parent != null)
|
|
{
|
|
indent += ViewOptions.Indent;
|
|
parent = parent.Parent;
|
|
}
|
|
return indent;
|
|
}
|
|
protected virtual Rectangle GetPlusMinusRectangle(Node node, TreeListColumn firstColumn, int visibleRowIndex)
|
|
{
|
|
if (node.HasChildren == false)
|
|
return Rectangle.Empty;
|
|
int hScrollOffset = HScrollValue();
|
|
if (firstColumn.CalculatedRect.Right - hScrollOffset < RowHeaderWidth())
|
|
return Rectangle.Empty;
|
|
//System.Diagnostics.Debug.Assert(firstColumn.VisibleIndex == 0);
|
|
|
|
Rectangle glyphRect = firstColumn.CalculatedRect;
|
|
glyphRect.X -= hScrollOffset;
|
|
glyphRect.X += GetIndentSize(node);
|
|
glyphRect.X += Columns.Options.LeftMargin;
|
|
glyphRect.Width = 10;
|
|
glyphRect.Y = VisibleRowToYPoint(visibleRowIndex);
|
|
glyphRect.Height = RowOptions.ItemHeight;
|
|
return glyphRect;
|
|
}
|
|
protected virtual Image GetNodeBitmap(Node node)
|
|
{
|
|
if (node != null)
|
|
return node.Image;
|
|
return null;
|
|
}
|
|
protected virtual Image GetHoverNodeBitmap(Node node)
|
|
{
|
|
if (node != null)
|
|
return node.HoverImage;
|
|
return null;
|
|
}
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
base.OnPaint(e);
|
|
|
|
int hScrollOffset = HScrollValue();
|
|
int remainder = 0;
|
|
int visiblerows = MaxVisibleRows(out remainder);
|
|
if (remainder > 0)
|
|
visiblerows++;
|
|
|
|
bool drawColumnHeaders = true;
|
|
// draw columns
|
|
if (drawColumnHeaders)
|
|
{
|
|
Rectangle headerRect = e.ClipRectangle;
|
|
Columns.Draw(e.Graphics, headerRect, hScrollOffset);
|
|
}
|
|
|
|
int visibleRowIndex = 0;
|
|
TreeListColumn[] visibleColumns = this.Columns.VisibleColumns;
|
|
int columnsWidth = Columns.ColumnsWidth;
|
|
foreach (Node node in NodeCollection.ForwardNodeIterator(m_firstVisibleNode, true))
|
|
{
|
|
Rectangle rowRect = CalcRowRectangle(visibleRowIndex);
|
|
if (rowRect == Rectangle.Empty || rowRect.Bottom <= e.ClipRectangle.Top || rowRect.Top >= e.ClipRectangle.Bottom)
|
|
{
|
|
if (visibleRowIndex > visiblerows)
|
|
break;
|
|
visibleRowIndex++;
|
|
continue;
|
|
}
|
|
rowRect.X = RowHeaderWidth() - hScrollOffset;
|
|
rowRect.Width = columnsWidth;
|
|
|
|
// draw the current node
|
|
PaintNode(e.Graphics, rowRect, node, visibleColumns, visibleRowIndex);
|
|
|
|
// drow row header for current node
|
|
Rectangle headerRect = rowRect;
|
|
headerRect.X = 0;
|
|
headerRect.Width = RowHeaderWidth();
|
|
|
|
int absoluteRowIndex = visibleRowIndex + VScrollValue();
|
|
headerRect.Width = RowHeaderWidth();
|
|
m_rowPainter.DrawHeader(e.Graphics, headerRect, absoluteRowIndex == m_hotrow);
|
|
|
|
visibleRowIndex++;
|
|
}
|
|
|
|
visibleRowIndex = 0;
|
|
foreach (Node node in NodeCollection.ForwardNodeIterator(m_firstVisibleNode, true))
|
|
{
|
|
Rectangle rowRect = CalcRowRectangle(visibleRowIndex);
|
|
// draw horizontal grid line for current node
|
|
if (ViewOptions.ShowGridLines)
|
|
{
|
|
Rectangle r = rowRect;
|
|
r.X = RowHeaderWidth();
|
|
r.Width = columnsWidth - hScrollOffset;
|
|
m_rowPainter.DrawHorizontalGridLine(e.Graphics, r, GridLineColour);
|
|
}
|
|
|
|
visibleRowIndex++;
|
|
}
|
|
|
|
// draw vertical grid lines
|
|
if (ViewOptions.ShowGridLines)
|
|
{
|
|
// visible row count
|
|
int remainRows = Nodes.VisibleNodeCount - m_vScroll.Value;
|
|
if (visiblerows > remainRows)
|
|
visiblerows = remainRows;
|
|
|
|
Rectangle fullRect = ClientRectangle;
|
|
if (drawColumnHeaders)
|
|
fullRect.Y += Columns.Options.HeaderHeight;
|
|
fullRect.Height = visiblerows * RowOptions.ItemHeight;
|
|
Columns.Painter.DrawVerticalGridLines(Columns, e.Graphics, fullRect, hScrollOffset);
|
|
}
|
|
}
|
|
|
|
protected override bool IsInputKey(Keys keyData)
|
|
{
|
|
if ((int)(keyData & Keys.Shift) > 0)
|
|
return true;
|
|
switch (keyData)
|
|
{
|
|
case Keys.Left:
|
|
case Keys.Right:
|
|
case Keys.Down:
|
|
case Keys.Up:
|
|
case Keys.PageUp:
|
|
case Keys.PageDown:
|
|
case Keys.Home:
|
|
case Keys.End:
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
protected override void OnKeyDown(KeyEventArgs e)
|
|
{
|
|
Node newnode = null;
|
|
if (e.KeyCode == Keys.PageUp)
|
|
{
|
|
int remainder = 0;
|
|
int diff = MaxVisibleRows(out remainder)-1;
|
|
newnode = NodeCollection.GetNextNode(FocusedNode, -diff);
|
|
if (newnode == null)
|
|
newnode = Nodes.FirstVisibleNode();
|
|
}
|
|
if (e.KeyCode == Keys.PageDown)
|
|
{
|
|
int remainder = 0;
|
|
int diff = MaxVisibleRows(out remainder)-1;
|
|
newnode = NodeCollection.GetNextNode(FocusedNode, diff);
|
|
if (newnode == null)
|
|
newnode = Nodes.LastVisibleNode(true);
|
|
}
|
|
|
|
if (e.KeyCode == Keys.Down)
|
|
{
|
|
newnode = NodeCollection.GetNextNode(FocusedNode, 1);
|
|
}
|
|
if (e.KeyCode == Keys.Up)
|
|
{
|
|
newnode = NodeCollection.GetNextNode(FocusedNode, -1);
|
|
}
|
|
if (e.KeyCode == Keys.Home)
|
|
{
|
|
newnode = Nodes.FirstNode;
|
|
}
|
|
if (e.KeyCode == Keys.End)
|
|
{
|
|
newnode = Nodes.LastVisibleNode(true);
|
|
}
|
|
if (e.KeyCode == Keys.Left)
|
|
{
|
|
if (FocusedNode != null)
|
|
{
|
|
if (FocusedNode.Expanded)
|
|
{
|
|
FocusedNode.Collapse();
|
|
EnsureVisible(FocusedNode);
|
|
return;
|
|
}
|
|
if (FocusedNode.Parent != null)
|
|
{
|
|
FocusedNode = FocusedNode.Parent;
|
|
EnsureVisible(FocusedNode);
|
|
}
|
|
}
|
|
}
|
|
if (e.KeyCode == Keys.Right)
|
|
{
|
|
if (FocusedNode != null)
|
|
{
|
|
if (FocusedNode.Expanded == false && FocusedNode.HasChildren)
|
|
{
|
|
FocusedNode.Expand();
|
|
EnsureVisible(FocusedNode);
|
|
return;
|
|
}
|
|
if (FocusedNode.Expanded == true && FocusedNode.HasChildren)
|
|
{
|
|
FocusedNode = FocusedNode.Nodes.FirstNode;
|
|
EnsureVisible(FocusedNode);
|
|
}
|
|
}
|
|
}
|
|
if (newnode != null)
|
|
{
|
|
if (MultiSelect)
|
|
{
|
|
// tree behavior is
|
|
// keys none, the selected node is added as the focused and selected node
|
|
// keys control, only focused node is moved, the selected nodes collection is not modified
|
|
// keys shift, selection from first selected node to current node is done
|
|
if (Control.ModifierKeys == Keys.Control)
|
|
FocusedNode = newnode;
|
|
else
|
|
MultiSelectAdd(newnode, Control.ModifierKeys);
|
|
}
|
|
else
|
|
FocusedNode = newnode;
|
|
EnsureVisible(FocusedNode);
|
|
}
|
|
base.OnKeyDown(e);
|
|
}
|
|
|
|
internal void internalUpdateStyles()
|
|
{
|
|
base.UpdateStyles();
|
|
}
|
|
|
|
#region ISupportInitialize Members
|
|
|
|
public void BeginInit()
|
|
{
|
|
Columns.BeginInit();
|
|
}
|
|
public void EndInit()
|
|
{
|
|
Columns.EndInit();
|
|
}
|
|
|
|
#endregion
|
|
internal new bool DesignMode
|
|
{
|
|
get { return base.DesignMode; }
|
|
}
|
|
}
|
|
|
|
public class TreeListViewNodes : NodeCollection
|
|
{
|
|
TreeListView m_tree;
|
|
bool m_isUpdating = false;
|
|
public void BeginUpdate()
|
|
{
|
|
m_isUpdating = true;
|
|
}
|
|
public void EndUpdate()
|
|
{
|
|
m_isUpdating = false;
|
|
}
|
|
public TreeListViewNodes(TreeListView owner) : base(null)
|
|
{
|
|
m_tree = owner;
|
|
OwnerView = owner;
|
|
}
|
|
protected override void UpdateNodeCount(int oldvalue, int newvalue)
|
|
{
|
|
base.UpdateNodeCount(oldvalue, newvalue);
|
|
if (!m_isUpdating)
|
|
m_tree.RecalcLayout();
|
|
}
|
|
public override void Clear()
|
|
{
|
|
base.Clear();
|
|
m_tree.RecalcLayout();
|
|
}
|
|
public override void NodetifyBeforeExpand(Node nodeToExpand, bool expanding)
|
|
{
|
|
if (!m_tree.DesignMode)
|
|
m_tree.OnNotifyBeforeExpand(nodeToExpand, expanding);
|
|
}
|
|
public override void NodetifyAfterExpand(Node nodeToExpand, bool expanded)
|
|
{
|
|
m_tree.OnNotifyAfterExpand(nodeToExpand, expanded);
|
|
}
|
|
protected override int GetFieldIndex(string fieldname)
|
|
{
|
|
TreeListColumn col = m_tree.Columns[fieldname];
|
|
if (col != null)
|
|
return col.Index;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|