// -----------------------------------------------------------------------
//
// 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
}
}