ScrollBar.cs 18 KB

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