// ----------------------------------------------------------------------- // // http://www.codeproject.com/Articles/20731/Gantt-Chart // // Adds an easy to use Gantt Chart to your application // Created by Adrian "Adagio" Grau // Version 0.55 // // // // ----------------------------------------------------------------------- using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing.Drawing2D; using System.Drawing; using System.Windows.Forms; /// /// TODO: Update summary. /// public class GanttChart : Control { private MouseOverPart mouseHoverPart = MouseOverPart.Empty; private int mouseHoverBarIndex = -1; private List bars = new List(); private System.DateTime headerFromDate; private System.DateTime headerToDate; private int barIsChanging = -1; private int barStartRight = 20; private int barStartLeft = 100; private int headerTimeStartTop = 30; private List
shownHeaderList; private int barStartTop = 50; private int barHeight = 9; private int barSpace = 5; private int widthPerItem; private System.DateTime _mouseOverColumnValue; private string _mouseOverRowText = ""; private object _mouseOverRowValue = null; private Pen lineColor = Pens.Bisque; private Font dateTextFont = new Font("VERDANA", 8.0f, FontStyle.Regular, GraphicsUnit.Point); private Font timeTextFont = new Font("VERDANA", 8.0f, FontStyle.Regular, GraphicsUnit.Point); private Font rowTextFont = new Font("VERDANA", 8.0f, FontStyle.Regular, GraphicsUnit.Point); private System.Windows.Forms.ToolTip withEventsField_ToolTip = new System.Windows.Forms.ToolTip(); internal System.Windows.Forms.ToolTip ToolTip { get { return withEventsField_ToolTip; } set { if (withEventsField_ToolTip != null) { withEventsField_ToolTip.Draw -= ToolTipText_Draw; withEventsField_ToolTip.Popup -= ToolTipText_Popup; } withEventsField_ToolTip = value; if (withEventsField_ToolTip != null) { withEventsField_ToolTip.Draw += ToolTipText_Draw; withEventsField_ToolTip.Popup += ToolTipText_Popup; } } } private bool _allowEditBarWithMouse = false; public event MouseDraggedEventHandler MouseDragged; public delegate void MouseDraggedEventHandler(object sender, System.Windows.Forms.MouseEventArgs e); public event BarChangedEventHandler BarChanged; public delegate void BarChangedEventHandler(object sender, object barValue); private Bitmap objBmp; private Graphics objGraphics; protected new bool DesignMode { get { if (base.DesignMode) return true; return System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime; } } #region "Public properties" /// /// Sets to true if the user should be able to manually edit bars /// /// /// /// public bool AllowManualEditBar { get { return _allowEditBarWithMouse; } set { _allowEditBarWithMouse = value; } } /// /// The start date/time of the chart /// /// /// /// public System.DateTime FromDate { get { return headerFromDate; } set { headerFromDate = value; } } /// /// The end date/time of the chart /// /// /// /// public System.DateTime ToDate { get { return headerToDate; } set { headerToDate = value; } } /// /// The text for the current row the mouse hovers above /// /// /// /// public string MouseOverRowText { get { return _mouseOverRowText; } } /// /// The value for the current bar the mouse hovers above /// /// /// /// public object MouseOverRowValue { get { return _mouseOverRowValue; } } /// /// The date/time the mouse hovers above /// /// /// /// public System.DateTime MouseOverColumnDate { get { return _mouseOverColumnValue; } } /// /// The color of the grid /// /// /// /// public System.Drawing.Pen GridColor { get { return lineColor; } set { lineColor = value; } } /// /// The font used for the row text /// /// /// /// public Font RowFont { get { return rowTextFont; } set { rowTextFont = value; } } /// /// The font used for the "date" text in the columns /// /// /// /// public Font DateFont { get { return dateTextFont; } set { dateTextFont = value; } } /// /// The font used for the "time" text in the colums) /// /// /// /// public Font TimeFont { get { return timeTextFont; } set { timeTextFont = value; } } #endregion #region "Constructor" /// /// Default constructor /// /// public GanttChart() { if (!DesignMode) { MouseWheel += GanttChart_MouseWheel; MouseClick += GanttChart_Click; MouseDragged += GanttChart_MouseDragged; MouseLeave += GanttChart_MouseLeave; MouseMove += GanttChart_MouseMove; ToolTip.AutoPopDelay = 15000; ToolTip.InitialDelay = 250; ToolTip.OwnerDraw = true; objBmp = new Bitmap(1280, 1024, System.Drawing.Imaging.PixelFormat.Format24bppRgb); objGraphics = Graphics.FromImage(objBmp); // Flicker free drawing this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); } } #endregion #region "Bars" private void SetBarStartLeft(string rowText) { Graphics gfx = this.CreateGraphics(); int length = Convert.ToInt32(gfx.MeasureString(rowText, rowTextFont, 500).Width); if (length > barStartLeft) { barStartLeft = length; } } /// /// Adds a bar to the list /// /// Text for the row /// Value for the row /// The date/time the bar starts /// The date/time the bar ends /// The color of the bar /// The hover color of the bar /// The rowindex of the bar (useful if you want several bars on the same row) /// public void AddChartBar(string rowText, object barValue, System.DateTime fromTime, System.DateTime toTime, Color color, Color hoverColor, int rowIndex) { ChartBarDate bar = new ChartBarDate(); bar.Text = rowText; bar.Value = barValue; bar.StartValue = fromTime; bar.EndValue = toTime; bar.Color = color; bar.HoverColor = hoverColor; bar.RowIndex = rowIndex; bars.Add(bar); SetBarStartLeft(rowText); } /// /// Adds a bar to the list /// /// Text for the row /// Value for the row /// The date/time the bar starts /// The date/time the bar ends /// The color of the bar /// The hover color of the bar /// The rowindex of the bar (useful if you want several bars on the same row) /// If you want to "hide" the bar from mousemove event /// public void AddChartBar(string rowText, object barValue, System.DateTime fromTime, System.DateTime toTime, Color color, Color hoverColor, int rowIndex, bool hideFromMouseMove) { ChartBarDate bar = new ChartBarDate(); bar.Text = rowText; bar.Value = barValue; bar.StartValue = fromTime; bar.EndValue = toTime; bar.Color = color; bar.HoverColor = hoverColor; bar.RowIndex = rowIndex; bar.HideFromMouseMove = hideFromMouseMove; bars.Add(bar); SetBarStartLeft(rowText); } /// /// Gets the next index /// /// /// /// public int GetIndexChartBar(string rowText) { int index = -1; foreach (ChartBarDate bar in bars) { if (bar.Text.Equals(rowText) == true) { return bar.RowIndex; } if (bar.RowIndex > index) { index = bar.RowIndex; } } return index + 1; } /// /// Removes all bars from list /// /// public void RemoveBars() { bars = new List(); barStartLeft = 100; } #endregion #region "Draw" /// /// Redraws the Gantt chart /// /// public void PaintChart() { this.Invalidate(); } /// /// Redraws the Gantt chart /// /// /// private void PaintChart(Graphics gfx) { gfx.Clear(this.BackColor); if (headerFromDate == null | headerToDate == null) return; DrawScrollBar(gfx); DrawHeader(gfx, null); DrawNetHorizontal(gfx); DrawNetVertical(gfx); DrawBars(gfx); objBmp = new Bitmap(this.Width - barStartRight, lastLineStop, System.Drawing.Imaging.PixelFormat.Format24bppRgb); objGraphics = Graphics.FromImage(objBmp); } /// /// Redraws the Gantt chart /// /// /// protected override void OnPaint(System.Windows.Forms.PaintEventArgs pe) { base.OnPaint(pe); if (!DesignMode) { PaintChart(pe.Graphics); } } /// /// Draws the list of headers. Automatically shows which headers to draw, based on the width of the Gantt Chart /// /// /// /// private void DrawHeader(Graphics gfx, List
headerList) { if (headerList == null) { headerList = GetFullHeaderList(); } if (headerList.Count == 0) return; dynamic availableWidth = this.Width - 10 - barStartLeft - barStartRight; widthPerItem = availableWidth / headerList.Count; if (widthPerItem < 40) { List
newHeaderList = new List
(); bool showNext = true; // If there's not enough room for all headers remove 50% foreach (Header header in headerList) { if (showNext == true) { newHeaderList.Add(header); showNext = false; } else { showNext = true; } } DrawHeader(gfx, newHeaderList); return; } int index = 0; int headerStartPosition = -1; Header lastHeader = null; foreach (Header header in headerList) { int startPos = barStartLeft + (index * widthPerItem); bool showDateHeader = false; header.StartLocation = startPos; // Checks whether to show the date or not if (lastHeader == null) { showDateHeader = true; } else if (header.Time.Hour < lastHeader.Time.Hour) { showDateHeader = true; } else if (header.Time.Minute == lastHeader.Time.Minute) { showDateHeader = true; } // Show date if (showDateHeader == true) { string str = ""; if (header.HeaderTextInsteadOfTime.Length > 0) { str = header.HeaderTextInsteadOfTime; } else { str = header.Time.ToString("d-MMM"); } gfx.DrawString(str, dateTextFont, Brushes.Black, startPos, 0); } // Show time gfx.DrawString(header.HeaderText, timeTextFont, Brushes.Black, startPos, headerTimeStartTop); index += 1; lastHeader = header; } shownHeaderList = headerList; widthPerItem = (this.Width - 10 - barStartLeft - barStartRight) / shownHeaderList.Count; } /// /// Draws the bars /// /// /// private void DrawBars(Graphics grfx, bool ignoreScrollAndMousePosition = false) { if (shownHeaderList == null) return; if (shownHeaderList.Count == 0) return; int index = 0; // Finds pixels per minute TimeSpan timeBetween = shownHeaderList[1].Time - shownHeaderList[0].Time; int minutesBetween = Convert.ToInt32(timeBetween.TotalMinutes); //(timeBetween.Days * 1440) + (timeBetween.Hours * 60) + timeBetween.Minutes dynamic widthBetween = (shownHeaderList[1].StartLocation - shownHeaderList[0].StartLocation); decimal perMinute = widthBetween / minutesBetween; // Draws each bar foreach (ChartBarDate bar in bars) { index = bar.RowIndex; int startLocation = 0; int width = 0; int startMinutes = 0; // Number of minutes from start of the gantt chart TimeSpan startTimeSpan = default(TimeSpan); int lengthMinutes = 0; // Number of minutes from bar start to bar end TimeSpan lengthTimeSpan = default(TimeSpan); int scrollPos = 0; if (ignoreScrollAndMousePosition == false) { scrollPos = scrollPosition; } // Calculates where the bar should be located startTimeSpan = bar.StartValue - FromDate; startMinutes = (startTimeSpan.Days * 1440) + (startTimeSpan.Hours * 60) + startTimeSpan.Minutes; startLocation = Convert.ToInt32(perMinute * startMinutes); System.DateTime endValue = bar.EndValue; if (endValue == null) { endValue = System.DateTime.Now; } lengthTimeSpan = endValue - bar.StartValue; lengthMinutes = (lengthTimeSpan.Days * 1440) + (lengthTimeSpan.Hours * 60) + lengthTimeSpan.Minutes; width = Convert.ToInt32(perMinute * lengthMinutes); int a = barStartLeft + startLocation; int b = barStartTop + (barHeight * (index - scrollPos)) + (barSpace * (index - scrollPos)) + 2; int c = width; int d = barHeight; if (c == 0) c = 1; // Stops a bar from going into the row-text area if (a - barStartLeft < 0) { a = barStartLeft; } System.Drawing.Color color = default(System.Drawing.Color); // If mouse is over bar, set the color to be hovercolor if (MouseOverRowText == bar.Text & bar.StartValue <= _mouseOverColumnValue & bar.EndValue >= _mouseOverColumnValue) { color = bar.HoverColor; } else { color = bar.Color; } // Set the location for the graphics bar.TopLocation.Left = new Point(a, b); bar.TopLocation.Right = new Point(a + c, b); bar.BottomLocation.Left = new Point(a, b + d); bar.BottomLocation.Right = new Point(a, b + d); LinearGradientBrush obBrush = null; Rectangle obRect = new Rectangle(a, b, c, d); if (bar.StartValue != null & endValue != null) { if ((index >= scrollPos & index < barsViewable + scrollPos) | ignoreScrollAndMousePosition == true) { // Makes the bar gradient obBrush = new LinearGradientBrush(obRect, color, Color.Gray, LinearGradientMode.Vertical); // Draws the bar grfx.DrawRectangle(Pens.Black, obRect); grfx.FillRectangle(obBrush, obRect); // Draws the rowtext grfx.DrawString(bar.Text, rowTextFont, Brushes.Black, 0, barStartTop + (barHeight * (index - scrollPos)) + (barSpace * (index - scrollPos))); obBrush = null; //obRect = null; //obRect.TryDispose(); obBrush = null; } } //color = null; //color.TryDispose(); } } /// /// Draws the vertical lines /// /// /// public void DrawNetVertical(Graphics grfx) { if (shownHeaderList == null) return; if (shownHeaderList.Count == 0) return; int index = 0; int availableWidth = this.Width - 10 - barStartLeft - barStartRight; Header lastHeader = null; foreach (Header header in shownHeaderList) { int headerLocationY = 0; if (lastHeader == null) { headerLocationY = 0; } else if (header.Time.Hour < lastHeader.Time.Hour) { headerLocationY = 0; } else { headerLocationY = headerTimeStartTop; } grfx.DrawLine(Pens.Bisque, barStartLeft + (index * widthPerItem), headerLocationY, barStartLeft + (index * widthPerItem), lastLineStop); index += 1; lastHeader = header; } grfx.DrawLine(lineColor, barStartLeft + (index * widthPerItem), headerTimeStartTop, barStartLeft + (index * widthPerItem), lastLineStop); } /// /// Draws the horizontal lines /// /// /// public void DrawNetHorizontal(Graphics grfx) { if (shownHeaderList == null) return; if (shownHeaderList.Count == 0) return; int index = 0; int width = (widthPerItem * shownHeaderList.Count) + barStartLeft; // Last used index. Hopefully nobody will make a row named QQQ :o) for (index = 0; index <= GetIndexChartBar("QQQQQQ"); index++) { foreach (ChartBarDate bar in bars) { grfx.DrawLine(lineColor, 0, barStartTop + (barHeight * index) + (barSpace * index), width, barStartTop + (barHeight * index) + (barSpace * index)); } } lastLineStop = barStartTop + (barHeight * (index - 1)) + (barSpace * (index - 1)); } // This is the position (in pixels, from top) of the last line. Used for drawing lines private int lastLineStop = 0; #endregion #region "Header list" /// /// Gets the full header list, consisting of hours between the two dates set /// /// /// private List
GetFullHeaderList() { List
result = new List
(); System.DateTime newFromTime = new System.DateTime(FromDate.Year, FromDate.Month, FromDate.Day); string item = null; TimeSpan interval = ToDate - FromDate; if (interval.TotalDays < 1) { var _with1 = newFromTime; newFromTime = _with1.AddHours(FromDate.Hour); if (headerFromDate.Minute < 59 & headerFromDate.Minute > 29) { newFromTime = _with1.AddMinutes(30); } else { newFromTime = _with1.AddMinutes(0); } while (newFromTime <= ToDate) { item = newFromTime.Hour + ":"; if (newFromTime.Minute < 10) { item += "0" + newFromTime.Minute; } else { item += "" + newFromTime.Minute; } Header header = new Header(); header.HeaderText = item; header.HeaderTextInsteadOfTime = ""; header.Time = new System.DateTime(newFromTime.Year, newFromTime.Month, newFromTime.Day, newFromTime.Hour, newFromTime.Minute, 0); result.Add(header); newFromTime = newFromTime.AddMinutes(5); // The minimum interval of time between the headers } } else if (interval.TotalDays < 60) { while (newFromTime <= ToDate) { Header header = new Header(); header.HeaderText = ""; header.HeaderTextInsteadOfTime = ""; header.Time = new System.DateTime(newFromTime.Year, newFromTime.Month, newFromTime.Day, 0, 0, 0); result.Add(header); newFromTime = newFromTime.AddDays(1); // The minimum interval of time between the headers } } else { while (newFromTime <= ToDate) { Header header = new Header(); header.HeaderText = ""; header.Time = new System.DateTime(newFromTime.Year, newFromTime.Month, newFromTime.Day, 0, 0, 0); header.HeaderTextInsteadOfTime = newFromTime.ToString("MMM"); result.Add(header); newFromTime = newFromTime.AddMonths(1); // The minimum interval of time between the headers } } return result; } #endregion #region "Mouse Move" /// /// Finds the current row and column based on mouse position /// /// /// /// private void GanttChart_MouseMove(System.Object sender, System.Windows.Forms.MouseEventArgs e) { if (shownHeaderList == null) return; if (shownHeaderList.Count == 0) return; if (e.Button != System.Windows.Forms.MouseButtons.Left) { mouseHoverPart = MouseOverPart.Empty; // If bar has changed manually, but left mouse button is no longer pressed the BarChanged event will be raised if (AllowManualEditBar == true) { if (barIsChanging >= 0) { if (BarChanged != null) { BarChanged(this, bars[barIsChanging].Value); } barIsChanging = -1; } } } mouseHoverBarIndex = -1; Point LocalMousePosition = default(Point); LocalMousePosition = this.PointToClient(Cursor.Position); // Finds pixels per minute TimeSpan timeBetween = shownHeaderList[1].Time - shownHeaderList[0].Time; int minutesBetween = (timeBetween.Days * 1440) + (timeBetween.Hours * 60) + timeBetween.Minutes; dynamic widthBetween = (shownHeaderList[1].StartLocation - shownHeaderList[0].StartLocation); decimal perMinute = widthBetween / minutesBetween; // Finds the time at mousepointer int minutesAtCursor = 0; if (LocalMousePosition.X > barStartLeft && perMinute > 0) { minutesAtCursor = Convert.ToInt32((LocalMousePosition.X - barStartLeft) / perMinute); _mouseOverColumnValue = FromDate.AddMinutes(minutesAtCursor); } else { //_mouseOverColumnValue.TryDispose(); } // Finds the row at mousepointer string rowText = ""; object rowValue = null; string columnText = ""; // Tests to see if the mouse pointer is hovering above the scrollbar bool scrollBarStatusChanged = false; // Tests to see if the mouse is hovering over the scroll-area bottom-arrow if (LocalMousePosition.X > BottomPart.Left & LocalMousePosition.Y < BottomPart.Right & LocalMousePosition.Y < BottomPart.Bottom & LocalMousePosition.Y > BottomPart.Top) { if (mouseOverBottomPart == false) { scrollBarStatusChanged = true; } mouseOverBottomPart = true; } else { if (mouseOverBottomPart == false) { scrollBarStatusChanged = true; } mouseOverBottomPart = false; } // Tests to see if the mouse is hovering over the scroll-area top-arrow if (LocalMousePosition.X > topPart.Left & LocalMousePosition.Y < topPart.Right & LocalMousePosition.Y < topPart.Bottom & LocalMousePosition.Y > topPart.Top) { if (mouseOverTopPart == false) { scrollBarStatusChanged = true; } mouseOverTopPart = true; } else { if (mouseOverTopPart == false) { scrollBarStatusChanged = true; } mouseOverTopPart = false; } // Tests to see if the mouse is hovering over the scroll if (LocalMousePosition.X > scroll.Left & LocalMousePosition.Y < scroll.Right & LocalMousePosition.Y < scroll.Bottom & LocalMousePosition.Y > scroll.Top) { if (mouseOverScrollBar == false) { scrollBarStatusChanged = true; } mouseOverScrollBar = true; mouseOverScrollBarArea = true; } else { if (mouseOverScrollBar == false) { scrollBarStatusChanged = true; } mouseOverScrollBar = false; mouseOverScrollBarArea = false; } // 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) if (mouseOverScrollBarArea == false) { if (LocalMousePosition.X > scrollBarArea.Left & LocalMousePosition.Y < scrollBarArea.Right & LocalMousePosition.Y < scrollBarArea.Bottom & LocalMousePosition.Y > scrollBarArea.Top) { mouseOverScrollBarArea = true; } } // Tests to see if the mouse pointer is hovering above a bar int index = 0; foreach (ChartBarDate bar in bars) { // If the bar is set to be hidden from mouse move, the current bar will be ignored if (bar.HideFromMouseMove == false) { if (bar.EndValue == null) { bar.EndValue = System.DateTime.Now; } // Mouse pointer needs to be inside the X and Y positions of the bar if (LocalMousePosition.Y > bar.TopLocation.Left.Y & LocalMousePosition.Y < bar.BottomLocation.Left.Y) { if (LocalMousePosition.X > bar.TopLocation.Left.X & LocalMousePosition.X < bar.TopLocation.Right.X) { // If the current bar is the one where the mouse is above, the rowText and rowValue needs to be set correctly rowText = bar.Text; rowValue = bar.Value; mouseHoverBarIndex = index; if (mouseHoverPart != MouseOverPart.BarLeftSide & mouseHoverPart != MouseOverPart.BarRightSide) { mouseHoverPart = MouseOverPart.Bar; } } // If mouse pointer is near the edges of the bar it will open up for editing the bar if (AllowManualEditBar == true) { int areaSize = 5; if (e.Button == System.Windows.Forms.MouseButtons.Left) { areaSize = 50; } if (LocalMousePosition.X > bar.TopLocation.Left.X - areaSize & LocalMousePosition.X < bar.TopLocation.Left.X + areaSize & mouseHoverPart != MouseOverPart.BarRightSide) { this.Cursor = Cursors.VSplit; mouseHoverPart = MouseOverPart.BarLeftSide; mouseHoverBarIndex = index; } else if (LocalMousePosition.X > bar.TopLocation.Right.X - areaSize & LocalMousePosition.X < bar.TopLocation.Right.X + areaSize & mouseHoverPart != MouseOverPart.BarLeftSide) { this.Cursor = Cursors.VSplit; mouseHoverPart = MouseOverPart.BarRightSide; mouseHoverBarIndex = index; } else { this.Cursor = Cursors.Default; } } } } index += 1; } // Sets the mouseover row value and text _mouseOverRowText = rowText; _mouseOverRowValue = rowValue; if (e.Button == System.Windows.Forms.MouseButtons.Left) { if (MouseDragged != null) { MouseDragged(sender, e); } } else { // A simple test to see if the mousemovement has caused any changes to how it should be displayed // It only redraws if mouse moves from a bar to blank area or from blank area to a bar // This increases performance compared to having a redraw every time a mouse moves if ((_mouseOverRowValue == null & (rowValue != null)) | ((_mouseOverRowValue != null) & rowValue == null) | scrollBarStatusChanged == true) { PaintChart(); } } } /// /// Mouse leave event /// /// /// /// private void GanttChart_MouseLeave(System.Object sender, System.EventArgs e) { _mouseOverRowText = null; _mouseOverRowValue = null; mouseHoverPart = MouseOverPart.Empty; PaintChart(); } /// /// Mouse drag event /// /// /// /// public void GanttChart_MouseDragged(object sender, System.Windows.Forms.MouseEventArgs e) { if (mouseOverScrollBarArea == true) { ScrollPositionY = e.Location.Y; } if (AllowManualEditBar == true) { if (mouseHoverBarIndex > -1) { if (mouseHoverPart == MouseOverPart.BarLeftSide) { barIsChanging = mouseHoverBarIndex; bars[mouseHoverBarIndex].StartValue = _mouseOverColumnValue; PaintChart(); } else if (mouseHoverPart == MouseOverPart.BarRightSide) { barIsChanging = mouseHoverBarIndex; bars[mouseHoverBarIndex].EndValue = _mouseOverColumnValue; PaintChart(); } } } } #endregion #region "ToolTipText" private List _toolTipText = new List(); private string _toolTipTextTitle = ""; private Point MyPoint = new Point(0, 0); /// /// The title to draw /// /// /// /// public string ToolTipTextTitle { get { return _toolTipTextTitle; } set { _toolTipTextTitle = value; } } /// /// Gets or sets the ToolTipText lines /// /// /// /// Don not use the add function directly on this, use ToolTipText = value public List ToolTipText { get { if (_toolTipText == null) _toolTipText = new List(); return _toolTipText; } set { _toolTipText = value; Point LocalMousePosition = default(Point); LocalMousePosition = this.PointToClient(Cursor.Position); if (LocalMousePosition == MyPoint) return; MyPoint = LocalMousePosition; ToolTip.SetToolTip(this, "."); } } /// /// Draws the ToolTip window /// /// /// /// private void ToolTipText_Draw(System.Object sender, System.Windows.Forms.DrawToolTipEventArgs e) { if (ToolTipText == null) { ToolTipText = new List(); return; } if (ToolTipText.Count == 0) { return; } else if (ToolTipText[0].Length == 0) { return; } int x = 0; int y = 0; e.Graphics.FillRectangle(Brushes.AntiqueWhite, e.Bounds); e.DrawBorder(); int titleHeight = 14; int fontHeight = 12; // Draws the line just below the title e.Graphics.DrawLine(Pens.Black, 0, titleHeight, e.Bounds.Width, titleHeight); int lines = 1; string text = ToolTipTextTitle; // Draws the title using (Font font = new Font(e.Font, FontStyle.Bold)) { x = Convert.ToInt32((e.Bounds.Width - e.Graphics.MeasureString(text, font).Width) / 2); y = Convert.ToInt32((titleHeight - e.Graphics.MeasureString(text, font).Height) / 2); e.Graphics.DrawString(text, font, Brushes.Black, x, y); } // Draws the lines for (int i = 0; i < ToolTipText.Count; i++) { Font font = new Font(e.Font, FontStyle.Regular); if (ToolTipText[i].Contains("[b]")) { font = new Font(font.FontFamily, font.Size, FontStyle.Bold, font.Unit); ToolTipText[i] = ToolTipText[i].Replace("[b]", ""); } using (font) { x = 5; y = Convert.ToInt32((titleHeight - fontHeight - e.Graphics.MeasureString(ToolTipText[i], font).Height) / 2 + 10 + (lines * 14)); e.Graphics.DrawString(ToolTipText[i], font, Brushes.Black, x, y); } lines += 1; } //foreach (string str in ToolTipText) //{ // Font font = new Font(e.Font, FontStyle.Regular); // if (str.Contains("[b]")) // { // font = new Font(font.FontFamily, font.Size, FontStyle.Bold, font.Unit); // str = str.Replace("[b]", ""); // } // using (font) // { // x = 5; // y = Convert.ToInt32((titleHeight - fontHeight - e.Graphics.MeasureString(str, font).Height) / 2 + 10 + (lines * 14)); // e.Graphics.DrawString(str, font, Brushes.Black, x, y); // } // lines += 1; //} } /// /// Automatically resizes the ToolTip window /// /// /// /// private void ToolTipText_Popup(System.Object sender, System.Windows.Forms.PopupEventArgs e) { if (ToolTipText == null) { ToolTipText = new List(); } if (ToolTipText.Count == 0) { e.ToolTipSize = new Size(0, 0); return; } else if (ToolTipText[0].Length == 0) { e.ToolTipSize = new Size(0, 0); return; } // resizes the ToolTip window int height = 18 + (ToolTipText.Count * 15); e.ToolTipSize = new Size(200, height); } #endregion #region "ChartBar" private class ChartBarDate { internal class Location { private Point _right = new Point(0, 0); private Point _left = new Point(0, 0); public Point Right { get { return _right; } set { _right = value; } } public Point Left { get { return _left; } set { _left = value; } } } private System.DateTime _startValue; private System.DateTime _endValue; private Color _color; private Color _hoverColor; private string _text; private object _value; private int _rowIndex; private Location _topLocation = new Location(); private Location _bottomLocation = new Location(); private bool _hideFromMouseMove = false; public System.DateTime StartValue { get { return _startValue; } set { _startValue = value; } } public System.DateTime EndValue { get { return _endValue; } set { _endValue = value; } } public Color Color { get { return _color; } set { _color = value; } } public Color HoverColor { get { return _hoverColor; } set { _hoverColor = value; } } public string Text { get { return _text; } set { _text = value; } } public object Value { get { return _value; } set { _value = value; } } public int RowIndex { get { return _rowIndex; } set { _rowIndex = value; } } public bool HideFromMouseMove { get { return _hideFromMouseMove; } set { _hideFromMouseMove = value; } } internal Location TopLocation { get { return _topLocation; } set { _topLocation = value; } } internal Location BottomLocation { get { return _bottomLocation; } set { _bottomLocation = value; } } } #endregion #region "Headers" private class Header { private string _headerText; private int _startLocation; private string _headerTextInsteadOfTime = ""; private System.DateTime _time; public string HeaderText { get { return _headerText; } set { _headerText = value; } } public int StartLocation { get { return _startLocation; } set { _startLocation = value; } } /// /// If this string is larger than 0, this will be used instead of Time /// /// /// /// public string HeaderTextInsteadOfTime { get { return _headerTextInsteadOfTime; } set { _headerTextInsteadOfTime = value; } } /// /// Time to display /// /// /// /// public System.DateTime Time { get { return _time; } set { _time = value; } } } #endregion #region "Resize" /// /// On resize the Gantt Chart is redrawn /// /// /// protected override void OnResize(System.EventArgs e) { base.OnResize(e); scrollPosition = 0; // Used for when the Gantt Chart is saved as an image if (lastLineStop > 0) { objBmp = new Bitmap(this.Width - barStartRight, lastLineStop, System.Drawing.Imaging.PixelFormat.Format24bppRgb); objGraphics = Graphics.FromImage(objBmp); } PaintChart(); } #endregion #region "Scrollbar" private int barsViewable = -1; private int scrollPosition = 0; private Rectangle topPart; private Rectangle BottomPart; private Rectangle scroll; private Rectangle scrollBarArea; private bool mouseOverTopPart = false; private bool mouseOverBottomPart = false; private bool mouseOverScrollBar = false; private bool mouseOverScrollBarArea = false; /// /// Draws a scrollbar to the component, if there's a need for it /// /// /// private void DrawScrollBar(Graphics grfx) { barsViewable = (this.Height - barStartTop) / (barHeight + barSpace); int barCount = GetIndexChartBar("QQQWWW"); if (barCount == 0) return; int maxHeight = this.Height - 30; decimal scrollHeight = (maxHeight / barCount) * barsViewable; // If the scroll area is filled there's no need to show the scrollbar if (scrollHeight >= maxHeight) return; decimal scrollSpeed = (maxHeight - scrollHeight) / (barCount - barsViewable); scrollBarArea = new Rectangle(this.Width - 20, 19, 12, maxHeight); scroll = new Rectangle(this.Width - 20, 19 + Convert.ToInt32((scrollPosition * scrollSpeed)), 12, Convert.ToInt32(scrollHeight)); topPart = new Rectangle(this.Width - 20, 10, 12, 8); BottomPart = new Rectangle(this.Width - 20, this.Height - 10, 12, 8); Brush colorTopPart = null; Brush colorBottomPart = null; Brush colorScroll = null; if (mouseOverTopPart == true) { colorTopPart = Brushes.Black; } else { colorTopPart = Brushes.Gray; } if (mouseOverBottomPart == true) { colorBottomPart = Brushes.Black; } else { colorBottomPart = Brushes.Gray; } if (mouseOverScrollBar == true) { colorScroll = new LinearGradientBrush(scroll, Color.Bisque, Color.Gray, LinearGradientMode.Horizontal); } else { colorScroll = new LinearGradientBrush(scroll, Color.White, Color.Gray, LinearGradientMode.Horizontal); } // Draws the top and bottom part of the scrollbar grfx.DrawRectangle(Pens.Black, topPart); grfx.FillRectangle(Brushes.LightGray, topPart); grfx.DrawRectangle(Pens.Black, BottomPart); grfx.FillRectangle(Brushes.LightGray, BottomPart); // Draws arrows PointF[] points = new PointF[3]; points[0] = new PointF(topPart.Left, topPart.Bottom - 1); points[1] = new PointF(topPart.Right, topPart.Bottom - 1); points[2] = new PointF((topPart.Left + topPart.Right) / 2, topPart.Top + 1); grfx.FillPolygon(colorTopPart, points); points[0] = new PointF(BottomPart.Left, BottomPart.Top + 1); points[1] = new PointF(BottomPart.Right, BottomPart.Top + 1); points[2] = new PointF((BottomPart.Left + BottomPart.Right) / 2, BottomPart.Bottom - 1); grfx.FillPolygon(colorBottomPart, points); // Draws the scroll area grfx.DrawRectangle(Pens.Black, scrollBarArea); grfx.FillRectangle(Brushes.DarkGray, scrollBarArea); // Draws the actual scrollbar grfx.DrawRectangle(Pens.Black, scroll); grfx.FillRectangle(colorScroll, scroll); } /// /// The Y-position of the center of the scroll /// /// /// /// private int ScrollPositionY { get { if (scroll == null) return -1; return ((scroll.Height / 2) + scroll.Location.Y) + 19; } set { int barCount = GetIndexChartBar("QQQWWW"); int maxHeight = this.Height - 30; decimal scrollHeight = (maxHeight / barCount) * barsViewable; decimal scrollSpeed = (maxHeight - scrollHeight) / (barCount - barsViewable); int index = 0; dynamic distanceFromLastPosition = 9999; // Tests to see what scrollposition is the closest to the set position while (index < barCount) { int newPositionTemp = Convert.ToInt32((index * scrollSpeed) + (scrollHeight / 2) + (30 / 2)); dynamic distanceFromCurrentPosition = newPositionTemp - value; if (distanceFromLastPosition < 0) { if (distanceFromCurrentPosition < distanceFromLastPosition) { scrollPosition = index - 1; PaintChart(); return; } } else { if (distanceFromCurrentPosition > distanceFromLastPosition) { scrollPosition = index - 1; // A precaution to make sure the scroll bar doesn't go too far down if (scrollPosition + barsViewable > GetIndexChartBar("QQQWWW")) { scrollPosition = GetIndexChartBar("QQQWWW") - barsViewable; } PaintChart(); return; } } distanceFromLastPosition = distanceFromCurrentPosition; index += 1; } } } /// /// Scrolls one row up /// /// public void ScrollOneup() { if (scrollPosition == 0) return; scrollPosition -= 1; PaintChart(); } /// /// Scrolls one row down /// /// public void ScrollOneDown() { if (scrollPosition + barsViewable >= GetIndexChartBar("QQQWWW")) return; scrollPosition += 1; PaintChart(); } /// /// If the user clicks on the scrollbar, scrolling functions will be called /// /// /// /// private void GanttChart_Click(System.Object sender, System.Windows.Forms.MouseEventArgs e) { if (e.Button == System.Windows.Forms.MouseButtons.Left) { if (mouseOverBottomPart == true) { ScrollOneDown(); } else if (mouseOverTopPart == true) { ScrollOneup(); } } } /// /// When mousewheel is used, the scrollbar will scroll /// /// /// /// private void GanttChart_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e) { if (e.Delta > 0) { ScrollOneup(); } else { ScrollOneDown(); } } #endregion #region "Save" /// /// Saves the GanttChart to specified image file /// /// /// public void SaveImage(string filePath) { objGraphics.SmoothingMode = SmoothingMode.HighSpeed; objGraphics.Clear(this.BackColor); if (headerFromDate == null | headerToDate == null) return; DrawHeader(objGraphics, null); DrawNetHorizontal(objGraphics); DrawNetVertical(objGraphics); DrawBars(objGraphics, true); objBmp.Save(filePath); } #endregion private enum MouseOverPart { Empty, Bar, BarLeftSide, BarRightSide } }