first commit
This commit is contained in:
@@ -0,0 +1,314 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public abstract class BaseTextControl : EditableControl
|
||||
{
|
||||
private TextFormatFlags _baseFormatFlags;
|
||||
private TextFormatFlags _formatFlags;
|
||||
private Pen _focusPen;
|
||||
private StringFormat _format;
|
||||
|
||||
#region Properties
|
||||
|
||||
private Font _font = null;
|
||||
public Font Font
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_font == null)
|
||||
return Control.DefaultFont;
|
||||
else
|
||||
return _font;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == Control.DefaultFont)
|
||||
_font = null;
|
||||
else
|
||||
_font = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected bool ShouldSerializeFont()
|
||||
{
|
||||
return (_font != null);
|
||||
}
|
||||
|
||||
private HorizontalAlignment _textAlign = HorizontalAlignment.Left;
|
||||
[DefaultValue(HorizontalAlignment.Left)]
|
||||
public HorizontalAlignment TextAlign
|
||||
{
|
||||
get { return _textAlign; }
|
||||
set
|
||||
{
|
||||
_textAlign = value;
|
||||
SetFormatFlags();
|
||||
}
|
||||
}
|
||||
|
||||
private StringTrimming _trimming = StringTrimming.None;
|
||||
[DefaultValue(StringTrimming.None)]
|
||||
public StringTrimming Trimming
|
||||
{
|
||||
get { return _trimming; }
|
||||
set
|
||||
{
|
||||
_trimming = value;
|
||||
SetFormatFlags();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _displayHiddenContentInToolTip = true;
|
||||
[DefaultValue(true)]
|
||||
public bool DisplayHiddenContentInToolTip
|
||||
{
|
||||
get { return _displayHiddenContentInToolTip; }
|
||||
set { _displayHiddenContentInToolTip = value; }
|
||||
}
|
||||
|
||||
private bool _useCompatibleTextRendering = false;
|
||||
[DefaultValue(false)]
|
||||
public bool UseCompatibleTextRendering
|
||||
{
|
||||
get { return _useCompatibleTextRendering; }
|
||||
set { _useCompatibleTextRendering = value; }
|
||||
}
|
||||
|
||||
[DefaultValue(false)]
|
||||
public bool TrimMultiLine
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected BaseTextControl()
|
||||
{
|
||||
IncrementalSearchEnabled = true;
|
||||
_focusPen = new Pen(Color.Black);
|
||||
_focusPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
|
||||
|
||||
_format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoClip | StringFormatFlags.FitBlackBox | StringFormatFlags.MeasureTrailingSpaces);
|
||||
_baseFormatFlags = TextFormatFlags.PreserveGraphicsClipping |
|
||||
TextFormatFlags.PreserveGraphicsTranslateTransform;
|
||||
SetFormatFlags();
|
||||
LeftMargin = 3;
|
||||
}
|
||||
|
||||
private void SetFormatFlags()
|
||||
{
|
||||
_format.Alignment = TextHelper.TranslateAligment(TextAlign);
|
||||
_format.Trimming = Trimming;
|
||||
|
||||
_formatFlags = _baseFormatFlags | TextHelper.TranslateAligmentToFlag(TextAlign)
|
||||
| TextHelper.TranslateTrimmingToFlag(Trimming);
|
||||
}
|
||||
|
||||
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
return GetLabelSize(node, context);
|
||||
}
|
||||
|
||||
protected Size GetLabelSize(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
return GetLabelSize(node, context, GetLabel(node));
|
||||
}
|
||||
|
||||
protected Size GetLabelSize(TreeNodeAdv node, DrawContext context, string label)
|
||||
{
|
||||
PerformanceAnalyzer.Start("GetLabelSize");
|
||||
CheckThread();
|
||||
Font font = GetDrawingFont(node, context, label);
|
||||
Size s = Size.Empty;
|
||||
if (UseCompatibleTextRendering)
|
||||
s = TextRenderer.MeasureText(label, font);
|
||||
else
|
||||
{
|
||||
SizeF sf = context.Graphics.MeasureString(label, font);
|
||||
s = new Size((int)Math.Ceiling(sf.Width), (int)Math.Ceiling(sf.Height));
|
||||
}
|
||||
PerformanceAnalyzer.Finish("GetLabelSize");
|
||||
|
||||
if (!s.IsEmpty)
|
||||
return s;
|
||||
else
|
||||
return new Size(10, Font.Height);
|
||||
}
|
||||
|
||||
protected Font GetDrawingFont(TreeNodeAdv node, DrawContext context, string label)
|
||||
{
|
||||
Font font = context.Font;
|
||||
if (DrawTextMustBeFired(node))
|
||||
{
|
||||
DrawEventArgs args = new DrawEventArgs(node, this, context, label);
|
||||
args.Font = context.Font;
|
||||
OnDrawText(args);
|
||||
font = args.Font;
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
protected void SetEditControlProperties(Control control, TreeNodeAdv node)
|
||||
{
|
||||
string label = GetLabel(node);
|
||||
DrawContext context = new DrawContext();
|
||||
context.Font = control.Font;
|
||||
control.Font = GetDrawingFont(node, context, label);
|
||||
}
|
||||
|
||||
public override void Draw(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
if (context.CurrentEditorOwner == this && node == Parent.CurrentNode)
|
||||
return;
|
||||
|
||||
PerformanceAnalyzer.Start("BaseTextControl.Draw");
|
||||
string label = GetLabel(node);
|
||||
Rectangle bounds = GetBounds(node, context);
|
||||
Rectangle focusRect = new Rectangle(bounds.X, context.Bounds.Y,
|
||||
bounds.Width, context.Bounds.Height);
|
||||
|
||||
Brush backgroundBrush;
|
||||
Color textColor;
|
||||
Font font;
|
||||
CreateBrushes(node, context, label, out backgroundBrush, out textColor, out font, ref label);
|
||||
|
||||
if (backgroundBrush != null)
|
||||
context.Graphics.FillRectangle(backgroundBrush, focusRect);
|
||||
if (context.DrawFocus)
|
||||
{
|
||||
focusRect.Width--;
|
||||
focusRect.Height--;
|
||||
if (context.DrawSelection == DrawSelectionMode.None)
|
||||
_focusPen.Color = SystemColors.ControlText;
|
||||
else
|
||||
_focusPen.Color = SystemColors.InactiveCaption;
|
||||
context.Graphics.DrawRectangle(_focusPen, focusRect);
|
||||
}
|
||||
|
||||
PerformanceAnalyzer.Start("BaseTextControl.DrawText");
|
||||
if (UseCompatibleTextRendering)
|
||||
TextRenderer.DrawText(context.Graphics, label, font, bounds, textColor, _formatFlags);
|
||||
else
|
||||
context.Graphics.DrawString(label, font, GetFrush(textColor), bounds, _format);
|
||||
PerformanceAnalyzer.Finish("BaseTextControl.DrawText");
|
||||
|
||||
PerformanceAnalyzer.Finish("BaseTextControl.Draw");
|
||||
}
|
||||
|
||||
private static Dictionary<Color, Brush> _brushes = new Dictionary<Color,Brush>();
|
||||
private static Brush GetFrush(Color color)
|
||||
{
|
||||
Brush br;
|
||||
if (_brushes.ContainsKey(color))
|
||||
br = _brushes[color];
|
||||
else
|
||||
{
|
||||
br = new SolidBrush(color);
|
||||
_brushes.Add(color, br);
|
||||
}
|
||||
return br;
|
||||
}
|
||||
|
||||
private void CreateBrushes(TreeNodeAdv node, DrawContext context, string text, out Brush backgroundBrush, out Color textColor, out Font font, ref string label)
|
||||
{
|
||||
textColor = Parent.ForeColor;
|
||||
backgroundBrush = null;
|
||||
font = context.Font;
|
||||
if (context.DrawSelection == DrawSelectionMode.Active)
|
||||
{
|
||||
textColor = SystemColors.HighlightText;
|
||||
backgroundBrush = SystemBrushes.Highlight;
|
||||
}
|
||||
else if (context.DrawSelection == DrawSelectionMode.Inactive)
|
||||
{
|
||||
textColor = Parent.ForeColor;
|
||||
backgroundBrush = SystemBrushes.InactiveBorder;
|
||||
}
|
||||
else if (context.DrawSelection == DrawSelectionMode.FullRowSelect)
|
||||
textColor = Parent.ForeColor;
|
||||
|
||||
if (!context.Enabled)
|
||||
textColor = SystemColors.GrayText;
|
||||
|
||||
if (DrawTextMustBeFired(node))
|
||||
{
|
||||
DrawEventArgs args = new DrawEventArgs(node, this, context, text);
|
||||
args.Text = label;
|
||||
args.TextColor = textColor;
|
||||
args.BackgroundBrush = backgroundBrush;
|
||||
args.Font = font;
|
||||
|
||||
OnDrawText(args);
|
||||
|
||||
textColor = args.TextColor;
|
||||
backgroundBrush = args.BackgroundBrush;
|
||||
font = args.Font;
|
||||
label = args.Text;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetLabel(TreeNodeAdv node)
|
||||
{
|
||||
if (node != null && node.Tag != null)
|
||||
{
|
||||
object obj = GetValue(node);
|
||||
if (obj != null)
|
||||
return FormatLabel(obj);
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
protected virtual string FormatLabel(object obj)
|
||||
{
|
||||
var res = obj.ToString();
|
||||
if (TrimMultiLine && res != null)
|
||||
{
|
||||
string[] parts = res.Split('\n');
|
||||
if (parts.Length > 1)
|
||||
return parts[0] + "...";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public void SetLabel(TreeNodeAdv node, string value)
|
||||
{
|
||||
SetValue(node, value);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
{
|
||||
_focusPen.Dispose();
|
||||
_format.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires when control is going to draw a text. Can be used to change text or back color
|
||||
/// </summary>
|
||||
public event EventHandler<DrawEventArgs> DrawText;
|
||||
protected virtual void OnDrawText(DrawEventArgs args)
|
||||
{
|
||||
TreeViewAdv tree = args.Node.Tree;
|
||||
if (tree != null)
|
||||
tree.FireDrawControl(args);
|
||||
if (DrawText != null)
|
||||
DrawText(this, args);
|
||||
}
|
||||
|
||||
protected virtual bool DrawTextMustBeFired(TreeNodeAdv node)
|
||||
{
|
||||
return DrawText != null || (node.Tree != null && node.Tree.DrawControlMustBeFired());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public abstract class BindableControl : NodeControl
|
||||
{
|
||||
private struct MemberAdapter
|
||||
{
|
||||
private object _obj;
|
||||
private PropertyInfo _pi;
|
||||
private FieldInfo _fi;
|
||||
|
||||
public static readonly MemberAdapter Empty = new MemberAdapter();
|
||||
|
||||
public Type MemberType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pi != null)
|
||||
return _pi.PropertyType;
|
||||
else if (_fi != null)
|
||||
return _fi.FieldType;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_pi != null && _pi.CanRead)
|
||||
return _pi.GetValue(_obj, null);
|
||||
else if (_fi != null)
|
||||
return _fi.GetValue(_obj);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_pi != null && _pi.CanWrite)
|
||||
_pi.SetValue(_obj, value, null);
|
||||
else if (_fi != null)
|
||||
_fi.SetValue(_obj, value);
|
||||
}
|
||||
}
|
||||
|
||||
public MemberAdapter(object obj, PropertyInfo pi)
|
||||
{
|
||||
_obj = obj;
|
||||
_pi = pi;
|
||||
_fi = null;
|
||||
}
|
||||
|
||||
public MemberAdapter(object obj, FieldInfo fi)
|
||||
{
|
||||
_obj = obj;
|
||||
_fi = fi;
|
||||
_pi = null;
|
||||
}
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
private bool _virtualMode = false;
|
||||
[DefaultValue(false), Category("Data")]
|
||||
public bool VirtualMode
|
||||
{
|
||||
get { return _virtualMode; }
|
||||
set { _virtualMode = value; }
|
||||
}
|
||||
|
||||
private string _propertyName = "";
|
||||
[DefaultValue(""), Category("Data")]
|
||||
public string DataPropertyName
|
||||
{
|
||||
get { return _propertyName; }
|
||||
set
|
||||
{
|
||||
if (_propertyName == null)
|
||||
_propertyName = string.Empty;
|
||||
_propertyName = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool _incrementalSearchEnabled = false;
|
||||
[DefaultValue(false)]
|
||||
public bool IncrementalSearchEnabled
|
||||
{
|
||||
get { return _incrementalSearchEnabled; }
|
||||
set { _incrementalSearchEnabled = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual object GetValue(TreeNodeAdv node)
|
||||
{
|
||||
if (VirtualMode)
|
||||
{
|
||||
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
|
||||
OnValueNeeded(args);
|
||||
return args.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetMemberAdapter(node).Value;
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
if (ex.InnerException != null)
|
||||
throw new ArgumentException(ex.InnerException.Message, ex.InnerException);
|
||||
else
|
||||
throw new ArgumentException(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetValue(TreeNodeAdv node, object value)
|
||||
{
|
||||
if (VirtualMode)
|
||||
{
|
||||
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
|
||||
args.Value = value;
|
||||
OnValuePushed(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
MemberAdapter ma = GetMemberAdapter(node);
|
||||
ma.Value = value;
|
||||
}
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
if (ex.InnerException != null)
|
||||
throw new ArgumentException(ex.InnerException.Message, ex.InnerException);
|
||||
else
|
||||
throw new ArgumentException(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type GetPropertyType(TreeNodeAdv node)
|
||||
{
|
||||
return GetMemberAdapter(node).MemberType;
|
||||
}
|
||||
|
||||
private MemberAdapter GetMemberAdapter(TreeNodeAdv node)
|
||||
{
|
||||
if (node.Tag != null && !string.IsNullOrEmpty(DataPropertyName))
|
||||
{
|
||||
Type type = node.Tag.GetType();
|
||||
PropertyInfo pi = type.GetProperty(DataPropertyName);
|
||||
if (pi != null)
|
||||
return new MemberAdapter(node.Tag, pi);
|
||||
else
|
||||
{
|
||||
FieldInfo fi = type.GetField(DataPropertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (fi != null)
|
||||
return new MemberAdapter(node.Tag, fi);
|
||||
}
|
||||
}
|
||||
return MemberAdapter.Empty;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (string.IsNullOrEmpty(DataPropertyName))
|
||||
return GetType().Name;
|
||||
else
|
||||
return string.Format("{0} ({1})", GetType().Name, DataPropertyName);
|
||||
}
|
||||
|
||||
public event EventHandler<NodeControlValueEventArgs> ValueNeeded;
|
||||
private void OnValueNeeded(NodeControlValueEventArgs args)
|
||||
{
|
||||
if (ValueNeeded != null)
|
||||
ValueNeeded(this, args);
|
||||
}
|
||||
|
||||
public event EventHandler<NodeControlValueEventArgs> ValuePushed;
|
||||
private void OnValuePushed(NodeControlValueEventArgs args)
|
||||
{
|
||||
if (ValuePushed != null)
|
||||
ValuePushed(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram MajorVersion="1" MinorVersion="1">
|
||||
<Font Name="Microsoft Sans Serif" Size="8.25" />
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeStateIcon" Collapsed="true">
|
||||
<Position X="0.5" Y="4" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeStateIcon.cs</FileName>
|
||||
<HashCode>ABAAAAAAAAQAQAAAAAAAAAAAAAAAAAAAQIAAAAAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.BindableControl" Collapsed="true">
|
||||
<Position X="2.75" Y="1.5" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\BindableControl.cs</FileName>
|
||||
<HashCode>FAAAAAAQIBAQCgAEAAAAIAAAAAAAAAEMAAACAAAAAAE=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeCheckBox" Collapsed="true">
|
||||
<Position X="5" Y="4" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeCheckBox.cs</FileName>
|
||||
<HashCode>AAEAAAAAAAACgkQCAAAAAAigAgAAEGABAAAIAAAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeControl" Collapsed="true">
|
||||
<Position X="1.5" Y="0.5" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeControl.cs</FileName>
|
||||
<HashCode>AAAAAJAAgIgBkkoQAAgAQAAwAAABEIQAAEBIAAAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
<Compartments>
|
||||
<Compartment Name="Fields" Collapsed="true" />
|
||||
</Compartments>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeIcon" Collapsed="true">
|
||||
<Position X="0.5" Y="2.75" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeIcon.cs</FileName>
|
||||
<HashCode>ABAAAAAAAAAAAgAAAAAAAAAgAAAAAAAAAAAAAAAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodePlusMinus" Collapsed="true">
|
||||
<Position X="0.5" Y="1.5" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodePlusMinus.cs</FileName>
|
||||
<HashCode>AAAAAAAAAAAAAgAAAAAAAEAgAAAAMCAAAAAIACAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.BaseTextControl" Collapsed="true">
|
||||
<Position X="3" Y="5" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\BaseTextControl.cs</FileName>
|
||||
<HashCode>AAAAICBQACAAIgACBCAEAQA8AgmFoAAwAAAAACACAMA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeTextBox" Collapsed="true">
|
||||
<Position X="1" Y="6" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeTextBox.cs</FileName>
|
||||
<HashCode>QQQAhAAAADAMgAAAABAAAAAAAgEAIAAAAAAAAIAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.EditableControl" Collapsed="true">
|
||||
<Position X="3" Y="4" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\EditableControl.cs</FileName>
|
||||
<HashCode>QQAgAAAACGgkAMAABAEEkADAEAAUEAAABAGoAAAAAQA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeComboBox" Collapsed="true">
|
||||
<Position X="3" Y="6" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeComboBox.cs</FileName>
|
||||
<HashCode>wQACAAAAAAAMAEBAAAAAAABAAAAAAAABAAAAAAAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeNumericUpDown" Collapsed="true">
|
||||
<Position X="5" Y="6" Width="1.75" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeNumericUpDown.cs</FileName>
|
||||
<HashCode>wQAAAACAAAAEAABAIAAQIAAAAAAAAAABAAAIAAAAAII=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.InteractiveControl" Collapsed="true">
|
||||
<Position X="4" Y="2.75" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\InteractiveControl.cs</FileName>
|
||||
<HashCode>AAAABAAAAAAAAAAACAAAAAAAABAAAQAAAAAAAAIAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeDecimalTextBox" Collapsed="true">
|
||||
<Position X="2.5" Y="7" Width="1.75" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeDecimalTextBox.cs</FileName>
|
||||
<HashCode>AQAAAAAAAACAAAACAAAAAAQAAAAAIAAAAAgAAAAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Aga.Controls.Tree.NodeControls.NodeIntegerTextBox" Collapsed="true">
|
||||
<Position X="0.5" Y="7" Width="1.75" />
|
||||
<TypeIdentifier>
|
||||
<FileName>Tree\NodeControls\NodeIntegerTextBox.cs</FileName>
|
||||
<HashCode>AQAAAAAAAAAAAAACAAAAAAQAAAAAIAAAAAAAAAAAAAA=</HashCode>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
</ClassDiagram>
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class DrawEventArgs : NodeEventArgs
|
||||
{
|
||||
private DrawContext _context;
|
||||
public DrawContext Context
|
||||
{
|
||||
get { return _context; }
|
||||
}
|
||||
|
||||
private Brush _textBrush;
|
||||
[Obsolete("Use TextColor")]
|
||||
public Brush TextBrush
|
||||
{
|
||||
get { return _textBrush; }
|
||||
set { _textBrush = value; }
|
||||
}
|
||||
|
||||
private Brush _backgroundBrush;
|
||||
public Brush BackgroundBrush
|
||||
{
|
||||
get { return _backgroundBrush; }
|
||||
set { _backgroundBrush = value; }
|
||||
}
|
||||
|
||||
private Font _font;
|
||||
public Font Font
|
||||
{
|
||||
get { return _font; }
|
||||
set { _font = value; }
|
||||
}
|
||||
|
||||
private Color _textColor;
|
||||
public Color TextColor
|
||||
{
|
||||
get { return _textColor; }
|
||||
set { _textColor = value; }
|
||||
}
|
||||
|
||||
private string _text;
|
||||
public string Text
|
||||
{
|
||||
get { return _text; }
|
||||
set { _text = value; }
|
||||
}
|
||||
|
||||
|
||||
private EditableControl _control;
|
||||
public EditableControl Control
|
||||
{
|
||||
get { return _control; }
|
||||
}
|
||||
|
||||
public DrawEventArgs(TreeNodeAdv node, EditableControl control, DrawContext context, string text)
|
||||
: base(node)
|
||||
{
|
||||
_control = control;
|
||||
_context = context;
|
||||
_text = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class EditEventArgs : NodeEventArgs
|
||||
{
|
||||
private Control _control;
|
||||
public Control Control
|
||||
{
|
||||
get { return _control; }
|
||||
}
|
||||
|
||||
public EditEventArgs(TreeNodeAdv node, Control control)
|
||||
: base(node)
|
||||
{
|
||||
_control = control;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public abstract class EditableControl : InteractiveControl
|
||||
{
|
||||
private Timer _timer;
|
||||
private bool _editFlag;
|
||||
|
||||
#region Properties
|
||||
|
||||
private bool _editOnClick = false;
|
||||
[DefaultValue(false)]
|
||||
public bool EditOnClick
|
||||
{
|
||||
get { return _editOnClick; }
|
||||
set { _editOnClick = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected EditableControl()
|
||||
{
|
||||
_timer = new Timer();
|
||||
_timer.Interval = 500;
|
||||
_timer.Tick += new EventHandler(TimerTick);
|
||||
}
|
||||
|
||||
private void TimerTick(object sender, EventArgs e)
|
||||
{
|
||||
_timer.Stop();
|
||||
if (_editFlag)
|
||||
BeginEdit();
|
||||
_editFlag = false;
|
||||
}
|
||||
|
||||
public void SetEditorBounds(EditorContext context)
|
||||
{
|
||||
Size size = CalculateEditorSize(context);
|
||||
context.Editor.Bounds = new Rectangle(context.Bounds.X, context.Bounds.Y,
|
||||
Math.Min(size.Width, context.Bounds.Width),
|
||||
Math.Min(size.Height, Parent.ClientSize.Height - context.Bounds.Y)
|
||||
);
|
||||
}
|
||||
|
||||
protected abstract Size CalculateEditorSize(EditorContext context);
|
||||
|
||||
protected virtual bool CanEdit(TreeNodeAdv node)
|
||||
{
|
||||
return (node.Tag != null) && IsEditEnabled(node);
|
||||
}
|
||||
|
||||
public void BeginEdit()
|
||||
{
|
||||
if (Parent != null && Parent.CurrentNode != null && CanEdit(Parent.CurrentNode))
|
||||
{
|
||||
CancelEventArgs args = new CancelEventArgs();
|
||||
OnEditorShowing(args);
|
||||
if (!args.Cancel)
|
||||
{
|
||||
var editor = CreateEditor(Parent.CurrentNode);
|
||||
Parent.DisplayEditor(editor, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EndEdit(bool applyChanges)
|
||||
{
|
||||
if (Parent != null)
|
||||
if (Parent.HideEditor(applyChanges))
|
||||
OnEditorHided();
|
||||
}
|
||||
|
||||
public virtual void UpdateEditor(Control control)
|
||||
{
|
||||
}
|
||||
|
||||
internal void ApplyChanges(TreeNodeAdv node, Control editor)
|
||||
{
|
||||
DoApplyChanges(node, editor);
|
||||
OnChangesApplied();
|
||||
}
|
||||
|
||||
internal void DoDisposeEditor(Control editor)
|
||||
{
|
||||
DisposeEditor(editor);
|
||||
}
|
||||
|
||||
protected abstract void DoApplyChanges(TreeNodeAdv node, Control editor);
|
||||
|
||||
protected abstract Control CreateEditor(TreeNodeAdv node);
|
||||
|
||||
protected abstract void DisposeEditor(Control editor);
|
||||
|
||||
public virtual void Cut(Control control)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Copy(Control control)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Paste(Control control)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Delete(Control control)
|
||||
{
|
||||
}
|
||||
|
||||
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
_editFlag = (!EditOnClick && args.Button == MouseButtons.Left
|
||||
&& args.ModifierKeys == Keys.None && args.Node.IsSelected);
|
||||
}
|
||||
|
||||
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
if (args.Node.IsSelected)
|
||||
{
|
||||
if (EditOnClick && args.Button == MouseButtons.Left && args.ModifierKeys == Keys.None)
|
||||
{
|
||||
Parent.ItemDragMode = false;
|
||||
BeginEdit();
|
||||
args.Handled = true;
|
||||
}
|
||||
else if (_editFlag)// && args.Node.IsSelected)
|
||||
_timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
_editFlag = false;
|
||||
_timer.Stop();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
if (disposing)
|
||||
_timer.Dispose();
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public event CancelEventHandler EditorShowing;
|
||||
protected void OnEditorShowing(CancelEventArgs args)
|
||||
{
|
||||
if (EditorShowing != null)
|
||||
EditorShowing(this, args);
|
||||
}
|
||||
|
||||
public event EventHandler EditorHided;
|
||||
protected void OnEditorHided()
|
||||
{
|
||||
if (EditorHided != null)
|
||||
EditorHided(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public event EventHandler ChangesApplied;
|
||||
protected void OnChangesApplied()
|
||||
{
|
||||
if (ChangesApplied != null)
|
||||
ChangesApplied(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays an animated icon for those nodes, who are in expanding state.
|
||||
/// Parent TreeView must have AsyncExpanding property set to true.
|
||||
/// </summary>
|
||||
public class ExpandingIcon: NodeControl
|
||||
{
|
||||
private static GifDecoder _gif = ResourceHelper.LoadingIcon;
|
||||
private static int _index = 0;
|
||||
private static volatile Thread _animatingThread;
|
||||
private static object _lock = new object();
|
||||
|
||||
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
return ResourceHelper.LoadingIcon.FrameSize;
|
||||
}
|
||||
|
||||
protected override void OnIsVisibleValueNeeded(NodeControlValueEventArgs args)
|
||||
{
|
||||
args.Value = args.Node.IsExpandingNow;
|
||||
base.OnIsVisibleValueNeeded(args);
|
||||
}
|
||||
|
||||
public override void Draw(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
Rectangle rect = GetBounds(node, context);
|
||||
Image img = _gif.GetFrame(_index).Image;
|
||||
context.Graphics.DrawImage(img, rect.Location);
|
||||
}
|
||||
|
||||
public static void Start()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_animatingThread == null)
|
||||
{
|
||||
_index = 0;
|
||||
_animatingThread = new Thread(new ThreadStart(IterateIcons));
|
||||
_animatingThread.IsBackground = true;
|
||||
_animatingThread.Priority = ThreadPriority.Lowest;
|
||||
_animatingThread.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_index = 0;
|
||||
_animatingThread = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static void IterateIcons()
|
||||
{
|
||||
while (_animatingThread != null)
|
||||
{
|
||||
if (_index < _gif.FrameCount - 1)
|
||||
_index++;
|
||||
else
|
||||
_index = 0;
|
||||
|
||||
if (IconChanged != null)
|
||||
IconChanged(null, EventArgs.Empty);
|
||||
|
||||
int delay = _gif.GetFrame(_index).Delay;
|
||||
Thread.Sleep(delay);
|
||||
}
|
||||
System.Diagnostics.Debug.WriteLine("IterateIcons Stopped");
|
||||
}
|
||||
|
||||
public static event EventHandler IconChanged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public abstract class InteractiveControl : BindableControl
|
||||
{
|
||||
private bool _editEnabled = false;
|
||||
[DefaultValue(false)]
|
||||
public bool EditEnabled
|
||||
{
|
||||
get { return _editEnabled; }
|
||||
set { _editEnabled = value; }
|
||||
}
|
||||
|
||||
protected bool IsEditEnabled(TreeNodeAdv node)
|
||||
{
|
||||
if (EditEnabled)
|
||||
{
|
||||
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
|
||||
args.Value = true;
|
||||
OnIsEditEnabledValueNeeded(args);
|
||||
return Convert.ToBoolean(args.Value);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public event EventHandler<NodeControlValueEventArgs> IsEditEnabledValueNeeded;
|
||||
private void OnIsEditEnabledValueNeeded(NodeControlValueEventArgs args)
|
||||
{
|
||||
if (IsEditEnabledValueNeeded != null)
|
||||
IsEditEnabledValueNeeded(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class LabelEventArgs : EventArgs
|
||||
{
|
||||
private object _subject;
|
||||
public object Subject
|
||||
{
|
||||
get { return _subject; }
|
||||
}
|
||||
|
||||
private string _oldLabel;
|
||||
public string OldLabel
|
||||
{
|
||||
get { return _oldLabel; }
|
||||
}
|
||||
|
||||
private string _newLabel;
|
||||
public string NewLabel
|
||||
{
|
||||
get { return _newLabel; }
|
||||
}
|
||||
|
||||
public LabelEventArgs(object subject, string oldLabel, string newLabel)
|
||||
{
|
||||
_subject = subject;
|
||||
_oldLabel = oldLabel;
|
||||
_newLabel = newLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using Aga.Controls.Properties;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeCheckBox : InteractiveControl
|
||||
{
|
||||
public const int ImageSize = 13;
|
||||
|
||||
private Bitmap _check;
|
||||
private Bitmap _uncheck;
|
||||
private Bitmap _unknown;
|
||||
|
||||
#region Properties
|
||||
|
||||
private bool _threeState;
|
||||
[DefaultValue(false)]
|
||||
public bool ThreeState
|
||||
{
|
||||
get { return _threeState; }
|
||||
set { _threeState = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public NodeCheckBox()
|
||||
: this(string.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
public NodeCheckBox(string propertyName)
|
||||
{
|
||||
_check = Resources.check;
|
||||
_uncheck = Resources.uncheck;
|
||||
_unknown = Resources.unknown;
|
||||
DataPropertyName = propertyName;
|
||||
LeftMargin = 0;
|
||||
}
|
||||
|
||||
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
int scaledX = node.Tree.GetScaledSize(ImageSize, false);
|
||||
int scaledY = node.Tree.GetScaledSize(ImageSize);
|
||||
return new Size(scaledX, scaledY);
|
||||
}
|
||||
|
||||
public override void Draw(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
Rectangle bounds = GetBounds(node, context);
|
||||
CheckState state = GetCheckState(node);
|
||||
if (TreeViewAdv.CustomCheckRenderFunc != null)
|
||||
{
|
||||
TreeViewAdv.CustomCheckRenderFunc(context.Graphics, bounds, state == CheckState.Checked);
|
||||
}
|
||||
else if (Application.RenderWithVisualStyles)
|
||||
{
|
||||
VisualStyleRenderer renderer;
|
||||
int scaledX = node.Tree.GetScaledSize(ImageSize, false);
|
||||
int scaledY = node.Tree.GetScaledSize(ImageSize);
|
||||
if (state == CheckState.Indeterminate)
|
||||
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.MixedNormal);
|
||||
else if (state == CheckState.Checked)
|
||||
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal);
|
||||
else
|
||||
renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal);
|
||||
renderer.DrawBackground(context.Graphics, new Rectangle(bounds.X, bounds.Y, scaledX, scaledY));
|
||||
}
|
||||
else
|
||||
{
|
||||
Image img;
|
||||
if (state == CheckState.Indeterminate)
|
||||
img = _unknown;
|
||||
else if (state == CheckState.Checked)
|
||||
img = _check;
|
||||
else
|
||||
img = _uncheck;
|
||||
context.Graphics.DrawImage(img, bounds.Location);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual CheckState GetCheckState(TreeNodeAdv node)
|
||||
{
|
||||
object obj = GetValue(node);
|
||||
if (obj is CheckState)
|
||||
return (CheckState)obj;
|
||||
else if (obj is bool)
|
||||
return (bool)obj ? CheckState.Checked : CheckState.Unchecked;
|
||||
else
|
||||
return CheckState.Unchecked;
|
||||
}
|
||||
|
||||
protected virtual void SetCheckState(TreeNodeAdv node, CheckState value)
|
||||
{
|
||||
if (VirtualMode)
|
||||
{
|
||||
SetValue(node, value);
|
||||
OnCheckStateChanged(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
Type type = GetPropertyType(node);
|
||||
if (type == typeof(CheckState))
|
||||
{
|
||||
SetValue(node, value);
|
||||
OnCheckStateChanged(node);
|
||||
}
|
||||
else if (type == typeof(bool))
|
||||
{
|
||||
SetValue(node, value != CheckState.Unchecked);
|
||||
OnCheckStateChanged(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButtons.Left && IsEditEnabled(args.Node))
|
||||
{
|
||||
DrawContext context = new DrawContext();
|
||||
context.Bounds = args.ControlBounds;
|
||||
Rectangle rect = GetBounds(args.Node, context);
|
||||
if (rect.Contains(args.ViewLocation))
|
||||
{
|
||||
CheckState state = GetCheckState(args.Node);
|
||||
state = GetNewState(state);
|
||||
SetCheckState(args.Node, state);
|
||||
Parent.UpdateView();
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private CheckState GetNewState(CheckState state)
|
||||
{
|
||||
if (state == CheckState.Indeterminate)
|
||||
return CheckState.Unchecked;
|
||||
else if(state == CheckState.Unchecked)
|
||||
return CheckState.Checked;
|
||||
else
|
||||
return ThreeState ? CheckState.Indeterminate : CheckState.Unchecked;
|
||||
}
|
||||
|
||||
public override void KeyDown(KeyEventArgs args)
|
||||
{
|
||||
if (args.KeyCode == Keys.Space && EditEnabled)
|
||||
{
|
||||
Parent.BeginUpdate();
|
||||
try
|
||||
{
|
||||
if (Parent.CurrentNode != null)
|
||||
{
|
||||
CheckState value = GetNewState(GetCheckState(Parent.CurrentNode));
|
||||
foreach (TreeNodeAdv node in Parent.Selection)
|
||||
if (IsEditEnabled(node))
|
||||
SetCheckState(node, value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Parent.EndUpdate();
|
||||
}
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<TreePathEventArgs> CheckStateChanged;
|
||||
protected void OnCheckStateChanged(TreePathEventArgs args)
|
||||
{
|
||||
if (CheckStateChanged != null)
|
||||
CheckStateChanged(this, args);
|
||||
}
|
||||
|
||||
protected void OnCheckStateChanged(TreeNodeAdv node)
|
||||
{
|
||||
TreePath path = this.Parent.GetPath(node);
|
||||
OnCheckStateChanged(new TreePathEventArgs(path));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeComboBox : BaseTextControl
|
||||
{
|
||||
#region Properties
|
||||
|
||||
private int _editorWidth = 100;
|
||||
[DefaultValue(100)]
|
||||
public int EditorWidth
|
||||
{
|
||||
get { return _editorWidth; }
|
||||
set { _editorWidth = value; }
|
||||
}
|
||||
|
||||
private int _editorHeight = 100;
|
||||
[DefaultValue(100)]
|
||||
public int EditorHeight
|
||||
{
|
||||
get { return _editorHeight; }
|
||||
set { _editorHeight = value; }
|
||||
}
|
||||
|
||||
private List<object> _dropDownItems;
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")]
|
||||
[Editor(typeof(StringCollectionEditor), typeof(UITypeEditor)), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
||||
public List<object> DropDownItems
|
||||
{
|
||||
get { return _dropDownItems; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public event EventHandler<EditEventArgs> CreatingEditor;
|
||||
|
||||
public NodeComboBox()
|
||||
{
|
||||
_dropDownItems = new List<object>();
|
||||
}
|
||||
|
||||
protected override Size CalculateEditorSize(EditorContext context)
|
||||
{
|
||||
if (Parent.UseColumns)
|
||||
{
|
||||
if (context.Editor is CheckedListBox)
|
||||
return new Size(context.Bounds.Size.Width, EditorHeight);
|
||||
else
|
||||
return context.Bounds.Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context.Editor is CheckedListBox)
|
||||
return new Size(EditorWidth, EditorHeight);
|
||||
else
|
||||
return new Size(EditorWidth, context.Bounds.Height);
|
||||
}
|
||||
}
|
||||
|
||||
protected override Control CreateEditor(TreeNodeAdv node)
|
||||
{
|
||||
Control c;
|
||||
object value = GetValue(node);
|
||||
if (IsCheckedListBoxRequired(node))
|
||||
c = CreateCheckedListBox(node);
|
||||
else
|
||||
c = CreateCombo(node);
|
||||
OnCreatingEditor(new EditEventArgs(node, c));
|
||||
return c;
|
||||
}
|
||||
|
||||
protected override void DisposeEditor(Control editor)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnCreatingEditor(EditEventArgs args)
|
||||
{
|
||||
if (CreatingEditor != null)
|
||||
CreatingEditor(this, args);
|
||||
}
|
||||
|
||||
protected virtual bool IsCheckedListBoxRequired(TreeNodeAdv node)
|
||||
{
|
||||
object value = GetValue(node);
|
||||
if (value != null)
|
||||
{
|
||||
Type t = value.GetType();
|
||||
object[] arr = t.GetCustomAttributes(typeof(FlagsAttribute), false);
|
||||
return (t.IsEnum && arr.Length == 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Control CreateCombo(TreeNodeAdv node)
|
||||
{
|
||||
ComboBox comboBox = new ComboBox();
|
||||
if (DropDownItems != null)
|
||||
comboBox.Items.AddRange(DropDownItems.ToArray());
|
||||
comboBox.SelectedItem = GetValue(node);
|
||||
comboBox.DropDownStyle = ComboBoxStyle.DropDownList;
|
||||
comboBox.DropDownClosed += new EventHandler(EditorDropDownClosed);
|
||||
SetEditControlProperties(comboBox, node);
|
||||
return comboBox;
|
||||
}
|
||||
|
||||
private Control CreateCheckedListBox(TreeNodeAdv node)
|
||||
{
|
||||
CheckedListBox listBox = new CheckedListBox();
|
||||
listBox.CheckOnClick = true;
|
||||
|
||||
object value = GetValue(node);
|
||||
Type enumType = GetEnumType(node);
|
||||
foreach (object obj in Enum.GetValues(enumType))
|
||||
{
|
||||
object[] attributes = enumType.GetField(obj.ToString()).GetCustomAttributes(typeof(BrowsableAttribute), false);
|
||||
if (attributes.Length == 0 || ((BrowsableAttribute)attributes[0]).Browsable)
|
||||
listBox.Items.Add(obj, IsContain(value, obj));
|
||||
}
|
||||
|
||||
SetEditControlProperties(listBox, node);
|
||||
if (CreatingEditor != null)
|
||||
CreatingEditor(this, new EditEventArgs(node, listBox));
|
||||
return listBox;
|
||||
}
|
||||
|
||||
protected virtual Type GetEnumType(TreeNodeAdv node)
|
||||
{
|
||||
object value = GetValue(node);
|
||||
return value.GetType();
|
||||
}
|
||||
|
||||
private bool IsContain(object value, object enumElement)
|
||||
{
|
||||
if (value == null || enumElement == null)
|
||||
return false;
|
||||
if (value.GetType().IsEnum)
|
||||
{
|
||||
int i1 = (int)value;
|
||||
int i2 = (int)enumElement;
|
||||
return (i1 & i2) == i2;
|
||||
}
|
||||
else
|
||||
{
|
||||
var arr = value as object[];
|
||||
foreach (object obj in arr)
|
||||
if ((int)obj == (int)enumElement)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string FormatLabel(object obj)
|
||||
{
|
||||
var arr = obj as object[];
|
||||
if (arr != null)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
foreach (object t in arr)
|
||||
{
|
||||
if (sb.Length > 0)
|
||||
sb.Append(", ");
|
||||
sb.Append(t);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
else
|
||||
return base.FormatLabel(obj);
|
||||
}
|
||||
|
||||
void EditorDropDownClosed(object sender, EventArgs e)
|
||||
{
|
||||
EndEdit(true);
|
||||
}
|
||||
|
||||
public override void UpdateEditor(Control control)
|
||||
{
|
||||
if (control is ComboBox)
|
||||
(control as ComboBox).DroppedDown = true;
|
||||
}
|
||||
|
||||
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
|
||||
{
|
||||
var combo = editor as ComboBox;
|
||||
if (combo != null)
|
||||
{
|
||||
if (combo.DropDownStyle == ComboBoxStyle.DropDown)
|
||||
SetValue(node, combo.Text);
|
||||
else
|
||||
SetValue(node, combo.SelectedItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
var listBox = editor as CheckedListBox;
|
||||
Type type = GetEnumType(node);
|
||||
if (IsFlags(type))
|
||||
{
|
||||
int res = 0;
|
||||
foreach (object obj in listBox.CheckedItems)
|
||||
res |= (int)obj;
|
||||
object val = Enum.ToObject(type, res);
|
||||
SetValue(node, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
List<object> list = new List<object>();
|
||||
foreach (object obj in listBox.CheckedItems)
|
||||
list.Add(obj);
|
||||
SetValue(node, list.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsFlags(Type type)
|
||||
{
|
||||
object[] atr = type.GetCustomAttributes(typeof(FlagsAttribute), false);
|
||||
return atr.Length == 1;
|
||||
}
|
||||
|
||||
public override void MouseUp(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
if (args.Node != null && args.Node.IsSelected) //Workaround of specific ComboBox control behavior
|
||||
base.MouseUp(args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
[DesignTimeVisible(false), ToolboxItem(false)]
|
||||
public abstract class NodeControl : Component
|
||||
{
|
||||
#region Properties
|
||||
|
||||
private TreeViewAdv _parent;
|
||||
[Browsable(false)]
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public TreeViewAdv Parent
|
||||
{
|
||||
get { return _parent; }
|
||||
set
|
||||
{
|
||||
if (value != _parent)
|
||||
{
|
||||
if (_parent != null)
|
||||
_parent.NodeControls.Remove(this);
|
||||
|
||||
if (value != null)
|
||||
value.NodeControls.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IToolTipProvider _toolTipProvider;
|
||||
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public IToolTipProvider ToolTipProvider
|
||||
{
|
||||
get { return _toolTipProvider; }
|
||||
set { _toolTipProvider = value; }
|
||||
}
|
||||
|
||||
private TreeColumn _parentColumn;
|
||||
public TreeColumn ParentColumn
|
||||
{
|
||||
get { return _parentColumn; }
|
||||
set
|
||||
{
|
||||
_parentColumn = value;
|
||||
if (_parent != null)
|
||||
_parent.FullUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private VerticalAlignment _verticalAlign = VerticalAlignment.Center;
|
||||
[DefaultValue(VerticalAlignment.Center)]
|
||||
public VerticalAlignment VerticalAlign
|
||||
{
|
||||
get { return _verticalAlign; }
|
||||
set
|
||||
{
|
||||
_verticalAlign = value;
|
||||
if (_parent != null)
|
||||
_parent.FullUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private int _leftMargin = 0;
|
||||
public int LeftMargin
|
||||
{
|
||||
get { return _leftMargin; }
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
throw new ArgumentOutOfRangeException();
|
||||
|
||||
_leftMargin = value;
|
||||
if (_parent != null)
|
||||
_parent.FullUpdate();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal virtual void AssignParent(TreeViewAdv parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
protected virtual Rectangle GetBounds(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
Rectangle r = context.Bounds;
|
||||
Size s = GetActualSize(node, context);
|
||||
Size bs = new Size(r.Width - LeftMargin, Math.Min(r.Height, s.Height));
|
||||
switch (VerticalAlign)
|
||||
{
|
||||
case VerticalAlignment.Top:
|
||||
return new Rectangle(new Point(r.X + LeftMargin, r.Y), bs);
|
||||
case VerticalAlignment.Bottom:
|
||||
return new Rectangle(new Point(r.X + LeftMargin, r.Bottom - s.Height), bs);
|
||||
default:
|
||||
return new Rectangle(new Point(r.X + LeftMargin, r.Y + (r.Height - s.Height) / 2), bs);
|
||||
}
|
||||
}
|
||||
|
||||
protected void CheckThread()
|
||||
{
|
||||
if (Parent != null && Control.CheckForIllegalCrossThreadCalls)
|
||||
if (Parent.InvokeRequired)
|
||||
throw new InvalidOperationException("Cross-thread calls are not allowed");
|
||||
}
|
||||
|
||||
public bool IsVisible(TreeNodeAdv node)
|
||||
{
|
||||
NodeControlValueEventArgs args = new NodeControlValueEventArgs(node);
|
||||
args.Value = true;
|
||||
OnIsVisibleValueNeeded(args);
|
||||
return Convert.ToBoolean(args.Value);
|
||||
}
|
||||
|
||||
internal Size GetActualSize(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
if (IsVisible(node))
|
||||
{
|
||||
Size s = MeasureSize(node, context);
|
||||
return new Size(s.Width + LeftMargin, s.Height);
|
||||
}
|
||||
else
|
||||
return Size.Empty;
|
||||
}
|
||||
|
||||
public abstract Size MeasureSize(TreeNodeAdv node, DrawContext context);
|
||||
|
||||
public abstract void Draw(TreeNodeAdv node, DrawContext context);
|
||||
|
||||
public virtual string GetToolTip(TreeNodeAdv node)
|
||||
{
|
||||
if (ToolTipProvider != null)
|
||||
return ToolTipProvider.GetToolTip(node, this);
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public virtual void MouseDown(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void MouseUp(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void KeyDown(KeyEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void KeyUp(KeyEventArgs args)
|
||||
{
|
||||
}
|
||||
|
||||
public event EventHandler<NodeControlValueEventArgs> IsVisibleValueNeeded;
|
||||
protected virtual void OnIsVisibleValueNeeded(NodeControlValueEventArgs args)
|
||||
{
|
||||
if (IsVisibleValueNeeded != null)
|
||||
IsVisibleValueNeeded(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeControlValueEventArgs : NodeEventArgs
|
||||
{
|
||||
private object _value;
|
||||
public object Value
|
||||
{
|
||||
get { return _value; }
|
||||
set { _value = value; }
|
||||
}
|
||||
|
||||
public NodeControlValueEventArgs(TreeNodeAdv node)
|
||||
:base(node)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
internal class NodeControlsCollection : Collection<NodeControl>
|
||||
{
|
||||
private TreeViewAdv _tree;
|
||||
|
||||
public NodeControlsCollection(TreeViewAdv tree)
|
||||
{
|
||||
_tree = tree;
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
{
|
||||
_tree.BeginUpdate();
|
||||
try
|
||||
{
|
||||
while (this.Count != 0)
|
||||
this.RemoveAt(this.Count - 1);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_tree.EndUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void InsertItem(int index, NodeControl item)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
if (item.Parent != _tree)
|
||||
{
|
||||
if (item.Parent != null)
|
||||
{
|
||||
item.Parent.NodeControls.Remove(item);
|
||||
}
|
||||
base.InsertItem(index, item);
|
||||
item.AssignParent(_tree);
|
||||
_tree.FullUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void RemoveItem(int index)
|
||||
{
|
||||
NodeControl value = this[index];
|
||||
value.AssignParent(null);
|
||||
base.RemoveItem(index);
|
||||
_tree.FullUpdate();
|
||||
}
|
||||
|
||||
protected override void SetItem(int index, NodeControl item)
|
||||
{
|
||||
if (item == null)
|
||||
throw new ArgumentNullException("item");
|
||||
|
||||
_tree.BeginUpdate();
|
||||
try
|
||||
{
|
||||
RemoveAt(index);
|
||||
InsertItem(index, item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_tree.EndUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class NodeControlCollectionEditor : CollectionEditor
|
||||
{
|
||||
private Type[] _types;
|
||||
|
||||
public NodeControlCollectionEditor(Type type)
|
||||
: base(type)
|
||||
{
|
||||
_types = new Type[] { typeof(NodeTextBox), typeof(NodeIntegerTextBox), typeof(NodeDecimalTextBox),
|
||||
typeof(NodeComboBox), typeof(NodeCheckBox),
|
||||
typeof(NodeStateIcon), typeof(NodeIcon), typeof(NodeNumericUpDown), typeof(ExpandingIcon) };
|
||||
}
|
||||
|
||||
protected override System.Type[] CreateNewItemTypes()
|
||||
{
|
||||
return _types;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeDecimalTextBox : NodeTextBox
|
||||
{
|
||||
private bool _allowDecimalSeparator = true;
|
||||
[DefaultValue(true)]
|
||||
public bool AllowDecimalSeparator
|
||||
{
|
||||
get { return _allowDecimalSeparator; }
|
||||
set { _allowDecimalSeparator = value; }
|
||||
}
|
||||
|
||||
private bool _allowNegativeSign = true;
|
||||
[DefaultValue(true)]
|
||||
public bool AllowNegativeSign
|
||||
{
|
||||
get { return _allowNegativeSign; }
|
||||
set { _allowNegativeSign = value; }
|
||||
}
|
||||
|
||||
protected NodeDecimalTextBox()
|
||||
{
|
||||
}
|
||||
|
||||
protected override TextBox CreateTextBox()
|
||||
{
|
||||
NumericTextBox textBox = new NumericTextBox();
|
||||
textBox.AllowDecimalSeparator = AllowDecimalSeparator;
|
||||
textBox.AllowNegativeSign = AllowNegativeSign;
|
||||
return textBox;
|
||||
}
|
||||
|
||||
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
|
||||
{
|
||||
SetValue(node, (editor as NumericTextBox).DecimalValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeEventArgs : EventArgs
|
||||
{
|
||||
private TreeNodeAdv _node;
|
||||
public TreeNodeAdv Node
|
||||
{
|
||||
get { return _node; }
|
||||
}
|
||||
|
||||
public NodeEventArgs(TreeNodeAdv node)
|
||||
{
|
||||
_node = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using Aga.Controls.Properties;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeIcon : BindableControl
|
||||
{
|
||||
public NodeIcon()
|
||||
{
|
||||
LeftMargin = 1;
|
||||
}
|
||||
|
||||
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
Image image = GetIcon(node);
|
||||
if (image != null)
|
||||
{
|
||||
int scaledX = node.Tree.GetScaledSize(image.Size.Width, false);
|
||||
int scaledY = node.Tree.GetScaledSize(image.Size.Height);
|
||||
return new Size(scaledX, scaledY); ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Size.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Draw(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
Image image = GetIcon(node);
|
||||
if (image != null)
|
||||
{
|
||||
Rectangle r = GetBounds(node, context);
|
||||
if ( image.Width > 0 && image.Height > 0 )
|
||||
{
|
||||
switch (_scaleMode)
|
||||
{
|
||||
case ImageScaleMode.Fit:
|
||||
context.Graphics.DrawImage(image, r);
|
||||
break;
|
||||
case ImageScaleMode.ScaleDown:
|
||||
{
|
||||
float factor = Math.Min((float)r.Width / (float)image.Width, (float)r.Height / (float)image.Height);
|
||||
if (factor < 1)
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
|
||||
else
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
|
||||
} break;
|
||||
case ImageScaleMode.ScaleUp:
|
||||
{
|
||||
float factor = Math.Max((float)r.Width / (float)image.Width, (float)r.Height / (float)image.Height);
|
||||
if (factor > 1)
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
|
||||
else
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
|
||||
} break;
|
||||
case ImageScaleMode.AlwaysScale:
|
||||
{
|
||||
float fx = (float)r.Width / (float)image.Width;
|
||||
float fy = (float)r.Height / (float)image.Height;
|
||||
if (Math.Min(fx, fy) < 1)
|
||||
{ //scale down
|
||||
float factor = Math.Min(fx, fy);
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
|
||||
}
|
||||
else if (Math.Max(fx, fy) > 1)
|
||||
{
|
||||
float factor = Math.Max(fx, fy);
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width * factor, image.Height * factor);
|
||||
}
|
||||
else
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
|
||||
} break;
|
||||
case ImageScaleMode.Clip:
|
||||
default:
|
||||
context.Graphics.DrawImage(image, r.X, r.Y, image.Width, image.Height);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual Image GetIcon(TreeNodeAdv node)
|
||||
{
|
||||
return GetValue(node) as Image;
|
||||
}
|
||||
|
||||
private ImageScaleMode _scaleMode = ImageScaleMode.Clip;
|
||||
[DefaultValue("Clip"), Category("Appearance")]
|
||||
public ImageScaleMode ScaleMode
|
||||
{
|
||||
get { return _scaleMode; }
|
||||
set { _scaleMode = value; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
|
||||
public class NodeIntegerTextBox : NodeTextBox
|
||||
{
|
||||
private bool _allowNegativeSign = true;
|
||||
[DefaultValue(true)]
|
||||
public bool AllowNegativeSign
|
||||
{
|
||||
get { return _allowNegativeSign; }
|
||||
set { _allowNegativeSign = value; }
|
||||
}
|
||||
|
||||
public NodeIntegerTextBox()
|
||||
{
|
||||
}
|
||||
|
||||
protected override TextBox CreateTextBox()
|
||||
{
|
||||
NumericTextBox textBox = new NumericTextBox();
|
||||
textBox.AllowDecimalSeparator = false;
|
||||
textBox.AllowNegativeSign = AllowNegativeSign;
|
||||
return textBox;
|
||||
}
|
||||
|
||||
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
|
||||
{
|
||||
SetValue(node, (editor as NumericTextBox).IntValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing.Design;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeNumericUpDown : BaseTextControl
|
||||
{
|
||||
#region Properties
|
||||
|
||||
private int _editorWidth = 100;
|
||||
[DefaultValue(100)]
|
||||
public int EditorWidth
|
||||
{
|
||||
get { return _editorWidth; }
|
||||
set { _editorWidth = value; }
|
||||
}
|
||||
|
||||
private int _decimalPlaces = 0;
|
||||
[Category("Data"), DefaultValue(0)]
|
||||
public int DecimalPlaces
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._decimalPlaces;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._decimalPlaces = value;
|
||||
}
|
||||
}
|
||||
|
||||
private decimal _increment = 1;
|
||||
[Category("Data"), DefaultValue(1)]
|
||||
public decimal Increment
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._increment;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._increment = value;
|
||||
}
|
||||
}
|
||||
|
||||
private decimal _minimum = 0;
|
||||
[Category("Data"), DefaultValue(0)]
|
||||
public decimal Minimum
|
||||
{
|
||||
get
|
||||
{
|
||||
return _minimum;
|
||||
}
|
||||
set
|
||||
{
|
||||
_minimum = value;
|
||||
}
|
||||
}
|
||||
|
||||
private decimal _maximum = 100;
|
||||
[Category("Data"), DefaultValue(100)]
|
||||
public decimal Maximum
|
||||
{
|
||||
get
|
||||
{
|
||||
return this._maximum;
|
||||
}
|
||||
set
|
||||
{
|
||||
this._maximum = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public NodeNumericUpDown()
|
||||
{
|
||||
}
|
||||
|
||||
protected override Size CalculateEditorSize(EditorContext context)
|
||||
{
|
||||
if (Parent.UseColumns)
|
||||
return context.Bounds.Size;
|
||||
else
|
||||
return new Size(EditorWidth, context.Bounds.Height);
|
||||
}
|
||||
|
||||
protected override Control CreateEditor(TreeNodeAdv node)
|
||||
{
|
||||
NumericUpDown num = new NumericUpDown();
|
||||
num.Increment = Increment;
|
||||
num.DecimalPlaces = DecimalPlaces;
|
||||
num.Minimum = Minimum;
|
||||
num.Maximum = Maximum;
|
||||
num.Value = (decimal)GetValue(node);
|
||||
SetEditControlProperties(num, node);
|
||||
return num;
|
||||
}
|
||||
|
||||
protected override void DisposeEditor(Control editor)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
|
||||
{
|
||||
SetValue(node, (editor as NumericUpDown).Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using Aga.Controls.Properties;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Forms.VisualStyles;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
internal class NodePlusMinus : NodeControl
|
||||
{
|
||||
public const int ImageSize = 9;
|
||||
public const int Width = 16;
|
||||
private Bitmap _plus;
|
||||
private Bitmap _minus;
|
||||
|
||||
private VisualStyleRenderer _openedRenderer;
|
||||
private VisualStyleRenderer OpenedRenderer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_openedRenderer == null)
|
||||
_openedRenderer = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Opened);
|
||||
return _openedRenderer;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private VisualStyleRenderer _closedRenderer;
|
||||
private VisualStyleRenderer ClosedRenderer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_closedRenderer == null)
|
||||
_closedRenderer = new VisualStyleRenderer(VisualStyleElement.TreeView.Glyph.Closed);
|
||||
return _closedRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
public NodePlusMinus()
|
||||
{
|
||||
_plus = Resources.plus;
|
||||
_minus = Resources.minus;
|
||||
}
|
||||
|
||||
public override Size MeasureSize(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
int scaledX = node.Tree.GetScaledSize(Width, false);
|
||||
int scaledY = node.Tree.GetScaledSize(Width);
|
||||
return new Size(scaledX, scaledY);
|
||||
}
|
||||
|
||||
public override void Draw(TreeNodeAdv node, DrawContext context)
|
||||
{
|
||||
if (node.CanExpand)
|
||||
{
|
||||
Rectangle r = context.Bounds;
|
||||
int scaledX = node.Tree.GetScaledSize(ImageSize, false);
|
||||
int scaledY = node.Tree.GetScaledSize(ImageSize);
|
||||
int dy = (int)Math.Round((float)(r.Height - scaledY) / 2);
|
||||
if (TreeViewAdv.CustomPlusMinusRenderFunc != null)
|
||||
{
|
||||
TreeViewAdv.CustomPlusMinusRenderFunc(context.Graphics, r, node.IsExpanded);
|
||||
return;
|
||||
}
|
||||
else if (Application.RenderWithVisualStyles)
|
||||
{
|
||||
VisualStyleRenderer renderer;
|
||||
if (node.IsExpanded)
|
||||
renderer = OpenedRenderer;
|
||||
else
|
||||
renderer = ClosedRenderer;
|
||||
renderer.DrawBackground(context.Graphics, new Rectangle(r.X, r.Y + dy, scaledX, scaledY));
|
||||
}
|
||||
else
|
||||
{
|
||||
Image img;
|
||||
if (node.IsExpanded)
|
||||
img = _minus;
|
||||
else
|
||||
img = _plus;
|
||||
context.Graphics.DrawImageUnscaled(img, new Point(r.X, r.Y + dy));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void MouseDown(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButtons.Left)
|
||||
{
|
||||
args.Handled = true;
|
||||
if (args.Node.CanExpand)
|
||||
args.Node.IsExpanded = !args.Node.IsExpanded;
|
||||
}
|
||||
}
|
||||
|
||||
public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args)
|
||||
{
|
||||
args.Handled = true; // Supress expand/collapse when double click on plus/minus
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using Aga.Controls.Properties;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeStateIcon: NodeIcon
|
||||
{
|
||||
private Image _leaf;
|
||||
private Image _opened;
|
||||
private Image _closed;
|
||||
|
||||
public NodeStateIcon()
|
||||
{
|
||||
_leaf = MakeTransparent(Resources.Leaf);
|
||||
_opened = MakeTransparent(Resources.Folder);
|
||||
_closed = MakeTransparent(Resources.FolderClosed);
|
||||
}
|
||||
|
||||
private static Image MakeTransparent(Bitmap bitmap)
|
||||
{
|
||||
bitmap.MakeTransparent(bitmap.GetPixel(0,0));
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
protected override Image GetIcon(TreeNodeAdv node)
|
||||
{
|
||||
Image icon = base.GetIcon(node);
|
||||
if (icon != null)
|
||||
return icon;
|
||||
else if (node.IsLeaf)
|
||||
return _leaf;
|
||||
else if (node.CanExpand && node.IsExpanded)
|
||||
return _opened;
|
||||
else
|
||||
return _closed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using System.Reflection;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Aga.Controls.Tree.NodeControls
|
||||
{
|
||||
public class NodeTextBox : BaseTextControl
|
||||
{
|
||||
private const int MinTextBoxWidth = 30;
|
||||
|
||||
public NodeTextBox()
|
||||
{
|
||||
}
|
||||
|
||||
protected override Size CalculateEditorSize(EditorContext context)
|
||||
{
|
||||
if (Parent.UseColumns)
|
||||
return context.Bounds.Size;
|
||||
else
|
||||
{
|
||||
Size size = GetLabelSize(context.CurrentNode, context.DrawContext, _label);
|
||||
int width = Math.Max(size.Width + Font.Height, MinTextBoxWidth); // reserve a place for new typed character
|
||||
return new Size(width, size.Height);
|
||||
}
|
||||
}
|
||||
|
||||
public override void KeyDown(KeyEventArgs args)
|
||||
{
|
||||
if (args.KeyCode == Keys.F2 && Parent.CurrentNode != null && EditEnabled)
|
||||
{
|
||||
args.Handled = true;
|
||||
BeginEdit();
|
||||
}
|
||||
}
|
||||
|
||||
protected override Control CreateEditor(TreeNodeAdv node)
|
||||
{
|
||||
TextBox textBox = CreateTextBox();
|
||||
textBox.TextAlign = TextAlign;
|
||||
textBox.Text = GetLabel(node);
|
||||
textBox.BorderStyle = BorderStyle.FixedSingle;
|
||||
textBox.TextChanged += EditorTextChanged;
|
||||
textBox.KeyDown += EditorKeyDown;
|
||||
_label = textBox.Text;
|
||||
SetEditControlProperties(textBox, node);
|
||||
return textBox;
|
||||
}
|
||||
|
||||
protected virtual TextBox CreateTextBox()
|
||||
{
|
||||
return new TextBox();
|
||||
}
|
||||
|
||||
protected override void DisposeEditor(Control editor)
|
||||
{
|
||||
var textBox = editor as TextBox;
|
||||
textBox.TextChanged -= EditorTextChanged;
|
||||
textBox.KeyDown -= EditorKeyDown;
|
||||
}
|
||||
|
||||
private void EditorKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Escape)
|
||||
EndEdit(false);
|
||||
else if (e.KeyCode == Keys.Enter)
|
||||
EndEdit(true);
|
||||
}
|
||||
|
||||
private string _label;
|
||||
private void EditorTextChanged(object sender, EventArgs e)
|
||||
{
|
||||
var textBox = sender as TextBox;
|
||||
_label = textBox.Text;
|
||||
Parent.UpdateEditorBounds();
|
||||
}
|
||||
|
||||
protected override void DoApplyChanges(TreeNodeAdv node, Control editor)
|
||||
{
|
||||
var label = (editor as TextBox).Text;
|
||||
string oldLabel = GetLabel(node);
|
||||
if (oldLabel != label)
|
||||
{
|
||||
SetLabel(node, label);
|
||||
OnLabelChanged(node.Tag, oldLabel, label);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Cut(Control control)
|
||||
{
|
||||
(control as TextBox).Cut();
|
||||
}
|
||||
|
||||
public override void Copy(Control control)
|
||||
{
|
||||
(control as TextBox).Copy();
|
||||
}
|
||||
|
||||
public override void Paste(Control control)
|
||||
{
|
||||
(control as TextBox).Paste();
|
||||
}
|
||||
|
||||
public override void Delete(Control control)
|
||||
{
|
||||
var textBox = control as TextBox;
|
||||
int len = Math.Max(textBox.SelectionLength, 1);
|
||||
if (textBox.SelectionStart < textBox.Text.Length)
|
||||
{
|
||||
int start = textBox.SelectionStart;
|
||||
textBox.Text = textBox.Text.Remove(textBox.SelectionStart, len);
|
||||
textBox.SelectionStart = start;
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler<LabelEventArgs> LabelChanged;
|
||||
protected void OnLabelChanged(object subject, string oldLabel, string newLabel)
|
||||
{
|
||||
if (LabelChanged != null)
|
||||
LabelChanged(this, new LabelEventArgs(subject, oldLabel, newLabel));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user