Click here to Skip to main content
15,885,309 members
Articles / Programming Languages / C#

DSGraphEdit: A Reasonable Facsimile of Microsoft's GraphEdit in .NET

Rate me:
Please Sign up or sign in to vote.
4.93/5 (79 votes)
28 Jan 2018MIT7 min read 296.1K   10K   142  
A library for adding DirectShow GraphEdit-like abilities to .NET applications
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.Globalization;

namespace DaggerLib.DSGraphEdit
{
    /// <summary>
    /// Summary description for GradientRange.
    /// </summary>
    [ToolboxItem(false)]
    public class TimeSliderControl : System.Windows.Forms.UserControl
    {
        private Pen blackPen = new Pen(Color.White, 1);
        private Pen TimePen = new Pen(Color.LightBlue);
        private Brush TextBrush = new SolidBrush(Color.Black);
        private Font myFont = null;
        private int TimeStampWidth = 0;

        private Color color1 = Color.Black;
        private Color color2 = Color.White;
        private Color color3 = Color.Black;
        private ColorSliderType type = ColorSliderType.Gradient;
        private bool doubleArrow = true;
        private Bitmap arrow;
        private int min = 0, max = 1000;
        private int width;
        private int height = 10;
        private int extent = 1000;
        private int trackMode = 0;
        private int position = 0;

        // values changed event
        public event EventHandler ValuesChanged;

        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.Container components = null;

        public TimeSliderControl()
        {
            // This call is required by the Windows.Forms Form Designer.
            InitializeComponent();

            // TODO: Add any initialization after the InitializeComponent call

            SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw |
                ControlStyles.DoubleBuffer | ControlStyles.UserPaint, true);

            // create arrow bitmap
            arrow = new Bitmap(9, 6);
            Graphics g = Graphics.FromImage(arrow);
            Pen p = new Pen(Color.Black);
            Brush b = new SolidBrush(Color.White);
            g.FillRectangle(b, 0, 0, 8, 5);
            g.DrawLine(p, 4, 1, 7, 4);
            g.DrawLine(p, 7, 4, 1, 4);
            g.DrawLine(p, 1, 4, 4, 1);

            myFont = new Font("MicroSoft Sans Serif", 7f);
            TimeStampWidth = (int)g.MeasureString("0:00:00;00", myFont).Width;

            g.Dispose();
            p.Dispose();
            b.Dispose();

            arrow.MakeTransparent(Color.FromArgb(255, 255, 255));

            width = this.Width - 6;
        }

        // Color1 property
        [DefaultValue(typeof(Color), "Black")]
        public Color Color1
        {
            get { return color1; }
            set
            {
                color1 = value;
                Invalidate();
            }
        }
        // Color2 property
        [DefaultValue(typeof(Color), "White")]
        public Color Color2
        {
            get { return color2; }
            set
            {
                color2 = value;
                Invalidate();
            }
        }
        // Color3 property
        [DefaultValue(typeof(Color), "Black")]
        public Color Color3
        {
            get { return color3; }
            set
            {
                color3 = value;
                if (TimePen != null) TimePen.Dispose();
                TimePen = new Pen(value);
                Invalidate();
            }
        }

        // Type property
        [DefaultValue(ColorSliderType.Gradient)]
        public ColorSliderType Type
        {
            get { return type; }
            set
            {
                type = value;
                if (type != ColorSliderType.Gradient)
                    DoubleArrow = true;
                Invalidate();
            }
        }
        // Min property
        [DefaultValue(0)]
        public int Min
        {
            get { return min; }
            set
            {
                min = value;
                if (position < min) Pos = min;
                Invalidate();
            }
        }

        // Min property
        [DefaultValue(1000)]
        public int Extent
        {
            get { return extent; }
            set
            {
                extent = value;
                Invalidate();
            }
        }

        // Max property
        [DefaultValue(1000)]
        public int Max
        {
            get { return max; }
            set
            {
                if (value > extent) value = extent;
                max = value;
                if (position > max) Pos = max;
                Invalidate();
            }
        }

        public int Pos
        {
            get { return position; }
            set
            {
                if (value > max) value = max;
                if (value < min) value = min;
                position = value;
                Invalidate();
            }
        }

        // DoubleArrow property
        [DefaultValue(true)]
        public bool DoubleArrow
        {
            get { return doubleArrow; }
            set
            {
                doubleArrow = value;
                if (!doubleArrow)
                    Type = ColorSliderType.Gradient;
                Invalidate();
            }
        }

        public bool Tracking
        {
            get
            {
                if (this.trackMode > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public TimeSliderTrackMode TrackMode
        {
            get
            {
                return (TimeSliderTrackMode)trackMode;
            }
        }

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (components != null)
                {
                    blackPen.Dispose();
                    arrow.Dispose();
                    components.Dispose();
                    myFont.Dispose();
                    TextBrush.Dispose();
                    TimePen.Dispose();
                }
            }
            base.Dispose(disposing);
        }

        #region Component Designer generated code
        /// <summary> 
        /// Required method for Designer support - do not modify 
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            // 
            // GradientRange
            // 
            this.Name = "GradientRange";
            this.Resize += new System.EventHandler(this.GradientRange_Resize);
            this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.GradientRange_MouseUp);
            this.Paint += new System.Windows.Forms.PaintEventHandler(this.GradientRange_Paint);
            this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.GradientRange_MouseMove);
            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.GradientRange_MouseDown);

        }
        #endregion

        private void GradientRange_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Graphics g = e.Graphics;
            Rectangle rc = this.ClientRectangle;
            //rc.Width =- 6;

            Brush brush;
            int x = 3;
            int y = 12;


            switch (type)
            {
                case ColorSliderType.Gradient:
                case ColorSliderType.InnerGradient:
                case ColorSliderType.OuterGradient:

                    // create gradient brush
                    brush = new LinearGradientBrush(new Point(x, 0), new Point(x + this.Width, 0), color1, color2);

                    g.FillRectangle(brush, x, y, width, height);
                    brush.Dispose();

                    // check type
                    if (type == ColorSliderType.InnerGradient)
                    {
                        // inner gradient
                        brush = new SolidBrush(color3);

                        if (min != 0)
                        {
                            g.FillRectangle(brush,
                                x,
                                y,
                                (min * ((float)width / extent)),
                                height);
                        }
                        if (max != extent)
                        {
                            g.FillRectangle(brush,
                                x + (max * ((float)width / extent)) + 1,
                                y,
                                (extent * ((float)width / extent)) - (max * ((float)width / extent)),
                                height);
                        }
                        brush.Dispose();
                    }
                    else if (type == ColorSliderType.OuterGradient)
                    {
                        // outer gradient
                        brush = new SolidBrush(color3);
                        // fill space between min & max with color 3
                        g.FillRectangle(brush,
                            x + (min * ((float)width / extent)),
                            y,
                            (max * ((float)width / extent)) - (min * ((float)width / extent)) + 1,
                            height);

                        brush.Dispose();
                    }
                    break;
                case ColorSliderType.Threshold:
                    // 1 - fill with color 1
                    brush = new SolidBrush(color1);
                    g.FillRectangle(brush, x, y, width, height);
                    brush.Dispose();
                    // 2 - fill space between min & max with color 2
                    brush = new SolidBrush(color2);
                    if (extent == 0) extent = 1;
                    g.FillRectangle(brush,
                        x + (min * ((float)width / extent)),
                        y,
                        (max * ((float)width / extent)) - (min * ((float)width / extent)) + 1,
                        height);

                    brush.Dispose();
                    break;
            }

            // draw rectangle around the control
            g.DrawRectangle(blackPen, x, y - 1, width, height + 1);

            //draw time marker
            g.DrawLine(TimePen, x + (position * ((float)width / extent)), y, x + (position * ((float)width / extent)), y + height);

            // draw arrows
            x -= 4;
            y += 1 + height;

            if (this.doubleArrow)
            {
                g.DrawImage(arrow, x + (min * ((float)width / extent)), y, 9, 6);
                g.DrawImage(arrow, x + (max * ((float)width / extent)), y, 9, 6);
            }
            else
            {
                g.DrawImage(arrow, x + (min * ((float)width / extent)), y, 9, 6);
            }

            //position time stamp
            PointF stampLoc = new PointF((position * ((float)width / extent)), 0.0f);
            if ((stampLoc.X + TimeStampWidth) > this.width) stampLoc.X = this.width - TimeStampWidth;
            g.DrawString(TimeCodeString(position), myFont, TextBrush, stampLoc);

            //min time stamp
            stampLoc.Y = 26;
            stampLoc.X = (min * ((float)width / extent)) - TimeStampWidth;
            g.DrawString(TimeCodeString(min), myFont, TextBrush, stampLoc);

            stampLoc.X = max * ((float)width / extent);
            g.DrawString(TimeCodeString(max), myFont, TextBrush, stampLoc);
        }

        private void GradientRange_Resize(object sender, System.EventArgs e)
        {
            width = this.Width - 6;
        }

        private void GradientRange_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            int x = 3;
            int y = 12 + height;

            // check Y coordinate
            if ((e.Y >= y) && (e.Y < y + 6))
            {
                // check X coordinate
                if (this.doubleArrow && (e.X >= 2 - x + (max * ((float)width / extent))) && (e.X < x + (max * ((float)width / extent)) + 8))
                {
                    // right arrow
                    trackMode = 2;
                }
                else if ((e.X >= 2 - x + (min * ((float)width / extent))) && (e.X < x + (min * ((float)width / extent)) + 8))
                {
                    // left arrow
                    trackMode = 1;
                }
            }
            // check Y coordinate
            if (e.Y < y)
            {
                // check X coordinate
                //if(this.doubleArrow && (e.X >= 2 - x + ( position * ((float)width / extent))) && (e.X < x + ( position * ((float)width / extent)) + 8) )
                //{
                // right arrow
                trackMode = 3;
                //}
            }

            if (trackMode != 0)
                this.Capture = true;
        }

        private void GradientRange_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (trackMode != 0)
            {
                // release capture
                this.Capture = false;
                trackMode = 0;
            }
        }

        private void GradientRange_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (trackMode != 0)
            {
                if (trackMode == 1)
                {
                    // left arrow tracking
                    min = (int)((float)(e.X - 3) / ((float)width / (float)extent));
                    min = Math.Max(min, 0);
                    min = Math.Min(min, extent);
                    if (min > max) max = min;
                    if (position < min) position = min;

                }
                if (trackMode == 2)
                {
                    // right arrow tracking
                    max = (int)((float)(e.X - 3) / ((float)width / (float)extent));
                    max = Math.Max(max, 0);
                    max = Math.Min(max, extent);
                    if (max < min) min = max;
                    if (position > max) position = max;
                }
                if (trackMode == 3)
                {
                    //time marker tracking
                    position = (int)((float)(e.X - 3) / ((float)width / (float)extent));
                    position = Math.Max(position, 0);
                    position = Math.Min(position, extent);
                    if (position > max) position = max;
                    if (position < min) position = min;
                }

                // notify client
                if (ValuesChanged != null)
                    ValuesChanged(this, new EventArgs());

                // repaint control
                Invalidate();
            }
            else
            {
                //change the cursor if needed
                int x = 3;
                int y = 12 + height;
                Cursor = Cursors.Default;
                // check Y coordinate
                if ((e.Y >= y) && (e.Y < y + 6))
                {
                    // check X coordinate
                    if (this.doubleArrow && (e.X >= 2 - x + (max * ((float)width / extent))) && (e.X < x + (max * ((float)width / extent)) + 8))
                    {
                        Cursor = Cursors.SizeWE;
                    }
                    else if ((e.X >= 2 - x + (min * ((float)width / extent))) && (e.X < x + (min * ((float)width / extent)) + 8))
                    {
                        Cursor = Cursors.SizeWE;
                    }
                }
                // check Y coordinate
                if (e.Y < y)
                {
                    // check X coordinate
                    if (this.doubleArrow && (e.X >= 2 - x + (position * ((float)width / extent))) && (e.X < x + (position * ((float)width / extent)) + 8))
                    {
                        Cursor = Cursors.VSplit;
                    }
                }
            }
        }

        public static string TimeCodeString(int msecs)
        {
            //frames
            int timebase = msecs % 1000;
            string frames = ((int)((float)timebase / 33.3333333333f)).ToString();
            if (frames.Length == 1) frames = "0" + frames;
            msecs -= timebase;

            //seconds
            timebase = msecs % 60000;
            string secs = (timebase / 1000).ToString();
            if (secs.Length == 1) secs = "0" + secs;
            msecs -= timebase;

            //minutes
            timebase = msecs % 3600000;
            string mins = (timebase / 60000).ToString();
            if (mins.Length == 1) mins = "0" + mins;
            msecs -= timebase;

            return (msecs / 3600000).ToString() + ":" + mins + ":" + secs + ";" + frames;
        }
    }

    // ColorSliderType enumeration
    public enum ColorSliderType
    {
        Gradient,
        InnerGradient,
        OuterGradient,
        Threshold
    }

    public enum TimeSliderTrackMode
    {
        None,
        StartTime,
        StopTime,
        CurrentTime
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer (Senior)
United States United States
AKA Rich Insley.

I have over 25 years experience in programming, and I'm completely self taught. (Except for one year at California State University Fresno where I had to learn the God awful language Miranda (http://miranda.org.uk/). I've spent 10 years as a Paratrooper in the US Army during the Clinton Administration.

Comments and Discussions