1974 lines
69 KiB
C#
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
|
|
|
|
}
|
|
}
|