ButtonCellRenderer.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. //#########################################################################################
  2. //★★★★★★★ http://www.cnpopsoft.com [华普软件] ★★★★★★★
  3. //★★★★★★★ 华普软件 - VB & C#.NET 专业论文与源码荟萃! ★★★★★★★
  4. //#########################################################################################
  5. /*
  6. * Copyright ?2005, Mathew Hall
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without modification,
  10. * are permitted provided that the following conditions are met:
  11. *
  12. * - Redistributions of source code must retain the above copyright notice,
  13. * this list of conditions and the following disclaimer.
  14. *
  15. * - Redistributions in binary form must reproduce the above copyright notice,
  16. * this list of conditions and the following disclaimer in the documentation
  17. * and/or other materials provided with the distribution.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  21. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  23. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  24. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  25. * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  26. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  28. * OF SUCH DAMAGE.
  29. */
  30. using System;
  31. using System.ComponentModel;
  32. using System.Drawing;
  33. using System.Globalization;
  34. using System.Windows.Forms;
  35. using XPTable.Events;
  36. using XPTable.Models;
  37. using XPTable.Themes;
  38. namespace XPTable.Renderers
  39. {
  40. /// <summary>
  41. /// A CellRenderer that draws Cell contents as Buttons
  42. /// </summary>
  43. public class ButtonCellRenderer : CellRenderer
  44. {
  45. #region Class Data
  46. /// <summary>
  47. /// Specifies the alignment of the Image displayed on the button
  48. /// </summary>
  49. private ContentAlignment imageAlignment;
  50. #endregion
  51. #region Constructor
  52. /// <summary>
  53. /// Initializes a new instance of the ButtonCellRenderer class with
  54. /// default settings
  55. /// </summary>
  56. public ButtonCellRenderer() : base()
  57. {
  58. this.imageAlignment = ContentAlignment.MiddleCenter;
  59. }
  60. #endregion
  61. #region Methods
  62. /// <summary>
  63. /// Gets the ButtonCellRenderer specific data used by the Renderer from
  64. /// the specified Cell
  65. /// </summary>
  66. /// <param name="cell">The Cell to get the ButtonCellRenderer data for</param>
  67. /// <returns>The ButtonCellRenderer data for the specified Cell</returns>
  68. protected ButtonRendererData GetButtonRendererData(Cell cell)
  69. {
  70. object rendererData = this.GetRendererData(cell);
  71. if (rendererData == null || !(rendererData is ButtonRendererData))
  72. {
  73. rendererData = new ButtonRendererData();
  74. this.SetRendererData(cell, rendererData);
  75. }
  76. return (ButtonRendererData) rendererData;
  77. }
  78. /// <summary>
  79. /// Returns a Rectangle that specifies the size and location of the button
  80. /// </summary>
  81. /// <returns>A Rectangle that specifies the size and location of the button</returns>
  82. protected virtual Rectangle CalcButtonBounds()
  83. {
  84. return this.ClientRectangle;
  85. }
  86. /// <summary>
  87. /// Returns a Rectangle that specifies the size and location of the buttons Image
  88. /// </summary>
  89. /// <param name="image">The buttons image</param>
  90. /// <param name="imageAlignment">The alignment of the image</param>
  91. /// <returns>A Rectangle that specifies the size and location of the buttons Image</returns>
  92. protected Rectangle CalcImageRect(Image image, ContentAlignment imageAlignment)
  93. {
  94. Rectangle imageRect = new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, image.Width, image.Height);
  95. switch (imageAlignment)
  96. {
  97. case ContentAlignment.TopCenter:
  98. case ContentAlignment.MiddleCenter:
  99. case ContentAlignment.BottomCenter:
  100. {
  101. imageRect.X += (this.ClientRectangle.Width - image.Width) / 2;
  102. break;
  103. }
  104. case ContentAlignment.TopRight:
  105. case ContentAlignment.MiddleRight:
  106. case ContentAlignment.BottomRight:
  107. {
  108. imageRect.X = this.ClientRectangle.Right - image.Width;
  109. break;
  110. }
  111. }
  112. switch (imageAlignment)
  113. {
  114. case ContentAlignment.TopLeft:
  115. case ContentAlignment.TopCenter:
  116. case ContentAlignment.TopRight:
  117. {
  118. imageRect.Y += 2;
  119. break;
  120. }
  121. case ContentAlignment.MiddleLeft:
  122. case ContentAlignment.MiddleCenter:
  123. case ContentAlignment.MiddleRight:
  124. {
  125. imageRect.Y += (this.ClientRectangle.Height - image.Height) / 2;
  126. break;
  127. }
  128. case ContentAlignment.BottomLeft:
  129. case ContentAlignment.BottomCenter:
  130. case ContentAlignment.BottomRight:
  131. {
  132. imageRect.Y = this.ClientRectangle.Bottom - image.Height - 2;
  133. break;
  134. }
  135. }
  136. return imageRect;
  137. }
  138. #endregion
  139. #region Properties
  140. /// <summary>
  141. /// Gets or sets the alignment of the Image displayed on the buttons
  142. /// </summary>
  143. public ContentAlignment ImageAlignment
  144. {
  145. get
  146. {
  147. return this.imageAlignment;
  148. }
  149. set
  150. {
  151. this.imageAlignment = value;
  152. }
  153. }
  154. #endregion
  155. #region Events
  156. #region Focus
  157. /// <summary>
  158. /// Raises the GotFocus event
  159. /// </summary>
  160. /// <param name="e">A CellFocusEventArgs that contains the event data</param>
  161. public override void OnGotFocus(CellFocusEventArgs e)
  162. {
  163. base.OnGotFocus(e);
  164. // get the table to redraw the cell
  165. e.Table.Invalidate(e.CellRect);
  166. }
  167. /// <summary>
  168. /// Raises the LostFocus event
  169. /// </summary>
  170. /// <param name="e">A CellFocusEventArgs that contains the event data</param>
  171. public override void OnLostFocus(CellFocusEventArgs e)
  172. {
  173. base.OnLostFocus(e);
  174. // get the table to redraw the cell
  175. e.Table.Invalidate(e.CellRect);
  176. }
  177. #endregion
  178. #region Keys
  179. /// <summary>
  180. /// Raises the KeyDown event
  181. /// </summary>
  182. /// <param name="e">A CellKeyEventArgs that contains the event data</param>
  183. public override void OnKeyDown(CellKeyEventArgs e)
  184. {
  185. base.OnKeyDown(e);
  186. // get the button renderer data
  187. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  188. //
  189. if (e.KeyData == Keys.Enter || e.KeyData == Keys.Space)
  190. {
  191. rendererData.ButtonState = PushButtonStates.Pressed;
  192. e.Table.Invalidate(e.CellRect);
  193. }
  194. }
  195. /// <summary>
  196. /// Raises the KeyUp event
  197. /// </summary>
  198. /// <param name="e">A CellKeyEventArgs that contains the event data</param>
  199. public override void OnKeyUp(CellKeyEventArgs e)
  200. {
  201. base.OnKeyUp(e);
  202. // get the button renderer data
  203. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  204. //
  205. if (e.KeyData == Keys.Enter || e.KeyData == Keys.Space)
  206. {
  207. rendererData.ButtonState = PushButtonStates.Normal;
  208. e.Table.Invalidate(e.CellRect);
  209. e.Table.OnCellButtonClicked(new CellButtonEventArgs(e.Cell, e.Column, e.Row));
  210. }
  211. }
  212. #endregion
  213. #region Mouse
  214. #region MouseEnter
  215. /// <summary>
  216. /// Raises the MouseEnter event
  217. /// </summary>
  218. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  219. public override void OnMouseEnter(CellMouseEventArgs e)
  220. {
  221. base.OnMouseEnter(e);
  222. // get the button renderer data
  223. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  224. // if the mouse is inside the button, make sure it is "hot"
  225. if (this.CalcButtonBounds().Contains(e.X, e.Y))
  226. {
  227. if (rendererData.ButtonState != PushButtonStates.Hot)
  228. {
  229. rendererData.ButtonState = PushButtonStates.Hot;
  230. e.Table.Invalidate(e.CellRect);
  231. }
  232. }
  233. // the mouse isn't inside the button, so it is in its normal state
  234. else
  235. {
  236. if (rendererData.ButtonState != PushButtonStates.Normal)
  237. {
  238. rendererData.ButtonState = PushButtonStates.Normal;
  239. e.Table.Invalidate(e.CellRect);
  240. }
  241. }
  242. }
  243. #endregion
  244. #region MouseLeave
  245. /// <summary>
  246. /// Raises the MouseLeave event
  247. /// </summary>
  248. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  249. public override void OnMouseLeave(CellMouseEventArgs e)
  250. {
  251. base.OnMouseLeave(e);
  252. // get the button renderer data
  253. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  254. // make sure the button is in its normal state
  255. if (rendererData.ButtonState != PushButtonStates.Normal)
  256. {
  257. rendererData.ButtonState = PushButtonStates.Normal;
  258. e.Table.Invalidate(e.CellRect);
  259. }
  260. }
  261. #endregion
  262. #region MouseUp
  263. /// <summary>
  264. /// Raises the MouseUp event
  265. /// </summary>
  266. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  267. public override void OnMouseUp(CellMouseEventArgs e)
  268. {
  269. base.OnMouseUp(e);
  270. // get the button renderer data
  271. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  272. // check for the left mouse button
  273. if (e.Button == MouseButtons.Left)
  274. {
  275. Rectangle buttonRect = this.CalcButtonBounds();
  276. // if the mouse pointer is over the button, make sure
  277. // the button is "hot"
  278. if (buttonRect.Contains(e.X, e.Y))
  279. {
  280. rendererData.ButtonState = PushButtonStates.Hot;
  281. e.Table.Invalidate(e.CellRect);
  282. // check if the click started inside the button. if
  283. // it did, Raise the tables CellButtonClicked event
  284. if (buttonRect.Contains(rendererData.ClickPoint))
  285. {
  286. e.Table.OnCellButtonClicked(new CellButtonEventArgs(e.Cell, e.Column, e.Row));
  287. }
  288. }
  289. else
  290. {
  291. // the mouse was released somewhere outside of the button,
  292. // so make set the button back to its normal state
  293. if (rendererData.ButtonState != PushButtonStates.Normal)
  294. {
  295. rendererData.ButtonState = PushButtonStates.Normal;
  296. e.Table.Invalidate(e.CellRect);
  297. }
  298. }
  299. }
  300. // reset the click point
  301. rendererData.ClickPoint = Point.Empty;
  302. }
  303. #endregion
  304. #region MouseDown
  305. /// <summary>
  306. /// Raises the MouseDown event
  307. /// </summary>
  308. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  309. public override void OnMouseDown(CellMouseEventArgs e)
  310. {
  311. base.OnMouseDown(e);
  312. // get the button renderer data
  313. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  314. // check if the left mouse button is pressed
  315. if (e.Button == MouseButtons.Left)
  316. {
  317. // record where the click started
  318. rendererData.ClickPoint = new Point(e.X, e.Y);
  319. // if the click was inside the button, set the button state to pressed
  320. if (this.CalcButtonBounds().Contains(rendererData.ClickPoint))
  321. {
  322. rendererData.ButtonState = PushButtonStates.Pressed;
  323. e.Table.Invalidate(e.CellRect);
  324. }
  325. }
  326. }
  327. #endregion
  328. #region MouseMove
  329. /// <summary>
  330. /// Raises the MouseMove event
  331. /// </summary>
  332. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  333. public override void OnMouseMove(CellMouseEventArgs e)
  334. {
  335. base.OnMouseMove(e);
  336. // get the button renderer data
  337. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  338. Rectangle buttonRect = this.CalcButtonBounds();
  339. // check if the left mouse button is pressed
  340. if (e.Button == MouseButtons.Left)
  341. {
  342. // check if the mouse press originated in the button area
  343. if (buttonRect.Contains(rendererData.ClickPoint))
  344. {
  345. // check if the mouse is currently in the button
  346. if (buttonRect.Contains(e.X, e.Y))
  347. {
  348. // make sure the button is pressed
  349. if (rendererData.ButtonState != PushButtonStates.Pressed)
  350. {
  351. rendererData.ButtonState = PushButtonStates.Pressed;
  352. e.Table.Invalidate(e.CellRect);
  353. }
  354. }
  355. else
  356. {
  357. // the mouse isn't inside the button so make sure it is "hot"
  358. if (rendererData.ButtonState != PushButtonStates.Hot)
  359. {
  360. rendererData.ButtonState = PushButtonStates.Hot;
  361. e.Table.Invalidate(e.CellRect);
  362. }
  363. }
  364. }
  365. }
  366. else
  367. {
  368. // check if the mouse is currently in the button
  369. if (buttonRect.Contains(e.X, e.Y))
  370. {
  371. // the mouse is inside the button so make sure it is "hot"
  372. if (rendererData.ButtonState != PushButtonStates.Hot)
  373. {
  374. rendererData.ButtonState = PushButtonStates.Hot;
  375. e.Table.Invalidate(e.CellRect);
  376. }
  377. }
  378. else
  379. {
  380. // not inside the button so make sure it is in its normal state
  381. if (rendererData.ButtonState != PushButtonStates.Normal)
  382. {
  383. rendererData.ButtonState = PushButtonStates.Normal;
  384. e.Table.Invalidate(e.CellRect);
  385. }
  386. }
  387. }
  388. }
  389. #endregion
  390. #endregion
  391. #region Paint
  392. /// <summary>
  393. /// Raises the PaintCell event
  394. /// </summary>
  395. /// <param name="e">A PaintCellEventArgs that contains the event data</param>
  396. public override void OnPaintCell(PaintCellEventArgs e)
  397. {
  398. if (e.Table.ColumnModel.Columns[e.Column] is ButtonColumn)
  399. {
  400. this.ImageAlignment = ((ButtonColumn) e.Table.ColumnModel.Columns[e.Column]).ImageAlignment;
  401. }
  402. else
  403. {
  404. this.ImageAlignment = ContentAlignment.MiddleLeft;
  405. }
  406. base.OnPaintCell(e);
  407. }
  408. /// <summary>
  409. /// Raises the PaintBackground event
  410. /// </summary>
  411. /// <param name="e">A PaintCellEventArgs that contains the event data</param>
  412. protected override void OnPaintBackground(PaintCellEventArgs e)
  413. {
  414. base.OnPaintBackground(e);
  415. // don't bother going any further if the Cell is null
  416. if (e.Cell == null)
  417. {
  418. return;
  419. }
  420. // get the button state
  421. ButtonRendererData rendererData = this.GetButtonRendererData(e.Cell);
  422. PushButtonStates state = rendererData.ButtonState;
  423. // if the cell has focus and is in its normal state,
  424. // make the button look like a default button
  425. if (state == PushButtonStates.Normal && e.Focused)
  426. {
  427. state = PushButtonStates.Default;
  428. }
  429. // if the table is not enabled, make sure the button is disabled
  430. if (!e.Enabled)
  431. {
  432. state = PushButtonStates.Disabled;
  433. }
  434. // draw the button
  435. ThemeManager.DrawButton(e.Graphics, this.CalcButtonBounds(), state);
  436. }
  437. /// <summary>
  438. /// Raises the Paint event
  439. /// </summary>
  440. /// <param name="e">A PaintCellEventArgs that contains the event data</param>
  441. protected override void OnPaint(PaintCellEventArgs e)
  442. {
  443. base.OnPaint(e);
  444. // don't bother going any further if the Cell is null
  445. if (e.Cell == null)
  446. {
  447. return;
  448. }
  449. Rectangle textRect = this.CalcButtonBounds();
  450. textRect.Inflate(-4, -2);
  451. if (e.Cell.Image != null)
  452. {
  453. Rectangle imageRect = this.CalcImageRect(e.Cell.Image, this.ImageAlignment);
  454. if (this.GetButtonRendererData(e.Cell).ButtonState == PushButtonStates.Pressed && !ThemeManager.VisualStylesEnabled)
  455. {
  456. imageRect.X += 1;
  457. imageRect.Y += 1;
  458. }
  459. this.DrawImage(e.Graphics, e.Cell.Image, imageRect, e.Enabled);
  460. }
  461. // draw the text
  462. if (e.Cell.Text != null && e.Cell.Text.Length != 0)
  463. {
  464. if (e.Enabled)
  465. {
  466. if (!ThemeManager.VisualStylesEnabled && this.GetButtonRendererData(e.Cell).ButtonState == PushButtonStates.Pressed)
  467. {
  468. textRect.X += 1;
  469. textRect.Y += 1;
  470. }
  471. // if the cell or the row it is in is selected
  472. // our forecolor will be the selection forecolor.
  473. // we'll ignore this and reset our forecolor to
  474. // that of the cell being rendered
  475. if (e.Selected)
  476. {
  477. this.ForeColor = e.Cell.ForeColor;
  478. }
  479. e.Graphics.DrawString(e.Cell.Text, this.Font, this.ForeBrush, textRect, this.StringFormat);
  480. }
  481. else
  482. {
  483. e.Graphics.DrawString(e.Cell.Text, this.Font, this.GrayTextBrush, textRect, this.StringFormat);
  484. }
  485. }
  486. // draw focus
  487. if (e.Focused && e.Enabled)
  488. {
  489. Rectangle focusRect = this.CalcButtonBounds();
  490. if (ThemeManager.VisualStylesEnabled)
  491. {
  492. focusRect.Inflate(-3, -3);
  493. if (this.GetButtonRendererData(e.Cell).ButtonState != PushButtonStates.Pressed)
  494. {
  495. ControlPaint.DrawFocusRectangle(e.Graphics, focusRect);
  496. }
  497. }
  498. else
  499. {
  500. focusRect.Inflate(-4, -4);
  501. ControlPaint.DrawFocusRectangle(e.Graphics, focusRect);
  502. }
  503. }
  504. }
  505. /// <summary>
  506. /// Draws the Image displayed on the button
  507. /// </summary>
  508. /// <param name="g">The Graphics to draw on</param>
  509. /// <param name="image">The Image to draw</param>
  510. /// <param name="imageRect">A Rectangle that specifies the location
  511. /// of the Image</param>
  512. /// <param name="enabled">Specifies whether the Image should be drawn
  513. /// in an enabled state</param>
  514. protected void DrawImage(Graphics g, Image image, Rectangle imageRect, bool enabled)
  515. {
  516. if (enabled)
  517. {
  518. g.DrawImageUnscaled(image, imageRect);
  519. }
  520. else
  521. {
  522. ControlPaint.DrawImageDisabled(g, image, imageRect.X, imageRect.Y, this.BackColor);
  523. }
  524. }
  525. #endregion
  526. #endregion
  527. }
  528. }