VScrollBarEx.cs
Upload User: nnpulika
Upload Date: 2013-02-15
Package Size: 597k
Code Size: 17k
Category:

StatusBar

Development Platform:

C#

  1. using System;
  2. using System.Drawing;
  3. using System.Diagnostics;
  4. using System.Runtime.InteropServices;
  5. using System.ComponentModel;
  6. using System.Windows.Forms;
  7. using UtilityLibrary.Win32;
  8. using UtilityLibrary.General;
  9. namespace UtilityLibrary.WinControls
  10. {
  11. /// <summary>
  12. /// 
  13. /// </summary>
  14. [ToolboxItem(false)]
  15. public class VScrollBarEx : ScrollBarEx
  16. {
  17. #region Events
  18. public event ThumbHandler ThumbUp = null;
  19. public event ThumbHandler ThumbDown = null;
  20. public event EventHandler LineUp = null;
  21. public event EventHandler LineDown = null;
  22. public event EventHandler PageUp = null;
  23. public event EventHandler PageDown = null;
  24. #endregion
  25. #region Class variables
  26. DrawState upArrowDrawState = DrawState.Normal;
  27. DrawState downArrowDrawState = DrawState.Normal;
  28. bool ignoreMouseMove = false;
  29. bool draggingThumb = false;
  30. int oldMouseY = 0;
  31. ScrollBarHit currentTarget = ScrollBarHit.None;
  32. bool firstTick = false;
  33. double thumbPixelPos = 0;
  34. bool processingAutomaticScrolling = false;
  35. const int MINIMUM_THUMB_HEIGHT = 6;
  36. #endregion
  37. #region Constructors
  38. public VScrollBarEx()
  39. {
  40. }
  41. public VScrollBarEx(Control parent) : base(parent)
  42. {
  43. }
  44. #endregion
  45. #region Properties
  46. public ImageList UpArrowImageList
  47. {
  48. set {  upArrowImageList = value; }
  49. get { return upArrowImageList; }
  50. }
  51. public ImageList DownArrowImageList
  52. {
  53. set {  downArrowImageList = value; }
  54. get { return downArrowImageList; }
  55. }
  56. #endregion
  57. #region Overrides
  58. protected override void OnMouseDown(MouseEventArgs e)
  59. {
  60. base.OnMouseDown(e);
  61. if ( e.Button != MouseButtons.Left )
  62. return;
  63. ScrollBarHit hit = HitTest(new Point(e.X, e.Y));
  64. if ( hit == ScrollBarHit.UpArrow )
  65. {
  66. upArrowDrawState = DrawState.Hot;
  67. Position -= smallChange;
  68. FireLineUp();
  69. }
  70. else if ( hit == ScrollBarHit.DownArrow )
  71. {
  72. downArrowDrawState = DrawState.Hot;
  73. Position += smallChange;
  74. FireLineDown();
  75. }
  76. else if ( hit == ScrollBarHit.PageUp )
  77. {
  78. Position -= largeChange;
  79. FirePageUp();
  80. }
  81. else if ( hit == ScrollBarHit.PageDown )
  82. {
  83. Position += largeChange;
  84. FirePageDown();
  85. }
  86. else if ( hit == ScrollBarHit.Thumb )
  87. {
  88. Capture = true;
  89. draggingThumb = true;
  90. thumbDrawState = DrawState.Pressed;
  91. oldMouseY = e.Y;
  92.                 thumbPixelPos = GetThumbPixelPosition(pos);
  93. Invalidate();
  94. }
  95. // Don't create reentry problems
  96. if ( !processingAutomaticScrolling )
  97. {
  98. if ( hit != ScrollBarHit.Thumb && hit != ScrollBarHit.None )
  99. ProcessScrolling(hit);
  100. }
  101. }
  102. protected override void OnMouseMove(MouseEventArgs e)
  103. {
  104. base.OnMouseDown(e);
  105. if ( ignoreMouseMove) 
  106. {
  107. ignoreMouseMove = false;
  108. return;
  109. }
  110. // Reset every thing to normal state
  111. upArrowDrawState = DrawState.Normal;
  112. downArrowDrawState = DrawState.Normal;
  113. thumbDrawState = DrawState.Normal;
  114. ScrollBarHit hit = HitTest(new Point(e.X, e.Y));
  115. if ( hit == ScrollBarHit.UpArrow )
  116. {
  117. upArrowDrawState = DrawState.Hot;
  118. }
  119. else if ( hit == ScrollBarHit.DownArrow )
  120. {
  121. downArrowDrawState = DrawState.Hot;
  122. }
  123. else if ( hit == ScrollBarHit.Thumb || draggingThumb )
  124. {
  125. if ( draggingThumb )
  126. {
  127. thumbDrawState = DrawState.Pressed;
  128. UpdatePosition(e.Y);
  129. oldMouseY = e.Y;
  130. if ( dragFrequency == ThumbDraggedFireFrequency.MouseMove )
  131. {
  132. if ( pos > previousPos )
  133. FireThumbDown((int)pos-(int)previousPos);
  134. else
  135. FireThumbUp((int)previousPos-(int)pos);
  136. }
  137. }
  138. else
  139. {
  140. thumbDrawState = DrawState.Hot;
  141. }
  142. }
  143. Invalidate();
  144. }
  145. protected override void OnMouseUp(MouseEventArgs e)
  146. {
  147. base.OnMouseUp(e);
  148. if ( e.Button != MouseButtons.Left )
  149. return;
  150. // Reset drawing to normal state
  151. upArrowDrawState = DrawState.Normal;
  152. downArrowDrawState = DrawState.Normal;
  153. thumbDrawState = DrawState.Normal;
  154. ignoreMouseMove = true;
  155. if ( draggingThumb )
  156. {
  157. Capture = false;
  158. thumbDrawState = DrawState.Normal;
  159. UpdatePosition(e.Y);
  160. draggingThumb = false;
  161.                 
  162. if ( pos > previousPos )
  163. {
  164. FireThumbDown((int)pos-(int)previousPos);
  165. }
  166. else
  167. FireThumbUp((int)previousPos-(int)pos);
  168. // For users who that want to know when the
  169. // Thumb is released
  170. FireThumbRelease();
  171. }
  172. Invalidate();
  173. }
  174. protected override void OnMouseEnter(EventArgs e)
  175. {
  176. // Set state to hot
  177. base.OnMouseEnter(e);
  178. Point pos = Control.MousePosition;
  179. pos = PointToClient(pos);
  180. ScrollBarHit hit = HitTest(pos);
  181. if ( hit == ScrollBarHit.UpArrow )
  182. {
  183. upArrowDrawState = DrawState.Hot;
  184. }
  185. else if ( hit == ScrollBarHit.DownArrow )
  186. {
  187. downArrowDrawState = DrawState.Hot;
  188. }
  189. else if ( hit == ScrollBarHit.Thumb )
  190. {
  191. thumbDrawState = DrawState.Hot;
  192. }
  193. Invalidate();
  194. }
  195. protected override void OnMouseLeave(EventArgs e)
  196. {
  197. // Set state to Normal
  198. base.OnMouseLeave(e);
  199. upArrowDrawState = DrawState.Normal;
  200. downArrowDrawState = DrawState.Normal;
  201. thumbDrawState = DrawState.Normal;
  202. Invalidate();
  203. }
  204. protected override void SizeScrollBar()
  205. {
  206. // Resize scrollbar
  207. // Size scrollbar to have the standard dimensions
  208. // of an operating system created scrollbar
  209. Rectangle rcParent = parentWindow.ClientRectangle;
  210. // If both scrollbar are being used
  211. if ( usingBothScrollBars )
  212. {
  213. Bounds =  new Rectangle(rcParent.Right-VThumb-BorderGap, 
  214. rcParent.Top+BorderGap, VThumb, rcParent.Bottom - BorderGap*2 - HThumb);
  215. }
  216. else
  217. {
  218. Bounds =  new Rectangle(rcParent.Right-VThumb-BorderGap, 
  219. rcParent.Top+BorderGap, VThumb, rcParent.Bottom - BorderGap*2);
  220. }
  221. }
  222. protected override void DrawScrollBar(Graphics g)
  223. {
  224. // Draw background
  225. DrawBackground(g);
  226. // Draw Button up arrow
  227. if ( Enabled )
  228. {
  229. // Up and Down buttons
  230. DrawArrowButtons(g);
  231. // Draw Thumb
  232. DrawThumb(g, thumbDrawState);
  233. // Draw Gripper
  234. if ( drawGripper )
  235. DrawThumbGripper(g, thumbDrawState);
  236. }
  237. }
  238. #endregion
  239. #region Implementation
  240. void FireThumbUp(int delta)
  241. {
  242. if ( ThumbUp != null && previousPos != pos )
  243. ThumbUp(this, delta);
  244. }
  245. void FireThumbDown(int delta)
  246. {
  247. if ( ThumbDown != null && previousPos != pos )
  248. ThumbDown(this, delta);
  249. }
  250. void FireLineUp()
  251. {
  252. if ( LineUp != null && previousPos != pos )
  253. LineUp(this, EventArgs.Empty);
  254. }
  255. void FireLineDown()
  256. {
  257. if ( LineDown != null && previousPos != pos )
  258. LineDown(this, EventArgs.Empty);
  259. }
  260.         
  261. void FirePageUp()
  262. {
  263. if ( PageUp != null && previousPos != pos )
  264. PageUp(this, EventArgs.Empty);
  265. }
  266. void FirePageDown()
  267. {
  268. if ( PageDown != null && previousPos != pos )
  269. PageDown(this, EventArgs.Empty);
  270. }
  271. void ProcessScrolling(ScrollBarHit hit)
  272. {
  273. // Capture the mouse
  274. stopAutomaticScrolling = false;
  275. Capture = true;
  276. firstTick = true;
  277. // Start timer
  278. System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
  279. timer.Tick += new EventHandler(ScrollingTick);
  280. timer.Interval = TIMER_INTERVAL;
  281. timer.Start();
  282. currentTarget = hit;
  283.                          
  284. while ( stopAutomaticScrolling == false ) 
  285. {
  286. // Check messages until we find a condition to break out of the loop
  287. Win32.MSG msg = new Win32.MSG();
  288. WindowsAPI.GetMessage(ref msg, 0, 0, 0);
  289. Point point = new Point(0,0);
  290. if ( msg.message == (int)Msg.WM_MOUSEMOVE 
  291. || msg.message == (int)Msg.WM_LBUTTONUP || msg.message == (int)Msg.WM_LBUTTONDBLCLK )
  292. {
  293. point = WindowsAPI.GetPointFromLPARAM((int)msg.lParam);
  294. }
  295. Msg thisMessage = (Msg)msg.message;
  296. switch(msg.message)
  297. {
  298. case (int)Msg.WM_MOUSEMOVE:
  299. {
  300. ScrollBarHit current = HitTest(point);
  301. ProcessMouseMoveScrolling(current);
  302. Invalidate();
  303. break;
  304. }
  305. case (int)Msg.WM_LBUTTONUP:
  306. case (int)Msg.WM_LBUTTONDBLCLK:
  307. {
  308. stopAutomaticScrolling = true;
  309. WindowsAPI.DispatchMessage(ref msg);
  310. break;
  311. }
  312. case (int)Msg.WM_KEYDOWN:
  313. {
  314. if ( (int)msg.wParam == (int)VirtualKeys.VK_ESCAPE) 
  315. stopAutomaticScrolling = true;
  316. break;
  317. }
  318. default:
  319. WindowsAPI.DispatchMessage(ref msg);
  320. break;
  321. }
  322. }
  323. // Stop timer
  324. timer.Stop();
  325. timer.Dispose();
  326. Invalidate();
  327. // Release the capture
  328. Capture = false;
  329. if ( processingAutomaticScrolling )
  330. {
  331. processingAutomaticScrolling = false;
  332. FireStoppingAutomaticScrolling();
  333. }
  334. }
  335. void ProcessMouseMoveScrolling(ScrollBarHit hit)
  336. {
  337. upArrowDrawState = DrawState.Normal;
  338. downArrowDrawState = DrawState.Normal;
  339. if ( hit == ScrollBarHit.UpArrow )
  340. upArrowDrawState = DrawState.Hot;
  341. else if ( hit == ScrollBarHit.DownArrow )
  342. downArrowDrawState = DrawState.Hot;
  343.             
  344. }
  345. void ScrollingTick(Object timeObject, EventArgs eventArgs) 
  346. {
  347. processingAutomaticScrolling = true;
  348. FireStartingAutomaticScrolling();
  349. // Ignore the first tick since sometimes the user
  350. // is just clicking and the first tick happens
  351. // so fast that produces the effect of scrolling twice
  352. if ( firstTick )
  353. {
  354. firstTick = false;
  355. return;
  356. }
  357. // Get mouse coordinates
  358. Point point = Control.MousePosition;
  359. point = PointToClient(point);
  360. Rectangle rc = Rectangle.Empty;
  361. if ( currentTarget == ScrollBarHit.UpArrow )
  362. {
  363. rc = GetArrowButtonRectangle(true);
  364. if ( rc.Contains(point) )
  365. {
  366. Position -= smallChange;
  367. FireLineUp();
  368. }
  369. }
  370. else if ( currentTarget == ScrollBarHit.DownArrow )
  371. {
  372. rc = GetArrowButtonRectangle(false);
  373. if ( rc.Contains(point) )
  374. {
  375. Position += smallChange;
  376. FireLineDown();
  377. }
  378. }
  379. else if ( currentTarget == ScrollBarHit.PageUp )
  380. {
  381. rc = GetPageRect(true);
  382. if ( rc.Contains(point) )
  383. {
  384. Position -= largeChange;
  385. FirePageUp();
  386. }
  387. }
  388. else if ( currentTarget == ScrollBarHit.PageDown )
  389. {
  390. rc = GetPageRect(false);
  391. if ( rc.Contains(point) )
  392. {
  393. Position += largeChange;
  394. FirePageDown();
  395. }
  396. }
  397. }
  398. void SetPosition(double fpos)
  399. {
  400. if ( pos != fpos )
  401. {
  402. previousPos = pos;
  403. double newValue = fpos;
  404. if ( newValue >= max-largeChange ) 
  405. {
  406. // Position cannot be larger than
  407. // max-largeChange
  408. pos = max-largeChange;
  409. }
  410. else if ( newValue < 0 )
  411. {
  412. // Negative values don't make sense
  413. pos = 0;
  414. }
  415. else
  416. pos = newValue;
  417. if ( previousPos != pos )
  418. Invalidate();
  419. }
  420. else
  421. previousPos = pos;
  422. }
  423. void UpdatePosition(int yPos)
  424. {
  425. int increment = 0;
  426. if ( yPos >= oldMouseY )
  427. increment = yPos - oldMouseY;
  428. else
  429. increment = (oldMouseY - yPos)*(-1);
  430. thumbPixelPos += increment; 
  431. double fPos = GetThumbLogicalPosition(thumbPixelPos);
  432. SetPosition(fPos);
  433. }
  434. protected virtual void DrawArrowButtons(Graphics g)
  435. {
  436. Rectangle upRect = GetArrowButtonRectangle(true); 
  437. Rectangle downRect = GetArrowButtonRectangle(false);
  438. DrawFlatArrowButton(g, upRect, ArrowGlyph.Up, upArrowDrawState);
  439. DrawFlatArrowButton(g, downRect, ArrowGlyph.Down, downArrowDrawState);
  440. }
  441. protected virtual void DrawThumbGripper(Graphics g, DrawState drawState)
  442. {
  443. Rectangle rc = GetThumbRect();
  444. // Don't draw it if it won't fit
  445. if ( rc.Height < MINIMUM_THUMB_WITH_GRIPPER_SIZE )
  446. return;
  447. int yMiddle = rc.Top + rc.Height/2;
  448. int xPos = rc.Left + (rc.Width - GRIPPER_WIDTH)/2;
  449.             
  450. Color lightColor = ColorUtil.VSNetSelectionColor;
  451. Color darkColor = ColorUtil.VSNetPressedColor;
  452. // Check if the user set custom colors for the gripper
  453. if ( gripperLightColor != Color.Empty )
  454. lightColor = gripperLightColor;
  455. if ( gripperDarkColor != Color.Empty )
  456. darkColor = gripperDarkColor;
  457. Pen lightPen = new Pen(lightColor);
  458. Pen darkPen = new Pen(darkColor);
  459. Point pt1 = new Point(xPos, yMiddle-GRIPPER_HEIGHT/2);
  460. Point pt2 = new Point(xPos + GRIPPER_WIDTH, yMiddle-GRIPPER_HEIGHT/2);
  461. g.DrawLine(lightPen, pt1, pt2);
  462. pt1 = new Point(xPos+1, yMiddle-GRIPPER_HEIGHT/2+1);
  463. pt2 = new Point(xPos + GRIPPER_WIDTH + 1, yMiddle-GRIPPER_HEIGHT/2+1);
  464. g.DrawLine(darkPen, pt1, pt2);
  465. pt1 = new Point(xPos, yMiddle-GRIPPER_HEIGHT/2+2);
  466. pt2 = new Point(xPos + GRIPPER_WIDTH, yMiddle-GRIPPER_HEIGHT/2+2);
  467. g.DrawLine(lightPen, pt1, pt2);
  468. pt1 = new Point(xPos+1, yMiddle-GRIPPER_HEIGHT/2+3);
  469. pt2 = new Point(xPos + GRIPPER_WIDTH + 1, yMiddle-GRIPPER_HEIGHT/2+3);
  470. g.DrawLine(darkPen, pt1, pt2);
  471. pt1 = new Point(xPos, yMiddle-GRIPPER_HEIGHT/2+4);
  472. pt2 = new Point(xPos + GRIPPER_WIDTH, yMiddle-GRIPPER_HEIGHT/2+4);
  473. g.DrawLine(lightPen, pt1, pt2);
  474. pt1 = new Point(xPos+1, yMiddle-GRIPPER_HEIGHT/2+5);
  475. pt2 = new Point(xPos + GRIPPER_WIDTH+1, yMiddle-GRIPPER_HEIGHT/2+5);
  476. g.DrawLine(darkPen, pt1, pt2);
  477. pt1 = new Point(xPos, yMiddle-GRIPPER_HEIGHT/2+6);
  478. pt2 = new Point(xPos + GRIPPER_WIDTH, yMiddle-GRIPPER_HEIGHT/2+6);
  479. g.DrawLine(lightPen, pt1, pt2);
  480. pt1 = new Point(xPos+1, yMiddle-GRIPPER_HEIGHT/2+7);
  481. pt2 = new Point(xPos + GRIPPER_WIDTH + 1, yMiddle-GRIPPER_HEIGHT/2+7);
  482. g.DrawLine(darkPen, pt1, pt2);
  483. // Cleanup 
  484. lightPen.Dispose();
  485. darkPen.Dispose();
  486. }
  487. Rectangle GetArrowButtonRectangle( bool upButton)
  488. {
  489. Rectangle rc = ClientRectangle;
  490. if ( upButton )
  491. {
  492. return new Rectangle(0, rc.Top,
  493. VThumb, VThumb);
  494. }
  495. else
  496. {
  497. return new Rectangle(0, rc.Bottom-VThumb,
  498. VThumb, VThumb);
  499. }
  500. }
  501. protected override Rectangle GetThumbRect()
  502. {
  503. double thumbHeight = GetThumbPixelSize();
  504. int drawPos = 0;
  505. if ( draggingThumb  ) 
  506. {
  507. // If dragging the thumb don't use
  508. // a position based on the scaled calculation
  509. // but the actual one from the OnMouseMove event
  510. // to avoid jerkiness from rounding off errors
  511. drawPos = GetSafeThumbPixelPos((int)thumbHeight);
  512. }
  513. else
  514. {
  515. drawPos = (int)GetThumbPixelPosition(pos);
  516. }
  517. // To avoid rounding off errors
  518. if ( pos == max-largeChange )
  519. {
  520. drawPos = ClientRectangle.Height - VThumb - (int)thumbHeight;
  521. }
  522. Rectangle rc = Rectangle.Empty;
  523. // If width is too small, don't let it disappear
  524. if ( thumbHeight < MINIMUM_THUMB_HEIGHT )
  525. thumbHeight = MINIMUM_THUMB_HEIGHT;
  526. // Smaller than the total width of the scrollbar
  527. // to make it look nicer
  528. rc = new Rectangle(0, drawPos, VThumb, (int)thumbHeight);
  529. rc.Inflate(-1, 0);
  530. return rc;
  531. }
  532. int GetSafeThumbPixelPos(int thumbHeight)
  533. {
  534. if ( thumbPixelPos > (ClientRectangle.Height - VThumb)-thumbHeight) 
  535. {
  536. // Position cannot be larger than
  537. // max-largeChange
  538. return (ClientRectangle.Height - VThumb)-thumbHeight;
  539. }
  540. else if ( thumbPixelPos <= VThumb )
  541. {
  542. // Negative values don't make sense
  543. return VThumb;
  544. }
  545. else
  546. return (int)thumbPixelPos;
  547. }
  548. Rectangle GetPageRect(bool up)
  549. {
  550. Rectangle rcClient = ClientRectangle;
  551. Rectangle rcThumb = GetThumbRect();
  552. Rectangle pageRect;
  553. if ( up )
  554. {
  555. pageRect = new Rectangle(rcClient.Left, 
  556. rcClient.Top+VThumb+1, rcClient.Width, rcThumb.Top-VThumb-2);
  557. }
  558. else
  559. {
  560. pageRect = new Rectangle(rcClient.Left, 
  561. rcThumb.Bottom+1, rcClient.Width, rcClient.Bottom-VThumb-1);
  562. }
  563. return pageRect;
  564. }
  565. double GetThumbPixelSize()
  566. {
  567. Rectangle rc =ClientRectangle;
  568. int height = rc.Height - VThumb*2;
  569. if ( largeChange == 0 || (max-min) == 0)
  570. return 0;
  571. float numOfPages = (float)(max-min)/(float)largeChange;
  572. return height/numOfPages;                         
  573. }
  574. double GetThumbPixelPosition(double logicalPos)
  575. {
  576. double fHeight = ClientRectangle.Height - VThumb*2;
  577. double fRange = (max-min);
  578. double fLogicalPos = logicalPos;
  579. return (fLogicalPos*fHeight)/fRange + VThumb;
  580. }
  581. double GetThumbLogicalPosition(double pixelPos)
  582. {
  583. double fHeight = ClientRectangle.Height - VThumb*2;
  584. double fRange = (max-min);
  585. double fpixelPos = pixelPos;
  586. return (fRange*(fpixelPos-VThumb)/fHeight);
  587. }
  588. ScrollBarHit HitTest(Point point)
  589. {
  590. Rectangle upArrow = GetArrowButtonRectangle(true);
  591. if ( upArrow.Contains(point) )
  592. return ScrollBarHit.UpArrow;
  593. Rectangle downArrow = GetArrowButtonRectangle(false);
  594. if ( downArrow.Contains(point) )
  595. return ScrollBarHit.DownArrow;
  596. Rectangle upPageRect = GetPageRect(true);
  597. if ( upPageRect.Contains(point) )
  598. return ScrollBarHit.PageUp;
  599. Rectangle downPageRect = GetPageRect(false);
  600. if ( downPageRect.Contains(point) )
  601. return ScrollBarHit.PageDown;
  602. Rectangle thumbRect = GetThumbRect();
  603. if ( thumbRect.Contains(point) )
  604. return ScrollBarHit.Thumb;
  605.             
  606. return ScrollBarHit.None;
  607. }
  608. #endregion
  609. }
  610. }