Click here to Skip to main content
15,880,469 members
Articles / Programming Languages / C#
Article

Owner-drawn trackbar(slider)

Rate me:
Please Sign up or sign in to vote.
4.68/5 (44 votes)
30 Jan 2007LGPL32 min read 229.6K   14.9K   93   43
Implementing a Windows Forms owner-drawn trackbar (slider) control in C#.

Sample Image - ColorSlider.gif

Introduction

This article presents owner-drawn trackbar control. Component is written entirely from scratch. All painting events are done by code. It’s got cool, modern look. The best thing is, however, the capability of changing slider’s thumb shape. It is done simply by providing appropriate graphics path.

Background (optional)

I always wanted to have cool slider for my audio player application. The best I could find here was Guinness4Strength's article. Unfortunately, I didn’t find it pretty enough, so I decided to write my own trackbar. Hopefully you like it.

Properties

Appearance:

  • ThumbSize - Gets or sets the size of the thumb
  • ThumbCustomShape - Gets or sets the thumb custom shape. Use ThumbRect property to determine bounding rectangle.
  • ThumbRoundRectSize - Gets or sets the size of the thumb round rectangle edges.
  • BorderRoundRectSize - Gets or sets the size of the border round rect.

Values:

  • Orientation - Gets or sets the orientation of Slider.
  • Value - Gets or sets the value of Slider.
  • Minimum - Gets or sets the minimum value.
  • Maximum - Gets or sets the maximum value.
  • SmallChange - Gets or sets trackbar's small change. It affects how to behave when directional keys are pressed
  • LargeChange - Gets or sets trackbar's large change. It affects how to behave when PageUp/PageDown keys are pressed

Behavior:

  • DrawFocusRectangle - Gets or sets a value indicating whether to draw focus rectangle.
  • DrawSemitransparentThumb - Gets or sets a value indicating whether to draw semitransparent thumb.
  • MouseEffects - Gets or sets whether mouse entry and exit actions have impact on how control look.
  • MouseWheelBarPartitions - Gets or sets the mouse wheel bar partitions.

Colors:

  • ThumbOuterColor - Gets or sets the thumb outer color.
  • ThumbInnerColor - Gets or sets the inner color of the thumb.
  • ThumbPenColor - Gets or sets the color of the thumb pen.
  • BarOuterColor - Gets or sets the outer color of the bar.
  • BarInnerColor - Gets or sets the inner color of the bar.
  • BarPenColor - Gets or sets the color of the bar pen.
  • ElapsedOuterColor - Gets or sets the outer color of the elapsed.
  • ElapsedInnerColor - Gets or sets the inner color of the elapsed.

Points of Interest

This control will provide design-time support. Next version should contain custom properties editors.

History

  • 30.01.2007 - first version.
  • License

    This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


    Written By
    Architect Nokia Siemens Networks
    Poland Poland
    Michał is C# and whole .NET enthusiast. He graduated from computer science MSc studies at Wroclaw University of Technology, Poland.

    He is interested in photography and diving. He is member of PADI, currently with divemaster certificate.

    His favorite movies are Matrix, Amélie(Le Fabuleux Destin d'Amélie Poulain), Stargate SG-1 TV Serie and comedies of Mel Brooks.

    Michał lives in Wroclaw, Poland. To contact Michał, email him at michal.brylka[mail-'"at'"-sign]op.pl.

    Comments and Discussions

     
    AnswerRe: Panel scrolls on mouse wheel before trackbar Pin
    howardfarrar28-Sep-10 1:13
    howardfarrar28-Sep-10 1:13 
    GeneralMy vote of 5 Pin
    Xmen Real 16-Jul-10 15:48
    professional Xmen Real 16-Jul-10 15:48 
    Generalgood control Pin
    securigy19-Jun-10 0:29
    securigy19-Jun-10 0:29 
    GeneralVery cool, small addition I did for myself Pin
    IssaharNoam22-Mar-09 0:38
    IssaharNoam22-Mar-09 0:38 
    GeneralRe: Very cool, small addition I did for myself Pin
    Xmen Real 16-Jul-10 15:50
    professional Xmen Real 16-Jul-10 15:50 
    Questionorientation slider value reversed Pin
    TVW036-Mar-09 12:11
    TVW036-Mar-09 12:11 
    AnswerRe: orientation slider value reversed [modified] Pin
    tgpfarm11027-Mar-09 14:30
    tgpfarm11027-Mar-09 14:30 
    GeneralRe: orientation slider value reversed [modified] Pin
    Mark Cortejo24-Jul-14 14:55
    Mark Cortejo24-Jul-14 14:55 
    AnswerRe: orientation slider value reversed Pin
    Michal Brylka8-Mar-09 8:57
    Michal Brylka8-Mar-09 8:57 
    GeneralBrilliant implementation! Following slight change I did for myself Pin
    IssaharNoam23-Feb-09 0:42
    IssaharNoam23-Feb-09 0:42 
    GeneralRe: Brilliant implementation! Following slight change I did for myself Pin
    Michal Brylka8-Mar-09 8:42
    Michal Brylka8-Mar-09 8:42 
    GeneralFantastic! Pin
    -Sean-20-Feb-09 11:38
    -Sean-20-Feb-09 11:38 
    GeneralRe: Fantastic! Pin
    Michal Brylka8-Mar-09 6:36
    Michal Brylka8-Mar-09 6:36 
    QuestionConversion to VB? Pin
    Prishalan18-Oct-07 22:59
    Prishalan18-Oct-07 22:59 
    GeneralRe: Conversion to VB? Pin
    Michal Brylka22-Feb-08 2:50
    Michal Brylka22-Feb-08 2:50 
    GeneralSlight improvements Pin
    Jerome Hordies16-Sep-07 5:07
    Jerome Hordies16-Sep-07 5:07 
    Good job !
    In order to use it in my application i made 2 small modifs:
    - I fired the Scroll event after the OnMouse_Wheel
    - I added the support for Image Thumb

    Here is the changed code of ColorSlider.cs:

    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;

    namespace MB.Controls
    {
    /// <summary>
    /// Encapsulates control that visualy displays certain integer value and allows user to change it within desired range. It imitates <see cref="System.Windows.Forms.TrackBar"/> as far as mouse usage is concerned.
    /// </summary>
    [ToolboxBitmap(typeof(TrackBar))]
    [DefaultEvent("Scroll"), DefaultProperty("BarInnerColor")]
    public partial class ColorSlider : Control
    {
    #region Events

    /// <summary>
    /// Fires when Slider position has changed
    /// </summary>
    [Description("Event fires when the Value property changes")]
    [Category("Action")]
    public event EventHandler ValueChanged;

    /// <summary>
    /// Fires when user scrolls the Slider
    /// </summary>
    [Description("Event fires when the Slider position is changed")]
    [Category("Behavior")]
    public event ScrollEventHandler Scroll;

    #endregion

    #region Properties

    private Rectangle thumbRect; //bounding rectangle of thumb area
    /// <summary>
    /// Gets the thumb rect. Usefull to determine bounding rectangle when creating custom thumb shape.
    /// </summary>
    /// <value>The thumb rect.</value>
    [Browsable(false)]
    public Rectangle ThumbRect
    {
    get { return thumbRect; }
    }

    private Rectangle barRect; //bounding rectangle of bar area
    private Rectangle barHalfRect;
    private Rectangle thumbHalfRect;
    private Rectangle elapsedRect; //bounding rectangle of elapsed area

    private int thumbSize = 15;
    /// <summary>
    /// Gets or sets the size of the thumb.
    /// </summary>
    /// <value>The size of the thumb.</value>
    /// <exception cref="T:System.ArgumentOutOfRangeException">exception thrown when value is lower than zero or grather than half of appropiate dimension</exception>
    [Description("Set Slider thumb size")]
    [Category("ColorSlider")]
    [DefaultValue(15)]
    public int ThumbSize
    {
    get { return thumbSize; }
    set
    {
    if (value > 0 &
    value < (barOrientation == Orientation.Horizontal ? ClientRectangle.Width : ClientRectangle.Height))
    thumbSize = value;
    else
    throw new ArgumentOutOfRangeException(
    "TrackSize has to be greather than zero and lower than half of Slider width");
    Invalidate();
    }
    }

    private GraphicsPath thumbCustomShape = null;
    /// <summary>
    /// Gets or sets the thumb custom shape. Use ThumbRect property to determine bounding rectangle.
    /// </summary>
    /// <value>The thumb custom shape. null means default shape</value>
    [Description("Set Slider's thumb's custom shape")]
    [Category("ColorSlider")]
    [Browsable(false)]
    [DefaultValue(typeof(GraphicsPath), "null")]
    public GraphicsPath ThumbCustomShape
    {
    get { return thumbCustomShape; }
    set
    {
    thumbCustomShape = value;
    thumbSize = (int) (barOrientation == Orientation.Horizontal ? value.GetBounds().Width : value.GetBounds().Height) + 1;
    Invalidate();
    }
    }

    private Size thumbRoundRectSize = new Size(8, 8);
    /// <summary>
    /// Gets or sets the size of the thumb round rectangle edges.
    /// </summary>
    /// <value>The size of the thumb round rectangle edges.</value>
    [Description("Set Slider's thumb round rect size")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Size), "8; 8")]
    public Size ThumbRoundRectSize
    {
    get { return thumbRoundRectSize; }
    set
    {
    int h = value.Height, w = value.Width;
    if (h <= 0) h = 1;
    if (w <= 0) w = 1;
    thumbRoundRectSize = new Size(w, h);
    Invalidate();
    }
    }

    private Size borderRoundRectSize = new Size(8, 8);
    /// <summary>
    /// Gets or sets the size of the border round rect.
    /// </summary>
    /// <value>The size of the border round rect.</value>
    [Description("Set Slider's border round rect size")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Size), "8; 8")]
    public Size BorderRoundRectSize
    {
    get { return borderRoundRectSize; }
    set
    {
    int h = value.Height, w = value.Width;
    if (h <= 0) h = 1;
    if (w <= 0) w = 1;
    borderRoundRectSize = new Size(w, h);
    Invalidate();
    }
    }

    private Orientation barOrientation = Orientation.Horizontal;
    /// <summary>
    /// Gets or sets the orientation of Slider.
    /// </summary>
    /// <value>The orientation.</value>
    [Description("Set Slider orientation")]
    [Category("ColorSlider")]
    [DefaultValue(Orientation.Horizontal)]
    public Orientation Orientation
    {
    get { return barOrientation; }
    set
    {
    if (barOrientation != value)
    {
    barOrientation = value;
    int temp = Width;
    Width = Height;
    Height = temp;
    if (thumbCustomShape != null)
    thumbSize =
    (int)
    (barOrientation == Orientation.Horizontal
    ? thumbCustomShape.GetBounds().Width
    : thumbCustomShape.GetBounds().Height) + 1;
    Invalidate();
    }
    }
    }


    private int trackerValue = 50;
    /// <summary>
    /// Gets or sets the value of Slider.
    /// </summary>
    /// <value>The value.</value>
    /// <exception cref="T:System.ArgumentOutOfRangeException">exception thrown when value is outside appropriate range (min, max)</exception>
    [Description("Set Slider value")]
    [Category("ColorSlider")]
    [DefaultValue(50)]
    public int Value
    {
    get { return trackerValue; }
    set
    {
    if (value >= barMinimum & value <= barMaximum)
    {
    trackerValue = value;
    if (ValueChanged != null) ValueChanged(this, new EventArgs());
    Invalidate();
    }
    else throw new ArgumentOutOfRangeException("Value is outside appropriate range (min, max)");
    }
    }


    private int barMinimum = 0;
    /// <summary>
    /// Gets or sets the minimum value.
    /// </summary>
    /// <value>The minimum value.</value>
    /// <exception cref="T:System.ArgumentOutOfRangeException">exception thrown when minimal value is greather than maximal one</exception>
    [Description("Set Slider minimal point")]
    [Category("ColorSlider")]
    [DefaultValue(0)]
    public int Minimum
    {
    get { return barMinimum; }
    set
    {
    if (value < barMaximum)
    {
    barMinimum = value;
    if (trackerValue < barMinimum)
    {
    trackerValue = barMinimum;
    if (ValueChanged != null) ValueChanged(this, new EventArgs());
    }
    Invalidate();
    }
    else throw new ArgumentOutOfRangeException("Minimal value is greather than maximal one");
    }
    }


    private int barMaximum = 100;
    /// <summary>
    /// Gets or sets the maximum value.
    /// </summary>
    /// <value>The maximum value.</value>
    /// <exception cref="T:System.ArgumentOutOfRangeException">exception thrown when maximal value is lower than minimal one</exception>
    [Description("Set Slider maximal point")]
    [Category("ColorSlider")]
    [DefaultValue(100)]
    public int Maximum
    {
    get { return barMaximum; }
    set
    {
    if (value > barMinimum)
    {
    barMaximum = value;
    if (trackerValue > barMaximum)
    {
    trackerValue = barMaximum;
    if (ValueChanged != null) ValueChanged(this, new EventArgs());
    }
    Invalidate();
    }
    else throw new ArgumentOutOfRangeException("Maximal value is lower than minimal one");
    }
    }

    private uint smallChange = 1;
    /// <summary>
    /// Gets or sets trackbar's small change. It affects how to behave when directional keys are pressed
    /// </summary>
    /// <value>The small change value.</value>
    [Description("Set trackbar's small change")]
    [Category("ColorSlider")]
    [DefaultValue(1)]
    public uint SmallChange
    {
    get { return smallChange; }
    set { smallChange = value; }
    }

    private uint largeChange = 5;

    /// <summary>
    /// Gets or sets trackbar's large change. It affects how to behave when PageUp/PageDown keys are pressed
    /// </summary>
    /// <value>The large change value.</value>
    [Description("Set trackbar's large change")]
    [Category("ColorSlider")]
    [DefaultValue(5)]
    public uint LargeChange
    {
    get { return largeChange; }
    set { largeChange = value; }
    }

    private bool drawFocusRectangle = true;
    /// <summary>
    /// Gets or sets a value indicating whether to draw focus rectangle.
    /// </summary>
    /// <value><c>true</c> if focus rectangle should be drawn; otherwise, <c>false</c>.</value>
    [Description("Set whether to draw focus rectangle")]
    [Category("ColorSlider")]
    [DefaultValue(true)]
    public bool DrawFocusRectangle
    {
    get { return drawFocusRectangle; }
    set
    {
    drawFocusRectangle = value;
    Invalidate();
    }
    }

    private bool drawSemitransparentThumb = true;
    /// <summary>
    /// Gets or sets a value indicating whether to draw semitransparent thumb.
    /// </summary>
    /// <value><c>true</c> if semitransparent thumb should be drawn; otherwise, <c>false</c>.</value>
    [Description("Set whether to draw semitransparent thumb")]
    [Category("ColorSlider")]
    [DefaultValue(true)]
    public bool DrawSemitransparentThumb
    {
    get { return drawSemitransparentThumb; }
    set
    {
    drawSemitransparentThumb = value;
    Invalidate();
    }
    }

    private bool mouseEffects = true;
    /// <summary>
    /// Gets or sets whether mouse entry and exit actions have impact on how control look.
    /// </summary>
    /// <value><c>true</c> if mouse entry and exit actions have impact on how control look; otherwise, <c>false</c>.</value>
    [Description("Set whether mouse entry and exit actions have impact on how control look")]
    [Category("ColorSlider")]
    [DefaultValue(true)]
    public bool MouseEffects
    {
    get { return mouseEffects; }
    set
    {
    mouseEffects = value;
    Invalidate();
    }
    }

    private int mouseWheelBarPartitions = 10;
    /// <summary>
    /// Gets or sets the mouse wheel bar partitions.
    /// </summary>
    /// <value>The mouse wheel bar partitions.</value>
    /// <exception cref="T:System.ArgumentOutOfRangeException">exception thrown when value isn't greather than zero</exception>
    [Description("Set to how many parts is bar divided when using mouse wheel")]
    [Category("ColorSlider")]
    [DefaultValue(10)]
    public int MouseWheelBarPartitions
    {
    get { return mouseWheelBarPartitions; }
    set
    {
    if (value > 0)
    mouseWheelBarPartitions = value;
    else throw new ArgumentOutOfRangeException("MouseWheelBarPartitions has to be greather than zero");
    }
    }

    private Image thumbImage = null;
    /// <summary>
    /// Gets or sets the Image use to render the thumb.
    /// </summary>
    /// <value>the thumb Image</value>
    [Description("Set to use a specific Image for the thumb")]
    [Category("ColorSlider")]
    [DefaultValue(null)]
    public Image ThumbImage
    {
    get { return thumbImage; }
    set
    {
    if (value !=null )
    {
    thumbImage = value;
    }
    }
    }

    private Color thumbOuterColor = Color.White;
    /// <summary>
    /// Gets or sets the thumb outer color .
    /// </summary>
    /// <value>The thumb outer color.</value>
    [Description("Set Slider thumb outer color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "White")]
    public Color ThumbOuterColor
    {
    get { return thumbOuterColor; }
    set
    {
    thumbOuterColor = value;
    Invalidate();
    }
    }


    private Color thumbInnerColor = Color.Gainsboro;
    /// <summary>
    /// Gets or sets the inner color of the thumb.
    /// </summary>
    /// <value>The inner color of the thumb.</value>
    [Description("Set Slider thumb inner color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "Gainsboro")]
    public Color ThumbInnerColor
    {
    get { return thumbInnerColor; }
    set
    {
    thumbInnerColor = value;
    Invalidate();
    }
    }


    private Color thumbPenColor = Color.Silver;
    /// <summary>
    /// Gets or sets the color of the thumb pen.
    /// </summary>
    /// <value>The color of the thumb pen.</value>
    [Description("Set Slider thumb pen color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "Silver")]
    public Color ThumbPenColor
    {
    get { return thumbPenColor; }
    set
    {
    thumbPenColor = value;
    Invalidate();
    }
    }


    private Color barOuterColor = Color.SkyBlue;
    /// <summary>
    /// Gets or sets the outer color of the bar.
    /// </summary>
    /// <value>The outer color of the bar.</value>
    [Description("Set Slider bar outer color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "SkyBlue")]
    public Color BarOuterColor
    {
    get { return barOuterColor; }
    set
    {
    barOuterColor = value;
    Invalidate();
    }
    }


    private Color barInnerColor = Color.DarkSlateBlue;
    /// <summary>
    /// Gets or sets the inner color of the bar.
    /// </summary>
    /// <value>The inner color of the bar.</value>
    [Description("Set Slider bar inner color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "DarkSlateBlue")]
    public Color BarInnerColor
    {
    get { return barInnerColor; }
    set
    {
    barInnerColor = value;
    Invalidate();
    }
    }


    private Color barPenColor = Color.Gainsboro;
    /// <summary>
    /// Gets or sets the color of the bar pen.
    /// </summary>
    /// <value>The color of the bar pen.</value>
    [Description("Set Slider bar pen color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "Gainsboro")]
    public Color BarPenColor
    {
    get { return barPenColor; }
    set
    {
    barPenColor = value;
    Invalidate();
    }
    }

    private Color elapsedOuterColor = Color.DarkGreen;
    /// <summary>
    /// Gets or sets the outer color of the elapsed.
    /// </summary>
    /// <value>The outer color of the elapsed.</value>
    [Description("Set Slider's elapsed part outer color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "DarkGreen")]
    public Color ElapsedOuterColor
    {
    get { return elapsedOuterColor; }
    set
    {
    elapsedOuterColor = value;
    Invalidate();
    }
    }

    private Color elapsedInnerColor = Color.Chartreuse;
    /// <summary>
    /// Gets or sets the inner color of the elapsed.
    /// </summary>
    /// <value>The inner color of the elapsed.</value>
    [Description("Set Slider's elapsed part inner color")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(Color), "Chartreuse")]
    public Color ElapsedInnerColor
    {
    get { return elapsedInnerColor; }
    set
    {
    elapsedInnerColor = value;
    Invalidate();
    }
    }

    #endregion

    #region Color schemas

    //define own color schemas
    private Color[,] aColorSchema = new Color[,]
    {
    {
    Color.White, Color.Gainsboro, Color.Silver, Color.SkyBlue, Color.DarkSlateBlue, Color.Gainsboro,
    Color.DarkGreen, Color.Chartreuse
    },
    {
    Color.White, Color.Gainsboro, Color.Silver, Color.Red, Color.DarkRed, Color.Gainsboro, Color.Coral,
    Color.LightCoral
    },
    {
    Color.White, Color.Gainsboro, Color.Silver, Color.GreenYellow, Color.Yellow, Color.Gold, Color.Orange,
    Color.OrangeRed
    },
    {
    Color.White, Color.Gainsboro, Color.Silver, Color.Red, Color.Crimson, Color.Gainsboro, Color.DarkViolet
    , Color.Violet
    }
    };

    public enum ColorSchemas
    {
    PerlBlueGreen,
    PerlRedCoral,
    PerlGold,
    PerlRoyalColors
    }

    private ColorSchemas colorSchema = ColorSchemas.PerlBlueGreen;
    /// <summary>
    /// Sets color schema. Color generalization / fast color changing. Has no effect when slider colors are changed manually after schema was applied.
    /// </summary>
    /// <value>New color schema value</value>
    [Description("Set Slider color schema. Has no effect when slider colors are changed manually after schema was applied.")]
    [Category("ColorSlider")]
    [DefaultValue(typeof(ColorSchemas), "PerlBlueGreen")]
    public ColorSchemas ColorSchema
    {
    get { return colorSchema; }
    set
    {
    colorSchema = value;
    byte sn = (byte)value;
    thumbOuterColor = aColorSchema[sn, 0];
    thumbInnerColor = aColorSchema[sn, 1];
    thumbPenColor = aColorSchema[sn, 2];
    barOuterColor = aColorSchema[sn, 3];
    barInnerColor = aColorSchema[sn, 4];
    barPenColor = aColorSchema[sn, 5];
    elapsedOuterColor = aColorSchema[sn, 6];
    elapsedInnerColor = aColorSchema[sn, 7];

    Invalidate();
    }
    }

    #endregion

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="ColorSlider"/> class.
    /// </summary>
    /// <param name="min">The minimum value.</param>
    /// <param name="max">The maximum value.</param>
    /// <param name="value">The current value.</param>
    public ColorSlider(int min, int max, int value)
    {
    InitializeComponent();
    SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer |
    ControlStyles.ResizeRedraw | ControlStyles.Selectable |
    ControlStyles.SupportsTransparentBackColor | ControlStyles.UserMouse |
    ControlStyles.UserPaint, true);
    BackColor = Color.Transparent;

    Minimum = min;
    Maximum = max;
    Value = value;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="ColorSlider"/> class.
    /// </summary>
    public ColorSlider() : this(0, 100, 50) { }

    #endregion

    #region Paint

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.Paint"></see> event.
    /// </summary>
    /// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"></see> that contains the event data.</param>
    protected override void OnPaint(PaintEventArgs e)
    {
    if (!Enabled)
    {
    Color[] desaturatedColors = DesaturateColors(thumbOuterColor, thumbInnerColor, thumbPenColor,
    barOuterColor, barInnerColor, barPenColor,
    elapsedOuterColor, elapsedInnerColor);
    DrawColorSlider(e, desaturatedColors[0], desaturatedColors[1], desaturatedColors[2],
    desaturatedColors[3],
    desaturatedColors[4], desaturatedColors[5], desaturatedColors[6], desaturatedColors[7]);
    }
    else
    {
    if (mouseEffects && mouseInRegion)
    {
    Color[] lightenedColors = LightenColors(thumbOuterColor, thumbInnerColor, thumbPenColor,
    barOuterColor, barInnerColor, barPenColor,
    elapsedOuterColor, elapsedInnerColor);
    DrawColorSlider(e, lightenedColors[0], lightenedColors[1], lightenedColors[2], lightenedColors[3],
    lightenedColors[4], lightenedColors[5], lightenedColors[6], lightenedColors[7]);
    }
    else
    {
    DrawColorSlider(e, thumbOuterColor, thumbInnerColor, thumbPenColor,
    barOuterColor, barInnerColor, barPenColor,
    elapsedOuterColor, elapsedInnerColor);
    }
    }
    }

    /// <summary>
    /// Draws the colorslider control using passed colors.
    /// </summary>
    /// <param name="e">The <see cref="T:System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
    /// <param name="thumbOuterColorPaint">The thumb outer color paint.</param>
    /// <param name="thumbInnerColorPaint">The thumb inner color paint.</param>
    /// <param name="thumbPenColorPaint">The thumb pen color paint.</param>
    /// <param name="barOuterColorPaint">The bar outer color paint.</param>
    /// <param name="barInnerColorPaint">The bar inner color paint.</param>
    /// <param name="barPenColorPaint">The bar pen color paint.</param>
    /// <param name="elapsedOuterColorPaint">The elapsed outer color paint.</param>
    /// <param name="elapsedInnerColorPaint">The elapsed inner color paint.</param>
    private void DrawColorSlider(PaintEventArgs e, Color thumbOuterColorPaint, Color thumbInnerColorPaint,
    Color thumbPenColorPaint, Color barOuterColorPaint, Color barInnerColorPaint,
    Color barPenColorPaint, Color elapsedOuterColorPaint, Color elapsedInnerColorPaint)
    {
    try
    {
    //set up thumbRect aproprietly
    if (barOrientation == Orientation.Horizontal)
    {
    int TrackX = (((trackerValue - barMinimum) * (ClientRectangle.Width - thumbSize)) / (barMaximum - barMinimum));
    thumbRect = new Rectangle(TrackX, 1, thumbSize - 1, ClientRectangle.Height - 3);
    }
    else
    {
    int TrackY = (((trackerValue - barMinimum) * (ClientRectangle.Height - thumbSize)) / (barMaximum - barMinimum));
    thumbRect = new Rectangle(1, TrackY, ClientRectangle.Width - 3, thumbSize - 1);
    }

    //adjust drawing rects
    barRect = ClientRectangle;
    thumbHalfRect = thumbRect;
    LinearGradientMode gradientOrientation;
    if (barOrientation == Orientation.Horizontal)
    {
    barRect.Inflate(-1, -barRect.Height / 3);
    barHalfRect = barRect;
    barHalfRect.Height /= 2;
    gradientOrientation = LinearGradientMode.Vertical;
    thumbHalfRect.Height /= 2;
    elapsedRect = barRect;
    elapsedRect.Width = thumbRect.Left + thumbSize / 2;
    }
    else
    {
    barRect.Inflate(-barRect.Width / 3, -1);
    barHalfRect = barRect;
    barHalfRect.Width /= 2;
    gradientOrientation = LinearGradientMode.Horizontal;
    thumbHalfRect.Width /= 2;
    elapsedRect = barRect;
    elapsedRect.Height = thumbRect.Top + thumbSize / 2;
    }
    //get thumb shape path
    GraphicsPath thumbPath;
    if (thumbCustomShape == null)
    thumbPath = CreateRoundRectPath(thumbRect, thumbRoundRectSize);
    else
    {
    thumbPath = thumbCustomShape;
    Matrix m = new Matrix();
    m.Translate(thumbRect.Left - thumbPath.GetBounds().Left, thumbRect.Top - thumbPath.GetBounds().Top);
    thumbPath.Transform(m);
    }

    //draw bar
    using (
    LinearGradientBrush lgbBar =
    new LinearGradientBrush(barHalfRect, barOuterColorPaint, barInnerColorPaint, gradientOrientation)
    )
    {
    lgbBar.WrapMode = WrapMode.TileFlipXY;
    e.Graphics.FillRectangle(lgbBar, barRect);
    //draw elapsed bar
    using (
    LinearGradientBrush lgbElapsed =
    new LinearGradientBrush(barHalfRect, elapsedOuterColorPaint, elapsedInnerColorPaint,
    gradientOrientation))
    {
    lgbElapsed.WrapMode = WrapMode.TileFlipXY;
    if (Capture && drawSemitransparentThumb)
    {
    Region elapsedReg = new Region(elapsedRect);
    elapsedReg.Exclude(thumbPath);
    e.Graphics.FillRegion(lgbElapsed, elapsedReg);
    }
    else
    e.Graphics.FillRectangle(lgbElapsed, elapsedRect);
    }
    //draw bar band
    using (Pen barPen = new Pen(barPenColorPaint, 0.5f))
    {
    e.Graphics.DrawRectangle(barPen, barRect);
    }
    }

    //draw thumb
    Color newthumbOuterColorPaint = thumbOuterColorPaint, newthumbInnerColorPaint = thumbInnerColorPaint;
    if (Capture && drawSemitransparentThumb)
    {
    newthumbOuterColorPaint = Color.FromArgb(175, thumbOuterColorPaint);
    newthumbInnerColorPaint = Color.FromArgb(175, thumbInnerColorPaint);
    }
    using (
    LinearGradientBrush lgbThumb =
    new LinearGradientBrush(thumbHalfRect, newthumbOuterColorPaint, newthumbInnerColorPaint,
    gradientOrientation))
    {
    lgbThumb.WrapMode = WrapMode.TileFlipXY;
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    //draw thumb band
    Color newThumbPenColor = thumbPenColorPaint;
    if (mouseEffects && (Capture || mouseInThumbRegion))
    newThumbPenColor = ControlPaint.Dark(newThumbPenColor);
    using (Pen thumbPen = new Pen(newThumbPenColor))
    {
    if (thumbImage != null)
    {
    e.Graphics.DrawImage(thumbImage, thumbRect);
    }
    else
    {
    e.Graphics.FillPath(lgbThumb, thumbPath);
    e.Graphics.DrawPath(thumbPen, thumbPath);
    }
    }
    //gp.Dispose();
    /*if (Capture || mouseInThumbRegion)
    using (LinearGradientBrush lgbThumb2 = new LinearGradientBrush(thumbHalfRect, Color.FromArgb(150, Color.Blue), Color.Transparent, gradientOrientation))
    {
    lgbThumb2.WrapMode = WrapMode.TileFlipXY;
    e.Graphics.FillPath(lgbThumb2, gp);
    }*/
    }

    //draw focusing rectangle
    if (Focused & drawFocusRectangle)
    using (Pen p = new Pen(Color.FromArgb(200, barPenColorPaint)))
    {
    p.DashStyle = DashStyle.Dot;
    Rectangle r = ClientRectangle;
    r.Width -= 2;
    r.Height--;
    r.X++;
    //ControlPaint.DrawFocusRectangle(e.Graphics, r);
    using (GraphicsPath gpBorder = CreateRoundRectPath(r, borderRoundRectSize))
    {
    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.DrawPath(p, gpBorder);
    }
    }
    }
    catch (Exception Err)
    {
    Console.WriteLine("DrawBackGround Error in " + Name + ":" + Err.Message);
    }
    finally
    {
    }
    }

    #endregion

    #region Overided events

    private bool mouseInRegion = false;
    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.EnabledChanged"></see> event.
    /// </summary>
    /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
    protected override void OnEnabledChanged(EventArgs e)
    {
    base.OnEnabledChanged(e);
    Invalidate();
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.MouseEnter"></see> event.
    /// </summary>
    /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
    protected override void OnMouseEnter(EventArgs e)
    {
    base.OnMouseEnter(e);
    mouseInRegion = true;
    Invalidate();
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.MouseLeave"></see> event.
    /// </summary>
    /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
    protected override void OnMouseLeave(EventArgs e)
    {
    base.OnMouseLeave(e);
    mouseInRegion = false;
    mouseInThumbRegion = false;
    Invalidate();
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.MouseDown"></see> event.
    /// </summary>
    /// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"></see> that contains the event data.</param>
    protected override void OnMouseDown(MouseEventArgs e)
    {
    base.OnMouseDown(e);
    if (e.Button == MouseButtons.Left)
    {
    Capture = true;
    if (Scroll != null) Scroll(this, new ScrollEventArgs(ScrollEventType.ThumbTrack, trackerValue));
    if (ValueChanged != null) ValueChanged(this, new EventArgs());
    OnMouseMove(e);
    }
    }

    private bool mouseInThumbRegion = false;

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.MouseMove"></see> event.
    /// </summary>
    /// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"></see> that contains the event data.</param>
    protected override void OnMouseMove(MouseEventArgs e)
    {
    base.OnMouseMove(e);
    mouseInThumbRegion = IsPointInRect(e.Location, thumbRect);
    if (Capture & e.Button == MouseButtons.Left)
    {
    ScrollEventType set = ScrollEventType.ThumbPosition;
    Point pt = e.Location;
    int p = barOrientation == Orientation.Horizontal ? pt.X : pt.Y;
    int margin = thumbSize >> 1;
    p -= margin;
    float coef = (float)(barMaximum - barMinimum) /
    (float)
    ((barOrientation == Orientation.Horizontal ? ClientSize.Width : ClientSize.Height) -
    2 * margin);
    trackerValue = (int)(p * coef + barMinimum);

    if (trackerValue <= barMinimum)
    {
    trackerValue = barMinimum;
    set = ScrollEventType.First;
    }
    else if (trackerValue >= barMaximum)
    {
    trackerValue = barMaximum;
    set = ScrollEventType.Last;
    }

    if (Scroll != null) Scroll(this, new ScrollEventArgs(set, trackerValue));
    if (ValueChanged != null) ValueChanged(this, new EventArgs());
    }
    Invalidate();
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.MouseUp"></see> event.
    /// </summary>
    /// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"></see> that contains the event data.</param>
    protected override void OnMouseUp(MouseEventArgs e)
    {
    base.OnMouseUp(e);
    Capture = false;
    mouseInThumbRegion = IsPointInRect(e.Location, thumbRect);
    if (Scroll != null) Scroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, trackerValue));
    if (ValueChanged != null) ValueChanged(this, new EventArgs());
    Invalidate();
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.MouseWheel"></see> event.
    /// </summary>
    /// <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs"></see> that contains the event data.</param>
    protected override void OnMouseWheel(MouseEventArgs e)
    {
    base.OnMouseWheel(e);
    int v = e.Delta / 120 * (barMaximum - barMinimum) / mouseWheelBarPartitions;
    SetProperValue(Value + v);
    if (Scroll != null) Scroll(this, new ScrollEventArgs(ScrollEventType.EndScroll, trackerValue));
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.GotFocus"></see> event.
    /// </summary>
    /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
    protected override void OnGotFocus(EventArgs e)
    {
    base.OnGotFocus(e);
    Invalidate();
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.LostFocus"></see> event.
    /// </summary>
    /// <param name="e">An <see cref="T:System.EventArgs"></see> that contains the event data.</param>
    protected override void OnLostFocus(EventArgs e)
    {
    base.OnLostFocus(e);
    Invalidate();
    }

    /// <summary>
    /// Raises the <see cref="E:System.Windows.Forms.Control.KeyUp"></see> event.
    /// </summary>
    /// <param name="e">A <see cref="T:System.Windows.Forms.KeyEventArgs"></see> that contains the event data.</param>
    protected override void OnKeyUp(KeyEventArgs e)
    {
    base.OnKeyUp(e);
    switch (e.KeyCode)
    {
    case Keys.Down:
    case Keys.Left:
    SetProperValue(Value - (int)smallChange);
    if (Scroll != null) Scroll(this, new ScrollEventArgs(ScrollEventType.SmallDecrement, Value));
    break;
    case Keys.Up:
    case Keys.Right:
    SetProperValue(Value + (int)smallChange);
    if (Scroll != null) Scroll(this, new ScrollEventArgs(ScrollEventType.SmallIncrement, Value));
    break;
    case Keys.Home:
    Value = barMinimum;
    break;
    case Keys.End:
    Value = barMaximum;
    break;
    case Keys.PageDown:
    SetProperValue(Value - (int)largeChange);
    if (Scroll != null) Scroll(this, new ScrollEventArgs(ScrollEventType.LargeDecrement, Value));
    break;
    case Keys.PageUp:
    SetProperValue(Value + (int)largeChange);
    if (Scroll != null) Scroll(this, new ScrollEventArgs(ScrollEventType.LargeIncrement, Value));
    break;
    }
    if (Scroll != null && Value == barMinimum) Scroll(this, new ScrollEventArgs(ScrollEventType.First, Value));
    if (Scroll != null && Value == barMaximum) Scroll(this, new ScrollEventArgs(ScrollEventType.Last, Value));
    Point pt = PointToClient(Cursor.Position);
    OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, pt.X, pt.Y, 0));
    }

    /// <summary>
    /// Processes a dialog key.
    /// </summary>
    /// <param name="keyData">One of the <see cref="T:System.Windows.Forms.Keys"></see> values that represents the key to process.</param>
    /// <returns>
    /// true if the key was processed by the control; otherwise, false.
    /// </returns>
    protected override bool ProcessDialogKey(Keys keyData)
    {
    if (keyData == Keys.Tab | ModifierKeys == Keys.Shift)
    return base.ProcessDialogKey(keyData);
    else
    {
    OnKeyDown(new KeyEventArgs(keyData));
    return true;
    }
    }

    #endregion

    #region Help routines

    /// <summary>
    /// Creates the round rect path.
    /// </summary>
    /// <param name="rect">The rectangle on which graphics path will be spanned.</param>
    /// <param name="size">The size of rounded rectangle edges.</param>
    /// <returns></returns>
    public static GraphicsPath CreateRoundRectPath(Rectangle rect, Size size)
    {
    GraphicsPath gp = new GraphicsPath();
    gp.AddLine(rect.Left + size.Width / 2, rect.Top, rect.Right - size.Width / 2, rect.Top);
    gp.AddArc(rect.Right - size.Width, rect.Top, size.Width, size.Height, 270, 90);

    gp.AddLine(rect.Right, rect.Top + size.Height / 2, rect.Right, rect.Bottom - size.Width / 2);
    gp.AddArc(rect.Right - size.Width, rect.Bottom - size.Height, size.Width, size.Height, 0, 90);

    gp.AddLine(rect.Right - size.Width / 2, rect.Bottom, rect.Left + size.Width / 2, rect.Bottom);
    gp.AddArc(rect.Left, rect.Bottom - size.Height, size.Width, size.Height, 90, 90);

    gp.AddLine(rect.Left, rect.Bottom - size.Height / 2, rect.Left, rect.Top + size.Height / 2);
    gp.AddArc(rect.Left, rect.Top, size.Width, size.Height, 180, 90);
    return gp;
    }

    /// <summary>
    /// Desaturates colors from given array.
    /// </summary>
    /// <param name="colorsToDesaturate">The colors to be desaturated.</param>
    /// <returns></returns>
    public static Color[] DesaturateColors(params Color[] colorsToDesaturate)
    {
    Color[] colorsToReturn = new Color[colorsToDesaturate.Length];
    for (int i = 0; i < colorsToDesaturate.Length; i++)
    {
    //use NTSC weighted avarage
    int gray =
    (int)(colorsToDesaturate[i].R * 0.3 + colorsToDesaturate[i].G * 0.6 + colorsToDesaturate[i].B * 0.1);
    colorsToReturn[i] = Color.FromArgb(-0x010101 * (255 - gray) - 1);
    }
    return colorsToReturn;
    }

    /// <summary>
    /// Lightens colors from given array.
    /// </summary>
    /// <param name="colorsToLighten">The colors to lighten.</param>
    /// <returns></returns>
    public static Color[] LightenColors(params Color[] colorsToLighten)
    {
    Color[] colorsToReturn = new Color[colorsToLighten.Length];
    for (int i = 0; i < colorsToLighten.Length; i++)
    {
    colorsToReturn[i] = ControlPaint.Light(colorsToLighten[i]);
    }
    return colorsToReturn;
    }

    /// <summary>
    /// Sets the trackbar value so that it wont exceed allowed range.
    /// </summary>
    /// <param name="val">The value.</param>
    private void SetProperValue(int val)
    {
    if (val < barMinimum) Value = barMinimum;
    else if (val > barMaximum) Value = barMaximum;
    else Value = val;
    }

    /// <summary>
    /// Determines whether rectangle contains given point.
    /// </summary>
    /// <param name="pt">The point to test.</param>
    /// <param name="rect">The base rectangle.</param>
    /// <returns>
    /// <c>true</c> if rectangle contains given point; otherwise, <c>false</c>.
    /// </returns>
    private static bool IsPointInRect(Point pt, Rectangle rect)
    {
    if (pt.X > rect.Left & pt.X < rect.Right & pt.Y > rect.Top & pt.Y < rect.Bottom)
    return true;
    else return false;
    }

    #endregion
    }
    }
    GeneralRe: Slight improvements Pin
    Michal Brylka14-Feb-08 17:43
    Michal Brylka14-Feb-08 17:43 
    GeneralGreat control Pin
    Ross_MacGregor25-Jul-07 8:59
    Ross_MacGregor25-Jul-07 8:59 
    GeneralMulitple TrackPoints Pin
    bizzysim6-Jul-07 9:36
    bizzysim6-Jul-07 9:36 
    GeneralRe: Mulitple TrackPoints Pin
    Michal Brylka6-Jul-07 10:26
    Michal Brylka6-Jul-07 10:26 
    NewsGreat Control - added ToolStrip support Pin
    Thomas-H.28-Jun-07 5:08
    Thomas-H.28-Jun-07 5:08 
    GeneralRe: Great Control - added ToolStrip support [modified] Pin
    Michal Brylka28-Jun-07 7:34
    Michal Brylka28-Jun-07 7:34 
    Generalyour control is very good,I want Two blocks in your control, Pin
    frequent30-May-07 18:55
    frequent30-May-07 18:55 
    GeneralRe: your control is very good,I want Two blocks in your control, Pin
    Michal Brylka31-May-07 8:35
    Michal Brylka31-May-07 8:35 
    QuestionAccessiblity? Pin
    Zorbek5-Feb-07 21:59
    Zorbek5-Feb-07 21:59 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.