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-2005, Novell, Inc. 24 // 25 // Authors: 26 // Jordi Mas i Hernandez jordi@ximian.com 27 // 28 // 29 30 // COMPLETE 31 32 using System.Drawing; 33 using System.Drawing.Imaging; 34 using System.Drawing.Drawing2D; 35 using System.ComponentModel; 36 using System.Runtime.InteropServices; 37 38 namespace System.Windows.Forms 39 { 40 [ComVisible (true)] 41 [ClassInterface (ClassInterfaceType.AutoDispatch)] 42 [DefaultEvent ("Scroll")] 43 [DefaultProperty ("Value")] 44 public abstract class ScrollBar : Control 45 { 46 #region Local Variables 47 private int position; 48 private int minimum; 49 private int maximum; 50 private int large_change; 51 private int small_change; 52 internal int scrollbutton_height; 53 internal int scrollbutton_width; 54 private Rectangle first_arrow_area = new Rectangle (); // up or left 55 private Rectangle second_arrow_area = new Rectangle (); // down or right 56 private Rectangle thumb_pos = new Rectangle (); 57 private Rectangle thumb_area = new Rectangle (); 58 internal ButtonState firstbutton_state = ButtonState.Normal; 59 internal ButtonState secondbutton_state = ButtonState.Normal; 60 private bool firstbutton_pressed = false; 61 private bool secondbutton_pressed = false; 62 private bool thumb_pressed = false; 63 private float pixel_per_pos = 0; 64 private Timer timer = new Timer (); 65 private TimerType timer_type; 66 private int thumb_size = 40; 67 private const int thumb_min_size = 8; 68 private const int thumb_notshown_size = 40; 69 internal bool use_manual_thumb_size; 70 internal int manual_thumb_size; 71 internal bool vert; 72 internal bool implicit_control; 73 private int lastclick_pos; // Position of the last button-down event 74 private int thumbclick_offset; // Position of the last button-down event relative to the thumb edge 75 private Rectangle dirty; 76 77 internal ThumbMoving thumb_moving = ThumbMoving.None; 78 bool first_button_entered; 79 bool second_button_entered; 80 bool thumb_entered; 81 #endregion // Local Variables 82 83 private enum TimerType 84 { 85 HoldButton, 86 RepeatButton, 87 HoldThumbArea, 88 RepeatThumbArea 89 } 90 91 internal enum ThumbMoving 92 { 93 None, 94 Forward, 95 Backwards, 96 } 97 98 #region events 99 [Browsable (false)] 100 [EditorBrowsable (EditorBrowsableState.Never)] 101 public new event EventHandler AutoSizeChanged { 102 add { base.AutoSizeChanged += value; } 103 remove { base.AutoSizeChanged -= value; } 104 } 105 106 [Browsable (false)] 107 [EditorBrowsable (EditorBrowsableState.Never)] 108 public new event EventHandler BackColorChanged { 109 add { base.BackColorChanged += value; } 110 remove { base.BackColorChanged -= value; } 111 } 112 113 [Browsable (false)] 114 [EditorBrowsable (EditorBrowsableState.Never)] 115 public new event EventHandler BackgroundImageChanged { 116 add { base.BackgroundImageChanged += value; } 117 remove { base.BackgroundImageChanged -= value; } 118 } 119 120 [Browsable (false)] 121 [EditorBrowsable (EditorBrowsableState.Never)] 122 public new event EventHandler BackgroundImageLayoutChanged { 123 add { base.BackgroundImageLayoutChanged += value; } 124 remove { base.BackgroundImageLayoutChanged -= value; } 125 } 126 127 [Browsable (false)] 128 [EditorBrowsable (EditorBrowsableState.Never)] 129 public new event EventHandler Click { 130 add { base.Click += value; } 131 remove { base.Click -= value; } 132 } 133 134 [Browsable (false)] 135 [EditorBrowsable (EditorBrowsableState.Never)] 136 public new event EventHandler DoubleClick { 137 add { base.DoubleClick += value; } 138 remove { base.DoubleClick -= value; } 139 } 140 141 [Browsable (false)] 142 [EditorBrowsable (EditorBrowsableState.Never)] 143 public new event EventHandler FontChanged { 144 add { base.FontChanged += value; } 145 remove { base.FontChanged -= value; } 146 } 147 148 [Browsable (false)] 149 [EditorBrowsable (EditorBrowsableState.Never)] 150 public new event EventHandler ForeColorChanged { 151 add { base.ForeColorChanged += value; } 152 remove { base.ForeColorChanged -= value; } 153 } 154 155 [Browsable (false)] 156 [EditorBrowsable (EditorBrowsableState.Never)] 157 public new event EventHandler ImeModeChanged { 158 add { base.ImeModeChanged += value; } 159 remove { base.ImeModeChanged -= value; } 160 } 161 162 [Browsable (false)] 163 [EditorBrowsable (EditorBrowsableState.Never)] 164 public new event MouseEventHandler MouseClick { 165 add { base.MouseClick += value; } 166 remove { base.MouseClick -= value; } 167 } 168 169 [Browsable (false)] 170 [EditorBrowsable (EditorBrowsableState.Never)] 171 public new event MouseEventHandler MouseDoubleClick { 172 add { base.MouseDoubleClick += value; } 173 remove { base.MouseDoubleClick -= value; } 174 } 175 176 [Browsable (false)] 177 [EditorBrowsable (EditorBrowsableState.Never)] 178 public new event MouseEventHandler MouseDown { 179 add { base.MouseDown += value; } 180 remove { base.MouseDown -= value; } 181 } 182 183 [Browsable (false)] 184 [EditorBrowsable (EditorBrowsableState.Never)] 185 public new event MouseEventHandler MouseMove { 186 add { base.MouseMove += value; } 187 remove { base.MouseMove -= value; } 188 } 189 190 [Browsable (false)] 191 [EditorBrowsable (EditorBrowsableState.Never)] 192 public new event MouseEventHandler MouseUp { 193 add { base.MouseUp += value; } 194 remove { base.MouseUp -= value; } 195 } 196 197 [Browsable (false)] 198 [EditorBrowsable (EditorBrowsableState.Never)] 199 public new event PaintEventHandler Paint { 200 add { base.Paint += value; } 201 remove { base.Paint -= value; } 202 } 203 204 static object ScrollEvent = new object (); 205 static object ValueChangedEvent = new object (); 206 207 public event ScrollEventHandler Scroll { 208 add { Events.AddHandler (ScrollEvent, value); } 209 remove { Events.RemoveHandler (ScrollEvent, value); } 210 } 211 212 [Browsable (false)] 213 [EditorBrowsable (EditorBrowsableState.Never)] 214 public new event EventHandler TextChanged { 215 add { base.TextChanged += value; } 216 remove { base.TextChanged -= value; } 217 } 218 219 public event EventHandler ValueChanged { 220 add { Events.AddHandler (ValueChangedEvent, value); } 221 remove { Events.RemoveHandler (ValueChangedEvent, value); } 222 } 223 #endregion Events 224 ScrollBar()225 public ScrollBar () 226 { 227 position = 0; 228 minimum = 0; 229 maximum = 100; 230 large_change = 10; 231 small_change = 1; 232 233 timer.Tick += new EventHandler (OnTimer); 234 MouseEnter += new EventHandler (OnMouseEnter); 235 MouseLeave += new EventHandler (OnMouseLeave); 236 base.KeyDown += new KeyEventHandler (OnKeyDownSB); 237 base.MouseDown += new MouseEventHandler (OnMouseDownSB); 238 base.MouseUp += new MouseEventHandler (OnMouseUpSB); 239 base.MouseMove += new MouseEventHandler (OnMouseMoveSB); 240 base.Resize += new EventHandler (OnResizeSB); 241 base.TabStop = false; 242 base.Cursor = Cursors.Default; 243 244 SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick | ControlStyles.UseTextForAccessibility, false); 245 } 246 247 #region Internal & Private Properties 248 internal Rectangle FirstArrowArea { 249 get { 250 return this.first_arrow_area; 251 } 252 253 set { 254 this.first_arrow_area = value; 255 } 256 } 257 258 internal Rectangle SecondArrowArea { 259 get { 260 return this.second_arrow_area; 261 } 262 263 set { 264 this.second_arrow_area = value; 265 } 266 } 267 268 int MaximumAllowed { 269 get { 270 return use_manual_thumb_size ? maximum - manual_thumb_size + 1 : 271 maximum - LargeChange + 1; 272 } 273 } 274 275 internal Rectangle ThumbPos { 276 get { 277 return thumb_pos; 278 } 279 280 set { 281 thumb_pos = value; 282 } 283 } 284 285 internal bool FirstButtonEntered { 286 get { return first_button_entered; } 287 private set { 288 if (first_button_entered == value) 289 return; 290 first_button_entered = value; 291 if (ThemeEngine.Current.ScrollBarHasHotElementStyles) 292 Invalidate (first_arrow_area); 293 } 294 } 295 296 internal bool SecondButtonEntered { 297 get { return second_button_entered; } 298 private set { 299 if (second_button_entered == value) 300 return; 301 second_button_entered = value; 302 if (ThemeEngine.Current.ScrollBarHasHotElementStyles) 303 Invalidate (second_arrow_area); 304 } 305 } 306 307 internal bool ThumbEntered { 308 get { return thumb_entered; } 309 private set { 310 if (thumb_entered == value) 311 return; 312 thumb_entered = value; 313 if (ThemeEngine.Current.ScrollBarHasHotElementStyles) 314 Invalidate (thumb_pos); 315 } 316 } 317 318 internal bool ThumbPressed { 319 get { return thumb_pressed; } 320 private set { 321 if (thumb_pressed == value) 322 return; 323 thumb_pressed = value; 324 if (ThemeEngine.Current.ScrollBarHasPressedThumbStyle) 325 Invalidate (thumb_pos); 326 } 327 } 328 329 #endregion // Internal & Private Properties 330 331 #region Public Properties 332 [EditorBrowsable (EditorBrowsableState.Never)] 333 [Browsable (false)] 334 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 335 public override bool AutoSize { 336 get { return base.AutoSize; } 337 set { base.AutoSize = value; } 338 } 339 340 [EditorBrowsable (EditorBrowsableState.Never)] 341 [Browsable (false)] 342 public override Color BackColor 343 { 344 get { return base.BackColor; } 345 set { 346 if (base.BackColor == value) 347 return; 348 base.BackColor = value; 349 Refresh (); 350 } 351 } 352 353 [EditorBrowsable (EditorBrowsableState.Never)] 354 [Browsable (false)] 355 public override Image BackgroundImage 356 { 357 get { return base.BackgroundImage; } 358 set { 359 if (base.BackgroundImage == value) 360 return; 361 362 base.BackgroundImage = value; 363 } 364 } 365 366 [EditorBrowsable (EditorBrowsableState.Never)] 367 [Browsable (false)] 368 public override ImageLayout BackgroundImageLayout { 369 get { return base.BackgroundImageLayout; } 370 set { base.BackgroundImageLayout = value; } 371 } 372 373 protected override CreateParams CreateParams 374 { 375 get { return base.CreateParams; } 376 } 377 378 protected override Padding DefaultMargin { 379 get { return Padding.Empty; } 380 } 381 382 protected override ImeMode DefaultImeMode 383 { 384 get { return ImeMode.Disable; } 385 } 386 387 [EditorBrowsable (EditorBrowsableState.Never)] 388 [Browsable (false)] 389 public override Font Font 390 { 391 get { return base.Font; } 392 set { 393 if (base.Font.Equals (value)) 394 return; 395 396 base.Font = value; 397 } 398 } 399 400 [EditorBrowsable (EditorBrowsableState.Never)] 401 [Browsable (false)] 402 public override Color ForeColor 403 { 404 get { return base.ForeColor; } 405 set { 406 if (base.ForeColor == value) 407 return; 408 409 base.ForeColor = value; 410 Refresh (); 411 } 412 } 413 414 [EditorBrowsable (EditorBrowsableState.Never)] 415 [Browsable (false)] 416 public new ImeMode ImeMode 417 { 418 get { return base.ImeMode; } 419 set { 420 if (base.ImeMode == value) 421 return; 422 423 base.ImeMode = value; 424 } 425 } 426 427 [DefaultValue (10)] 428 [RefreshProperties(RefreshProperties.Repaint)] 429 [MWFDescription("Scroll amount when clicking in the scroll area"), MWFCategory("Behaviour")] 430 public int LargeChange { 431 get { return Math.Min (large_change, maximum - minimum + 1); } 432 set { 433 if (value < 0) 434 throw new ArgumentOutOfRangeException ("LargeChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value)); 435 436 if (large_change != value) { 437 large_change = value; 438 439 // thumb area depends on large change value, 440 // so we need to recalculate it. 441 CalcThumbArea (); 442 UpdatePos (Value, true); 443 InvalidateDirty (); 444 445 // UIA Framework: Generate UIA Event to indicate LargeChange change 446 OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.LargeIncrement, value)); 447 } 448 } 449 } 450 451 [DefaultValue (100)] 452 [RefreshProperties(RefreshProperties.Repaint)] 453 [MWFDescription("Highest value for scrollbar"), MWFCategory("Behaviour")] 454 public int Maximum { 455 get { return maximum; } 456 set { 457 if (maximum == value) 458 return; 459 460 maximum = value; 461 462 // UIA Framework: Generate UIA Event to indicate Maximum change 463 OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.Last, value)); 464 465 if (maximum < minimum) 466 minimum = maximum; 467 if (Value > maximum) 468 Value = maximum; 469 470 // thumb area depends on maximum value, 471 // so we need to recalculate it. 472 CalcThumbArea (); 473 UpdatePos (Value, true); 474 InvalidateDirty (); 475 } 476 } 477 SetValues(int maximum, int large_change)478 internal void SetValues (int maximum, int large_change) 479 { 480 SetValues (-1, maximum, -1, large_change); 481 } 482 SetValues(int minimum, int maximum, int small_change, int large_change)483 internal void SetValues (int minimum, int maximum, int small_change, int large_change) 484 { 485 bool update = false; 486 487 if (-1 != minimum && this.minimum != minimum) { 488 this.minimum = minimum; 489 490 if (minimum > this.maximum) 491 this.maximum = minimum; 492 update = true; 493 494 // change the position if it is out of range now 495 position = Math.Max (position, minimum); 496 } 497 498 if (-1 != maximum && this.maximum != maximum) { 499 this.maximum = maximum; 500 501 if (maximum < this.minimum) 502 this.minimum = maximum; 503 update = true; 504 505 // change the position if it is out of range now 506 position = Math.Min (position, maximum); 507 } 508 509 if (-1 != small_change && this.small_change != small_change) { 510 this.small_change = small_change; 511 } 512 513 if (this.large_change != large_change) { 514 this.large_change = large_change; 515 update = true; 516 } 517 518 if (update) { 519 CalcThumbArea (); 520 UpdatePos (Value, true); 521 InvalidateDirty (); 522 } 523 } 524 525 [DefaultValue (0)] 526 [RefreshProperties(RefreshProperties.Repaint)] 527 [MWFDescription("Smallest value for scrollbar"), MWFCategory("Behaviour")] 528 public int Minimum { 529 get { return minimum; } 530 set { 531 if (minimum == value) 532 return; 533 534 minimum = value; 535 536 // UIA Framework: Generate UIA Event to indicate Minimum change 537 OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.First, value)); 538 539 if (minimum > maximum) 540 maximum = minimum; 541 542 // thumb area depends on minimum value, 543 // so we need to recalculate it. 544 CalcThumbArea (); 545 UpdatePos (Value, true); 546 InvalidateDirty (); 547 } 548 } 549 550 [DefaultValue (1)] 551 [MWFDescription("Scroll amount when clicking scroll arrows"), MWFCategory("Behaviour")] 552 public int SmallChange { 553 get { return small_change > LargeChange ? LargeChange : small_change; } 554 set { 555 if ( value < 0 ) 556 throw new ArgumentOutOfRangeException ("SmallChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value)); 557 558 if (small_change != value) { 559 small_change = value; 560 UpdatePos (Value, true); 561 InvalidateDirty (); 562 563 // UIA Framework: Generate UIA Event to indicate SmallChange change 564 OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.SmallIncrement, value)); 565 } 566 } 567 } 568 569 [DefaultValue (false)] 570 public new bool TabStop { 571 get { return base.TabStop; } 572 set { base.TabStop = value; } 573 } 574 575 [EditorBrowsable (EditorBrowsableState.Never)] 576 [Bindable (false)] 577 [Browsable (false)] 578 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] 579 public override string Text { 580 get { return base.Text; } 581 set { base.Text = value; } 582 } 583 584 [Bindable(true)] 585 [DefaultValue (0)] 586 [MWFDescription("Current value for scrollbar"), MWFCategory("Behaviour")] 587 public int Value { 588 get { return position; } 589 set { 590 if ( value < minimum || value > maximum ) 591 throw new ArgumentOutOfRangeException ("Value", string.Format ("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value)); 592 593 if (position != value){ 594 position = value; 595 596 OnValueChanged (EventArgs.Empty); 597 598 if (IsHandleCreated) { 599 Rectangle thumb_rect = thumb_pos; 600 601 UpdateThumbPos ((vert ? thumb_area.Y : thumb_area.X) + (int)(((float)(position - minimum)) * pixel_per_pos), false, false); 602 603 MoveThumb (thumb_rect, vert ? thumb_pos.Y : thumb_pos.X); 604 } 605 } 606 } 607 } 608 609 #endregion //Public Properties 610 611 #region Public Methods GetScaledBounds(Rectangle bounds, SizeF factor, BoundsSpecified specified)612 protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified) 613 { 614 // Basically, we want to keep our small edge and scale the long edge 615 // ie: if we are vertical, don't scale our width 616 if (vert) 617 return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Height) | (specified & BoundsSpecified.Location)); 618 else 619 return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Width) | (specified & BoundsSpecified.Location)); 620 } 621 OnEnabledChanged(EventArgs e)622 protected override void OnEnabledChanged (EventArgs e) 623 { 624 base.OnEnabledChanged (e); 625 626 if (Enabled) 627 firstbutton_state = secondbutton_state = ButtonState.Normal; 628 else 629 firstbutton_state = secondbutton_state = ButtonState.Inactive; 630 631 Refresh (); 632 } 633 OnHandleCreated(System.EventArgs e)634 protected override void OnHandleCreated (System.EventArgs e) 635 { 636 base.OnHandleCreated (e); 637 638 CalcButtonSizes (); 639 CalcThumbArea (); 640 UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), true, false); 641 } 642 OnScroll(ScrollEventArgs se)643 protected virtual void OnScroll (ScrollEventArgs se) 644 { 645 ScrollEventHandler eh = (ScrollEventHandler)(Events [ScrollEvent]); 646 if (eh == null) 647 return; 648 649 if (se.NewValue < Minimum) { 650 se.NewValue = Minimum; 651 } 652 653 if (se.NewValue > Maximum) { 654 se.NewValue = Maximum; 655 } 656 657 eh (this, se); 658 } 659 SendWMScroll(ScrollBarCommands cmd)660 private void SendWMScroll(ScrollBarCommands cmd) { 661 if ((Parent != null) && Parent.IsHandleCreated) { 662 if (vert) { 663 XplatUI.SendMessage(Parent.Handle, Msg.WM_VSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle); 664 } else { 665 XplatUI.SendMessage(Parent.Handle, Msg.WM_HSCROLL, (IntPtr)cmd, implicit_control ? IntPtr.Zero : Handle); 666 } 667 } 668 } 669 OnValueChanged(EventArgs e)670 protected virtual void OnValueChanged (EventArgs e) 671 { 672 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); 673 if (eh != null) 674 eh (this, e); 675 } 676 ToString()677 public override string ToString() 678 { 679 return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}", 680 GetType( ).FullName, minimum, maximum, position); 681 } 682 UpdateScrollInfo()683 protected void UpdateScrollInfo () 684 { 685 Refresh (); 686 } 687 WndProc(ref Message m)688 protected override void WndProc (ref Message m) 689 { 690 base.WndProc (ref m); 691 } 692 693 #endregion //Public Methods 694 695 #region Private Methods 696 CalcButtonSizes()697 private void CalcButtonSizes () 698 { 699 if (vert) { 700 if (Height < ThemeEngine.Current.ScrollBarButtonSize * 2) 701 scrollbutton_height = Height /2; 702 else 703 scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize; 704 705 } else { 706 if (Width < ThemeEngine.Current.ScrollBarButtonSize * 2) 707 scrollbutton_width = Width /2; 708 else 709 scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize; 710 } 711 } 712 CalcThumbArea()713 private void CalcThumbArea () 714 { 715 int lchange = use_manual_thumb_size ? manual_thumb_size : LargeChange; 716 717 // Thumb area 718 if (vert) { 719 720 thumb_area.Height = Height - scrollbutton_height - scrollbutton_height; 721 thumb_area.X = 0; 722 thumb_area.Y = scrollbutton_height; 723 thumb_area.Width = Width; 724 725 if (Height < thumb_notshown_size) 726 thumb_size = 0; 727 else { 728 double per = ((double) lchange / (double)((1 + maximum - minimum))); 729 thumb_size = 1 + (int) (thumb_area.Height * per); 730 731 if (thumb_size < thumb_min_size) 732 thumb_size = thumb_min_size; 733 734 // Give the user something to drag if LargeChange is zero 735 if (LargeChange == 0) 736 thumb_size = 17; 737 } 738 739 pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - lchange) + 1)); 740 741 } else { 742 743 thumb_area.Y = 0; 744 thumb_area.X = scrollbutton_width; 745 thumb_area.Height = Height; 746 thumb_area.Width = Width - scrollbutton_width - scrollbutton_width; 747 748 if (Width < thumb_notshown_size) 749 thumb_size = 0; 750 else { 751 double per = ((double) lchange / (double)((1 + maximum - minimum))); 752 thumb_size = 1 + (int) (thumb_area.Width * per); 753 754 if (thumb_size < thumb_min_size) 755 thumb_size = thumb_min_size; 756 757 // Give the user something to drag if LargeChange is zero 758 if (LargeChange == 0) 759 thumb_size = 17; 760 } 761 762 pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - lchange) + 1)); 763 } 764 } 765 LargeIncrement()766 private void LargeIncrement () 767 { 768 ScrollEventArgs event_args; 769 int pos = Math.Min (MaximumAllowed, position + large_change); 770 771 event_args = new ScrollEventArgs (ScrollEventType.LargeIncrement, pos); 772 OnScroll (event_args); 773 Value = event_args.NewValue; 774 775 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); 776 OnScroll (event_args); 777 Value = event_args.NewValue; 778 779 // UIA Framework event invoked when the "LargeIncrement 780 // Button" is "clicked" either by using the Invoke Pattern 781 // or the space between the thumb and the bottom/right button 782 OnUIAScroll (new ScrollEventArgs (ScrollEventType.LargeIncrement, Value)); 783 } 784 LargeDecrement()785 private void LargeDecrement () 786 { 787 ScrollEventArgs event_args; 788 int pos = Math.Max (Minimum, position - large_change); 789 790 event_args = new ScrollEventArgs (ScrollEventType.LargeDecrement, pos); 791 OnScroll (event_args); 792 Value = event_args.NewValue; 793 794 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); 795 OnScroll (event_args); 796 Value = event_args.NewValue; 797 798 // UIA Framework event invoked when the "LargeDecrement 799 // Button" is "clicked" either by using the Invoke Pattern 800 // or the space between the thumb and the top/left button 801 OnUIAScroll (new ScrollEventArgs (ScrollEventType.LargeDecrement, Value)); 802 } 803 OnResizeSB(Object o, EventArgs e)804 private void OnResizeSB (Object o, EventArgs e) 805 { 806 if (Width <= 0 || Height <= 0) 807 return; 808 809 CalcButtonSizes (); 810 CalcThumbArea (); 811 UpdatePos (position, true); 812 813 Refresh (); 814 } 815 OnPaintInternal(PaintEventArgs pevent)816 internal override void OnPaintInternal (PaintEventArgs pevent) 817 { 818 ThemeEngine.Current.DrawScrollBar (pevent.Graphics, pevent.ClipRectangle, this); 819 } 820 OnTimer(Object source, EventArgs e)821 private void OnTimer (Object source, EventArgs e) 822 { 823 ClearDirty (); 824 825 switch (timer_type) { 826 827 case TimerType.HoldButton: 828 SetRepeatButtonTimer (); 829 break; 830 831 case TimerType.RepeatButton: 832 { 833 if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Minimum) { 834 SmallDecrement(); 835 SendWMScroll(ScrollBarCommands.SB_LINEUP); 836 } 837 838 if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Maximum) { 839 SmallIncrement(); 840 SendWMScroll(ScrollBarCommands.SB_LINEDOWN); 841 } 842 843 break; 844 } 845 846 case TimerType.HoldThumbArea: 847 SetRepeatThumbAreaTimer (); 848 break; 849 850 case TimerType.RepeatThumbArea: 851 { 852 Point pnt, pnt_screen; 853 Rectangle thumb_area_screen = thumb_area; 854 855 pnt_screen = PointToScreen (new Point (thumb_area.X, thumb_area.Y)); 856 thumb_area_screen.X = pnt_screen.X; 857 thumb_area_screen.Y = pnt_screen.Y; 858 859 if (thumb_area_screen.Contains (MousePosition) == false) { 860 timer.Enabled = false; 861 thumb_moving = ThumbMoving.None; 862 DirtyThumbArea (); 863 InvalidateDirty (); 864 } 865 866 pnt = PointToClient (MousePosition); 867 868 if (vert) 869 lastclick_pos = pnt.Y; 870 else 871 lastclick_pos = pnt.X; 872 873 if (thumb_moving == ThumbMoving.Forward) { 874 if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) || 875 (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) || 876 (thumb_area.Contains (pnt) == false)) { 877 timer.Enabled = false; 878 thumb_moving = ThumbMoving.None; 879 Refresh (); 880 return; 881 } else { 882 LargeIncrement (); 883 SendWMScroll(ScrollBarCommands.SB_PAGEDOWN); 884 } 885 } else { 886 if ((vert && (thumb_pos.Y < lastclick_pos)) || 887 (!vert && (thumb_pos.X < lastclick_pos))){ 888 timer.Enabled = false; 889 thumb_moving = ThumbMoving.None; 890 SendWMScroll(ScrollBarCommands.SB_PAGEUP); 891 Refresh (); 892 } else { 893 LargeDecrement (); 894 SendWMScroll(ScrollBarCommands.SB_PAGEUP); 895 } 896 } 897 898 break; 899 } 900 default: 901 break; 902 } 903 904 InvalidateDirty (); 905 } 906 MoveThumb(Rectangle original_thumbpos, int value)907 private void MoveThumb (Rectangle original_thumbpos, int value) 908 { 909 /* so, the reason this works can best be 910 * described by the following 1 dimensional 911 * pictures 912 * 913 * say you have a scrollbar thumb positioned 914 * thusly: 915 * 916 * <---------------------| |------------------------------> 917 * 918 * and you want it to end up looking like this: 919 * 920 * <-----------------------------| |----------------------> 921 * 922 * that can be done with the scrolling api by 923 * extending the rectangle to encompass both 924 * positions: 925 * 926 * start of range end of range 927 * \ / 928 * <---------------------| |-------|----------------------> 929 * 930 * so, we end up scrolling just this little region: 931 * 932 * | |-------| 933 * 934 * and end up with ********| | 935 * 936 * where ****** is space that is automatically 937 * redrawn. 938 * 939 * It's clear that in both cases (left to 940 * right, right to left) we need to extend the 941 * size of the scroll rectangle to encompass 942 * both. In the right to left case, we also 943 * need to decrement the X coordinate. 944 * 945 * We call Update after scrolling to make sure 946 * there's no garbage left in the window to be 947 * copied again if we're called before the 948 * paint events have been handled. 949 * 950 */ 951 int delta; 952 953 if (vert) { 954 delta = value - original_thumbpos.Y; 955 956 if (delta < 0) { 957 original_thumbpos.Y += delta; 958 original_thumbpos.Height -= delta; 959 } 960 else { 961 original_thumbpos.Height += delta; 962 } 963 964 XplatUI.ScrollWindow (Handle, original_thumbpos, 0, delta, false); 965 } 966 else { 967 delta = value - original_thumbpos.X; 968 969 if (delta < 0) { 970 original_thumbpos.X += delta; 971 original_thumbpos.Width -= delta; 972 } 973 else { 974 original_thumbpos.Width += delta; 975 } 976 977 XplatUI.ScrollWindow (Handle, original_thumbpos, delta, 0, false); 978 } 979 980 Update (); 981 } 982 OnMouseMoveSB(object sender, MouseEventArgs e)983 private void OnMouseMoveSB (object sender, MouseEventArgs e) 984 { 985 if (Enabled == false) 986 return; 987 988 FirstButtonEntered = first_arrow_area.Contains (e.Location); 989 SecondButtonEntered = second_arrow_area.Contains (e.Location); 990 991 if (thumb_size == 0) 992 return; 993 994 ThumbEntered = thumb_pos.Contains (e.Location); 995 996 if (firstbutton_pressed) { 997 if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) { 998 firstbutton_state = ButtonState.Normal; 999 Invalidate (first_arrow_area); 1000 Update(); 1001 return; 1002 } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) { 1003 firstbutton_state = ButtonState.Pushed; 1004 Invalidate (first_arrow_area); 1005 Update(); 1006 return; 1007 } 1008 } else if (secondbutton_pressed) { 1009 if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) { 1010 secondbutton_state = ButtonState.Normal; 1011 Invalidate (second_arrow_area); 1012 Update(); 1013 return; 1014 } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) { 1015 secondbutton_state = ButtonState.Pushed; 1016 Invalidate (second_arrow_area); 1017 Update(); 1018 return; 1019 } 1020 } else if (thumb_pressed == true) { 1021 if (vert) { 1022 int thumb_edge = e.Y - thumbclick_offset; 1023 1024 if (thumb_edge < thumb_area.Y) 1025 thumb_edge = thumb_area.Y; 1026 else if (thumb_edge > thumb_area.Bottom - thumb_size) 1027 thumb_edge = thumb_area.Bottom - thumb_size; 1028 1029 if (thumb_edge != thumb_pos.Y) { 1030 Rectangle thumb_rect = thumb_pos; 1031 1032 UpdateThumbPos (thumb_edge, false, true); 1033 1034 MoveThumb (thumb_rect, thumb_pos.Y); 1035 1036 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position)); 1037 } 1038 SendWMScroll(ScrollBarCommands.SB_THUMBTRACK); 1039 } else { 1040 int thumb_edge = e.X - thumbclick_offset; 1041 1042 if (thumb_edge < thumb_area.X) 1043 thumb_edge = thumb_area.X; 1044 else if (thumb_edge > thumb_area.Right - thumb_size) 1045 thumb_edge = thumb_area.Right - thumb_size; 1046 1047 if (thumb_edge != thumb_pos.X) { 1048 Rectangle thumb_rect = thumb_pos; 1049 1050 UpdateThumbPos (thumb_edge, false, true); 1051 1052 MoveThumb (thumb_rect, thumb_pos.X); 1053 1054 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position)); 1055 } 1056 SendWMScroll(ScrollBarCommands.SB_THUMBTRACK); 1057 } 1058 1059 } 1060 1061 } 1062 OnMouseDownSB(object sender, MouseEventArgs e)1063 private void OnMouseDownSB (object sender, MouseEventArgs e) 1064 { 1065 ClearDirty (); 1066 1067 if (Enabled == false || (e.Button & MouseButtons.Left) == 0) 1068 return; 1069 1070 if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) { 1071 SendWMScroll(ScrollBarCommands.SB_LINEUP); 1072 firstbutton_state = ButtonState.Pushed; 1073 firstbutton_pressed = true; 1074 Invalidate (first_arrow_area); 1075 Update(); 1076 if (!timer.Enabled) { 1077 SetHoldButtonClickTimer (); 1078 timer.Enabled = true; 1079 } 1080 } 1081 1082 if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) { 1083 SendWMScroll(ScrollBarCommands.SB_LINEDOWN); 1084 secondbutton_state = ButtonState.Pushed; 1085 secondbutton_pressed = true; 1086 Invalidate (second_arrow_area); 1087 Update(); 1088 if (!timer.Enabled) { 1089 SetHoldButtonClickTimer (); 1090 timer.Enabled = true; 1091 } 1092 } 1093 1094 if (thumb_size > 0 && thumb_pos.Contains (e.X, e.Y)) { 1095 ThumbPressed = true; 1096 SendWMScroll(ScrollBarCommands.SB_THUMBTRACK); 1097 if (vert) { 1098 thumbclick_offset = e.Y - thumb_pos.Y; 1099 lastclick_pos = e.Y; 1100 } 1101 else { 1102 thumbclick_offset = e.X - thumb_pos.X; 1103 lastclick_pos = e.X; 1104 } 1105 } else { 1106 if (thumb_size > 0 && thumb_area.Contains (e.X, e.Y)) { 1107 1108 if (vert) { 1109 lastclick_pos = e.Y; 1110 1111 if (e.Y > thumb_pos.Y + thumb_pos.Height) { 1112 SendWMScroll(ScrollBarCommands.SB_PAGEDOWN); 1113 LargeIncrement (); 1114 thumb_moving = ThumbMoving.Forward; 1115 Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height, 1116 ClientRectangle.Width, 1117 ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) - 1118 scrollbutton_height)); 1119 } else { 1120 SendWMScroll(ScrollBarCommands.SB_PAGEUP); 1121 LargeDecrement (); 1122 thumb_moving = ThumbMoving.Backwards; 1123 Dirty (new Rectangle (0, scrollbutton_height, 1124 ClientRectangle.Width, 1125 thumb_pos.Y - scrollbutton_height)); 1126 } 1127 } else { 1128 1129 lastclick_pos = e.X; 1130 1131 if (e.X > thumb_pos.X + thumb_pos.Width) { 1132 SendWMScroll(ScrollBarCommands.SB_PAGEDOWN); 1133 thumb_moving = ThumbMoving.Forward; 1134 LargeIncrement (); 1135 Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0, 1136 ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) - 1137 scrollbutton_width, 1138 ClientRectangle.Height)); 1139 } else { 1140 SendWMScroll(ScrollBarCommands.SB_PAGEUP); 1141 thumb_moving = ThumbMoving.Backwards; 1142 LargeDecrement (); 1143 Dirty (new Rectangle (scrollbutton_width, 0, 1144 thumb_pos.X - scrollbutton_width, 1145 ClientRectangle.Height)); 1146 } 1147 } 1148 1149 SetHoldThumbAreaTimer (); 1150 timer.Enabled = true; 1151 InvalidateDirty (); 1152 } 1153 } 1154 } 1155 OnMouseUpSB(object sender, MouseEventArgs e)1156 private void OnMouseUpSB (object sender, MouseEventArgs e) 1157 { 1158 ClearDirty (); 1159 1160 if (Enabled == false) 1161 return; 1162 1163 timer.Enabled = false; 1164 if (thumb_moving != ThumbMoving.None) { 1165 DirtyThumbArea (); 1166 thumb_moving = ThumbMoving.None; 1167 } 1168 1169 if (firstbutton_pressed) { 1170 firstbutton_state = ButtonState.Normal; 1171 if (first_arrow_area.Contains (e.X, e.Y)) { 1172 SmallDecrement (); 1173 } 1174 SendWMScroll(ScrollBarCommands.SB_LINEUP); 1175 firstbutton_pressed = false; 1176 Dirty (first_arrow_area); 1177 } else if (secondbutton_pressed) { 1178 secondbutton_state = ButtonState.Normal; 1179 if (second_arrow_area.Contains (e.X, e.Y)) { 1180 SmallIncrement (); 1181 } 1182 SendWMScroll(ScrollBarCommands.SB_LINEDOWN); 1183 Dirty (second_arrow_area); 1184 secondbutton_pressed = false; 1185 } else if (thumb_pressed == true) { 1186 OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position)); 1187 OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position)); 1188 SendWMScroll(ScrollBarCommands.SB_THUMBPOSITION); 1189 ThumbPressed = false; 1190 return; 1191 } 1192 1193 InvalidateDirty (); 1194 } 1195 OnKeyDownSB(Object o, KeyEventArgs key)1196 private void OnKeyDownSB (Object o, KeyEventArgs key) 1197 { 1198 if (Enabled == false) 1199 return; 1200 1201 ClearDirty (); 1202 1203 switch (key.KeyCode){ 1204 case Keys.Up: 1205 { 1206 SmallDecrement (); 1207 break; 1208 } 1209 case Keys.Down: 1210 { 1211 SmallIncrement (); 1212 break; 1213 } 1214 case Keys.PageUp: 1215 { 1216 LargeDecrement (); 1217 break; 1218 } 1219 case Keys.PageDown: 1220 { 1221 LargeIncrement (); 1222 break; 1223 } 1224 case Keys.Home: 1225 { 1226 SetHomePosition (); 1227 break; 1228 } 1229 case Keys.End: 1230 { 1231 SetEndPosition (); 1232 break; 1233 } 1234 default: 1235 break; 1236 } 1237 1238 InvalidateDirty (); 1239 } 1240 1241 // I hate to do this, but we don't have the resources to track 1242 // down everything internal that is setting a value outside the 1243 // correct range, so we'll clamp it to the acceptable values. SafeValueSet(int value)1244 internal void SafeValueSet (int value) 1245 { 1246 value = Math.Min (value, maximum); 1247 value = Math.Max (value, minimum); 1248 1249 Value = value; 1250 } 1251 SetEndPosition()1252 private void SetEndPosition () 1253 { 1254 ScrollEventArgs event_args; 1255 int pos = MaximumAllowed; 1256 1257 event_args = new ScrollEventArgs (ScrollEventType.Last, pos); 1258 OnScroll (event_args); 1259 pos = event_args.NewValue; 1260 1261 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos); 1262 OnScroll (event_args); 1263 pos = event_args.NewValue; 1264 1265 SetValue (pos); 1266 } 1267 SetHomePosition()1268 private void SetHomePosition () 1269 { 1270 ScrollEventArgs event_args; 1271 int pos = Minimum; 1272 1273 event_args = new ScrollEventArgs (ScrollEventType.First, pos); 1274 OnScroll (event_args); 1275 pos = event_args.NewValue; 1276 1277 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos); 1278 OnScroll (event_args); 1279 pos = event_args.NewValue; 1280 1281 SetValue (pos); 1282 } 1283 SmallIncrement()1284 private void SmallIncrement () 1285 { 1286 ScrollEventArgs event_args; 1287 int pos = Math.Min (MaximumAllowed, position + SmallChange); 1288 1289 event_args = new ScrollEventArgs (ScrollEventType.SmallIncrement, pos); 1290 OnScroll (event_args); 1291 Value = event_args.NewValue; 1292 1293 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); 1294 OnScroll (event_args); 1295 Value = event_args.NewValue; 1296 1297 // UIA Framework event invoked when the "SmallIncrement 1298 // Button" (a.k.a bottom/right button) is "clicked" either 1299 // by using the Invoke Pattern or the button itself 1300 OnUIAScroll (new ScrollEventArgs (ScrollEventType.SmallIncrement, Value)); 1301 } 1302 SmallDecrement()1303 private void SmallDecrement () 1304 { 1305 ScrollEventArgs event_args; 1306 int pos = Math.Max (Minimum, position - SmallChange); 1307 1308 event_args = new ScrollEventArgs (ScrollEventType.SmallDecrement, pos); 1309 OnScroll (event_args); 1310 Value = event_args.NewValue; 1311 1312 event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value); 1313 OnScroll (event_args); 1314 Value = event_args.NewValue; 1315 1316 // UIA Framework event invoked when the "SmallDecrement 1317 // Button" (a.k.a top/left button) is "clicked" either 1318 // by using the Invoke Pattern or the button itself 1319 OnUIAScroll (new ScrollEventArgs (ScrollEventType.SmallDecrement, Value)); 1320 } 1321 SetHoldButtonClickTimer()1322 private void SetHoldButtonClickTimer () 1323 { 1324 timer.Enabled = false; 1325 timer.Interval = 200; 1326 timer_type = TimerType.HoldButton; 1327 timer.Enabled = true; 1328 } 1329 SetRepeatButtonTimer()1330 private void SetRepeatButtonTimer () 1331 { 1332 timer.Enabled = false; 1333 timer.Interval = 50; 1334 timer_type = TimerType.RepeatButton; 1335 timer.Enabled = true; 1336 } 1337 SetHoldThumbAreaTimer()1338 private void SetHoldThumbAreaTimer () 1339 { 1340 timer.Enabled = false; 1341 timer.Interval = 200; 1342 timer_type = TimerType.HoldThumbArea; 1343 timer.Enabled = true; 1344 } 1345 SetRepeatThumbAreaTimer()1346 private void SetRepeatThumbAreaTimer () 1347 { 1348 timer.Enabled = false; 1349 timer.Interval = 50; 1350 timer_type = TimerType.RepeatThumbArea; 1351 timer.Enabled = true; 1352 } 1353 UpdatePos(int newPos, bool update_thumbpos)1354 private void UpdatePos (int newPos, bool update_thumbpos) 1355 { 1356 int pos; 1357 1358 if (newPos < minimum) 1359 pos = minimum; 1360 else 1361 if (newPos > MaximumAllowed) 1362 pos = MaximumAllowed; 1363 else 1364 pos = newPos; 1365 1366 // pos can't be less than minimum or greater than maximum 1367 if (pos < minimum) 1368 pos = minimum; 1369 if (pos > maximum) 1370 pos = maximum; 1371 1372 if (update_thumbpos) { 1373 if (vert) 1374 UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false); 1375 else 1376 UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false); 1377 SetValue (pos); 1378 } 1379 else { 1380 position = pos; // Updates directly the value to avoid thumb pos update 1381 1382 1383 // XXX some reason we don't call OnValueChanged? 1384 EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); 1385 if (eh != null) 1386 eh (this, EventArgs.Empty); 1387 } 1388 } 1389 UpdateThumbPos(int pixel, bool dirty, bool update_value)1390 private void UpdateThumbPos (int pixel, bool dirty, bool update_value) 1391 { 1392 float new_pos = 0; 1393 1394 if (vert) { 1395 if (dirty) 1396 Dirty (thumb_pos); 1397 if (pixel < thumb_area.Y) 1398 thumb_pos.Y = thumb_area.Y; 1399 else if (pixel > thumb_area.Bottom - thumb_size) 1400 thumb_pos.Y = thumb_area.Bottom - thumb_size; 1401 else 1402 thumb_pos.Y = pixel; 1403 1404 thumb_pos.X = 0; 1405 thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize; 1406 thumb_pos.Height = thumb_size; 1407 new_pos = (float) (thumb_pos.Y - thumb_area.Y); 1408 new_pos = new_pos / pixel_per_pos; 1409 if (dirty) 1410 Dirty (thumb_pos); 1411 } else { 1412 if (dirty) 1413 Dirty (thumb_pos); 1414 if (pixel < thumb_area.X) 1415 thumb_pos.X = thumb_area.X; 1416 else if (pixel > thumb_area.Right - thumb_size) 1417 thumb_pos.X = thumb_area.Right - thumb_size; 1418 else 1419 thumb_pos.X = pixel; 1420 1421 thumb_pos.Y = 0; 1422 thumb_pos.Width = thumb_size; 1423 thumb_pos.Height = ThemeEngine.Current.ScrollBarButtonSize; 1424 new_pos = (float) (thumb_pos.X - thumb_area.X); 1425 new_pos = new_pos / pixel_per_pos; 1426 1427 if (dirty) 1428 Dirty (thumb_pos); 1429 } 1430 1431 if (update_value) 1432 UpdatePos ((int) new_pos + minimum, false); 1433 } 1434 SetValue(int value)1435 private void SetValue (int value) 1436 { 1437 if ( value < minimum || value > maximum ) 1438 throw new ArgumentException( 1439 String.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value)); 1440 1441 if (position != value){ 1442 position = value; 1443 1444 OnValueChanged (EventArgs.Empty); 1445 UpdatePos (value, true); 1446 } 1447 } 1448 ClearDirty()1449 private void ClearDirty () 1450 { 1451 dirty = Rectangle.Empty; 1452 } 1453 Dirty(Rectangle r)1454 private void Dirty (Rectangle r) 1455 { 1456 if (dirty == Rectangle.Empty) { 1457 dirty = r; 1458 return; 1459 } 1460 dirty = Rectangle.Union (dirty, r); 1461 } 1462 DirtyThumbArea()1463 private void DirtyThumbArea () 1464 { 1465 if (thumb_moving == ThumbMoving.Forward) { 1466 if (vert) { 1467 Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height, 1468 ClientRectangle.Width, 1469 ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) - 1470 scrollbutton_height)); 1471 } else { 1472 Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0, 1473 ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) - 1474 scrollbutton_width, 1475 ClientRectangle.Height)); 1476 } 1477 } else if (thumb_moving == ThumbMoving.Backwards) { 1478 if (vert) { 1479 Dirty(new Rectangle (0, scrollbutton_height, 1480 ClientRectangle.Width, 1481 thumb_pos.Y - scrollbutton_height)); 1482 } else { 1483 Dirty (new Rectangle (scrollbutton_width, 0, 1484 thumb_pos.X - scrollbutton_width, 1485 ClientRectangle.Height)); 1486 } 1487 } 1488 } 1489 InvalidateDirty()1490 private void InvalidateDirty () 1491 { 1492 Invalidate (dirty); 1493 Update(); 1494 dirty = Rectangle.Empty; 1495 } 1496 OnMouseEnter(object sender, EventArgs e)1497 void OnMouseEnter (object sender, EventArgs e) 1498 { 1499 if (ThemeEngine.Current.ScrollBarHasHoverArrowButtonStyle) { 1500 Region region_to_invalidate = new Region (first_arrow_area); 1501 region_to_invalidate.Union (second_arrow_area); 1502 Invalidate (region_to_invalidate); 1503 } 1504 } 1505 OnMouseLeave(object sender, EventArgs e)1506 void OnMouseLeave (object sender, EventArgs e) 1507 { 1508 Region region_to_invalidate = new Region (); 1509 region_to_invalidate.MakeEmpty (); 1510 bool dirty = false; 1511 if (ThemeEngine.Current.ScrollBarHasHoverArrowButtonStyle) { 1512 region_to_invalidate.Union (first_arrow_area); 1513 region_to_invalidate.Union (second_arrow_area); 1514 dirty = true; 1515 } else 1516 if (ThemeEngine.Current.ScrollBarHasHotElementStyles) 1517 if (first_button_entered) { 1518 region_to_invalidate.Union (first_arrow_area); 1519 dirty = true; 1520 } else if (second_button_entered) { 1521 region_to_invalidate.Union (second_arrow_area); 1522 dirty = true; 1523 } 1524 if (ThemeEngine.Current.ScrollBarHasHotElementStyles) 1525 if (thumb_entered) { 1526 region_to_invalidate.Union (thumb_pos); 1527 dirty = true; 1528 } 1529 first_button_entered = false; 1530 second_button_entered = false; 1531 thumb_entered = false; 1532 if (dirty) 1533 Invalidate (region_to_invalidate); 1534 region_to_invalidate.Dispose (); 1535 } 1536 #endregion //Private Methods OnMouseWheel(MouseEventArgs e)1537 protected override void OnMouseWheel (MouseEventArgs e) 1538 { 1539 base.OnMouseWheel (e); 1540 } 1541 1542 #region UIA Framework Section: Events, Methods and Properties. 1543 1544 //NOTE: 1545 // We are using Reflection to add/remove internal events. 1546 // Class ScrollBarButtonInvokePatternInvokeEvent uses the events. 1547 // 1548 // Types used to generate UIA InvokedEvent 1549 // * args.Type = ScrollEventType.LargeIncrement. Space between Thumb and bottom/right Button 1550 // * args.Type = ScrollEventType.LargeDecrement. Space between Thumb and top/left Button 1551 // * args.Type = ScrollEventType.SmallIncrement. Small increment UIA Button (bottom/right Button) 1552 // * args.Type = ScrollEventType.SmallDecrement. Small decrement UIA Button (top/left Button) 1553 // Types used to generate RangeValue-related events 1554 // * args.Type = ScrollEventType.LargeIncrement. LargeChange event 1555 // * args.Type = ScrollEventType.Last. Maximum event 1556 // * args.Type = ScrollEventType.First. Minimum event 1557 // * args.Type = ScrollEventType.SmallIncrement. SmallChange event 1558 static object UIAScrollEvent = new object (); 1559 static object UIAValueChangeEvent = new object (); 1560 1561 internal event ScrollEventHandler UIAScroll { 1562 add { Events.AddHandler (UIAScrollEvent, value); } 1563 remove { Events.RemoveHandler (UIAScrollEvent, value); } 1564 } 1565 1566 internal event ScrollEventHandler UIAValueChanged { 1567 add { Events.AddHandler (UIAValueChangeEvent, value); } 1568 remove { Events.RemoveHandler (UIAValueChangeEvent, value); } 1569 } 1570 OnUIAScroll(ScrollEventArgs args)1571 internal void OnUIAScroll (ScrollEventArgs args) 1572 { 1573 ScrollEventHandler eh = (ScrollEventHandler) Events [UIAScrollEvent]; 1574 if (eh != null) 1575 eh (this, args); 1576 } 1577 OnUIAValueChanged(ScrollEventArgs args)1578 internal void OnUIAValueChanged (ScrollEventArgs args) 1579 { 1580 ScrollEventHandler eh = (ScrollEventHandler) Events [UIAValueChangeEvent]; 1581 if (eh != null) 1582 eh (this, args); 1583 } 1584 1585 //NOTE: 1586 // Wrapper methods used by the Reflection. 1587 // Class ScrollBarButtonInvokeProviderBehavior uses the events. 1588 // UIALargeIncrement()1589 internal void UIALargeIncrement () 1590 { 1591 LargeIncrement (); 1592 } 1593 UIALargeDecrement()1594 internal void UIALargeDecrement () 1595 { 1596 LargeDecrement (); 1597 } 1598 UIASmallIncrement()1599 internal void UIASmallIncrement () 1600 { 1601 SmallIncrement (); 1602 } 1603 UIASmallDecrement()1604 internal void UIASmallDecrement () 1605 { 1606 SmallDecrement (); 1607 } 1608 1609 internal Rectangle UIAThumbArea { 1610 get { return thumb_area; } 1611 } 1612 1613 internal Rectangle UIAThumbPosition { 1614 get { return thumb_pos; } 1615 } 1616 1617 #endregion UIA Framework Section: Events, Methods and Properties. 1618 1619 } 1620 } 1621 1622 1623 1624