moel@345: using System; moel@345: using System.Collections.Generic; moel@345: using System.Text; moel@345: using System.Drawing; moel@345: using Aga.Controls.Properties; moel@345: using System.Reflection; moel@345: using System.Windows.Forms; moel@345: using System.Windows.Forms.VisualStyles; moel@345: using System.ComponentModel; moel@345: moel@345: namespace Aga.Controls.Tree.NodeControls moel@345: { moel@345: public class NodeCheckBox : InteractiveControl moel@345: { moel@345: public const int ImageSize = 13; moel@345: moel@345: private Bitmap _check; moel@345: private Bitmap _uncheck; moel@345: private Bitmap _unknown; moel@345: moel@345: #region Properties moel@345: moel@345: private bool _threeState; moel@345: [DefaultValue(false)] moel@345: public bool ThreeState moel@345: { moel@345: get { return _threeState; } moel@345: set { _threeState = value; } moel@345: } moel@345: moel@345: #endregion moel@345: moel@345: public NodeCheckBox() moel@345: : this(string.Empty) moel@345: { moel@345: } moel@345: moel@345: public NodeCheckBox(string propertyName) moel@345: { moel@345: _check = Resources.check; moel@345: _uncheck = Resources.uncheck; moel@345: _unknown = Resources.unknown; moel@345: DataPropertyName = propertyName; moel@345: LeftMargin = 0; moel@345: } moel@345: moel@345: public override Size MeasureSize(TreeNodeAdv node, DrawContext context) moel@345: { moel@345: return new Size(ImageSize, ImageSize); moel@345: } moel@345: moel@345: public override void Draw(TreeNodeAdv node, DrawContext context) moel@345: { moel@345: Rectangle bounds = GetBounds(node, context); moel@345: CheckState state = GetCheckState(node); moel@345: if (Application.RenderWithVisualStyles) moel@345: { moel@345: VisualStyleRenderer renderer; moel@345: if (state == CheckState.Indeterminate) moel@345: renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.MixedNormal); moel@345: else if (state == CheckState.Checked) moel@345: renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.CheckedNormal); moel@345: else moel@345: renderer = new VisualStyleRenderer(VisualStyleElement.Button.CheckBox.UncheckedNormal); moel@345: renderer.DrawBackground(context.Graphics, new Rectangle(bounds.X, bounds.Y, ImageSize, ImageSize)); moel@345: } moel@345: else moel@345: { moel@345: Image img; moel@345: if (state == CheckState.Indeterminate) moel@345: img = _unknown; moel@345: else if (state == CheckState.Checked) moel@345: img = _check; moel@345: else moel@345: img = _uncheck; moel@345: context.Graphics.DrawImage(img, bounds.Location); moel@345: } moel@345: } moel@345: moel@345: protected virtual CheckState GetCheckState(TreeNodeAdv node) moel@345: { moel@345: object obj = GetValue(node); moel@345: if (obj is CheckState) moel@345: return (CheckState)obj; moel@345: else if (obj is bool) moel@345: return (bool)obj ? CheckState.Checked : CheckState.Unchecked; moel@345: else moel@345: return CheckState.Unchecked; moel@345: } moel@345: moel@345: protected virtual void SetCheckState(TreeNodeAdv node, CheckState value) moel@345: { moel@345: if (VirtualMode) moel@345: { moel@345: SetValue(node, value); moel@345: OnCheckStateChanged(node); moel@345: } moel@345: else moel@345: { moel@345: Type type = GetPropertyType(node); moel@345: if (type == typeof(CheckState)) moel@345: { moel@345: SetValue(node, value); moel@345: OnCheckStateChanged(node); moel@345: } moel@345: else if (type == typeof(bool)) moel@345: { moel@345: SetValue(node, value != CheckState.Unchecked); moel@345: OnCheckStateChanged(node); moel@345: } moel@345: } moel@345: } moel@345: moel@345: public override void MouseDown(TreeNodeAdvMouseEventArgs args) moel@345: { moel@345: if (args.Button == MouseButtons.Left && IsEditEnabled(args.Node)) moel@345: { moel@345: DrawContext context = new DrawContext(); moel@345: context.Bounds = args.ControlBounds; moel@345: Rectangle rect = GetBounds(args.Node, context); moel@345: if (rect.Contains(args.ViewLocation)) moel@345: { moel@345: CheckState state = GetCheckState(args.Node); moel@345: state = GetNewState(state); moel@345: SetCheckState(args.Node, state); moel@345: Parent.UpdateView(); moel@345: args.Handled = true; moel@345: } moel@345: } moel@345: } moel@345: moel@345: public override void MouseDoubleClick(TreeNodeAdvMouseEventArgs args) moel@345: { moel@345: args.Handled = true; moel@345: } moel@345: moel@345: private CheckState GetNewState(CheckState state) moel@345: { moel@345: if (state == CheckState.Indeterminate) moel@345: return CheckState.Unchecked; moel@345: else if(state == CheckState.Unchecked) moel@345: return CheckState.Checked; moel@345: else moel@345: return ThreeState ? CheckState.Indeterminate : CheckState.Unchecked; moel@345: } moel@345: moel@345: public override void KeyDown(KeyEventArgs args) moel@345: { moel@345: if (args.KeyCode == Keys.Space && EditEnabled) moel@345: { moel@345: Parent.BeginUpdate(); moel@345: try moel@345: { moel@345: if (Parent.CurrentNode != null) moel@345: { moel@345: CheckState value = GetNewState(GetCheckState(Parent.CurrentNode)); moel@345: foreach (TreeNodeAdv node in Parent.Selection) moel@345: if (IsEditEnabled(node)) moel@345: SetCheckState(node, value); moel@345: } moel@345: } moel@345: finally moel@345: { moel@345: Parent.EndUpdate(); moel@345: } moel@345: args.Handled = true; moel@345: } moel@345: } moel@345: moel@345: public event EventHandler CheckStateChanged; moel@345: protected void OnCheckStateChanged(TreePathEventArgs args) moel@345: { moel@345: if (CheckStateChanged != null) moel@345: CheckStateChanged(this, args); moel@345: } moel@345: moel@345: protected void OnCheckStateChanged(TreeNodeAdv node) moel@345: { moel@345: TreePath path = this.Parent.GetPath(node); moel@345: OnCheckStateChanged(new TreePathEventArgs(path)); moel@345: } moel@345: moel@345: } moel@345: }