NumberCellRenderer.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  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.Windows.Forms;
  34. using XPTable.Editors;
  35. using XPTable.Events;
  36. using XPTable.Models;
  37. using XPTable.Themes;
  38. namespace XPTable.Renderers
  39. {
  40. /// <summary>
  41. /// A base class for drawing Cells contents as numbers
  42. /// </summary>
  43. public class NumberCellRenderer : CellRenderer
  44. {
  45. #region Class Data
  46. /// <summary>
  47. /// The width of the ComboBox's dropdown button
  48. /// </summary>
  49. private int buttonWidth;
  50. /// <summary>
  51. /// Specifies whether the up and down buttons should be drawn
  52. /// </summary>
  53. private bool showUpDownButtons;
  54. /// <summary>
  55. /// The alignment of the up and down buttons in the Cell
  56. /// </summary>
  57. private LeftRightAlignment upDownAlignment;
  58. /// <summary>
  59. /// The maximum value for the Cell
  60. /// </summary>
  61. private decimal maximum;
  62. /// <summary>
  63. /// The minimum value for the Cell
  64. /// </summary>
  65. private decimal minimum;
  66. #endregion
  67. #region Constructor
  68. /// <summary>
  69. /// Initializes a new instance of the NumberCellRenderer class with
  70. /// default settings
  71. /// </summary>
  72. public NumberCellRenderer() : base()
  73. {
  74. this.StringFormat.Trimming = StringTrimming.None;
  75. this.Format = "G";
  76. this.buttonWidth = 15;
  77. this.showUpDownButtons = false;
  78. this.upDownAlignment = LeftRightAlignment.Right;
  79. this.maximum = (decimal) 100;
  80. this.minimum = (decimal) 0;
  81. }
  82. #endregion
  83. #region Methods
  84. /// <summary>
  85. /// Returns a Rectangle that specifies the size and location of the
  86. /// up and down buttons
  87. /// </summary>
  88. /// <returns>A Rectangle that specifies the size and location of the
  89. /// up and down buttons</returns>
  90. protected Rectangle CalcButtonBounds()
  91. {
  92. Rectangle buttonRect = this.ClientRectangle;
  93. buttonRect.Width = this.ButtonWidth;
  94. if (this.UpDownAlign == LeftRightAlignment.Right)
  95. {
  96. buttonRect.X = this.ClientRectangle.Right - buttonRect.Width;
  97. }
  98. if (buttonRect.Width > this.ClientRectangle.Width)
  99. {
  100. buttonRect = this.ClientRectangle;
  101. }
  102. return buttonRect;
  103. }
  104. /// <summary>
  105. /// Returns a Rectangle that specifies the size and location of the up button
  106. /// </summary>
  107. /// <returns>A Rectangle that specifies the size and location of the up button</returns>
  108. protected Rectangle GetUpButtonBounds()
  109. {
  110. Rectangle buttonRect = this.CalcButtonBounds();
  111. buttonRect.Height /= 2;
  112. return buttonRect;
  113. }
  114. /// <summary>
  115. /// Returns a Rectangle that specifies the size and location of the down button
  116. /// </summary>
  117. /// <returns>A Rectangle that specifies the size and location of the down button</returns>
  118. protected Rectangle GetDownButtonBounds()
  119. {
  120. Rectangle buttonRect = this.CalcButtonBounds();
  121. int height = buttonRect.Height / 2;
  122. buttonRect.Height -= height;
  123. buttonRect.Y += height;
  124. return buttonRect;
  125. }
  126. /// <summary>
  127. /// Gets the NumberRendererData specific data used by the Renderer from
  128. /// the specified Cell
  129. /// </summary>
  130. /// <param name="cell">The Cell to get the NumberRendererData data for</param>
  131. /// <returns>The NumberRendererData data for the specified Cell</returns>
  132. protected NumberRendererData GetNumberRendererData(Cell cell)
  133. {
  134. object rendererData = this.GetRendererData(cell);
  135. if (rendererData == null || !(rendererData is NumberRendererData))
  136. {
  137. rendererData = new NumberRendererData();
  138. this.SetRendererData(cell, rendererData);
  139. }
  140. return (NumberRendererData) rendererData;
  141. }
  142. /// <summary>
  143. /// Gets whether the specified Table is using a NumericCellEditor to edit the
  144. /// Cell at the specified CellPos
  145. /// </summary>
  146. /// <param name="table">The Table to check</param>
  147. /// <param name="cellPos">A CellPos that represents the Cell to check</param>
  148. /// <returns>true if the specified Table is using a NumericCellEditor to edit the
  149. /// Cell at the specified CellPos, false otherwise</returns>
  150. internal bool TableUsingNumericCellEditor(Table table, CellPos cellPos)
  151. {
  152. return (table.IsEditing && cellPos == table.EditingCell && table.EditingCellEditor is NumberCellEditor);
  153. }
  154. #endregion
  155. #region Properties
  156. /// <summary>
  157. /// Gets or sets the width of the dropdown button
  158. /// </summary>
  159. protected internal int ButtonWidth
  160. {
  161. get
  162. {
  163. return this.buttonWidth;
  164. }
  165. set
  166. {
  167. this.buttonWidth = value;
  168. }
  169. }
  170. /// <summary>
  171. /// Gets or sets whether the up and down buttons should be drawn
  172. /// </summary>
  173. protected bool ShowUpDownButtons
  174. {
  175. get
  176. {
  177. return this.showUpDownButtons;
  178. }
  179. set
  180. {
  181. this.showUpDownButtons = value;
  182. }
  183. }
  184. /// <summary>
  185. /// Gets or sets the alignment of the up and down buttons in the Cell
  186. /// </summary>
  187. protected LeftRightAlignment UpDownAlign
  188. {
  189. get
  190. {
  191. return this.upDownAlignment;
  192. }
  193. set
  194. {
  195. if (!Enum.IsDefined(typeof(LeftRightAlignment), value))
  196. {
  197. throw new InvalidEnumArgumentException("value", (int) value, typeof(LeftRightAlignment));
  198. }
  199. this.upDownAlignment = value;
  200. }
  201. }
  202. /// <summary>
  203. /// Gets or sets the maximum value for the Cell
  204. /// </summary>
  205. protected decimal Maximum
  206. {
  207. get
  208. {
  209. return this.maximum;
  210. }
  211. set
  212. {
  213. this.maximum = value;
  214. if (this.minimum > this.maximum)
  215. {
  216. this.minimum = this.maximum;
  217. }
  218. }
  219. }
  220. /// <summary>
  221. /// Gets or sets the minimum value for the Cell
  222. /// </summary>
  223. protected decimal Minimum
  224. {
  225. get
  226. {
  227. return this.minimum;
  228. }
  229. set
  230. {
  231. this.minimum = value;
  232. if (this.minimum > this.maximum)
  233. {
  234. this.maximum = value;
  235. }
  236. }
  237. }
  238. #endregion
  239. #region Events
  240. #region Mouse
  241. #region MouseLeave
  242. /// <summary>
  243. /// Raises the MouseLeave event
  244. /// </summary>
  245. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  246. public override void OnMouseLeave(CellMouseEventArgs e)
  247. {
  248. base.OnMouseLeave(e);
  249. if (this.ShowUpDownButtons || this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  250. {
  251. if (e.Table.IsCellEditable(e.CellPos))
  252. {
  253. // get the button renderer data
  254. NumberRendererData rendererData = this.GetNumberRendererData(e.Cell);
  255. if (rendererData.UpButtonState != UpDownStates.Normal)
  256. {
  257. rendererData.UpButtonState = UpDownStates.Normal;
  258. e.Table.Invalidate(e.CellRect);
  259. }
  260. else if (rendererData.DownButtonState != UpDownStates.Normal)
  261. {
  262. rendererData.DownButtonState = UpDownStates.Normal;
  263. e.Table.Invalidate(e.CellRect);
  264. }
  265. }
  266. }
  267. }
  268. #endregion
  269. #region MouseUp
  270. /// <summary>
  271. /// Raises the MouseUp event
  272. /// </summary>
  273. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  274. public override void OnMouseUp(CellMouseEventArgs e)
  275. {
  276. base.OnMouseUp(e);
  277. //
  278. if (this.ShowUpDownButtons || this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  279. {
  280. if (e.Table.IsCellEditable(e.CellPos))
  281. {
  282. // get the renderer data
  283. NumberRendererData rendererData = this.GetNumberRendererData(e.Cell);
  284. rendererData.ClickPoint = new Point(-1, -1);
  285. if (this.GetUpButtonBounds().Contains(e.X, e.Y))
  286. {
  287. rendererData.UpButtonState = UpDownStates.Hot;
  288. if (!e.Table.IsEditing)
  289. {
  290. e.Table.EditCell(e.CellPos);
  291. }
  292. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseUp(this, e);
  293. e.Table.Invalidate(e.CellRect);
  294. }
  295. else if (this.GetDownButtonBounds().Contains(e.X, e.Y))
  296. {
  297. rendererData.DownButtonState = UpDownStates.Hot;
  298. if (!e.Table.IsEditing)
  299. {
  300. e.Table.EditCell(e.CellPos);
  301. }
  302. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseUp(this, e);
  303. e.Table.Invalidate(e.CellRect);
  304. }
  305. }
  306. }
  307. }
  308. #endregion
  309. #region MouseDown
  310. /// <summary>
  311. /// Raises the MouseDown event
  312. /// </summary>
  313. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  314. public override void OnMouseDown(CellMouseEventArgs e)
  315. {
  316. base.OnMouseDown(e);
  317. //
  318. if (this.ShowUpDownButtons || this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  319. {
  320. if (e.Table.IsCellEditable(e.CellPos))
  321. {
  322. // get the button renderer data
  323. NumberRendererData rendererData = this.GetNumberRendererData(e.Cell);
  324. rendererData.ClickPoint = new Point(e.X, e.Y);
  325. if (this.CalcButtonBounds().Contains(e.X, e.Y))
  326. {
  327. if (!(e.Table.ColumnModel.GetCellEditor(e.CellPos.Column) is NumberCellEditor))
  328. {
  329. throw new InvalidOperationException("Cannot edit Cell as NumberCellRenderer requires a NumberColumn that uses a NumberCellEditor");
  330. }
  331. if (!e.Table.IsEditing)
  332. {
  333. e.Table.EditCell(e.CellPos);
  334. }
  335. if (this.GetUpButtonBounds().Contains(e.X, e.Y))
  336. {
  337. rendererData.UpButtonState = UpDownStates.Pressed;
  338. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseDown(this, e);
  339. e.Table.Invalidate(e.CellRect);
  340. }
  341. else if (this.GetDownButtonBounds().Contains(e.X, e.Y))
  342. {
  343. rendererData.DownButtonState = UpDownStates.Pressed;
  344. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseDown(this, e);
  345. e.Table.Invalidate(e.CellRect);
  346. }
  347. }
  348. }
  349. }
  350. }
  351. #endregion
  352. #region MouseMove
  353. /// <summary>
  354. /// Raises the MouseMove event
  355. /// </summary>
  356. /// <param name="e">A CellMouseEventArgs that contains the event data</param>
  357. public override void OnMouseMove(XPTable.Events.CellMouseEventArgs e)
  358. {
  359. base.OnMouseMove(e);
  360. if (this.ShowUpDownButtons || this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  361. {
  362. if (e.Table.IsCellEditable(e.CellPos))
  363. {
  364. // get the button renderer data
  365. NumberRendererData rendererData = this.GetNumberRendererData(e.Cell);
  366. if (this.GetUpButtonBounds().Contains(e.X, e.Y))
  367. {
  368. if (rendererData.UpButtonState == UpDownStates.Normal)
  369. {
  370. if (e.Button == MouseButtons.Left && e.Row == e.Table.LastMouseDownCell.Row && e.Column == e.Table.LastMouseDownCell.Column)
  371. {
  372. if (this.GetUpButtonBounds().Contains(rendererData.ClickPoint))
  373. {
  374. rendererData.UpButtonState = UpDownStates.Pressed;
  375. if (this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  376. {
  377. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseDown(this, e);
  378. }
  379. }
  380. else if (this.GetDownButtonBounds().Contains(rendererData.ClickPoint))
  381. {
  382. rendererData.DownButtonState = UpDownStates.Normal;
  383. if (this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  384. {
  385. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseUp(this, e);
  386. }
  387. }
  388. }
  389. else
  390. {
  391. rendererData.UpButtonState = UpDownStates.Hot;
  392. if (rendererData.DownButtonState == UpDownStates.Hot)
  393. {
  394. rendererData.DownButtonState = UpDownStates.Normal;
  395. }
  396. }
  397. e.Table.Invalidate(e.CellRect);
  398. }
  399. }
  400. else if (this.GetDownButtonBounds().Contains(e.X, e.Y))
  401. {
  402. if (rendererData.DownButtonState == UpDownStates.Normal)
  403. {
  404. if (e.Button == MouseButtons.Left && e.Row == e.Table.LastMouseDownCell.Row && e.Column == e.Table.LastMouseDownCell.Column)
  405. {
  406. if (this.GetDownButtonBounds().Contains(rendererData.ClickPoint))
  407. {
  408. rendererData.DownButtonState = UpDownStates.Pressed;
  409. if (this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  410. {
  411. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseDown(this, e);
  412. }
  413. }
  414. else if (this.GetUpButtonBounds().Contains(rendererData.ClickPoint))
  415. {
  416. rendererData.UpButtonState = UpDownStates.Normal;
  417. if (this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  418. {
  419. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseUp(this, e);
  420. }
  421. }
  422. }
  423. else
  424. {
  425. rendererData.DownButtonState = UpDownStates.Hot;
  426. if (rendererData.UpButtonState == UpDownStates.Hot)
  427. {
  428. rendererData.UpButtonState = UpDownStates.Normal;
  429. }
  430. }
  431. e.Table.Invalidate(e.CellRect);
  432. }
  433. }
  434. else
  435. {
  436. if (rendererData.UpButtonState != UpDownStates.Normal || rendererData.DownButtonState != UpDownStates.Normal)
  437. {
  438. rendererData.UpButtonState = UpDownStates.Normal;
  439. rendererData.DownButtonState = UpDownStates.Normal;
  440. if (this.TableUsingNumericCellEditor(e.Table, e.CellPos))
  441. {
  442. ((IEditorUsesRendererButtons) e.Table.EditingCellEditor).OnEditorButtonMouseUp(this, e);
  443. }
  444. e.Table.Invalidate(e.CellRect);
  445. }
  446. }
  447. }
  448. }
  449. }
  450. #endregion
  451. #endregion
  452. #region Paint
  453. /// <summary>
  454. /// Raises the PaintCell event
  455. /// </summary>
  456. /// <param name="e">A PaintCellEventArgs that contains the event data</param>
  457. public override void OnPaintCell(PaintCellEventArgs e)
  458. {
  459. if (e.Table.ColumnModel.Columns[e.Column] is NumberColumn)
  460. {
  461. NumberColumn column = (NumberColumn) e.Table.ColumnModel.Columns[e.Column];
  462. this.ShowUpDownButtons = column.ShowUpDownButtons;
  463. this.UpDownAlign = column.UpDownAlign;
  464. this.Maximum = column.Maximum;
  465. this.Minimum = column.Minimum;
  466. // if the table is editing this cell and the editor is a
  467. // NumberCellEditor then we should display the updown buttons
  468. if (e.Table.IsEditing && e.Table.EditingCell == e.CellPos && e.Table.EditingCellEditor is NumberCellEditor)
  469. {
  470. this.ShowUpDownButtons = true;
  471. }
  472. }
  473. else
  474. {
  475. this.ShowUpDownButtons = false;
  476. this.UpDownAlign = LeftRightAlignment.Right;
  477. this.Maximum = 100;
  478. this.Minimum = 0;
  479. }
  480. base.OnPaintCell(e);
  481. }
  482. /// <summary>
  483. /// Raises the PaintBackground event
  484. /// </summary>
  485. /// <param name="e">A PaintCellEventArgs that contains the event data</param>
  486. protected override void OnPaintBackground(PaintCellEventArgs e)
  487. {
  488. base.OnPaintBackground(e);
  489. // don't bother going any further if the Cell is null
  490. if (e.Cell == null)
  491. {
  492. return;
  493. }
  494. if (this.ShowUpDownButtons)
  495. {
  496. UpDownStates upButtonState = this.GetNumberRendererData(e.Cell).UpButtonState;
  497. UpDownStates downButtonState = this.GetNumberRendererData(e.Cell).DownButtonState;
  498. if (!e.Enabled)
  499. {
  500. upButtonState = UpDownStates.Disabled;
  501. downButtonState = UpDownStates.Disabled;
  502. }
  503. ThemeManager.DrawUpDownButtons(e.Graphics, this.GetUpButtonBounds(), upButtonState, this.GetDownButtonBounds(), downButtonState);
  504. }
  505. }
  506. /// <summary>
  507. /// Raises the Paint event
  508. /// </summary>
  509. /// <param name="e">A PaintCellEventArgs that contains the event data</param>
  510. protected override void OnPaint(PaintCellEventArgs e)
  511. {
  512. base.OnPaint(e);
  513. // don't bother if the Cell is null
  514. if (e.Cell == null)
  515. {
  516. return;
  517. }
  518. // get the Cells value
  519. decimal decimalVal = decimal.MinValue;
  520. if (e.Cell.Data != null && (e.Cell.Data is int || e.Cell.Data is double || e.Cell.Data is float || e.Cell.Data is decimal))
  521. {
  522. decimalVal = Convert.ToDecimal(e.Cell.Data);
  523. }
  524. // draw the value
  525. if (decimalVal != decimal.MinValue)
  526. {
  527. Rectangle textRect = this.ClientRectangle;
  528. if (this.ShowUpDownButtons)
  529. {
  530. textRect.Width -= this.CalcButtonBounds().Width - 1;
  531. if (this.UpDownAlign == LeftRightAlignment.Left)
  532. {
  533. textRect.X = this.ClientRectangle.Right - textRect.Width;
  534. }
  535. }
  536. if (e.Enabled)
  537. {
  538. e.Graphics.DrawString(decimalVal.ToString(this.Format), this.Font, this.ForeBrush, textRect, this.StringFormat);
  539. }
  540. else
  541. {
  542. e.Graphics.DrawString(decimalVal.ToString(this.Format), this.Font, this.GrayTextBrush, textRect, this.StringFormat);
  543. }
  544. }
  545. if (e.Focused && e.Enabled)
  546. {
  547. Rectangle focusRect = this.ClientRectangle;
  548. if (this.ShowUpDownButtons)
  549. {
  550. focusRect.Width -= this.CalcButtonBounds().Width;
  551. if (this.UpDownAlign == LeftRightAlignment.Left)
  552. {
  553. focusRect.X = this.ClientRectangle.Right - focusRect.Width;
  554. }
  555. }
  556. ControlPaint.DrawFocusRectangle(e.Graphics, focusRect);
  557. }
  558. }
  559. #endregion
  560. #endregion
  561. }
  562. }