1548 lines
40 KiB
C#
1548 lines
40 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
using DevComponents.DotNetBar.Charts.Style;
|
|
|
|
namespace DevComponents.DotNetBar.Charts
|
|
{
|
|
[ToolboxItem(false)]
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
public class HScrollBarLite : ScrollBarLite
|
|
{
|
|
public HScrollBarLite()
|
|
{
|
|
Orientation = Orientation.Horizontal;
|
|
}
|
|
}
|
|
|
|
[ToolboxItem(false)]
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
public class VScrollBarLite : ScrollBarLite
|
|
{
|
|
public VScrollBarLite()
|
|
{
|
|
Orientation = Orientation.Vertical;
|
|
}
|
|
}
|
|
|
|
[ToolboxItem(false)]
|
|
[TypeConverter(typeof(BlankExpandableObjectConverter))]
|
|
public class ScrollBarLite : ChartVisualElement
|
|
{
|
|
#region Events
|
|
|
|
#region Scroll
|
|
|
|
/// <summary>
|
|
/// Occurs when the Horizontal or Vertical scrollbar has been scrolled
|
|
/// </summary>
|
|
[Description("Occurs when the Horizontal or Vertical scrollbar has been scrolled.")]
|
|
public event EventHandler<ScrollEventArgs> Scroll;
|
|
|
|
#endregion
|
|
|
|
#region ValueChanged
|
|
|
|
/// <summary>
|
|
/// Occurs when the Value property is changed.
|
|
/// </summary>
|
|
public event EventHandler<ValueChangedEventArgs> ValueChanged;
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Private Variables
|
|
|
|
private Orientation _Orientation = Orientation.Horizontal;
|
|
|
|
private int _LargeChange = 10;
|
|
private int _Maximum = 100;
|
|
private int _Minimum;
|
|
private int _SmallChange = 1;
|
|
private int _Value;
|
|
|
|
private bool _Enabled = true;
|
|
|
|
private Rectangle _ArrowIncreaseBounds;
|
|
private Rectangle _ArrowDecreaseBounds;
|
|
private Rectangle _ThumbBounds;
|
|
|
|
private Size _MinArrowSize = new Size(5, 7);
|
|
private Size _MaxArrowSize = new Size(50, 50);
|
|
private Size _MinThumbSize = new Size(10, 12);
|
|
|
|
private ScrollBarVisualStyles _ScrollBarVisualStyles;
|
|
private EffectiveStyles<ScrollBarVisualStyle> _EffectiveStyles;
|
|
|
|
private ItemHitArea _HitArea;
|
|
private ItemHitArea _LastHitArea;
|
|
private ItemHitArea _MouseDownHitArea;
|
|
private int _ThumbOffset;
|
|
|
|
private Timer _ClickTimer;
|
|
private int _ClickCount;
|
|
private bool _RaiseEndScroll;
|
|
|
|
private bool _Inverted;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
public ScrollBarLite()
|
|
{
|
|
Size = new Size(10, 10);
|
|
|
|
_EffectiveStyles = new EffectiveStyles<ScrollBarVisualStyle>(this);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Public properties
|
|
|
|
#region Enabled
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public bool Enabled
|
|
{
|
|
get { return (_Enabled); }
|
|
|
|
internal set
|
|
{
|
|
if (value != _Enabled)
|
|
{
|
|
_Enabled = value;
|
|
|
|
InvalidateRender();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Orientation
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public Orientation Orientation
|
|
{
|
|
get { return (_Orientation); }
|
|
|
|
internal set
|
|
{
|
|
if (value != _Orientation)
|
|
{
|
|
_Orientation = value;
|
|
|
|
InvalidateLayout();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ScrollBarVisualStyles
|
|
|
|
/// <summary>
|
|
/// Gets or sets the visual styles for the ScrollBar.
|
|
/// </summary>
|
|
[Category("Style")]
|
|
[Description("Indicates the visual styles for the ScrollBar.")]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
|
|
public ScrollBarVisualStyles ScrollBarVisualStyles
|
|
{
|
|
get
|
|
{
|
|
if (_ScrollBarVisualStyles == null)
|
|
{
|
|
_ScrollBarVisualStyles = new ScrollBarVisualStyles();
|
|
|
|
StyleVisualChangeHandler(null, _ScrollBarVisualStyles);
|
|
}
|
|
|
|
return (_ScrollBarVisualStyles);
|
|
}
|
|
|
|
set
|
|
{
|
|
if (_ScrollBarVisualStyles != value)
|
|
{
|
|
ScrollBarVisualStyles oldValue = _ScrollBarVisualStyles;
|
|
|
|
_ScrollBarVisualStyles = value;
|
|
|
|
OnStyleChanged("ScrollBarVisualStyles", oldValue, value);
|
|
|
|
if (oldValue != null)
|
|
oldValue.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Value
|
|
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public int Value
|
|
{
|
|
get { return (_Value); }
|
|
|
|
set
|
|
{
|
|
if (value < Minimum)
|
|
throw new ArgumentOutOfRangeException("Value must be >= to Minimum property value.");
|
|
|
|
if (value > Maximum)
|
|
throw new ArgumentOutOfRangeException("Value must be <= to Maximum property value.");
|
|
|
|
value = NormalizeValue(value);
|
|
|
|
if (value != _Value)
|
|
{
|
|
int oldValue = _Value;
|
|
_Value = value;
|
|
|
|
OnValueChanged(oldValue, value);
|
|
|
|
InvalidateLayoutBounds(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
#region OnValueChanged
|
|
|
|
private void OnValueChanged(int oldValue, int newValue)
|
|
{
|
|
if (ValueChanged != null)
|
|
{
|
|
ValueChangedEventArgs args
|
|
= new ValueChangedEventArgs(oldValue, newValue);
|
|
|
|
ValueChanged(this, args);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Visible
|
|
|
|
/// <summary>
|
|
/// Get or sets whether the item is visible
|
|
/// </summary>
|
|
[Browsable(false)]
|
|
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
|
public new bool Visible
|
|
{
|
|
get { return (base.Visible); }
|
|
set { base.Visible = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Internal properties
|
|
|
|
#region Height
|
|
|
|
internal int Height
|
|
{
|
|
get { return (BoundsRelative.Height); }
|
|
|
|
set
|
|
{
|
|
if (value != BoundsRelative.Height)
|
|
{
|
|
Rectangle r = BoundsRelative;
|
|
|
|
_ThumbOffset -= (value - r.Height);
|
|
|
|
r.Height = value;
|
|
|
|
BoundsRelative = r;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Inverted
|
|
|
|
internal bool Inverted
|
|
{
|
|
get { return (_Inverted); }
|
|
set { _Inverted = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsAtMaxumum
|
|
|
|
internal bool IsAtMaxumum
|
|
{
|
|
get { return (_Value + _LargeChange >= _Maximum); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsAtMinumum
|
|
|
|
internal bool IsAtMinumum
|
|
{
|
|
get { return (_Value == _Minimum); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsVertical
|
|
|
|
internal bool IsVertical
|
|
{
|
|
get { return (Orientation == Orientation.Vertical); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region LargeChange
|
|
|
|
internal int LargeChange
|
|
{
|
|
get { return (_LargeChange); }
|
|
|
|
set
|
|
{
|
|
if (value != _LargeChange)
|
|
{
|
|
if (value < 0)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
_LargeChange = value;
|
|
|
|
InvalidateRender();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Location
|
|
|
|
internal Point Location
|
|
{
|
|
get { return (BoundsRelative.Location); }
|
|
|
|
set
|
|
{
|
|
Rectangle r = BoundsRelative;
|
|
r.Location = value;
|
|
|
|
BoundsRelative = r;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Maximum
|
|
|
|
internal int Maximum
|
|
{
|
|
get { return (_Maximum); }
|
|
|
|
set
|
|
{
|
|
if (value != _Maximum)
|
|
{
|
|
_Maximum = value;
|
|
|
|
InvalidateRender();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Minimum
|
|
|
|
internal int Minimum
|
|
{
|
|
get { return (_Minimum); }
|
|
|
|
set
|
|
{
|
|
if (value != _Minimum)
|
|
{
|
|
_Minimum = value;
|
|
|
|
InvalidateRender();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SmallChange
|
|
|
|
internal int SmallChange
|
|
{
|
|
get { return (_SmallChange); }
|
|
|
|
set
|
|
{
|
|
if (value != _SmallChange)
|
|
{
|
|
if (value < 0)
|
|
throw new ArgumentOutOfRangeException();
|
|
|
|
_SmallChange = value;
|
|
|
|
InvalidateRender();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Width
|
|
|
|
internal int Width
|
|
{
|
|
get { return (BoundsRelative.Width); }
|
|
|
|
set
|
|
{
|
|
if (value != BoundsRelative.Width)
|
|
{
|
|
Rectangle r = BoundsRelative;
|
|
|
|
_ThumbOffset -= (value - r.Width);
|
|
|
|
r.Width = value;
|
|
|
|
BoundsRelative = r;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MeasureOverride
|
|
|
|
protected override void MeasureOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ArrangeOverride
|
|
|
|
protected override void ArrangeOverride(ChartLayoutInfo layoutInfo)
|
|
{
|
|
UpdateBarBounds();
|
|
}
|
|
|
|
#region UpdateBarBounds
|
|
|
|
private void UpdateBarBounds()
|
|
{
|
|
Rectangle bounds = Bounds;
|
|
|
|
_ThumbBounds = Rectangle.Empty;
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
int arrowWidth = Height;
|
|
arrowWidth = Math.Max(arrowWidth, _MinArrowSize.Width);
|
|
arrowWidth = Math.Min(arrowWidth, _MaxArrowSize.Width);
|
|
|
|
_ArrowDecreaseBounds = bounds;
|
|
_ArrowDecreaseBounds.Width = arrowWidth;
|
|
|
|
_ArrowIncreaseBounds = bounds;
|
|
_ArrowIncreaseBounds.X = _ArrowIncreaseBounds.Right - arrowWidth;
|
|
_ArrowIncreaseBounds.Width = arrowWidth;
|
|
|
|
if (bounds.Width > (_ArrowDecreaseBounds.Width +
|
|
_ArrowIncreaseBounds.Width + _MinThumbSize.Width))
|
|
{
|
|
int tv = Maximum - Minimum;
|
|
int width = Width - (2 * arrowWidth);
|
|
int x = (width * Value) / tv;
|
|
|
|
_ThumbBounds = bounds;
|
|
_ThumbBounds.X += (x + arrowWidth);
|
|
_ThumbBounds.Width = GetThumbSize();
|
|
_ThumbBounds.Y += 1;
|
|
_ThumbBounds.Height -= 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int arrowHeight = Width;
|
|
arrowHeight = Math.Max(arrowHeight, _MinArrowSize.Height);
|
|
arrowHeight = Math.Min(arrowHeight, _MaxArrowSize.Height);
|
|
|
|
_ArrowDecreaseBounds = bounds;
|
|
_ArrowDecreaseBounds.Height = arrowHeight;
|
|
|
|
_ArrowIncreaseBounds = bounds;
|
|
_ArrowIncreaseBounds.Y = bounds.Bottom - arrowHeight;
|
|
_ArrowIncreaseBounds.Height = arrowHeight;
|
|
|
|
if (bounds.Height > (_ArrowDecreaseBounds.Height +
|
|
_ArrowIncreaseBounds.Height + _MinThumbSize.Height))
|
|
{
|
|
int tv = Maximum - Minimum;
|
|
int height = Height - (2 * arrowHeight);
|
|
int y = (height * Value) / tv;
|
|
|
|
_ThumbBounds = bounds;
|
|
_ThumbBounds.Height = GetThumbSize();
|
|
|
|
if (Inverted == true)
|
|
_ThumbBounds.Y = (bounds.Bottom - _ThumbBounds.Height) - (y + arrowHeight);
|
|
else
|
|
_ThumbBounds.Y += (y + arrowHeight);
|
|
|
|
_ThumbBounds.X += 1;
|
|
_ThumbBounds.Width -= 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
#region GetThumbSize
|
|
|
|
private int GetThumbSize()
|
|
{
|
|
int size = GetAvailableTrackArea();
|
|
|
|
int i = (int)(size * ((float)LargeChange / (float)(Maximum - Minimum))) + 1;
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
i = Math.Max(_MinThumbSize.Width, i);
|
|
else
|
|
i = Math.Max(_MinThumbSize.Height, i);
|
|
|
|
i = Math.Min(i, size);
|
|
|
|
return i;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetAvailableTrackArea
|
|
|
|
private int GetAvailableTrackArea()
|
|
{
|
|
Rectangle r = BoundsRelative;
|
|
|
|
int size;
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
size = r.Width - (_ArrowDecreaseBounds.Width + _ArrowIncreaseBounds.Width);
|
|
else
|
|
size = r.Height - (_ArrowDecreaseBounds.Height + _ArrowIncreaseBounds.Height);
|
|
|
|
return Math.Max(size, 8);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderOverride
|
|
|
|
protected override void RenderOverride(ChartRenderInfo renderInfo)
|
|
{
|
|
Graphics g = renderInfo.Graphics;
|
|
|
|
if (CanDrawScrollBar())
|
|
{
|
|
Rectangle bounds = Bounds;
|
|
|
|
RenderBackground(g, bounds);
|
|
|
|
RenderArrowDecrease(g, bounds);
|
|
RenderArrowIncrease(g, bounds);
|
|
|
|
RenderThumb(g, bounds);
|
|
|
|
RenderBorder(g, bounds);
|
|
}
|
|
}
|
|
|
|
#region CanDrawScrollBar
|
|
|
|
private bool CanDrawScrollBar()
|
|
{
|
|
Rectangle bounds = Bounds;
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
if (bounds.Height < _MinArrowSize.Height)
|
|
return (false);
|
|
|
|
int widthNeeded = (_ArrowIncreaseBounds.Width + _ArrowDecreaseBounds.Width);
|
|
|
|
return (bounds.Width >= widthNeeded);
|
|
}
|
|
else
|
|
{
|
|
if (bounds.Width < _MinArrowSize.Width)
|
|
return (false);
|
|
|
|
int heightNeeded = (_ArrowIncreaseBounds.Height + _ArrowDecreaseBounds.Height);
|
|
|
|
return (bounds.Height >= heightNeeded);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderBackground
|
|
|
|
private void RenderBackground(Graphics g, Rectangle bounds)
|
|
{
|
|
ScrollBarVisualStyle style = GetEffectiveStyle();
|
|
|
|
bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
|
|
|
|
using (Brush br = style.TrackBackground.GetBrush(bounds, noAlpha))
|
|
g.FillRectangle(br, bounds);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderArrowDecrease
|
|
|
|
private void RenderArrowDecrease(Graphics g, Rectangle bounds)
|
|
{
|
|
ScrollBarVisualStyle style = GetAreaStyle(Inverted == true ? ItemHitArea.ArrowIncrease : ItemHitArea.ArrowDecrease);
|
|
Rectangle r = _ArrowDecreaseBounds;
|
|
|
|
bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
|
|
|
|
using (Brush br = style.ArrowBackground.GetBrush(r, noAlpha))
|
|
g.FillRectangle(br, r);
|
|
|
|
if (style.ArrowColor.IsEmpty == false)
|
|
{
|
|
Color color = style.GetColor(style.ArrowColor, noAlpha);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
{
|
|
int n = Math.Min(r.Width, r.Height) / 4 + 1;
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
int x = r.X + (n * 5 / 4);
|
|
int y = r.Y + (r.Height / 2);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
g.DrawLine(pen, x + i, y - i, x + i + 1, y - i);
|
|
g.DrawLine(pen, x + i, y + i, x + i + 1, y + i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int x = r.X + (r.Width / 2);
|
|
int y = r.Y + (n * 5 / 4);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
g.DrawLine(pen, x - i, y + i, x - i, y + i + 1);
|
|
g.DrawLine(pen, x + i, y + i, x + i, y + i + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (style.ArrowBorderColor.IsEmpty == false)
|
|
{
|
|
Color color = style.GetColor(style.ArrowBorderColor, noAlpha);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
g.DrawRectangle(pen, r);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderArrowIncrease
|
|
|
|
private void RenderArrowIncrease(Graphics g, Rectangle bounds)
|
|
{
|
|
ScrollBarVisualStyle style = GetAreaStyle(Inverted == true ? ItemHitArea.ArrowDecrease : ItemHitArea.ArrowIncrease);
|
|
Rectangle r = _ArrowIncreaseBounds;
|
|
|
|
bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
|
|
|
|
using (Brush br = style.ArrowBackground.GetBrush(r, noAlpha))
|
|
g.FillRectangle(br, r);
|
|
|
|
if (style.ArrowColor.IsEmpty == false)
|
|
{
|
|
Color color = style.GetColor(style.ArrowColor, noAlpha);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
{
|
|
int n = Math.Min(r.Width, r.Height) / 4 + 1;
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
int x = r.Right - (n * 5 / 4);
|
|
int y = r.Y + (r.Height / 2);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
g.DrawLine(pen, x - i, y - i, x - i - 1, y - i);
|
|
g.DrawLine(pen, x - i, y + i, x - i - 1, y + i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int x = r.X + (r.Width / 2);
|
|
int y = r.Bottom - (n * 5 / 4);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
g.DrawLine(pen, x - i, y - i, x - i, y - i - 1);
|
|
g.DrawLine(pen, x + i, y - i, x + i, y - i - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (style.ArrowBorderColor.IsEmpty == false)
|
|
{
|
|
Color color = style.GetColor(style.ArrowBorderColor, noAlpha);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
g.DrawRectangle(pen, r);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderThumb
|
|
|
|
private void RenderThumb(Graphics g, Rectangle bounds)
|
|
{
|
|
if (_ThumbBounds.IsEmpty == false)
|
|
{
|
|
ScrollBarVisualStyle style = GetAreaStyle(ItemHitArea.Thumb);
|
|
|
|
bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
|
|
|
|
using (Brush br = style.ThumbBackground.GetBrush(_ThumbBounds, noAlpha))
|
|
g.FillRectangle(br, _ThumbBounds);
|
|
|
|
if (style.ThumbColor.IsEmpty == false)
|
|
{
|
|
Color color = style.GetColor(style.ThumbColor, noAlpha);
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
RenderHThumbHashMarks(g, bounds, color);
|
|
else
|
|
RenderVThumbHashMarks(g, bounds, color);
|
|
}
|
|
|
|
if (style.ThumbBorderColor.IsEmpty == false)
|
|
{
|
|
Color color = style.GetColor(style.ThumbBorderColor, noAlpha);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
g.DrawRectangle(pen, _ThumbBounds);
|
|
}
|
|
}
|
|
}
|
|
|
|
#region RenderHThumbHashMarks
|
|
|
|
private void RenderHThumbHashMarks(
|
|
Graphics g, Rectangle bounds, Color color)
|
|
{
|
|
Rectangle r = _ThumbBounds;
|
|
|
|
if (_ThumbBounds.Width > 20)
|
|
{
|
|
int n = r.Height / 6 + 1;
|
|
int m = r.Height / 10 + 1;
|
|
|
|
r.X += (r.Width / 2 - 1 - m);
|
|
r.Y += n;
|
|
|
|
r.Width = m * 2 + 3;
|
|
r.Height -= (n * 2);
|
|
|
|
Point pt1 = new Point(r.X, r.Y);
|
|
Point pt2 = new Point(r.X, r.Bottom);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
g.DrawLine(pen, pt1, pt2);
|
|
|
|
pt1.X += (m + 1);
|
|
pt2.X += (m + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region RenderVThumbHashMarks
|
|
|
|
private void RenderVThumbHashMarks(
|
|
Graphics g, Rectangle bounds, Color color)
|
|
{
|
|
Rectangle r = _ThumbBounds;
|
|
|
|
if (_ThumbBounds.Height > 20)
|
|
{
|
|
int n = r.Width / 6 + 1;
|
|
int m = r.Width / 10 + 1;
|
|
|
|
r.Y += (r.Height / 2 - 1 - m);
|
|
r.X += n;
|
|
|
|
r.Height = m * 2 + 3;
|
|
r.Width -= (n * 2);
|
|
|
|
Point pt1 = new Point(r.Left, r.Y);
|
|
Point pt2 = new Point(r.Right, r.Y);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
{
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
g.DrawLine(pen, pt1, pt2);
|
|
|
|
pt1.Y += (m + 1);
|
|
pt2.Y += (m + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region RenderBorder
|
|
|
|
private void RenderBorder(Graphics g, Rectangle bounds)
|
|
{
|
|
ScrollBarVisualStyle style = GetEffectiveStyle();
|
|
|
|
if (style.BorderColor.IsEmpty == false)
|
|
{
|
|
bool noAlpha = (style.NoAlphaOnMouseOver == Tbool.True) ? IsMouseOver : false;
|
|
|
|
Color color = style.GetColor(style.BorderColor, noAlpha);
|
|
|
|
using (Pen pen = new Pen(color))
|
|
g.DrawRectangle(pen, bounds);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetAreaStyle
|
|
|
|
private ScrollBarVisualStyle GetAreaStyle(ItemHitArea scrollBarArea)
|
|
{
|
|
StyleState state = StyleState.Default;
|
|
|
|
if (_HitArea == scrollBarArea)
|
|
state |= StyleState.MouseOver;
|
|
|
|
if (_MouseDownHitArea == scrollBarArea)
|
|
state |= StyleState.Selected;
|
|
|
|
return (GetEffectiveStyle(state));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Mouse handling
|
|
|
|
#region OnMouseEnter
|
|
|
|
protected override bool OnMouseEnter(EventArgs e)
|
|
{
|
|
ChartCursor = Cursors.Default;
|
|
|
|
InvalidateRender();
|
|
|
|
return (true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OnMouseLeave
|
|
|
|
protected override bool OnMouseLeave(EventArgs e)
|
|
{
|
|
_HitArea = ItemHitArea.None;
|
|
|
|
InvalidateRender();
|
|
|
|
return (true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OnMouseMove
|
|
|
|
/// <summary>
|
|
/// InternalMouseMove
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
protected override bool OnMouseMove(MouseEventArgs e)
|
|
{
|
|
_HitArea = GetHitArea(e.Location);
|
|
|
|
if (_HitArea != _LastHitArea)
|
|
{
|
|
_LastHitArea = _HitArea;
|
|
|
|
InvalidateRender();
|
|
}
|
|
|
|
if (IsMouseDown == false)
|
|
_MouseDownHitArea = ItemHitArea.None;
|
|
|
|
if (_MouseDownHitArea == ItemHitArea.Thumb)
|
|
ProcessThumbMove(e);
|
|
|
|
ChartCursor = Cursors.Default;
|
|
|
|
return (true);
|
|
}
|
|
|
|
#region ProcessThumbMove
|
|
|
|
private void ProcessThumbMove(MouseEventArgs e)
|
|
{
|
|
int track;
|
|
int tc;
|
|
int tv = Maximum - Minimum - _LargeChange;
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
track = e.Location.X - _ThumbOffset;
|
|
track -= _ArrowDecreaseBounds.Right;
|
|
|
|
tc = Width - (_ArrowDecreaseBounds.Width + _ArrowIncreaseBounds.Width + _ThumbBounds.Width);
|
|
}
|
|
else
|
|
{
|
|
track = e.Location.Y - _ThumbOffset;
|
|
track -= _ArrowDecreaseBounds.Bottom;
|
|
|
|
tc = Height - (_ArrowDecreaseBounds.Height + _ArrowIncreaseBounds.Height + _ThumbBounds.Height);
|
|
}
|
|
|
|
if (tc > 0)
|
|
{
|
|
int value = (tv * track) / tc;
|
|
|
|
if (Inverted == true)
|
|
value = tv - value;
|
|
|
|
SetScrollValue(value, ScrollEventType.ThumbPosition);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region OnMouseDown
|
|
|
|
protected override bool OnMouseDown(MouseEventArgs e)
|
|
{
|
|
_MouseDownHitArea = _HitArea;
|
|
|
|
if (_HitArea != ItemHitArea.None)
|
|
{
|
|
ChartControl.CapturedItem = this;
|
|
|
|
switch (_HitArea)
|
|
{
|
|
case ItemHitArea.Thumb:
|
|
if (Orientation == Orientation.Horizontal)
|
|
_ThumbOffset = MouseDownPoint.X - _ThumbBounds.X;
|
|
else
|
|
_ThumbOffset = MouseDownPoint.Y - _ThumbBounds.Y;
|
|
break;
|
|
|
|
case ItemHitArea.TrackDecrease:
|
|
SetScrollValue(Value - _LargeChange, ScrollEventType.LargeDecrement);
|
|
break;
|
|
|
|
case ItemHitArea.TrackIncrease:
|
|
SetScrollValue(Value + _LargeChange, ScrollEventType.LargeIncrement);
|
|
break;
|
|
|
|
case ItemHitArea.ArrowDecrease:
|
|
SetScrollValue(Value - _SmallChange, ScrollEventType.SmallDecrement);
|
|
break;
|
|
|
|
case ItemHitArea.ArrowIncrease:
|
|
SetScrollValue(Value + _SmallChange, ScrollEventType.SmallIncrement);
|
|
break;
|
|
}
|
|
|
|
if (_HitArea != ItemHitArea.Thumb)
|
|
SetupClickTimer();
|
|
}
|
|
|
|
InvalidateRender();
|
|
|
|
return (true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OnMouseUp
|
|
|
|
protected override bool OnMouseUp(MouseEventArgs e)
|
|
{
|
|
ChartControl.CapturedItem = null;
|
|
|
|
if (_MouseDownHitArea != ItemHitArea.None)
|
|
{
|
|
if (_RaiseEndScroll == true)
|
|
{
|
|
OnScroll(ScrollEventType.EndScroll, Value, Value);
|
|
|
|
_RaiseEndScroll = false;
|
|
}
|
|
}
|
|
|
|
DisposeTimer();
|
|
|
|
_MouseDownHitArea = ItemHitArea.None;
|
|
|
|
InvalidateRender();
|
|
|
|
return (true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region NormalizeValue
|
|
|
|
private int NormalizeValue(int value)
|
|
{
|
|
value = Math.Max(Minimum, value);
|
|
|
|
if (value + _LargeChange > _Maximum)
|
|
value = _Maximum - _LargeChange;
|
|
|
|
return (value);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Timer support
|
|
|
|
#region SetupClickTimer
|
|
|
|
private void SetupClickTimer()
|
|
{
|
|
if (_ClickTimer == null)
|
|
{
|
|
_ClickCount = 0;
|
|
|
|
_ClickTimer = new Timer();
|
|
_ClickTimer.Interval = 100;
|
|
_ClickTimer.Tick += new EventHandler(ClickTimerTick);
|
|
|
|
_ClickTimer.Enabled = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DisposeTimer
|
|
|
|
private void DisposeTimer()
|
|
{
|
|
Timer clickTimer = _ClickTimer;
|
|
|
|
if (clickTimer != null)
|
|
{
|
|
_ClickTimer = null;
|
|
|
|
clickTimer.Enabled = false;
|
|
clickTimer.Tick -= new EventHandler(ClickTimerTick);
|
|
|
|
clickTimer.Dispose();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ClickTimerTick
|
|
|
|
private void ClickTimerTick(object sender, EventArgs e)
|
|
{
|
|
if (IsMouseDown == true)
|
|
{
|
|
if (_MouseDownHitArea == ItemHitArea.TrackDecrease || _MouseDownHitArea == ItemHitArea.TrackIncrease)
|
|
{
|
|
Point pt = ChartControl.PointToClient(Control.MousePosition);
|
|
|
|
if (_ThumbBounds.Contains(pt))
|
|
{
|
|
DisposeTimer();
|
|
}
|
|
else
|
|
{
|
|
if (_MouseDownHitArea == ItemHitArea.TrackDecrease)
|
|
SetScrollValue(Value - _LargeChange, ScrollEventType.LargeDecrement);
|
|
else
|
|
SetScrollValue(Value + _LargeChange, ScrollEventType.LargeIncrement);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_HitArea == ItemHitArea.ArrowDecrease)
|
|
SetScrollValue(Value - _SmallChange, ScrollEventType.SmallDecrement);
|
|
|
|
else if (_HitArea == ItemHitArea.ArrowIncrease)
|
|
SetScrollValue(Value + _SmallChange, ScrollEventType.SmallIncrement);
|
|
|
|
else
|
|
{
|
|
_ClickCount = 0;
|
|
_ClickTimer.Interval = 100;
|
|
}
|
|
}
|
|
|
|
Timer clickTimer = _ClickTimer;
|
|
|
|
if (clickTimer != null)
|
|
{
|
|
_ClickCount++;
|
|
|
|
if (_ClickCount > 4 && clickTimer.Interval > 20)
|
|
clickTimer.Interval -= 10;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region SetScrollValue
|
|
|
|
private void SetScrollValue(int value, ScrollEventType type)
|
|
{
|
|
value = NormalizeValue(value);
|
|
int oldValue = _Value;
|
|
|
|
Value = value;
|
|
|
|
OnScroll(type, _Value, oldValue);
|
|
|
|
_RaiseEndScroll = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OnScroll
|
|
|
|
private void OnScroll(ScrollEventType type, int oldValue, int newValue)
|
|
{
|
|
ScrollEventArgs args = null;
|
|
|
|
if (Scroll != null)
|
|
{
|
|
ScrollOrientation so = (Orientation == Orientation.Horizontal)
|
|
? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll;
|
|
|
|
args = new ScrollEventArgs(type, oldValue, newValue, so);
|
|
|
|
Scroll(this, args);
|
|
}
|
|
|
|
if (ChartControl.IsScrollHooked == true)
|
|
{
|
|
if (args == null)
|
|
{
|
|
ScrollOrientation so = (Orientation == Orientation.Horizontal)
|
|
? ScrollOrientation.HorizontalScroll : ScrollOrientation.VerticalScroll;
|
|
|
|
args = new ScrollEventArgs(type, oldValue, newValue, so);
|
|
}
|
|
|
|
ChartControl.DoScrollEvent((ChartContainer)Parent, args, this);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetBarAreaAt
|
|
|
|
public override ItemHitArea GetHitArea(Point pt)
|
|
{
|
|
if ((Bounds.Contains(pt) == false) ||
|
|
(Visible == false || Enabled == false))
|
|
{
|
|
return (ItemHitArea.None);
|
|
}
|
|
|
|
if (_ArrowDecreaseBounds.Contains(pt))
|
|
return (Inverted ? ItemHitArea.ArrowIncrease : ItemHitArea.ArrowDecrease);
|
|
|
|
if (_ArrowIncreaseBounds.Contains(pt))
|
|
return (Inverted ? ItemHitArea.ArrowDecrease : ItemHitArea.ArrowIncrease);
|
|
|
|
if (_ThumbBounds.Contains(pt))
|
|
return (ItemHitArea.Thumb);
|
|
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
if (pt.X < _ThumbBounds.Left)
|
|
{
|
|
if (Inverted == false)
|
|
return (ItemHitArea.TrackDecrease);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pt.Y < _ThumbBounds.Top)
|
|
{
|
|
if (Inverted == false)
|
|
return (ItemHitArea.TrackDecrease);
|
|
}
|
|
}
|
|
|
|
return (ItemHitArea.TrackIncrease);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Style handling
|
|
|
|
#region GetEffectiveStyle
|
|
|
|
///<summary>
|
|
/// Gets the EffectiveStyle for the ScrollBar. The effective
|
|
/// style is a composite, cached style definition.
|
|
///</summary>
|
|
/// <param name="state"></param>
|
|
/// <returns></returns>
|
|
public ScrollBarVisualStyle GetEffectiveStyle(StyleState state)
|
|
{
|
|
return (_EffectiveStyles[state]);
|
|
}
|
|
|
|
///<summary>
|
|
/// Gets the EffectiveStyle for the ScrollBar. The effective
|
|
/// style is a composite, cached style definition.
|
|
///</summary>
|
|
///<returns></returns>
|
|
public ScrollBarVisualStyle GetEffectiveStyle()
|
|
{
|
|
StyleState state = GetStyleState();
|
|
|
|
return (_EffectiveStyles[state]);
|
|
}
|
|
|
|
#region GetStyleState
|
|
|
|
private StyleState GetStyleState()
|
|
{
|
|
StyleState state = StyleState.Default;
|
|
|
|
Point pt = ChartControl.PointToClient(Control.MousePosition);
|
|
|
|
if (Bounds.Contains(pt))
|
|
state |= StyleState.MouseOver;
|
|
|
|
if (_MouseDownHitArea != ItemHitArea.None)
|
|
state |= StyleState.Selected;
|
|
|
|
return (state);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ApplyStyles
|
|
|
|
public override void ApplyStyles(BaseVisualStyle style, StyleType cs)
|
|
{
|
|
ScrollBarVisualStyle pstyle = style as ScrollBarVisualStyle;
|
|
|
|
if (pstyle != null)
|
|
{
|
|
ApplyParentStyles(pstyle, cs, Parent as ChartContainer);
|
|
|
|
pstyle.ApplyStyle(ScrollBarVisualStyles[cs]);
|
|
}
|
|
}
|
|
|
|
#region ApplyParentStyles
|
|
|
|
private void ApplyParentStyles(
|
|
ScrollBarVisualStyle pstyle, StyleType cs, ChartContainer item)
|
|
{
|
|
if (item != null)
|
|
{
|
|
ApplyParentStyles(pstyle, cs, item.Parent as ChartContainer);
|
|
|
|
if (item is ChartXy)
|
|
{
|
|
if (Orientation == Orientation.Horizontal)
|
|
pstyle.ApplyStyle(((ChartXy)item).ChartVisualStyle.HScrollBarVisualStyles[cs]);
|
|
else
|
|
pstyle.ApplyStyle(((ChartXy)item).ChartVisualStyle.VScrollBarVisualStyles[cs]);
|
|
}
|
|
else if (item is ChartPanel)
|
|
{
|
|
if (Orientation == Orientation.Horizontal)
|
|
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.HScrollBarVisualStyles[cs]);
|
|
else
|
|
pstyle.ApplyStyle(((ChartPanel)item).DefaultVisualStyles.VScrollBarVisualStyles[cs]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Orientation == Orientation.Horizontal)
|
|
{
|
|
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.HScrollBarVisualStyles[cs]);
|
|
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.HScrollBarVisualStyles[cs]);
|
|
}
|
|
else
|
|
{
|
|
pstyle.ApplyStyle(ChartControl.BaseVisualStyles.VScrollBarVisualStyles[cs]);
|
|
pstyle.ApplyStyle(ChartControl.DefaultVisualStyles.VScrollBarVisualStyles[cs]);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region ApplyDefaults
|
|
|
|
public override void ApplyDefaults(BaseVisualStyle style, StyleType cs)
|
|
{
|
|
ScrollBarVisualStyle pstyle = style as ScrollBarVisualStyle;
|
|
|
|
if (pstyle != null)
|
|
pstyle.ApplyDefaults();
|
|
|
|
base.ApplyDefaults(style, cs);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region InvalidateStyle
|
|
|
|
///<summary>
|
|
///Invalidate the cached Styles
|
|
///</summary>
|
|
public void InvalidateStyle()
|
|
{
|
|
ClearEffectiveStyles();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ClearEffectiveStyles
|
|
|
|
protected override void ClearEffectiveStyles()
|
|
{
|
|
_EffectiveStyles.InvalidateStyles();
|
|
|
|
base.ClearEffectiveStyles();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region InvalidateLayoutBounds
|
|
|
|
/// <summary>
|
|
/// Invalidates the layout bounds for the item container
|
|
/// </summary>
|
|
public override void InvalidateLayoutBounds(ScrollBarLite sbar)
|
|
{
|
|
ChartVisualElement parent = Parent as ChartVisualElement;
|
|
|
|
if (parent is IScrollable)
|
|
{
|
|
IScrollable isc = (IScrollable)parent;
|
|
|
|
isc.InvalidateLayoutBounds(sbar);
|
|
|
|
Rectangle scrollBounds = GetScrollBounds(isc.ScrollBounds);
|
|
|
|
parent.InvalidateRender(scrollBounds);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSerialData
|
|
|
|
internal override SerialElementCollection GetSerialData(string serialName)
|
|
{
|
|
SerialElementCollection sec = new SerialElementCollection();
|
|
|
|
if (serialName != null)
|
|
{
|
|
if (serialName.Equals("") == true)
|
|
serialName = "ChartXy";
|
|
|
|
sec.AddStartElement(serialName);
|
|
}
|
|
|
|
if (_ScrollBarVisualStyles != null && _ScrollBarVisualStyles.IsEmpty == false)
|
|
sec.AddElement(_ScrollBarVisualStyles.GetSerialData("ScrollBarVisualStyles"));
|
|
|
|
sec.AddElement(base.GetSerialData(null));
|
|
|
|
if (serialName != null)
|
|
sec.AddEndElement(serialName);
|
|
|
|
return (sec);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PutSerialData
|
|
|
|
#region ProcessCollection
|
|
|
|
internal override void ProcessCollection(SerialElement se)
|
|
{
|
|
SerialElementCollection sec = se.Sec;
|
|
|
|
switch (se.Name)
|
|
{
|
|
case "ScrollBarVisualStyles":
|
|
sec.PutSerialData(ScrollBarVisualStyles);
|
|
break;
|
|
|
|
default:
|
|
base.ProcessCollection(se);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region IDisposable
|
|
|
|
public override void Dispose()
|
|
{
|
|
ScrollBarVisualStyles = null;
|
|
|
|
base.Dispose();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region EventArgs
|
|
|
|
#region ValueChangedEventArgs
|
|
|
|
/// <summary>
|
|
/// ValueChangedEventArgs
|
|
/// </summary>
|
|
public class ValueChangedEventArgs : EventArgs
|
|
{
|
|
#region Private variables
|
|
|
|
private int _OldValue;
|
|
private int _NewValue;
|
|
|
|
#endregion
|
|
|
|
///<summary>
|
|
/// ValueChangedEventArgs
|
|
///</summary>
|
|
///<param name="oldValue"></param>
|
|
///<param name="newValue"></param>
|
|
public ValueChangedEventArgs(int oldValue, int newValue)
|
|
{
|
|
_OldValue = oldValue;
|
|
_NewValue = newValue;
|
|
}
|
|
|
|
#region Public properties
|
|
|
|
/// <summary>
|
|
/// Gets the old scroll Value
|
|
/// </summary>
|
|
public int OldValue
|
|
{
|
|
get { return (_OldValue); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the new scroll Value
|
|
/// </summary>
|
|
public int NewValue
|
|
{
|
|
get { return (_NewValue); }
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Interfaces
|
|
|
|
#region IScrollable
|
|
|
|
internal interface IScrollable
|
|
{
|
|
Rectangle ScrollBounds { get; }
|
|
Rectangle ScrollBoundsEx { get; }
|
|
|
|
Point ScrollBoundsOffset { get; }
|
|
|
|
void InvalidateLayoutBounds(ScrollBarLite sbar);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
} |