diff options
Diffstat (limited to 'source/ShiftUI/Widgets/TrackBar.cs')
| -rw-r--r-- | source/ShiftUI/Widgets/TrackBar.cs | 907 |
1 files changed, 907 insertions, 0 deletions
diff --git a/source/ShiftUI/Widgets/TrackBar.cs b/source/ShiftUI/Widgets/TrackBar.cs new file mode 100644 index 0000000..a0952a8 --- /dev/null +++ b/source/ShiftUI/Widgets/TrackBar.cs @@ -0,0 +1,907 @@ +// +// ShiftUI.TrackBar.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-2006 Novell, Inc. +// +// Authors: +// Jordi Mas i Hernandez, [email protected] +// Rolf Bjarne Kvinge, [email protected] +// +// TODO: +// - The AutoSize functionality seems quite broken for vertical Widgets in .Net 1.1. Not +// sure if we are implementing it the right way. +// + +// NOT COMPLETE + +using System.ComponentModel; +using System.ComponentModel.Design; +using System.Drawing; +using System.Drawing.Imaging; +using System.Drawing.Drawing2D; +using System.Timers; +using System.Runtime.InteropServices; +using System; + +namespace ShiftUI +{ + [DefaultBindingProperty ("Value")] + [ComVisible (true)] + [ClassInterface (ClassInterfaceType.AutoDispatch)] + //[Designer("ShiftUI.Design.TrackBarDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] + [DefaultEvent ("Scroll")] + [DefaultProperty("Value")] + [ToolboxWidget] + public class TrackBar : Widget, ISupportInitialize + { + private int minimum; + private int maximum; + internal int tickFrequency; + private bool autosize; + private int position; + private int smallChange; + private int largeChange; + private Orientation orientation; + private TickStyle tickStyle; + private Rectangle thumb_pos = new Rectangle (); /* Current position and size of the thumb */ + private Rectangle thumb_area = new Rectangle (); /* Area where the thumb can scroll */ + internal bool thumb_pressed = false; + private System.Timers.Timer holdclick_timer = new System.Timers.Timer (); + internal int thumb_mouseclick; + private bool mouse_clickmove; + private bool is_moving_right; // which way the thumb should move when mouse is down (right=up, left=down) + internal int mouse_down_x_offset; // how far from left side of thumb was the mouse clicked. + internal bool mouse_moved; // has the mouse moved since it was clicked? + private const int size_of_autosize = 45; + private bool right_to_left_layout; + bool thumb_entered; + + #region events + //[EditorBrowsable (EditorBrowsableState.Always)] + [Browsable (true)] + public new event EventHandler AutoSizeChanged { + add {base.AutoSizeChanged += value;} + remove {base.AutoSizeChanged -= value;} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler BackgroundImageChanged { + add { base.BackgroundImageChanged += value; } + remove { base.BackgroundImageChanged -= value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + 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 EventHandler PaddingChanged + { + add { base.PaddingChanged += value; } + remove { base.PaddingChanged -= value; } + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event PaintEventHandler Paint { + add { base.Paint += value; } + remove { base.Paint -= value; } + } + + public event EventHandler RightToLeftLayoutChanged { + add {Events.AddHandler (RightToLeftLayoutChangedEvent, value);} + remove {Events.RemoveHandler (RightToLeftLayoutChangedEvent, value);} + } + + [Browsable (false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new event EventHandler TextChanged { + add { base.TextChanged += value; } + remove { base.TextChanged -= value; } + } + + static object RightToLeftLayoutChangedEvent = new object (); + static object ScrollEvent = new object (); + static object ValueChangedEvent = new object (); + + public event EventHandler Scroll { + add { Events.AddHandler (ScrollEvent, value); } + remove { Events.RemoveHandler (ScrollEvent, value); } + } + + public event EventHandler ValueChanged { + add { Events.AddHandler (ValueChangedEvent, value); } + remove { Events.RemoveHandler (ValueChangedEvent, value); } + } + + #endregion // Events + + #region UIA FrameWork Events + static object UIAValueParamChangedEvent = new object (); + + internal event EventHandler UIAValueParamChanged { + add { Events.AddHandler (UIAValueParamChangedEvent, value); } + remove { Events.RemoveHandler (UIAValueParamChangedEvent, value); } + } + + internal void OnUIAValueParamChanged () + { + EventHandler eh = (EventHandler) Events [UIAValueParamChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + #endregion + + public TrackBar () + { + orientation = Orientation.Horizontal; + minimum = 0; + maximum = 10; + tickFrequency = 1; + autosize = true; + position = 0; + tickStyle = TickStyle.BottomRight; + smallChange = 1; + largeChange = 5; + mouse_clickmove = false; + MouseDown += new MouseEventHandler (OnMouseDownTB); + MouseUp += new MouseEventHandler (OnMouseUpTB); + MouseMove += new MouseEventHandler (OnMouseMoveTB); + MouseLeave += new EventHandler (OnMouseLeave); + KeyDown += new KeyEventHandler (OnKeyDownTB); + LostFocus += new EventHandler (OnLostFocusTB); + GotFocus += new EventHandler (OnGotFocusTB); + holdclick_timer.Elapsed += new ElapsedEventHandler (OnFirstClickTimer); + + SetStyle (Widgetstyles.UserPaint | Widgetstyles.Opaque | Widgetstyles.UseTextForAccessibility, false); + } + + #region Private & Internal Properties + internal Rectangle ThumbPos { + get { + return thumb_pos; + } + + set { + thumb_pos = value; + } + } + + internal Rectangle ThumbArea { + get { + return thumb_area; + } + + set { + thumb_area = value; + } + } + + internal bool ThumbEntered { + get { return thumb_entered; } + set { + if (thumb_entered == value) + return; + thumb_entered = value; + if (ThemeEngine.Current.TrackBarHasHotThumbStyle) + Invalidate (GetRealThumbRectangle ()); + } + } + #endregion // Private & Internal Properties + + #region Public Properties + + [Browsable (true)] + //[EditorBrowsable (EditorBrowsableState.Always)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Visible)] + [DefaultValue (true)] + public override bool AutoSize { + get { return autosize; } + set { autosize = value;} + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Image BackgroundImage { + get { return base.BackgroundImage; } + set { 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 ImeMode DefaultImeMode { + get {return ImeMode.Disable; } + } + + protected override Size DefaultSize { + get { return ThemeEngine.Current.TrackBarDefaultSize; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + protected override bool DoubleBuffered { + get { + return base.DoubleBuffered; + } + set { + base.DoubleBuffered = value; + } + } + + [Browsable(false)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public override Font Font { + get { return base.Font; } + set { base.Font = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public override Color ForeColor { + get { return base.ForeColor; } + set { base.ForeColor = value; } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Browsable (false)] + public new ImeMode ImeMode { + get { return base.ImeMode; } + set { base.ImeMode = value; } + } + + [DefaultValue (5)] + public int LargeChange + { + get { return largeChange; } + set { + if (value < 0) + throw new ArgumentOutOfRangeException (string.Format ("Value '{0}' must be greater than or equal to 0.", value)); + + largeChange = value; + + OnUIAValueParamChanged (); + } + } + + [DefaultValue (10)] + [RefreshProperties (RefreshProperties.All)] + public int Maximum { + get { return maximum; } + set { + if (maximum != value) { + maximum = value; + + if (maximum < minimum) + minimum = maximum; + + Refresh (); + + OnUIAValueParamChanged (); + } + } + } + + [DefaultValue (0)] + [RefreshProperties (RefreshProperties.All)] + public int Minimum { + get { return minimum; } + set { + + if (Minimum != value) { + minimum = value; + + if (minimum > maximum) + maximum = minimum; + + Refresh (); + + OnUIAValueParamChanged (); + } + } + } + + [DefaultValue (Orientation.Horizontal)] + [Localizable (true)] + public Orientation Orientation { + get { return orientation; } + set { + if (!Enum.IsDefined (typeof (Orientation), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Orientation", value)); + + /* Orientation can be changed once the control has been created */ + if (orientation != value) { + orientation = value; + + if (this.IsHandleCreated) { + Size = new Size (Height, Width); + Refresh (); + } + } + } + } + + [Browsable (false)] + //[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] + //[EditorBrowsable (EditorBrowsableState.Never)] + public new Padding Padding { + get { + return base.Padding; + } + set { + base.Padding = value; + } + } + + [Localizable (true)] + [DefaultValue (false)] + public virtual bool RightToLeftLayout { + get { + return right_to_left_layout; + } + set { + if (value != right_to_left_layout) { + right_to_left_layout = value; + OnRightToLeftLayoutChanged (EventArgs.Empty); + } + } + } + + [DefaultValue (1)] + public int SmallChange { + get { return smallChange;} + set { + if (value < 0) + throw new ArgumentOutOfRangeException (string.Format ("Value '{0}' must be greater than or equal to 0.", value)); + + if (smallChange != value) { + smallChange = value; + + OnUIAValueParamChanged (); + } + } + } + + //[EditorBrowsable (EditorBrowsableState.Never)] + [Bindable (false)] + [Browsable (false)] + public override string Text { + get { return base.Text; } + set { base.Text = value; } + } + + [DefaultValue (1)] + public int TickFrequency { + get { return tickFrequency; } + set { + if ( value > 0 ) { + tickFrequency = value; + Refresh (); + } + } + } + + [DefaultValue (TickStyle.BottomRight)] + public TickStyle TickStyle { + get { return tickStyle; } + set { + if (!Enum.IsDefined (typeof (TickStyle), value)) + throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for TickStyle", value)); + + if (tickStyle != value) { + tickStyle = value; + Refresh (); + } + } + } + + [DefaultValue (0)] + [Bindable (true)] + public int Value { + get { return position; } + set { + SetValue (value, false); + } + } + + void SetValue (int value, bool fire_onscroll) + { + 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) + return; + + position = value; + + // OnScroll goes before OnValueChanged + if (fire_onscroll) + OnScroll (EventArgs.Empty); + + // XXX any reason we don't call OnValueChanged here? + EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); + if (eh != null) + eh (this, EventArgs.Empty); + + Invalidate (thumb_area); + } + + #endregion //Public Properties + + #region Public Methods + + public void BeginInit () + { + + } + + protected override void CreateHandle () + { + base.CreateHandle (); + } + + protected override void SetBoundsCore (int x, int y,int width, int height, BoundsSpecified specified) + { + if (AutoSize) { + if (orientation == Orientation.Vertical) { + width = size_of_autosize; + } else { + height = size_of_autosize; + } + } + base.SetBoundsCore (x, y, width, height, specified); + } + + public void EndInit () + { + + } + + protected override bool IsInputKey (Keys keyData) + { + if ((keyData & Keys.Alt) == 0) { + switch (keyData & Keys.KeyCode) { + case Keys.Down: + case Keys.Right: + case Keys.Up: + case Keys.Left: + case Keys.PageUp: + case Keys.PageDown: + case Keys.Home: + case Keys.End: + return true; + } + } + return base.IsInputKey (keyData); + } + + protected override void OnBackColorChanged (EventArgs e) + { + base.OnBackColorChanged (e); + } + + protected override void OnHandleCreated (EventArgs e) + { + base.OnHandleCreated (e); + + if (AutoSize) + if (Orientation == Orientation.Horizontal) + Size = new Size (Width, 40); + else + Size = new Size (50, Height); + + UpdatePos (Value, true); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected override void OnMouseWheel (MouseEventArgs e) + { + base.OnMouseWheel (e); + + if (!Enabled) return; + + if (e.Delta > 0) + SmallDecrement (); + else + SmallIncrement (); + } + + //[EditorBrowsable (EditorBrowsableState.Advanced)] + protected virtual void OnRightToLeftLayoutChanged (EventArgs e) + { + EventHandler eh = (EventHandler)Events [RightToLeftLayoutChangedEvent]; + if (eh != null) + eh (this, e); + } + + protected virtual void OnScroll (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ScrollEvent]); + if (eh != null) + eh (this, e); + } + + protected override void OnSystemColorsChanged (EventArgs e) + { + base.OnSystemColorsChanged (e); + Invalidate (); + } + + protected virtual void OnValueChanged (EventArgs e) + { + EventHandler eh = (EventHandler)(Events [ValueChangedEvent]); + if (eh != null) + eh (this, e); + } + + public void SetRange (int minValue, int maxValue) + { + Minimum = minValue; + Maximum = maxValue; + } + + public override string ToString() + { + return string.Format("ShiftUI.TrackBar, Minimum: {0}, Maximum: {1}, Value: {2}", + Minimum, Maximum, Value); + } + + + protected override void WndProc (ref Message m) + { + base.WndProc (ref m); + + // Basically we want Widgetstyles.ResizeRedraw but + // tests say we can't set that flag + if ((Msg)m.Msg == Msg.WM_WINDOWPOSCHANGED && Visible) + Invalidate (); + } + + #endregion Public Methods + + #region Private Methods + + private void UpdatePos (int newPos, bool update_trumbpos) + { + if (newPos < minimum){ + SetValue (minimum, true); + } + else { + if (newPos > maximum) { + SetValue (maximum, true); + } + else { + SetValue (newPos, true); + } + } + } + + // Used by UIA implementation, so making internal + internal void LargeIncrement () + { + UpdatePos (position + LargeChange, true); + Invalidate (thumb_area); + } + + // Used by UIA implementation, so making internal + internal void LargeDecrement () + { + UpdatePos (position - LargeChange, true); + Invalidate (thumb_area); + } + + private void SmallIncrement () + { + UpdatePos (position + SmallChange, true); + Invalidate (thumb_area); + } + + private void SmallDecrement () + { + UpdatePos (position - SmallChange, true); + Invalidate (thumb_area); + } + + private void OnMouseUpTB (object sender, MouseEventArgs e) + { + if (!Enabled) return; + + if (thumb_pressed == true || mouse_clickmove == true) { + thumb_pressed = false; + holdclick_timer.Enabled = false; + this.Capture = false; + Invalidate (thumb_area); + } + } + + private void OnMouseDownTB (object sender, MouseEventArgs e) + { + if (!Enabled) return; + + mouse_moved = false; + + bool fire_timer = false; + + Point point = new Point (e.X, e.Y); + + if (orientation == Orientation.Horizontal) { + + if (thumb_pos.Contains (point)) { + this.Capture = true; + thumb_pressed = true; + thumb_mouseclick = e.X; + mouse_down_x_offset = e.X - thumb_pos.X; + Invalidate (thumb_area); + } + else { + if (thumb_area.Contains (point)) { + is_moving_right = e.X > thumb_pos.X + thumb_pos.Width; + if (is_moving_right) + LargeIncrement (); + else + LargeDecrement (); + + Invalidate (thumb_area); + fire_timer = true; + mouse_clickmove = true; + } + } + } + else { + Rectangle vertical_thumb_pos = thumb_pos; + vertical_thumb_pos.Width = thumb_pos.Height; + vertical_thumb_pos.Height = thumb_pos.Width; + if (vertical_thumb_pos.Contains (point)) { + this.Capture = true; + thumb_pressed = true; + thumb_mouseclick = e.Y; + mouse_down_x_offset = e.Y - thumb_pos.Y; + Invalidate (thumb_area); + } + else { + if (thumb_area.Contains (point)) { + is_moving_right = e.Y > thumb_pos.Y + thumb_pos.Width; + if (is_moving_right) + LargeDecrement (); + else + LargeIncrement (); + + Invalidate (thumb_area); + fire_timer = true; + mouse_clickmove = true; + } + } + } + + if (fire_timer) { + holdclick_timer.Interval = 300; + holdclick_timer.Enabled = true; + } + } + + private void OnMouseMoveTB (object sender, MouseEventArgs e) + { + if (!Enabled) return; + + mouse_moved = true; + + /* Moving the thumb */ + if (thumb_pressed) + SetValue (ThemeEngine.Current.TrackBarValueFromMousePosition (e.X, e.Y, this), true); + + ThumbEntered = GetRealThumbRectangle ().Contains (e.Location); + } + + Rectangle GetRealThumbRectangle () + { + Rectangle result = thumb_pos; + if (Orientation == Orientation.Vertical) { + result.Width = thumb_pos.Height; + result.Height = thumb_pos.Width; + } + return result; + } + + internal override void OnPaintInternal (PaintEventArgs pevent) + { + ThemeEngine.Current.DrawTrackBar (pevent.Graphics, pevent.ClipRectangle, this); + } + + private void OnLostFocusTB (object sender, EventArgs e) + { + Invalidate(); + } + + private void OnGotFocusTB (object sender, EventArgs e) + { + Invalidate(); + } + private void OnKeyDownTB (object sender, KeyEventArgs e) + { + bool horiz = Orientation == Orientation.Horizontal; + switch (e.KeyCode) { + + case Keys.Down: + case Keys.Right: + if(horiz) + SmallIncrement(); + else + SmallDecrement (); + break; + + case Keys.Up: + case Keys.Left: + if (horiz) + SmallDecrement(); + else + SmallIncrement(); + break; + + case Keys.PageUp: + if (horiz) + LargeDecrement(); + else + LargeIncrement(); + break; + + case Keys.PageDown: + if (horiz) + LargeIncrement(); + else + LargeDecrement(); + break; + + case Keys.Home: + if (horiz) + SetValue (Minimum, true); + else + SetValue (Maximum, true); + break; + + case Keys.End: + if (horiz) + SetValue (Maximum, true); + else + SetValue (Minimum, true); + break; + + default: + break; + } + } + + private void OnFirstClickTimer (Object source, ElapsedEventArgs e) + { + Point pnt; + pnt = PointToClient (MousePosition); + /* + On Win32 the thumb only moves in one direction after a click, + if the thumb passes the clicked point it will never go in the + other way unless the mouse is released and clicked again. This + is also true if the mouse moves while beeing hold down. + */ + + if (thumb_area.Contains (pnt)) { + bool invalidate = false; + if (orientation == Orientation.Horizontal) { + if (pnt.X > thumb_pos.X + thumb_pos.Width && is_moving_right) { + LargeIncrement (); + invalidate = true; + } else if (pnt.X < thumb_pos.X && !is_moving_right) { + LargeDecrement (); + invalidate = true; + } + } else { + if (pnt.Y > thumb_pos.Y + thumb_pos.Width && is_moving_right) { + LargeDecrement (); + invalidate = true; + } else if (pnt.Y < thumb_pos.Y && !is_moving_right) { + LargeIncrement (); + invalidate = true; + } + } + if (invalidate) + // A Refresh is necessary because the mouse is down and if we just invalidate + // we'll only get paint events once in a while. + Refresh(); + } + } + + void OnMouseLeave (object sender, EventArgs e) + { + ThumbEntered = false; + } + #endregion // Private Methods + } +} + |
