using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using DevComponents.Instrumentation.Primitives;
namespace DevComponents.Instrumentation
{
///
/// Defines Knob instrumentation control.
///
[ToolboxItem(true)]
[Designer("DevComponents.Instrumentation.Design.KnobControlDesigner, DevComponents.Instrumentation.Design, Version=14.1.0.37, Culture=neutral, PublicKeyToken=76cb4c6eb576bca5")]
public partial class KnobControl : Control, IDisposable
{
#region Delegates
private delegate void InternalRender(PaintEventArgs e);
public delegate void PreRenderEventHandler(object sender, PreRenderEventArgs e);
public delegate void PostRenderEventHandler(object sender, PostRenderEventArgs e);
public delegate void RenderFocusRectEventHandler(object sender, RenderFocusRectEventArgs e);
#endregion
#region Events
#region RenderEvent
#region PreRender
///
/// Event raised just before the ZoneIndicator is rendered
///
[Description("Event raised just before the ZoneIndicator is rendered ")]
public event PreRenderEventHandler PreRenderZoneIndicator;
///
/// Event raised just before the Minor Tick Marks are rendered
///
[Description("Event raised just before the Minor Tick Marks are rendered ")]
public event PreRenderEventHandler PreRenderTickMinor;
///
/// Event raised just before the Major Tick Marks are rendered
///
[Description("Event raised just before the Major Tick Marks are rendered ")]
public event PreRenderEventHandler PreRenderTickMajor;
///
/// Event raised just before the Tick Labels are rendered
///
[Description("Event raised just before the Tick Labels are rendered ")]
public event PreRenderEventHandler PreRenderTickLabel;
///
/// Event raised just before the KnobFace is rendered
///
[Description("Event raised just before the KnobFace is rendered ")]
public event PreRenderEventHandler PreRenderKnobFace;
///
/// Event raised just before the KnobIndicator is rendered
///
[Description("Event raised just before the KnobIndicator is rendered ")]
public event PreRenderEventHandler PreRenderKnobIndicator;
#endregion
#region PostRender
///
/// Event raised right after the ZoneIndicator is rendered
///
[Description("Event raised right after the ZoneIndicator is rendered ")]
public event PostRenderEventHandler PostRenderZoneIndicator;
///
/// Event raised right after the Minor Tick Marks are rendered
///
[Description("Event raised right after the Minor Tick Marks are rendered ")]
public event PostRenderEventHandler PostRenderTickMinor;
///
/// Event raised right after the Major Tick Marks are rendered
///
[Description("Event raised right after the Major Tick Marks are rendered ")]
public event PostRenderEventHandler PostRenderTickMajor;
///
/// Event raised right after the Tick Labels are rendered
///
[Description("Event raised right after the Tick Labels are rendered ")]
public event PostRenderEventHandler PostRenderTickLabel;
///
/// Event raised right after the KnobFace is rendered
///
[Description("Event raised right after the KnobFace is rendered ")]
public event PostRenderEventHandler PostRenderKnobFace;
///
/// Event raised right after the KnobIndicator is rendered
///
[Description("Event raised right after the KnobIndicator is rendered ")]
public event PostRenderEventHandler PostRenderKnobIndicator;
#endregion
#region RenderFocusRect
///
/// Event raised when the Focus Rectangle needs rendered
///
[Description("Event raised when the Focus Rectangle needs rendered ")]
public event RenderFocusRectEventHandler RenderFocusRect;
#endregion
#endregion
#region ValueChanged
///
/// Event raised when the Focus Rectangle needs rendered
///
[Description("Event raised when the Knob Value has changed.")]
public event EventHandler ValueChanged;
#endregion
#region ColorTableChanged
///
/// Event raised when the Knob ColorTable has changed
///
[Description("Event raised when the Knob ColorTable has changed.")]
public event EventHandler ColorTableChanged;
#endregion
#endregion
#region Constants
internal int MinKnobSize = 60;
#endregion
#region Private variables
private BaseKnob _Knob; // Base knob
private eKnobStyle _KnobStyle = eKnobStyle.Style1; // Default style
private decimal _Value; // Knob Value
private decimal _MajorTickAmount = 10; // Major tick amount
private decimal _MinorTickAmount = 2; // Minor tick amount
private bool _AllowDecimalValueSelection = true; // Allow decimal values or not
private int _SelectionDecimals = 1;
private decimal _MinValue; // Minimum allowable value
private decimal _MaxValue = 100; // Maximum allowable value
private int _StartAngle = 130; // Starting knob angle
private int _SweepAngle = 280; // Sweep angle (start + sweep == end)
private int _MinZonePercentage = 80; // Min zone percentage
private int _MaxZonePercentage = 20; // Max zone percentage
private bool _KnobRotating; // Is the knob being rotated by the mouse?
private decimal _SaveValue; // Rotation cancel value
private bool _FocusCuesEnabled = true; // Are Focus cues enabled?
private bool _ShowTickLabels = true; // Show tick labels?
private bool _ReadOnly; // ReadOnly?
private bool _IgnoreKeyLimits; // Allow key wrapping?
private bool _SetValueOnFocus = true;
private KnobColorTable _KnobColor;
private decimal _SelectionDelta;
private string _TickLabelFormat;
#endregion
///
/// Constructor
///
public KnobControl()
{
// Initialize our control
InitializeComponent();
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.StandardDoubleClick, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
SetStyle(ControlStyles.Selectable, true);
// Set our Knob Style and default KnobColorTable
SetKnobStyle(eKnobStyle.Style1);
KnobColor = new KnobColorTable();
// Hook on to our events
HookEvents(true);
}
#region Public properties
#region AllowDecimalValueSelection
///
/// Gets and sets whether Values with decimals can be used
///
[Browsable(true), Category("Behavior"), DefaultValue(true)]
[Description("Indicates whether Values with decimals can be used")]
public bool AllowDecimalValueSelection
{
get { return (_AllowDecimalValueSelection); }
set { _AllowDecimalValueSelection = value; InvalidateKnob(); }
}
#endregion
#region FocusCuesEnabled
///
/// Gets or sets whether control displays focus cues when focused.
///
[Category("Behavior"), DefaultValue(true)]
[Description("Indicates whether control displays focus cues when focused.")]
public bool FocusCuesEnabled
{
get { return _FocusCuesEnabled; }
set
{
_FocusCuesEnabled = value;
if (this.Focused)
InvalidateKnob();
}
}
#endregion
#region Font
///
/// Gets or sets the KnobControl Font
///
[Browsable(true), Category("Appearance")]
[Description("Indicates the KnobControl Font")]
public override Font Font
{
get { return base.Font; }
set { base.Font = value; InvalidateKnob(); }
}
#endregion
#region IgnoreKeyLimits
///
/// Gets and sets whether key processing will ignore or
/// stop at knob min/max limits (default is 'false').
///
[Browsable(true), Category("Behavior"), DefaultValue(false)]
[Description("Indicates whether key processing will ignore or stop at knob min/max limits (default is 'false').")]
public bool IgnoreKeyLimits
{
get { return (_IgnoreKeyLimits); }
set { _IgnoreKeyLimits = value; }
}
#endregion
#region KnobColor
///
/// Gets and sets the display Colors of the KnobControl
///
[Browsable(true), Category("Appearance")]
[Description("Indicates the display Colors of the KnobControl")]
public KnobColorTable KnobColor
{
get { return (_KnobColor); }
set
{
if (_KnobColor != null)
_KnobColor.ColorTableChanged -= KnobColor_ColorTableChanged;
_KnobColor = value;
if (_KnobColor != null)
_KnobColor.ColorTableChanged += KnobColor_ColorTableChanged;
OnColorTableChanged();
InvalidateKnob();
}
}
///
/// Gets whether property should be serialized
///
public bool ShouldSerializeKnobColor()
{
return (_KnobColor.IsEmpty == false);
}
///
/// Resets property to it's default value
///
public void ResetKnobColor()
{
KnobColor = KnobColorTable.Empty;
}
#endregion
#region KnobStyle
///
/// Gets and sets the display style of the knob
///
[Browsable(true), Category("Appearance"), DefaultValue(eKnobStyle.Style1)]
[Description("Indicates the display style of the knob")]
public eKnobStyle KnobStyle
{
get { return _KnobStyle; }
set
{
if (_KnobStyle != value)
{
SetKnobStyle(value);
InvalidateKnob();
}
}
}
#region SetKnobStyle
///
/// Sets the display style for the control
///
///
private void SetKnobStyle(eKnobStyle style)
{
switch (style)
{
case eKnobStyle.Style1:
_Knob = new KnobStyle1(this);
break;
case eKnobStyle.Style2:
_Knob = new KnobStyle2(this);
break;
case eKnobStyle.Style3:
_Knob = new KnobStyle3(this);
break;
default:
_Knob = new KnobStyle4(this);
break;
}
_KnobStyle = style;
}
#endregion
#endregion
#region MinZonePercentage
///
/// Get and sets the numeric value that
/// represents the MinZoneIndicator percentage
///
[Browsable(true), Category("Appearance"), DefaultValue(80)]
[Description("Indicates numeric value that represents the MinZoneIndicator percentage")]
public int MinZonePercentage
{
get { return (_MinZonePercentage); }
set
{
if (_MinZonePercentage != value)
{
if (value < 0)
{
const string s = "Value must be non-negative.";
throw new ArgumentOutOfRangeException(s);
}
if (value > 100)
{
const string s = "Value must be less or equal to 100.";
throw new ArgumentOutOfRangeException(s);
}
_MinZonePercentage = value;
InvalidateKnob();
}
}
}
#endregion
#region MajorTickAmount
///
/// Gets and sets the amount each
/// major tick represents on the knob
///
[Browsable(true), Category("Appearance")]
[Description("Indicates the amount each major tick represents on the knob")]
public decimal MajorTickAmount
{
get { return _MajorTickAmount; }
set
{
if (_MajorTickAmount != value)
{
if (value < 0)
{
const string s = "Value must be non-negative.";
throw new ArgumentOutOfRangeException(s);
}
_MajorTickAmount = value;
InvalidateKnob();
}
}
}
///
/// Gets whether property should be serialized
///
public bool ShouldSerializeMajorTickAmount()
{
return (_MajorTickAmount != 10);
}
///
/// Resets property to it's default value
///
public void ResetMajorTickAmount()
{
MajorTickAmount = 10;
}
#endregion
#region MaxValue
///
/// Get and sets the upper limit of the knob range
///
[Browsable(true), Category("Behavior"), DefaultValue(100)]
[Description("Indicates the upper limit of the knob range")]
public decimal MaxValue
{
get
{
return ((_AllowDecimalValueSelection == false) ?
Math.Round(_MaxValue) : Math.Round(_MaxValue, _SelectionDecimals));
}
set
{
if (_MaxValue != value)
{
if (value <= MinValue)
MinValue = value - 1;
_MaxValue = value;
// Keep the current Value within the
// users MinValue and MaxValue range
if (_Value > _MaxValue)
_Value = _MaxValue;
InvalidateKnob();
}
}
}
///
/// Gets whether property should be serialized
///
public bool ShouldSerializeMaxValue()
{
return (_MaxValue != 100);
}
///
/// Resets property to it's default value
///
public void ResetMaxValue()
{
MaxValue = 100;
}
#endregion
#region MinorTickAmount
///
/// Gets and sets the amount each
/// minor tick represents on the knob
///
[Browsable(true), Category("Appearance")]
[Description("Indicates the amount each minor tick represents on the knob")]
public decimal MinorTickAmount
{
get { return _MinorTickAmount; }
set
{
if (_MinorTickAmount != value)
{
if (value < 0)
{
const string s = "Value must be non-negative.";
throw new ArgumentOutOfRangeException(s);
}
_MinorTickAmount = value;
InvalidateKnob();
}
}
}
///
/// Gets whether property should be serialized
///
public bool ShouldSerializeMinorTickAmount()
{
return (_MinorTickAmount != 2);
}
///
/// Resets property to it's default value
///
public void ResetMinorTickAmount()
{
MinorTickAmount = 2;
}
#endregion
#region MinValue
///
/// Gets and sets the lower limit of the knob range
///
[Browsable(true), Category("Behavior"), DefaultValue(0)]
[Description("Indicates the lower limit of the knob range")]
public decimal MinValue
{
get
{
return ((_AllowDecimalValueSelection == false) ?
Math.Round(_MinValue) : Math.Round(_MinValue, _SelectionDecimals));
}
set
{
if (_MinValue != value)
{
if (value >= MaxValue)
MaxValue = value + 1;
_MinValue = value;
// Keep the current Value within the
// users MinValue and MaxValue range
if (_Value < _MinValue)
_Value = _MinValue;
InvalidateKnob();
}
}
}
///
/// Gets whether property should be serialized
///
public bool ShouldSerializeMinValue()
{
return (_MinValue != 100);
}
///
/// Resets property to it's default value
///
public void ResetMinValue()
{
MinValue = 0;
}
#endregion
#region MaxZonePercentage
///
/// Get and sets the numeric value that
/// represents the MaxZoneIndicator percentage
///
[Browsable(true), Category("Appearance"), DefaultValue(20)]
[Description("Indicates numeric value that represents the MaxZoneIndicator percentage")]
public int MaxZonePercentage
{
get { return (_MaxZonePercentage); }
set
{
if (_MaxZonePercentage != value)
{
if (value < 0)
{
const string s = "Value must be non-negative.";
throw new ArgumentOutOfRangeException(s);
}
if (value > 100)
{
const string s = "Value must be less or equal to 100.";
throw new ArgumentOutOfRangeException(s);
}
_MaxZonePercentage = value;
InvalidateKnob();
}
}
}
#endregion
#region ReadOnly
///
/// Get and sets the (user access) ReadOnly state of the control
///
[Browsable(true), Category("Behavior"), DefaultValue(false)]
[Description("Indicates the (user access) ReadOnly state of the control")]
public bool ReadOnly
{
get { return (_ReadOnly); }
set { _ReadOnly = value; }
}
#endregion
#region SelectionDecimals
///
/// Gets and sets the number of selection decimals. This is used in conjunction with AllowDecimalValueSelection.
///
[Browsable(true), Category("Behavior"), DefaultValue(1)]
[Description("Indicates the number of selection decimals. This is used in conjunction with AllowDecimalValueSelection.")]
public int SelectionDecimals
{
get { return (_SelectionDecimals); }
set { _SelectionDecimals = value; InvalidateKnob(); }
}
#endregion
#region SelectionDelta
///
/// Gets or sets the delta value used to adjust the knob Value, when
/// the user presses the up or down arrow keys. (0 signifies use of
/// SelectionDecimals precision as default delta value.)
///
[Browsable(true), Category("Behavior"), DefaultValue(typeof(Decimal), "0")]
[Description("Indicates the delta value used to adjust the knob Value, when the user presses the up or down arrow keys. (0 signifies use of SelectionDecimals precision as default delta value.)")]
public decimal SelectionDelta
{
get { return (_SelectionDelta); }
set { _SelectionDelta = value; }
}
#endregion
#region SetValueOnFocus
///
/// Gets and sets whether the knob Value will be set when
/// knob is given focus via mouse selection.
///
[Browsable(true), Category("Behavior"), DefaultValue(true)]
[Description("Indicates whether the knob Value will be set when knob is given focus via mouse selection")]
public bool SetValueOnFocus
{
get { return (_SetValueOnFocus); }
set { _SetValueOnFocus = value; }
}
#endregion
#region ShowTickLabels
[Category("Behavior"), DefaultValue(true)]
[Description("Indicates whether control displays the MajorTick text labels.")]
public bool ShowTickLabels
{
get { return (_ShowTickLabels); }
set { _ShowTickLabels = value; InvalidateKnob(); }
}
#endregion
#region StartAngle
///
/// Gets and sets the angle measured
/// from the x-axis to the starting point of the gauge zone
///
[Browsable(true), Category("Appearance"), DefaultValue(130)]
[Description("Angle measured from the x-axis to the starting point of the gauge zone")]
public int StartAngle
{
get { return _StartAngle; }
set
{
if (_StartAngle != value)
{
if (value < 0 || value > 360)
{
const string s = "Value must be between 0 and 360, inclusive.";
throw new ArgumentOutOfRangeException(s);
}
_StartAngle = value;
InvalidateKnob();
}
}
}
#endregion
#region SweepAngle
///
/// Get and sets the angle measured from the StartAngle to the ending point of the gauge zone.
/// Positive values signify clockwise rotation; negative values, counter-clockwise rotation.
///
[Browsable(true), Category("Appearance"), DefaultValue(280)]
[Description("Angle measured from the StartAngle to the ending point of the gauge zone. Positive values signify clockwise rotation; negative values, counter-clockwise rotation.")]
public int SweepAngle
{
get { return _SweepAngle; }
set
{
if (_SweepAngle != value)
{
int n = Math.Abs(value);
if (n > 360)
{
const string s = "Value must be between -360 and 360, inclusive.";
throw new ArgumentOutOfRangeException(s);
}
_SweepAngle = value;
InvalidateKnob();
}
}
}
#endregion
#region TickLabelFormat
///
/// Get and sets the .Net Numeric Format String
/// specifier to be used for the numeric knob tick labels.
///
[Browsable(true), Category("Appearance"), DefaultValue(null)]
[Description("Indicates the .Net Numeric Format String specifier to be used for the numeric knob tick labels.")]
public string TickLabelFormat
{
get { return (_TickLabelFormat); }
set
{
_TickLabelFormat = value;
InvalidateKnob();
}
}
#endregion
#region Value
///
/// Gets and sets the numeric value that
/// represents the current position of the knob selector
///
[Browsable(true), Category("Behavior")]
[Description("Indicates numeric value that represents the current position of the knob selector")]
public decimal Value
{
get
{
return (_Value);
}
set
{
if (_Value != value)
{
value = (_AllowDecimalValueSelection == false) ?
Math.Round(value) : (Math.Round(value, _SelectionDecimals));
if (value < MinValue)
{
const string s = "Value must be greater or equal than the Minimum property value.";
throw new ArgumentOutOfRangeException(s);
}
if (value > MaxValue)
{
const string s = "Value must be greater or equal than the Maximum property value.";
throw new ArgumentOutOfRangeException(s);
}
decimal oldValue = _Value;
_Value = value;
OnValueChanged(oldValue, value);
InvalidateKnob();
}
}
}
///
/// Gets whether property should be serialized
///
public bool ShouldSerializeValue()
{
return (Value != 0);
}
///
/// Resets property to it's default value
///
public void ResetValue()
{
Value = 0;
}
#endregion
#endregion
#region HookEvents
///
/// Hooks or unhooks needed events
///
/// true to hook
private void HookEvents(bool hook)
{
if (hook == true)
Resize += KnobControl_Resize;
else
Resize -= KnobControl_Resize;
}
#endregion
#region Event processing
#region KnobControl_Resize
///
/// Control Resize processing
///
///
///
void KnobControl_Resize(object sender, EventArgs e)
{
if (Width < MinKnobSize)
Width = MinKnobSize;
if (Height < MinKnobSize)
Height = MinKnobSize;
_Knob.ResetKnob();
}
#endregion
#region KnobColor_ColorTableChanged
void KnobColor_ColorTableChanged(object sender, EventArgs e)
{
Invalidate();
OnColorTableChanged();
}
#endregion
#endregion
#region OnGotFocus
///
/// Handles control GotFocus
///
///
protected override void OnGotFocus(EventArgs e)
{
if (_FocusCuesEnabled == true)
InvalidateKnob();
base.OnGotFocus(e);
}
#endregion
#region OnLostFocus
///
/// Handles control GotFocus
///
///
protected override void OnLostFocus(EventArgs e)
{
if (_FocusCuesEnabled == true)
InvalidateKnob();
base.OnLostFocus(e);
}
#endregion
#region OnValueChanged
///
/// Called when the control 'Value' is changed
///
protected virtual void OnValueChanged(decimal oldValue, decimal newValue)
{
if (ValueChanged != null)
ValueChanged(this, new ValueChangedEventArgs(oldValue, newValue));
}
#endregion
#region OnColorTableChanged
///
/// Called when the Knob ColorTable has changed
///
private void OnColorTableChanged()
{
if (ColorTableChanged != null)
ColorTableChanged(this, EventArgs.Empty);
}
#endregion
#region OnPaint
#region OnPaint
///
/// Paints the contents of the control
///
///
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
SmoothingMode sm = g.SmoothingMode;
g.SmoothingMode = SmoothingMode.AntiAlias;
// Paint our background
using (Brush br = new SolidBrush(BackColor))
{
Rectangle r = Bounds;
r.Location = Point.Empty;
g.FillRectangle(br, r);
}
// Initialize the rendering process
// and render each individual part
_Knob.InitRender(e);
RenderZoneIndicator(e);
RenderTickMinor(e);
RenderTickMajor(e);
RenderTickLabel(e);
RenderKnobFace(e);
RenderKnobIndicator(e);
RenderFocusRectangle(e);
g.SmoothingMode = sm;
}
#endregion
#region RenderZoneIndicator
///
/// RenderZoneIndicator
///
///
private void RenderZoneIndicator(PaintEventArgs e)
{
RenderPart(e, _Knob.ZoneIndicatorBounds,
PreRenderZoneIndicator, PostRenderZoneIndicator, _Knob.RenderZoneIndicator);
}
#endregion
#region RenderTickMinor
///
/// RenderTickMinor
///
///
private void RenderTickMinor(PaintEventArgs e)
{
RenderPart(e, _Knob.ZoneIndicatorBounds,
PreRenderTickMinor, PostRenderTickMinor, _Knob.RenderTickMinor);
}
#endregion
#region RenderTickMajor
///
/// RenderTickMajor
///
///
private void RenderTickMajor(PaintEventArgs e)
{
RenderPart(e, _Knob.ZoneIndicatorBounds,
PreRenderTickMajor, PostRenderTickMajor, _Knob.RenderTickMajor);
}
#endregion
#region RenderTickLabel
///
/// RenderTickLabel
///
///
private void RenderTickLabel(PaintEventArgs e)
{
if (_ShowTickLabels == true)
{
RenderPart(e, _Knob.TickLabelBounds,
PreRenderTickLabel, PostRenderTickLabel, _Knob.RenderTickLabel);
}
}
#endregion
#region RenderKnobFace
///
/// RenderKnobFace
///
///
private void RenderKnobFace(PaintEventArgs e)
{
RenderPart(e, _Knob.KnobFaceBounds,
PreRenderKnobFace, PostRenderKnobFace, _Knob.RenderKnobFace);
}
#endregion
#region RenderKnobIndicator
///
/// RenderKnobIndicator
///
///
private void RenderKnobIndicator(PaintEventArgs e)
{
RenderPart(e, _Knob.KnobIndicatorBounds,
PreRenderKnobIndicator, PostRenderKnobIndicator, _Knob.RenderKnobIndicator);
}
#endregion
#region RenderFocusRectangle
///
/// RenderFocusRectangle
///
///
private void RenderFocusRectangle(PaintEventArgs e)
{
if (_FocusCuesEnabled == true && Focused == true)
{
if (RenderFocusRect != null)
{
RenderFocusRectEventArgs ev =
new RenderFocusRectEventArgs(e.Graphics, e.ClipRectangle, _Knob.FocusRectBounds);
RenderFocusRect(this, ev);
}
else
{
_Knob.RenderFocusRect(e);
}
}
}
#endregion
#region RenderPart
///
/// Renders an individual 'part' of the control knob
///
///
/// Bounding rectangle
/// User PreRender callout
/// User PostRender callout
/// Internal render callout
private void RenderPart(PaintEventArgs e, Rectangle bounds,
PreRenderEventHandler preRender, PostRenderEventHandler postRender,
InternalRender internalRender)
{
bool cancel = false;
// If the user wants to PreRender the control
// then callout to their associated handler
if (preRender != null)
{
PreRenderEventArgs ev =
new PreRenderEventArgs(e.Graphics, e.ClipRectangle, bounds);
preRender(this, ev);
cancel = ev.Cancel;
}
// If our internal rendering was not canceled
// by the user (via the PreRender event), then
// perform our own rendering of the control
if (cancel == false)
{
internalRender(e);
// If the user cancelled our internal rendering
// then their is no need to PostRender, but if not
// then we need to give them another shot at the
// rendering process
if (postRender != null)
{
PostRenderEventArgs ev =
new PostRenderEventArgs(e.Graphics, e.ClipRectangle, bounds);
postRender(this, ev);
}
}
}
#endregion
#endregion
#region Keyboard support
#region IsInputKey
///
/// Routine to signify that the directional keys
/// (up/down/left/right) are special input keys
///
///
/// true if the key is an input key
protected override bool IsInputKey(Keys key)
{
if (_ReadOnly == true)
return (false);
switch (key)
{
// Incrementing keys
case Keys.Up:
case Keys.Right:
case Keys.End:
case Keys.PageUp:
// Decrementing keys
case Keys.Down:
case Keys.Left:
case Keys.Home:
case Keys.PageDown:
return (true);
}
return (base.IsInputKey(key));
}
#endregion
#region OnKeyDown
///
/// Handles knob rotation via key input
///
///
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Handled == false)
{
if (_ReadOnly == false)
{
switch (e.KeyCode)
{
case Keys.Home:
Value = MinValue;
break;
case Keys.End:
Value = MaxValue;
break;
case Keys.Right:
case Keys.Up:
AdjustValue(GetDelta(ModifierKeys, true));
break;
case Keys.Left:
case Keys.Down:
AdjustValue(GetDelta(ModifierKeys, false));
break;
case Keys.PageUp:
AdjustValue(GetDelta(Keys.Control | Keys.Shift, true));
break;
case Keys.PageDown:
AdjustValue(GetDelta(Keys.Control | Keys.Shift, false));
break;
}
}
}
}
#endregion
#region AdjustValue
///
/// Adjusts the Value via the keyboard or mouse
///
///
private void AdjustValue(decimal delta)
{
decimal value = Value + delta;
if (value < MinValue)
value = (IgnoreKeyLimits ? MaxValue - (MinValue - value) : MinValue);
if (value > MaxValue)
value = (IgnoreKeyLimits ? (value - MaxValue) : MaxValue);
Value = value;
}
#endregion
#region GetDelta
///
/// Calculates the delta adjustment for the
/// pos or neg increment with respect to the
/// supplied modifiers (Control/Shift)
///
/// Keys.Control and/or Keys.Shift
/// Denotes whether to increment or decrement
/// Signed delta value
private decimal GetDelta(Keys mods, bool inc)
{
decimal delta = 0;
// If the Control Key is pressed then the user is
// wanting to jump by tick amounts (either Minor or Major)
if ((mods & Keys.Control) == Keys.Control)
{
// Shift Key denotes Major tick changes, no shift
// key denotes Minor tick changes
delta = ((mods & Keys.Shift) == Keys.Shift) ?
MajorTickAmount : MinorTickAmount;
// Make our first adjustment align
// on a tick boundary
if (delta > 0)
{
decimal dv = Value % delta;
if (dv > 0)
delta = inc ? delta - dv : dv;
else if (dv < 0)
delta = inc ? -dv : delta + dv;
if (AllowDecimalValueSelection == false)
delta = Math.Round(delta, 1);
}
}
// Adjust delta to a valid unit
if (delta == 0)
{
// No tick change, so just advance
// by single units
if (_SelectionDelta != 0)
{
delta = _SelectionDelta;
}
else
{
delta = (AllowDecimalValueSelection == true) ?
(decimal)(1 / Math.Pow(10, SelectionDecimals)) : 1;
}
}
return (inc == true ? delta : -delta);
}
#endregion
#endregion
#region Mouse support
#region OnMouseDown
///
/// MouseDown processing
///
///
protected override void OnMouseDown(MouseEventArgs e)
{
if (_ReadOnly == false)
{
// Check to see if the user's MouseDown
// was inside our knob control
Point pt = new Point(e.X, e.Y);
if (DesignMode == false && _Knob.PointInControl(pt) == true)
{
if (SetValueOnFocus == true || Focused == true)
{
// Save the current control Value incase
// the user cancels the operation
_SaveValue = Value;
// Set the new knob Value and set our state
// to signify we are rotating the knob
Value = _Knob.GetValueFromPoint(pt);
Cursor = Cursors.Hand;
_KnobRotating = true;
}
// Give the control the focus
Focus();
}
}
base.OnMouseDown(e);
}
#endregion
#region OnMouseUp
///
/// MouseUp processing
///
///
protected override void OnMouseUp(MouseEventArgs e)
{
// If the user is actively was rotating the knob
// then reset our state processing accordingly
if (_KnobRotating == true)
{
Cursor = Cursors.Default;
_KnobRotating = false;
}
base.OnMouseUp(e);
}
#endregion
#region OnMouseMove
///
/// MouseMove processing
///
///
protected override void OnMouseMove(MouseEventArgs e)
{
// Process the mouse movement if the user
// is actively rotating the knob
if (_KnobRotating == true)
{
Point pt = new Point(e.X, e.Y);
// If the mouse is within the knob control
// then set the new Value accordingly, otherwise
// restore the Value to our previous Value
if (_Knob.PointInControl(pt) == true)
{
Value = _Knob.GetValueFromPoint(pt);
Cursor = Cursors.Hand;
}
else
{
Value = _SaveValue;
Cursor = Cursors.Default;
}
}
base.OnMouseMove(e);
}
#endregion
#region OnMouseWheel
///
/// Handles MouseWheel events
///
///
protected override void OnMouseWheel(MouseEventArgs e)
{
if (_ReadOnly == false)
{
// Adjust the Value based upon the
// MouseWheel delta value
AdjustValue(GetDelta(ModifierKeys, e.Delta > 0));
}
// Add call the base handler
base.OnMouseWheel(e);
}
#endregion
#endregion
#region InvalidateKnob
///
/// Invalidates the knob
///
private void InvalidateKnob()
{
// Signal that the knob definition changed and
// that a reconfigure of the control will need
// to be done
_Knob.ResetKnob();
// Invalidate the control
Invalidate();
}
#endregion
#region GetValueFromPoint
///
/// Gets the Knob value from the given Point
///
/// Point
/// Value
public decimal GetValueFromPoint(Point pt)
{
return (_Knob.GetValueFromPoint(pt));
}
#endregion
#region IDisposable Members
///
/// IDisposable.Dispose
///
void IDisposable.Dispose()
{
HookEvents(false);
Dispose();
}
#endregion
}
#region Enums
///
/// Various Knob Control display styles
///
public enum eKnobStyle
{
Style1,
Style2,
Style3,
Style4
}
#endregion
#region EventArgs
#region PreRenderEventArgs
///
/// PreRenderEventArgs - user cancellable
///
public class PreRenderEventArgs : CancelEventArgs
{
#region Private variables
private Graphics _Graphics; // Graphics object
private Rectangle _ClipRectangle; // Cliprect
private Rectangle _Bounds; // Bounding rectangle
#endregion
///
/// PreRenderEventArgs
///
///
///
///
public PreRenderEventArgs(Graphics graphics, Rectangle clipRectangle, Rectangle bounds)
{
_Graphics = graphics;
_ClipRectangle = clipRectangle;
_Bounds = bounds;
}
#region Public properties
///
/// Gets the event Graphics object
///
public Graphics Graphics
{
get { return (_Graphics); }
}
///
/// Gets the event ClipRectangle
///
public Rectangle ClipRectangle
{
get { return (_ClipRectangle); }
}
///
/// Gets the event Bounds
///
public Rectangle Bounds
{
get { return (_Bounds); }
}
#endregion
}
#endregion
#region PostRenderEventArgs
///
/// PostRenderEventArgs
///
public class PostRenderEventArgs : EventArgs
{
#region Private variables
private Graphics _Graphics; // Graphics object
private Rectangle _ClipRectangle; // Cliprect
private Rectangle _Bounds; // Bounding rectangle
#endregion
///
/// PostRenderEventArgs
///
///
///
///
public PostRenderEventArgs(Graphics graphics, Rectangle clipRectangle, Rectangle bounds)
{
_Graphics = graphics;
_ClipRectangle = clipRectangle;
_Bounds = bounds;
}
#region Public properties
///
/// Gets the event Graphics object
///
public Graphics Graphics
{
get { return (_Graphics); }
}
///
/// Gets the event ClipRectangle
///
public Rectangle ClipRectangle
{
get { return (_ClipRectangle); }
}
///
/// Gets the event Bounds
///
public Rectangle Bounds
{
get { return (_Bounds); }
}
#endregion
}
#endregion
#region RenderFocusRectEventArgs
///
/// RenderFocusRectEventArgs
///
public class RenderFocusRectEventArgs : EventArgs
{
#region Private variables
private Graphics _Graphics; // Graphics object
private Rectangle _ClipRectangle; // Cliprect
private Rectangle _Bounds; // Bounding rectangle
#endregion
///
/// RenderFocusRectEventArgs
///
///
///
///
public RenderFocusRectEventArgs(Graphics graphics, Rectangle clipRectangle, Rectangle bounds)
{
_Graphics = graphics;
_ClipRectangle = clipRectangle;
_Bounds = bounds;
}
#region Public properties
///
/// Gets the event Graphics object
///
public Graphics Graphics
{
get { return (_Graphics); }
}
///
/// Gets the event ClipRectangle
///
public Rectangle ClipRectangle
{
get { return (_ClipRectangle); }
}
///
/// Gets the event Bounds
///
public Rectangle Bounds
{
get { return (_Bounds); }
}
#endregion
}
#endregion
#region ValueChangedEventArgs
///
/// ValueChangedEventArgs
///
public class ValueChangedEventArgs : EventArgs
{
#region Private variables
private decimal _OldValue; // Old value
private decimal _NewValue; // New value
#endregion
///
/// ValueChangedEventArgs
///
public ValueChangedEventArgs(decimal oldValue, decimal newValue)
{
_OldValue = oldValue;
_NewValue = newValue;
}
#region Public properties
///
/// Gets the old value
///
public decimal OldValue
{
get { return (_OldValue); }
}
///
/// Gets the new value
///
public decimal NewValue
{
get { return (_NewValue); }
}
#endregion
}
#endregion
#endregion
}