using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
namespace IP.Components
{
partial class Toolbox
{
/// <summary>
/// Represents an item in a <see cref="Toolbox"/> control.
/// </summary>
[Serializable]
[ToolboxItem(false)]
[DesignTimeVisible(false)]
[TypeConverter(typeof(ItemConverter))]
public class Item : IToolboxObject, ICloneable
{
#region Fields
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string _text = string.Empty;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Image _image = null;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Color _foreColor = Color.White;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Color _backColor = Color.LightGray;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool _enabled = true;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool _visible = true;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool _selected = false;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool _highlighted = false;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string _tooltip = string.Empty;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Point _location;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private bool _renaming = false;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private Color _transparentColor;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private ITab _owner;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private object _tag;
#endregion
#region Static members
internal static readonly StringFormat _itemTextFormat;
private static readonly Type DefaulValueAttributeType = typeof(DefaultValueAttribute);
private static readonly Type StringType = typeof(string);
private static readonly Type ColorType = typeof(Color);
private static readonly Type ImageType = typeof(Image);
private static Dictionary<Type, List<PropertyInfo>> _serializableProperties;
static Item()
{
_itemTextFormat = new StringFormat();
_itemTextFormat.LineAlignment = StringAlignment.Center;
_itemTextFormat.Trimming = StringTrimming.EllipsisWord;
}
/// <summary>
/// Gets the public browsable properties which could be serialized.
/// </summary>
private static List<PropertyInfo> GetSerializableProperties(Type type)
{
if (_serializableProperties == null)
{
_serializableProperties = new Dictionary<Type, List<PropertyInfo>>();
}
List<PropertyInfo> properties;
if (!_serializableProperties.TryGetValue(type, out properties))
{
properties = new List<PropertyInfo>(type.GetProperties());
for (int i = properties.Count - 1; i >= 0; i--)
{
PropertyInfo pi = properties[i];
if (!pi.CanRead || !pi.CanWrite)
{
properties.RemoveAt(i);
}
else if (pi.IsDefined(typeof(XmlIgnoreAttribute), false))
{
properties.RemoveAt(i);
}
else if (pi.IsDefined(typeof(BrowsableAttribute), true))
{
BrowsableAttribute[] attributes = (BrowsableAttribute[])pi.GetCustomAttributes(typeof(BrowsableAttribute), true);
if (!attributes[0].Browsable)
properties.RemoveAt(i);
}
}
_serializableProperties.Add(type, properties);
}
return properties;
}
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> class with default values.
/// </summary>
public Item() : this(string.Empty)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> class with the specified item text.
/// </summary>
/// <param name="text">The text to display for the item.</param>
public Item(string text) : this(text, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> class with the specified item text and image.
/// </summary>
/// <param name="text">The text to display for the item.</param>
/// <param name="image">The image to display for the item.</param>
public Item(string text, Image image) : this(text, image, Color.Transparent)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Item"/> class with the specified item text, image and image transparency color.
/// </summary>
/// <param name="text">The text to display for the item.</param>
/// <param name="image">The image to display for the item.</param>
/// <param name="transparentColor">The transparent color for the <paramref name="image"/>.</param>
public Item(string text, Image image, Color transparentColor)
{
if (string.IsNullOrEmpty(text))
text = "Item";
_text = text;
_image = image;
_transparentColor = transparentColor;
}
#region Public Properties
/// <summary>
/// Gets or sets the text value of the <see cref="Item"/>.
/// </summary>
public virtual string Text
{
[DebuggerStepThrough]
get { return _text; }
[DebuggerStepThrough]
set
{
if (_text != value && !string.IsNullOrEmpty(value))
{
_text = value;
}
}
}
/// <summary>
/// Gets or sets the image displayed for the <see cref="Item"/>.
/// </summary>
[DefaultValue(typeof(Image), "null")]
public virtual Image Image
{
[DebuggerStepThrough]
get { return _image; }
[DebuggerStepThrough]
set { _image = value; }
}
/// <summary>
/// Gets or sets the color to treat as transparent for the <see cref="Image"/>.
/// </summary>
/// <value>One of the <see cref="Color"/> values. The default is <b>null</b>.</value>
/// <remarks>The transparent color is not rendered when the image is drawn.</remarks>
[DefaultValue(typeof(Color), "Transparent")]
public virtual Color TransparentColor
{
[DebuggerStepThrough]
get { return _transparentColor; }
[DebuggerStepThrough]
set { _transparentColor = value; }
}
/// <summary>
/// Gets or sets the color to display the text of the <see cref="Item"/>.
/// </summary>
[DefaultValue(typeof(Color), "White")]
public virtual Color ForeColor
{
[DebuggerStepThrough]
get { return _foreColor; }
[DebuggerStepThrough]
set { _foreColor = value; }
}
/// <summary>
/// Gets or sets the color of the <see cref="Item"/> background.
/// </summary>
[DefaultValue(typeof(Color), "LightGray")]
public virtual Color BackColor
{
[DebuggerStepThrough]
get { return _backColor; }
[DebuggerStepThrough]
set { _backColor = value; }
}
/// <summary>
/// Gets or sets whether the <see cref="Item"/> is selectable.
/// </summary>
[DefaultValue(true)]
public virtual bool Enabled
{
[DebuggerStepThrough]
get { return _enabled; }
[DebuggerStepThrough]
set { _enabled = value; }
}
/// <summary>
/// Gets or sets whether the <see cref="Item"/> is visible on the <see cref="Toolbox"/>
/// </summary>
[DefaultValue(true)]
public virtual bool Visible
{
[DebuggerStepThrough]
get { return _visible; }
[DebuggerStepThrough]
set { _visible = value; }
}
/// <summary>
/// Gets or sets the tooltip text of the <see cref="Item"/>.
/// </summary>
[DefaultValue("")]
public virtual string Tooltip
{
#if DEBUG
get { return _text; }
#else
[DebuggerStepThrough]
get
{
if (string.IsNullOrEmpty(_tooltip))
{
_tooltip = _text;
}
return _tooltip;
}
#endif
[DebuggerStepThrough]
set
{
if (value != null)
{
_tooltip = value;
}
}
}
/// <summary>
/// Gets the value indicating whether the <see cref="Item"/> is currently selected.
/// </summary>
[Browsable(false)]
[DefaultValue(false)]
public virtual bool Selected
{
[DebuggerStepThrough]
get { return _selected; }
internal set
{
if (_selected != value && Toolbox != null)
{
_selected = value;
Toolbox.Invalidate(this.Bounds);
}
}
}
/// <summary>
/// Gets the value indicating whether the <see cref="Item"/> is currently highlighted.
/// </summary>
[Browsable(false)]
[DefaultValue(false)]
public virtual bool Highlighted
{
[DebuggerStepThrough]
get { return _highlighted; }
internal set
{
if (_highlighted != value && Toolbox != null)
{
_highlighted = value;
Toolbox.Invalidate(this.Bounds);
}
}
}
/// <summary>
/// Gets the <see cref="Tab">Category</see> that contains the <see cref="Item"/>.
/// </summary>
[Browsable(false)]
internal Tab Category
{
[DebuggerStepThrough]
get
{
Toolbox toolbox = _owner as Toolbox;
if (toolbox != null)
{
if (toolbox.AllowToolboxItems)
return null;
else
return toolbox.GetToolboxItemsTab(true);
}
return _owner as Tab;
}
}
/// <summary>
/// Gets the <see cref="Toolbox"/> that contains the <see cref="Item"/>.
/// </summary>
[Browsable(false)]
public Toolbox Toolbox
{
get
{
Tab tab = _owner as Tab;
if (tab != null)
return tab.Toolbox;
return (Toolbox)_owner;
}
}
/// <summary>
/// Gets the <see cref="ITab">current</see> object that contains the <see cref="Item"/>.
/// </summary>
[Browsable(false)]
public ITab Owner
{
[DebuggerStepThrough]
get { return _owner; }
[DebuggerStepThrough]
internal set { _owner = value; }
}
/// <summary>
/// Gets or sets an object that contains data to associate with the item.
/// </summary>
[XmlIgnore]
public object Tag
{
[DebuggerStepThrough]
get { return _tag; }
[DebuggerStepThrough]
set { _tag = value; }
}
#endregion
#region Other Properties
/// <summary>
/// Gets the location of the left top point where to draw the <see cref="Item"/> on the <see cref="Toolbox"/>.
/// </summary>
protected internal Point Location
{
[DebuggerStepThrough]
get { return _location; }
[DebuggerStepThrough]
private set { _location = value; }
}
/// <summary>
/// Gets the width of the <see cref="Item"/> on the <see cref="Toolbox"/>.
/// </summary>
protected int Width
{
get
{
if (this.Owner == null)
return 0;
Toolbox toolbox = this.Toolbox;
if (toolbox == null)
return 0;
int width = this.Owner.Width;
if (this.Owner is Toolbox)
{
width = this.Owner.VisibleRectangle.Width - 2 * Toolbox.Gap_TabBorder;
}
else if (toolbox.DrawTabLevel && (!(this.Owner is Toolbox) || !toolbox.AllowToolboxItems))
{
width -= Toolbox.Gap_TabLevel;
}
return width;
}
}
/// <summary>
/// Gets the bounds of the <see cref="Item"/> on the <see cref="Toolbox"/>.
/// </summary>
protected internal virtual Rectangle Bounds
{
get
{
Toolbox toolbox = this.Toolbox;
if (toolbox == null)
return Rectangle.Empty;
return new Rectangle(this.Location, new Size(this.Width, toolbox.ItemHeight));
}
}
/// <summary>
/// Gets or sets the value indicating whether the <see cref="Item"/> is currently renamed.
/// </summary>
protected internal bool Renaming
{
[DebuggerStepThrough]
get { return _renaming; }
set
{
if (Toolbox != null)
{
_renaming = value;
Toolbox.Invalidate(Bounds);
}
}
}
#endregion
#region Public Methods
/// <summary>
/// Selects the <see cref="Item"/> on the <see cref="Toolbox"/>.
/// </summary>
public void Select()
{
if (Toolbox != null && Visible && Enabled)
{
EnsureVisible();
Toolbox.SelectTool(this);
}
}
/// <summary>
/// Returns a string representation of the <see cref="Item"/>.
/// </summary>
/// <returns>A string that states an <see cref="Item"/> type and the its text.</returns>
public override string ToString()
{
return string.Format("{0}: {1}", GetType().Name, Text);
}
/// <summary>
/// Ensures that the <see cref="Item"/> is visible within the <see cref="Toolbox"/>, scrolling the contents of the <see cref="Toolbox"/> if necessary and opening the container <see cref="Tab">Category</see>.
/// </summary>
public void EnsureVisible()
{
if (Toolbox != null && Visible)
{
if (Category != null)
Category.Opened = true;
Toolbox.EnsureVisible(Bounds);
}
}
#endregion
#region Protected Methods
/// <summary>
/// Invoked when the mouse button is pressed on the <see cref="Item"/>.
/// </summary>
/// <param name="e">A <see cref="System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
protected virtual void OnMouseDown(MouseEventArgs e)
{
}
/// <summary>
/// Invoked when the mouse button is depressed on the <see cref="Item"/>.
/// </summary>
/// <param name="e">A <see cref="System.Windows.Forms.MouseEventArgs"/> that contains the event data.</param>
/// <remarks>
/// If the mouse button is <see cref="MouseButtons.Right"/> the <see cref="IP.Components.Toolbox.ItemMenu"/> is shown if available.
/// </remarks>
protected virtual void OnMouseUp(MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
if (Toolbox.ItemMenu != null)
{
Toolbox.ItemMenu.Tag = this;
Toolbox.ItemMenu.Show(Toolbox, e.Location);
}
}
}
/// <summary>
/// Invoked when the user clicks on the <see cref="Item"/>.
/// </summary>
/// <param name="e">A <see cref="System.EventArgs"/> that contains the event data.</param>
protected virtual void OnClick(EventArgs e)
{
}
/// <summary>
/// Invoked when the user double clicks on the <see cref="Item"/>.
/// </summary>
/// <param name="e">A <see cref="System.EventArgs"/> that contains the event data.</param>
protected virtual void OnDoubleClick(EventArgs e)
{
}
/// <summary>
/// Draws the <see cref="Item"/> on the <see cref="Toolbox"/>.
/// </summary>
/// <param name="e">A <see cref="PaintEventArgs"/> that contains the paint event data.</param>
protected virtual void OnPaint(PaintEventArgs e)
{
bool setOwnClip = false;
Region oldClip = e.Graphics.Clip;
try
{
if (e.ClipRectangle.Contains(this.Bounds))
{
setOwnClip = true;
e.Graphics.Clip = new Region(Bounds);
}
GraphicsPath itemPath = this.GetItemPath();
RectangleF itemRect = itemPath.GetBounds();
Rectangle itemCorrectRect = Rectangle.Round(itemRect);
if (this.Enabled)
{
// Fill item
if (this.Selected && this.Highlighted)
{
using (Brush selHighBrush = new SolidBrush(Toolbox.ItemSelectHoverColor))
{
e.Graphics.FillRectangle(selHighBrush, itemRect);
}
}
else if (this.Selected)
{
using (Brush selBrush = new SolidBrush(Toolbox.ItemSelectColor))
{
e.Graphics.FillRectangle(selBrush, itemRect);
}
}
else if (this.Highlighted)
{
using (Brush hoverBrush = new SolidBrush(Toolbox.ItemHoverColor))
{
e.Graphics.FillRectangle(hoverBrush, itemRect);
}
}
// Draw border
if (Selected || Highlighted)
{
using (Pen selPen = new Pen(Toolbox.ItemSelectBorderColor))
{
e.Graphics.DrawRectangle(selPen, itemRect.Left, itemRect.Top, itemRect.Width, itemRect.Height);
}
}
}
// Draw icon
Rectangle imageRectangle = Rectangle.Empty;
if (this.Image != null && Toolbox.ShowIcons)
{
Size size = new Size(Image.Width, Toolbox.ItemHeight);
imageRectangle = new Rectangle(new Point(itemCorrectRect.Left + Toolbox.Gap_IconFromText, itemCorrectRect.Top), size);
if (imageRectangle.Height > Image.Height || imageRectangle.Width > Image.Width)
imageRectangle.Offset((int)(imageRectangle.Width - Image.Width) / 2, (int)(imageRectangle.Height - Image.Height) / 2);
using (Bitmap image = new Bitmap(this.Image))
{
if (this.TransparentColor != Color.Empty)
image.MakeTransparent(this.TransparentColor);
if (this.Enabled)
e.Graphics.DrawImageUnscaled(image, imageRectangle);
else
ControlPaint.DrawImageDisabled(e.Graphics, image, imageRectangle.Left, imageRectangle.Top, Toolbox.BackColorGradientStart);
}
}
// Write text
Rectangle itemTextRect = itemCorrectRect;
if (Toolbox.ShowIcons)
{
itemTextRect.Offset(imageRectangle.Width + 2 * Toolbox.Gap_IconFromText, 0);
itemTextRect.Width -= (imageRectangle.Width + 2 * Toolbox.Gap_IconFromText);
}
Brush textBrush = new SolidBrush(Toolbox.ForeColor);
if (this.Enabled)
e.Graphics.DrawString(this.Text, Toolbox.Font, textBrush, itemTextRect, _itemTextFormat);
else
ControlPaint.DrawStringDisabled(e.Graphics, this.Text, Toolbox.Font, Toolbox.BackColor, itemTextRect, _itemTextFormat);
}
finally
{
if (setOwnClip)
e.Graphics.Clip = oldClip;
}
}
/// <summary>
/// Returns the <see cref="GraphicsPath"/> structure that represents the <see cref="Item"/> drawing region.
/// </summary>
protected virtual GraphicsPath GetItemPath()
{
Rectangle rect = Bounds;
rect.Width -= 1;
rect.Height -= 1;
GraphicsPath path = new GraphicsPath();
path.AddRectangle(rect);
return path;
}
/// <summary>
/// Serializes an <see cref="Item"/> to the <see cref="XmlElement"/>.
/// </summary>
/// <param name="document">An <see cref="XmlDocument"/> that will own the resulting <see cref="XmlElement"/>.</param>
/// <returns>An <see cref="XmlElement"/> that contains <see cref="Item"/> data.</returns>
/// <exception cref="System.ArgumentNullException"><paramref name="document"/> is a null reference.</exception>
protected internal virtual XmlElement SerializeToXml(XmlDocument document)
{
if (document == null)
throw new ArgumentNullException("document");
XmlElement tabItem = document.CreateElement(Serializer_Item);
Type thisType = this.GetType();
foreach (PropertyInfo pi in Item.GetSerializableProperties(thisType))
{
object value = pi.GetValue(this, null);
if (value != null)
{
if (pi.IsDefined(Item.DefaulValueAttributeType, true))
{
object[] attributes = pi.GetCustomAttributes(Item.DefaulValueAttributeType, true);
DefaultValueAttribute attr = (DefaultValueAttribute)attributes[0];
if (attr.Value == value || (attr.Value != null && attr.Value.Equals(value)))
continue;
}
if (pi.PropertyType.IsPrimitive || pi.PropertyType.IsEnum)
tabItem.SetAttribute(pi.Name, value.ToString());
else if (pi.PropertyType == Item.StringType)
tabItem.SetAttribute(pi.Name, (string)value);
else if (pi.PropertyType == Item.ColorType)
tabItem.SetAttribute(pi.Name, ((Color)value).ToArgb().ToString());
else if (pi.PropertyType == Item.ImageType)
{
Image image = (Image)value;
using (MemoryStream stream = new MemoryStream())
{
image.Save(stream, ImageFormat.Bmp);
stream.Flush();
tabItem.SetAttribute(pi.Name, Convert.ToBase64String(stream.ToArray()));
}
}
}
}
return tabItem;
}
/// <summary>
/// Deserializes an <see cref="Item"/> data from the <see cref="XmlElement"/>.
/// </summary>
/// <param name="element">An <see cref="XmlElement"/> that contains <see cref="Item"/> data.</param>
/// <exception cref="System.ArgumentNullException"><paramref name="element"/> is a null reference.</exception>
protected internal virtual void DeserializeXml(XmlElement element)
{
if (element == null)
throw new ArgumentNullException("element");
foreach (PropertyInfo pi in Item.GetSerializableProperties(this.GetType()))
{
XmlAttribute attribute = element.Attributes[pi.Name];
if (attribute != null)
{
try
{
if (pi.PropertyType.IsPrimitive || pi.PropertyType.IsEnum)
{
pi.SetValue(this, Convert.ChangeType(attribute.Value, pi.PropertyType), null);
}
else if (pi.PropertyType == Item.StringType)
{
pi.SetValue(this, attribute.Value, null);
}
else if (pi.PropertyType == Item.ColorType)
{
int argb;
if (int.TryParse(attribute.Value, out argb))
pi.SetValue(this, Color.FromArgb(argb), null);
}
else if (pi.PropertyType == Item.ImageType)
{
MemoryStream stream = new MemoryStream(Convert.FromBase64String(attribute.Value));
this.Image = System.Drawing.Image.FromStream(stream);
}
}
catch { }
}
}
}
#endregion
#region Internal Methods
internal void InternalPaint(PaintEventArgs e, Point location)
{
this.Location = location;
OnPaint(e);
}
internal void InternalMouseDown(MouseEventArgs e)
{
OnMouseDown(e);
}
internal void InternalMouseUp(MouseEventArgs e)
{
OnMouseUp(e);
}
internal void InternalClick(EventArgs e)
{
OnClick(e);
}
internal void InternalDoubleClick(EventArgs e)
{
OnDoubleClick(e);
}
/// <summary>
/// Returns a bounds <see cref="Rectangle"/> of the <see cref="Item"/>.
/// </summary>
/// <param name="includeImage">Indicates whether to include image rectangle into returned bounds.</param>
internal protected Rectangle GetBounds(bool includeImage)
{
Rectangle rect = Bounds;
if (!includeImage && Image != null && Toolbox.ShowIcons)
{
int offset = Image.Width + 2 * Toolbox.Gap_IconFromText;
rect.X += offset;
rect.Width -= offset;
}
return rect;
}
#endregion
#region Private Methods
private bool ShouldSerializeImage()
{
if (this.Image == null)
return false;
return true;
}
private bool ShouldSerializeTransparentColor()
{
if (this.TransparentColor == Color.Empty)
return false;
return true;
}
private bool ShouldSerializeTab()
{
return false;
}
private void ResetImage()
{
this.Image = null;
}
#endregion
#region ICloneable Members
/// <summary>
/// Creates a new object that is a copy of the current instance.
/// </summary>
object ICloneable.Clone()
{
return Clone();
}
/// <summary>
/// Creates an identical copy of the <see cref="Item"/>.
/// </summary>
/// <returns>An object that represents an <see cref="Item"/> that has the same text, image, forecolor and backcolor associated with it as the cloned item.</returns>
public virtual Item Clone()
{
Item item = new Item();
item._text = _text;
item._image = _image;
item._foreColor = _foreColor;
item._backColor = _backColor;
return item;
}
#endregion
}
}
}