2756 lines
83 KiB
C#

#if FRAMEWORK20
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Globalization;
using System.Windows.Forms;
namespace DevComponents.DotNetBar.Schedule
{
public class MonthView : BaseView
{
#region Constants
private const int MaxNumberOfWeeks = 52;
#endregion
#region Events
public event EventHandler<IsSideBarVisibleChangedEventArgs> IsSideBarVisibleChanged;
#endregion
#region Private variables
private int _NumberOfWeeks; // Number of week in display
private MonthWeek[] _MonthWeeks; // Array of weeks
private CalendarMonthColor _ViewColor = // View display color table
new CalendarMonthColor(eCalendarColor.Automatic);
private int _DaysOffset; // Moving day offset
private bool _IsSideBarVisible = true; // Flag denoting SideBar visibility
private Size _MoreImageSize = new Size(16, 16);
private Bitmap _MoreImage;
private Bitmap _MoreImageHot;
private ItemRect _MoreRect;
#endregion
/// <summary>
/// Constructor
/// </summary>
/// <param name="calendarView">Parent CalendarView</param>
public MonthView(CalendarView calendarView)
: base(calendarView, eCalendarView.Month)
{
// Set our non-client drawing info and our CalendarColor
NClientData = new NonClientData(
eTabOrientation.Horizontal,
(int)eCalendarMonthPart.OwnerTabBorder,
(int)eCalendarMonthPart.OwnerTabForeground,
(int)eCalendarMonthPart.OwnerTabBackground,
(int)eCalendarMonthPart.OwnerTabContentBackground,
(int)eCalendarMonthPart.OwnerTabSelectedForeground,
(int)eCalendarMonthPart.OwnerTabSelectedBackground);
CalendarColorTable = _ViewColor;
// Hook onto needed event
HookEvents(true);
}
#region Public properties
#region MonthWeek
public MonthWeek[] MonthWeeks
{
get { return (_MonthWeeks); }
}
#endregion
#region IsSideBarVisible
/// <summary>
/// Gets and sets the SideBar visibility
/// </summary>
public bool IsSideBarVisible
{
get { return (_IsSideBarVisible); }
set
{
if (_IsSideBarVisible != value)
{
bool oldValue = _IsSideBarVisible;
_IsSideBarVisible = value;
OnIsSideBarVisibleChanged(oldValue, value);
InvalidateRect(true);
}
}
}
/// <summary>
/// OnIsSideBarVisibleChanged event propagation
/// </summary>
protected virtual void OnIsSideBarVisibleChanged(bool oldVal, bool newVal)
{
if (IsSideBarVisibleChanged != null)
IsSideBarVisibleChanged(this, new IsSideBarVisibleChangedEventArgs(oldVal, newVal));
}
#endregion
#endregion
#region Private properties
/// <summary>
/// Gets the sidebar width
/// </summary>
private int SideBarWidth
{
get
{
return (_IsSideBarVisible ? Font.Height + 6 : 0);
}
}
/// <summary>
/// Gets the DayHeader height
/// </summary>
private int DayHeaderHeight
{
get { return (Font.Height + 4); }
}
#endregion
#region HookEvents
/// <summary>
/// Hooks (or unhooks) needed events
/// </summary>
/// <param name="hook">True to hook, false to unhook</param>
private void HookEvents(bool hook)
{
if (hook == true)
{
CalendarView.SelectedViewChanged += SelectedViewChanged;
CalendarView.MonthViewStartDateChanged += MonthViewStartDateChanged;
CalendarView.MonthViewEndDateChanged += MonthViewEndDateChanged;
CalendarView.IsMonthSideBarVisibleChanged += IsMonthSideBarVisibleChanged;
}
else
{
CalendarView.SelectedViewChanged -= SelectedViewChanged;
CalendarView.MonthViewStartDateChanged -= MonthViewStartDateChanged;
CalendarView.MonthViewEndDateChanged -= MonthViewEndDateChanged;
CalendarView.IsMonthSideBarVisibleChanged -= IsMonthSideBarVisibleChanged;
}
}
#endregion
#region Event handling
#region SelectedViewChanged
/// <summary>
/// Processes CalendarView SelectedViewChanged events
/// </summary>
/// <param name="sender">CalendarView</param>
/// <param name="e">SelectedViewEventArgs</param>
void SelectedViewChanged(object sender, SelectedViewEventArgs e)
{
IsViewSelected = (e.NewValue == eCalendarView.Month);
if (IsViewSelected == true)
{
AutoSyncViewDate(e.OldValue);
UpdateDateSelection();
}
else
{
ResetView();
}
}
#endregion
#region MonthViewStartDateChanged
/// <summary>
/// Processes StartDate changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void MonthViewStartDateChanged(object sender, DateChangeEventArgs e)
{
StartDate = e.NewValue;
}
#endregion
#region MonthViewEndDateChanged
/// <summary>
/// Processes EndDate changes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void MonthViewEndDateChanged(object sender, DateChangeEventArgs e)
{
EndDate = e.NewValue;
}
#endregion
#region IsMonthSideBarVisibleChanged
/// <summary>
/// Processes CalendarView IsMonthSideBarVisibleChanged events
/// </summary>
/// <param name="sender">CalendarView</param>
/// <param name="e">SelectedViewEventArgs</param>
void IsMonthSideBarVisibleChanged(
object sender, IsMonthSideBarVisibleChangedEventArgs e)
{
IsSideBarVisible = e.NewValue;
}
#endregion
#endregion
#region GetViewAreaFromPoint
/// <summary>
/// Gets the view area under the given mouse
/// point (tab, header, content, etc)
/// </summary>
/// <param name="pt">Point</param>
/// <returns>eViewArea</returns>
public override eViewArea GetViewAreaFromPoint(Point pt)
{
if (Bounds.Contains(pt) == true)
{
if (ClientRect.Contains(pt))
{
if (pt.X < Bounds.X + SideBarWidth)
return (eViewArea.InSideBarPanel);
if (pt.Y < ClientRect.Y + DayOfWeekHeaderHeight)
return (eViewArea.InDayOfWeekHeader);
if (pt.X >= _MonthWeeks[0].Bounds.X)
{
for (int i = 0; i < _NumberOfWeeks; i++)
{
if (pt.Y < _MonthWeeks[i].Bounds.Y + DayHeaderHeight)
return (eViewArea.InWeekHeader);
if (pt.Y < _MonthWeeks[i].Bounds.Bottom)
return (eViewArea.InContent);
}
}
return (eViewArea.NotInView);
}
return (base.GetViewAreaFromPoint(pt));
}
return (eViewArea.NotInView);
}
#endregion
#region GetDateSelectionFromPoint
/// <summary>
/// Gets the date selection from the given point. The startDate
/// and endDate will vary based upon the view type (WeekDay / Month)
/// </summary>
/// <param name="pt">Point in question</param>
/// <param name="startDate">out start date</param>
/// <param name="endDate">out end date</param>
/// <returns>True if a valid selection exists
/// at the given point</returns>
public override bool GetDateSelectionFromPoint(
Point pt, out DateTime startDate, out DateTime endDate)
{
base.GetDateSelectionFromPoint(pt, out startDate, out endDate);
int week, day;
if (GetPointItem(pt, out week, out day))
{
startDate = _MonthWeeks[week].FirstDayOfWeek.AddDays(day);
endDate = startDate.AddDays(1);
return (true);
}
return (false);
}
#endregion
#region GetItemWeek
public MonthWeek GetItemWeek(CalendarItem item)
{
for (int i = 0; i < _NumberOfWeeks; i++)
{
if (_MonthWeeks[i].CalendarItems.Contains(item))
return (_MonthWeeks[i]);
}
return (null);
}
#endregion
#region SetSelectedItem
/// <summary>
/// Handles selected item changes
/// </summary>
/// <param name="sender">CalendarItem</param>
/// <param name="e">EventArgs</param>
public void ItemIsSelectedChanged(object sender, EventArgs e)
{
CalendarItem ci = sender as CalendarItem;
if (ci != null && IsSelecting == false)
{
try
{
IsSelecting = true;
if (ci.IsSelected == true)
{
SelectedItem = SetSelectedItem(SelectedItem, ci);
}
else
{
if (ci == SelectedItem)
SelectedItem = null;
}
}
finally
{
IsSelecting = false;
}
}
}
/// <summary>
/// Sets the current selected item
/// </summary>
/// <param name="pci">Previous CalendarItem</param>
/// <param name="nci">New CalendarItem to select</param>
/// <returns>Base selected CalendarItem</returns>
protected override CalendarItem SetSelectedItem(CalendarItem pci, CalendarItem nci)
{
CalendarItem selItem = null;
for (int i = 0; i < _NumberOfWeeks; i++)
{
List<CalendarItem> items = _MonthWeeks[i].CalendarItems;
for (int j = 0; j < items.Count; j++)
{
CalendarItem item = items[j];
item.IsSelected = (nci != null ? (item.ModelItem == nci.ModelItem) : false);
if (item.IsSelected == true && selItem == null)
{
selItem = item;
SelectedItem = item;
}
}
}
return (selItem);
}
#endregion
#region UpdateDateSelection
/// <summary>
/// Updates each monthWeeks DayRects to reflect
/// the date selection start and end values
/// </summary>
protected override void UpdateDateSelection()
{
if (IsViewSelected == true)
{
// Loop through each week
for (int i = 0; i < _NumberOfWeeks; i++)
{
DateTime date = _MonthWeeks[i].FirstDayOfWeek;
// loop through each day of the week, setting
// the selection status according to the date
// selection range
for (int j = 0; j < DaysInWeek; j++)
{
bool selected = (DateSelectionStart.HasValue && DateSelectionEnd.HasValue &&
date >= DateSelectionStart && date < DateSelectionEnd);
_MonthWeeks[i].DayRects[j].IsSelected = selected;
date = date.AddDays(1);
}
}
}
}
#endregion
#region RecalcSize routines
/// <summary>
/// Performs NeedRecalcSize requests
/// </summary>
public override void RecalcSize()
{
base.RecalcSize();
if (IsViewSelected == true)
{
// Normalize our start and end dates
DateTime startDate;
DateTime endDate;
NormalizeDates(out startDate, out endDate);
// Calculate each weeks display info
CalcMonthWeeks(startDate, endDate);
// Update our Model connection and views
UpdateView();
UpdateDateSelection();
if (DaysOfTheWeek != null)
DaysOfTheWeek.NeedsMeasured = true;
NeedRecalcLayout = false;
}
}
#region NormalizeDates
/// <summary>
/// Normalizes the user specified start and end dates
/// </summary>
/// <param name="startDate">[out] Normalized start date</param>
/// <param name="endDate">[out] Normalized end date</param>
private void NormalizeDates(out DateTime startDate, out DateTime endDate)
{
startDate = this.StartDate;
endDate = this.EndDate;
// If both values are unset, then set them to
// today's date / + 1 month
if (startDate == DateTime.MinValue && endDate == DateTime.MinValue)
{
startDate = DateTime.Today.Date;
endDate = startDate.AddMonths(1);
}
endDate = DateHelper.GetEndOfWeek(endDate, DateHelper.GetLastDayOfWeek());
startDate = DateHelper.GetDateForDayOfWeek(startDate, DateHelper.GetFirstDayOfWeek());
DaysOfTheWeek = new DaysOfTheWeek();
}
#endregion
#region Update View
/// <summary>
/// Updates our connection model view
/// </summary>
private void UpdateView()
{
// If we have had a date range change, just
// reset our entire view
if (DateRangeChanged == true)
ResetView();
// If we have no Model connection, attempt
// to reconnect if this view is selected
if (Connector == null)
{
if (CalendarModel != null)
Connector = new ModelMonthViewConnector(CalendarModel, this);
}
// We have a connection, so update our CalendarItems
if (Connector != null)
{
UpdateCalendarItems();
CalendarView.DoViewLoadComplete(this);
}
}
#region UpdateCalendarItems
/// <summary>
/// Updates our CalendarItems list
/// </summary>
private void UpdateCalendarItems()
{
// Get a working list of our CalendarItems
List<CalendarItem>[] items = SortCalendarItems();
// Go through our CalendarItems on a per week basis
bool moreItems = false;
int days = _NumberOfWeeks * DaysInWeek;
ulong[] acc = new ulong[days];
for (int i = 0; i < _NumberOfWeeks; i++)
{
// Calculate the display bounds for each item
for (int j = 0; j < items[i].Count; j++)
CalcAppointmentBounds(items[i][j], i, acc);
moreItems |= UpdateMoreItems(_MonthWeeks[i], acc, i);
}
// If we have no need of our previously allocated "More"
// images then dispose of them and reset our handles
if (moreItems == false)
{
if (_MoreImage != null)
{
_MoreImage.Dispose();
_MoreImage = null;
}
if (_MoreImageHot != null)
{
_MoreImageHot.Dispose();
_MoreImageHot = null;
}
}
// Update our current day selection
UpdateDateSelection();
}
#region SortCalendarItems
/// <summary>
/// Sorts the provided CalendarItems
/// </summary>
/// <returns>Sorted CalendarItems</returns>
private List<CalendarItem>[] SortCalendarItems()
{
List<CalendarItem>[] items = new List<CalendarItem>[_NumberOfWeeks];
for (int i = 0; i < _NumberOfWeeks; i++)
{
items[i] = new List<CalendarItem>(_MonthWeeks[i].CalendarItems.Count);
if (_MonthWeeks[i].CalendarItems.Count > 0)
{
items[i].AddRange(_MonthWeeks[i].CalendarItems);
items[i].Sort(
delegate(CalendarItem c1, CalendarItem c2)
{
int n = c1.StartTime.TimeOfDay.CompareTo(c2.StartTime.TimeOfDay);
if (n != 0)
return (n);
n = c1.StartTime.CompareTo(c2.StartTime);
if (n != 0)
return (n);
n = c1.EndTime.CompareTo(c2.EndTime);
if (n != 0)
return (n);
int result = 0;
CalendarView.DoDetailSortEvent(this, c1, c2, ref result);
return (result);
}
);
}
}
return (items);
}
#endregion
#region CalcAppointmentBounds
/// <summary>
/// Calculates the display bounds for the AppointmentView
/// </summary>
/// <param name="item">CalendarItem</param>
/// <param name="week">Week associated with the view</param>
/// <param name="acc">Row accumulator</param>
private void CalcAppointmentBounds(
CalendarItem item, int week, ulong[] acc)
{
// Determine the starting day index for
// the given appointment
int ns = GetDayIndex(week, item);
// Calculate the top and height for the item
Rectangle r = _MonthWeeks[week].DayRects[ns].Bounds;
r.Y += DayHeaderHeight + 1;
r.Height = AppointmentHeight;
r.Width = 0;
// Determine the ending day index
DateTime st = _MonthWeeks[week].FirstDayOfWeek.AddDays(ns);
int ne = ns + (item.EndTime - st).Days;
if (item.EndTime.Hour > 0 || item.EndTime.Minute > 0 || item.EndTime.Second > 0)
ne++;
if (ne > DaysInWeek)
ne = DaysInWeek;
int weekOffset = week * DaysInWeek;
int freeAcc = GetFreeAcc(weekOffset + ns, weekOffset + ne, acc);
if (freeAcc >= 0)
{
ulong u = (1ul << freeAcc);
for (int i = ns; i < ne; i++)
{
r.Width += _MonthWeeks[week].DayRects[i].Bounds.Width;
acc[weekOffset + i] |= u;
}
r.Y += (freeAcc * AppointmentHeight);
}
else
{
r.Y = _MonthWeeks[week].Bounds.Bottom;
}
DateTime start = _MonthWeeks[week].FirstDayOfWeek;
DateTime end = start.AddDays(DaysInWeek);
// Check to see if we can only display
// a partial representation for the view
if (item.EndTime >= start && item.StartTime < end)
{
int hpad = CalendarView.MonthViewHorizontalPadding;
if (item.StartTime >= start)
{
r.X += hpad;
r.Width -= hpad;
}
if (item.EndTime <= end)
r.Width -= hpad;
}
// Now that we have calculated the items height and
// width, invoke a Recalc on the item
item.WidthInternal = r.Width - 1;
item.HeightInternal = r.Height - 1;
item.RecalcSize();
// Set our bounds for the item
r.Width = item.WidthInternal;
r.Height = item.HeightInternal;
item.Bounds = r;
// Set it's display state
if (CalendarView.IsMonthMoreItemsIndicatorVisible == true)
item.Displayed = (r.Bottom < _MonthWeeks[week].Bounds.Bottom - _MoreImageSize.Height);
else
item.Displayed = (r.Top < _MonthWeeks[week].Bounds.Bottom - 2);
}
#region GetFreeAcc
private int GetFreeAcc(int ns, int ne, ulong[] acc)
{
for (int i = 0; i < sizeof(ulong) * 8; i++)
{
if (CheckFreeAcc(ns, ne, acc, i) == true)
return (i);
}
return (-1);
}
#region CheckFreeAcc
private bool CheckFreeAcc(int ns, int ne, ulong[] acc, int n)
{
for (int i = ns; i < ne; i++)
{
ulong u = acc[i];
if ((u & (1ul << n)) != 0)
return (false);
}
return (true);
}
#endregion
#endregion
#region GetDayIndex
/// <summary>
/// Gets the starting day index for the given appointment
/// </summary>
/// <param name="week">Week index</param>
/// <param name="item">CalendarItem</param>
/// <returns>Day of week index (0-6)</returns>
private int GetDayIndex(int week, CalendarItem item)
{
DateTime date = _MonthWeeks[week].FirstDayOfWeek;
for (int i = 0; i < DaysInWeek; i++)
{
date = date.AddDays(1);
if (date > item.StartTime)
return (i);
}
return (0);
}
#endregion
#endregion
#region UpdateMoreItems
/// <summary>
/// UpdateMoreItems
/// </summary>
/// <param name="monthWeek"></param>
/// <param name="acc"></param>
/// <returns></returns>
private bool UpdateMoreItems(MonthWeek monthWeek, ulong[] acc, int week)
{
bool moreItems = false;
int weekOffset = week * DaysInWeek;
int rowHeight = monthWeek.DayRects[0].Bounds.Height -
DayHeaderHeight - _MoreImageSize.Height - 1;
for (int j = 0; j < DaysInWeek; j++)
{
int height = GetMoreHeight(acc[weekOffset + j]);
if (CalendarView.IsMonthMoreItemsIndicatorVisible == false || height <= rowHeight)
{
monthWeek.MoreItems[j].Bounds = Rectangle.Empty;
}
else
{
moreItems = true;
Rectangle r = monthWeek.DayRects[j].Bounds;
r.X = r.Right - _MoreImageSize.Width;
r.Y = r.Bottom - _MoreImageSize.Height;
r.Size = _MoreImageSize;
monthWeek.MoreItems[j].Bounds = r;
}
}
return (moreItems);
}
#region GetMoreHeight
private int GetMoreHeight(ulong u)
{
int height = 0;
while (u != 0)
{
height += AppointmentHeight;
u = u >> 1;
}
return (height);
}
#endregion
#endregion
#endregion
#region CalcMonthWeeks
/// <summary>
/// Calculates display info for the MonthWeek data
/// </summary>
/// <param name="startDate">Start date</param>
/// <param name="endDate">End date</param>
private void CalcMonthWeeks(DateTime startDate, DateTime endDate)
{
// Get the number of weeks for the date range
_NumberOfWeeks = DateHelper.GetNumberOfWeeks(startDate, endDate);
_NumberOfWeeks = Math.Max(1, _NumberOfWeeks);
_NumberOfWeeks = Math.Min(_NumberOfWeeks, MaxNumberOfWeeks);
// Allocate our MonthWeeks array to
// hold our weeks info
if (_MonthWeeks == null || _MonthWeeks.Length != _NumberOfWeeks)
_MonthWeeks = new MonthWeek[_NumberOfWeeks];
// Update display info on each week
float dy = 0;
float weekHeight =
((float)ClientRect.Height - DayOfWeekHeaderHeight) / _NumberOfWeeks;
int sx = ClientRect.X + SideBarWidth;
int sy = ClientRect.Y + DayOfWeekHeaderHeight;
int y2 = sy;
// Loop through each week
for (int i = 0; i < _NumberOfWeeks; i++)
{
if (_MonthWeeks[i] == null)
_MonthWeeks[i] = new MonthWeek(this);
// Set the weeks first day of the week
_MonthWeeks[i].FirstDayOfWeek = startDate.AddDays(i * DaysInWeek);
// Calculate the bounding rect limits
dy += weekHeight;
int y1 = y2;
y2 = sy + (int)dy;
if (i + 1 == _NumberOfWeeks)
y2 = ClientRect.Y + ClientRect.Height - 1;
// Set the bounding rect
_MonthWeeks[i].Bounds =
new Rectangle(sx, y1, ClientRect.Width - SideBarWidth - 1, y2 - y1);
}
}
#endregion
#endregion
#endregion
#region Paint processing
#region Root paint code
/// <summary>
/// Paint processing
/// </summary>
/// <param name="e">ItemPaintArgs</param>
public override void Paint(ItemPaintArgs e)
{
// Set our current color table
_ViewColor.SetColorTable();
// Only draw something if we have something to draw
if (_NumberOfWeeks > 0)
{
// Calculate our drawing ranges
int dayStart, dayEnd, dayCount;
int weekStart, weekEnd, weekCount;
if (e.ClipRectangle.Contains(ClientRect))
{
// The clipping rect encompasses our entire calendar
// so set our start and end values accordingly
dayStart = 0; dayEnd = DaysInWeek - 1;
dayCount = DaysInWeek;
weekStart = 0; weekEnd = _NumberOfWeeks - 1;
weekCount = _NumberOfWeeks;
}
else
{
// We only need to draw part of our calendar, so
// calculate our day and week count and range
dayCount = GetDayRange(e, out dayStart, out dayEnd);
weekCount = GetWeekRange(e, out weekStart, out weekEnd);
}
// Draw our calendar parts
if (dayCount > 0)
{
DrawDayOfTheWeekHeader(e, dayStart, dayEnd);
if (weekCount > 0)
{
DrawDays(e, weekStart, weekEnd, dayStart, dayEnd);
if (Connector != null && Connector.IsConnected)
DrawWeekAppointments(e, weekStart, weekEnd);
}
}
if (_IsSideBarVisible == true && weekCount > 0)
DrawSideBarHeader(e, weekStart, weekEnd);
}
// Let the base painting take place
base.Paint(e);
}
#region Clip range routines
/// <summary>
/// Calculates the range of days needed to be drawn
/// to satisfy the specified paint request
/// </summary>
/// <param name="e">ItemPaintArgs</param>
/// <param name="dayStart">[out] Day start index</param>
/// <param name="dayEnd">[out] Day end index</param>
/// <returns>Day range count (end - start)</returns>
private int GetDayRange(ItemPaintArgs e, out int dayStart, out int dayEnd)
{
// Calc our starting index
int start = 0;
while (start < DaysInWeek)
{
Rectangle dr1 = _MonthWeeks[0].DayRects[start].Bounds;
if (dr1.Right >= e.ClipRectangle.X)
break;
start++;
}
// Calc our ending index
int end = start;
while (end < DaysInWeek)
{
Rectangle dr2 = _MonthWeeks[0].DayRects[end].Bounds;
if (dr2.X >= e.ClipRectangle.Right)
break;
end++;
}
// Set the user supplied 'out' values, and
// return the range count to the caller
if (end - start == 0)
{
dayStart = 0;
dayEnd = 0;
return (0);
}
dayStart = start;
dayEnd = end - 1;
return (end - start);
}
/// <summary>
/// Calculates the range of weeks needed to be drawn
/// to satisfy the specified paint request
/// </summary>
/// <param name="e">ItemPaintArgs</param>
/// <param name="weekStart">[out] Week start index</param>
/// <param name="weekEnd">[out] Week end index</param>
/// <returns>Week range count (end - start)</returns>
private int GetWeekRange(ItemPaintArgs e, out int weekStart, out int weekEnd)
{
// Calc our starting index
int start = 0;
while (start < _NumberOfWeeks)
{
if (_MonthWeeks[start].Bounds.Bottom > e.ClipRectangle.Y)
break;
start++;
}
// Calc our ending index
int end = start;
while (end < _NumberOfWeeks)
{
if (_MonthWeeks[end].Bounds.Y >= e.ClipRectangle.Bottom)
break;
end++;
}
// Set the user supplied 'out' values, and
// return the range count to the caller
if (end - start == 0)
{
weekStart = 0;
weekEnd = 0;
return (0);
}
weekStart = start;
weekEnd = end - 1;
return (end - start);
}
#endregion
#endregion
#region DayOfTheWeek header drawing
#region DrawDayOfTheWeekHeader
/// <summary>
/// Draws the top Day of the week header
/// </summary>
/// <param name="e">ItemPaintArgs</param>
/// <param name="dayStart">Start day index</param>
/// <param name="dayEnd">End day index</param>
private void DrawDayOfTheWeekHeader(ItemPaintArgs e, int dayStart, int dayEnd)
{
Graphics g = e.Graphics;
Rectangle r = new Rectangle(ClientRect.X - 1, ClientRect.Y - 1,
SideBarWidth + 1, DayOfWeekHeaderHeight + 1);
using (Brush br =
_ViewColor.BrushPart((int)eCalendarMonthPart.OwnerTabContentBackground, r))
{
g.FillRectangle(br, r);
}
// Calculate our contiguous header rect
// area so we can fill it all at once
r = new Rectangle(
_MonthWeeks[0].DayRects[dayStart].Bounds.X, ClientRect.Y,
_MonthWeeks[0].DayRects[dayEnd].Bounds.Right -
_MonthWeeks[0].DayRects[dayStart].Bounds.X, DayOfWeekHeaderHeight);
if (r.Width > 0 && r.Height > 0)
{
using (Brush lbr =
_ViewColor.BrushPart((int)eCalendarMonthPart.DayOfTheWeekHeaderBackground, r))
{
g.FillRectangle(lbr, r);
}
// Establish our Days Of The Week text type
DaysOfTheWeek.eDayType type = GetDaysOfTheWeekType(g);
// Loop through each day, drawing the
// day of the week text in the header area
eTextFormat tf = eTextFormat.VerticalCenter | eTextFormat.NoPadding;
using (Pen pen = new Pen(
_ViewColor.GetColor((int)eCalendarMonthPart.DayOfTheWeekHeaderBorder)))
{
for (int i = dayStart; i <= dayEnd; i++)
{
r.X = _MonthWeeks[0].DayRects[i].Bounds.X;
r.Width = _MonthWeeks[0].DayRects[i].Bounds.Width;
if (CalendarView.DoPreRenderMonthHeader(g, this, i, r) == false)
{
// Center the header text until the text
// will no longer fit, then left justify it
if (DaysOfTheWeek.DaySize[(int) type][i].Width < r.Width)
tf |= eTextFormat.HorizontalCenter;
// Draw the text and header border
TextDrawing.DrawString(g, DaysOfTheWeek.DayText[(int) type][i], Font,
_ViewColor.GetColor((int) eCalendarMonthPart.DayOfTheWeekHeaderForeground), r, tf);
CalendarView.DoPostRenderMonthHeader(g, this, i, r);
}
g.DrawRectangle(pen, r);
}
}
}
}
#endregion
#region GetDaysOfTheWeekType
private DaysOfTheWeek.eDayType GetDaysOfTheWeekType(Graphics g)
{
// Determine if the current DayRect bounds
// are constrained by the text threshold
DaysOfTheWeek.MeasureText(g, Font);
for (int i = 0; i < DaysInWeek; i++)
{
if (_MonthWeeks[0].DayRects[i].Bounds.Width <
DaysOfTheWeek.DaySize[(int)DaysOfTheWeek.eDayType.Long][i].Width)
{
return (DaysOfTheWeek.eDayType.Short);
}
}
return (DaysOfTheWeek.eDayType.Long);
}
#endregion
#endregion
#region Day drawing
#region DrawDays
/// <summary>
/// Draws day header and content
/// </summary>
/// <param name="e">ItemPaintArgs</param>
/// <param name="weekStart">Week start index</param>
/// <param name="weekEnd">Week end index</param>
/// <param name="dayStart">Day start index</param>
/// <param name="dayEnd">Day end index</param>
private void DrawDays(ItemPaintArgs e,
int weekStart, int weekEnd, int dayStart, int dayEnd)
{
Graphics g = e.Graphics;
Rectangle r = new Rectangle(
_MonthWeeks[0].DayRects[dayStart].Bounds.X, 0,
_MonthWeeks[0].DayRects[dayEnd].Bounds.Right -
_MonthWeeks[0].DayRects[dayStart].Bounds.X, DayHeaderHeight);
if (r.Width > 0 && r.Height > 0)
{
// Loop through each day in each week, displaying
// the associated day content and header
int nowHeaderWeek = -1;
int nowHeaderDay = -1;
DateTime now = DateTime.Now;
using (Pen pen1 = new Pen(
_ViewColor.GetColor((int) eCalendarMonthPart.DayContentBorder)))
{
using (Pen pen2 = new Pen(
_ViewColor.GetColor((int) eCalendarMonthPart.DayHeaderBorder)))
{
for (int i = weekStart; i <= weekEnd; i++)
{
for (int j = dayStart; j <= dayEnd; j++)
{
if (CalendarView.HighlightCurrentDay == true)
{
DateTime date = _MonthWeeks[i].FirstDayOfWeek.AddDays(j);
if (now.Date.Equals(date.Date) == true)
{
nowHeaderDay = i;
nowHeaderWeek = j;
continue;
}
}
DrawDayBackground(g, i, j, eCalendarMonthPart.DayHeaderBackground);
DrawDayContent(g, i, j, pen1);
DrawDayHeader(g, i, j, pen2);
}
}
}
}
// Draw "Now" day header and border
if (nowHeaderDay >= 0)
{
using (Pen pen1 = new Pen(
_ViewColor.GetColor((int) eCalendarMonthPart.NowDayHeaderBorder)))
{
using (Pen pen2 = new Pen(
_ViewColor.GetColor((int) eCalendarMonthPart.NowDayHeaderBorder)))
{
DrawDayBackground(g, nowHeaderDay, nowHeaderWeek, eCalendarMonthPart.NowDayHeaderBackground);
DrawDayContent(g, nowHeaderDay, nowHeaderWeek, pen1);
DrawDayHeader(g, nowHeaderDay, nowHeaderWeek, pen2);
}
}
}
}
}
#region DrawDayBackground
/// <summary>
/// DrawDayBackground
/// </summary>
/// <param name="g"></param>
/// <param name="week"></param>
/// <param name="day"></param>
/// <param name="part"></param>
private void DrawDayBackground(Graphics g,
int week, int day, eCalendarMonthPart part)
{
Rectangle r = _MonthWeeks[week].DayRects[day].Bounds;
r.Height = DayHeaderHeight;
using (Brush br = _ViewColor.BrushPart((int)part, r))
g.FillRectangle(br, r);
}
#endregion
#endregion
#region DrawDayContent
/// <summary>
/// Draws the day content
/// </summary>
/// <param name="g"></param>
/// <param name="iweek">Week index</param>
/// <param name="iday">Day index</param>
/// <param name="pen">Pen</param>
private void DrawDayContent(Graphics g, int iweek, int iday, Pen pen)
{
Rectangle r = _MonthWeeks[iweek].DayRects[iday].Bounds;
r.Y += DayHeaderHeight;
r.Height -= DayHeaderHeight;
DrawBackground(g, iweek, iday, r);
DrawMoreImage(g, iweek, iday, r);
DrawBorder(g, pen, iweek, r);
}
#region DrawBackground
private void DrawBackground(Graphics g,
int iweek, int iday, Rectangle r)
{
DateTime date = _MonthWeeks[iweek].FirstDayOfWeek.AddDays(iday);
int dayMonth = date.Month;
DateTime startTime = date;
DateTime endTime = date.AddDays(1).AddMinutes(-1);
eSlotDisplayState state = GetSlotState(iweek, iday, dayMonth);
if (CalendarView.DoMonthViewPreRenderSlotBackground(
g, this, startTime, endTime, r, ref state) == false)
{
eCalendarMonthPart part = GetContentPart(state);
using (Brush br = _ViewColor.BrushPart((int)part, r))
g.FillRectangle(br, r);
CalendarView.DoMonthViewPostRenderSlotBackground(
g, this, startTime, endTime, r, state);
}
}
#region GetSlotState
/// <summary>
/// GetSlotState
/// </summary>
/// <returns></returns>
private eSlotDisplayState
GetSlotState(int iweek, int iday, int dayMonth)
{
eSlotDisplayState state = eSlotDisplayState.None;
if (DisplayedOwnerKeyIndex == CalendarView.SelectedOwnerIndex)
{
if (_MonthWeeks[iweek].DayRects[iday].IsSelected)
state |= eSlotDisplayState.Selected;
}
if (dayMonth == StartDate.Month)
state |= eSlotDisplayState.Work;
return (state);
}
#endregion
#region GetContentPart
/// <summary>
/// Gets the content calendar part for the given
/// week and dayMonth
/// </summary>
/// <returns></returns>
private eCalendarMonthPart GetContentPart(eSlotDisplayState state)
{
if ((state & eSlotDisplayState.Selected) == eSlotDisplayState.Selected)
return (eCalendarMonthPart.DayContentSelectionBackground);
if ((state & eSlotDisplayState.Work) == eSlotDisplayState.Work)
return (eCalendarMonthPart.DayContentActiveBackground);
return (eCalendarMonthPart.DayContactInactiveBackground);
}
#endregion
#endregion
#region DrawMoreImage
private void DrawMoreImage(Graphics g, int iweek, int iday, Rectangle r)
{
ItemRect moreRect = _MonthWeeks[iweek].MoreItems[iday];
if (moreRect.Bounds.IsEmpty == false)
{
Bitmap bm = moreRect.IsSelected ? GetMoreImageHot(g) : GetMoreImage(g);
if (bm != null)
{
Region regSave = g.Clip;
g.SetClip(r, CombineMode.Intersect);
g.DrawImageUnscaledAndClipped(bm, moreRect.Bounds);
g.Clip = regSave;
}
}
}
#endregion
#region DrawBorder
private void DrawBorder(
Graphics g, Pen pen, int iweek, Rectangle r)
{
if (iweek < _NumberOfWeeks - 1)
r.Height--;
g.DrawRectangle(pen, r);
}
#endregion
#endregion
#region DrawDayHeader
/// <summary>
/// Draws day header
/// </summary>
/// <param name="g"></param>
/// <param name="iweek">Week index</param>
/// <param name="iday">Day index</param>
/// <param name="pen">Text pen</param>
private void DrawDayHeader(Graphics g, int iweek, int iday, Pen pen)
{
// Calculate the display rect and draw the text
Rectangle r = _MonthWeeks[iweek].DayRects[iday].Bounds;
r.Height = Math.Min(DayHeaderHeight, r.Height);
if (r.Height > 0)
{
// Draw the border area
g.DrawRectangle(pen, r);
// Get the associated day and text
DateTime day = _MonthWeeks[iweek].FirstDayOfWeek.AddDays(iday);
string s = GetDayHeaderText(day);
r.Inflate(-2, 0);
TextDrawing.DrawString(g, s, BoldFont,
_ViewColor.GetColor((int)eCalendarMonthPart.DayHeaderForeground), r,
eTextFormat.VerticalCenter | eTextFormat.Left | eTextFormat.NoPadding);
}
}
#region GetDayHeaderText
/// <summary>
/// GetDayHeaderText
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
private string GetDayHeaderText(DateTime date)
{
if (date.Day == 1)
{
DateTimeFormatInfo dtfi =
ScheduleSettings.GetActiveCulture().DateTimeFormat;
string s = dtfi.MonthDayPattern.Replace("dd", "d");
return (date.ToString(s));
}
return (String.Format("{0}", date.Day));
}
#endregion
#endregion
#endregion
#region DrawWeekAppointments
/// <summary>
/// Initiates the drawing of weekly appointments
/// </summary>
/// <param name="e">ItemPaintArgs</param>
/// <param name="weekStart">Week start index</param>
/// <param name="weekEnd">Week end index</param>
private void DrawWeekAppointments(ItemPaintArgs e, int weekStart, int weekEnd)
{
Graphics g = e.Graphics;
// Loop through each subItem - on a weekly basis - so that
// we can set an appropriate clipping region for the week
for (int i = weekStart; i <= weekEnd; i++)
{
List<CalendarItem> items = _MonthWeeks[i].CalendarItems;
if (items.Count > 0)
{
// Set our week-based clipping region
Rectangle r = _MonthWeeks[i].Bounds;
r.Height -= 1;
Region regSave = g.Clip;
g.SetClip(r, CombineMode.Intersect);
// Loop through each CalendarItem in the week
for (int j = 0; j < items.Count; j++)
{
// If we can display the item, then initiate the paint
if (items[j].Displayed == true)
{
if (e.ClipRectangle.IsEmpty ||
e.ClipRectangle.IntersectsWith(items[j].DisplayRectangle))
{
items[j].Paint(e);
}
}
}
// Restore the original clip region
g.Clip = regSave;
regSave.Dispose();
}
}
}
#endregion
#region GetMoreImage
private Bitmap GetMoreImage(Graphics g)
{
if (_MoreImage == null)
_MoreImage = GetMoreBitmap(g, Color.LightGray);
return (_MoreImage);
}
#endregion
#region GetMoreImageHot
private Bitmap GetMoreImageHot(Graphics g)
{
if (_MoreImageHot == null)
_MoreImageHot = GetMoreBitmap(g, _ViewColor.GetColor((int)eCalendarMonthPart.NowDayHeaderBorder));
return (_MoreImageHot);
}
#endregion
#region GetMoreBitmap
private Bitmap GetMoreBitmap(Graphics g, Color color)
{
Bitmap bmp = new Bitmap(_MoreImageSize.Width, _MoreImageSize.Height, g);
using (Graphics gBmp = Graphics.FromImage(bmp))
{
gBmp.CompositingQuality = CompositingQuality.HighQuality;
gBmp.SmoothingMode = SmoothingMode.AntiAlias;
using (GraphicsPath path = GetMoreImagePath())
{
using (Brush br = new SolidBrush(color))
gBmp.FillPath(br, path);
gBmp.DrawPath(Pens.White, path);
}
}
return (bmp);
}
#endregion
#region GetMoreImagePath
/// <summary>
/// Gets the More image path
/// </summary>
/// <returns></returns>
private GraphicsPath GetMoreImagePath()
{
GraphicsPath path = new GraphicsPath();
path.AddLines(new Point[]
{
new Point(2, 3),
new Point(7, 11),
new Point(12, 3)
});
path.CloseAllFigures();
return (path);
}
#endregion
#region SideBar header drawing
/// <summary>
/// Draws the SideBar header
/// </summary>
/// <param name="e">ItemPaintArgs</param>
/// <param name="weekStart">Week start index</param>
/// <param name="weekEnd">Week end index</param>
private void DrawSideBarHeader(ItemPaintArgs e, int weekStart, int weekEnd)
{
// Calc the contiguous SideBar background rect
Rectangle r = new Rectangle(ClientRect.X, _MonthWeeks[weekStart].Bounds.Y,
SideBarWidth, _MonthWeeks[weekEnd].Bounds.Bottom - _MonthWeeks[weekStart].Bounds.Y);
// Make sure we have something to draw
if (r.Height > 0 && r.Width > 0 && e.ClipRectangle.IntersectsWith(r))
{
Graphics g = e.Graphics;
// Fill the bar with our color gradient
using (Brush lbr = _ViewColor.BrushPart((int)eCalendarMonthPart.SideBarBackground, r))
{
g.FillRectangle(lbr, r);
}
// Set uo our output to have both
// vertically and horizontally centered text
using (StringFormat sf = new StringFormat())
{
sf.FormatFlags = StringFormatFlags.NoWrap;
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
// Calc our rect origin and prepare to
// output the SideBar text
PointF ptf = new PointF(ClientRect.X, 0);
Rectangle rf = new Rectangle(0, 0, 0, SideBarWidth);
using (Brush br =
_ViewColor.BrushPart((int)eCalendarMonthPart.SideBarForeground, rf))
{
using (Pen pen = new Pen(
_ViewColor.GetColor((int)eCalendarMonthPart.SideBarBorder)))
{
// Loop through each individual week, displaying
// the rotated header text appropriately
for (int i = weekStart; i <= weekEnd; i++)
{
rf.Width = _MonthWeeks[i].Bounds.Height;
if (rf.Width > 0)
{
ptf.Y = _MonthWeeks[i].Bounds.Y + rf.Width;
g.TranslateTransform(ptf.X, ptf.Y);
g.RotateTransform(-90);
g.DrawString(_MonthWeeks[i].WeekRange, Font, br, rf, sf);
g.DrawRectangle(pen, rf.X, rf.Y, rf.Width, rf.Height);
g.ResetTransform();
}
}
}
}
}
}
}
#endregion
#endregion
#region Mouse routines
#region MouseDown processing
/// <summary>
/// MouseDown event processing
/// </summary>
/// <param name="objArg"></param>
public override void InternalMouseDown(MouseEventArgs objArg)
{
// Forward on the event
base.InternalMouseDown(objArg);
if (objArg.Button == MouseButtons.Left)
{
if (IsTabMoving == false)
{
// Locate where the event took place
int week, day;
if (GetPointItem(objArg.Location, out week, out day))
{
MyCursor = GetCursor();
if (ProcessCilButtonDown(week, day) == false)
{
if (ProcessMoreButtonDown(week, day) == false)
ProcessMvlButtonDown(week, day);
}
}
IsCopyDrag = false;
}
}
}
#region CalendarItem MouseDown processing
/// <summary>
/// CalendarItem left mouseDown processing
/// </summary>
/// <param name="week">Week index</param>
/// <param name="day">Day index</param>
private bool ProcessCilButtonDown(int week, int day)
{
CalendarItem item = m_HotSubItem as CalendarItem;
if (item != null)
{
if (item.HitArea != CalendarItem.eHitArea.None)
{
// Give the user a chance to cancel the
// operation before it starts
if (CalendarView.DoBeforeAppointmentViewChange(this, item,
((item.HitArea == CalendarItem.eHitArea.Move) ?
eViewOperation.AppointmentMove : eViewOperation.AppointmentResize)) == false)
{
if (IsResizing == false && IsMoving == false)
{
OldStartTime = item.StartTime;
OldEndTime = item.EndTime;
OldOwnerKey = OwnerKey;
}
// Flag appropriate action
if (item.HitArea == CalendarItem.eHitArea.LeftResize)
IsStartResizing = true;
else if (item.HitArea == CalendarItem.eHitArea.RightResize)
IsEndResizing = true;
else if (item.HitArea == CalendarItem.eHitArea.Move)
{
TimeSpan ts = _MonthWeeks[week].FirstDayOfWeek.AddDays(day) - item.StartTime;
_DaysOffset = (int)(Math.Ceiling(ts.TotalDays));
IsMoving = true;
}
}
}
return (true);
}
return (false);
}
#endregion
#region MonthView MouseDown processing
/// <summary>
/// Handles MonthView left MouseDown events
/// </summary>
/// <param name="week">Week index</param>
/// <param name="day">Day index</param>
private void ProcessMvlButtonDown(int week, int day)
{
DateTime startDate = _MonthWeeks[week].FirstDayOfWeek.AddDays(day);
DateTime endDate = startDate.AddDays(1);
ExtendSelection(ref startDate, ref endDate);
CalendarView.DateSelectionStart = startDate;
CalendarView.DateSelectionEnd = endDate;
SelectedItem = null;
}
#endregion
#region MoreItems MouseDown processing
/// <summary>
/// ProcessMoreButtonDown
/// </summary>
/// <param name="week"></param>
/// <param name="day"></param>
/// <returns></returns>
private bool ProcessMoreButtonDown(int week, int day)
{
if (CalendarView.IsMonthMoreItemsIndicatorVisible == true)
{
ItemRect moreRect = _MonthWeeks[week].MoreItems[day];
if (moreRect.IsSelected == true)
{
eCalendarView calendarView = eCalendarView.Day;
DateTime startDate = _MonthWeeks[week].FirstDayOfWeek.AddDays(day);
if (CalendarView.DoMonthMoreItemsIndicatorClick(
this, ref calendarView, ref startDate) == false)
{
moreRect.IsSelected = false;
DateSelectionAnchor = null;
CalendarView.DateSelectionStart = null;
CalendarView.DateSelectionEnd = null;
CalendarView.SelectedView = calendarView;
CalendarView.EnsureVisible(startDate, startDate);
}
return (true);
}
}
return (false);
}
#endregion
#endregion
#region MouseMove processing
/// <summary>
/// MouseMove event processing
/// </summary>
/// <param name="objArg">MouseEventArgs</param>
public override void InternalMouseMove(MouseEventArgs objArg)
{
// Forward on the event, but only if we are not in
// the middle of moving or resizing a CalendarItem
if (Control.MouseButtons == MouseButtons.None)
ClearMouseStates();
if (!IsMoving && !IsStartResizing && !IsEndResizing)
base.InternalMouseMove(objArg);
if (IsTabMoving == false)
{
// Set the cursor
MyCursor = GetCursor();
int week, day;
bool inItem = GetPointItem(objArg.Location, out week, out day);
switch (objArg.Button)
{
case MouseButtons.Left:
if (DragDropAppointment(objArg) == false)
{
// Locate where the event took place
// and process it accordingly
if (inItem == true)
{
if (DateSelectionAnchor != null)
{
ProcessMvMouseMove(week, day);
}
else if (SelectedItem != null)
{
if (IsMoving == true)
ProcessItemMove(week, day);
else if (IsStartResizing == true)
ProcessItemLeftResize(week, day);
else if (IsEndResizing == true)
ProcessItemRightResize(week, day);
}
}
}
break;
case MouseButtons.None:
if (inItem == true)
ProcessMoreMouseMove(week, day, objArg);
break;
}
}
}
#region GetCursor
/// <summary>
/// Gets the cursor
/// </summary>
/// <returns>Cursor</returns>
private Cursor GetCursor()
{
CalendarItem item = m_HotSubItem as CalendarItem;
if (item != null)
{
switch (item.HitArea)
{
case CalendarItem.eHitArea.LeftResize:
case CalendarItem.eHitArea.RightResize:
return (Cursors.SizeWE);
case CalendarItem.eHitArea.Move:
return (IsMoving ? Cursors.SizeAll : DefaultCursor);
}
}
return (DefaultCursor);
}
#endregion
#region DragDropAppointment
/// <summary>
/// Initiates a user "DragDrop" operation - if enabled
/// </summary>
/// <param name="objArgs"></param>
/// <returns>True if operation started</returns>
private bool DragDropAppointment(MouseEventArgs objArgs)
{
if (IsMoving == true && CanDrag == true)
{
Point pt = objArgs.Location;
BaseView bv = CalendarView.GetViewFromPoint(pt);
MonthView mv = bv as MonthView;
if (mv != null && mv != this)
{
eViewArea area = mv.GetViewAreaFromPoint(pt);
if (area == eViewArea.InContent)
{
bool isNewCopyDrag = IsNewCopyDrag;
if (CalendarView.DoAppointmentViewChanging(SelectedItem, mv.OwnerKey, SelectedItem.StartTime,
SelectedItem.EndTime, eViewOperation.AppointmentMove, isNewCopyDrag) == false)
{
DragCopy();
ClearMouseStates();
if (PosWin != null)
PosWin.Hide();
AppointmentView av = SelectedItem as AppointmentView;
if (av != null)
return (mv.DragAppointment(this, av, pt, isNewCopyDrag));
CustomCalendarItem ci = SelectedItem as CustomCalendarItem;
if (ci != null)
return (mv.DragCustomItem(this, ci, pt, isNewCopyDrag));
}
}
}
}
return (false);
}
#region DragCustomItem
private bool DragCustomItem(
MonthView pv, CustomCalendarItem ci, Point pt, bool isNewCopyDrag)
{
// Set the new owner and selected view, and
// recalc the new layout
ci.OwnerKey = OwnerKey;
DateTime sd = ci.StartTime;
TimeSpan ts = ci.EndTime.Subtract(ci.StartTime);
int week = GetPointWeek(pt);
int day = GetPointDay(pt, week);
MonthWeek mw = _MonthWeeks[week];
DateTime date = mw.FirstDayOfWeek.AddDays(day - pv._DaysOffset);
ci.StartTime = new
DateTime(date.Year, date.Month, date.Day, sd.Hour, sd.Minute, 0);
ci.EndTime = ci.StartTime.Add(ts);
NeedRecalcLayout = true;
RecalcSize();
CalendarView.SelectedOwnerIndex = this.DisplayedOwnerKeyIndex;
// Get the new view
CustomCalendarItem view = GetCustomCalendarItem(ci);
if (view != null)
SetNewDragItem(pv, view, isNewCopyDrag);
return (true);
}
#endregion
#region DragAppointment
/// <summary>
/// Drags the given appointment from one view to another
/// </summary>
/// <param name="pv">Previous view</param>
/// <param name="av">AppointmentView</param>
/// <param name="pt">Point</param>
private bool DragAppointment(
MonthView pv, AppointmentView av, Point pt, bool isNewCopyDrag)
{
// Set the new owner and selected view, and
// recalc the new layout
av.Appointment.OwnerKey = OwnerKey;
DateTime sd = av.Appointment.StartTime;
int week = GetPointWeek(pt);
if (week >= 0)
{
int day = GetPointDay(pt, week);
MonthWeek mw = _MonthWeeks[week];
DateTime date = mw.FirstDayOfWeek.AddDays(day - pv._DaysOffset);
av.Appointment.MoveTo(
new DateTime(date.Year, date.Month, date.Day, sd.Hour, sd.Minute, 0));
NeedRecalcLayout = true;
RecalcSize();
CalendarView.SelectedOwnerIndex = this.DisplayedOwnerKeyIndex;
// Get the new appointment view
AppointmentView view = GetAppointmentView(av.Appointment);
if (view != null)
SetNewDragItem(pv, view, isNewCopyDrag);
}
return (true);
}
#endregion
#region SetNewDragItem
private void SetNewDragItem(MonthView pv, CalendarItem view, bool isNewCopyDrag)
{
CalendarView.CalendarPanel.InternalMouseMove(new
MouseEventArgs(MouseButtons.None, 0, view.Bounds.X + 5, view.Bounds.Y, 0));
MouseEventArgs args = new
MouseEventArgs(MouseButtons.Left, 1, view.Bounds.X + 5, view.Bounds.Y, 0);
IsMoving = true;
InternalMouseMove(args);
CalendarView.CalendarPanel.InternalMouseDown(args);
_DaysOffset = pv._DaysOffset;
SelectedItem = view;
IsCopyDrag = true;
IsNewCopyDrag = isNewCopyDrag;
}
#endregion
#endregion
#region MonthView mouseMove processing
/// <summary>
/// Processes MonthView mouseMove events
/// </summary>
/// <param name="week"></param>
/// <param name="day"></param>
private void ProcessMvMouseMove(int week, int day)
{
DateTime date = _MonthWeeks[week].FirstDayOfWeek.AddDays(day);
// Let the user select forwards or backwards
if (date >= DateSelectionAnchor)
{
CalendarView.DateSelectionStart = DateSelectionAnchor.Value;
CalendarView.DateSelectionEnd = date.AddDays(1);
}
else
{
CalendarView.DateSelectionStart = date;
CalendarView.DateSelectionEnd = DateSelectionAnchor.Value.AddDays(1);
}
}
#endregion
#region MoreItems MouseMove processing
/// <summary>
/// ProcessMoreMouseMove
/// </summary>
/// <param name="week"></param>
/// <param name="day"></param>
/// <param name="objArg"></param>
private void ProcessMoreMouseMove(int week, int day, MouseEventArgs objArg)
{
ItemRect moreRect = _MonthWeeks[week].MoreItems[day];
if (moreRect.Bounds.Contains(objArg.Location) == true)
{
if (_MoreRect != moreRect)
{
if (_MoreRect != null)
_MoreRect.IsSelected = false;
_MoreRect = moreRect;
_MoreRect.IsSelected = true;
}
}
else
{
if (_MoreRect != null)
{
_MoreRect.IsSelected = false;
_MoreRect = null;
}
}
}
#endregion
#region CalendarItem mouseMove processing
/// <summary>
/// Processes CalendarItem mouseMove events
/// </summary>
/// <param name="week">Week index</param>
/// <param name="day">Day index</param>
private void ProcessItemMove(int week, int day)
{
day -= _DaysOffset;
DateTime date =
_MonthWeeks[week].FirstDayOfWeek.AddDays(day);
DateTime newDate = new DateTime(date.Year, date.Month, date.Day,
SelectedItem.StartTime.Hour, SelectedItem.StartTime.Minute,
SelectedItem.StartTime.Second);
TimeSpan ts = SelectedItem.EndTime - SelectedItem.StartTime;
int startWeek1, endWeek1;
int day1 = GetCalendarItemWeekRange(SelectedItem, out startWeek1, out endWeek1);
if (startWeek1 != week || day1 != day)
{
if (DragCopy() == false)
{
try
{
if (SelectedItem is CustomCalendarItem)
CalendarView.CustomItems.BeginUpdate();
else
CalendarModel.BeginUpdate();
// Let the user cancel the operation if desired
if (CalendarView.DoAppointmentViewChanging(SelectedItem, null, newDate,
newDate + ts, eViewOperation.AppointmentMove, IsNewCopyDrag) == false)
{
SelectedItem.StartTime = newDate;
SelectedItem.EndTime = newDate + ts;
int startWeek2, endWeek2;
GetCalendarItemWeekRange(SelectedItem, out startWeek2, out endWeek2);
startWeek1 = Math.Min(startWeek1, startWeek2);
endWeek1 = Math.Max(endWeek1, endWeek2);
for (int i = startWeek1; i <= endWeek1; i++)
InvalidateRect(_MonthWeeks[i].Bounds, true);
}
}
finally
{
if (SelectedItem is CustomCalendarItem)
CalendarView.CustomItems.EndUpdate();
else
CalendarModel.EndUpdate();
}
}
}
}
/// <summary>
/// Gets the CalendarItems current week/day range
/// </summary>
/// <param name="item">CalendarItem</param>
/// <param name="startWeek">[out] Start week index</param>
/// <param name="endWeek">[out] End week index</param>
/// <returns>Day index</returns>
private int GetCalendarItemWeekRange(
CalendarItem item, out int startWeek, out int endWeek)
{
startWeek = -1;
endWeek = -1;
int day = 0;
for (int i = 0; i < _NumberOfWeeks; i++)
{
DateTime startTime = _MonthWeeks[i].FirstDayOfWeek;
DateTime endTime = startTime.AddDays(DaysInWeek);
if (item.StartTime < endTime && item.EndTime > startTime)
{
if (startWeek < 0)
{
startWeek = i;
day = item.StartTime.Day - startTime.Day;
}
endWeek = i;
}
}
if (startWeek == -1)
{
startWeek = 0;
endWeek = _NumberOfWeeks - 1;
day = 0;
}
return (day);
}
#endregion
#region CalendarItem mouseResize processing
/// <summary>
/// Processes CalendarItem left resizing
/// </summary>
/// <param name="week">Week index</param>
/// <param name="day">Day index</param>
private void ProcessItemLeftResize(int week, int day)
{
DateTime date =
_MonthWeeks[week].FirstDayOfWeek.AddDays(day);
DateTime newStartTime = new DateTime(date.Year, date.Month, date.Day,
SelectedItem.StartTime.Hour, SelectedItem.StartTime.Minute,
SelectedItem.StartTime.Second);
if (newStartTime < SelectedItem.EndTime && SelectedItem.StartTime != newStartTime)
{
// Let the user cancel the operation if desired
if (CalendarView.DoAppointmentViewChanging(SelectedItem, null, newStartTime,
SelectedItem.EndTime, eViewOperation.AppointmentResize, IsNewCopyDrag) == false)
{
SelectedItem.StartTime = newStartTime;
InvalidateRect(true);
}
}
}
/// <summary>
/// Processes CalendarItem right resizing
/// </summary>
/// <param name="week">Week index</param>
/// <param name="day">Day index</param>
private void ProcessItemRightResize(int week, int day)
{
DateTime date =
_MonthWeeks[week].FirstDayOfWeek.AddDays(day);
DateTime newEndTime = new DateTime(date.Year, date.Month, date.Day,
SelectedItem.EndTime.Hour, SelectedItem.EndTime.Minute,
SelectedItem.EndTime.Second);
if (newEndTime.Hour == 0 && newEndTime.Minute == 0 && newEndTime.Second == 0)
newEndTime = newEndTime.AddDays(1);
if (newEndTime > SelectedItem.StartTime && SelectedItem.EndTime != newEndTime)
{
// Let the user cancel the operation if desired
if (CalendarView.DoAppointmentViewChanging(SelectedItem, null, SelectedItem.StartTime,
newEndTime, eViewOperation.AppointmentResize, IsNewCopyDrag) == false)
{
SelectedItem.EndTime = newEndTime;
InvalidateRect(true);
}
}
}
#endregion
#endregion
#region Mouse support routines
/// <summary>
/// Gets the week and day index item for
/// the given point
/// </summary>
/// <param name="pt">Point</param>
/// <param name="week">[out] Week index</param>
/// <param name="day">[out] Day index</param>
/// <returns>Success or failure</returns>
private bool GetPointItem(Point pt, out int week, out int day)
{
day = -1;
if ((week = GetPointWeek(pt)) >= 0)
{
if ((day = GetPointDay(pt, week)) >= 0)
return (true);
}
return (false);
}
/// <summary>
/// Gets the week index for the given point
/// </summary>
/// <param name="pt">Point</param>
/// <returns>Week index</returns>
private int GetPointWeek(Point pt)
{
for (int i = 0; i < _NumberOfWeeks; i++)
{
Rectangle r = _MonthWeeks[i].Bounds;
if (pt.X >= r.X && pt.X <= r.Right && pt.Y > r.Y && pt.Y < r.Bottom)
return (i);
}
return (-1);
}
/// <summary>
/// Gets the day index for the given point
/// </summary>
/// <param name="pt">Point</param>
/// <param name="week">Week index</param>
/// <returns>Day index</returns>
private int GetPointDay(Point pt, int week)
{
ItemRects rs = _MonthWeeks[week].DayRects;
for (int i = 0; i < DaysInWeek; i++)
{
Rectangle r = rs[i].Bounds;
if (pt.X >= r.X && pt.X <= r.Right && pt.Y > r.Y && pt.Y < r.Bottom)
return (i);
}
return (-1);
}
#endregion
#endregion
#region InternalKeyDown
#region InternalKeyDown
/// <summary>
/// Processes KeyDown events
/// </summary>
/// <param name="objArg"></param>
public override void InternalKeyDown(KeyEventArgs objArg)
{
switch (objArg.KeyData)
{
case Keys.Up:
case Keys.Up | Keys.Shift:
case Keys.Up | Keys.Control:
case Keys.Up | Keys.Control | Keys.Shift:
ProcessUpDownKey(objArg, -7);
break;
case Keys.Down:
case Keys.Down | Keys.Shift:
case Keys.Down | Keys.Control:
case Keys.Down | Keys.Control | Keys.Shift:
ProcessUpDownKey(objArg, 7);
break;
case Keys.Left:
case Keys.Left | Keys.Shift:
case Keys.Left | Keys.Control:
case Keys.Left | Keys.Control | Keys.Shift:
ProcessLeftRightKey(objArg, -1);
break;
case Keys.Right:
case Keys.Right | Keys.Shift:
case Keys.Right | Keys.Control:
case Keys.Right | Keys.Control | Keys.Shift:
ProcessLeftRightKey(objArg, 1);
break;
case Keys.Home:
case Keys.Home | Keys.Shift:
case Keys.Home | Keys.Control:
case Keys.Home | Keys.Control | Keys.Shift:
ProcessHomeKey(objArg);
break;
case Keys.End:
case Keys.End | Keys.Shift:
case Keys.End | Keys.Control:
case Keys.End | Keys.Control | Keys.Shift:
ProcessEndKey(objArg);
break;
case Keys.PageUp:
case Keys.PageUp | Keys.Shift:
case Keys.PageUp | Keys.Control:
case Keys.PageUp | Keys.Control | Keys.Shift:
ProcessUpDownKey(objArg, -7);
break;
case Keys.PageDown:
case Keys.PageDown | Keys.Shift:
case Keys.PageDown | Keys.Control:
case Keys.PageDown | Keys.Control | Keys.Shift:
ProcessUpDownKey(objArg, 7);
break;
}
}
#endregion
#region ProcessUpDownKey
/// <summary>
/// Processes Up and Down Key events
/// </summary>
/// <param name="objArg"></param>
/// <param name="dy"></param>
protected virtual void ProcessUpDownKey(KeyEventArgs objArg, int dy)
{
if (ValidDateSelection())
{
DateTime startDate = CalendarView.DateSelectionStart.Value;
DateTime endDate = CalendarView.DateSelectionEnd.Value;
if (startDate.Equals(DateSelectionAnchor.Value) == true)
startDate = endDate.AddDays(-1);
startDate = startDate.AddDays(dy);
endDate = startDate.AddDays(1);
int week = GetWeekFromDate(startDate);
if (week >= 0)
{
ExtendSelection(ref startDate, ref endDate);
CalendarView.DateSelectionStart = startDate;
CalendarView.DateSelectionEnd = endDate;
}
}
objArg.Handled = true;
}
#endregion
#region ProcessLeftRightKey
/// <summary>
/// Processes Left and Right key events
/// </summary>
/// <param name="objArg"></param>
/// <param name="dx"></param>
protected virtual void ProcessLeftRightKey(KeyEventArgs objArg, int dx)
{
if (ValidDateSelection())
{
DateTime startDate = CalendarView.DateSelectionStart.Value;
DateTime endDate = CalendarView.DateSelectionEnd.Value;
if (startDate.Equals(DateSelectionAnchor.Value) == true)
startDate = endDate.AddDays(-1);
startDate = startDate.AddDays(dx);
endDate = startDate.AddDays(1);
DateTime viewStart = _MonthWeeks[0].FirstDayOfWeek;
DateTime viewEnd = _MonthWeeks[_MonthWeeks.Length - 1].FirstDayOfWeek.AddDays(7);
bool cancelled = false;
if (startDate < viewStart || endDate > viewEnd)
{
cancelled = CalendarView.DoViewDateChanging(this,
StartDate, EndDate, ref startDate, ref endDate);
if (cancelled == false)
CalendarView.EnsureVisible(startDate, startDate.AddDays(1));
}
if (cancelled == false)
{
ExtendSelection(ref startDate, ref endDate);
CalendarView.DateSelectionStart = startDate;
CalendarView.DateSelectionEnd = endDate;
}
}
objArg.Handled = true;
}
#endregion
#region ProcessHomeKey
/// <summary>
/// Processes Hoe key events
/// </summary>
/// <param name="objArg"></param>
protected virtual void ProcessHomeKey(KeyEventArgs objArg)
{
int week = ((objArg.Modifiers & Keys.Control) != Keys.Control)
? GetHomeEndWeek()
: 0;
if (week >= 0)
{
DateTime startDate = _MonthWeeks[week].FirstDayOfWeek;
DateTime endDate = startDate.AddDays(1);
ExtendSelection(ref startDate, ref endDate);
CalendarView.DateSelectionStart = startDate;
CalendarView.DateSelectionEnd = endDate;
SelectedItem = null;
}
objArg.Handled = true;
}
#endregion
#region ProcessEndKey
/// <summary>
/// Processes End key events
/// </summary>
/// <param name="objArg"></param>
protected virtual void ProcessEndKey(KeyEventArgs objArg)
{
int week = ((objArg.Modifiers & Keys.Control) != Keys.Control)
? GetHomeEndWeek()
: _NumberOfWeeks - 1;
if (week >= 0)
{
DateTime startDate = _MonthWeeks[week].FirstDayOfWeek.AddDays(6);
DateTime endDate = startDate.AddDays(1);
ExtendSelection(ref startDate, ref endDate);
CalendarView.DateSelectionStart = startDate;
CalendarView.DateSelectionEnd = endDate;
SelectedItem = null;
}
objArg.Handled = true;
}
#endregion
#region GetWeekFromDate
/// <summary>
/// Gets the week containing the given date
/// </summary>
/// <param name="date"></param>
/// <returns>Week or -1</returns>
private int GetWeekFromDate(DateTime date)
{
for (int i = 0; i < _NumberOfWeeks; i++)
{
DateTime dc = _MonthWeeks[i].FirstDayOfWeek;
if (dc <= date && dc.AddDays(7) > date)
return (i);
}
return (-1);
}
#endregion
#region GetHomeEndWeek
/// <summary>
/// Gets the Home and End week from the
/// current selection range
/// </summary>
/// <returns></returns>
private int GetHomeEndWeek()
{
if (ValidDateSelection() == true)
{
if (CalendarView.DateSelectionStart.Equals(DateSelectionAnchor.Value) == true)
return (GetWeekFromDate(DateSelectionEnd.Value.AddDays(-1)));
return (GetWeekFromDate(DateSelectionStart.Value));
}
return (-1);
}
#endregion
#endregion
#region IDisposable Members
protected override void Dispose(bool disposing)
{
if (disposing == true && IsDisposed == false)
{
ResetView();
HookEvents(false);
}
base.Dispose(disposing);
}
#endregion
#region Copy object
/// <summary>
/// Returns copy of the item.
/// </summary>
public override BaseItem Copy()
{
MonthView objCopy = new MonthView(this.CalendarView);
CopyToItem(objCopy);
return (objCopy);
}
/// <summary>
/// Copies the MonthView specific properties to new instance of the item.
/// </summary>
/// <param name="copy">New MonthView instance</param>
protected override void CopyToItem(BaseItem copy)
{
MonthView objCopy = copy as MonthView;
if (objCopy != null)
{
base.CopyToItem(objCopy);
objCopy._IsSideBarVisible = this._IsSideBarVisible;
}
}
#endregion
}
#region EventArgs
#region IsSideBarVisibleChangedEventArgs
/// <summary>
/// IsSideBarVisibleChangedEventArgs
/// </summary>
public class IsSideBarVisibleChangedEventArgs : ValueChangedEventArgs<bool, bool>
{
public IsSideBarVisibleChangedEventArgs(bool oldValue, bool newValue)
: base(oldValue, newValue)
{
}
}
#endregion
#endregion
}
#endif