ScrollBar.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. //
  2. // System.Windows.Forms.ScrollBar.cs
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. // Copyright (C) 2004, Novell, Inc.
  24. //
  25. // Authors:
  26. // Jordi Mas i Hernandez [email protected]
  27. //
  28. //
  29. // $Revision: 1.5 $
  30. // $Modtime: $
  31. // $Log: ScrollBar.cs,v $
  32. // Revision 1.5 2004/08/10 19:21:27 jordi
  33. // scrollbar enhancements and standarize on win colors defaults
  34. //
  35. // Revision 1.4 2004/08/10 15:41:50 jackson
  36. // Allow control to handle buffering
  37. //
  38. // Revision 1.3 2004/07/27 15:29:40 jordi
  39. // fixes scrollbar events
  40. //
  41. // Revision 1.2 2004/07/26 17:42:03 jordi
  42. // Theme support
  43. //
  44. // NOT COMPLETE
  45. using System.Drawing;
  46. using System.Drawing.Imaging;
  47. using System.Drawing.Drawing2D;
  48. using System.ComponentModel;
  49. using System.Runtime.InteropServices;
  50. using System.Timers;
  51. namespace System.Windows.Forms
  52. {
  53. public class ScrollBar : Control
  54. {
  55. #region Local Variables
  56. private int position;
  57. private int minimum;
  58. private int maximum;
  59. private int largeChange;
  60. private int smallChange;
  61. private int scrollbutton_height;
  62. private int scrollbutton_width;
  63. private Rectangle paint_area = new Rectangle ();
  64. private ScrollBars type;
  65. private Rectangle first_arrow_area = new Rectangle (); // up or left
  66. private Rectangle second_arrow_area = new Rectangle (); // down or right
  67. private Rectangle thumb_pos = new Rectangle ();
  68. private Rectangle thumb_area = new Rectangle ();
  69. private ButtonState firstbutton_state = ButtonState.Normal;
  70. private ButtonState secondbutton_state = ButtonState.Normal;
  71. private bool thumb_pressed = false;
  72. private float pixel_per_pos = 0;
  73. private System.Timers.Timer firstclick_timer = new System.Timers.Timer ();
  74. private System.Timers.Timer holdclick_timer = new System.Timers.Timer ();
  75. private int thumb_pixel_click_move;
  76. private int thumb_size = 0;
  77. private const int thumb_min_size = 8;
  78. protected bool vert;
  79. public event ScrollEventHandler Scroll;
  80. public event EventHandler ValueChanged;
  81. #endregion // Local Variables
  82. public ScrollBar() : base()
  83. {
  84. position = 0;
  85. minimum = 0;
  86. maximum = 100;
  87. largeChange = 10;
  88. smallChange = 1;
  89. // base.TabStop = false;
  90. // RightToLeft = RightToLeft.No;
  91. Scroll = null;
  92. ValueChanged = null;
  93. SetStyle (ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
  94. SetStyle (ControlStyles.ResizeRedraw | ControlStyles.Opaque, true);
  95. }
  96. [EditorBrowsable (EditorBrowsableState.Never)]
  97. public override Color BackColor
  98. {
  99. get { return base.BackColor; }
  100. set { base.BackColor = value;}
  101. }
  102. [EditorBrowsable (EditorBrowsableState.Never)]
  103. [MonoTODO]
  104. public override Image BackgroundImage
  105. {
  106. get {
  107. throw new NotImplementedException();
  108. }
  109. set {
  110. throw new NotImplementedException();
  111. }
  112. }
  113. [EditorBrowsable (EditorBrowsableState.Never)]
  114. public override Color ForeColor
  115. {
  116. get { return base.ForeColor; }
  117. set { base.ForeColor = value; }
  118. }
  119. [EditorBrowsable (EditorBrowsableState.Never)]
  120. [MonoTODO]
  121. public new ImeMode ImeMode
  122. {
  123. get { return ImeMode.Disable;}
  124. set { throw new NotImplementedException(); }
  125. }
  126. public int LargeChange {
  127. get { return largeChange; }
  128. set {
  129. if (value < 0)
  130. throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
  131. if (largeChange != value) {
  132. largeChange = value;
  133. Refresh ();
  134. }
  135. }
  136. }
  137. public int Maximum {
  138. get { return maximum; }
  139. set {
  140. maximum = value;
  141. if (maximum < minimum)
  142. minimum = maximum;
  143. Refresh ();
  144. }
  145. }
  146. public int Minimum {
  147. get { return minimum; }
  148. set {
  149. minimum = value;
  150. if (minimum > maximum)
  151. maximum = minimum;
  152. Refresh ();
  153. }
  154. }
  155. public int SmallChange {
  156. get { return smallChange; }
  157. set {
  158. if ( value < 0 )
  159. throw new Exception( string.Format("Value '{0}' must be greater than or equal to 0.", value));
  160. if (smallChange != value) {
  161. smallChange = value;
  162. Refresh ();
  163. }
  164. }
  165. }
  166. [EditorBrowsable (EditorBrowsableState.Never)]
  167. public override string Text {
  168. get { return base.Text; }
  169. set { base.Text = value; }
  170. }
  171. public int Value {
  172. get { return position; }
  173. set {
  174. if ( value < Minimum || value > Maximum )
  175. throw new ArgumentException(
  176. string.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
  177. if (position != value){
  178. position = value;
  179. if (ValueChanged != null)
  180. ValueChanged (this, EventArgs.Empty);
  181. Refresh ();
  182. }
  183. }
  184. }
  185. public override string ToString()
  186. {
  187. return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}",
  188. GetType( ).FullName.ToString( ), Minimum, Maximum, position);
  189. }
  190. protected override CreateParams CreateParams {
  191. get {
  192. CreateParams createParams = base.CreateParams;
  193. createParams.ClassName = XplatUI.DefaultClassName;
  194. createParams.Style = (int) (
  195. WindowStyles.WS_CHILD |
  196. WindowStyles.WS_VISIBLE);
  197. return createParams;
  198. }
  199. }
  200. protected override ImeMode DefaultImeMode {
  201. get { return ImeMode.Disable; }
  202. }
  203. private void fire_Scroll (ScrollEventArgs event_args)
  204. {
  205. if (Scroll == null)
  206. return;
  207. Scroll (this, event_args);
  208. //if (event_args.NewValue != position)
  209. // UpdatePos (event_args.NewValue, true);
  210. }
  211. protected virtual void OnValueChanged (EventArgs e)
  212. {
  213. if (ValueChanged != null)
  214. ValueChanged (this, e);
  215. }
  216. private void Draw ()
  217. {
  218. ThemeEngine.Current.DrawScrollBar (DeviceContext, paint_area, thumb_pos,
  219. ref first_arrow_area, ref second_arrow_area,
  220. firstbutton_state, secondbutton_state,
  221. ref scrollbutton_width, ref scrollbutton_height,
  222. Enabled, vert);
  223. }
  224. private void CalcThumbArea ()
  225. {
  226. // Thumb area
  227. if (vert) {
  228. thumb_area.Height = Height - scrollbutton_height - scrollbutton_height;
  229. thumb_area.X = 0;
  230. thumb_area.Y = scrollbutton_height;
  231. thumb_area.Width = Width;
  232. if (Height < scrollbutton_height * 2)
  233. thumb_size = 0;
  234. else {
  235. double per = ((double)LargeChange / (double)((1 + Maximum - Minimum)));
  236. thumb_size = 1 + (int) (thumb_area.Height * per);
  237. //Console.WriteLine ("size: {0} {1} {2}", thumb_size, thumb_area.Height, per);
  238. if (thumb_size < thumb_min_size)
  239. thumb_size = thumb_min_size;
  240. }
  241. pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((Maximum - Minimum - LargeChange) + 1));
  242. } else {
  243. if (Width < scrollbutton_width * 2)
  244. thumb_size = 0;
  245. else
  246. if (Width < 70)
  247. thumb_size = 8;
  248. else
  249. thumb_size = Width /10;
  250. thumb_area.Y = 0;
  251. thumb_area.X = scrollbutton_width;
  252. thumb_area.Height = Height;
  253. thumb_area.Width = Width - scrollbutton_width - scrollbutton_width;
  254. pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((Maximum - Minimum - LargeChange) + 1));
  255. }
  256. }
  257. protected override void OnResize (EventArgs e)
  258. {
  259. base.OnResize (e);
  260. if (Width <= 0 || Height <= 0)
  261. return;
  262. paint_area.X = paint_area. Y = 0;
  263. paint_area.Width = Width;
  264. paint_area.Height = Height;
  265. CreateBuffers (Width, Height);
  266. CalcThumbArea ();
  267. UpdatePos (position, true);
  268. }
  269. /*
  270. Called when the control is created
  271. */
  272. protected override void CreateHandle()
  273. {
  274. base.CreateHandle(); // Let control.cs create the underlying Window
  275. scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
  276. scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
  277. CreateBuffers (Width, Height);
  278. CalcThumbArea ();
  279. UpdatePos (Value, true);
  280. }
  281. protected override void OnPaint (PaintEventArgs pevent)
  282. {
  283. if (Width <= 0 || Height <= 0 || Visible == false)
  284. return;
  285. /* Copies memory drawing buffer to screen*/
  286. Draw ();
  287. pevent.Graphics.DrawImage (ImageBuffer, 0, 0);
  288. }
  289. /* Disable background painting to avoid flickering, since we do our painting*/
  290. protected override void OnPaintBackground (PaintEventArgs pevent)
  291. {
  292. // None
  293. }
  294. protected override void OnClick (EventArgs e)
  295. {
  296. //Console.WriteLine ("On click");
  297. }
  298. private void UpdatePos (int newPos, bool update_trumbpos)
  299. {
  300. int old = position;
  301. if (newPos < minimum)
  302. position = minimum;
  303. else
  304. if (newPos > maximum)
  305. position = maximum;
  306. else
  307. position = newPos;
  308. if (update_trumbpos)
  309. if (vert)
  310. UpdateThumbPos (thumb_area.Y + (int)(((float)(position - Minimum)) * pixel_per_pos), false);
  311. else
  312. UpdateThumbPos (thumb_area.X + (int)(((float)(position - Minimum)) * pixel_per_pos), false);
  313. if (position != old) // Fire event
  314. fire_Scroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
  315. }
  316. private void UpdateThumbPos (int pixel, bool update_value)
  317. {
  318. float new_pos = 0;
  319. if (vert) {
  320. if (pixel < thumb_area.Y)
  321. thumb_pos.Y = thumb_area.Y;
  322. else
  323. if (pixel > thumb_area.Y + thumb_area.Height - thumb_size)
  324. thumb_pos.Y = thumb_area.Y + thumb_area.Height - thumb_size;
  325. else
  326. thumb_pos.Y = pixel;
  327. thumb_pos = new Rectangle (0, thumb_pos.Y, ThemeEngine.Current.ScrollBarButtonSize, thumb_size);
  328. new_pos = (float) (thumb_pos.Y - thumb_area.Y);
  329. new_pos = new_pos / pixel_per_pos;
  330. } else {
  331. if (pixel < thumb_area.X)
  332. thumb_pos.X = thumb_area.X;
  333. else
  334. if (pixel > thumb_area.X + thumb_area.Width - thumb_size)
  335. thumb_pos.X = thumb_area.X + thumb_area.Width - thumb_size;
  336. else
  337. thumb_pos.X = pixel;
  338. thumb_pos = new Rectangle (thumb_pos.X, 0, thumb_size, ThemeEngine.Current.ScrollBarButtonSize);
  339. new_pos = (float) (thumb_pos.X - thumb_area.X);
  340. new_pos = new_pos / pixel_per_pos;
  341. }
  342. //Console.WriteLine ("UpdateThumbPos: thumb_pos.Y {0} thumb_area.Y {1} pixel_per_pos {2}, new pos {3}, pixel {4}",
  343. // thumb_pos.Y, thumb_area.Y, pixel_per_pos, new_pos, pixel);
  344. if (update_value)
  345. UpdatePos ((int) new_pos, false);
  346. }
  347. private void OnHoldClickTimer (Object source, ElapsedEventArgs e)
  348. {
  349. if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
  350. SmallDecrement();
  351. if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
  352. SmallIncrement();
  353. }
  354. private void OnFirstClickTimer (Object source, ElapsedEventArgs e)
  355. {
  356. firstclick_timer.Enabled = false;
  357. holdclick_timer.Elapsed += new ElapsedEventHandler (OnHoldClickTimer);
  358. holdclick_timer.Interval = 50;
  359. holdclick_timer.Enabled = true;
  360. }
  361. protected override void OnMouseMove (MouseEventArgs e)
  362. {
  363. if (!first_arrow_area.Contains (new Point (e.X, e.Y)) &&
  364. ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
  365. firstbutton_state = ButtonState.Normal;
  366. Refresh ();
  367. }
  368. if (!second_arrow_area.Contains (new Point (e.X, e.Y)) &&
  369. ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
  370. secondbutton_state = ButtonState.Normal;
  371. Refresh ();
  372. }
  373. if (thumb_pos.Contains (new Point (e.X, e.Y)) && thumb_pressed) {
  374. int pixel_pos;
  375. if (vert)
  376. pixel_pos = e.Y - (thumb_pixel_click_move - thumb_pos.Y);
  377. else
  378. pixel_pos = e.X - (thumb_pixel_click_move - thumb_pos.X);
  379. UpdateThumbPos (pixel_pos, true);
  380. if (vert)
  381. thumb_pixel_click_move = e.Y;
  382. else
  383. thumb_pixel_click_move = e.X;
  384. //System.Console.WriteLine ("OnMouseMove thumb "+ e.Y
  385. // + " clickpos " + thumb_pixel_click_move + " pos:" + thumb_pos.Y);
  386. Refresh ();
  387. }
  388. if (!thumb_pos.Contains (new Point (e.X, e.Y)) && thumb_pressed) {
  389. thumb_pressed = false;
  390. Refresh ();
  391. }
  392. }
  393. protected override void OnMouseDown (MouseEventArgs e)
  394. {
  395. //System.Console.WriteLine ("OnMouseDown");
  396. Point point = new Point (e.X, e.Y);
  397. if (first_arrow_area.Contains (point)) {
  398. firstbutton_state = ButtonState.Pushed;
  399. Refresh ();
  400. }
  401. if (second_arrow_area.Contains (point)) {
  402. secondbutton_state = ButtonState.Pushed;
  403. Refresh ();
  404. }
  405. if (thumb_pos.Contains (point)) {
  406. thumb_pressed = true;
  407. Refresh ();
  408. if (vert)
  409. thumb_pixel_click_move = e.Y;
  410. else
  411. thumb_pixel_click_move = e.X;
  412. }
  413. else
  414. if (thumb_area.Contains (point)) {
  415. if (vert) {
  416. if (e.Y > thumb_pos.Y + thumb_pos.Height)
  417. LargeIncrement();
  418. else
  419. LargeDecrement();
  420. } else {
  421. if (e.X > thumb_pos.X + thumb_pos.Width)
  422. LargeIncrement();
  423. else
  424. LargeDecrement();
  425. }
  426. }
  427. /* If arrows are pressed, lunch timer for auto-repeat */
  428. if ((((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)
  429. || ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) &&
  430. firstclick_timer.Enabled == false) {
  431. //Console.WriteLine ("Activate Timer");
  432. firstclick_timer.Elapsed += new ElapsedEventHandler (OnFirstClickTimer);
  433. firstclick_timer.Interval = 400;
  434. firstclick_timer.Enabled = true;
  435. firstclick_timer.AutoReset = false;
  436. }
  437. }
  438. private void SmallIncrement()
  439. {
  440. if (vert)
  441. UpdateThumbPos (thumb_pos.Y + SmallChange, true);
  442. else
  443. UpdateThumbPos (thumb_pos.X + SmallChange, true);
  444. Refresh ();
  445. fire_Scroll (new ScrollEventArgs (ScrollEventType.SmallIncrement, position));
  446. fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
  447. }
  448. private void SmallDecrement()
  449. {
  450. if (vert)
  451. UpdateThumbPos (thumb_pos.Y - SmallChange, true);
  452. else
  453. UpdateThumbPos (thumb_pos.X - SmallChange, true);
  454. Refresh ();
  455. fire_Scroll (new ScrollEventArgs (ScrollEventType.SmallDecrement, position));
  456. fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
  457. }
  458. private void LargeIncrement()
  459. {
  460. if (vert)
  461. UpdateThumbPos (thumb_pos.Y + LargeChange, true);
  462. else
  463. UpdateThumbPos (thumb_pos.X + LargeChange, true);
  464. Refresh ();
  465. fire_Scroll (new ScrollEventArgs (ScrollEventType.LargeIncrement, position));
  466. fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
  467. }
  468. private void LargeDecrement()
  469. {
  470. if (vert)
  471. UpdateThumbPos (thumb_pos.Y - LargeChange, true);
  472. else
  473. UpdateThumbPos (thumb_pos.X - LargeChange, true);
  474. Refresh ();
  475. fire_Scroll (new ScrollEventArgs (ScrollEventType.LargeDecrement, position));
  476. fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
  477. }
  478. protected override void OnMouseUp (MouseEventArgs e)
  479. {
  480. //System.Console.WriteLine ("OnMouseUp");
  481. if (first_arrow_area.Contains (new Point (e.X, e.Y))) {
  482. firstbutton_state = ButtonState.Normal;
  483. SmallDecrement ();
  484. holdclick_timer.Enabled = false;
  485. }
  486. if (second_arrow_area.Contains (new Point (e.X, e.Y))) {
  487. secondbutton_state = ButtonState.Normal;
  488. SmallIncrement ();
  489. holdclick_timer.Enabled = false;
  490. }
  491. if (thumb_pos.Contains (new Point (e.X, e.Y))) {
  492. fire_Scroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
  493. fire_Scroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
  494. thumb_pressed = false;
  495. Refresh ();
  496. }
  497. }
  498. //TODO: Untested
  499. protected override void OnKeyDown (KeyEventArgs key)
  500. {
  501. switch (key.KeyCode){
  502. case Keys.Up:
  503. {
  504. SmallDecrement ();
  505. break;
  506. }
  507. case Keys.Down:
  508. {
  509. SmallIncrement ();
  510. break;
  511. }
  512. case Keys.PageUp:
  513. {
  514. LargeDecrement ();
  515. break;
  516. }
  517. case Keys.PageDown:
  518. {
  519. LargeIncrement ();
  520. break;
  521. }
  522. default:
  523. break;
  524. }
  525. }
  526. protected void UpdateScrollInfo ()
  527. {
  528. Refresh ();
  529. }
  530. }
  531. }