1. // -----------------------------------------------------------------------
  2. // <copyright file="GanttChart.cs">
  3. // http://www.codeproject.com/Articles/20731/Gantt-Chart
  4. // <summary>
  5. // Adds an easy to use Gantt Chart to your application
  6. // Created by Adrian "Adagio" Grau
  7. // Version 0.55
  8. // </summary>
  9. // <remarks></remarks>
  10. // </copyright>
  11. // -----------------------------------------------------------------------
  12.  
  13.     using System;
  14.     using System.Collections.Generic;
  15.     using System.Linq;
  16.     using System.Text;
  17.     using System.Drawing.Drawing2D;
  18.     using System.Drawing;
  19.     using System.Windows.Forms;
  20.  
  21.     /// <summary>
  22.     /// TODO: Update summary.
  23.     /// </summary>
  24.     public class GanttChart : Control
  25.     {
  26.  
  27.         private MouseOverPart mouseHoverPart = MouseOverPart.Empty;
  28.  
  29.         private int mouseHoverBarIndex = -1;
  30.         private List<ChartBarDate> bars = new List<ChartBarDate>();
  31.         private System.DateTime headerFromDate;
  32.  
  33.         private System.DateTime headerToDate;
  34.  
  35.         private int barIsChanging = -1;
  36.         private int barStartRight = 20;
  37.         private int barStartLeft = 100;
  38.         private int headerTimeStartTop = 30;
  39.  
  40.         private List<Header> shownHeaderList;
  41.         private int barStartTop = 50;
  42.         private int barHeight = 9;
  43.  
  44.         private int barSpace = 5;
  45.  
  46.         private int widthPerItem;
  47.         private System.DateTime _mouseOverColumnValue;
  48.         private string _mouseOverRowText = "";
  49.  
  50.         private object _mouseOverRowValue = null;
  51.         private Pen lineColor = Pens.Bisque;
  52.         private Font dateTextFont = new Font("VERDANA", 8.0f, FontStyle.Regular, GraphicsUnit.Point);
  53.         private Font timeTextFont = new Font("VERDANA", 8.0f, FontStyle.Regular, GraphicsUnit.Point);
  54.  
  55.         private Font rowTextFont = new Font("VERDANA", 8.0f, FontStyle.Regular, GraphicsUnit.Point);
  56.         private System.Windows.Forms.ToolTip withEventsField_ToolTip = new System.Windows.Forms.ToolTip();
  57.         internal System.Windows.Forms.ToolTip ToolTip
  58.         {
  59.             get { return withEventsField_ToolTip; }
  60.             set
  61.             {
  62.                 if (withEventsField_ToolTip != null)
  63.                 {
  64.                     withEventsField_ToolTip.Draw -= ToolTipText_Draw;
  65.                     withEventsField_ToolTip.Popup -= ToolTipText_Popup;
  66.                 }
  67.                 withEventsField_ToolTip = value;
  68.                 if (withEventsField_ToolTip != null)
  69.                 {
  70.                     withEventsField_ToolTip.Draw += ToolTipText_Draw;
  71.                     withEventsField_ToolTip.Popup += ToolTipText_Popup;
  72.                 }
  73.             }
  74.  
  75.         }
  76.  
  77.         private bool _allowEditBarWithMouse = false;
  78.         public event MouseDraggedEventHandler MouseDragged;
  79.         public delegate void MouseDraggedEventHandler(object sender, System.Windows.Forms.MouseEventArgs e);
  80.         public event BarChangedEventHandler BarChanged;
  81.         public delegate void BarChangedEventHandler(object sender, object barValue);
  82.  
  83.         private Bitmap objBmp;
  84.  
  85.         private Graphics objGraphics;
  86.  
  87.         protected new bool DesignMode
  88.         {
  89.             get
  90.             {
  91.                 if (base.DesignMode)
  92.                     return true;
  93.  
  94.                 return System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime;
  95.             }
  96.         }
  97.  
  98.         #region "Public properties"
  99.  
  100.         /// <summary>
  101.         /// Sets to true if the user should be able to manually edit bars
  102.         /// </summary>
  103.         /// <value></value>
  104.         /// <returns></returns>
  105.         /// <remarks></remarks>
  106.  
  107.         public bool AllowManualEditBar
  108.         {
  109.             get { return _allowEditBarWithMouse; }
  110.             set { _allowEditBarWithMouse = value; }
  111.         }
  112.  
  113.         /// <summary>
  114.         /// The start date/time of the chart
  115.         /// </summary>
  116.         /// <value></value>
  117.         /// <returns></returns>
  118.         /// <remarks></remarks>
  119.  
  120.         public System.DateTime FromDate
  121.         {
  122.             get { return headerFromDate; }
  123.             set { headerFromDate = value; }
  124.         }
  125.  
  126.         /// <summary>
  127.         /// The end date/time of the chart
  128.         /// </summary>
  129.         /// <value></value>
  130.         /// <returns></returns>
  131.         /// <remarks></remarks>
  132.  
  133.         public System.DateTime ToDate
  134.         {
  135.             get { return headerToDate; }
  136.             set { headerToDate = value; }
  137.         }
  138.  
  139.         /// <summary>
  140.         /// The text for the current row the mouse hovers above
  141.         /// </summary>
  142.         /// <value></value>
  143.         /// <returns></returns>
  144.         /// <remarks></remarks>
  145.  
  146.         public string MouseOverRowText
  147.         {
  148.             get { return _mouseOverRowText; }
  149.         }
  150.  
  151.         /// <summary>
  152.         /// The value for the current bar the mouse hovers above
  153.         /// </summary>
  154.         /// <value></value>
  155.         /// <returns></returns>
  156.         /// <remarks></remarks>
  157.  
  158.         public object MouseOverRowValue
  159.         {
  160.             get { return _mouseOverRowValue; }
  161.         }
  162.  
  163.         /// <summary>
  164.         /// The date/time the mouse hovers above
  165.         /// </summary>
  166.         /// <value></value>
  167.         /// <returns></returns>
  168.         /// <remarks></remarks>
  169.  
  170.         public System.DateTime MouseOverColumnDate
  171.         {
  172.             get { return _mouseOverColumnValue; }
  173.         }
  174.  
  175.         /// <summary>
  176.         /// The color of the grid
  177.         /// </summary>
  178.         /// <value></value>
  179.         /// <returns></returns>
  180.         /// <remarks></remarks>
  181.  
  182.         public System.Drawing.Pen GridColor
  183.         {
  184.             get { return lineColor; }
  185.             set { lineColor = value; }
  186.         }
  187.  
  188.         /// <summary>
  189.         /// The font used for the row text
  190.         /// </summary>
  191.         /// <value></value>
  192.         /// <returns></returns>
  193.         /// <remarks></remarks>
  194.  
  195.         public Font RowFont
  196.         {
  197.             get { return rowTextFont; }
  198.             set { rowTextFont = value; }
  199.         }
  200.  
  201.         /// <summary>
  202.         /// The font used for the "date" text in the columns
  203.         /// </summary>
  204.         /// <value></value>
  205.         /// <returns></returns>
  206.         /// <remarks></remarks>
  207.  
  208.         public Font DateFont
  209.         {
  210.             get { return dateTextFont; }
  211.             set { dateTextFont = value; }
  212.         }
  213.  
  214.         /// <summary>
  215.         /// The font used for the "time" text in the colums)
  216.         /// </summary>
  217.         /// <value></value>
  218.         /// <returns></returns>
  219.         /// <remarks></remarks>
  220.  
  221.         public Font TimeFont
  222.         {
  223.             get { return timeTextFont; }
  224.             set { timeTextFont = value; }
  225.         }
  226.  
  227.         #endregion
  228.  
  229.         #region "Constructor"
  230.  
  231.         /// <summary>
  232.         /// Default constructor
  233.         /// </summary>
  234.         /// <remarks></remarks>
  235.  
  236.         public GanttChart()
  237.         {
  238.             if (!DesignMode)
  239.             {
  240.  
  241.                 MouseWheel += GanttChart_MouseWheel;
  242.                 MouseClick += GanttChart_Click;
  243.                 MouseDragged += GanttChart_MouseDragged;
  244.                 MouseLeave += GanttChart_MouseLeave;
  245.                 MouseMove += GanttChart_MouseMove;
  246.                 ToolTip.AutoPopDelay = 15000;
  247.                 ToolTip.InitialDelay = 250;
  248.                 ToolTip.OwnerDraw = true;
  249.  
  250.                 objBmp = new Bitmap(1280, 1024, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  251.                 objGraphics = Graphics.FromImage(objBmp);
  252.  
  253.                 // Flicker free drawing
  254.  
  255.                 this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
  256.             }
  257.  
  258.         }
  259.  
  260.         #endregion
  261.  
  262.         #region "Bars"
  263.  
  264.         private void SetBarStartLeft(string rowText)
  265.         {
  266.             Graphics gfx = this.CreateGraphics();
  267.  
  268.             int length = Convert.ToInt32(gfx.MeasureString(rowText, rowTextFont, 500).Width);
  269.  
  270.             if (length > barStartLeft)
  271.             {
  272.                 barStartLeft = length;
  273.             }
  274.         }
  275.  
  276.         /// <summary>
  277.         /// Adds a bar to the list
  278.         /// </summary>
  279.         /// <param name="rowText">Text for the row</param>
  280.         /// <param name="barValue">Value for the row</param>
  281.         /// <param name="fromTime">The date/time the bar starts</param>
  282.         /// <param name="toTime">The date/time the bar ends</param>
  283.         /// <param name="color">The color of the bar</param>
  284.         /// <param name="hoverColor">The hover color of the bar</param>
  285.         /// <param name="rowIndex">The rowindex of the bar (useful if you want several bars on the same row)</param>
  286.         /// <remarks></remarks>
  287.  
  288.         public void AddChartBar(string rowText, object barValue, System.DateTime fromTime, System.DateTime toTime, Color color, Color hoverColor, int rowIndex)
  289.         {
  290.             ChartBarDate bar = new ChartBarDate();
  291.             bar.Text = rowText;
  292.             bar.Value = barValue;
  293.             bar.StartValue = fromTime;
  294.             bar.EndValue = toTime;
  295.             bar.Color = color;
  296.             bar.HoverColor = hoverColor;
  297.             bar.RowIndex = rowIndex;
  298.             bars.Add(bar);
  299.  
  300.             SetBarStartLeft(rowText);
  301.         }
  302.  
  303.         /// <summary>
  304.         /// Adds a bar to the list
  305.         /// </summary>
  306.         /// <param name="rowText">Text for the row</param>
  307.         /// <param name="barValue">Value for the row</param>
  308.         /// <param name="fromTime">The date/time the bar starts</param>
  309.         /// <param name="toTime">The date/time the bar ends</param>
  310.         /// <param name="color">The color of the bar</param>
  311.         /// <param name="hoverColor">The hover color of the bar</param>
  312.         /// <param name="rowIndex">The rowindex of the bar (useful if you want several bars on the same row)</param>
  313.         /// <param name="hideFromMouseMove">If you want to "hide" the bar from mousemove event</param>
  314.         /// <remarks></remarks>
  315.  
  316.         public void AddChartBar(string rowText, object barValue, System.DateTime fromTime, System.DateTime toTime, Color color, Color hoverColor, int rowIndex, bool hideFromMouseMove)
  317.         {
  318.             ChartBarDate bar = new ChartBarDate();
  319.             bar.Text = rowText;
  320.             bar.Value = barValue;
  321.             bar.StartValue = fromTime;
  322.             bar.EndValue = toTime;
  323.             bar.Color = color;
  324.             bar.HoverColor = hoverColor;
  325.             bar.RowIndex = rowIndex;
  326.             bar.HideFromMouseMove = hideFromMouseMove;
  327.             bars.Add(bar);
  328.  
  329.             SetBarStartLeft(rowText);
  330.         }
  331.  
  332.         /// <summary>
  333.         /// Gets the next index
  334.         /// </summary>
  335.         /// <param name="rowText"></param>
  336.         /// <returns></returns>
  337.         /// <remarks></remarks>
  338.  
  339.         public int GetIndexChartBar(string rowText)
  340.         {
  341.             int index = -1;
  342.  
  343.             foreach (ChartBarDate bar in bars)
  344.             {
  345.                 if (bar.Text.Equals(rowText) == true)
  346.                 {
  347.                     return bar.RowIndex;
  348.                 }
  349.                 if (bar.RowIndex > index)
  350.                 {
  351.                     index = bar.RowIndex;
  352.                 }
  353.             }
  354.  
  355.             return index + 1;
  356.         }
  357.  
  358.         /// <summary>
  359.         /// Removes all bars from list
  360.         /// </summary>
  361.         /// <remarks></remarks>
  362.  
  363.         public void RemoveBars()
  364.         {
  365.             bars = new List<ChartBarDate>();
  366.  
  367.             barStartLeft = 100;
  368.         }
  369.  
  370.         #endregion
  371.  
  372.         #region "Draw"
  373.  
  374.         /// <summary>
  375.         /// Redraws the Gantt chart
  376.         /// </summary>
  377.         /// <remarks></remarks>
  378.  
  379.         public void PaintChart()
  380.         {
  381.             this.Invalidate();
  382.         }
  383.  
  384.         /// <summary>
  385.         /// Redraws the Gantt chart
  386.         /// </summary>
  387.         /// <param name="gfx"></param>
  388.         /// <remarks></remarks>
  389.  
  390.         private void PaintChart(Graphics gfx)
  391.         {
  392.             gfx.Clear(this.BackColor);
  393.  
  394.             if (headerFromDate == null | headerToDate == null)
  395.                 return;
  396.  
  397.             DrawScrollBar(gfx);
  398.             DrawHeader(gfx, null);
  399.             DrawNetHorizontal(gfx);
  400.             DrawNetVertical(gfx);
  401.             DrawBars(gfx);
  402.  
  403.             objBmp = new Bitmap(this.Width - barStartRight, lastLineStop, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  404.             objGraphics = Graphics.FromImage(objBmp);
  405.         }
  406.  
  407.         /// <summary>
  408.         /// Redraws the Gantt chart
  409.         /// </summary>
  410.         /// <param name="pe"></param>
  411.         /// <remarks></remarks>
  412.  
  413.         protected override void OnPaint(System.Windows.Forms.PaintEventArgs pe)
  414.         {
  415.             base.OnPaint(pe);
  416.             if (!DesignMode)
  417.             {
  418.                 PaintChart(pe.Graphics);
  419.             }
  420.         }
  421.  
  422.         /// <summary>
  423.         /// Draws the list of headers. Automatically shows which headers to draw, based on the width of the Gantt Chart
  424.         /// </summary>
  425.         /// <param name="gfx"></param>
  426.         /// <param name="headerList"></param>
  427.         /// <remarks></remarks>
  428.  
  429.         private void DrawHeader(Graphics gfx, List<Header> headerList)
  430.         {
  431.             if (headerList == null)
  432.             {
  433.                 headerList = GetFullHeaderList();
  434.             }
  435.  
  436.             if (headerList.Count == 0)
  437.                 return;
  438.  
  439.             dynamic availableWidth = this.Width - 10 - barStartLeft - barStartRight;
  440.             widthPerItem = availableWidth / headerList.Count;
  441.  
  442.             if (widthPerItem < 40)
  443.             {
  444.                 List<Header> newHeaderList = new List<Header>();
  445.  
  446.                 bool showNext = true;
  447.  
  448.                 // If there's not enough room for all headers remove 50%
  449.  
  450.                 foreach (Header header in headerList)
  451.                 {
  452.                     if (showNext == true)
  453.                     {
  454.                         newHeaderList.Add(header);
  455.                         showNext = false;
  456.                     }
  457.                     else
  458.                     {
  459.                         showNext = true;
  460.                     }
  461.                 }
  462.  
  463.                 DrawHeader(gfx, newHeaderList);
  464.                 return;
  465.             }
  466.  
  467.             int index = 0;
  468.             int headerStartPosition = -1;
  469.             Header lastHeader = null;
  470.  
  471.             foreach (Header header in headerList)
  472.             {
  473.                 int startPos = barStartLeft + (index * widthPerItem);
  474.                 bool showDateHeader = false;
  475.  
  476.                 header.StartLocation = startPos;
  477.  
  478.                 // Checks whether to show the date or not
  479.  
  480.                 if (lastHeader == null)
  481.                 {
  482.                     showDateHeader = true;
  483.                 }
  484.                 else if (header.Time.Hour < lastHeader.Time.Hour)
  485.                 {
  486.                     showDateHeader = true;
  487.                 }
  488.                 else if (header.Time.Minute == lastHeader.Time.Minute)
  489.                 {
  490.                     showDateHeader = true;
  491.                 }
  492.  
  493.                 // Show date
  494.  
  495.                 if (showDateHeader == true)
  496.                 {
  497.                     string str = "";
  498.  
  499.                     if (header.HeaderTextInsteadOfTime.Length > 0)
  500.                     {
  501.                         str = header.HeaderTextInsteadOfTime;
  502.                     }
  503.                     else
  504.                     {
  505.                         str = header.Time.ToString("d-MMM");
  506.                     }
  507.                     gfx.DrawString(str, dateTextFont, Brushes.Black, startPos, 0);
  508.                 }
  509.  
  510.                 // Show time
  511.  
  512.                 gfx.DrawString(header.HeaderText, timeTextFont, Brushes.Black, startPos, headerTimeStartTop);
  513.                 index += 1;
  514.  
  515.                 lastHeader = header;
  516.             }
  517.  
  518.             shownHeaderList = headerList;
  519.             widthPerItem = (this.Width - 10 - barStartLeft - barStartRight) / shownHeaderList.Count;
  520.         }
  521.  
  522.         /// <summary>
  523.         /// Draws the bars
  524.         /// </summary>
  525.         /// <param name="grfx"></param>
  526.         /// <remarks></remarks>
  527.  
  528.         private void DrawBars(Graphics grfx, bool ignoreScrollAndMousePosition = false)
  529.         {
  530.             if (shownHeaderList == null)
  531.                 return;
  532.             if (shownHeaderList.Count == 0)
  533.                 return;
  534.  
  535.             int index = 0;
  536.  
  537.             // Finds pixels per minute
  538.  
  539.             TimeSpan timeBetween = shownHeaderList[1].Time - shownHeaderList[0].Time;
  540.             int minutesBetween = Convert.ToInt32(timeBetween.TotalMinutes);
  541.             //(timeBetween.Days * 1440) + (timeBetween.Hours * 60) + timeBetween.Minutes
  542.             dynamic widthBetween = (shownHeaderList[1].StartLocation - shownHeaderList[0].StartLocation);
  543.             decimal perMinute = widthBetween / minutesBetween;
  544.  
  545.             // Draws each bar
  546.  
  547.             foreach (ChartBarDate bar in bars)
  548.             {
  549.                 index = bar.RowIndex;
  550.  
  551.                 int startLocation = 0;
  552.                 int width = 0;
  553.                 int startMinutes = 0;
  554.                 // Number of minutes from start of the gantt chart
  555.                 TimeSpan startTimeSpan = default(TimeSpan);
  556.                 int lengthMinutes = 0;
  557.                 // Number of minutes from bar start to bar end
  558.                 TimeSpan lengthTimeSpan = default(TimeSpan);
  559.  
  560.                 int scrollPos = 0;
  561.  
  562.                 if (ignoreScrollAndMousePosition == false)
  563.                 {
  564.                     scrollPos = scrollPosition;
  565.                 }
  566.  
  567.                 // Calculates where the bar should be located
  568.  
  569.                 startTimeSpan = bar.StartValue - FromDate;
  570.                 startMinutes = (startTimeSpan.Days * 1440) + (startTimeSpan.Hours * 60) + startTimeSpan.Minutes;
  571.  
  572.                 startLocation = Convert.ToInt32(perMinute * startMinutes);
  573.  
  574.                 System.DateTime endValue = bar.EndValue;
  575.  
  576.                 if (endValue == null)
  577.                 {
  578.                     endValue = System.DateTime.Now;
  579.                 }
  580.  
  581.                 lengthTimeSpan = endValue - bar.StartValue;
  582.                 lengthMinutes = (lengthTimeSpan.Days * 1440) + (lengthTimeSpan.Hours * 60) + lengthTimeSpan.Minutes;
  583.  
  584.                 width = Convert.ToInt32(perMinute * lengthMinutes);
  585.  
  586.                 int a = barStartLeft + startLocation;
  587.                 int b = barStartTop + (barHeight * (index - scrollPos)) + (barSpace * (index - scrollPos)) + 2;
  588.                 int c = width;
  589.                 int d = barHeight;
  590.  
  591.                 if (c == 0)
  592.                     c = 1;
  593.  
  594.                 // Stops a bar from going into the row-text area
  595.  
  596.                 if (a - barStartLeft < 0)
  597.                 {
  598.                     a = barStartLeft;
  599.                 }
  600.  
  601.                 System.Drawing.Color color = default(System.Drawing.Color);
  602.  
  603.                 // If mouse is over bar, set the color to be hovercolor
  604.  
  605.                 if (MouseOverRowText == bar.Text & bar.StartValue <= _mouseOverColumnValue & bar.EndValue >= _mouseOverColumnValue)
  606.                 {
  607.                     color = bar.HoverColor;
  608.                 }
  609.                 else
  610.                 {
  611.                     color = bar.Color;
  612.                 }
  613.  
  614.                 // Set the location for the graphics
  615.  
  616.                 bar.TopLocation.Left = new Point(a, b);
  617.                 bar.TopLocation.Right = new Point(a + c, b);
  618.                 bar.BottomLocation.Left = new Point(a, b + d);
  619.                 bar.BottomLocation.Right = new Point(a, b + d);
  620.  
  621.                 LinearGradientBrush obBrush = null;
  622.                 Rectangle obRect = new Rectangle(a, b, c, d);
  623.  
  624.                 if (bar.StartValue != null & endValue != null)
  625.                 {
  626.  
  627.                     if ((index >= scrollPos & index < barsViewable + scrollPos) | ignoreScrollAndMousePosition == true)
  628.                     {
  629.                         // Makes the bar gradient
  630.  
  631.                         obBrush = new LinearGradientBrush(obRect, color, Color.Gray, LinearGradientMode.Vertical);
  632.  
  633.                         // Draws the bar
  634.  
  635.                         grfx.DrawRectangle(Pens.Black, obRect);
  636.                         grfx.FillRectangle(obBrush, obRect);
  637.  
  638.                         // Draws the rowtext
  639.  
  640.                         grfx.DrawString(bar.Text, rowTextFont, Brushes.Black, 0, barStartTop + (barHeight * (index - scrollPos)) + (barSpace * (index - scrollPos)));
  641.  
  642.                         obBrush = null;
  643.                         //obRect = null;
  644.                         //obRect.TryDispose();
  645.                         obBrush = null;
  646.                     }
  647.                 }
  648.  
  649.                 //color = null;
  650.                 //color.TryDispose();
  651.             }
  652.         }
  653.  
  654.         /// <summary>
  655.         /// Draws the vertical lines
  656.         /// </summary>
  657.         /// <param name="grfx"></param>
  658.         /// <remarks></remarks>
  659.  
  660.         public void DrawNetVertical(Graphics grfx)
  661.         {
  662.             if (shownHeaderList == null)
  663.                 return;
  664.             if (shownHeaderList.Count == 0)
  665.                 return;
  666.  
  667.             int index = 0;
  668.             int availableWidth = this.Width - 10 - barStartLeft - barStartRight;
  669.             Header lastHeader = null;
  670.  
  671.             foreach (Header header in shownHeaderList)
  672.             {
  673.                 int headerLocationY = 0;
  674.  
  675.                 if (lastHeader == null)
  676.                 {
  677.                     headerLocationY = 0;
  678.                 }
  679.                 else if (header.Time.Hour < lastHeader.Time.Hour)
  680.                 {
  681.                     headerLocationY = 0;
  682.                 }
  683.                 else
  684.                 {
  685.                     headerLocationY = headerTimeStartTop;
  686.                 }
  687.  
  688.                 grfx.DrawLine(Pens.Bisque, barStartLeft + (index * widthPerItem), headerLocationY, barStartLeft + (index * widthPerItem), lastLineStop);
  689.                 index += 1;
  690.  
  691.                 lastHeader = header;
  692.             }
  693.  
  694.             grfx.DrawLine(lineColor, barStartLeft + (index * widthPerItem), headerTimeStartTop, barStartLeft + (index * widthPerItem), lastLineStop);
  695.         }
  696.  
  697.         /// <summary>
  698.         /// Draws the horizontal lines
  699.         /// </summary>
  700.         /// <param name="grfx"></param>
  701.         /// <remarks></remarks>
  702.  
  703.         public void DrawNetHorizontal(Graphics grfx)
  704.         {
  705.             if (shownHeaderList == null)
  706.                 return;
  707.             if (shownHeaderList.Count == 0)
  708.                 return;
  709.  
  710.             int index = 0;
  711.             int width = (widthPerItem * shownHeaderList.Count) + barStartLeft;
  712.  
  713.             // Last used index. Hopefully nobody will make a row named QQQ :o)
  714.             for (index = 0; index <= GetIndexChartBar("QQQQQQ"); index++)
  715.             {
  716.                 foreach (ChartBarDate bar in bars)
  717.                 {
  718.                     grfx.DrawLine(lineColor, 0, barStartTop + (barHeight * index) + (barSpace * index), width, barStartTop + (barHeight * index) + (barSpace * index));
  719.                 }
  720.             }
  721.  
  722.             lastLineStop = barStartTop + (barHeight * (index - 1)) + (barSpace * (index - 1));
  723.         }
  724.  
  725.         // This is the position (in pixels, from top) of the last line. Used for drawing lines
  726.  
  727.  
  728.         private int lastLineStop = 0;
  729.         #endregion
  730.  
  731.         #region "Header list"
  732.  
  733.         /// <summary>
  734.         /// Gets the full header list, consisting of hours between the two dates set
  735.         /// </summary>
  736.         /// <returns></returns>
  737.         /// <remarks></remarks>
  738.  
  739.         private List<Header> GetFullHeaderList()
  740.         {
  741.             List<Header> result = new List<Header>();
  742.             System.DateTime newFromTime = new System.DateTime(FromDate.Year, FromDate.Month, FromDate.Day);
  743.             string item = null;
  744.  
  745.             TimeSpan interval = ToDate - FromDate;
  746.  
  747.             if (interval.TotalDays < 1)
  748.             {
  749.                 var _with1 = newFromTime;
  750.                 newFromTime = _with1.AddHours(FromDate.Hour);
  751.  
  752.                 if (headerFromDate.Minute < 59 & headerFromDate.Minute > 29)
  753.                 {
  754.                     newFromTime = _with1.AddMinutes(30);
  755.                 }
  756.                 else
  757.                 {
  758.                     newFromTime = _with1.AddMinutes(0);
  759.                 }
  760.  
  761.                 while (newFromTime <= ToDate)
  762.                 {
  763.                     item = newFromTime.Hour + ":";
  764.  
  765.                     if (newFromTime.Minute < 10)
  766.                     {
  767.                         item += "0" + newFromTime.Minute;
  768.                     }
  769.                     else
  770.                     {
  771.                         item += "" + newFromTime.Minute;
  772.                     }
  773.  
  774.                     Header header = new Header();
  775.  
  776.                     header.HeaderText = item;
  777.                     header.HeaderTextInsteadOfTime = "";
  778.                     header.Time = new System.DateTime(newFromTime.Year, newFromTime.Month, newFromTime.Day, newFromTime.Hour, newFromTime.Minute, 0);
  779.                     result.Add(header);
  780.  
  781.                     newFromTime = newFromTime.AddMinutes(5);
  782.                     // The minimum interval of time between the headers
  783.                 }
  784.             }
  785.             else if (interval.TotalDays < 60)
  786.             {
  787.                 while (newFromTime <= ToDate)
  788.                 {
  789.                     Header header = new Header();
  790.  
  791.                     header.HeaderText = "";
  792.                     header.HeaderTextInsteadOfTime = "";
  793.                     header.Time = new System.DateTime(newFromTime.Year, newFromTime.Month, newFromTime.Day, 0, 0, 0);
  794.                     result.Add(header);
  795.  
  796.                     newFromTime = newFromTime.AddDays(1);
  797.                     // The minimum interval of time between the headers
  798.                 }
  799.             }
  800.             else
  801.             {
  802.                 while (newFromTime <= ToDate)
  803.                 {
  804.                     Header header = new Header();
  805.  
  806.                     header.HeaderText = "";
  807.                     header.Time = new System.DateTime(newFromTime.Year, newFromTime.Month, newFromTime.Day, 0, 0, 0);
  808.                     header.HeaderTextInsteadOfTime = newFromTime.ToString("MMM");
  809.                     result.Add(header);
  810.  
  811.                     newFromTime = newFromTime.AddMonths(1);
  812.                     // The minimum interval of time between the headers
  813.                 }
  814.             }
  815.  
  816.             return result;
  817.         }
  818.  
  819.         #endregion
  820.  
  821.         #region "Mouse Move"
  822.  
  823.         /// <summary>
  824.         /// Finds the current row and column based on mouse position
  825.         /// </summary>
  826.         /// <param name="sender"></param>
  827.         /// <param name="e"></param>
  828.         /// <remarks></remarks>
  829.  
  830.         private void GanttChart_MouseMove(System.Object sender, System.Windows.Forms.MouseEventArgs e)
  831.         {
  832.             if (shownHeaderList == null)
  833.                 return;
  834.             if (shownHeaderList.Count == 0)
  835.                 return;
  836.  
  837.             if (e.Button != System.Windows.Forms.MouseButtons.Left)
  838.             {
  839.                 mouseHoverPart = MouseOverPart.Empty;
  840.  
  841.                 // If bar has changed manually, but left mouse button is no longer pressed the BarChanged event will be raised
  842.  
  843.                 if (AllowManualEditBar == true)
  844.                 {
  845.                     if (barIsChanging >= 0)
  846.                     {
  847.                         if (BarChanged != null)
  848.                         {
  849.                             BarChanged(this, bars[barIsChanging].Value);
  850.                         }
  851.                         barIsChanging = -1;
  852.                     }
  853.                 }
  854.             }
  855.  
  856.             mouseHoverBarIndex = -1;
  857.  
  858.             Point LocalMousePosition = default(Point);
  859.  
  860.             LocalMousePosition = this.PointToClient(Cursor.Position);
  861.  
  862.             // Finds pixels per minute
  863.  
  864.             TimeSpan timeBetween = shownHeaderList[1].Time - shownHeaderList[0].Time;
  865.             int minutesBetween = (timeBetween.Days * 1440) + (timeBetween.Hours * 60) + timeBetween.Minutes;
  866.             dynamic widthBetween = (shownHeaderList[1].StartLocation - shownHeaderList[0].StartLocation);
  867.             decimal perMinute = widthBetween / minutesBetween;
  868.  
  869.             // Finds the time at mousepointer
  870.  
  871.             int minutesAtCursor = 0;
  872.  
  873.             if (LocalMousePosition.X > barStartLeft && perMinute > 0)
  874.             {
  875.                 minutesAtCursor = Convert.ToInt32((LocalMousePosition.X - barStartLeft) / perMinute);
  876.                 _mouseOverColumnValue = FromDate.AddMinutes(minutesAtCursor);
  877.             }
  878.             else
  879.             {
  880.                 //_mouseOverColumnValue.TryDispose();
  881.             }
  882.  
  883.             // Finds the row at mousepointer
  884.  
  885.             string rowText = "";
  886.             object rowValue = null;
  887.             string columnText = "";
  888.  
  889.             // Tests to see if the mouse pointer is hovering above the scrollbar
  890.  
  891.             bool scrollBarStatusChanged = false;
  892.  
  893.             // Tests to see if the mouse is hovering over the scroll-area bottom-arrow
  894.  
  895.             if (LocalMousePosition.X > BottomPart.Left & LocalMousePosition.Y < BottomPart.Right & LocalMousePosition.Y < BottomPart.Bottom & LocalMousePosition.Y > BottomPart.Top)
  896.             {
  897.                 if (mouseOverBottomPart == false)
  898.                 {
  899.                     scrollBarStatusChanged = true;
  900.                 }
  901.  
  902.                 mouseOverBottomPart = true;
  903.             }
  904.             else
  905.             {
  906.                 if (mouseOverBottomPart == false)
  907.                 {
  908.                     scrollBarStatusChanged = true;
  909.                 }
  910.  
  911.                 mouseOverBottomPart = false;
  912.             }
  913.  
  914.             // Tests to see if the mouse is hovering over the scroll-area top-arrow
  915.  
  916.             if (LocalMousePosition.X > topPart.Left & LocalMousePosition.Y < topPart.Right & LocalMousePosition.Y < topPart.Bottom & LocalMousePosition.Y > topPart.Top)
  917.             {
  918.                 if (mouseOverTopPart == false)
  919.                 {
  920.                     scrollBarStatusChanged = true;
  921.                 }
  922.  
  923.                 mouseOverTopPart = true;
  924.             }
  925.             else
  926.             {
  927.                 if (mouseOverTopPart == false)
  928.                 {
  929.                     scrollBarStatusChanged = true;
  930.                 }
  931.  
  932.                 mouseOverTopPart = false;
  933.             }
  934.  
  935.             // Tests to see if the mouse is hovering over the scroll
  936.  
  937.             if (LocalMousePosition.X > scroll.Left & LocalMousePosition.Y < scroll.Right & LocalMousePosition.Y < scroll.Bottom & LocalMousePosition.Y > scroll.Top)
  938.             {
  939.                 if (mouseOverScrollBar == false)
  940.                 {
  941.                     scrollBarStatusChanged = true;
  942.                 }
  943.  
  944.                 mouseOverScrollBar = true;
  945.                 mouseOverScrollBarArea = true;
  946.             }
  947.             else
  948.             {
  949.                 if (mouseOverScrollBar == false)
  950.                 {
  951.                     scrollBarStatusChanged = true;
  952.                 }
  953.  
  954.                 mouseOverScrollBar = false;
  955.                 mouseOverScrollBarArea = false;
  956.             }
  957.  
  958.             // If the mouse is not above the scroll, test if it's over the scroll area (no need to test if it's not above the scroll)
  959.  
  960.             if (mouseOverScrollBarArea == false)
  961.             {
  962.                 if (LocalMousePosition.X > scrollBarArea.Left & LocalMousePosition.Y < scrollBarArea.Right & LocalMousePosition.Y < scrollBarArea.Bottom & LocalMousePosition.Y > scrollBarArea.Top)
  963.                 {
  964.                     mouseOverScrollBarArea = true;
  965.                 }
  966.             }
  967.  
  968.  
  969.             // Tests to see if the mouse pointer is hovering above a bar
  970.  
  971.             int index = 0;
  972.  
  973.  
  974.             foreach (ChartBarDate bar in bars)
  975.             {
  976.                 // If the bar is set to be hidden from mouse move, the current bar will be ignored
  977.  
  978.                 if (bar.HideFromMouseMove == false)
  979.                 {
  980.                     if (bar.EndValue == null)
  981.                     {
  982.                         bar.EndValue = System.DateTime.Now;
  983.                     }
  984.  
  985.                     // Mouse pointer needs to be inside the X and Y positions of the bar
  986.  
  987.                     if (LocalMousePosition.Y > bar.TopLocation.Left.Y & LocalMousePosition.Y < bar.BottomLocation.Left.Y)
  988.                     {
  989.  
  990.                         if (LocalMousePosition.X > bar.TopLocation.Left.X & LocalMousePosition.X < bar.TopLocation.Right.X)
  991.                         {
  992.                             // If the current bar is the one where the mouse is above, the rowText and rowValue needs to be set correctly
  993.  
  994.                             rowText = bar.Text;
  995.                             rowValue = bar.Value;
  996.                             mouseHoverBarIndex = index;
  997.  
  998.                             if (mouseHoverPart != MouseOverPart.BarLeftSide & mouseHoverPart != MouseOverPart.BarRightSide)
  999.                             {
  1000.                                 mouseHoverPart = MouseOverPart.Bar;
  1001.                             }
  1002.                         }
  1003.  
  1004.                         // If mouse pointer is near the edges of the bar it will open up for editing the bar
  1005.  
  1006.                         if (AllowManualEditBar == true)
  1007.                         {
  1008.                             int areaSize = 5;
  1009.  
  1010.                             if (e.Button == System.Windows.Forms.MouseButtons.Left)
  1011.                             {
  1012.                                 areaSize = 50;
  1013.                             }
  1014.  
  1015.                             if (LocalMousePosition.X > bar.TopLocation.Left.X - areaSize & LocalMousePosition.X < bar.TopLocation.Left.X + areaSize & mouseHoverPart != MouseOverPart.BarRightSide)
  1016.                             {
  1017.                                 this.Cursor = Cursors.VSplit;
  1018.                                 mouseHoverPart = MouseOverPart.BarLeftSide;
  1019.                                 mouseHoverBarIndex = index;
  1020.                             }
  1021.                             else if (LocalMousePosition.X > bar.TopLocation.Right.X - areaSize & LocalMousePosition.X < bar.TopLocation.Right.X + areaSize & mouseHoverPart != MouseOverPart.BarLeftSide)
  1022.                             {
  1023.                                 this.Cursor = Cursors.VSplit;
  1024.                                 mouseHoverPart = MouseOverPart.BarRightSide;
  1025.                                 mouseHoverBarIndex = index;
  1026.                             }
  1027.                             else
  1028.                             {
  1029.                                 this.Cursor = Cursors.Default;
  1030.                             }
  1031.                         }
  1032.                     }
  1033.                 }
  1034.  
  1035.                 index += 1;
  1036.             }
  1037.  
  1038.             // Sets the mouseover row value and text
  1039.  
  1040.             _mouseOverRowText = rowText;
  1041.             _mouseOverRowValue = rowValue;
  1042.  
  1043.             if (e.Button == System.Windows.Forms.MouseButtons.Left)
  1044.             {
  1045.                 if (MouseDragged != null)
  1046.                 {
  1047.                     MouseDragged(sender, e);
  1048.                 }
  1049.  
  1050.             }
  1051.             else
  1052.             {
  1053.                 // A simple test to see if the mousemovement has caused any changes to how it should be displayed
  1054.                 // It only redraws if mouse moves from a bar to blank area or from blank area to a bar
  1055.                 // This increases performance compared to having a redraw every time a mouse moves
  1056.  
  1057.                 if ((_mouseOverRowValue == null & (rowValue != null)) | ((_mouseOverRowValue != null) & rowValue == null) | scrollBarStatusChanged == true)
  1058.                 {
  1059.                     PaintChart();
  1060.                 }
  1061.             }
  1062.         }
  1063.  
  1064.         /// <summary>
  1065.         /// Mouse leave event
  1066.         /// </summary>
  1067.         /// <param name="sender"></param>
  1068.         /// <param name="e"></param>
  1069.         /// <remarks></remarks>
  1070.  
  1071.         private void GanttChart_MouseLeave(System.Object sender, System.EventArgs e)
  1072.         {
  1073.             _mouseOverRowText = null;
  1074.             _mouseOverRowValue = null;
  1075.             mouseHoverPart = MouseOverPart.Empty;
  1076.  
  1077.             PaintChart();
  1078.         }
  1079.  
  1080.         /// <summary>
  1081.         /// Mouse drag event
  1082.         /// </summary>
  1083.         /// <param name="sender"></param>
  1084.         /// <param name="e"></param>
  1085.         /// <remarks></remarks>
  1086.  
  1087.         public void GanttChart_MouseDragged(object sender, System.Windows.Forms.MouseEventArgs e)
  1088.         {
  1089.             if (mouseOverScrollBarArea == true)
  1090.             {
  1091.                 ScrollPositionY = e.Location.Y;
  1092.             }
  1093.  
  1094.             if (AllowManualEditBar == true)
  1095.             {
  1096.                 if (mouseHoverBarIndex > -1)
  1097.                 {
  1098.                     if (mouseHoverPart == MouseOverPart.BarLeftSide)
  1099.                     {
  1100.                         barIsChanging = mouseHoverBarIndex;
  1101.                         bars[mouseHoverBarIndex].StartValue = _mouseOverColumnValue;
  1102.                         PaintChart();
  1103.                     }
  1104.                     else if (mouseHoverPart == MouseOverPart.BarRightSide)
  1105.                     {
  1106.                         barIsChanging = mouseHoverBarIndex;
  1107.                         bars[mouseHoverBarIndex].EndValue = _mouseOverColumnValue;
  1108.                         PaintChart();
  1109.                     }
  1110.                 }
  1111.             }
  1112.         }
  1113.  
  1114.  
  1115.         #endregion
  1116.  
  1117.         #region "ToolTipText"
  1118.  
  1119.         private List<string> _toolTipText = new List<string>();
  1120.  
  1121.         private string _toolTipTextTitle = "";
  1122.  
  1123.         private Point MyPoint = new Point(0, 0);
  1124.         /// <summary>
  1125.         /// The title to draw
  1126.         /// </summary>
  1127.         /// <value></value>
  1128.         /// <returns></returns>
  1129.         /// <remarks></remarks>
  1130.  
  1131.         public string ToolTipTextTitle
  1132.         {
  1133.             get { return _toolTipTextTitle; }
  1134.             set { _toolTipTextTitle = value; }
  1135.         }
  1136.  
  1137.         /// <summary>
  1138.         /// Gets or sets the ToolTipText lines
  1139.         /// </summary>
  1140.         /// <value></value>
  1141.         /// <returns></returns>
  1142.         /// <remarks>Don not use the add function directly on this, use ToolTipText = value</remarks>
  1143.  
  1144.         public List<string> ToolTipText
  1145.         {
  1146.             get
  1147.             {
  1148.                 if (_toolTipText == null)
  1149.                     _toolTipText = new List<string>();
  1150.                 return _toolTipText;
  1151.             }
  1152.             set
  1153.             {
  1154.                 _toolTipText = value;
  1155.  
  1156.                 Point LocalMousePosition = default(Point);
  1157.  
  1158.                 LocalMousePosition = this.PointToClient(Cursor.Position);
  1159.  
  1160.  
  1161.                 if (LocalMousePosition == MyPoint)
  1162.                     return;
  1163.  
  1164.                 MyPoint = LocalMousePosition;
  1165.  
  1166.                 ToolTip.SetToolTip(this, ".");
  1167.             }
  1168.         }
  1169.  
  1170.         /// <summary>
  1171.         /// Draws the ToolTip window
  1172.         /// </summary>
  1173.         /// <param name="sender"></param>
  1174.         /// <param name="e"></param>
  1175.         /// <remarks></remarks>
  1176.  
  1177.         private void ToolTipText_Draw(System.Object sender, System.Windows.Forms.DrawToolTipEventArgs e)
  1178.         {
  1179.             if (ToolTipText == null)
  1180.             {
  1181.                 ToolTipText = new List<string>();
  1182.                 return;
  1183.             }
  1184.  
  1185.             if (ToolTipText.Count == 0)
  1186.             {
  1187.                 return;
  1188.             }
  1189.             else if (ToolTipText[0].Length == 0)
  1190.             {
  1191.                 return;
  1192.             }
  1193.  
  1194.             int x = 0;
  1195.             int y = 0;
  1196.  
  1197.             e.Graphics.FillRectangle(Brushes.AntiqueWhite, e.Bounds);
  1198.             e.DrawBorder();
  1199.  
  1200.             int titleHeight = 14;
  1201.             int fontHeight = 12;
  1202.  
  1203.             // Draws the line just below the title
  1204.  
  1205.             e.Graphics.DrawLine(Pens.Black, 0, titleHeight, e.Bounds.Width, titleHeight);
  1206.  
  1207.             int lines = 1;
  1208.             string text = ToolTipTextTitle;
  1209.  
  1210.             // Draws the title
  1211.  
  1212.             using (Font font = new Font(e.Font, FontStyle.Bold))
  1213.             {
  1214.                 x = Convert.ToInt32((e.Bounds.Width - e.Graphics.MeasureString(text, font).Width) / 2);
  1215.                 y = Convert.ToInt32((titleHeight - e.Graphics.MeasureString(text, font).Height) / 2);
  1216.                 e.Graphics.DrawString(text, font, Brushes.Black, x, y);
  1217.             }
  1218.  
  1219.             // Draws the lines
  1220.             for (int i = 0; i < ToolTipText.Count; i++)
  1221.             {
  1222.                 Font font = new Font(e.Font, FontStyle.Regular);
  1223.  
  1224.                 if (ToolTipText[i].Contains("[b]"))
  1225.                 {
  1226.                     font = new Font(font.FontFamily, font.Size, FontStyle.Bold, font.Unit);
  1227.                     ToolTipText[i] = ToolTipText[i].Replace("[b]", "");
  1228.                 }
  1229.  
  1230.                 using (font)
  1231.                 {
  1232.                     x = 5;
  1233.                     y = Convert.ToInt32((titleHeight - fontHeight - e.Graphics.MeasureString(ToolTipText[i], font).Height) / 2 + 10 + (lines * 14));
  1234.                     e.Graphics.DrawString(ToolTipText[i], font, Brushes.Black, x, y);
  1235.                 }
  1236.  
  1237.                 lines += 1;
  1238.             }
  1239.             //foreach (string str in ToolTipText)
  1240.             //{
  1241.             //    Font font = new Font(e.Font, FontStyle.Regular);
  1242.  
  1243.             //    if (str.Contains("[b]"))
  1244.             //    {
  1245.             //        font = new Font(font.FontFamily, font.Size, FontStyle.Bold, font.Unit);
  1246.             //        str = str.Replace("[b]", "");
  1247.             //    }
  1248.  
  1249.             //    using (font)
  1250.             //    {
  1251.             //        x = 5;
  1252.             //        y = Convert.ToInt32((titleHeight - fontHeight - e.Graphics.MeasureString(str, font).Height) / 2 + 10 + (lines * 14));
  1253.             //        e.Graphics.DrawString(str, font, Brushes.Black, x, y);
  1254.             //    }
  1255.  
  1256.             //    lines += 1;
  1257.             //}
  1258.         }
  1259.  
  1260.         /// <summary>
  1261.         /// Automatically resizes the ToolTip window
  1262.         /// </summary>
  1263.         /// <param name="sender"></param>
  1264.         /// <param name="e"></param>
  1265.         /// <remarks></remarks>
  1266.  
  1267.         private void ToolTipText_Popup(System.Object sender, System.Windows.Forms.PopupEventArgs e)
  1268.         {
  1269.             if (ToolTipText == null)
  1270.             {
  1271.                 ToolTipText = new List<string>();
  1272.             }
  1273.  
  1274.             if (ToolTipText.Count == 0)
  1275.             {
  1276.                 e.ToolTipSize = new Size(0, 0);
  1277.                 return;
  1278.             }
  1279.             else if (ToolTipText[0].Length == 0)
  1280.             {
  1281.                 e.ToolTipSize = new Size(0, 0);
  1282.                 return;
  1283.             }
  1284.  
  1285.             // resizes the ToolTip window
  1286.  
  1287.             int height = 18 + (ToolTipText.Count * 15);
  1288.             e.ToolTipSize = new Size(200, height);
  1289.         }
  1290.  
  1291.         #endregion
  1292.  
  1293.         #region "ChartBar"
  1294.  
  1295.         private class ChartBarDate
  1296.         {
  1297.  
  1298.             internal class Location
  1299.             {
  1300.  
  1301.                 private Point _right = new Point(0, 0);
  1302.  
  1303.                 private Point _left = new Point(0, 0);
  1304.                 public Point Right
  1305.                 {
  1306.                     get { return _right; }
  1307.                     set { _right = value; }
  1308.                 }
  1309.  
  1310.                 public Point Left
  1311.                 {
  1312.                     get { return _left; }
  1313.                     set { _left = value; }
  1314.                 }
  1315.  
  1316.             }
  1317.  
  1318.             private System.DateTime _startValue;
  1319.  
  1320.             private System.DateTime _endValue;
  1321.             private Color _color;
  1322.  
  1323.             private Color _hoverColor;
  1324.             private string _text;
  1325.  
  1326.             private object _value;
  1327.  
  1328.             private int _rowIndex;
  1329.             private Location _topLocation = new Location();
  1330.  
  1331.             private Location _bottomLocation = new Location();
  1332.  
  1333.             private bool _hideFromMouseMove = false;
  1334.             public System.DateTime StartValue
  1335.             {
  1336.                 get { return _startValue; }
  1337.                 set { _startValue = value; }
  1338.             }
  1339.  
  1340.             public System.DateTime EndValue
  1341.             {
  1342.                 get { return _endValue; }
  1343.                 set { _endValue = value; }
  1344.             }
  1345.  
  1346.             public Color Color
  1347.             {
  1348.                 get { return _color; }
  1349.                 set { _color = value; }
  1350.             }
  1351.  
  1352.             public Color HoverColor
  1353.             {
  1354.                 get { return _hoverColor; }
  1355.                 set { _hoverColor = value; }
  1356.             }
  1357.  
  1358.             public string Text
  1359.             {
  1360.                 get { return _text; }
  1361.                 set { _text = value; }
  1362.             }
  1363.  
  1364.             public object Value
  1365.             {
  1366.                 get { return _value; }
  1367.                 set { _value = value; }
  1368.             }
  1369.  
  1370.             public int RowIndex
  1371.             {
  1372.                 get { return _rowIndex; }
  1373.                 set { _rowIndex = value; }
  1374.             }
  1375.  
  1376.             public bool HideFromMouseMove
  1377.             {
  1378.                 get { return _hideFromMouseMove; }
  1379.                 set { _hideFromMouseMove = value; }
  1380.             }
  1381.  
  1382.             internal Location TopLocation
  1383.             {
  1384.                 get { return _topLocation; }
  1385.                 set { _topLocation = value; }
  1386.             }
  1387.  
  1388.             internal Location BottomLocation
  1389.             {
  1390.                 get { return _bottomLocation; }
  1391.                 set { _bottomLocation = value; }
  1392.             }
  1393.  
  1394.         }
  1395.  
  1396.         #endregion
  1397.  
  1398.         #region "Headers"
  1399.  
  1400.         private class Header
  1401.         {
  1402.  
  1403.             private string _headerText;
  1404.             private int _startLocation;
  1405.             private string _headerTextInsteadOfTime = "";
  1406.  
  1407.             private System.DateTime _time;
  1408.             public string HeaderText
  1409.             {
  1410.                 get { return _headerText; }
  1411.                 set { _headerText = value; }
  1412.             }
  1413.  
  1414.             public int StartLocation
  1415.             {
  1416.                 get { return _startLocation; }
  1417.                 set { _startLocation = value; }
  1418.             }
  1419.  
  1420.             /// <summary>
  1421.             /// If this string is larger than 0, this will be used instead of Time
  1422.             /// </summary>
  1423.             /// <value></value>
  1424.             /// <returns></returns>
  1425.             /// <remarks></remarks>
  1426.  
  1427.             public string HeaderTextInsteadOfTime
  1428.             {
  1429.                 get { return _headerTextInsteadOfTime; }
  1430.                 set { _headerTextInsteadOfTime = value; }
  1431.             }
  1432.  
  1433.             /// <summary>
  1434.             /// Time to display
  1435.             /// </summary>
  1436.             /// <value></value>
  1437.             /// <returns></returns>
  1438.             /// <remarks></remarks>
  1439.  
  1440.             public System.DateTime Time
  1441.             {
  1442.                 get { return _time; }
  1443.                 set { _time = value; }
  1444.             }
  1445.  
  1446.         }
  1447.  
  1448.         #endregion
  1449.  
  1450.         #region "Resize"
  1451.  
  1452.         /// <summary>
  1453.         /// On resize the Gantt Chart is redrawn
  1454.         /// </summary>
  1455.         /// <param name="e"></param>
  1456.         /// <remarks></remarks>
  1457.  
  1458.         protected override void OnResize(System.EventArgs e)
  1459.         {
  1460.             base.OnResize(e);
  1461.  
  1462.             scrollPosition = 0;
  1463.  
  1464.             // Used for when the Gantt Chart is saved as an image
  1465.  
  1466.             if (lastLineStop > 0)
  1467.             {
  1468.                 objBmp = new Bitmap(this.Width - barStartRight, lastLineStop, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
  1469.                 objGraphics = Graphics.FromImage(objBmp);
  1470.             }
  1471.  
  1472.             PaintChart();
  1473.         }
  1474.  
  1475.         #endregion
  1476.  
  1477.         #region "Scrollbar"
  1478.  
  1479.         private int barsViewable = -1;
  1480.         private int scrollPosition = 0;
  1481.         private Rectangle topPart;
  1482.         private Rectangle BottomPart;
  1483.         private Rectangle scroll;
  1484.  
  1485.         private Rectangle scrollBarArea;
  1486.         private bool mouseOverTopPart = false;
  1487.         private bool mouseOverBottomPart = false;
  1488.         private bool mouseOverScrollBar = false;
  1489.  
  1490.         private bool mouseOverScrollBarArea = false;
  1491.         /// <summary>
  1492.         /// Draws a scrollbar to the component, if there's a need for it
  1493.         /// </summary>
  1494.         /// <param name="grfx"></param>
  1495.         /// <remarks></remarks>
  1496.  
  1497.         private void DrawScrollBar(Graphics grfx)
  1498.         {
  1499.             barsViewable = (this.Height - barStartTop) / (barHeight + barSpace);
  1500.             int barCount = GetIndexChartBar("QQQWWW");
  1501.             if (barCount == 0)
  1502.                 return;
  1503.  
  1504.             int maxHeight = this.Height - 30;
  1505.             decimal scrollHeight = (maxHeight / barCount) * barsViewable;
  1506.  
  1507.             // If the scroll area is filled there's no need to show the scrollbar
  1508.  
  1509.             if (scrollHeight >= maxHeight)
  1510.                 return;
  1511.  
  1512.             decimal scrollSpeed = (maxHeight - scrollHeight) / (barCount - barsViewable);
  1513.  
  1514.             scrollBarArea = new Rectangle(this.Width - 20, 19, 12, maxHeight);
  1515.             scroll = new Rectangle(this.Width - 20, 19 + Convert.ToInt32((scrollPosition * scrollSpeed)), 12, Convert.ToInt32(scrollHeight));
  1516.  
  1517.             topPart = new Rectangle(this.Width - 20, 10, 12, 8);
  1518.             BottomPart = new Rectangle(this.Width - 20, this.Height - 10, 12, 8);
  1519.  
  1520.             Brush colorTopPart = null;
  1521.             Brush colorBottomPart = null;
  1522.             Brush colorScroll = null;
  1523.  
  1524.             if (mouseOverTopPart == true)
  1525.             {
  1526.                 colorTopPart = Brushes.Black;
  1527.             }
  1528.             else
  1529.             {
  1530.                 colorTopPart = Brushes.Gray;
  1531.             }
  1532.  
  1533.             if (mouseOverBottomPart == true)
  1534.             {
  1535.                 colorBottomPart = Brushes.Black;
  1536.             }
  1537.             else
  1538.             {
  1539.                 colorBottomPart = Brushes.Gray;
  1540.             }
  1541.  
  1542.             if (mouseOverScrollBar == true)
  1543.             {
  1544.                 colorScroll = new LinearGradientBrush(scroll, Color.Bisque, Color.Gray, LinearGradientMode.Horizontal);
  1545.             }
  1546.             else
  1547.             {
  1548.                 colorScroll = new LinearGradientBrush(scroll, Color.White, Color.Gray, LinearGradientMode.Horizontal);
  1549.             }
  1550.  
  1551.             // Draws the top and bottom part of the scrollbar
  1552.  
  1553.             grfx.DrawRectangle(Pens.Black, topPart);
  1554.             grfx.FillRectangle(Brushes.LightGray, topPart);
  1555.  
  1556.             grfx.DrawRectangle(Pens.Black, BottomPart);
  1557.             grfx.FillRectangle(Brushes.LightGray, BottomPart);
  1558.  
  1559.             // Draws arrows
  1560.  
  1561.             PointF[] points = new PointF[3];
  1562.             points[0] = new PointF(topPart.Left, topPart.Bottom - 1);
  1563.             points[1] = new PointF(topPart.Right, topPart.Bottom - 1);
  1564.             points[2] = new PointF((topPart.Left + topPart.Right) / 2, topPart.Top + 1);
  1565.  
  1566.             grfx.FillPolygon(colorTopPart, points);
  1567.  
  1568.             points[0] = new PointF(BottomPart.Left, BottomPart.Top + 1);
  1569.             points[1] = new PointF(BottomPart.Right, BottomPart.Top + 1);
  1570.             points[2] = new PointF((BottomPart.Left + BottomPart.Right) / 2, BottomPart.Bottom - 1);
  1571.  
  1572.             grfx.FillPolygon(colorBottomPart, points);
  1573.  
  1574.             // Draws the scroll area
  1575.  
  1576.             grfx.DrawRectangle(Pens.Black, scrollBarArea);
  1577.             grfx.FillRectangle(Brushes.DarkGray, scrollBarArea);
  1578.  
  1579.             // Draws the actual scrollbar
  1580.  
  1581.             grfx.DrawRectangle(Pens.Black, scroll);
  1582.             grfx.FillRectangle(colorScroll, scroll);
  1583.         }
  1584.  
  1585.         /// <summary>
  1586.         /// The Y-position of the center of the scroll
  1587.         /// </summary>
  1588.         /// <value></value>
  1589.         /// <returns></returns>
  1590.         /// <remarks></remarks>
  1591.  
  1592.         private int ScrollPositionY
  1593.         {
  1594.             get
  1595.             {
  1596.                 if (scroll == null)
  1597.                     return -1;
  1598.                 return ((scroll.Height / 2) + scroll.Location.Y) + 19;
  1599.             }
  1600.             set
  1601.             {
  1602.                 int barCount = GetIndexChartBar("QQQWWW");
  1603.                 int maxHeight = this.Height - 30;
  1604.                 decimal scrollHeight = (maxHeight / barCount) * barsViewable;
  1605.                 decimal scrollSpeed = (maxHeight - scrollHeight) / (barCount - barsViewable);
  1606.                 int index = 0;
  1607.                 dynamic distanceFromLastPosition = 9999;
  1608.  
  1609.                 // Tests to see what scrollposition is the closest to the set position
  1610.  
  1611.                 while (index < barCount)
  1612.                 {
  1613.                     int newPositionTemp = Convert.ToInt32((index * scrollSpeed) + (scrollHeight / 2) + (30 / 2));
  1614.                     dynamic distanceFromCurrentPosition = newPositionTemp - value;
  1615.  
  1616.                     if (distanceFromLastPosition < 0)
  1617.                     {
  1618.                         if (distanceFromCurrentPosition < distanceFromLastPosition)
  1619.                         {
  1620.                             scrollPosition = index - 1;
  1621.                             PaintChart();
  1622.                             return;
  1623.                         }
  1624.                     }
  1625.                     else
  1626.                     {
  1627.                         if (distanceFromCurrentPosition > distanceFromLastPosition)
  1628.                         {
  1629.                             scrollPosition = index - 1;
  1630.  
  1631.                             // A precaution to make sure the scroll bar doesn't go too far down
  1632.  
  1633.                             if (scrollPosition + barsViewable > GetIndexChartBar("QQQWWW"))
  1634.                             {
  1635.                                 scrollPosition = GetIndexChartBar("QQQWWW") - barsViewable;
  1636.                             }
  1637.  
  1638.                             PaintChart();
  1639.                             return;
  1640.                         }
  1641.                     }
  1642.  
  1643.                     distanceFromLastPosition = distanceFromCurrentPosition;
  1644.  
  1645.                     index += 1;
  1646.                 }
  1647.             }
  1648.         }
  1649.  
  1650.         /// <summary>
  1651.         /// Scrolls one row up
  1652.         /// </summary>
  1653.         /// <remarks></remarks>
  1654.  
  1655.         public void ScrollOneup()
  1656.         {
  1657.             if (scrollPosition == 0)
  1658.                 return;
  1659.  
  1660.             scrollPosition -= 1;
  1661.  
  1662.             PaintChart();
  1663.         }
  1664.  
  1665.         /// <summary>
  1666.         /// Scrolls one row down
  1667.         /// </summary>
  1668.         /// <remarks></remarks>
  1669.  
  1670.         public void ScrollOneDown()
  1671.         {
  1672.             if (scrollPosition + barsViewable >= GetIndexChartBar("QQQWWW"))
  1673.                 return;
  1674.  
  1675.             scrollPosition += 1;
  1676.  
  1677.             PaintChart();
  1678.         }
  1679.  
  1680.         /// <summary>
  1681.         /// If the user clicks on the scrollbar, scrolling functions will be called
  1682.         /// </summary>
  1683.         /// <param name="sender"></param>
  1684.         /// <param name="e"></param>
  1685.         /// <remarks></remarks>
  1686.  
  1687.         private void GanttChart_Click(System.Object sender, System.Windows.Forms.MouseEventArgs e)
  1688.         {
  1689.             if (e.Button == System.Windows.Forms.MouseButtons.Left)
  1690.             {
  1691.                 if (mouseOverBottomPart == true)
  1692.                 {
  1693.                     ScrollOneDown();
  1694.                 }
  1695.                 else if (mouseOverTopPart == true)
  1696.                 {
  1697.                     ScrollOneup();
  1698.                 }
  1699.             }
  1700.         }
  1701.  
  1702.         /// <summary>
  1703.         /// When mousewheel is used, the scrollbar will scroll
  1704.         /// </summary>
  1705.         /// <param name="sender"></param>
  1706.         /// <param name="e"></param>
  1707.         /// <remarks></remarks>
  1708.  
  1709.         private void GanttChart_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
  1710.         {
  1711.             if (e.Delta > 0)
  1712.             {
  1713.                 ScrollOneup();
  1714.             }
  1715.             else
  1716.             {
  1717.                 ScrollOneDown();
  1718.             }
  1719.         }
  1720.  
  1721.         #endregion
  1722.  
  1723.         #region "Save"
  1724.  
  1725.         /// <summary>
  1726.         /// Saves the GanttChart to specified image file
  1727.         /// </summary>
  1728.         /// <param name="filePath"></param>
  1729.         /// <remarks></remarks>
  1730.  
  1731.         public void SaveImage(string filePath)
  1732.         {
  1733.             objGraphics.SmoothingMode = SmoothingMode.HighSpeed;
  1734.             objGraphics.Clear(this.BackColor);
  1735.  
  1736.             if (headerFromDate == null | headerToDate == null)
  1737.                 return;
  1738.  
  1739.             DrawHeader(objGraphics, null);
  1740.             DrawNetHorizontal(objGraphics);
  1741.             DrawNetVertical(objGraphics);
  1742.             DrawBars(objGraphics, true);
  1743.  
  1744.             objBmp.Save(filePath);
  1745.         }
  1746.  
  1747.         #endregion
  1748.  
  1749.         private enum MouseOverPart
  1750.         {
  1751.  
  1752.             Empty,
  1753.             Bar,
  1754.             BarLeftSide,
  1755.             BarRightSide
  1756.  
  1757.         }
  1758.  
  1759.     }