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 }