aboutsummaryrefslogtreecommitdiff
path: root/source/ShiftUI/Widgets/ScrollBar.cs
diff options
context:
space:
mode:
Diffstat (limited to 'source/ShiftUI/Widgets/ScrollBar.cs')
-rw-r--r--source/ShiftUI/Widgets/ScrollBar.cs1624
1 files changed, 1624 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/ScrollBar.cs b/source/ShiftUI/Widgets/ScrollBar.cs
new file mode 100644
index 0000000..9fceb0b
--- /dev/null
+++ b/source/ShiftUI/Widgets/ScrollBar.cs
@@ -0,0 +1,1624 @@
+//
+// ShiftUI.ScrollBar.cs
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// Copyright (C) 2004-2005, Novell, Inc.
+//
+// Authors:
+// Jordi Mas i Hernandez [email protected]
+//
+//
+
+// COMPLETE
+
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Drawing.Drawing2D;
+using System.ComponentModel;
+using System.Runtime.InteropServices;
+using System;
+
+namespace ShiftUI
+{
+ [ComVisible (true)]
+ [ClassInterface (ClassInterfaceType.AutoDispatch)]
+ [DefaultEvent ("Scroll")]
+ [DefaultProperty ("Value")]
+ public abstract class ScrollBar : Widget
+ {
+ #region Local Variables
+ private int position;
+ private int minimum;
+ private int maximum;
+ private int large_change;
+ private int small_change;
+ internal int scrollbutton_height;
+ internal int scrollbutton_width;
+ private Rectangle first_arrow_area = new Rectangle (); // up or left
+ private Rectangle second_arrow_area = new Rectangle (); // down or right
+ private Rectangle thumb_pos = new Rectangle ();
+ private Rectangle thumb_area = new Rectangle ();
+ internal ButtonState firstbutton_state = ButtonState.Normal;
+ internal ButtonState secondbutton_state = ButtonState.Normal;
+ private bool firstbutton_pressed = false;
+ private bool secondbutton_pressed = false;
+ private bool thumb_pressed = false;
+ private float pixel_per_pos = 0;
+ private Timer timer = new Timer ();
+ private TimerType timer_type;
+ private int thumb_size = 40;
+ private const int thumb_min_size = 8;
+ private const int thumb_notshown_size = 40;
+ internal bool use_manual_thumb_size;
+ internal int manual_thumb_size;
+ internal bool vert;
+ internal bool implicit_Widget;
+ private int lastclick_pos; // Position of the last button-down event
+ private int thumbclick_offset; // Position of the last button-down event relative to the thumb edge
+ private Rectangle dirty;
+
+ internal ThumbMoving thumb_moving = ThumbMoving.None;
+ bool first_button_entered;
+ bool second_button_entered;
+ bool thumb_entered;
+ #endregion // Local Variables
+
+ private enum TimerType
+ {
+ HoldButton,
+ RepeatButton,
+ HoldThumbArea,
+ RepeatThumbArea
+ }
+
+ internal enum ThumbMoving
+ {
+ None,
+ Forward,
+ Backwards,
+ }
+
+ #region events
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler AutoSizeChanged {
+ add { base.AutoSizeChanged += value; }
+ remove { base.AutoSizeChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler BackColorChanged {
+ add { base.BackColorChanged += value; }
+ remove { base.BackColorChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler BackgroundImageChanged {
+ add { base.BackgroundImageChanged += value; }
+ remove { base.BackgroundImageChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler BackgroundImageLayoutChanged {
+ add { base.BackgroundImageLayoutChanged += value; }
+ remove { base.BackgroundImageLayoutChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler Click {
+ add { base.Click += value; }
+ remove { base.Click -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler DoubleClick {
+ add { base.DoubleClick += value; }
+ remove { base.DoubleClick -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler FontChanged {
+ add { base.FontChanged += value; }
+ remove { base.FontChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler ForeColorChanged {
+ add { base.ForeColorChanged += value; }
+ remove { base.ForeColorChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler ImeModeChanged {
+ add { base.ImeModeChanged += value; }
+ remove { base.ImeModeChanged -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event MouseEventHandler MouseClick {
+ add { base.MouseClick += value; }
+ remove { base.MouseClick -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event MouseEventHandler MouseDoubleClick {
+ add { base.MouseDoubleClick += value; }
+ remove { base.MouseDoubleClick -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event MouseEventHandler MouseDown {
+ add { base.MouseDown += value; }
+ remove { base.MouseDown -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event MouseEventHandler MouseMove {
+ add { base.MouseMove += value; }
+ remove { base.MouseMove -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event MouseEventHandler MouseUp {
+ add { base.MouseUp += value; }
+ remove { base.MouseUp -= value; }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event PaintEventHandler Paint {
+ add { base.Paint += value; }
+ remove { base.Paint -= value; }
+ }
+
+ static object ScrollEvent = new object ();
+ static object ValueChangedEvent = new object ();
+
+ public event ScrollEventHandler Scroll {
+ add { Events.AddHandler (ScrollEvent, value); }
+ remove { Events.RemoveHandler (ScrollEvent, value); }
+ }
+
+ [Browsable (false)]
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ public new event EventHandler TextChanged {
+ add { base.TextChanged += value; }
+ remove { base.TextChanged -= value; }
+ }
+
+ public event EventHandler ValueChanged {
+ add { Events.AddHandler (ValueChangedEvent, value); }
+ remove { Events.RemoveHandler (ValueChangedEvent, value); }
+ }
+ #endregion Events
+
+ public ScrollBar ()
+ {
+ position = 0;
+ minimum = 0;
+ maximum = 100;
+ large_change = 10;
+ small_change = 1;
+
+ timer.Tick += new EventHandler (OnTimer);
+ MouseEnter += new EventHandler (OnMouseEnter);
+ MouseLeave += new EventHandler (OnMouseLeave);
+ base.KeyDown += new KeyEventHandler (OnKeyDownSB);
+ base.MouseDown += new MouseEventHandler (OnMouseDownSB);
+ base.MouseUp += new MouseEventHandler (OnMouseUpSB);
+ base.MouseMove += new MouseEventHandler (OnMouseMoveSB);
+ base.Resize += new EventHandler (OnResizeSB);
+ base.TabStop = false;
+ base.Cursor = Cursors.Default;
+
+ SetStyle (Widgetstyles.UserPaint | Widgetstyles.StandardClick | Widgetstyles.UseTextForAccessibility, false);
+ }
+
+ #region Internal & Private Properties
+ internal Rectangle FirstArrowArea {
+ get {
+ return this.first_arrow_area;
+ }
+
+ set {
+ this.first_arrow_area = value;
+ }
+ }
+
+ internal Rectangle SecondArrowArea {
+ get {
+ return this.second_arrow_area;
+ }
+
+ set {
+ this.second_arrow_area = value;
+ }
+ }
+
+ int MaximumAllowed {
+ get {
+ return use_manual_thumb_size ? maximum - manual_thumb_size + 1 :
+ maximum - LargeChange + 1;
+ }
+ }
+
+ internal Rectangle ThumbPos {
+ get {
+ return thumb_pos;
+ }
+
+ set {
+ thumb_pos = value;
+ }
+ }
+
+ internal bool FirstButtonEntered {
+ get { return first_button_entered; }
+ private set {
+ if (first_button_entered == value)
+ return;
+ first_button_entered = value;
+ if (ThemeEngine.Current.ScrollBarHasHotElementStyles)
+ Invalidate (first_arrow_area);
+ }
+ }
+
+ internal bool SecondButtonEntered {
+ get { return second_button_entered; }
+ private set {
+ if (second_button_entered == value)
+ return;
+ second_button_entered = value;
+ if (ThemeEngine.Current.ScrollBarHasHotElementStyles)
+ Invalidate (second_arrow_area);
+ }
+ }
+
+ internal bool ThumbEntered {
+ get { return thumb_entered; }
+ private set {
+ if (thumb_entered == value)
+ return;
+ thumb_entered = value;
+ if (ThemeEngine.Current.ScrollBarHasHotElementStyles)
+ Invalidate (thumb_pos);
+ }
+ }
+
+ internal bool ThumbPressed {
+ get { return thumb_pressed; }
+ private set {
+ if (thumb_pressed == value)
+ return;
+ thumb_pressed = value;
+ if (ThemeEngine.Current.ScrollBarHasPressedThumbStyle)
+ Invalidate (thumb_pos);
+ }
+ }
+
+ #endregion // Internal & Private Properties
+
+ #region Public Properties
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ public override bool AutoSize {
+ get { return base.AutoSize; }
+ set { base.AutoSize = value; }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ public override Color BackColor
+ {
+ get { return base.BackColor; }
+ set {
+ if (base.BackColor == value)
+ return;
+ base.BackColor = value;
+ Refresh ();
+ }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ public override Image BackgroundImage
+ {
+ get { return base.BackgroundImage; }
+ set {
+ if (base.BackgroundImage == value)
+ return;
+
+ base.BackgroundImage = value;
+ }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ public override ImageLayout BackgroundImageLayout {
+ get { return base.BackgroundImageLayout; }
+ set { base.BackgroundImageLayout = value; }
+ }
+
+ protected override CreateParams CreateParams
+ {
+ get { return base.CreateParams; }
+ }
+
+ protected override Padding DefaultMargin {
+ get { return Padding.Empty; }
+ }
+
+ protected override ImeMode DefaultImeMode
+ {
+ get { return ImeMode.Disable; }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ public override Font Font
+ {
+ get { return base.Font; }
+ set {
+ if (base.Font.Equals (value))
+ return;
+
+ base.Font = value;
+ }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ public override Color ForeColor
+ {
+ get { return base.ForeColor; }
+ set {
+ if (base.ForeColor == value)
+ return;
+
+ base.ForeColor = value;
+ Refresh ();
+ }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Browsable (false)]
+ public new ImeMode ImeMode
+ {
+ get { return base.ImeMode; }
+ set {
+ if (base.ImeMode == value)
+ return;
+
+ base.ImeMode = value;
+ }
+ }
+
+ [DefaultValue (10)]
+ [RefreshProperties(RefreshProperties.Repaint)]
+ [MWFDescription("Scroll amount when clicking in the scroll area"), MWFCategory("Behaviour")]
+ public int LargeChange {
+ get { return Math.Min (large_change, maximum - minimum + 1); }
+ set {
+ if (value < 0)
+ throw new ArgumentOutOfRangeException ("LargeChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value));
+
+ if (large_change != value) {
+ large_change = value;
+
+ // thumb area depends on large change value,
+ // so we need to recalculate it.
+ CalcThumbArea ();
+ UpdatePos (Value, true);
+ InvalidateDirty ();
+
+ // UIA Framework: Generate UIA Event to indicate LargeChange change
+ OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.LargeIncrement, value));
+ }
+ }
+ }
+
+ [DefaultValue (100)]
+ [RefreshProperties(RefreshProperties.Repaint)]
+ [MWFDescription("Highest value for scrollbar"), MWFCategory("Behaviour")]
+ public int Maximum {
+ get { return maximum; }
+ set {
+ if (maximum == value)
+ return;
+
+ maximum = value;
+
+ // UIA Framework: Generate UIA Event to indicate Maximum change
+ OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.Last, value));
+
+ if (maximum < minimum)
+ minimum = maximum;
+ if (Value > maximum)
+ Value = maximum;
+
+ // thumb area depends on maximum value,
+ // so we need to recalculate it.
+ CalcThumbArea ();
+ UpdatePos (Value, true);
+ InvalidateDirty ();
+ }
+ }
+
+ internal void SetValues (int maximum, int large_change)
+ {
+ SetValues (-1, maximum, -1, large_change);
+ }
+
+ internal void SetValues (int minimum, int maximum, int small_change, int large_change)
+ {
+ bool update = false;
+
+ if (-1 != minimum && this.minimum != minimum) {
+ this.minimum = minimum;
+
+ if (minimum > this.maximum)
+ this.maximum = minimum;
+ update = true;
+
+ // change the position if it is out of range now
+ position = Math.Max (position, minimum);
+ }
+
+ if (-1 != maximum && this.maximum != maximum) {
+ this.maximum = maximum;
+
+ if (maximum < this.minimum)
+ this.minimum = maximum;
+ update = true;
+
+ // change the position if it is out of range now
+ position = Math.Min (position, maximum);
+ }
+
+ if (-1 != small_change && this.small_change != small_change) {
+ this.small_change = small_change;
+ }
+
+ if (this.large_change != large_change) {
+ this.large_change = large_change;
+ update = true;
+ }
+
+ if (update) {
+ CalcThumbArea ();
+ UpdatePos (Value, true);
+ InvalidateDirty ();
+ }
+ }
+
+ [DefaultValue (0)]
+ [RefreshProperties(RefreshProperties.Repaint)]
+ [MWFDescription("Smallest value for scrollbar"), MWFCategory("Behaviour")]
+ public int Minimum {
+ get { return minimum; }
+ set {
+ if (minimum == value)
+ return;
+
+ minimum = value;
+
+ // UIA Framework: Generate UIA Event to indicate Minimum change
+ OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.First, value));
+
+ if (minimum > maximum)
+ maximum = minimum;
+
+ // thumb area depends on minimum value,
+ // so we need to recalculate it.
+ CalcThumbArea ();
+ UpdatePos (Value, true);
+ InvalidateDirty ();
+ }
+ }
+
+ [DefaultValue (1)]
+ [MWFDescription("Scroll amount when clicking scroll arrows"), MWFCategory("Behaviour")]
+ public int SmallChange {
+ get { return small_change > LargeChange ? LargeChange : small_change; }
+ set {
+ if ( value < 0 )
+ throw new ArgumentOutOfRangeException ("SmallChange", string.Format ("Value '{0}' must be greater than or equal to 0.", value));
+
+ if (small_change != value) {
+ small_change = value;
+ UpdatePos (Value, true);
+ InvalidateDirty ();
+
+ // UIA Framework: Generate UIA Event to indicate SmallChange change
+ OnUIAValueChanged (new ScrollEventArgs (ScrollEventType.SmallIncrement, value));
+ }
+ }
+ }
+
+ [DefaultValue (false)]
+ public new bool TabStop {
+ get { return base.TabStop; }
+ set { base.TabStop = value; }
+ }
+
+ //[EditorBrowsable (EditorBrowsableState.Never)]
+ [Bindable (false)]
+ [Browsable (false)]
+ //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
+ public override string Text {
+ get { return base.Text; }
+ set { base.Text = value; }
+ }
+
+ [Bindable(true)]
+ [DefaultValue (0)]
+ [MWFDescription("Current value for scrollbar"), MWFCategory("Behaviour")]
+ public int Value {
+ get { return position; }
+ set {
+ if ( value < minimum || value > maximum )
+ throw new ArgumentOutOfRangeException ("Value", string.Format ("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
+
+ if (position != value){
+ position = value;
+
+ OnValueChanged (EventArgs.Empty);
+
+ if (IsHandleCreated) {
+ Rectangle thumb_rect = thumb_pos;
+
+ UpdateThumbPos ((vert ? thumb_area.Y : thumb_area.X) + (int)(((float)(position - minimum)) * pixel_per_pos), false, false);
+
+ MoveThumb (thumb_rect, vert ? thumb_pos.Y : thumb_pos.X);
+ }
+ }
+ }
+ }
+
+ #endregion //Public Properties
+
+ #region Public Methods
+ protected override Rectangle GetScaledBounds (Rectangle bounds, SizeF factor, BoundsSpecified specified)
+ {
+ // Basically, we want to keep our small edge and scale the long edge
+ // ie: if we are vertical, don't scale our width
+ if (vert)
+ return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Height) | (specified & BoundsSpecified.Location));
+ else
+ return base.GetScaledBounds (bounds, factor, (specified & BoundsSpecified.Width) | (specified & BoundsSpecified.Location));
+ }
+
+ protected override void OnEnabledChanged (EventArgs e)
+ {
+ base.OnEnabledChanged (e);
+
+ if (Enabled)
+ firstbutton_state = secondbutton_state = ButtonState.Normal;
+ else
+ firstbutton_state = secondbutton_state = ButtonState.Inactive;
+
+ Refresh ();
+ }
+
+ protected override void OnHandleCreated (System.EventArgs e)
+ {
+ base.OnHandleCreated (e);
+
+ CalcButtonSizes ();
+ CalcThumbArea ();
+ UpdateThumbPos (thumb_area.Y + (int)(((float)(position - minimum)) * pixel_per_pos), true, false);
+ }
+
+ protected virtual void OnScroll (ScrollEventArgs se)
+ {
+ ScrollEventHandler eh = (ScrollEventHandler)(Events [ScrollEvent]);
+ if (eh == null)
+ return;
+
+ if (se.NewValue < Minimum) {
+ se.NewValue = Minimum;
+ }
+
+ if (se.NewValue > Maximum) {
+ se.NewValue = Maximum;
+ }
+
+ eh (this, se);
+ }
+
+ private void SendWMScroll(ScrollBarCommands cmd) {
+ if ((Parent != null) && Parent.IsHandleCreated) {
+ if (vert) {
+ XplatUI.SendMessage(Parent.Handle, Msg.WM_VSCROLL, (IntPtr)cmd, implicit_Widget ? IntPtr.Zero : Handle);
+ } else {
+ XplatUI.SendMessage(Parent.Handle, Msg.WM_HSCROLL, (IntPtr)cmd, implicit_Widget ? IntPtr.Zero : Handle);
+ }
+ }
+ }
+
+ protected virtual void OnValueChanged (EventArgs e)
+ {
+ EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
+ if (eh != null)
+ eh (this, e);
+ }
+
+ public override string ToString()
+ {
+ return string.Format("{0}, Minimum: {1}, Maximum: {2}, Value: {3}",
+ GetType( ).FullName, minimum, maximum, position);
+ }
+
+ protected void UpdateScrollInfo ()
+ {
+ Refresh ();
+ }
+
+ protected override void WndProc (ref Message m)
+ {
+ base.WndProc (ref m);
+ }
+
+ #endregion //Public Methods
+
+ #region Private Methods
+
+ private void CalcButtonSizes ()
+ {
+ if (vert) {
+ if (Height < ThemeEngine.Current.ScrollBarButtonSize * 2)
+ scrollbutton_height = Height /2;
+ else
+ scrollbutton_height = ThemeEngine.Current.ScrollBarButtonSize;
+
+ } else {
+ if (Width < ThemeEngine.Current.ScrollBarButtonSize * 2)
+ scrollbutton_width = Width /2;
+ else
+ scrollbutton_width = ThemeEngine.Current.ScrollBarButtonSize;
+ }
+ }
+
+ private void CalcThumbArea ()
+ {
+ int lchange = use_manual_thumb_size ? manual_thumb_size : LargeChange;
+
+ // Thumb area
+ if (vert) {
+
+ thumb_area.Height = Height - scrollbutton_height - scrollbutton_height;
+ thumb_area.X = 0;
+ thumb_area.Y = scrollbutton_height;
+ thumb_area.Width = Width;
+
+ if (Height < thumb_notshown_size)
+ thumb_size = 0;
+ else {
+ double per = ((double) lchange / (double)((1 + maximum - minimum)));
+ thumb_size = 1 + (int) (thumb_area.Height * per);
+
+ if (thumb_size < thumb_min_size)
+ thumb_size = thumb_min_size;
+
+ // Give the user something to drag if LargeChange is zero
+ if (LargeChange == 0)
+ thumb_size = 17;
+ }
+
+ pixel_per_pos = ((float)(thumb_area.Height - thumb_size) / (float) ((maximum - minimum - lchange) + 1));
+
+ } else {
+
+ thumb_area.Y = 0;
+ thumb_area.X = scrollbutton_width;
+ thumb_area.Height = Height;
+ thumb_area.Width = Width - scrollbutton_width - scrollbutton_width;
+
+ if (Width < thumb_notshown_size)
+ thumb_size = 0;
+ else {
+ double per = ((double) lchange / (double)((1 + maximum - minimum)));
+ thumb_size = 1 + (int) (thumb_area.Width * per);
+
+ if (thumb_size < thumb_min_size)
+ thumb_size = thumb_min_size;
+
+ // Give the user something to drag if LargeChange is zero
+ if (LargeChange == 0)
+ thumb_size = 17;
+ }
+
+ pixel_per_pos = ((float)(thumb_area.Width - thumb_size) / (float) ((maximum - minimum - lchange) + 1));
+ }
+ }
+
+ private void LargeIncrement ()
+ {
+ ScrollEventArgs event_args;
+ int pos = Math.Min (MaximumAllowed, position + large_change);
+
+ event_args = new ScrollEventArgs (ScrollEventType.LargeIncrement, pos);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ // UIA Framework event invoked when the "LargeIncrement
+ // Button" is "clicked" either by using the Invoke Pattern
+ // or the space between the thumb and the bottom/right button
+ OnUIAScroll (new ScrollEventArgs (ScrollEventType.LargeIncrement, Value));
+ }
+
+ private void LargeDecrement ()
+ {
+ ScrollEventArgs event_args;
+ int pos = Math.Max (Minimum, position - large_change);
+
+ event_args = new ScrollEventArgs (ScrollEventType.LargeDecrement, pos);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ // UIA Framework event invoked when the "LargeDecrement
+ // Button" is "clicked" either by using the Invoke Pattern
+ // or the space between the thumb and the top/left button
+ OnUIAScroll (new ScrollEventArgs (ScrollEventType.LargeDecrement, Value));
+ }
+
+ private void OnResizeSB (Object o, EventArgs e)
+ {
+ if (Width <= 0 || Height <= 0)
+ return;
+
+ CalcButtonSizes ();
+ CalcThumbArea ();
+ UpdatePos (position, true);
+
+ Refresh ();
+ }
+
+ internal override void OnPaintInternal (PaintEventArgs pevent)
+ {
+ ThemeEngine.Current.DrawScrollBar (pevent.Graphics, pevent.ClipRectangle, this);
+ }
+
+ private void OnTimer (Object source, EventArgs e)
+ {
+ ClearDirty ();
+
+ switch (timer_type) {
+
+ case TimerType.HoldButton:
+ SetRepeatButtonTimer ();
+ break;
+
+ case TimerType.RepeatButton:
+ {
+ if ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Minimum) {
+ SmallDecrement();
+ SendWMScroll(ScrollBarCommands.SB_LINEUP);
+ }
+
+ if ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed && position != Maximum) {
+ SmallIncrement();
+ SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
+ }
+
+ break;
+ }
+
+ case TimerType.HoldThumbArea:
+ SetRepeatThumbAreaTimer ();
+ break;
+
+ case TimerType.RepeatThumbArea:
+ {
+ Point pnt, pnt_screen;
+ Rectangle thumb_area_screen = thumb_area;
+
+ pnt_screen = PointToScreen (new Point (thumb_area.X, thumb_area.Y));
+ thumb_area_screen.X = pnt_screen.X;
+ thumb_area_screen.Y = pnt_screen.Y;
+
+ if (thumb_area_screen.Contains (MousePosition) == false) {
+ timer.Enabled = false;
+ thumb_moving = ThumbMoving.None;
+ DirtyThumbArea ();
+ InvalidateDirty ();
+ }
+
+ pnt = PointToClient (MousePosition);
+
+ if (vert)
+ lastclick_pos = pnt.Y;
+ else
+ lastclick_pos = pnt.X;
+
+ if (thumb_moving == ThumbMoving.Forward) {
+ if ((vert && (thumb_pos.Y + thumb_size > lastclick_pos)) ||
+ (!vert && (thumb_pos.X + thumb_size > lastclick_pos)) ||
+ (thumb_area.Contains (pnt) == false)) {
+ timer.Enabled = false;
+ thumb_moving = ThumbMoving.None;
+ Refresh ();
+ return;
+ } else {
+ LargeIncrement ();
+ SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
+ }
+ } else {
+ if ((vert && (thumb_pos.Y < lastclick_pos)) ||
+ (!vert && (thumb_pos.X < lastclick_pos))){
+ timer.Enabled = false;
+ thumb_moving = ThumbMoving.None;
+ SendWMScroll(ScrollBarCommands.SB_PAGEUP);
+ Refresh ();
+ } else {
+ LargeDecrement ();
+ SendWMScroll(ScrollBarCommands.SB_PAGEUP);
+ }
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ InvalidateDirty ();
+ }
+
+ private void MoveThumb (Rectangle original_thumbpos, int value)
+ {
+ /* so, the reason this works can best be
+ * described by the following 1 dimensional
+ * pictures
+ *
+ * say you have a scrollbar thumb positioned
+ * thusly:
+ *
+ * <---------------------| |------------------------------>
+ *
+ * and you want it to end up looking like this:
+ *
+ * <-----------------------------| |---------------------->
+ *
+ * that can be done with the scrolling api by
+ * extending the rectangle to encompass both
+ * positions:
+ *
+ * start of range end of range
+ * \ /
+ * <---------------------| |-------|---------------------->
+ *
+ * so, we end up scrolling just this little region:
+ *
+ * | |-------|
+ *
+ * and end up with ********| |
+ *
+ * where ****** is space that is automatically
+ * redrawn.
+ *
+ * It's clear that in both cases (left to
+ * right, right to left) we need to extend the
+ * size of the scroll rectangle to encompass
+ * both. In the right to left case, we also
+ * need to decrement the X coordinate.
+ *
+ * We call Update after scrolling to make sure
+ * there's no garbage left in the window to be
+ * copied again if we're called before the
+ * paint events have been handled.
+ *
+ */
+ int delta;
+
+ if (vert) {
+ delta = value - original_thumbpos.Y;
+
+ if (delta < 0) {
+ original_thumbpos.Y += delta;
+ original_thumbpos.Height -= delta;
+ }
+ else {
+ original_thumbpos.Height += delta;
+ }
+
+ XplatUI.ScrollWindow (Handle, original_thumbpos, 0, delta, false);
+ }
+ else {
+ delta = value - original_thumbpos.X;
+
+ if (delta < 0) {
+ original_thumbpos.X += delta;
+ original_thumbpos.Width -= delta;
+ }
+ else {
+ original_thumbpos.Width += delta;
+ }
+
+ XplatUI.ScrollWindow (Handle, original_thumbpos, delta, 0, false);
+ }
+
+ Update ();
+ }
+
+ private void OnMouseMoveSB (object sender, MouseEventArgs e)
+ {
+ if (Enabled == false)
+ return;
+
+ FirstButtonEntered = first_arrow_area.Contains (e.Location);
+ SecondButtonEntered = second_arrow_area.Contains (e.Location);
+
+ if (thumb_size == 0)
+ return;
+
+ ThumbEntered = thumb_pos.Contains (e.Location);
+
+ if (firstbutton_pressed) {
+ if (!first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
+ firstbutton_state = ButtonState.Normal;
+ Invalidate (first_arrow_area);
+ Update();
+ return;
+ } else if (first_arrow_area.Contains (e.X, e.Y) && ((firstbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
+ firstbutton_state = ButtonState.Pushed;
+ Invalidate (first_arrow_area);
+ Update();
+ return;
+ }
+ } else if (secondbutton_pressed) {
+ if (!second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Pushed) == ButtonState.Pushed)) {
+ secondbutton_state = ButtonState.Normal;
+ Invalidate (second_arrow_area);
+ Update();
+ return;
+ } else if (second_arrow_area.Contains (e.X, e.Y) && ((secondbutton_state & ButtonState.Normal) == ButtonState.Normal)) {
+ secondbutton_state = ButtonState.Pushed;
+ Invalidate (second_arrow_area);
+ Update();
+ return;
+ }
+ } else if (thumb_pressed == true) {
+ if (vert) {
+ int thumb_edge = e.Y - thumbclick_offset;
+
+ if (thumb_edge < thumb_area.Y)
+ thumb_edge = thumb_area.Y;
+ else if (thumb_edge > thumb_area.Bottom - thumb_size)
+ thumb_edge = thumb_area.Bottom - thumb_size;
+
+ if (thumb_edge != thumb_pos.Y) {
+ Rectangle thumb_rect = thumb_pos;
+
+ UpdateThumbPos (thumb_edge, false, true);
+
+ MoveThumb (thumb_rect, thumb_pos.Y);
+
+ OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
+ }
+ SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
+ } else {
+ int thumb_edge = e.X - thumbclick_offset;
+
+ if (thumb_edge < thumb_area.X)
+ thumb_edge = thumb_area.X;
+ else if (thumb_edge > thumb_area.Right - thumb_size)
+ thumb_edge = thumb_area.Right - thumb_size;
+
+ if (thumb_edge != thumb_pos.X) {
+ Rectangle thumb_rect = thumb_pos;
+
+ UpdateThumbPos (thumb_edge, false, true);
+
+ MoveThumb (thumb_rect, thumb_pos.X);
+
+ OnScroll (new ScrollEventArgs (ScrollEventType.ThumbTrack, position));
+ }
+ SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
+ }
+
+ }
+
+ }
+
+ private void OnMouseDownSB (object sender, MouseEventArgs e)
+ {
+ ClearDirty ();
+
+ if (Enabled == false || (e.Button & MouseButtons.Left) == 0)
+ return;
+
+ if (firstbutton_state != ButtonState.Inactive && first_arrow_area.Contains (e.X, e.Y)) {
+ SendWMScroll(ScrollBarCommands.SB_LINEUP);
+ firstbutton_state = ButtonState.Pushed;
+ firstbutton_pressed = true;
+ Invalidate (first_arrow_area);
+ Update();
+ if (!timer.Enabled) {
+ SetHoldButtonClickTimer ();
+ timer.Enabled = true;
+ }
+ }
+
+ if (secondbutton_state != ButtonState.Inactive && second_arrow_area.Contains (e.X, e.Y)) {
+ SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
+ secondbutton_state = ButtonState.Pushed;
+ secondbutton_pressed = true;
+ Invalidate (second_arrow_area);
+ Update();
+ if (!timer.Enabled) {
+ SetHoldButtonClickTimer ();
+ timer.Enabled = true;
+ }
+ }
+
+ if (thumb_size > 0 && thumb_pos.Contains (e.X, e.Y)) {
+ ThumbPressed = true;
+ SendWMScroll(ScrollBarCommands.SB_THUMBTRACK);
+ if (vert) {
+ thumbclick_offset = e.Y - thumb_pos.Y;
+ lastclick_pos = e.Y;
+ }
+ else {
+ thumbclick_offset = e.X - thumb_pos.X;
+ lastclick_pos = e.X;
+ }
+ } else {
+ if (thumb_size > 0 && thumb_area.Contains (e.X, e.Y)) {
+
+ if (vert) {
+ lastclick_pos = e.Y;
+
+ if (e.Y > thumb_pos.Y + thumb_pos.Height) {
+ SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
+ LargeIncrement ();
+ thumb_moving = ThumbMoving.Forward;
+ Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
+ ClientRectangle.Width,
+ ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) -
+ scrollbutton_height));
+ } else {
+ SendWMScroll(ScrollBarCommands.SB_PAGEUP);
+ LargeDecrement ();
+ thumb_moving = ThumbMoving.Backwards;
+ Dirty (new Rectangle (0, scrollbutton_height,
+ ClientRectangle.Width,
+ thumb_pos.Y - scrollbutton_height));
+ }
+ } else {
+
+ lastclick_pos = e.X;
+
+ if (e.X > thumb_pos.X + thumb_pos.Width) {
+ SendWMScroll(ScrollBarCommands.SB_PAGEDOWN);
+ thumb_moving = ThumbMoving.Forward;
+ LargeIncrement ();
+ Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
+ ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) -
+ scrollbutton_width,
+ ClientRectangle.Height));
+ } else {
+ SendWMScroll(ScrollBarCommands.SB_PAGEUP);
+ thumb_moving = ThumbMoving.Backwards;
+ LargeDecrement ();
+ Dirty (new Rectangle (scrollbutton_width, 0,
+ thumb_pos.X - scrollbutton_width,
+ ClientRectangle.Height));
+ }
+ }
+
+ SetHoldThumbAreaTimer ();
+ timer.Enabled = true;
+ InvalidateDirty ();
+ }
+ }
+ }
+
+ private void OnMouseUpSB (object sender, MouseEventArgs e)
+ {
+ ClearDirty ();
+
+ if (Enabled == false)
+ return;
+
+ timer.Enabled = false;
+ if (thumb_moving != ThumbMoving.None) {
+ DirtyThumbArea ();
+ thumb_moving = ThumbMoving.None;
+ }
+
+ if (firstbutton_pressed) {
+ firstbutton_state = ButtonState.Normal;
+ if (first_arrow_area.Contains (e.X, e.Y)) {
+ SmallDecrement ();
+ }
+ SendWMScroll(ScrollBarCommands.SB_LINEUP);
+ firstbutton_pressed = false;
+ Dirty (first_arrow_area);
+ } else if (secondbutton_pressed) {
+ secondbutton_state = ButtonState.Normal;
+ if (second_arrow_area.Contains (e.X, e.Y)) {
+ SmallIncrement ();
+ }
+ SendWMScroll(ScrollBarCommands.SB_LINEDOWN);
+ Dirty (second_arrow_area);
+ secondbutton_pressed = false;
+ } else if (thumb_pressed == true) {
+ OnScroll (new ScrollEventArgs (ScrollEventType.ThumbPosition, position));
+ OnScroll (new ScrollEventArgs (ScrollEventType.EndScroll, position));
+ SendWMScroll(ScrollBarCommands.SB_THUMBPOSITION);
+ ThumbPressed = false;
+ return;
+ }
+
+ InvalidateDirty ();
+ }
+
+ private void OnKeyDownSB (Object o, KeyEventArgs key)
+ {
+ if (Enabled == false)
+ return;
+
+ ClearDirty ();
+
+ switch (key.KeyCode){
+ case Keys.Up:
+ {
+ SmallDecrement ();
+ break;
+ }
+ case Keys.Down:
+ {
+ SmallIncrement ();
+ break;
+ }
+ case Keys.PageUp:
+ {
+ LargeDecrement ();
+ break;
+ }
+ case Keys.PageDown:
+ {
+ LargeIncrement ();
+ break;
+ }
+ case Keys.Home:
+ {
+ SetHomePosition ();
+ break;
+ }
+ case Keys.End:
+ {
+ SetEndPosition ();
+ break;
+ }
+ default:
+ break;
+ }
+
+ InvalidateDirty ();
+ }
+
+ // I hate to do this, but we don't have the resources to track
+ // down everything internal that is setting a value outside the
+ // correct range, so we'll clamp it to the acceptable values.
+ internal void SafeValueSet (int value)
+ {
+ value = Math.Min (value, maximum);
+ value = Math.Max (value, minimum);
+
+ Value = value;
+ }
+
+ private void SetEndPosition ()
+ {
+ ScrollEventArgs event_args;
+ int pos = MaximumAllowed;
+
+ event_args = new ScrollEventArgs (ScrollEventType.Last, pos);
+ OnScroll (event_args);
+ pos = event_args.NewValue;
+
+ event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
+ OnScroll (event_args);
+ pos = event_args.NewValue;
+
+ SetValue (pos);
+ }
+
+ private void SetHomePosition ()
+ {
+ ScrollEventArgs event_args;
+ int pos = Minimum;
+
+ event_args = new ScrollEventArgs (ScrollEventType.First, pos);
+ OnScroll (event_args);
+ pos = event_args.NewValue;
+
+ event_args = new ScrollEventArgs (ScrollEventType.EndScroll, pos);
+ OnScroll (event_args);
+ pos = event_args.NewValue;
+
+ SetValue (pos);
+ }
+
+ private void SmallIncrement ()
+ {
+ ScrollEventArgs event_args;
+ int pos = Math.Min (MaximumAllowed, position + SmallChange);
+
+ event_args = new ScrollEventArgs (ScrollEventType.SmallIncrement, pos);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ // UIA Framework event invoked when the "SmallIncrement
+ // Button" (a.k.a bottom/right button) is "clicked" either
+ // by using the Invoke Pattern or the button itself
+ OnUIAScroll (new ScrollEventArgs (ScrollEventType.SmallIncrement, Value));
+ }
+
+ private void SmallDecrement ()
+ {
+ ScrollEventArgs event_args;
+ int pos = Math.Max (Minimum, position - SmallChange);
+
+ event_args = new ScrollEventArgs (ScrollEventType.SmallDecrement, pos);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ event_args = new ScrollEventArgs (ScrollEventType.EndScroll, Value);
+ OnScroll (event_args);
+ Value = event_args.NewValue;
+
+ // UIA Framework event invoked when the "SmallDecrement
+ // Button" (a.k.a top/left button) is "clicked" either
+ // by using the Invoke Pattern or the button itself
+ OnUIAScroll (new ScrollEventArgs (ScrollEventType.SmallDecrement, Value));
+ }
+
+ private void SetHoldButtonClickTimer ()
+ {
+ timer.Enabled = false;
+ timer.Interval = 200;
+ timer_type = TimerType.HoldButton;
+ timer.Enabled = true;
+ }
+
+ private void SetRepeatButtonTimer ()
+ {
+ timer.Enabled = false;
+ timer.Interval = 50;
+ timer_type = TimerType.RepeatButton;
+ timer.Enabled = true;
+ }
+
+ private void SetHoldThumbAreaTimer ()
+ {
+ timer.Enabled = false;
+ timer.Interval = 200;
+ timer_type = TimerType.HoldThumbArea;
+ timer.Enabled = true;
+ }
+
+ private void SetRepeatThumbAreaTimer ()
+ {
+ timer.Enabled = false;
+ timer.Interval = 50;
+ timer_type = TimerType.RepeatThumbArea;
+ timer.Enabled = true;
+ }
+
+ private void UpdatePos (int newPos, bool update_thumbpos)
+ {
+ int pos;
+
+ if (newPos < minimum)
+ pos = minimum;
+ else
+ if (newPos > MaximumAllowed)
+ pos = MaximumAllowed;
+ else
+ pos = newPos;
+
+ // pos can't be less than minimum or greater than maximum
+ if (pos < minimum)
+ pos = minimum;
+ if (pos > maximum)
+ pos = maximum;
+
+ if (update_thumbpos) {
+ if (vert)
+ UpdateThumbPos (thumb_area.Y + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
+ else
+ UpdateThumbPos (thumb_area.X + (int)(((float)(pos - minimum)) * pixel_per_pos), true, false);
+ SetValue (pos);
+ }
+ else {
+ position = pos; // Updates directly the value to avoid thumb pos update
+
+
+ // XXX some reason we don't call OnValueChanged?
+ EventHandler eh = (EventHandler)(Events [ValueChangedEvent]);
+ if (eh != null)
+ eh (this, EventArgs.Empty);
+ }
+ }
+
+ private void UpdateThumbPos (int pixel, bool dirty, bool update_value)
+ {
+ float new_pos = 0;
+
+ if (vert) {
+ if (dirty)
+ Dirty (thumb_pos);
+ if (pixel < thumb_area.Y)
+ thumb_pos.Y = thumb_area.Y;
+ else if (pixel > thumb_area.Bottom - thumb_size)
+ thumb_pos.Y = thumb_area.Bottom - thumb_size;
+ else
+ thumb_pos.Y = pixel;
+
+ thumb_pos.X = 0;
+ thumb_pos.Width = ThemeEngine.Current.ScrollBarButtonSize;
+ thumb_pos.Height = thumb_size;
+ new_pos = (float) (thumb_pos.Y - thumb_area.Y);
+ new_pos = new_pos / pixel_per_pos;
+ if (dirty)
+ Dirty (thumb_pos);
+ } else {
+ if (dirty)
+ Dirty (thumb_pos);
+ if (pixel < thumb_area.X)
+ thumb_pos.X = thumb_area.X;
+ else if (pixel > thumb_area.Right - thumb_size)
+ thumb_pos.X = thumb_area.Right - thumb_size;
+ else
+ thumb_pos.X = pixel;
+
+ thumb_pos.Y = 0;
+ thumb_pos.Width = thumb_size;
+ thumb_pos.Height = ThemeEngine.Current.ScrollBarButtonSize;
+ new_pos = (float) (thumb_pos.X - thumb_area.X);
+ new_pos = new_pos / pixel_per_pos;
+
+ if (dirty)
+ Dirty (thumb_pos);
+ }
+
+ if (update_value)
+ UpdatePos ((int) new_pos + minimum, false);
+ }
+
+ private void SetValue (int value)
+ {
+ if ( value < minimum || value > maximum )
+ throw new ArgumentException(
+ String.Format("'{0}' is not a valid value for 'Value'. 'Value' should be between 'Minimum' and 'Maximum'", value));
+
+ if (position != value){
+ position = value;
+
+ OnValueChanged (EventArgs.Empty);
+ UpdatePos (value, true);
+ }
+ }
+
+ private void ClearDirty ()
+ {
+ dirty = Rectangle.Empty;
+ }
+
+ private void Dirty (Rectangle r)
+ {
+ if (dirty == Rectangle.Empty) {
+ dirty = r;
+ return;
+ }
+ dirty = Rectangle.Union (dirty, r);
+ }
+
+ private void DirtyThumbArea ()
+ {
+ if (thumb_moving == ThumbMoving.Forward) {
+ if (vert) {
+ Dirty (new Rectangle (0, thumb_pos.Y + thumb_pos.Height,
+ ClientRectangle.Width,
+ ClientRectangle.Height - (thumb_pos.Y + thumb_pos.Height) -
+ scrollbutton_height));
+ } else {
+ Dirty (new Rectangle (thumb_pos.X + thumb_pos.Width, 0,
+ ClientRectangle.Width - (thumb_pos.X + thumb_pos.Width) -
+ scrollbutton_width,
+ ClientRectangle.Height));
+ }
+ } else if (thumb_moving == ThumbMoving.Backwards) {
+ if (vert) {
+ Dirty(new Rectangle (0, scrollbutton_height,
+ ClientRectangle.Width,
+ thumb_pos.Y - scrollbutton_height));
+ } else {
+ Dirty (new Rectangle (scrollbutton_width, 0,
+ thumb_pos.X - scrollbutton_width,
+ ClientRectangle.Height));
+ }
+ }
+ }
+
+ private void InvalidateDirty ()
+ {
+ Invalidate (dirty);
+ Update();
+ dirty = Rectangle.Empty;
+ }
+
+ void OnMouseEnter (object sender, EventArgs e)
+ {
+ if (ThemeEngine.Current.ScrollBarHasHoverArrowButtonStyle) {
+ Region region_to_invalidate = new Region (first_arrow_area);
+ region_to_invalidate.Union (second_arrow_area);
+ Invalidate (region_to_invalidate);
+ }
+ }
+
+ void OnMouseLeave (object sender, EventArgs e)
+ {
+ Region region_to_invalidate = new Region ();
+ region_to_invalidate.MakeEmpty ();
+ bool dirty = false;
+ if (ThemeEngine.Current.ScrollBarHasHoverArrowButtonStyle) {
+ region_to_invalidate.Union (first_arrow_area);
+ region_to_invalidate.Union (second_arrow_area);
+ dirty = true;
+ } else
+ if (ThemeEngine.Current.ScrollBarHasHotElementStyles)
+ if (first_button_entered) {
+ region_to_invalidate.Union (first_arrow_area);
+ dirty = true;
+ } else if (second_button_entered) {
+ region_to_invalidate.Union (second_arrow_area);
+ dirty = true;
+ }
+ if (ThemeEngine.Current.ScrollBarHasHotElementStyles)
+ if (thumb_entered) {
+ region_to_invalidate.Union (thumb_pos);
+ dirty = true;
+ }
+ first_button_entered = false;
+ second_button_entered = false;
+ thumb_entered = false;
+ if (dirty)
+ Invalidate (region_to_invalidate);
+ region_to_invalidate.Dispose ();
+ }
+ #endregion //Private Methods
+ protected override void OnMouseWheel (MouseEventArgs e)
+ {
+ base.OnMouseWheel (e);
+ }
+
+ #region UIA Framework Section: Events, Methods and Properties.
+
+ //NOTE:
+ // We are using Reflection to add/remove internal events.
+ // Class ScrollBarButtonInvokePatternInvokeEvent uses the events.
+ //
+ // Types used to generate UIA InvokedEvent
+ // * args.Type = ScrollEventType.LargeIncrement. Space between Thumb and bottom/right Button
+ // * args.Type = ScrollEventType.LargeDecrement. Space between Thumb and top/left Button
+ // * args.Type = ScrollEventType.SmallIncrement. Small increment UIA Button (bottom/right Button)
+ // * args.Type = ScrollEventType.SmallDecrement. Small decrement UIA Button (top/left Button)
+ // Types used to generate RangeValue-related events
+ // * args.Type = ScrollEventType.LargeIncrement. LargeChange event
+ // * args.Type = ScrollEventType.Last. Maximum event
+ // * args.Type = ScrollEventType.First. Minimum event
+ // * args.Type = ScrollEventType.SmallIncrement. SmallChange event
+ static object UIAScrollEvent = new object ();
+ static object UIAValueChangeEvent = new object ();
+
+ internal event ScrollEventHandler UIAScroll {
+ add { Events.AddHandler (UIAScrollEvent, value); }
+ remove { Events.RemoveHandler (UIAScrollEvent, value); }
+ }
+
+ internal event ScrollEventHandler UIAValueChanged {
+ add { Events.AddHandler (UIAValueChangeEvent, value); }
+ remove { Events.RemoveHandler (UIAValueChangeEvent, value); }
+ }
+
+ internal void OnUIAScroll (ScrollEventArgs args)
+ {
+ ScrollEventHandler eh = (ScrollEventHandler) Events [UIAScrollEvent];
+ if (eh != null)
+ eh (this, args);
+ }
+
+ internal void OnUIAValueChanged (ScrollEventArgs args)
+ {
+ ScrollEventHandler eh = (ScrollEventHandler) Events [UIAValueChangeEvent];
+ if (eh != null)
+ eh (this, args);
+ }
+
+ //NOTE:
+ // Wrapper methods used by the Reflection.
+ // Class ScrollBarButtonInvokeProviderBehavior uses the events.
+ //
+ internal void UIALargeIncrement ()
+ {
+ LargeIncrement ();
+ }
+
+ internal void UIALargeDecrement ()
+ {
+ LargeDecrement ();
+ }
+
+ internal void UIASmallIncrement ()
+ {
+ SmallIncrement ();
+ }
+
+ internal void UIASmallDecrement ()
+ {
+ SmallDecrement ();
+ }
+
+ internal Rectangle UIAThumbArea {
+ get { return thumb_area; }
+ }
+
+ internal Rectangle UIAThumbPosition {
+ get { return thumb_pos; }
+ }
+
+ #endregion UIA Framework Section: Events, Methods and Properties.
+
+ }
+}
+
+
+