using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
//-----------------------------------------------------------------------------
//Copyright �2002-2005 Jon Wojtowicz, All Rights Reserved.
// Some code may also contain other copyrights by the author.
// jwojtowicz@codemeister.net
//-----------------------------------------------------------------------------
// Distribution: You can freely use this code in your own
// applications provided that credit is given
// to the author.
//
//-----------------------------------------------------------------------------
namespace Persephone.Windows.Control
{
/// <summary>
/// A menu item with an associated icon.
/// </summary>
public class IconMenuItem : System.Windows.Forms.MenuItem
{
private const int defaultGraphicDimension = 20;
private Font _font = new Font("Arial", 8);
private Icon _icon;
private int _graphicWidth = defaultGraphicDimension;
private int _graphicHeight = defaultGraphicDimension;
private bool _drawGraphic = true;
#region Properties
/// <summary>
/// The actual text without the accelerator & in it.
/// </summary>
public string RealText
{
get{ return GetRealText(); }
}
/// <summary>
/// Whether the icon and icon area should be drawn.
/// </summary>
public bool DrawGraphic
{
get{ return _drawGraphic; }
set{_drawGraphic = value; }
}
/// <summary>
/// The icon to use with this menu item.
/// </summary>
public Icon Icon
{
get{ return _icon; }
set
{
if( _icon != null)
_icon.Dispose();
_icon = value;
if( _icon != null)
{
_graphicWidth = (_icon.Width > _graphicWidth? _icon.Width:_graphicWidth);
_graphicHeight = (_icon.Height > _graphicHeight? _icon.Height:_graphicHeight);
}
else
{
_graphicWidth = defaultGraphicDimension;
_graphicHeight = defaultGraphicDimension;
}
}
}
/// <summary>
/// The height of the graphic area for the icon.
/// </summary>
public int GraphicHeight
{
get { return _graphicHeight; }
set{ _graphicHeight = value; }
}
/// <summary>
/// The width of the graphic area for the icon.
/// </summary>
public int GraphicWidth
{
get{ return _graphicWidth; }
set{ _graphicWidth = value; }
}
/// <summary>
/// The font to use for the menu.
/// </summary>
public Font Font
{
get{ return _font; }
set
{
if(_font != null)
_font.Dispose();
_font = value;
}
}
#endregion
#region Constructors
/// <summary>
/// Default constructor
/// </summary>
public IconMenuItem(): base()
{
base.OwnerDraw = true;
}
/// <summary>
/// Constructor specifying the menu text.
/// </summary>
/// <param name="text">The menu text.</param>
public IconMenuItem(string text): base(text)
{
base.OwnerDraw = true;
}
/// <summary>
/// Constructor specifying the menu text and te click event handler.
/// </summary>
/// <param name="text">The menu text.</param>
/// <param name="onClick">The click event handler.</param>
public IconMenuItem(string text, EventHandler onClick): base(text, onClick)
{
base.OwnerDraw = true;
}
/// <summary>
/// Constructor specifying the text and child menu items.
/// </summary>
/// <param name="text">The menu text.</param>
/// <param name="items">The child menu items.</param>
public IconMenuItem(string text, MenuItem[] items): base(text, items)
{
base.OwnerDraw = true;
}
#endregion
#region Drawing
/// <summary>
/// Draw the menu.
/// </summary>
/// <param name="e">The event args specifying where to draw.</param>
protected virtual void DrawItems(DrawItemEventArgs e)
{
Rectangle rcBk = e.Bounds;
Brush br = null;
Pen nPen = null;
if (_drawGraphic)
{
rcBk.X += _graphicWidth;
}
if ((e.State & DrawItemState.Selected) != 0 && this.Enabled)
{
br = new LinearGradientBrush(rcBk, SystemColors.ActiveCaption, SystemColors.InactiveCaption, LinearGradientMode.Horizontal);
}
else
{
br = new SolidBrush(System.Drawing.SystemColors.Control);
}
using(br)
{
e.Graphics.FillRectangle(br, rcBk);
}
if (_drawGraphic)
{
rcBk.X -= _graphicWidth;
rcBk.Width = _graphicWidth + 4;
using(br = new SolidBrush(System.Drawing.SystemColors.ControlLight))
{
e.Graphics.FillRectangle(br, rcBk);
}
}
using(StringFormat sf = new StringFormat())
{
sf.HotkeyPrefix = HotkeyPrefix.Show;
sf.SetTabStops(60, new float[] {0});
int left = 4;
if (_drawGraphic)
{
left = e.Bounds.Left + _graphicWidth + 4;
}
if (String.Compare("-", this.Text) == 0 )
{
using(Pen lineBasePen = new Pen(System.Drawing.SystemColors.ControlDark, 1))
{
using(Pen lineHighlightPen = new Pen(System.Drawing.SystemColors.ControlLightLight, 1))
{
int lineY = ((e.Bounds.Bottom - e.Bounds.Top) / 2) + e.Bounds.Top;
e.Graphics.DrawLine(lineBasePen, left, lineY, e.Bounds.Right, lineY);
e.Graphics.DrawLine(lineHighlightPen, left, lineY + 1, e.Bounds.Right, lineY + 1);
}
}
}
else
{
if (this.Enabled)
{
br = new SolidBrush(e.ForeColor);
}
else
{
br = new SolidBrush(System.Drawing.SystemColors.GrayText);
}
using(br)
{
e.Graphics.DrawString(GetRealText(), _font, br, left, e.Bounds.Top + 2, sf);
}
}
}
if (_icon != null && _drawGraphic)
{
if (! this.Checked)
{
e.Graphics.DrawIcon(_icon, e.Bounds.Left, e.Bounds.Top);
}
else
{
e.Graphics.DrawIcon(_icon, e.Bounds.Left + 2, e.Bounds.Top + 2);
if (! this.Enabled)
{
nPen = new Pen(SystemColors.GrayText);
}
else
{
nPen = new Pen(SystemColors.ControlDarkDark);
}
using(nPen)
{
e.Graphics.DrawRectangle(nPen, 1, e.Bounds.Top, _graphicWidth, _graphicHeight);
}
}
}
else
{
if (this.Checked)
{
if (! this.Enabled)
{
nPen = new Pen(SystemColors.GrayText);
}
else
{
nPen = new Pen(SystemColors.ControlDarkDark);
}
using(nPen)
{
e.Graphics.DrawRectangle(nPen, 1, e.Bounds.Top, 20, 20);
}
Point[] Pnts = new Point[3];
Pnts[0] = new Point(15, e.Bounds.Top + 6);
Pnts[1] = new Point(8, e.Bounds.Top + 13);
Pnts[2] = new Point(5, e.Bounds.Top + 10);
if (this.Enabled)
{
nPen = new Pen(Color.Black);
}
else
{
nPen = new Pen(Color.Gray);
}
using(nPen)
{
e.Graphics.DrawLines(nPen, Pnts);
}
}
}
}
#endregion
#region Helper Methods
/// <summary>
/// Measure the size of the menu item. Return the value in the event args.
/// </summary>
/// <param name="e">The event args for measuring this item.</param>
protected virtual void MeasureItems(MeasureItemEventArgs e)
{
using(StringFormat sf = new StringFormat())
{
sf.HotkeyPrefix = HotkeyPrefix.Show;
sf.SetTabStops(60, new float[] {0});
if (String.Compare("-", this.Text) == 0)
{
e.ItemHeight = 3;
}
else
{
int textHeight = (int)(e.Graphics.MeasureString(GetRealText(), _font, 10000, sf).Height);
e.ItemHeight = (textHeight > _graphicHeight? textHeight: _graphicHeight);
}
e.ItemWidth = (int)(e.Graphics.MeasureString(GetRealText(), _font, 10000, sf).Width)
+ _graphicWidth + 10;
}
}
/// <summary>
/// Returns the actual menu text that will be displayed in the menu.
/// </summary>
/// <returns>The actual text of the menu.</returns>
protected string GetRealText()
{
string s = this.Text;
if (this.ShowShortcut && this.Shortcut != Shortcut.None)
{
Keys k = (Keys)this.Shortcut;
s = s + Convert.ToChar(9) + TypeDescriptor.GetConverter(typeof(Keys)).ConvertToString(k);
}
return s;
}
#endregion
#region Overrides
/// <summary>
/// Triggered by the system to get the menu item measurements.
/// </summary>
/// <param name="e">The event args for measuring this item.</param>
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
base.OnMeasureItem(e);
MeasureItems(e);
}
/// <summary>
/// Triggered by the system to get the menu item drawn.
/// </summary>
/// <param name="e">The event args specifying where to draw.</param>
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
base.OnDrawItem(e);
DrawItems(e);
}
/// <summary>
/// Clean up any contained objects that need to be disposed.
/// </summary>
/// <param name="disposing">True if dicpose is called from the client,
/// false if called from the finalizer.</param>
protected override void Dispose(bool disposing)
{
base.Dispose (disposing);
if(disposing)
{
if(_font != null)
_font.Dispose();
if(_icon != null)
_icon.Dispose();
}
}
#endregion
}
}
|