UpDownBase.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. // Permission is hereby granted, free of charge, to any person obtaining
  2. // a copy of this software and associated documentation files (the
  3. // "Software"), to deal in the Software without restriction, including
  4. // without limitation the rights to use, copy, modify, merge, publish,
  5. // distribute, sublicense, and/or sell copies of the Software, and to
  6. // permit persons to whom the Software is furnished to do so, subject to
  7. // the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be
  10. // included in all copies or substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  13. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  15. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  16. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  17. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  18. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. //
  20. // Copyright (c) 2005 Novell, Inc.
  21. //
  22. // Authors:
  23. // Jonathan Gilbert <[email protected]>
  24. //
  25. // Integration into MWF:
  26. // Peter Bartok <[email protected]>
  27. //
  28. // COMPLETE
  29. using System;
  30. using System.Collections;
  31. using System.ComponentModel;
  32. using System.Drawing;
  33. using System.Runtime.InteropServices;
  34. using System.Windows.Forms;
  35. namespace System.Windows.Forms
  36. {
  37. [Designer("System.Windows.Forms.Design.UpDownBaseDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
  38. public abstract class UpDownBase : System.Windows.Forms.ContainerControl {
  39. #region UpDownSpinner Sub-class
  40. internal sealed class UpDownSpinner : Control {
  41. #region Local Variables
  42. private const int InitialRepeatDelay = 50;
  43. private UpDownBase owner;
  44. private Timer tmrRepeat;
  45. private Rectangle top_button_rect;
  46. private Rectangle bottom_button_rect;
  47. private int mouse_pressed;
  48. private int mouse_x;
  49. private int mouse_y;
  50. private int repeat_delay;
  51. private int repeat_counter;
  52. #endregion // Local Variables
  53. #region Constructors
  54. public UpDownSpinner(UpDownBase owner) {
  55. this.owner = owner;
  56. mouse_pressed = 0;
  57. this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
  58. this.SetStyle(ControlStyles.DoubleBuffer, true);
  59. this.SetStyle(ControlStyles.Opaque, true);
  60. this.SetStyle(ControlStyles.ResizeRedraw, true);
  61. this.SetStyle(ControlStyles.UserPaint, true);
  62. this.SetStyle(ControlStyles.Selectable, false);
  63. tmrRepeat = new Timer();
  64. tmrRepeat.Enabled = false;
  65. tmrRepeat.Interval = 10;
  66. tmrRepeat.Tick += new EventHandler(tmrRepeat_Tick);
  67. compute_rects();
  68. }
  69. #endregion // Constructors
  70. #region Private & Internal Methods
  71. private void compute_rects() {
  72. int top_button_height;
  73. int bottom_button_height;
  74. top_button_height = ClientSize.Height / 2;
  75. bottom_button_height = ClientSize.Height - top_button_height;
  76. top_button_rect = new Rectangle(0, 0, ClientSize.Width, top_button_height);
  77. bottom_button_rect = new Rectangle(0, top_button_height, ClientSize.Width, bottom_button_height);
  78. }
  79. private void redraw(Graphics graphics) {
  80. ButtonState top_button_state;
  81. ButtonState bottom_button_state;
  82. top_button_state = bottom_button_state = ButtonState.Normal;
  83. if (mouse_pressed != 0) {
  84. if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y)) {
  85. top_button_state = ButtonState.Pushed;
  86. }
  87. if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y)) {
  88. bottom_button_state = ButtonState.Pushed;
  89. }
  90. }
  91. ControlPaint.DrawScrollButton(graphics, top_button_rect, ScrollButton.Up, top_button_state);
  92. ControlPaint.DrawScrollButton(graphics, bottom_button_rect, ScrollButton.Down, bottom_button_state);
  93. }
  94. private void tmrRepeat_Tick(object sender, EventArgs e) {
  95. if (repeat_delay > 1) {
  96. repeat_counter++;
  97. if (repeat_counter < repeat_delay) {
  98. return;
  99. }
  100. repeat_counter = 0;
  101. repeat_delay = (repeat_delay * 3 / 4);
  102. }
  103. if (mouse_pressed == 0) {
  104. tmrRepeat.Enabled = false;
  105. }
  106. if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y)) {
  107. owner.UpButton();
  108. }
  109. if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y)) {
  110. owner.DownButton();
  111. }
  112. }
  113. #endregion // Private & Internal Methods
  114. #region Protected Instance Methods
  115. protected override void OnMouseDown(MouseEventArgs e) {
  116. this.Select(owner.txtView);
  117. if (e.Button != MouseButtons.Left) {
  118. return;
  119. }
  120. if (top_button_rect.Contains(e.X, e.Y)) {
  121. mouse_pressed = 1;
  122. owner.UpButton();
  123. } else if (bottom_button_rect.Contains(e.X, e.Y)) {
  124. mouse_pressed = 2;
  125. owner.DownButton();
  126. }
  127. mouse_x = e.X;
  128. mouse_y = e.Y;
  129. Capture = true;
  130. tmrRepeat.Enabled = true;
  131. repeat_counter = 0;
  132. repeat_delay = InitialRepeatDelay;
  133. using (Graphics g = CreateGraphics()) {
  134. redraw(g);
  135. }
  136. }
  137. protected override void OnMouseMove(MouseEventArgs e) {
  138. ButtonState before, after;
  139. before = ButtonState.Normal;
  140. if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y))
  141. before = ButtonState.Pushed;
  142. if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y))
  143. before = ButtonState.Pushed;
  144. mouse_x = e.X;
  145. mouse_y = e.Y;
  146. after = ButtonState.Normal;
  147. if ((mouse_pressed == 1) && top_button_rect.Contains(mouse_x, mouse_y))
  148. after = ButtonState.Pushed;
  149. if ((mouse_pressed == 2) && bottom_button_rect.Contains(mouse_x, mouse_y))
  150. after = ButtonState.Pushed;
  151. if (before != after) {
  152. if (after == ButtonState.Pushed) {
  153. tmrRepeat.Enabled = true;
  154. repeat_counter = 0;
  155. repeat_delay = InitialRepeatDelay;
  156. // fire off one right now too for good luck
  157. if (mouse_pressed == 1)
  158. owner.UpButton();
  159. if (mouse_pressed == 2)
  160. owner.DownButton();
  161. }
  162. else
  163. tmrRepeat.Enabled = false;
  164. using (Graphics g = CreateGraphics()) {
  165. redraw(g);
  166. }
  167. }
  168. }
  169. protected override void OnMouseUp(MouseEventArgs e) {
  170. mouse_pressed = 0;
  171. Capture = false;
  172. using (Graphics g = CreateGraphics()) {
  173. redraw(g);
  174. }
  175. }
  176. protected override void OnMouseWheel(MouseEventArgs e) {
  177. if (e.Delta > 0)
  178. owner.UpButton();
  179. else if (e.Delta < 0)
  180. owner.DownButton();
  181. }
  182. protected override void OnPaint(PaintEventArgs e) {
  183. redraw(e.Graphics);
  184. }
  185. protected override void OnResize(EventArgs e) {
  186. base.OnResize(e);
  187. compute_rects();
  188. }
  189. #endregion // Protected Instance Methods
  190. }
  191. #endregion // UpDownSpinner Sub-class
  192. #region Local Variables
  193. internal TextBox txtView;
  194. private UpDownSpinner spnSpinner;
  195. private bool _InterceptArrowKeys = true;
  196. private LeftRightAlignment _UpDownAlign;
  197. private bool changing_text;
  198. private bool user_edit;
  199. #endregion // Local Variables
  200. #region Public Constructors
  201. public UpDownBase() {
  202. _UpDownAlign = LeftRightAlignment.Right;
  203. border_style = BorderStyle.Fixed3D;
  204. spnSpinner = new UpDownSpinner(this);
  205. txtView = new TextBox();
  206. txtView.ModifiedChanged += new EventHandler(OnChanged);
  207. txtView.AcceptsReturn = true;
  208. txtView.AutoSize = false;
  209. txtView.BorderStyle = BorderStyle.None;
  210. txtView.Location = new System.Drawing.Point(17, 17);
  211. txtView.TabIndex = 0;
  212. SuspendLayout ();
  213. Controls.AddImplicit (txtView);
  214. Controls.AddImplicit (spnSpinner);
  215. ResumeLayout ();
  216. this.ActiveControl = txtView;
  217. Height = PreferredHeight;
  218. base.BackColor = txtView.BackColor;
  219. txtView.MouseWheel += new MouseEventHandler(txtView_MouseWheel);
  220. txtView.KeyDown += new KeyEventHandler(OnTextBoxKeyDown);
  221. txtView.KeyPress += new KeyPressEventHandler(OnTextBoxKeyPress);
  222. txtView.LostFocus += new EventHandler(OnTextBoxLostFocus);
  223. txtView.Resize += new EventHandler(OnTextBoxResize);
  224. txtView.TextChanged += new EventHandler(OnTextBoxTextChanged);
  225. txtView.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
  226. this.Paint +=new PaintEventHandler(UpDownBase_Paint);
  227. SetStyle(ControlStyles.FixedHeight, true);
  228. UpdateEditText();
  229. }
  230. #endregion
  231. #region Private Methods
  232. void reseat_controls() {
  233. int text_displacement = 0;
  234. int spinner_width = 16;
  235. //int spinner_width = ClientSize.Height;
  236. if (_UpDownAlign == LeftRightAlignment.Left) {
  237. spnSpinner.Bounds = new Rectangle(0, 0, spinner_width, ClientSize.Height);
  238. text_displacement = spnSpinner.Width;
  239. spnSpinner.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
  240. } else {
  241. spnSpinner.Bounds = new Rectangle(ClientSize.Width - spinner_width, 0, spinner_width, ClientSize.Height);
  242. spnSpinner.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right;
  243. }
  244. txtView.Bounds = new Rectangle(text_displacement, 0, ClientSize.Width - spinner_width, Height);
  245. }
  246. private void txtView_MouseWheel(object sender, MouseEventArgs e) {
  247. if (e.Delta > 0) {
  248. UpButton();
  249. } else if (e.Delta < 0) {
  250. DownButton();
  251. }
  252. }
  253. private void UpDownBase_Paint(object sender, PaintEventArgs e) {
  254. e.Graphics.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(BackColor), ClientRectangle);
  255. }
  256. #endregion // Private Methods
  257. #region Public Instance Properties
  258. [Browsable(false)]
  259. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  260. [EditorBrowsable(EditorBrowsableState.Never)]
  261. public override bool AutoScroll {
  262. get {
  263. return base.AutoScroll;
  264. }
  265. set {
  266. base.AutoScroll = value;
  267. }
  268. }
  269. [Browsable(false)]
  270. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  271. [EditorBrowsable(EditorBrowsableState.Never)]
  272. public Size AutoScrollMargin {
  273. get {
  274. return base.AutoScrollMargin;
  275. }
  276. set {
  277. base.AutoScrollMargin = value;
  278. }
  279. }
  280. [Browsable(false)]
  281. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  282. [EditorBrowsable(EditorBrowsableState.Never)]
  283. public Size AutoScrollMinSize {
  284. get {
  285. return base.AutoScrollMinSize;
  286. }
  287. set {
  288. base.AutoScrollMinSize = value;
  289. }
  290. }
  291. public override Color BackColor {
  292. get {
  293. return base.BackColor;
  294. }
  295. set {
  296. base.BackColor = value;
  297. txtView.BackColor = value;
  298. }
  299. }
  300. [Browsable(false)]
  301. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  302. [EditorBrowsable(EditorBrowsableState.Never)]
  303. public override Image BackgroundImage {
  304. get {
  305. return base.BackgroundImage;
  306. }
  307. set {
  308. base.BackgroundImage = value;
  309. txtView.BackgroundImage = value;
  310. }
  311. }
  312. [DefaultValue(BorderStyle.Fixed3D)]
  313. [DispId(-504)]
  314. public BorderStyle BorderStyle {
  315. get { return InternalBorderStyle; }
  316. set { InternalBorderStyle = value; }
  317. }
  318. public override ContextMenu ContextMenu {
  319. get {
  320. return base.ContextMenu;
  321. }
  322. set {
  323. base.ContextMenu = value;
  324. txtView.ContextMenu = value;
  325. spnSpinner.ContextMenu = value;
  326. }
  327. }
  328. [Browsable(false)]
  329. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  330. [EditorBrowsable(EditorBrowsableState.Never)]
  331. public DockPaddingEdges DockPadding {
  332. get {
  333. return base.DockPadding;
  334. }
  335. }
  336. [Browsable(false)]
  337. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  338. public override bool Focused {
  339. get {
  340. return txtView.Focused;
  341. }
  342. }
  343. public override Color ForeColor {
  344. get {
  345. return base.ForeColor;
  346. }
  347. set {
  348. base.ForeColor = value;
  349. txtView.ForeColor = value;
  350. }
  351. }
  352. [DefaultValue(true)]
  353. public bool InterceptArrowKeys {
  354. get {
  355. return _InterceptArrowKeys;
  356. }
  357. set {
  358. _InterceptArrowKeys = value;
  359. }
  360. }
  361. [Browsable(false)]
  362. [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  363. [EditorBrowsable(EditorBrowsableState.Advanced)]
  364. public int PreferredHeight {
  365. get {
  366. // For some reason, the TextBox's PreferredHeight does not
  367. // change when the Font property is assigned. Without a
  368. // border, it will always be Font.Height anyway.
  369. //int text_box_preferred_height = (txtView != null) ? txtView.PreferredHeight : Font.Height;
  370. int text_box_preferred_height = Font.Height;
  371. switch (border_style) {
  372. case BorderStyle.FixedSingle:
  373. case BorderStyle.Fixed3D:
  374. text_box_preferred_height += 3; // magic number? :-)
  375. return text_box_preferred_height + 4;
  376. case BorderStyle.None:
  377. default:
  378. return text_box_preferred_height;
  379. }
  380. }
  381. }
  382. [DefaultValue(false)]
  383. public bool ReadOnly {
  384. get {
  385. return txtView.ReadOnly;
  386. }
  387. set {
  388. txtView.ReadOnly = value;
  389. }
  390. }
  391. [Localizable(true)]
  392. public override string Text {
  393. get {
  394. return txtView.Text;
  395. }
  396. set {
  397. bool suppress_validation = changing_text;
  398. txtView.Text = value;
  399. if (!suppress_validation)
  400. ValidateEditText();
  401. }
  402. }
  403. [DefaultValue(HorizontalAlignment.Left)]
  404. [Localizable(true)]
  405. public HorizontalAlignment TextAlign {
  406. get {
  407. return txtView.TextAlign;
  408. }
  409. set{
  410. txtView.TextAlign = value;
  411. }
  412. }
  413. [DefaultValue(LeftRightAlignment.Right)]
  414. [Localizable(true)]
  415. public LeftRightAlignment UpDownAlign {
  416. get {
  417. return _UpDownAlign;
  418. }
  419. set {
  420. _UpDownAlign = value;
  421. reseat_controls();
  422. }
  423. }
  424. #endregion // Public Instance Properties
  425. #region Protected Instance Properties
  426. protected bool ChangingText {
  427. get {
  428. return changing_text;
  429. }
  430. set {
  431. changing_text = value;
  432. }
  433. }
  434. protected override CreateParams CreateParams {
  435. get {
  436. return base.CreateParams;
  437. }
  438. }
  439. protected override Size DefaultSize {
  440. get {
  441. return new Size(120, this.PreferredHeight);
  442. }
  443. }
  444. protected bool UserEdit {
  445. get {
  446. return user_edit;
  447. }
  448. set {
  449. user_edit = value;
  450. }
  451. }
  452. #endregion // Protected Instance Properties
  453. #region Public Instance Methods
  454. public abstract void DownButton();
  455. public void Select(int start, int length) {
  456. txtView.Select(start, length);
  457. }
  458. public abstract void UpButton();
  459. #endregion // Public Instance Methods
  460. #region Protected Instance Methods
  461. protected override void Dispose(bool disposing) {
  462. if (disposing) {
  463. txtView.Dispose();
  464. txtView = null;
  465. spnSpinner.Dispose();
  466. spnSpinner = null;
  467. }
  468. base.Dispose (disposing);
  469. }
  470. [MonoTODO]
  471. protected virtual void OnChanged(object source, EventArgs e) {
  472. // FIXME
  473. }
  474. protected override void OnFontChanged(EventArgs e) {
  475. txtView.Font = this.Font;
  476. Height = PreferredHeight;
  477. }
  478. protected override void OnHandleCreated(EventArgs e) {
  479. base.OnHandleCreated (e);
  480. }
  481. protected override void OnLayout(LayoutEventArgs e) {
  482. base.OnLayout(e);
  483. }
  484. protected override void OnMouseWheel(MouseEventArgs e) {
  485. // prevent this event from firing twice for the same mouse action!
  486. if (GetChildAtPoint(new Point(e.X, e.Y)) == null)
  487. txtView_MouseWheel(null, e);
  488. }
  489. protected virtual void OnTextBoxKeyDown(object source, KeyEventArgs e) {
  490. if (_InterceptArrowKeys) {
  491. if ((e.KeyCode == Keys.Up) || (e.KeyCode == Keys.Down)) {
  492. e.Handled = true;
  493. if (e.KeyCode == Keys.Up)
  494. UpButton();
  495. if (e.KeyCode == Keys.Down)
  496. DownButton();
  497. }
  498. }
  499. OnKeyDown(e);
  500. }
  501. protected virtual void OnTextBoxKeyPress(object source, KeyPressEventArgs e) {
  502. if (e.KeyChar == '\r') {
  503. e.Handled = true;
  504. ValidateEditText();
  505. }
  506. OnKeyPress(e);
  507. }
  508. protected virtual void OnTextBoxLostFocus(object source, EventArgs e) {
  509. if (user_edit) {
  510. ValidateEditText();
  511. }
  512. }
  513. protected virtual void OnTextBoxResize(object source, EventArgs e) {
  514. // compute the new height, taking the border into account
  515. Height = PreferredHeight;
  516. // let anchoring reposition the controls
  517. }
  518. protected virtual void OnTextBoxTextChanged(object source, EventArgs e) {
  519. if (changing_text) {
  520. ChangingText = false;
  521. } else {
  522. UserEdit = true;
  523. }
  524. OnTextChanged(e);
  525. }
  526. protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
  527. base.SetBoundsCore(x, y, width, height, specified);
  528. if ((specified & BoundsSpecified.Size) != BoundsSpecified.None) {
  529. reseat_controls();
  530. }
  531. }
  532. protected abstract void UpdateEditText();
  533. protected virtual void ValidateEditText() {
  534. // to be overridden by subclassers
  535. }
  536. [EditorBrowsable(EditorBrowsableState.Advanced)]
  537. protected override void WndProc(ref Message m) {
  538. base.WndProc (ref m);
  539. }
  540. #endregion // Protected Instance Methods
  541. #region Events
  542. [Browsable(false)]
  543. [EditorBrowsable(EditorBrowsableState.Never)]
  544. public new event EventHandler BackgroundImageChanged;
  545. [Browsable(false)]
  546. [EditorBrowsable(EditorBrowsableState.Never)]
  547. public new event EventHandler MouseEnter;
  548. [Browsable(false)]
  549. [EditorBrowsable(EditorBrowsableState.Never)]
  550. public new event EventHandler MouseHover;
  551. [Browsable(false)]
  552. [EditorBrowsable(EditorBrowsableState.Never)]
  553. public new event EventHandler MouseLeave;
  554. [Browsable(false)]
  555. [EditorBrowsable(EditorBrowsableState.Never)]
  556. public new event MouseEventHandler MouseMove;
  557. #endregion // Events
  558. }
  559. }