Sunday, September 30, 2007

ButtonEx - Owner Drawn Button Control

Wow 2 posts in 1 day. I must have a lot of spare time today! Actually I'm down with a cold and I just feel sorry for myself when I stay in bed.

In this article I'd like to share another piece of code that I use quite often. Its a simple owner drawn button control that can have a nice 3D shadow. Drawing the 3D shadow effect was by complete accident though. I was trying to just draw a simple control that acts like a button. When I was drawing the borders the first time I drawn the rectangle a pixel bigger hence the control had a 1 pixel line of just black on the right and bottom side. Anyway, my graphic artist loved it and decided that we keep it.

The control has the following properties added:
  1) PushedColor (Color) - The color the control will be filled with once the MouseDown is fired
  2) DrawShadow (Boolean) - A flag whether to draw the 3D border

The default settings of the control is best on a form with a blue-ish background.

And here's the code:

public class ButtonEx : Control
{
  private Bitmap off_screen;
  private SolidBrush back_brush;
  private SolidBrush selected_brush;
  private SolidBrush text_brush;
  private Pen border_pen;
  private bool pushed;
  private bool shadow;

  public ButtonEx()
  {
    BackColor = Color.FromArgb(2, 32, 154);
    ForeColor = Color.White;

    back_brush = new SolidBrush(Color.FromArgb(48, 88, 198));
    selected_brush = new SolidBrush(Color.FromArgb(15, 51, 190));
    border_pen = new Pen(Color.White);
    text_brush = new SolidBrush(Color.White);
  }

  public override Color BackColor
  {
    get { return base.BackColor; }
    set
    {
      base.BackColor = value;
      back_brush = new SolidBrush(value);
    }
  }

  public override Color ForeColor
  {
    get { return base.ForeColor; }
    set
    {
      base.ForeColor = value;
      border_pen = new Pen(value);
      text_brush = new SolidBrush(value);
    }
  }

  public Color PushedColor
  {
    get { return selected_brush.Color; }
    set { selected_brush = new SolidBrush(value); }
    }

  public bool DrawShadow
  {
    get { return shadow; }
    set { shadow = value; }
  }

  protected override void OnPaint(PaintEventArgs e)
  {
    if (off_screen == null) {
      off_screen = new Bitmap(ClientSize.Width, ClientSize.Height);
    }

    using (Graphics gxOff = Graphics.FromImage(off_screen)) {
      gxOff.DrawRectangle(
        border_pen,
        0,
        0,
        ClientSize.Width - (shadow ? 0 : 1),
        ClientSize.Height - (shadow ? 0 : 1));

      Rectangle rect = new Rectangle(1, 1,
        ClientRectangle.Width - 2, ClientRectangle.Height - 2);

      gxOff.FillRectangle(
        pushed ? back_brush : selected_brush, rect);

      if (!string.IsNullOrEmpty(Text)) {
        SizeF size = gxOff.MeasureString(Text, Font);
        gxOff.DrawString(
          Text,
          Font,
          text_brush,
          (ClientSize.Width - size.Width) / 2,
          (ClientSize.Height - size.Height) / 2);
      }
    }

    e.Graphics.DrawImage(off_screen, 0, 0);
  }

  protected override void OnPaintBackground(PaintEventArgs e) { }

  protected override void OnMouseDown(MouseEventArgs e)
  {
    base.OnMouseDown(e);

    pushed = true;
    Invalidate();
  }

  protected override void OnMouseUp(MouseEventArgs e)
  {
    base.OnMouseUp(e);

    pushed = false;
    Invalidate();
  }

  protected override void OnTextChanged(EventArgs e)
  {
    base.OnTextChanged(e);

    Invalidate();
  }
}

No comments: