Files
Winforms-Calendar/WindowsFormsCalendar/Renderers/CalendarRenderer.cs
2019-04-23 12:29:22 -07:00

1974 lines
69 KiB
C#

/*
Copyright 2012 Justin LeCheminant
This file is part of WindowsFormsCalendar.
indowsFormsCalendar is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
indowsFormsCalendar is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with indowsFormsCalendar. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace WindowsFormsCalendar
{
/// <summary>
/// Base class that renders visual elements of Calendar control
/// </summary>
public class CalendarRenderer
{
#region Static
/// <summary>
/// Comparison delegate to sort items
/// </summary>
/// <param name="item1"></param>
/// <param name="item2"></param>
/// <returns></returns>
private static int CompareItems(CalendarItem item1, CalendarItem item2)
{
return item1.StartDate.CompareTo(item2.StartDate) * -1;
}
/// <summary>
/// Comparison delegate to sort units
/// </summary>
/// <param name="item1"></param>
/// <param name="item2"></param>
/// <returns></returns>
private static int CompareUnits(CalendarTimeScaleUnit item1, CalendarTimeScaleUnit item2)
{
return item1.Date.CompareTo(item2.Date);
}
/// <summary>
/// Compares both <see cref="CalendarDayTop"/> items by Date
/// </summary>
/// <param name="top1"></param>
/// <param name="top2"></param>
/// <returns></returns>
private static int CompareTops(CalendarDayTop top1, CalendarDayTop top2)
{
return top1.Date.CompareTo(top2.Date);
}
/// <summary>
/// Creates a rectangle with rounded corners
/// </summary>
/// <param name="r"></param>
/// <param name="radius"></param>
/// <returns></returns>
public static GraphicsPath RoundRectangle(Rectangle r, int radius)
{
return RoundRectangle(r, radius, Corners.All);
}
/// <summary>
/// Creates a rectangle with the specified corners rounded
/// </summary>
/// <param name="r"></param>
/// <param name="radius"></param>
/// <param name="corners"></param>
/// <returns></returns>
public static GraphicsPath RoundRectangle(Rectangle r, int radius, Corners corners)
{
GraphicsPath path = new GraphicsPath(); if (r.Width <= 0 || r.Height <= 0) return path;
int d = radius * 2;
int nw = (corners & Corners.NorthWest) == Corners.NorthWest ? d : 0;
int ne = (corners & Corners.NorthEast) == Corners.NorthEast ? d : 0;
int se = (corners & Corners.SouthEast) == Corners.SouthEast ? d : 0;
int sw = (corners & Corners.SouthWest) == Corners.SouthWest ? d : 0;
path.AddLine(r.Left + nw, r.Top, r.Right - ne, r.Top);
if (ne > 0)
{
path.AddArc(Rectangle.FromLTRB(r.Right - ne, r.Top, r.Right, r.Top + ne),
-90, 90);
}
path.AddLine(r.Right, r.Top + ne, r.Right, r.Bottom - se);
if (se > 0)
{
path.AddArc(Rectangle.FromLTRB(r.Right - se, r.Bottom - se, r.Right, r.Bottom),
0, 90);
}
path.AddLine(r.Right - se, r.Bottom, r.Left + sw, r.Bottom);
if (sw > 0)
{
path.AddArc(Rectangle.FromLTRB(r.Left, r.Bottom - sw, r.Left + sw, r.Bottom),
90, 90);
}
path.AddLine(r.Left, r.Bottom - sw, r.Left, r.Top + nw);
if (nw > 0)
{
path.AddArc(Rectangle.FromLTRB(r.Left, r.Top, r.Left + nw, r.Top + nw),
180, 90);
}
path.CloseFigure();
return path;
}
#endregion
#region Events
#endregion
#region Fields
private int _allDayItemsPadding;
private int _standardItemHeight;
private int _dayTopHeight;
private int _dayTopMinHeight;
private Calendar _calendar;
private Rectangle[] _dayNameHeaderColumns;
private int _dayHeaderHeight;
private int _dayNameHeadersHeight;
private int _itemInvalidateMargin;
private int _itemsPadding;
private Padding _itemTextMargin;
private int _itemShadowPadding;
private int _itemRoundness;
private Rectangle _timeScaleBounds;
private int _timeScaleUnitHeight;
private int _timeScaleWidth;
private int _weekHeaderWidth;
#endregion
#region Properties
/// <summary>
/// Gets or sets the padding of the items that goes on the top part of the days,
/// when in <see cref="CalendarDaysMode.Expanded"/>
/// </summary>
/// <value>
/// The day top items padding.
/// </value>
public int DayTopItemsPadding
{
get { return _allDayItemsPadding; }
set { _allDayItemsPadding = value; }
}
/// <summary>
/// Gets the current height of the all day items area
/// </summary>
/// <value>
/// The height of the day top.
/// </value>
public virtual int DayTopHeight
{
get
{
if( _dayTopHeight == 0 )
{
_dayTopHeight = DayTopMinHeight;
}
return _dayTopHeight;
}
set
{
_dayTopHeight = value;
}
}
/// <summary>
/// Gets the height of items on day tops
/// </summary>
/// <value>
/// The height of the standard item.
/// </value>
public virtual int StandardItemHeight
{
get
{
if( _standardItemHeight == 0 )
{
_standardItemHeight = TextRenderer.MeasureText( "Ag", Calendar.Font ).Height;
}
return _standardItemHeight + ItemTextMargin.Vertical;
}
}
/// <summary>
/// Gets the minimum height for day tops
/// </summary>
/// <value>
/// The height of the day top min.
/// </value>
public virtual int DayTopMinHeight
{
get
{
if( _dayTopMinHeight == 0 )
{
_dayTopMinHeight = TextRenderer.MeasureText( "Ag", Calendar.Font ).Height + 16;
}
return _dayTopMinHeight;
}
}
/// <summary>
/// Gets the <see cref="Calendar"/> this renderer belongs to
/// </summary>
public Calendar Calendar
{
get { return _calendar; }
}
/// <summary>
/// Gets the bounds for day name headers
/// </summary>
public Rectangle[] DayNameHeaderColumns
{
get { return _dayNameHeaderColumns; }
}
/// <summary>
/// Gets the height of the header of days
/// </summary>
/// <value>
/// The height of the day header.
/// </value>
public virtual int DayHeaderHeight
{
get
{
if( _dayHeaderHeight == 0 )
{
_dayHeaderHeight = TextRenderer.MeasureText( "Ag", Calendar.Font ).Height + 4;
}
return _dayHeaderHeight;
}
}
/// <summary>
/// Gets a value indicating if the day names headers are visible (e.g. Monday, Tuesday, Wednesday ...)
/// </summary>
/// <value>
/// <c>true</c> if [day name headers visible]; otherwise, <c>false</c>.
/// </value>
public bool DayNameHeadersVisible
{
get { return Calendar.DaysMode == CalendarDaysMode.Short; }
}
/// <summary>
/// Gets the height of the day name headers
/// </summary>
/// <value>
/// The height of the day name headers.
/// </value>
public virtual int DayNameHeadersHeight
{
get
{
if( _dayNameHeadersHeight == 0 )
{
_dayNameHeadersHeight = DayHeaderHeight;
}
return _dayNameHeadersHeight;
}
}
/// <summary>
/// Gets the margin of the text in the items
/// </summary>
/// <value>
/// The item text margin.
/// </value>
public virtual Padding ItemTextMargin
{
get { return _itemTextMargin; }
set
{
_itemTextMargin = value;
}
}
/// <summary>
/// Gets or sets the amount of pixels that the item's shadow is dropped
/// </summary>
/// <value>
/// The item shadow padding.
/// </value>
public virtual int ItemShadowPadding
{
get { return _itemShadowPadding; }
set { _itemShadowPadding = value; }
}
/// <summary>
/// Gets or sets the extra margin for invalidating and redrawing items
/// </summary>
/// <value>
/// The item invalidate margin.
/// </value>
public int ItemInvalidateMargin
{
get { return _itemInvalidateMargin; }
set { _itemInvalidateMargin = value; }
}
/// <summary>
/// Gets or sets the padding of items on expanded mode
/// </summary>
/// <value>
/// The items padding.
/// </value>
public int ItemsPadding
{
get { return _itemsPadding; }
set { _itemsPadding = value; }
}
/// <summary>
/// Gets or sets the roundness of the item
/// </summary>
/// <value>
/// The item roundness.
/// </value>
public int ItemRoundness
{
get { return _itemRoundness; }
set { _itemRoundness = value; }
}
/// <summary>
/// Gets or sets the bounds of the timescale
/// </summary>
/// <value>
/// The time scale bounds.
/// </value>
public Rectangle TimeScaleBounds
{
get { return _timeScaleBounds; }
set { _timeScaleBounds = value; }
}
/// <summary>
/// Gets the height of the time scale unit.
/// </summary>
/// <value>
/// The height of the time scale unit.
/// </value>
public virtual int TimeScaleUnitHeight
{
get
{
if( _timeScaleUnitHeight == 0 )
{
_timeScaleUnitHeight = TextRenderer.MeasureText( "Ag", Calendar.Font ).Height + 10;
}
return _timeScaleUnitHeight;
}
}
/// <summary>
/// Gets a value indicating whether [time scale visible].
/// </summary>
/// <value>
/// <c>true</c> if [time scale visible]; otherwise, <c>false</c>.
/// </value>
public bool TimeScaleVisible
{
get { return Calendar.DaysMode == CalendarDaysMode.Expanded; }
}
/// <summary>
/// Gets the width of the timescale
/// </summary>
/// <value>
/// The width of the time scale.
/// </value>
public virtual int TimeScaleWidth
{
get
{
if( _timeScaleWidth == 0 )
{
_timeScaleWidth = 60;
}
return _timeScaleWidth;
}
}
/// <summary>
/// Gets the width of the week header.
/// </summary>
/// <value>
/// The width of the week header.
/// </value>
public virtual int WeekHeaderWidth
{
get
{
if( _weekHeaderWidth == 0 )
{
_weekHeaderWidth = TextRenderer.MeasureText( "Ag", Calendar.Font ).Height + 4;
}
return _weekHeaderWidth;
}
}
#endregion
/// <summary>
/// Creates a new renderer for the specified calendar
/// </summary>
/// <param name="calendar"></param>
public CalendarRenderer(Calendar calendar)
{
if (calendar == null)
{
throw new ArgumentNullException("calendar");
}
_calendar = calendar;
_allDayItemsPadding = 5;
_itemsPadding = 5;
_itemTextMargin = new Padding(3);
_itemShadowPadding = 4;
_itemInvalidateMargin = 0;
}
#region Public Methods
/// <summary>
/// Gets the exact Y coordinate that corresponds to the specified time.
/// This only works when in <c>Expanded</c> mode.
/// </summary>
/// <param name="time">Time of day to get Y coordinate</param>
/// <returns>
/// Y coordinate corresponding to the specified <para>time</para>
/// </returns>
/// <exception cref="InvalidOperationException">When calendar is not in <c>Expaned</c> mode.</exception>
public int GetTimeY(TimeSpan time)
{
if (Calendar.DaysMode != CalendarDaysMode.Expanded)
throw new InvalidOperationException("Can't measure Time's Y when calendar isn't in Expanded mode");
//If no days, no Y
if (Calendar.Days == null || Calendar.Days.Length == 0)
return 0;
CalendarDay fisrtDay = Calendar.Days[0];
CalendarTimeScaleUnit firstUnit = fisrtDay.TimeUnits[0];
double duration = Convert.ToDouble(firstUnit.Duration.TotalMinutes);
double totalmins = time.TotalMinutes;
int unitIndex = Convert.ToInt32(Math.Floor(totalmins / duration));
double module = Convert.ToInt32(Math.Floor(totalmins % duration));
CalendarTimeScaleUnit unit = Calendar.Days[0].TimeUnits[unitIndex];
int minuteHeight = Convert.ToInt32(Convert.ToDouble(unit.Bounds.Height) / duration);
return unit.Bounds.Top + minuteHeight * Convert.ToInt32(module);
}
/// <summary>
/// Creates a rectangle with item roundess
/// </summary>
/// <param name="evtData">The instance containing the event data.</param>
/// <param name="bounds">The bounds.</param>
/// <returns></returns>
public GraphicsPath ItemRectangle(CalendarRendererItemBoundsEventArgs evtData, Rectangle bounds)
{
int pointerPadding = 5;
if ((evtData.Item.Bounds.Top != evtData.Item.MinuteStartTop ||
evtData.Item.Bounds.Bottom != evtData.Item.MinuteEndTop) &&
(evtData.Item.MinuteEndTop != 0 && evtData.Item.MinuteStartTop != 0) &&
! evtData.Item.IsOnDayTop && evtData.Calendar.DaysMode == CalendarDaysMode.Expanded)
{
/*
* Trace pointed item
*
* C--------------------D
* | |
* A---B |
* | |
* H---G |
* | |
* F--------------------E
*/
int sq = ItemRoundness * 2;
Point a = new Point(bounds.Left, evtData.Item.MinuteStartTop);
Point b = new Point(a.X + pointerPadding, a.Y);
Point c = new Point(b.X, bounds.Top);
Point d = new Point(bounds.Right, c.Y);
Point e = new Point(d.X, bounds.Bottom);
Point f = new Point(b.X, e.Y);
Point g = new Point(b.X, evtData.Item.MinuteEndTop);
Point h = new Point(a.X, g.Y);
GraphicsPath path = new GraphicsPath();
path.AddLine(a, b);
path.AddLine(b, c);
path.AddLine(c, new Point(d.X - sq, d.Y));
path.AddArc(new Rectangle(d.X - sq, d.Y, sq, sq), -90, 90);
path.AddLine(new Point(d.X, d.Y + sq), new Point(d.X, e.Y - sq));
path.AddArc(new Rectangle(e.X - sq, e.Y - sq, sq, sq), 0, 90);
path.AddLine(new Point(e.X - sq, e.Y), f);
path.AddLine(f, g);
path.AddLine(g, h);
path.AddLine(h, a);
path.CloseFigure();
return path;
}
else
{
Corners crns = Corners.None;
if (evtData.IsFirst)
{
crns |= Corners.West;
}
if (evtData.IsLast)
{
crns |= Corners.East;
}
return RoundRectangle(bounds, ItemRoundness, crns);
}
}
/// <summary>
/// Fills the specified rectangle with item border roundness
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererItemBoundsEventArgs"/> instance containing the event data.</param>
/// <param name="bounds">The bounds.</param>
/// <param name="north">The north.</param>
/// <param name="south">The south.</param>
public void ItemFill(CalendarRendererItemBoundsEventArgs e, Rectangle bounds, Color north, Color south)
{
if (bounds.Width <= 0 || bounds.Height <= 0)
{
return;
}
using (GraphicsPath r = ItemRectangle(e, bounds))
{
using (LinearGradientBrush b = new LinearGradientBrush(bounds, north, south, 90))
{
e.Graphics.FillPath(b, r);
}
}
}
/// <summary>
/// Items the pattern.
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererItemBoundsEventArgs"/> instance containing the event data.</param>
/// <param name="bounds">The bounds.</param>
/// <param name="patternColor">Color of the pattern.</param>
public void ItemPattern(CalendarRendererItemBoundsEventArgs e, Rectangle bounds, Color patternColor)
{
if (bounds.Width <= 0 || bounds.Height <= 0)
{
return;
}
using (GraphicsPath r = ItemRectangle(e, bounds))
{
using (Brush b = new HatchBrush(e.Item.Pattern, patternColor, Color.Transparent))
{
e.Graphics.FillPath(b, r);
}
}
}
/// <summary>
/// Draws the specified rectangle with item border roundnesss
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererItemBoundsEventArgs"/> instance containing the event data.</param>
/// <param name="bounds">The bounds.</param>
/// <param name="color">The color.</param>
/// <param name="width">The width.</param>
public void ItemBorder(CalendarRendererItemBoundsEventArgs e, Rectangle bounds, Color color, float width)
{
using (GraphicsPath r = ItemRectangle(e, bounds))
{
using (Pen p = new Pen(color, width))
{
e.Graphics.DrawPath(p, r);
}
}
}
/// <summary>
/// Peform layout of elements and items of the calendar
/// </summary>
public void PerformLayout()
{
PerformLayout(true);
}
/// <summary>
/// Updates the bounds of graphical elements.
/// Optionally calls <see cref="PerformItemsLayout"/> to update bounds of items.
/// </summary>
/// <remarks>
/// This method is called every time the <see cref="Calendar"/> control is resized.
/// </remarks>
public void PerformLayout(bool performItemsLayout)
{
if (Calendar.Days == null) return;
int leftStart = 0;
int curLeft = 0;
int curTop = 0;
int dayWidth = 0;
int dayHeight = 0;
int scrollBarWidth = 20;
TimeScaleBounds = Rectangle.Empty;
if (Calendar.DaysMode == CalendarDaysMode.Expanded)
{
#region Expanded days
TimeScaleBounds = new Rectangle(0, 0, TimeScaleWidth, Calendar.ClientRectangle.Height);
curLeft = TimeScaleBounds.Right;
dayHeight = Calendar.ClientSize.Height - 1;
dayWidth = (Calendar.ClientSize.Width - TimeScaleBounds.Width - scrollBarWidth) / Calendar.Days.Length;
for (int i = 0; i < Calendar.Days.Length; i++)
{
CalendarDay day = Calendar.Days[i];
day.SetBounds(new Rectangle(curLeft, curTop, dayWidth, dayHeight));
day.DayTop.SetBounds(new Rectangle(curLeft, day.HeaderBounds.Bottom, dayWidth, DayTopHeight));
curLeft += dayWidth + 1;
//int k = 0;
int utop = day.BodyBounds.Top + Calendar.TimeUnitsOffset * TimeScaleUnitHeight;
for (int j = 0; j < day.TimeUnits.Length; j++)
{
CalendarTimeScaleUnit unit = day.TimeUnits[j];
if (Calendar.TimeUnitsOffset * -1 >= (j + 1))
{
unit.SetVisible(false);
}
else
{
unit.SetVisible(true);
//unit.SetBounds(new Rectangle(day.Bounds.Left, day.BodyBounds.Top + k++ * TimeScaleUnitHeight, day.Bounds.Width, TimeScaleUnitHeight));
}
unit.SetBounds(new Rectangle(day.Bounds.Left, utop, day.Bounds.Width, TimeScaleUnitHeight));
utop += TimeScaleUnitHeight;
}
}
#endregion
}
else
{
#region Short days (Calendar View)
leftStart = WeekHeaderWidth;
curLeft = leftStart;
curTop = DayNameHeadersHeight;
dayWidth = (Calendar.ClientSize.Width - leftStart - scrollBarWidth) / 7;
dayHeight = (Calendar.ClientSize.Height - curTop) / (Calendar.Days.Length / 7) - 1;
_dayNameHeaderColumns = new Rectangle[7];
int j = 0;
for (int i = 0; i < Calendar.Days.Length; i++)
{
Calendar.Days[i].SetBounds(new Rectangle(curLeft, curTop, dayWidth, dayHeight));
curLeft += dayWidth + 1;
if ((i + 1) % 7 == 0)
{
curTop += dayHeight + 1;
curLeft = leftStart;
}
if (i < _dayNameHeaderColumns.Length)
{
_dayNameHeaderColumns[i] = new Rectangle(curLeft, 0, dayWidth, DayNameHeadersHeight);
}
if (Calendar.Days[i].Date.DayOfWeek == Calendar.FirstDayOfWeek)
{
Calendar.Weeks[j++].SetBounds(new Rectangle(0, curTop, Calendar.ClientSize.Width, dayHeight));
}
}
#endregion
}
if(performItemsLayout)
PerformItemsLayout();
}
/// <summary>
/// Updates the bounds of CalendarItems
/// </summary>
public void PerformItemsLayout()
{
if (Calendar.Days == null || Calendar.Items.Count == 0) return;
bool alldaychanged = false;
int offset = Math.Abs(Calendar.TimeUnitsOffset);
List<CalendarItem> itemsOnScene = new List<CalendarItem>();
foreach (CalendarDay day in Calendar.Days)
day.ContainedItems.Clear();
if (Calendar.DaysMode == CalendarDaysMode.Expanded)
{
#region Expanded mode algorithm
#region Assign units and initial coords
int maxItemsOnDayTop = 0;
foreach (CalendarItem item in Calendar.Items)
{
item.ClearBounds();
item.ClearPassings();
if (item.IsOnDayTop)
{
#region Among day tops
CalendarDay dayStart = item.DayStart;
CalendarDay dayEnd = item.DayEnd;
if (dayStart == null) dayStart = Calendar.Days[0];
if (dayEnd == null) dayEnd = Calendar.Days[Calendar.Days.Length - 1];
for (int i = dayStart.Index; i <= dayEnd.Index; i++)
{
item.AddTopPassing(Calendar.Days[i].DayTop);
Calendar.Days[i].DayTop.AddPassingItem(item);
}
item.SetBounds(Rectangle.FromLTRB(dayStart.DayTop.Bounds.Left, 0, dayEnd.DayTop.Bounds.Right, 1));
#endregion
}
else
{
#region Among time units
CalendarDay day = item.DayStart; if (day == null) continue;
double unitDurationMinutes = Convert.ToDouble((int)Calendar.TimeScale);
DateTime date1 = item.StartDate;
DateTime date2 = item.EndDate;
int indexStart = Convert.ToInt32(Math.Floor(date1.TimeOfDay.TotalMinutes / unitDurationMinutes));
int indexEnd = Convert.ToInt32(Math.Ceiling(date2.TimeOfDay.TotalMinutes / unitDurationMinutes));
for (int i = 0; i < day.TimeUnits.Length; i++)
{
if (i >= indexStart && i < indexEnd)
{
day.TimeUnits[i].AddPassingItem(item);
item.AddUnitPassing(day.TimeUnits[i]);
}
}
item.SetBounds(Rectangle.Empty);
itemsOnScene.Add(item);
#endregion
}
}
//Calendar.Items.Sort(CompareItems);
#endregion
#region Items on DayTops
foreach (CalendarDay day in Calendar.Days)
{
maxItemsOnDayTop = Math.Max(maxItemsOnDayTop, day.DayTop.PassingItems.Count);
}
int[,] tmatix = new int[Calendar.Days.Length, maxItemsOnDayTop];
if (tmatix.GetLength(1) > 0)
{
foreach (CalendarItem item in Calendar.Items)
{
if (!item.IsOnDayTop) continue;
item.TopsPassing.Sort(CompareTops);
int topStart = item.TopsPassing[0].Day.Index;
int topEnd = item.TopsPassing[item.TopsPassing.Count - 1].Day.Index;
PlaceInMatrix(ref tmatix, Calendar.Items.IndexOf(item) + 1, topStart, topEnd);
}
int dayTopsHeight = tmatix.GetLength(1) * StandardItemHeight + DayTopMinHeight;
if (DayTopHeight != dayTopsHeight)
{
DayTopHeight = dayTopsHeight;
alldaychanged = true;
}
int itemHeight = StandardItemHeight;//Convert.ToInt32(Math.Floor(Convert.ToSingle(DayTopHeight) / Convert.ToSingle(tmatix.GetLength(1))));
foreach (CalendarItem item in Calendar.Items)
{
if (!item.IsOnDayTop) continue;
int index = Calendar.Items.IndexOf(item);
int top, left;
FindInMatrix(tmatix, index + 1, out left, out top);
Rectangle r = item.Bounds;
r.Y = Calendar.Days[0].DayTop.Bounds.Top + top * itemHeight;
r.Height = itemHeight;
item.SetBounds(r);
item.FirstAndLastRectangleGapping();
}
}
if (alldaychanged)
PerformLayout(false);
#endregion
foreach (CalendarDay day in Calendar.Days)
{
#region Create groups
maxItemsOnDayTop = Math.Max(maxItemsOnDayTop, day.DayTop.PassingItems.Count);
List<List<CalendarItem>> groups = new List<List<CalendarItem>>();
List<CalendarItem> items = new List<CalendarItem>(day.ContainedItems);
while (items.Count > 0)
{
List<CalendarItem> group = new List<CalendarItem>();
CollectIntersectingGroup(items[0], items, group);
groups.Add(group);
foreach (CalendarItem item in group)
items.Remove(item);
}
#endregion
foreach (List<CalendarItem> group in groups)
{
#region Create group matrix
int maxConcurrent = 0;
int startIndex, endIndex;
GetGroupBoundUnits(group, out startIndex, out endIndex);
//Get the maximum concurrent items
for (int i = startIndex; i <= endIndex; i++) maxConcurrent = Math.Max(day.TimeUnits[i].PassingItems.Count, maxConcurrent);
int[,] matix = new int[maxConcurrent, endIndex - startIndex + 1];
foreach (CalendarItem item in group)
{
int x = 0;
item.UnitsPassing.Sort(CompareUnits);
int unitStart = item.UnitsPassing[0].Index - startIndex;
int unitEnd = unitStart + item.UnitsPassing.Count - 1;
bool xFound = false;
//if (startIndex + unitEnd < offset)
//{
// item.SetIsOnView(false);
// continue;
//}
//else
//{
// item.SetIsOnView(true);
//}
while (!xFound)
{
xFound = true;
for (int i = unitStart; i <= unitEnd; i++)
{
if (matix[x, i] != 0)
{
xFound = false;
break;
}
}
if (!xFound) x++;
}
for (int i = unitStart; i <= unitEnd; i++)
{
matix[x, i] = group.IndexOf(item) + 1;
}
}
#endregion
#region Expand Items
foreach (CalendarItem item in group)
{
int index = group.IndexOf(item);
int left, top;
int height = item.UnitsPassing.Count;
int width = 1;
FindInMatrix(matix, index + 1, out left, out top);
bool canExpand = left >= 0 && top >= 0;
while (canExpand)
{
for (int i = top; i < top + height; i++)
{
if (matix.GetLength(0) <= left + width || matix[left + width, i] != 0)
{
canExpand = false;
break;
}
}
if (canExpand)
{
for (int i = top; i < top + height; i++)
{
matix[left + width, i] = index + 1;
}
width++;
}
}
}
#endregion
#region Matrix to rectangles
int itemWidth = Convert.ToInt32(Math.Floor(Convert.ToSingle(day.Bounds.Width - ItemsPadding) / Convert.ToSingle(matix.GetLength(0))));
foreach (CalendarItem item in group)
{
int index = group.IndexOf(item);
int top, left;
int width = 1;
FindInMatrix(matix, index + 1, out left, out top);
if (left >= 0 && top >= 0)
{
for (int i = left + 1; i < matix.GetLength(0); i++)
{
if (matix[i, top] == index + 1)
{
width++;
}
else
{
break;
}
}
}
int rtop = day.TimeUnits[item.UnitsPassing[0].Index].Bounds.Top;
int bottom = day.TimeUnits[item.UnitsPassing[item.UnitsPassing.Count - 1].Index].Bounds.Bottom;
int rleft = day.Bounds.Left + left * itemWidth;
int right = rleft + itemWidth * width;
item.SetBounds(Rectangle.FromLTRB(rleft, rtop, right, bottom));
item.SetMinuteStartTop(GetTimeY(item.StartDate.TimeOfDay));
item.SetMinuteEndTop(GetTimeY(item.EndDate.TimeOfDay));
}
#endregion
}
}
#endregion
}
else if (Calendar.DaysMode == CalendarDaysMode.Short)
{
#region Short mode algorithm
Calendar.Items.Reverse();
for (int i = 0; i < Calendar.Days.Length; i++)
{
Calendar.Days[i].ContainedItems.Clear();
Calendar.Days[i].SetOverflowEnd(false);
Calendar.Days[i].SetOverflowStart(false);
}
int maxItems = 0;
foreach (CalendarItem item in Calendar.Items)
{
CalendarDay dayStart = item.DayStart;
CalendarDay dayEnd = item.DayEnd;
item.ClearBounds();
for (int i = dayStart.Index; i <= dayEnd.Index; i++)
{
Calendar.Days[i].AddContainedItem(item);
maxItems = Math.Max(maxItems, Calendar.Days[i].ContainedItems.Count);
}
}
int[,] matix = new int[Calendar.Days.Length, maxItems];
int curIndex = 0;
foreach (CalendarItem item in Calendar.Items)
{
CalendarDay dayStart = item.DayStart;
CalendarDay dayEnd = item.DayEnd;
PlaceInMatrix(ref matix, curIndex + 1, dayStart.Index, dayEnd.Index);
curIndex++;
}
for (int week = 0; week < Calendar.Weeks.Length; week++)
{
int xStart = week * 7;
int xEnd = xStart + 6;
int index = 0;
int[,] wmatix = new int[7, matix.GetLength(1)];
CalendarDay sunday = Calendar.FindDay(Calendar.Weeks[week].StartDate);
#region Fill week matrix
for (int i = 0; i < wmatix.GetLength(1); i++)
for (int j = 0; j < wmatix.GetLength(0); j++)
wmatix[j, i] = matix[j + xStart, i];
#endregion
foreach (CalendarItem item in Calendar.Items)
{
int left, top, width = 0;
FindInMatrix(wmatix, ++index, out left, out top);
if (left < 0 || top < 0) continue;
for (int i = left; i < wmatix.GetLength(0); i++)
if (wmatix[i, top] == index)
width++;
else
break;
CalendarDay dayStart = Calendar.Days[xStart + left];
CalendarDay dayEnd = Calendar.Days[xStart + left + width - 1];
Rectangle rStart = dayStart.Bounds;
Rectangle rEnd = dayEnd.Bounds;
int rtop = rStart.Top + DayHeaderHeight + top * StandardItemHeight;
Rectangle r = Rectangle.FromLTRB(rStart.Left, rtop, rEnd.Right, rtop + StandardItemHeight);
if (r.Bottom <= sunday.Bounds.Bottom)
item.AddBounds(r);
else
for (int i = dayStart.Index; i <= dayEnd.Index; i++)
Calendar.Days[i].SetOverflowEnd(true);
}
}
foreach (CalendarItem item in Calendar.Items)
item.FirstAndLastRectangleGapping();
Calendar.Items.Reverse();
#endregion
}
Calendar.RaiseItemsPositioned();
}
/// <summary>
/// Places the specified item in the matrix for the layout engine purposes
/// </summary>
/// <param name="m"></param>
/// <param name="index"></param>
/// <param name="startX"></param>
/// <param name="endX"></param>
private void PlaceInMatrix(ref int[,] m, int index, int startX, int endX)
{
int y = 0;
bool yFound = false;
while (!yFound && y < m.GetLength(1)) //HACK: && y < m.GetLength(1) //This is Because of some bug, possible item not showing
{
yFound = true;
for (int i = startX; i <= endX; i++)
{
if (i >= 0 && i < m.GetLength(0) &&
m[i, y] != 0)
{
yFound = false;
break;
}
}
if (!yFound) y++;
}
if (y < m.GetLength(1)) //HACK: This if is because of same bug
{
for (int i = startX; i <= endX; i++)
{
m[i, y] = index;
}
}
}
#endregion
#region Private Methods
/// <summary>
/// Gets the amout of units that can be displayed on the calendar viewport
/// </summary>
internal int GetVisibleTimeUnits()
{
if (Calendar.DaysMode == CalendarDaysMode.Short)
{
return 0;
}
else if (Calendar.Days != null && Calendar.Days.Length > 0)
{
return Convert.ToInt32(Math.Floor(
Convert.ToSingle(Calendar.Days[0].BodyBounds.Height) / Convert.ToSingle(TimeScaleUnitHeight)
));
}
else
{
return 0;
}
}
/// <summary>
/// Sets the value of the <see cref="DayTopHeight"/> property
/// </summary>
/// <param name="height">Height of all <see cref="CalendarDayTop"/> elements</param>
protected void SetDayTopHeight(int height)
{
_dayTopHeight = height;
}
/// <summary>
/// Sets the value of the <see cref="DayHeaderHeight"/> property
/// </summary>
/// <param name="height">Height of the day header</param>
protected void SetDayHeaderHeight(int height)
{
_dayHeaderHeight = height;
}
/// <summary>
/// Sets the value of the <see cref="DayNameHeadersHeight"/> property
/// </summary>
/// <param name="height">Height of the day name headers</param>
protected void SetDayNameHeadersHeight(int height)
{
_dayNameHeadersHeight = height;
}
/// <summary>
/// Sets the value of the <see cref="TimeScaleUnitHeight"/> property
/// </summary>
/// <param name="height">Height of the time scale unit</param>
protected void SetTimeScaleUnitHeight(int height)
{
_timeScaleUnitHeight = height;
}
/// <summary>
/// Sets the value of the <see cref="TimeScaleWidth"/> property
/// </summary>
/// <param name="width">New width for the time scale</param>
protected void SetTimeScaleWidth(int width)
{
_timeScaleWidth = width;
}
/// <summary>
/// Draws text using the information of the <see cref="CalendarRendererBoxEventArgs"/>
/// </summary>
/// <param name="e"></param>
protected virtual void DrawStandarBoxText(CalendarRendererBoxEventArgs e)
{
TextRenderer.DrawText(e.Graphics, e.Text, e.Font, e.Bounds, e.TextColor, e.Format);
}
/// <summary>
/// Outs the location of the specified number in the matrix
/// </summary>
/// <param name="m">Matrix to search in</param>
/// <param name="number">Number to find</param>
/// <param name="left">Result left</param>
/// <param name="top">Result top</param>
private void FindInMatrix(int[,] m, int number, out int left, out int top)
{
for (int i = 0; i < m.GetLength(1); i++)
{
for (int j = 0; j < m.GetLength(0); j++)
{
if (m[j, i] == number)
{
left = j;
top = i;
return;
}
}
}
left = top = -1;
}
/// <summary>
/// Outs the startIndex and the endIndex of units in the group
/// </summary>
/// <param name="group"></param>
/// <param name="startIndex"></param>
/// <param name="endIndex"></param>
private void GetGroupBoundUnits(List<CalendarItem> group, out int startIndex, out int endIndex)
{
startIndex = int.MaxValue;
endIndex = int.MinValue;
foreach (CalendarItem item in group)
{
foreach (CalendarTimeScaleUnit unit in item.UnitsPassing)
{
startIndex = Math.Min(startIndex, unit.Index);
endIndex = Math.Max(endIndex, unit.Index);
}
}
}
/// <summary>
/// Recursive method that collects items intersecting on time, to graphically represent-them on the layout
/// </summary>
/// <param name="calendarItem"></param>
/// <param name="items"></param>
/// <param name="grouped"></param>
private void CollectIntersectingGroup(CalendarItem calendarItem, List<CalendarItem> items, List<CalendarItem> grouped)
{
if (!grouped.Contains(calendarItem))
grouped.Add(calendarItem);
foreach (CalendarItem item in items)
{
if (!grouped.Contains(item) &&
calendarItem.IntersectsWith(item.StartDate.TimeOfDay, item.EndDate.TimeOfDay))
{
grouped.Add(item);
CollectIntersectingGroup(item, items, grouped);
}
}
}
/// <summary>
/// Prints the specified matrix on debug
/// </summary>
/// <param name="m"></param>
private void PrintMatrix(int[,] m)
{
//return;
Console.WriteLine("--------------------------------");
for (int i = 0; i < m.GetLength(1); i++)
{
for (int j = 0; j < m.GetLength(0); j++)
{
Console.Write(string.Format(" {0}", m[j, i]));
}
Console.WriteLine(" ");
}
Console.WriteLine("--------------------------------");
}
#endregion
#region Render Methods
/// <summary>
/// Initializes the Calendar
/// </summary>
/// <param name="e"></param>
public virtual void OnInitialize(CalendarRendererEventArgs e)
{
}
/// <summary>
/// Paints the background of the calendar
/// </summary>
/// <param name="e">Paint info</param>
public virtual void OnDrawBackground(CalendarRendererEventArgs e)
{
}
/// <summary>
/// Paints the timescale of the calendar
/// </summary>
/// <param name="e">Paint info</param>
public virtual void OnDrawTimeScale(CalendarRendererEventArgs e)
{
if (e.Calendar.DaysMode == CalendarDaysMode.Short
|| e.Calendar.Days == null
|| e.Calendar.Days.Length == 0
|| e.Calendar.Days[0].TimeUnits == null
) return;
Font hourFont = new Font(e.Calendar.Font.FontFamily, e.Calendar.Font.Size * (e.Calendar.TimeScale == CalendarTimeScale.SixtyMinutes ? 1f : 1.5f));
Font minuteFont = e.Calendar.Font;
int hourLeft = TimeScaleBounds.Left;
int hourWidth = TimeScaleBounds.Left + TimeScaleBounds.Width / 2;
int minuteLeft = hourLeft + hourWidth;
int minuteWidth = hourWidth;
int k = 0;
for (int i = 0; i < e.Calendar.Days[0].TimeUnits.Length; i++)
{
CalendarTimeScaleUnit unit = e.Calendar.Days[0].TimeUnits[i];
if (!unit.Visible) continue;
string hours = unit.Hours.ToString("00");
string minutes = unit.Minutes == 0 ? "00" : string.Empty;
if (!string.IsNullOrEmpty(minutes))
{
switch( _calendar.CalendarTimeFormat )
{
case CalendarTimeFormat.TwelveHour:
if( Convert.ToInt32( hours ) > 12 ) hours = ( Convert.ToInt32( hours ) - 12 ).ToString();
break;
case CalendarTimeFormat.TwentyFourHour:
if( hours == "00" ) hours = "12";
break;
}
CalendarRendererBoxEventArgs hevt = new CalendarRendererBoxEventArgs(e, new Rectangle(hourLeft, unit.Bounds.Top, hourWidth, unit.Bounds.Height), hours, TextFormatFlags.Right);
hevt.Font = hourFont;
OnDrawTimeScaleHour(hevt);
if (k++ == 0 || unit.Hours == 0 || unit.Hours == 12 ) minutes = unit.Date.ToString("tt");
CalendarRendererBoxEventArgs mevt = new CalendarRendererBoxEventArgs(e, new Rectangle(minuteLeft, unit.Bounds.Top, minuteWidth, unit.Bounds.Height), minutes, TextFormatFlags.Top | TextFormatFlags.Left);
mevt.Font = minuteFont;
OnDrawTimeScaleMinutes(mevt);
}
}
}
/// <summary>
/// Paints an hour of a timescale unit
/// </summary>
/// <param name="e">Paint Info</param>
public virtual void OnDrawTimeScaleHour(CalendarRendererBoxEventArgs e)
{
DrawStandarBoxText(e);
}
/// <summary>
/// Paints minutes of a timescale unit
/// </summary>
/// <param name="e">Paint Info</param>
public virtual void OnDrawTimeScaleMinutes(CalendarRendererBoxEventArgs e)
{
DrawStandarBoxText(e);
}
/// <summary>
/// Paints the days on the current calendar view
/// </summary>
/// <param name="e">Paint Info</param>
public virtual void OnDrawDays(CalendarRendererEventArgs e)
{
for (int i = 0; i < e.Calendar.Days.Length; i++)
{
CalendarDay day = e.Calendar.Days[i];
e.Tag = day;
OnDrawDay(new CalendarRendererDayEventArgs(e,
day));
}
}
/// <summary>
/// Paints the specified day on the calendar
/// </summary>
/// <param name="e">Paint info</param>
public virtual void OnDrawDay(CalendarRendererDayEventArgs e)
{
CalendarDay day = e.Day;
CalendarRendererBoxEventArgs hevt = new CalendarRendererBoxEventArgs(e,
day.HeaderBounds,
day.Date.Day.ToString(),
TextFormatFlags.VerticalCenter);
hevt.Font = new Font(Calendar.Font, FontStyle.Bold);
CalendarRendererBoxEventArgs devt = new CalendarRendererBoxEventArgs(e,
day.HeaderBounds,
day.Date.ToString("dddd"),
TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter);
OnDrawDayHeaderBackground(e);
if (Calendar.DaysMode == CalendarDaysMode.Short && (day.Index == 0 || day.Date.Day == 1))
{
hevt.Text = day.Date.ToString("dd MMM");
}
OnDrawDayHeaderText(hevt);
if (devt.TextSize.Width < day.HeaderBounds.Width - hevt.TextSize.Width * 2
&& e.Calendar.DaysMode == CalendarDaysMode.Expanded)
{
OnDrawDayHeaderText(devt);
}
OnDrawDayTimeUnits(e);
OnDrawDayTop(e);
OnDrawDayBorder(e);
}
/// <summary>
/// Paints the border of the specified day
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawDayBorder(CalendarRendererDayEventArgs e)
{
}
/// <summary>
/// Draws the all day items area
/// </summary>
/// <param name="e">Paint Info</param>
public virtual void OnDrawDayTop(CalendarRendererDayEventArgs e)
{
}
/// <summary>
/// Paints the background of the specified day's header
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawDayHeaderBackground(CalendarRendererDayEventArgs e)
{
}
/// <summary>
/// Paints the header of the specified day
/// </summary>
/// <param name="e">Paint info</param>
public virtual void OnDrawDayHeaderText(CalendarRendererBoxEventArgs e)
{
DrawStandarBoxText(e);
}
/// <summary>
/// Raises the <see cref="E:DrawDayTimeUnits"/> event.
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererDayEventArgs"/> instance containing the event data.</param>
public virtual void OnDrawDayTimeUnits(CalendarRendererDayEventArgs e)
{
for (int i = 0; i < e.Day.TimeUnits.Length; i++)
{
CalendarTimeScaleUnit unit = e.Day.TimeUnits[i];
if(unit.Visible)
OnDrawDayTimeUnit(new CalendarRendererTimeUnitEventArgs(e, unit));
}
}
/// <summary>
/// Draws a time unit of a day
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawDayTimeUnit(CalendarRendererTimeUnitEventArgs e)
{
}
/// <summary>
/// Raises the <see cref="E:DrawDayNameHeaders"/> event.
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererEventArgs"/> instance containing the event data.</param>
public virtual void OnDrawDayNameHeaders(CalendarRendererEventArgs e)
{
DateTime startDate = DateTime.Now.AddDays(-((int)DateTime.Now.DayOfWeek % 7) + 1 + (int)Calendar.FirstDayOfWeek);
for (int i = 0; i < DayNameHeaderColumns.Length; i++)
{
OnDrawDayNameHeader(new CalendarRendererBoxEventArgs(e,
DayNameHeaderColumns[i],
startDate.AddDays(i).ToString("dddd"),
TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter));
}
}
/// <summary>
/// Raises the <see cref="E:DrawDayNameHeader"/> event.
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererBoxEventArgs"/> instance containing the event data.</param>
public virtual void OnDrawDayNameHeader(CalendarRendererBoxEventArgs e)
{
DrawStandarBoxText(e);
}
/// <summary>
/// Draws the items of the calendar
/// </summary>
/// <param name="e">Event info</param>
public virtual void OnDrawItems(CalendarRendererEventArgs e)
{
Rectangle days = e.Calendar.DaysBodyRectangle; days.Inflate(-1, -1);
Region oldclip = e.Graphics.Clip;
bool doClip = e.Calendar.DaysMode == CalendarDaysMode.Expanded;
bool clipped = false;
#region Shadows
foreach (CalendarItem item in e.Calendar.Items)
{
clipped = false;
if (doClip && !item.IsOnDayTop && item.Bounds.Top < days.Top)
{
e.Graphics.SetClip(days, CombineMode.Intersect);
clipped = true;
}
List<Rectangle> rects = new List<Rectangle>(item.GetAllBounds());
for (int i = 0; i < rects.Count; i++)
{
CalendarRendererItemBoundsEventArgs evt = new CalendarRendererItemBoundsEventArgs(
new CalendarRendererItemEventArgs(e, item),
rects[i],
i == 0 && !item.IsOpenStart,
(i == rects.Count - 1) && !item.IsOpenEnd);
OnDrawItemShadow(evt);
}
if (clipped)
e.Graphics.SetClip(oldclip, CombineMode.Replace);
}
#endregion
#region Items
foreach (CalendarItem item in e.Calendar.Items)
{
clipped = false;
if( doClip && !item.IsOnDayTop && item.Bounds.Top < days.Top )
{
e.Graphics.SetClip( days, CombineMode.Intersect );
clipped = true;
}
OnDrawItem(new CalendarRendererItemEventArgs(e, item));
if( clipped )
{
e.Graphics.SetClip( oldclip, CombineMode.Replace );
}
}
#endregion
#region Borders of selected items
foreach (CalendarItem item in e.Calendar.Items)
{
if (!item.Selected) continue;
List<Rectangle> rects = new List<Rectangle>(item.GetAllBounds());
for (int i = 0; i < rects.Count; i++)
{
CalendarRendererItemBoundsEventArgs evt = new CalendarRendererItemBoundsEventArgs(
new CalendarRendererItemEventArgs(e, item),
rects[i],
i == 0 && !item.IsOpenStart,
(i == rects.Count - 1) && !item.IsOpenEnd);
SmoothingMode smbuff = e.Graphics.SmoothingMode;
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
OnDrawItemBorder(evt);
e.Graphics.SmoothingMode = smbuff;
}
}
#endregion
}
/// <summary>
/// Draws an item of the calendar
/// </summary>
/// <param name="e">Event Info</param>
public virtual void OnDrawItem( CalendarRendererItemEventArgs e )
{
List<Rectangle> rects = new List<Rectangle>( e.Item.GetAllBounds() );
for( int i = 0; i < rects.Count; i++ )
{
CalendarRendererItemBoundsEventArgs evt = new CalendarRendererItemBoundsEventArgs(
e,
rects[i],
i == 0 && !e.Item.IsOpenStart,
( i == rects.Count - 1 ) && !e.Item.IsOpenEnd );
OnDrawItemBackground( evt );
if( !evt.Item.PatternColor.IsEmpty )
{
OnDrawItemPattern( evt );
}
if( !e.Item.IsEditing )
{
OnDrawItemContent( evt );
}
OnDrawItemBorder( evt );
}
}
/// <summary>
/// Draws the background of the specified item
/// </summary>
/// <param name="e">Event Info</param>
public virtual void OnDrawItemBackground(CalendarRendererItemBoundsEventArgs e)
{
}
/// <summary>
/// Raises the <see cref="E:DrawItemPattern"/> event.
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererItemBoundsEventArgs"/> instance containing the event data.</param>
public virtual void OnDrawItemPattern(CalendarRendererItemBoundsEventArgs e)
{
foreach (Rectangle bounds in e.Item.GetAllBounds())
{
ItemPattern(e, bounds, e.Item.PatternColor);
}
}
/// <summary>
/// Draws the strings of an item. Strings inlude StartTime, EndTime and Text
/// </summary>
/// <param name="e">Event Info</param>
public virtual void OnDrawItemContent(CalendarRendererItemBoundsEventArgs e)
{
if (e.Item == e.Calendar.EditModeItem) return;
List<Rectangle> rectangles = new List<Rectangle>(e.Item.GetAllBounds());
for (int i = 0; i < rectangles.Count; i++)
{
Rectangle bounds = rectangles[i];
Rectangle imageBounds = Rectangle.Empty;
Rectangle rStartTime = new Rectangle();
Rectangle rEndTime = new Rectangle();
string endTime = string.Empty;
string startTime = string.Empty;
Color secondaryForecolor = e.Item.ForeColor;
if (e.Item.ShowEndTime && i == rectangles.Count - 1)
{
endTime = e.Item.EndDateText;
rEndTime = new Rectangle(Point.Empty, TextRenderer.MeasureText(endTime, e.Calendar.Font));
rEndTime = Rectangle.FromLTRB(bounds.Right - rEndTime.Width - ItemTextMargin.Right,
bounds.Top + ItemTextMargin.Top,
bounds.Right - ItemTextMargin.Right,
bounds.Bottom - ItemTextMargin.Bottom);
OnDrawItemEndTime(new CalendarRendererBoxEventArgs(e, rEndTime, endTime, secondaryForecolor));
}
if (e.Item.ShowStartTime && i == 0)
{
startTime = e.Item.StartDateText;
rStartTime = new Rectangle(Point.Empty, TextRenderer.MeasureText(startTime, e.Calendar.Font));
rStartTime.X = bounds.Left + ItemTextMargin.Left;
rStartTime.Y = bounds.Top + ItemTextMargin.Top;
rStartTime.Height = bounds.Height - ItemTextMargin.Vertical;
OnDrawItemStartTime(new CalendarRendererBoxEventArgs(e, rStartTime, startTime, secondaryForecolor));
}
Rectangle r = Rectangle.FromLTRB(
bounds.Left + ItemTextMargin.Left + rStartTime.Width,
bounds.Top + ItemTextMargin.Top,
bounds.Right - ItemTextMargin.Right - rEndTime.Width,
bounds.Bottom - ItemTextMargin.Bottom);
CalendarRendererBoxEventArgs evt = new CalendarRendererBoxEventArgs(e, r, e.Item.Text, TextFormatFlags.Left | TextFormatFlags.Top);
evt.Font = e.Item.Font;
if( e.Item.ShowStartTime || e.Item.ShowEndTime )
{
evt.Font = new Font( evt.Font, FontStyle.Bold );
}
if( e.Item.IsOnDayTop || Calendar.DaysMode == CalendarDaysMode.Short )
{
evt.Format |= TextFormatFlags.HorizontalCenter;
}
if (!e.Item.ForeColor.IsEmpty)
{
evt.TextColor = e.Item.ForeColor;
}
evt.Tag = e.Item;
#region Image
if (e.Item.Image != null)
{
Rectangle tBounds = e.Item.Bounds;
imageBounds.Size = e.Item.Image.Size;
switch (e.Item.ImageAlign)
{
case CalendarItemImageAlign.North:
tBounds.Height -= imageBounds.Height;
tBounds.Y += imageBounds.Height;
imageBounds.Y = tBounds.Y - imageBounds.Height;
break;
case CalendarItemImageAlign.South:
tBounds.Height -= imageBounds.Height;
imageBounds.Y = tBounds.Bottom;
break;
case CalendarItemImageAlign.East:
tBounds.Width -= imageBounds.Width;
imageBounds.X = tBounds.Right;
break;
case CalendarItemImageAlign.West:
tBounds.Width -= imageBounds.Width;
tBounds.X += imageBounds.Width;
imageBounds.X = tBounds.Left - imageBounds.Width;
break;
}
switch (e.Item.ImageAlign)
{
case CalendarItemImageAlign.North:
case CalendarItemImageAlign.South:
imageBounds.X = e.Item.Bounds.X + ( ( e.Item.Bounds.Width - imageBounds.Width ) / 2);
break;
case CalendarItemImageAlign.East:
case CalendarItemImageAlign.West:
imageBounds.Y = e.Item.Bounds.Y + ((e.Item.Bounds.Height - imageBounds.Height) / 2);
break;
}
evt.Bounds = tBounds;
OnDrawItemImage(new CalendarRendererItemBoundsEventArgs(e, imageBounds, false, false));
}
#endregion
OnDrawItemText(evt);
}
}
/// <summary>
/// Draws the text of an item
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawItemText(CalendarRendererBoxEventArgs e)
{
DrawStandarBoxText(e);
}
/// <summary>
/// Draws the image of an item
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawItemImage(CalendarRendererItemBoundsEventArgs e)
{
if (e.Item.Image != null)
{
e.Graphics.DrawImage(e.Item.Image, e.Bounds);
}
}
/// <summary>
/// Draws the starttime of the item if applicable
/// </summary>
/// <param name="e">Event data</param>
public virtual void OnDrawItemStartTime(CalendarRendererBoxEventArgs e)
{
DrawStandarBoxText(e);
}
/// <summary>
/// Draws the end time of the item if applicable
/// </summary>
/// <param name="e">Event data</param>
public virtual void OnDrawItemEndTime(CalendarRendererBoxEventArgs e)
{
DrawStandarBoxText(e);
}
/// <summary>
/// Draws the border of the specified item
/// </summary>
/// <param name="e">Event Info</param>
public virtual void OnDrawItemBorder(CalendarRendererItemBoundsEventArgs e)
{
}
/// <summary>
/// Draws the shadow of the specified item
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawItemShadow(CalendarRendererItemBoundsEventArgs e)
{
}
/// <summary>
/// Draws the overflows of days
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawOverflows(CalendarRendererEventArgs e)
{
for (int i = 0; i < e.Calendar.Days.Length; i++)
{
CalendarDay day = e.Calendar.Days[i];
if (day.OverflowStart)
{
OnDrawDayOverflowStart(new CalendarRendererDayEventArgs(e, day));
}
if(day.OverflowEnd)
{
OnDrawDayOverflowEnd(new CalendarRendererDayEventArgs(e, day));
}
}
}
/// <summary>
/// Draws the overflow to start of specified day
/// </summary>
/// <param name="e">Event data</param>
public virtual void OnDrawDayOverflowStart(CalendarRendererDayEventArgs e)
{
}
/// <summary>
/// Draws the overflow to end of specified day
/// </summary>
/// <param name="e"></param>
public virtual void OnDrawDayOverflowEnd(CalendarRendererDayEventArgs e)
{
//e.Graphics.FillRectangle(Brushes.Red, e.Day.OverflowEndBounds);
}
/// <summary>
/// Raises the <see cref="E:DrawWeekHeaders"/> event.
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererEventArgs"/> instance containing the event data.</param>
public virtual void OnDrawWeekHeaders(CalendarRendererEventArgs e)
{
if (Calendar.Weeks == null) return;
for (int i = 0; i < Calendar.Weeks.Length; i++)
{
string str = Calendar.Weeks[i].ToStringLarge();
SizeF sz = e.Graphics.MeasureString(str, e.Calendar.Font);
if (sz.Width > Calendar.Weeks[i].HeaderBounds.Height)
{
str = Calendar.Weeks[i].ToStringShort();
}
OnDrawWeekHeader(new CalendarRendererBoxEventArgs(e,
Calendar.Weeks[i].HeaderBounds, str, TextFormatFlags.Default));
}
}
/// <summary>
/// Raises the <see cref="E:DrawWeekHeader"/> event.
/// </summary>
/// <param name="e">The <see cref="WindowsFormsCalendar.CalendarRendererBoxEventArgs"/> instance containing the event data.</param>
public virtual void OnDrawWeekHeader(CalendarRendererBoxEventArgs e)
{
StringFormat sf = new StringFormat();
sf.FormatFlags = StringFormatFlags.DirectionVertical | StringFormatFlags.DirectionRightToLeft | StringFormatFlags.NoWrap;
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
using (SolidBrush b = new SolidBrush(e.TextColor))
{
e.Graphics.DrawString(e.Text, e.Font, b, e.Bounds, sf);
}
e.Graphics.ResetTransform();
sf.Dispose();
}
#endregion
}
}