www.pudn.com > sudoku.rar > TextStatefulButton.cs
//--------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: TextStatefulButton.cs
//
// Description: Custom button used for all buttons in Sudoku.
//
//--------------------------------------------------------------------------
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Text;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Windows.Forms;
using Microsoft.Sudoku.Utilities;
namespace Microsoft.Sudoku.Controls
{
/// A custom button rendered with multiple images and text.
[ToolboxBitmap(typeof(Button))]
internal sealed class TextStatefulButton : Control
{
/// Initializes the button.
public TextStatefulButton()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.DoubleBuffer |
ControlStyles.UserPaint | ControlStyles.ResizeRedraw |
ControlStyles.SupportsTransparentBackColor | ControlStyles.CacheText, true);
SetStyle(ControlStyles.StandardDoubleClick | ControlStyles.StandardClick, false);
SetStyle(ControlStyles.Selectable, false);
BackColor = Color.Transparent;
_centeredFormat = new StringFormat(); //StringFormatFlags.FitBlackBox);
_centeredFormat.LineAlignment = StringAlignment.Center;
_centeredFormat.Alignment = StringAlignment.Center;
}
/// Image used as the shadow of the control.
private Image _shadowImage;
/// Image used to represent the pressed/checked state of the control.
private Image _checkedImage;
/// Image used to represent the unpressed/unchecked state of the control.
private Image _uncheckedImage;
/// Image used to represent the highlighted state of the control.
private Image _highlightedImage;
/// Image used to represent the icon/overlay for the control.
private Image _overlayImage;
/// Whether the control can be checked.
private bool _allowChecking;
/// Whether the control can be unchecked by a user.
private bool _allowNonprogrammaticUnchecking;
/// Whether the control is checked.
private bool _checked;
/// Whether the control is currently highlighted.
private bool _highlighted;
/// Whether the mouse is currently down.
private bool _mouseDown;
/// Used to center the text.
private StringFormat _centeredFormat;
/// The current font for rendering.
private Font _font;
/// Whether the font should autosize to fit within the button.
private bool _autosizeFont = true;
/// Whether the placement of text should be adjusted based on whether the button is checked.
private bool _adjustTextPlacement = true;
/// Sets the image used as the shadow of the control.
public Image ShadowImage { set { _shadowImage = value; } }
/// Sets the image used to represent the pressed/checked state of the control.
public Image CheckedImage { set { _checkedImage = value; } }
/// Sets the image used to represent the unpressed/unchecked state of the control.
public Image UncheckedImage { set { _uncheckedImage = value; } }
/// Sets the image used to represent the highlighted state of the control.
public Image HighlightedImage { set { _highlightedImage = value; } }
/// Sets the image used to represent the icon/overlay for the control.
public Image OverlayImage { set { _overlayImage = value; } }
/// Gets whether the control can be checked.
public bool AllowChecking { get { return _allowChecking; } set { _allowChecking = value; } }
/// Gets whether the control can be unchecked by a user.
public bool AllowNonprogrammaticUnchecking { get { return _allowNonprogrammaticUnchecking; } set { _allowNonprogrammaticUnchecking = value; } }
/// Gets whether the control is currently highlighted.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
private bool Highlighted { get { return _highlighted; } }
/// Gets wether the mouse is currently down.
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(false)]
private bool MouseIsDown { get { return _mouseDown; } }
/// Gets or sets whether the control is checked.
public bool Checked
{
get { return _allowChecking ? _checked : false; }
set
{
if (_allowChecking && _checked != value)
{
CancelEventArgs e = new CancelEventArgs(false);
OnBeforeCheckedChanged(e);
if (!e.Cancel)
{
_checked = value;
Invalidate();
OnCheckedChanged();
}
}
}
}
/// Gets or sets whether the control is focusable.
public bool Focusable
{
get { return GetStyle(ControlStyles.Selectable); }
set { SetStyle(ControlStyles.Selectable, value); }
}
/// Gets or sets whether the control supports auto-font resize.
public bool AutosizeFont { get { return _autosizeFont; } set { _autosizeFont = value; } }
/// Gets or sets whether the font size should be adjusted based on whether the control is checked.
public bool AdjustTextPlacementWhenChecked { get { return _adjustTextPlacement; } set { _adjustTextPlacement = value; } }
/// Event raised before the control's checked state changes.
public event CancelEventHandler BeforeCheckedChanged;
/// Event raised after the control's checked state changes.
public event EventHandler CheckedChanged;
/// Cleans up.
/// Whether this is the result of a call to IDisposable.Dispose.
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_centeredFormat != null)
{
_centeredFormat.Dispose();
_centeredFormat = null;
}
if (_font != null)
{
_font.Dispose();
_font = null;
}
}
base.Dispose (disposing);
}
/// Handles the control's resize.
protected override void OnResize(EventArgs e)
{
ClearFont();
base.OnResize(e);
}
/// Handles the control's layout.
protected override void OnLayout(LayoutEventArgs levent)
{
ClearFont();
base.OnLayout (levent);
}
/// Handles the control's font change.
protected override void OnFontChanged(EventArgs e)
{
ClearFont();
base.OnFontChanged (e);
}
/// Handles the control's checked change.
private void OnCheckedChanged()
{
ClearFont();
EventHandler e = CheckedChanged;
if (e != null) e(this, EventArgs.Empty);
}
/// Raises the BeforeCheckedChanged event.
private void OnBeforeCheckedChanged(CancelEventArgs e)
{
CancelEventHandler handler = BeforeCheckedChanged;
if (handler != null) handler(this, e);
}
/// Handles the mouse enter event.
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter (e);
_highlighted = true;
Invalidate();
}
/// Handles the mouse leave event.
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave (e);
_highlighted = false;
Invalidate();
}
/// Handles the mouse down event.
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown (e);
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
_highlighted = false;
_mouseDown = true;
if (_allowNonprogrammaticUnchecking || !Checked) Checked = !Checked;
if (Focusable) Select();
Invalidate();
}
}
/// Handles the mouse up event.
protected override void OnMouseUp(MouseEventArgs e)
{
if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
{
_mouseDown = false;
if (!AllowChecking)
{
Point mousePosition = Control.MousePosition;
if (ClientRectangle.Contains(PointToClient(mousePosition)))
{
_highlighted = true;
}
}
Invalidate();
if (ClientRectangle.Contains(PointToClient(MousePosition))) OnClick(e);
}
base.OnMouseUp (e);
}
/// Clears the currently cached font.
private void ClearFont()
{
if (_font != null)
{
Font f = _font;
_font = null;
f.Dispose();
}
}
/// Gets the font to use for rendering.
/// The font to use for rendering.
private Font GetFontForText()
{
if (!_autosizeFont) return base.Font;
if (_font == null)
{
Font baseFont = base.Font;
if (Text == null || Text.Length == 0) return baseFont;
using(Graphics g = CreateGraphics())
{
int width = Width * 9 / 10;
int height = Height * 9 / 10;
_font = new Font(baseFont.FontFamily,
GraphicsHelpers.GetMaximumEMSize(Text, g, baseFont.FontFamily, baseFont.Style, width, height), baseFont.Style);
}
}
return _font;
}
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
OnClick(e);
}
else base.OnKeyDown (e);
}
protected override void OnGotFocus(EventArgs e)
{
base.OnGotFocus (e);
Invalidate();
}
protected override void OnLostFocus(EventArgs e)
{
base.OnLostFocus (e);
Invalidate();
}
/// Paints the button.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
// Setup the graphics object
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBilinear;
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
// Determine the image to be drawn based on the current state
Image img = _uncheckedImage;
if (Enabled && Visible)
{
if (Checked || _mouseDown) img = _checkedImage;
else if (_highlighted || this.Focused) img = _highlightedImage;
}
if (img != null)
{
using(ImageAttributes attrs = new ImageAttributes())
{
// If the control is disabled, use alpha blending
ColorMatrix m = new ColorMatrix();
m.Matrix33 = Enabled && Visible ? 1f : .5f;
attrs.SetColorMatrix(m);
int width = ClientRectangle.Width;
int height = ClientRectangle.Height;
// Draw the shadow if appropriate
if (Enabled && Visible && !Checked && !MouseIsDown && _shadowImage != null)
{
e.Graphics.DrawImage(_shadowImage, new Rectangle(1, 1, width, height),
0, 0, _shadowImage.Width, _shadowImage.Height, GraphicsUnit.Pixel, attrs);
}
width -= 2;
height -= 2;
// Draw the image
e.Graphics.DrawImage(img, new Rectangle(0, 0, width, height),
0, 0, img.Width, img.Height, GraphicsUnit.Pixel, attrs);
// Draw the icon if appropriate
if (_overlayImage != null)
{
Rectangle targetRect = new Rectangle(0, 0, width, height);
targetRect.Inflate(-width/8, -height/8);
if (Enabled && Visible && (Checked || _mouseDown))
{
targetRect.Offset((int)Math.Ceiling(ClientRectangle.Height/20f), (int)Math.Ceiling(ClientRectangle.Height/20f));
targetRect.Inflate((int)Math.Ceiling(-ClientRectangle.Height/30f), (int)Math.Ceiling(-ClientRectangle.Height/30f));
}
e.Graphics.DrawImage(_overlayImage, targetRect,
0, 0, _overlayImage.Width, _overlayImage.Height, GraphicsUnit.Pixel, attrs);
}
// If there's text to display
if (Text != null && Text.Length > 0)
{
RectangleF bounds = new RectangleF(0, 0, width, height);
// Update the bounds if necessary
if (Enabled && Visible && AdjustTextPlacementWhenChecked && (Checked || MouseIsDown))
{
bounds.Inflate(-ClientRectangle.Height/6, -ClientRectangle.Height/6);
bounds.Offset(ClientRectangle.Height/15, ClientRectangle.Height/15);
}
// Get the color to use for the text, alpha blended if the control is disabled
Color c = ForeColor;
if (!Enabled || !Visible) c = Color.FromArgb(128, c);
// Draw it
using(Brush b = new SolidBrush(c)) // Can cache this for improved performance
{
e.Graphics.DrawString(Text, GetFontForText(), b, bounds, _centeredFormat);
}
}
}
}
}
}
}