You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
553 lines
13 KiB
553 lines
13 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Text; |
|
using System.Windows.Forms; |
|
using System.Drawing; |
|
using Aga.Controls.Tree.NodeControls; |
|
using System.Drawing.Imaging; |
|
using System.Threading; |
|
|
|
namespace Aga.Controls.Tree |
|
{ |
|
public partial class TreeViewAdv |
|
{ |
|
#region Keys |
|
|
|
protected override bool IsInputChar(char charCode) |
|
{ |
|
return true; |
|
} |
|
|
|
protected override bool IsInputKey(Keys keyData) |
|
{ |
|
if (((keyData & Keys.Up) == Keys.Up) |
|
|| ((keyData & Keys.Down) == Keys.Down) |
|
|| ((keyData & Keys.Left) == Keys.Left) |
|
|| ((keyData & Keys.Right) == Keys.Right)) |
|
return true; |
|
else |
|
return base.IsInputKey(keyData); |
|
} |
|
|
|
internal void ChangeInput() |
|
{ |
|
if ((ModifierKeys & Keys.Shift) == Keys.Shift) |
|
{ |
|
if (!(Input is InputWithShift)) |
|
Input = new InputWithShift(this); |
|
} |
|
else if ((ModifierKeys & Keys.Control) == Keys.Control) |
|
{ |
|
if (!(Input is InputWithControl)) |
|
Input = new InputWithControl(this); |
|
} |
|
else |
|
{ |
|
if (!(Input.GetType() == typeof(NormalInputState))) |
|
Input = new NormalInputState(this); |
|
} |
|
} |
|
|
|
protected override void OnKeyDown(KeyEventArgs e) |
|
{ |
|
base.OnKeyDown(e); |
|
if (!e.Handled) |
|
{ |
|
if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey) |
|
ChangeInput(); |
|
Input.KeyDown(e); |
|
if (!e.Handled) |
|
{ |
|
foreach (NodeControlInfo item in GetNodeControls(CurrentNode)) |
|
{ |
|
item.Control.KeyDown(e); |
|
if (e.Handled) |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
protected override void OnKeyUp(KeyEventArgs e) |
|
{ |
|
base.OnKeyUp(e); |
|
if (!e.Handled) |
|
{ |
|
if (e.KeyCode == Keys.ShiftKey || e.KeyCode == Keys.ControlKey) |
|
ChangeInput(); |
|
if (!e.Handled) |
|
{ |
|
foreach (NodeControlInfo item in GetNodeControls(CurrentNode)) |
|
{ |
|
item.Control.KeyUp(e); |
|
if (e.Handled) |
|
return; |
|
} |
|
} |
|
} |
|
} |
|
|
|
protected override void OnKeyPress(KeyPressEventArgs e) |
|
{ |
|
base.OnKeyPress(e); |
|
if (!e.Handled) |
|
_search.Search(e.KeyChar); |
|
} |
|
|
|
#endregion |
|
|
|
#region Mouse |
|
|
|
private TreeNodeAdvMouseEventArgs CreateMouseArgs(MouseEventArgs e) |
|
{ |
|
TreeNodeAdvMouseEventArgs args = new TreeNodeAdvMouseEventArgs(e); |
|
args.ViewLocation = new Point(e.X + OffsetX, |
|
e.Y + _rowLayout.GetRowBounds(FirstVisibleRow).Y - ColumnHeaderHeight); |
|
args.ModifierKeys = ModifierKeys; |
|
args.Node = GetNodeAt(e.Location); |
|
NodeControlInfo info = GetNodeControlInfoAt(args.Node, e.Location); |
|
args.ControlBounds = info.Bounds; |
|
args.Control = info.Control; |
|
return args; |
|
} |
|
|
|
protected override void OnMouseWheel(MouseEventArgs e) |
|
{ |
|
_search.EndSearch(); |
|
if (SystemInformation.MouseWheelScrollLines > 0) |
|
{ |
|
int lines = e.Delta * SystemInformation.MouseWheelScrollLines / 120; |
|
int newValue = _vScrollBar.Value - lines; |
|
newValue = Math.Min(_vScrollBar.Maximum - _vScrollBar.LargeChange + 1, newValue); |
|
newValue = Math.Min(_vScrollBar.Maximum, newValue); |
|
_vScrollBar.Value = Math.Max(_vScrollBar.Minimum, newValue); |
|
} |
|
base.OnMouseWheel(e); |
|
} |
|
|
|
protected override void OnMouseDown(MouseEventArgs e) |
|
{ |
|
if (!Focused) |
|
Focus(); |
|
|
|
_search.EndSearch(); |
|
if (e.Button == MouseButtons.Left) |
|
{ |
|
TreeColumn c; |
|
c = GetColumnDividerAt(e.Location); |
|
if (c != null) |
|
{ |
|
Input = new ResizeColumnState(this, c, e.Location); |
|
return; |
|
} |
|
c = GetColumnAt(e.Location); |
|
if (c != null) |
|
{ |
|
Input = new ClickColumnState(this, c, e.Location); |
|
UpdateView(); |
|
return; |
|
} |
|
} |
|
|
|
ChangeInput(); |
|
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); |
|
|
|
if (args.Node != null && args.Control != null) |
|
args.Control.MouseDown(args); |
|
|
|
if (!args.Handled) { |
|
Input.MouseDown(args); |
|
base.ContextMenuStrip = _cms; |
|
} else |
|
base.ContextMenuStrip = null; |
|
|
|
base.OnMouseDown(e); |
|
} |
|
|
|
protected override void OnMouseClick(MouseEventArgs e) |
|
{ |
|
//TODO: Disable when click on plusminus icon |
|
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); |
|
if (args.Node != null) |
|
OnNodeMouseClick(args); |
|
|
|
base.OnMouseClick(e); |
|
} |
|
|
|
protected override void OnMouseDoubleClick(MouseEventArgs e) |
|
{ |
|
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); |
|
|
|
if (args.Node != null && args.Control != null) |
|
args.Control.MouseDoubleClick(args); |
|
|
|
if (!args.Handled) |
|
{ |
|
if (args.Node != null) |
|
OnNodeMouseDoubleClick(args); |
|
|
|
if (!args.Handled) |
|
{ |
|
if (args.Node != null && args.Button == MouseButtons.Left) |
|
args.Node.IsExpanded = !args.Node.IsExpanded; |
|
} |
|
} |
|
|
|
base.OnMouseDoubleClick(e); |
|
} |
|
|
|
protected override void OnMouseUp(MouseEventArgs e) |
|
{ |
|
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); |
|
if (Input is ResizeColumnState) |
|
Input.MouseUp(args); |
|
else |
|
{ |
|
if (args.Node != null && args.Control != null) |
|
args.Control.MouseUp(args); |
|
if (!args.Handled) |
|
Input.MouseUp(args); |
|
|
|
base.OnMouseUp(e); |
|
} |
|
} |
|
|
|
protected override void OnMouseMove(MouseEventArgs e) |
|
{ |
|
if (Input.MouseMove(e)) |
|
return; |
|
|
|
base.OnMouseMove(e); |
|
SetCursor(e); |
|
UpdateToolTip(e); |
|
if (ItemDragMode && Dist(e.Location, ItemDragStart) > ItemDragSensivity |
|
&& CurrentNode != null && CurrentNode.IsSelected) |
|
{ |
|
ItemDragMode = false; |
|
_toolTip.Active = false; |
|
OnItemDrag(e.Button, Selection.ToArray()); |
|
} |
|
} |
|
|
|
protected override void OnMouseLeave(EventArgs e) |
|
{ |
|
_hotColumn = null; |
|
UpdateHeaders(); |
|
base.OnMouseLeave(e); |
|
} |
|
|
|
private void SetCursor(MouseEventArgs e) |
|
{ |
|
TreeColumn col; |
|
col = GetColumnDividerAt(e.Location); |
|
if (col == null) |
|
_innerCursor = null; |
|
else |
|
{ |
|
if (col.Width == 0) |
|
_innerCursor = ResourceHelper.DVSplitCursor; |
|
else |
|
_innerCursor = Cursors.VSplit; |
|
} |
|
|
|
col = GetColumnAt(e.Location); |
|
if (col != _hotColumn) |
|
{ |
|
_hotColumn = col; |
|
UpdateHeaders(); |
|
} |
|
} |
|
|
|
internal TreeColumn GetColumnAt(Point p) |
|
{ |
|
if (p.Y > ColumnHeaderHeight) |
|
return null; |
|
|
|
int x = -OffsetX; |
|
foreach (TreeColumn col in Columns) |
|
{ |
|
if (col.IsVisible) |
|
{ |
|
Rectangle rect = new Rectangle(x, 0, col.Width, ColumnHeaderHeight); |
|
x += col.Width; |
|
if (rect.Contains(p)) |
|
return col; |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
internal int GetColumnX(TreeColumn column) |
|
{ |
|
int x = -OffsetX; |
|
foreach (TreeColumn col in Columns) |
|
{ |
|
if (col.IsVisible) |
|
{ |
|
if (column == col) |
|
return x; |
|
else |
|
x += col.Width; |
|
} |
|
} |
|
return x; |
|
} |
|
|
|
internal TreeColumn GetColumnDividerAt(Point p) |
|
{ |
|
if (p.Y > ColumnHeaderHeight) |
|
return null; |
|
|
|
int x = -OffsetX; |
|
TreeColumn prevCol = null; |
|
Rectangle left, right; |
|
foreach (TreeColumn col in Columns) |
|
{ |
|
if (col.IsVisible) |
|
{ |
|
if (col.Width > 0) |
|
{ |
|
left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight); |
|
right = new Rectangle(x + col.Width - (DividerWidth / 2), 0, DividerWidth / 2, ColumnHeaderHeight); |
|
if (left.Contains(p) && prevCol != null) |
|
return prevCol; |
|
else if (right.Contains(p)) |
|
return col; |
|
} |
|
prevCol = col; |
|
x += col.Width; |
|
} |
|
} |
|
|
|
left = new Rectangle(x, 0, DividerWidth / 2, ColumnHeaderHeight); |
|
if (left.Contains(p) && prevCol != null) |
|
return prevCol; |
|
|
|
return null; |
|
} |
|
|
|
TreeColumn _tooltipColumn; |
|
private void UpdateToolTip(MouseEventArgs e) |
|
{ |
|
TreeColumn col = GetColumnAt(e.Location); |
|
if (col != null) |
|
{ |
|
if (col != _tooltipColumn) |
|
SetTooltip(col.TooltipText); |
|
} |
|
else |
|
DisplayNodesTooltip(e); |
|
_tooltipColumn = col; |
|
} |
|
|
|
TreeNodeAdv _hotNode; |
|
NodeControl _hotControl; |
|
private void DisplayNodesTooltip(MouseEventArgs e) |
|
{ |
|
if (ShowNodeToolTips) |
|
{ |
|
TreeNodeAdvMouseEventArgs args = CreateMouseArgs(e); |
|
if (args.Node != null && args.Control != null) |
|
{ |
|
if (args.Node != _hotNode || args.Control != _hotControl) |
|
SetTooltip(GetNodeToolTip(args)); |
|
} |
|
else |
|
_toolTip.SetToolTip(this, null); |
|
|
|
_hotControl = args.Control; |
|
_hotNode = args.Node; |
|
} |
|
else |
|
_toolTip.SetToolTip(this, null); |
|
} |
|
|
|
private void SetTooltip(string text) |
|
{ |
|
if (!String.IsNullOrEmpty(text)) |
|
{ |
|
_toolTip.Active = false; |
|
_toolTip.SetToolTip(this, text); |
|
_toolTip.Active = true; |
|
} |
|
else |
|
_toolTip.SetToolTip(this, null); |
|
} |
|
|
|
private string GetNodeToolTip(TreeNodeAdvMouseEventArgs args) |
|
{ |
|
string msg = args.Control.GetToolTip(args.Node); |
|
|
|
BaseTextControl btc = args.Control as BaseTextControl; |
|
if (btc != null && btc.DisplayHiddenContentInToolTip && String.IsNullOrEmpty(msg)) |
|
{ |
|
Size ms = btc.GetActualSize(args.Node, _measureContext); |
|
if (ms.Width > args.ControlBounds.Size.Width || ms.Height > args.ControlBounds.Size.Height |
|
|| args.ControlBounds.Right - OffsetX > DisplayRectangle.Width) |
|
msg = btc.GetLabel(args.Node); |
|
} |
|
|
|
if (String.IsNullOrEmpty(msg) && DefaultToolTipProvider != null) |
|
msg = DefaultToolTipProvider.GetToolTip(args.Node, args.Control); |
|
|
|
return msg; |
|
} |
|
|
|
#endregion |
|
|
|
#region DragDrop |
|
|
|
private bool _dragAutoScrollFlag = false; |
|
private Bitmap _dragBitmap = null; |
|
private System.Threading.Timer _dragTimer; |
|
|
|
private void StartDragTimer() |
|
{ |
|
if (_dragTimer == null) |
|
_dragTimer = new System.Threading.Timer(new TimerCallback(DragTimerTick), null, 0, 100); |
|
} |
|
|
|
private void StopDragTimer() |
|
{ |
|
if (_dragTimer != null) |
|
{ |
|
_dragTimer.Dispose(); |
|
_dragTimer = null; |
|
} |
|
} |
|
|
|
private void SetDropPosition(Point pt) |
|
{ |
|
TreeNodeAdv node = GetNodeAt(pt); |
|
OnDropNodeValidating(pt, ref node); |
|
_dropPosition.Node = node; |
|
if (node != null) |
|
{ |
|
Rectangle first = _rowLayout.GetRowBounds(FirstVisibleRow); |
|
Rectangle bounds = _rowLayout.GetRowBounds(node.Row); |
|
float pos = (pt.Y + first.Y - ColumnHeaderHeight - bounds.Y) / (float)bounds.Height; |
|
if (pos < TopEdgeSensivity) |
|
_dropPosition.Position = NodePosition.Before; |
|
else if (pos > (1 - BottomEdgeSensivity)) |
|
_dropPosition.Position = NodePosition.After; |
|
else |
|
_dropPosition.Position = NodePosition.Inside; |
|
} |
|
} |
|
|
|
private void DragTimerTick(object state) |
|
{ |
|
_dragAutoScrollFlag = true; |
|
} |
|
|
|
private void DragAutoScroll() |
|
{ |
|
_dragAutoScrollFlag = false; |
|
Point pt = PointToClient(MousePosition); |
|
if (pt.Y < 20 && _vScrollBar.Value > 0) |
|
_vScrollBar.Value--; |
|
else if (pt.Y > Height - 20 && _vScrollBar.Value <= _vScrollBar.Maximum - _vScrollBar.LargeChange) |
|
_vScrollBar.Value++; |
|
} |
|
|
|
public void DoDragDropSelectedNodes(DragDropEffects allowedEffects) |
|
{ |
|
if (SelectedNodes.Count > 0) |
|
{ |
|
TreeNodeAdv[] nodes = new TreeNodeAdv[SelectedNodes.Count]; |
|
SelectedNodes.CopyTo(nodes, 0); |
|
DoDragDrop(nodes, allowedEffects); |
|
} |
|
} |
|
|
|
private void CreateDragBitmap(IDataObject data) |
|
{ |
|
if (UseColumns || !DisplayDraggingNodes) |
|
return; |
|
|
|
TreeNodeAdv[] nodes = data.GetData(typeof(TreeNodeAdv[])) as TreeNodeAdv[]; |
|
if (nodes != null && nodes.Length > 0) |
|
{ |
|
Rectangle rect = DisplayRectangle; |
|
Bitmap bitmap = new Bitmap(rect.Width, rect.Height); |
|
using (Graphics gr = Graphics.FromImage(bitmap)) |
|
{ |
|
gr.Clear(BackColor); |
|
DrawContext context = new DrawContext(); |
|
context.Graphics = gr; |
|
context.Font = Font; |
|
context.Enabled = true; |
|
int y = 0; |
|
int maxWidth = 0; |
|
foreach (TreeNodeAdv node in nodes) |
|
{ |
|
if (node.Tree == this) |
|
{ |
|
int x = 0; |
|
int height = _rowLayout.GetRowBounds(node.Row).Height; |
|
foreach (NodeControl c in NodeControls) |
|
{ |
|
Size s = c.GetActualSize(node, context); |
|
if (!s.IsEmpty) |
|
{ |
|
int width = s.Width; |
|
rect = new Rectangle(x, y, width, height); |
|
x += (width + 1); |
|
context.Bounds = rect; |
|
c.Draw(node, context); |
|
} |
|
} |
|
y += height; |
|
maxWidth = Math.Max(maxWidth, x); |
|
} |
|
} |
|
|
|
if (maxWidth > 0 && y > 0) |
|
{ |
|
_dragBitmap = new Bitmap(maxWidth, y, PixelFormat.Format32bppArgb); |
|
using (Graphics tgr = Graphics.FromImage(_dragBitmap)) |
|
tgr.DrawImage(bitmap, Point.Empty); |
|
BitmapHelper.SetAlphaChanelValue(_dragBitmap, 150); |
|
} |
|
else |
|
_dragBitmap = null; |
|
} |
|
} |
|
} |
|
|
|
protected override void OnDragOver(DragEventArgs drgevent) |
|
{ |
|
ItemDragMode = false; |
|
Point pt = PointToClient(new Point(drgevent.X, drgevent.Y)); |
|
if (_dragAutoScrollFlag) |
|
DragAutoScroll(); |
|
SetDropPosition(pt); |
|
UpdateView(); |
|
base.OnDragOver(drgevent); |
|
} |
|
|
|
protected override void OnDragEnter(DragEventArgs drgevent) |
|
{ |
|
_search.EndSearch(); |
|
DragMode = true; |
|
CreateDragBitmap(drgevent.Data); |
|
base.OnDragEnter(drgevent); |
|
} |
|
|
|
protected override void OnDragLeave(EventArgs e) |
|
{ |
|
DragMode = false; |
|
UpdateView(); |
|
base.OnDragLeave(e); |
|
} |
|
|
|
protected override void OnDragDrop(DragEventArgs drgevent) |
|
{ |
|
DragMode = false; |
|
UpdateView(); |
|
base.OnDragDrop(drgevent); |
|
} |
|
|
|
#endregion |
|
} |
|
}
|
|
|