ScrollBar.cs 18 KB

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