ScrollBar.cs 19 KB

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