#region Disclaimer / License
// Copyright (C) 2007, Kenneth Skovhede
// http://www.hexad.dk, opensource@hexad.dk
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion
using System;
using System.Windows.Forms;
using System.Drawing;
namespace WallpaperChanger
{
///
/// A menuitem with extra variables for images and fonts
///
public class ExtendedMenuItem
: MenuItem
{
private Font m_font;
private Image m_image;
private Icon m_icon;
///
/// Spacing constant for space between text and icon
///
private const int ICON_SPACING = 0;
///
/// Constant for spacing at the left and right edge of the menu item
///
private const int MENU_SPACING_WIDTH = 2;
///
/// Constant for spacing at the top and bottom of the menu item
///
private const int MENU_SPACING_HEIGHT = 2;
///
/// Basic default constructor
///
public ExtendedMenuItem()
: base()
{
m_font = SystemInformation.MenuFont;
base.OwnerDraw = true;
}
///
/// Specialized constructor
///
/// The text of the item
/// The delegate that is called when the menu is clicked
public ExtendedMenuItem(string text, System.EventHandler clickhandler)
: base (text, clickhandler)
{
m_font = SystemInformation.MenuFont;
base.OwnerDraw = true;
}
///
/// Gets or sets the font of the menu
///
public Font Font
{
get { return m_font; }
set { m_font = value; }
}
///
/// Gets or sets the image for the item. The image overrides any icon
///
public Image Image
{
get { return m_image; }
set { m_image = value; }
}
///
/// Gets or sets the icon for the item. The image overrides any icon
///
public Icon Icon
{
get { return m_icon; }
set { m_icon = value; }
}
///
/// Internal handler that ensures the menuitem is big enough to hold text and image/icon
///
/// An object with measuring information
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
//Get the size of the string, when using the current font
System.Drawing.StringFormat sf = new System.Drawing.StringFormat();
sf.Alignment = System.Drawing.StringAlignment.Near;
sf.FormatFlags = System.Drawing.StringFormatFlags.NoWrap;
sf.Trimming = System.Drawing.StringTrimming.Character;
System.Drawing.SizeF size = e.Graphics.MeasureString(base.Text, this.Font, new System.Drawing.Point(0,0), sf);
//TODO: Calculate the max width of all the images in this menu, and adjust the text according
//If we have an image or an icon, allocate space for that as well
if (m_image != null)
{
size.Width += m_image.Width + ICON_SPACING;
size.Height = Math.Max(size.Height, m_image.Height);
}
else if (m_icon != null)
{
size.Width += m_icon.Width + ICON_SPACING;
size.Height = Math.Max(size.Height, m_icon.Height);
}
//Add spacing to the return values
e.ItemWidth = (int)size.Width + (MENU_SPACING_WIDTH * 2);
e.ItemHeight = (int)size.Height + (MENU_SPACING_HEIGHT * 2);
}
///
/// Internal handler that draws the menuitem
///
/// An object with various drawing helper methods and objects
protected override void OnDrawItem(DrawItemEventArgs e)
{
//Select the current background color and foreground color, based on the system colors
System.Drawing.Color textColor = (e.State & DrawItemState.Selected) == 0 ? System.Drawing.SystemColors.MenuText : System.Drawing.SystemColors.HighlightText;
System.Drawing.Color backColor = (e.State & DrawItemState.Selected) == 0 ? System.Drawing.SystemColors.Menu : System.Drawing.SystemColors.Highlight;
//This call is broken for some reason...
//e.DrawBackground();
//So we emulate it the right way
using(System.Drawing.Pen p = new System.Drawing.Pen(backColor))
e.Graphics.DrawRectangle(p, e.Bounds);
using(System.Drawing.SolidBrush b = new System.Drawing.SolidBrush(backColor))
e.Graphics.FillRectangle(b, e.Bounds);
//Have not seen this effect being active...
if ((e.State & DrawItemState.Focus) != 0)
e.DrawFocusRectangle();
//Setup the string format and drawing area
System.Drawing.StringFormat sf = new System.Drawing.StringFormat();
sf.Alignment = System.Drawing.StringAlignment.Near;
sf.FormatFlags = System.Drawing.StringFormatFlags.NoWrap;
sf.Trimming = System.Drawing.StringTrimming.Character;
System.Drawing.Rectangle r = new System.Drawing.Rectangle(e.Bounds.Location, e.Bounds.Size);
//Adjust with some spacing top and left
r.X += MENU_SPACING_WIDTH;
r.Y += MENU_SPACING_HEIGHT;
//TODO: Calculate the max width of all the images in this menu, and adjust the text according
//If we have an image or an icon, draw it, and ajust the string rectangle
if (m_image != null)
{
e.Graphics.DrawImage(m_image, r.X, r.Y);
r.X += m_image.Width + ICON_SPACING;
r.Width -= m_image.Width + ICON_SPACING;
}
else if (m_icon != null)
{
e.Graphics.DrawIcon(m_icon, r.X, r.Y);
r.X += m_icon.Width + ICON_SPACING;
r.Width -= m_icon.Width + ICON_SPACING;
}
//Place the string in the middle of the box, as opposed to the top of the box
System.Drawing.SizeF sh = e.Graphics.MeasureString(base.Text, this.Font, new System.Drawing.Point(0,0), sf);
r.Y += ((int)((e.Bounds.Height - sh.Height) / 2)) - 1;
//Draw the current text
using(System.Drawing.SolidBrush b = new System.Drawing.SolidBrush(textColor))
e.Graphics.DrawString(base.Text, e.Font, b, r, sf);
}
}
}