//######################################################################################### //★★★★★★★ http://www.cnpopsoft.com [华普软件] ★★★★★★★ //★★★★★★★ 华普软件 - VB & C#.NET 专业论文与源码荟萃! ★★★★★★★ //######################################################################################### /* * Copyright ?2005, Mathew Hall * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ using System; using System.ComponentModel; using System.Drawing; using System.Globalization; using System.Windows.Forms; using XPTable.Events; using XPTable.Models; using XPTable.Themes; namespace XPTable.Renderers { /// /// A CellRenderer that draws Cell contents as Buttons /// public class ButtonCellRenderer : CellRenderer { #region Class Data /// /// Specifies the alignment of the Image displayed on the button /// private ContentAlignment imageAlignment; #endregion #region Constructor /// /// Initializes a new instance of the ButtonCellRenderer class with /// default settings /// public ButtonCellRenderer() : base() { this.imageAlignment = ContentAlignment.MiddleCenter; } #endregion #region Methods /// /// Gets the ButtonCellRenderer specific data used by the Renderer from /// the specified Cell /// /// The Cell to get the ButtonCellRenderer data for /// The ButtonCellRenderer data for the specified Cell protected ButtonRendererData GetButtonRendererData(Cell cell) { object rendererData = this.GetRendererData(cell); if (rendererData == null || !(rendererData is ButtonRendererData)) { rendererData = new ButtonRendererData(); this.SetRendererData(cell, rendererData); } return (ButtonRendererData) rendererData; } /// /// Returns a Rectangle that specifies the size and location of the button /// /// A Rectangle that specifies the size and location of the button protected virtual Rectangle CalcButtonBounds() { return this.ClientRectangle; } /// /// Returns a Rectangle that specifies the size and location of the buttons Image /// /// The buttons image /// The alignment of the image /// A Rectangle that specifies the size and location of the buttons Image protected Rectangle CalcImageRect(Image image, ContentAlignment imageAlignment) { Rectangle imageRect = new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, image.Width, image.Height); switch (imageAlignment) { case ContentAlignment.TopCenter: case ContentAlignment.MiddleCenter: case ContentAlignment.BottomCenter: { imageRect.X += (this.ClientRectangle.Width - image.Width) / 2; break; } case ContentAlignment.TopRight: case ContentAlignment.MiddleRight: case ContentAlignment.BottomRight: { imageRect.X = this.ClientRectangle.Right - image.Width; break; } } switch (imageAlignment) { case ContentAlignment.TopLeft: case ContentAlignment.TopCenter: case ContentAlignment.TopRight: { imageRect.Y += 2; break; } case ContentAlignment.MiddleLeft: case ContentAlignment.MiddleCenter: case ContentAlignment.MiddleRight: { imageRect.Y += (this.ClientRectangle.Height - image.Height) / 2; break; } case ContentAlignment.BottomLeft: case ContentAlignment.BottomCenter: case ContentAlignment.BottomRight: { imageRect.Y = this.ClientRectangle.Bottom - image.Height - 2; break; } } return imageRect; } #endregion #region Properties /// /// Gets or sets the alignment of the Image displayed on the buttons /// public ContentAlignment ImageAlignment { get { return this.imageAlignment; } set { this.imageAlignment = value; } } #endregion #region Events #region Focus /// /// Raises the GotFocus event /// /// A CellFocusEventArgs that contains the event data public override void OnGotFocus(CellFocusEventArgs e) { base.OnGotFocus(e); // get the table to redraw the cell e.Table.Invalidate(e.CellRect); } /// /// Raises the LostFocus event /// /// A CellFocusEventArgs that contains the event data public override void OnLostFocus(CellFocusEventArgs e) { base.OnLostFocus(e); // get the table to redraw the cell e.Table.Invalidate(e.CellRect); } #endregion #region Keys /// /// Raises the KeyDown event /// /// A CellKeyEventArgs that contains the event data public override void OnKeyDown(CellKeyEventArgs e) { base.OnKeyDown(e); // get the button renderer data ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); // if (e.KeyData == Keys.Enter || e.KeyData == Keys.Space) { rendererData.ButtonState = PushButtonStates.Pressed; e.Table.Invalidate(e.CellRect); } } /// /// Raises the KeyUp event /// /// A CellKeyEventArgs that contains the event data public override void OnKeyUp(CellKeyEventArgs e) { base.OnKeyUp(e); // get the button renderer data ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); // if (e.KeyData == Keys.Enter || e.KeyData == Keys.Space) { rendererData.ButtonState = PushButtonStates.Normal; e.Table.Invalidate(e.CellRect); e.Table.OnCellButtonClicked(new CellButtonEventArgs(e.Cell, e.Column, e.Row)); } } #endregion #region Mouse #region MouseEnter /// /// Raises the MouseEnter event /// /// A CellMouseEventArgs that contains the event data public override void OnMouseEnter(CellMouseEventArgs e) { base.OnMouseEnter(e); // get the button renderer data ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); // if the mouse is inside the button, make sure it is "hot" if (this.CalcButtonBounds().Contains(e.X, e.Y)) { if (rendererData.ButtonState != PushButtonStates.Hot) { rendererData.ButtonState = PushButtonStates.Hot; e.Table.Invalidate(e.CellRect); } } // the mouse isn't inside the button, so it is in its normal state else { if (rendererData.ButtonState != PushButtonStates.Normal) { rendererData.ButtonState = PushButtonStates.Normal; e.Table.Invalidate(e.CellRect); } } } #endregion #region MouseLeave /// /// Raises the MouseLeave event /// /// A CellMouseEventArgs that contains the event data public override void OnMouseLeave(CellMouseEventArgs e) { base.OnMouseLeave(e); // get the button renderer data ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); // make sure the button is in its normal state if (rendererData.ButtonState != PushButtonStates.Normal) { rendererData.ButtonState = PushButtonStates.Normal; e.Table.Invalidate(e.CellRect); } } #endregion #region MouseUp /// /// Raises the MouseUp event /// /// A CellMouseEventArgs that contains the event data public override void OnMouseUp(CellMouseEventArgs e) { base.OnMouseUp(e); // get the button renderer data ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); // check for the left mouse button if (e.Button == MouseButtons.Left) { Rectangle buttonRect = this.CalcButtonBounds(); // if the mouse pointer is over the button, make sure // the button is "hot" if (buttonRect.Contains(e.X, e.Y)) { rendererData.ButtonState = PushButtonStates.Hot; e.Table.Invalidate(e.CellRect); // check if the click started inside the button. if // it did, Raise the tables CellButtonClicked event if (buttonRect.Contains(rendererData.ClickPoint)) { e.Table.OnCellButtonClicked(new CellButtonEventArgs(e.Cell, e.Column, e.Row)); } } else { // the mouse was released somewhere outside of the button, // so make set the button back to its normal state if (rendererData.ButtonState != PushButtonStates.Normal) { rendererData.ButtonState = PushButtonStates.Normal; e.Table.Invalidate(e.CellRect); } } } // reset the click point rendererData.ClickPoint = Point.Empty; } #endregion #region MouseDown /// /// Raises the MouseDown event /// /// A CellMouseEventArgs that contains the event data public override void OnMouseDown(CellMouseEventArgs e) { base.OnMouseDown(e); // get the button renderer data ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); // check if the left mouse button is pressed if (e.Button == MouseButtons.Left) { // record where the click started rendererData.ClickPoint = new Point(e.X, e.Y); // if the click was inside the button, set the button state to pressed if (this.CalcButtonBounds().Contains(rendererData.ClickPoint)) { rendererData.ButtonState = PushButtonStates.Pressed; e.Table.Invalidate(e.CellRect); } } } #endregion #region MouseMove /// /// Raises the MouseMove event /// /// A CellMouseEventArgs that contains the event data public override void OnMouseMove(CellMouseEventArgs e) { base.OnMouseMove(e); // get the button renderer data ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); Rectangle buttonRect = this.CalcButtonBounds(); // check if the left mouse button is pressed if (e.Button == MouseButtons.Left) { // check if the mouse press originated in the button area if (buttonRect.Contains(rendererData.ClickPoint)) { // check if the mouse is currently in the button if (buttonRect.Contains(e.X, e.Y)) { // make sure the button is pressed if (rendererData.ButtonState != PushButtonStates.Pressed) { rendererData.ButtonState = PushButtonStates.Pressed; e.Table.Invalidate(e.CellRect); } } else { // the mouse isn't inside the button so make sure it is "hot" if (rendererData.ButtonState != PushButtonStates.Hot) { rendererData.ButtonState = PushButtonStates.Hot; e.Table.Invalidate(e.CellRect); } } } } else { // check if the mouse is currently in the button if (buttonRect.Contains(e.X, e.Y)) { // the mouse is inside the button so make sure it is "hot" if (rendererData.ButtonState != PushButtonStates.Hot) { rendererData.ButtonState = PushButtonStates.Hot; e.Table.Invalidate(e.CellRect); } } else { // not inside the button so make sure it is in its normal state if (rendererData.ButtonState != PushButtonStates.Normal) { rendererData.ButtonState = PushButtonStates.Normal; e.Table.Invalidate(e.CellRect); } } } } #endregion #endregion #region Paint /// /// Raises the PaintCell event /// /// A PaintCellEventArgs that contains the event data public override void OnPaintCell(PaintCellEventArgs e) { if (e.Table.ColumnModel.Columns[e.Column] is ButtonColumn) { this.ImageAlignment = ((ButtonColumn) e.Table.ColumnModel.Columns[e.Column]).ImageAlignment; } else { this.ImageAlignment = ContentAlignment.MiddleLeft; } base.OnPaintCell(e); } /// /// Raises the PaintBackground event /// /// A PaintCellEventArgs that contains the event data protected override void OnPaintBackground(PaintCellEventArgs e) { base.OnPaintBackground(e); // don't bother going any further if the Cell is null if (e.Cell == null) { return; } // get the button state ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell); PushButtonStates state = rendererData.ButtonState; // if the cell has focus and is in its normal state, // make the button look like a default button if (state == PushButtonStates.Normal && e.Focused) { state = PushButtonStates.Default; } // if the table is not enabled, make sure the button is disabled if (!e.Enabled) { state = PushButtonStates.Disabled; } // draw the button ThemeManager.DrawButton(e.Graphics, this.CalcButtonBounds(), state); } /// /// Raises the Paint event /// /// A PaintCellEventArgs that contains the event data protected override void OnPaint(PaintCellEventArgs e) { base.OnPaint(e); // don't bother going any further if the Cell is null if (e.Cell == null) { return; } Rectangle textRect = this.CalcButtonBounds(); textRect.Inflate(-4, -2); if (e.Cell.Image != null) { Rectangle imageRect = this.CalcImageRect(e.Cell.Image, this.ImageAlignment); if (this.GetButtonRendererData(e.Cell).ButtonState == PushButtonStates.Pressed && !ThemeManager.VisualStylesEnabled) { imageRect.X += 1; imageRect.Y += 1; } this.DrawImage(e.Graphics, e.Cell.Image, imageRect, e.Enabled); } // draw the text if (e.Cell.Text != null && e.Cell.Text.Length != 0) { if (e.Enabled) { if (!ThemeManager.VisualStylesEnabled && this.GetButtonRendererData(e.Cell).ButtonState == PushButtonStates.Pressed) { textRect.X += 1; textRect.Y += 1; } // if the cell or the row it is in is selected // our forecolor will be the selection forecolor. // we'll ignore this and reset our forecolor to // that of the cell being rendered if (e.Selected) { this.ForeColor = e.Cell.ForeColor; } e.Graphics.DrawString(e.Cell.Text, this.Font, this.ForeBrush, textRect, this.StringFormat); } else { e.Graphics.DrawString(e.Cell.Text, this.Font, this.GrayTextBrush, textRect, this.StringFormat); } } // draw focus if (e.Focused && e.Enabled) { Rectangle focusRect = this.CalcButtonBounds(); if (ThemeManager.VisualStylesEnabled) { focusRect.Inflate(-3, -3); if (this.GetButtonRendererData(e.Cell).ButtonState != PushButtonStates.Pressed) { ControlPaint.DrawFocusRectangle(e.Graphics, focusRect); } } else { focusRect.Inflate(-4, -4); ControlPaint.DrawFocusRectangle(e.Graphics, focusRect); } } } /// /// Draws the Image displayed on the button /// /// The Graphics to draw on /// The Image to draw /// A Rectangle that specifies the location /// of the Image /// Specifies whether the Image should be drawn /// in an enabled state protected void DrawImage(Graphics g, Image image, Rectangle imageRect, bool enabled) { if (enabled) { g.DrawImageUnscaled(image, imageRect); } else { ControlPaint.DrawImageDisabled(g, image, imageRect.X, imageRect.Y, this.BackColor); } } #endregion #endregion } }