#if FRAMEWORK20 using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Windows.Forms; using DevComponents.Schedule.Model; namespace DevComponents.DotNetBar.Schedule { public class WeekDayView : BaseView { #region Constants private const int HoursPerDay = 24; private const int MinutesPerHour = 60; private const int MaxNumberOfColumns = 3 * 31; #endregion #region Private variables private AllDayPanel _AllDayPanel; // AllDay items panel private DayColumn[] _DayColumns; // Array of DayColumns private int _NumberOfColumns; // Number of DayColumns private Size[] _DayColumnSize; // Array of day text sizes private CalendarWeekDayColor _ViewColor = // View display color table new CalendarWeekDayColor(eCalendarColor.Automatic); private int _LastCol; // Last processed column private Point _LastMovePoint; // Last mouse move Point private Point _LastPointOffset; // Last Point offset private Rectangle _LastBounds; // MouseDown item bounds int _LastMoveCol; int _LastDm; private bool _IsPanelResizing; // Flag denoting panel resizing private bool _WasAllDayItem; private int _SelectedSliceStart; // Absolute slice start private int _SelectedSliceEnd; // Absolute slice end (e.g. 450 - 1440) private Timer _ScrollViewTimer; // Timer used to implement auto view scrolling private int _VScrollPos; // Vertical scroll bar pos private Color _BusyColor; // Cached brush colors private Color _WorkColor; private Color _OffWorkColor; private Color _SelectedColor; private Brush _BusyBrush; // Cached brushes private Brush _WorkBrush; private Brush _OffWorkBrush; private Brush _SelectedBrush; private Brush _AllDayBrush; private Color _AllDayColor; private int _LocalStartSlice; private int _LocalNumberOfSlices; #endregion /// /// Constructor /// /// CalendarView /// public WeekDayView(CalendarView calendarView, eCalendarView eCalendarView) : base(calendarView, eCalendarView) { // Allocate our AllDayPanel _AllDayPanel = new AllDayPanel(this); _AllDayPanel.Displayed = true; // Set our non-client drawing info and CalendarColor NClientData = new NonClientData( eTabOrientation.Horizontal, (int)eCalendarWeekDayPart.OwnerTabBorder, (int)eCalendarWeekDayPart.OwnerTabForeground, (int)eCalendarWeekDayPart.OwnerTabBackground, (int)eCalendarWeekDayPart.OwnerTabContentBackground, (int)eCalendarWeekDayPart.OwnerTabSelectedForeground, (int)eCalendarWeekDayPart.OwnerTabSelectedBackground); CalendarColorTable = _ViewColor; // Hook onto our events HookEvents(true); } #region Public properties #region DayColumns /// /// Gets the view DayColumns /// public DayColumn[] DayColumns { get { return (_DayColumns); } } #endregion #region NumberOfColumns /// /// Gets the view's number of DayColumns /// public int NumberOfColumns { get { return (_NumberOfColumns); } } #endregion #region VScrollBar /// /// Gets the WeekDay vertical scrollbar /// public VScrollBarAdv VScrollBar { get { return (CalendarView.WeekDayVScrollBar ); } } #endregion #endregion #region Internal properties #region Base calendar properties /// /// Gets the Sub-Day view rectangle /// internal Rectangle ViewRect { get { Rectangle r = ClientRect; int n = DayOfWeekHeaderHeight + _AllDayPanel.PanelHeight; r.Y += n; r.Height -= (n + 1); return (r); } } /// /// Gets the CalendarColor /// internal CalendarWeekDayColor WeekDayColor { get { return (_ViewColor); } } #endregion #region DayColumn properties /// /// Gets the local StartSlice /// internal int LocalStartSlice { get { return (_LocalStartSlice); } } /// /// Gets the local NumberOfSlices /// internal int LocalNumberOfSlices { get { return (_LocalNumberOfSlices); } } #endregion #region AllDayPanel properties /// /// Gets the view's AllDayPanel /// internal AllDayPanel AllDayPanel { get { return (_AllDayPanel); } } #endregion #endregion #region Private properties #region DayColumnWidth /// /// Gets the DayColumnWidth /// private float DayColumnWidth { get { return (((float)ClientRect.Width - 1) / _NumberOfColumns); } } #endregion #region AllDay Panel properties /// /// Gets the maximum AllDayPanel height /// private int MaximumAllDayPanelHeight { get { return (CalendarView.MaximumAllDayPanelHeight); } } #endregion #region Time Slice properties /// /// Gets the TimeSlotDuration /// private int TimeSlotDuration { get { return (CalendarView.TimeSlotDuration); } } /// /// Gets the default Time Slice height /// private float TimeSliceHeight { get { return (CalendarView.TimeSliceHeight); } set { CalendarView.TimeSliceHeight = value; } } /// /// Gets the SlotsPerHour /// private int SlotsPerHour { get { return (CalendarView.SlotsPerHour); } } /// /// Gets the NumberOfSlices /// private int NumberOfSlices { get { return (CalendarView.NumberOfSlices); } set { CalendarView.NumberOfSlices = value; } } /// /// Gets the NumberOfActiveSlices /// private int NumberOfActiveSlices { get { return (CalendarView.NumberOfActiveSlices); } } /// /// Gets the StartSlice /// private int StartSlice { get { return (CalendarView.StartSlice); } set { CalendarView.StartSlice = value; } } #endregion #region BusyBrush /// /// Gets and sets the Busy time brush /// private Brush BusyBrush { get { Color color = _ViewColor.GetColor( (int)eCalendarWeekDayPart.DayAllDayEventBackground); if (_BusyColor != color) { _BusyColor = color; BusyBrush = new SolidBrush(color); } return (_BusyBrush); } set { if (_BusyBrush != value) { if (_BusyBrush != null) _BusyBrush.Dispose(); _BusyBrush = value; } } } #endregion #region WorkBrush /// /// Gets and sets the Work time brush /// private Brush WorkBrush { get { Color color = _ViewColor.GetColor( (int)eCalendarWeekDayPart.DayWorkHoursBackground); if (_WorkColor != color) { _WorkColor = color; WorkBrush = new SolidBrush(color); } return (_WorkBrush); } set { if (_WorkBrush != value) { if (_WorkBrush != null) _WorkBrush.Dispose(); _WorkBrush = value; } } } #endregion #region OffWorkBrush /// /// Gets and sets the Off-hours work time brush /// private Brush OffWorkBrush { get { Color color = _ViewColor.GetColor( (int)eCalendarWeekDayPart.DayOffWorkHoursBackground); if (_OffWorkColor != color) { _OffWorkColor = color; OffWorkBrush = new SolidBrush(color); } return (_OffWorkBrush); } set { if (_OffWorkBrush != value) { if (_OffWorkBrush != null) _OffWorkBrush.Dispose(); _OffWorkBrush = value; } } } #endregion #region AllDayBrush /// /// Gets and sets the Off-hours work time brush /// private Brush AllDayBrush { get { Color color = _ViewColor.GetColor( (int)eCalendarWeekDayPart.DayAllDayEventBackground); if (_AllDayColor != color) { _AllDayColor = color; AllDayBrush = new SolidBrush(color); } return (_AllDayBrush); } set { if (_AllDayBrush != value) { if (_AllDayBrush != null) _AllDayBrush.Dispose(); _AllDayBrush = value; } } } #endregion #region SelectedBrush /// /// Gets and sets the selected brush /// private Brush SelectedBrush { get { Color color = _ViewColor.GetColor( (int)eCalendarWeekDayPart.SelectionBackground); if (_SelectedColor != color) { _SelectedColor = color; SelectedBrush = new SolidBrush(color); } return (_SelectedBrush); } set { if (_SelectedBrush != value) { if (_SelectedBrush != null) _SelectedBrush.Dispose(); _SelectedBrush = value; } } } #endregion #region FirstOnScreenSlice private int FirstOnScreenSlice { get { return ((int)(-_VScrollPos / TimeSliceHeight)); } } #endregion #region LastOnScreenSlice private int LastOnScreenSlice { get { return (FirstOnScreenSlice + OnScreenSlices - 1); } } #endregion #region OnScreenSlices private int OnScreenSlices { get { return ((int)Math.Ceiling(VsPanel.ScrollBar.Height / TimeSliceHeight)); } } #endregion #region VsPanel /// /// Gets the WeekDay vertical scroll panel /// private VScrollPanel VsPanel { get { return (CalendarView.WeekDayVScrollPanel); } } #endregion #endregion #region Hook / Unhook Events /// /// Routine hooks all necessary events for this control /// /// True to hook, false to unhook private void HookEvents(bool hook) { if (hook == true) { CalendarView.SelectedViewChanged += SelectedViewChanged; CalendarView.TimeSlotDurationChanged += TimeSlotDurationChanged; CalendarView.FixedAllDayPanelHeightChanged += FixedAllDayPanelHeightChanged; CalendarView.MaximumAllDayPanelHeightChanged += MaximumAllDayPanelHeightChanged; CalendarView.WeekDayVScrollPanel.ScrollBarChanged += VScrollPanelScrollBarChanged; if (this.ECalendarView == eCalendarView.Day) { CalendarView.DayViewDateChanged += DayViewDateChanged; } else { CalendarView.WeekViewStartDateChanged += WeekViewStartDateChanged; CalendarView.WeekViewEndDateChanged += WeekViewEndDateChanged; } } else { CalendarView.SelectedViewChanged -= SelectedViewChanged; CalendarView.TimeSlotDurationChanged -= TimeSlotDurationChanged; CalendarView.FixedAllDayPanelHeightChanged -= FixedAllDayPanelHeightChanged; CalendarView.MaximumAllDayPanelHeightChanged -= MaximumAllDayPanelHeightChanged; CalendarView.WeekDayVScrollPanel.ScrollBarChanged -= VScrollPanelScrollBarChanged; if (this.ECalendarView == eCalendarView.Day) { CalendarView.DayViewDateChanged -= DayViewDateChanged; } else { CalendarView.WeekViewStartDateChanged -= WeekViewStartDateChanged; CalendarView.WeekViewEndDateChanged -= WeekViewEndDateChanged; } } } #endregion #region Event handling routines #region SelectedViewChanged /// /// Processes view changes /// /// object /// SelectedViewEventArgs void SelectedViewChanged(object sender, SelectedViewEventArgs e) { // Update our IsViewSelected state IsViewSelected = (e.NewValue == this.ECalendarView); if (IsViewSelected == true) { AutoSyncViewDate(e.OldValue); UpdateDateSelection(); } else { ResetView(); } // Update our AllDayPanel view _AllDayPanel.UpdateView(); } #endregion #region DayViewDateChanged /// /// Processes DayViewDate changes /// /// /// void DayViewDateChanged(object sender, DateChangeEventArgs e) { StartDate = e.NewValue; EndDate = e.NewValue; } #endregion #region WeekViewStartDateChanged /// /// Processes StartDate changes /// /// /// void WeekViewStartDateChanged(object sender, DateChangeEventArgs e) { StartDate = e.NewValue; } #endregion #region WeekViewEndDateChanged /// /// Processes EndDate changes /// /// /// void WeekViewEndDateChanged(object sender, DateChangeEventArgs e) { EndDate = e.NewValue; } #endregion #region TimeSlotDurationChanged /// /// Handles TimeSlotDurationChanged events /// /// object /// TimeSlotDurationChangedEventArgs void TimeSlotDurationChanged( object sender, TimeSlotDurationChangedEventArgs e) { // Reset our slice selection range and // invalidate our control _SelectedSliceStart = 0; _SelectedSliceEnd = 0; NeedRecalcLayout = true; RecalcSize(); } #endregion #region FixedAllDayPanelHeightChanged /// /// Handles FixedAllDayPanelHeightChanged events /// /// /// void FixedAllDayPanelHeightChanged( object sender, FixedAllDayPanelHeightChangedEventArgs e) { NeedRecalcLayout = true; } #endregion #region MaximumAllDayPanelHeightChanged /// /// Handles MaximumAllDayPanelHeightChanged events /// /// /// void MaximumAllDayPanelHeightChanged( object sender, MaximumAllDayPanelHeightChangedEventArgs e) { NeedRecalcLayout = true; } #endregion #region VScrollPanel_ScrollBarChanged /// /// Handles ScrollBarChanged events /// /// /// void VScrollPanelScrollBarChanged(object sender, EventArgs e) { int vdelta = -VsPanel.ScrollBar.Value - _VScrollPos; if (vdelta != 0) { _VScrollPos = -VsPanel.ScrollBar.Value; // Offset our DayColumn accordingly for (int i = 0; i < _NumberOfColumns; i++) { DayColumn dayColumn = _DayColumns[i]; Rectangle r = dayColumn.Bounds; r.Y += vdelta; dayColumn.Bounds = r; for (int j = 0; j < dayColumn.CalendarItems.Count; j++) { dayColumn.CalendarItems[j].Displayed = dayColumn.CalendarItems[j].Bounds.IntersectsWith(ClientRect); } } // Redraw our view InvalidateRect(ViewRect); } } #endregion #endregion #region GetViewAreaFromPoint /// /// Gets the view area under the given mouse /// point (tab, header, content, etc) /// /// Point /// eViewArea public override eViewArea GetViewAreaFromPoint(Point pt) { if (Bounds.Contains(pt) == true) { if (pt.Y >= ClientRect.Y) { if (AllDayPanel.Bounds.Contains(pt)) return (eViewArea.InAllDayPanel); if (pt.Y < ClientRect.Y + DayOfWeekHeaderHeight) return (eViewArea.InDayOfWeekHeader); return (eViewArea.InContent); } return (base.GetViewAreaFromPoint(pt)); } return (eViewArea.NotInView); } #endregion #region GetDateSelectionFromPoint /// /// Gets the date selection from the given point. The startDate /// and endDate will vary based upon the view type (WeekDay / Month) /// /// Point in question /// out start date /// out end date /// True if a valid selection exists /// at the given point public override bool GetDateSelectionFromPoint( Point pt, out DateTime startDate, out DateTime endDate) { base.GetDateSelectionFromPoint(pt, out startDate, out endDate); int col, slice; if (GetPointItem(pt, out col, out slice, true) == true) { startDate = GetTime(_DayColumns[col].Date, slice, 0); endDate = startDate.AddMinutes(TimeSlotDuration); return (true); } return (false); } #endregion #region GetDateBounds /// /// Gets the bounding display rectangle for the given date/time. /// /// The date/time /// Bounding display rectangle public Rectangle GetDateBounds(DateTime date) { int col = GetColumnFromDate(date); if (col >= 0) { int slice = GetDateSlice(date); if (slice >= 0) return (GetSliceRect(col, slice)); } return (Rectangle.Empty); } /// /// Gets the bounding display rectangle for the given /// starting and ending date/time range. /// /// Start date /// End date /// Bounding display rectangle public Rectangle GetDateBounds(DateTime startDate, DateTime endDate) { Rectangle r1 = GetDateBounds(startDate); Rectangle r2 = GetDateBounds(endDate); return (Rectangle.Union(r1, r2)); } #endregion #region IsAllDayItem internal bool IsAllDayItem(CalendarItem item) { if (item.Equals(SelectedItem) && (IsEndResizing || IsStartResizing || IsMoving)) { return (false); } return (IsAllDayItem(item.StartTime, item.EndTime)); } internal bool IsAllDayItem(Appointment item) { if (SelectedItem != null && item.Equals(SelectedItem.ModelItem) && (IsEndResizing || IsStartResizing || IsMoving)) { return (false); } return (IsAllDayItem(item.StartTime, item.EndTime)); } private bool IsAllDayItem(DateTime startTime, DateTime endTime) { //if (NumberOfColumns > 1 || if ( CalendarView.AllDayDisplayMode != eAllDayDisplayMode.None) { if ((endTime - startTime).TotalDays >= 1) return (true); } //if (NumberOfColumns > 1 || if ( CalendarView.AllDayDisplayMode == eAllDayDisplayMode.ByDayBoundary) { return (startTime.Day != endTime.Day || (endTime - startTime).TotalDays > 1); } return (false); } #endregion #region SetSelectedItem /// /// Handles selected item changes /// /// CalendarItem /// EventArgs internal void ItemIsSelectedChanged(object sender, EventArgs e) { CalendarItem ci = sender as CalendarItem; if (ci != null) { if (ci.IsSelected == true) { SelectedItem = SetSelectedItem(SelectedItem, ci); } else { if (ci == SelectedItem) SelectedItem = null; } } } #region SetSelectedItem protected override CalendarItem SetSelectedItem(CalendarItem pci, CalendarItem nci) { CalendarItem selItem = null; for (int i = 0; i < DayColumns.Length; i++) selItem = SetSelectedCalendarItem(nci, DayColumns[i].CalendarItems, selItem); selItem = SetSelectedCalendarItem(nci, AllDayPanel.CalendarItems, selItem); return (selItem); } #region SetSelectedCalendarItem private CalendarItem SetSelectedCalendarItem( CalendarItem nci, List items, CalendarItem selItem) { for (int i = 0; i < items.Count; i++) { CalendarItem item = items[i]; item.IsSelected = (nci != null ? (item.ModelItem == nci.ModelItem) : false); if (item.IsSelected == true && selItem == null) { selItem = item; SelectedItem = item; } } return (selItem); } #endregion #endregion #endregion #region UpdateDateSelection #region UpdateDateSelection /// /// Updates our slice selection range to reflect /// the given date selection start and end values /// protected override void UpdateDateSelection() { if (IsViewSelected == true) { // Get the new absolute slice selection range int sliceStart = 0; int sliceEnd = 0; if (DateSelectionStart.HasValue && DateSelectionEnd.HasValue) { sliceStart = GetDateSlice(DateSelectionStart); sliceEnd = GetDateSlice(DateSelectionEnd); if (sliceStart < 0 && sliceEnd < 0) { sliceStart = 0; sliceEnd = 0; } if (sliceStart < 0) sliceStart = 0; if (sliceEnd < 0) sliceEnd = _NumberOfColumns * NumberOfActiveSlices; } // Limit our range to only those slices // that are visible on the screen int s1 = (int)(-_VScrollPos / TimeSliceHeight); int s2 = (int)(s1 + ViewRect.Height / TimeSliceHeight + 2); if (s2 > s1) { ProcessSelRange(sliceStart, sliceEnd, s1, s2); // Save our new selection range _SelectedSliceStart = sliceStart; _SelectedSliceEnd = sliceEnd; } } } #endregion #region GetDateSlice /// /// Gets the absolute slice value for the given date /// /// Selection date /// Absolute slice private int GetDateSlice(DateTime? selDate) { if (selDate.HasValue) return (GetDateSlice(selDate.Value)); return (-1); } private int GetDateSlice(DateTime selDate) { // Loop through each column for (int i = 0; i < _NumberOfColumns; i++) { DateTime date = _DayColumns[i].Date; // If we have found our containing column, then // calculate the absolute slice value and return it if (selDate >= date && selDate < date.AddDays(1)) { int slice = ((selDate.Hour * MinutesPerHour) + selDate.Minute) / TimeSlotDuration; return (i * NumberOfActiveSlices + slice - StartSlice); } } return (-1); } #endregion #region ProcessSelRange /// /// Processes the selection time slice range /// /// Slice range start /// Slice range end /// Slice start limit /// Slice end limit private void ProcessSelRange(int sliceStart, int sliceEnd, int s1, int s2) { // Calculate our starting and ending column range int fcol = Math.Min(_SelectedSliceStart / NumberOfActiveSlices, sliceStart / NumberOfActiveSlices); int lcol = Math.Max(_SelectedSliceEnd / NumberOfActiveSlices, sliceEnd / NumberOfActiveSlices); lcol = Math.Min(_NumberOfColumns - 1, lcol); // Loop through each column for (int i = fcol; i <= lcol; i++) { // Get the selection status for the given range bool[] oldSelected = SelectedSlices(s1, s2, i, _SelectedSliceStart, _SelectedSliceEnd); bool[] newSelected = SelectedSlices(s1, s2, i, sliceStart, sliceEnd); // Invalidate those slices whose // selection status changed Rectangle vRect = ViewRect; for (int j = 0; j < s2 - s1; j++) { if (oldSelected[j] != newSelected[j]) { Rectangle r = GetSliceRect(i, s1 + j); r.Intersect(vRect); if (r.Width > 0 && r.Height > 0) InvalidateRect(r); } } } } #endregion #region SelectedSlices /// /// Gets an array of slice selection values /// over the given range of column slices /// /// Slice start limit /// Slice end limit /// Column /// Slice range start /// Slice range end /// Array of selection values private bool[] SelectedSlices(int s1, int s2, int col, int sliceStart, int sliceEnd) { // Calculate our number of entries and // allocate our IsSelected array accordingly int n = s2 - s1; bool[] sel = new bool[n + 1]; // Loop through the range of entries determining if // the specific slice is within the selection range int slice = col * NumberOfActiveSlices + s1; for (int i = 0; i < n; i++) { sel[i] = (slice >= sliceStart && slice < sliceEnd); slice++; } // Return the array to the caller return (sel); } #endregion #endregion #region RecalcSize routines #region RecalcSize /// /// Performs NeedRecalcSize requests /// public override void RecalcSize() { base.RecalcSize(); if (IsViewSelected == true) { // Normalize our start and end dates DateTime startDate; DateTime endDate; NormalizeDates(out startDate, out endDate); if (NeedRecalcLayout == true) _DayColumnSize = null; // Allocate our DayColumns AllocateDayColumns(startDate, endDate); // Update our Model connection view, // AllDayPanel, CalendarItems, and DateSelection UpdateView(); UpdateAllDayPanelItems(); UpdateDayColumns(startDate, endDate); UpdateCalendarItems(); UpdateDateSelection(); // Set our display view rectangle Rectangle r = ClientRect; r.Y += DayOfWeekHeaderHeight; r.Height -= DayOfWeekHeaderHeight; SetViewRectangle(r); // Final Recalc cleanup if (DaysOfTheWeek != null) DaysOfTheWeek.NeedsMeasured = true; NeedRecalcLayout = false; CalendarView.DoViewLoadComplete(this); } } #endregion #region NormalizeDates /// /// Normalizes the user specified start and end dates /// /// [out] Normalized start date /// [out] Normalized end date protected virtual void NormalizeDates(out DateTime startDate, out DateTime endDate) { startDate = this.StartDate; endDate = this.EndDate; } #endregion #region AllocateDayColumns /// /// Allocates out DayColumns /// /// /// private void AllocateDayColumns(DateTime startDate, DateTime endDate) { // Allocate our DayColumns array to // hold our info _NumberOfColumns = (endDate - startDate).Days + 1; _NumberOfColumns = Math.Max(_NumberOfColumns, 1); _NumberOfColumns = Math.Min(_NumberOfColumns, MaxNumberOfColumns); if (_DayColumns == null || _DayColumns.Length != _NumberOfColumns) _DayColumns = new DayColumn[_NumberOfColumns]; // Prepare to update display info on each time slot Rectangle r = ViewRect; r.Y += _VScrollPos; // Loop through each day column float dcWidth = DayColumnWidth; float x1 = r.X; // Update each DayColumn for (int i = 0; i < _NumberOfColumns; i++) { if (_DayColumns[i] == null) _DayColumns[i] = new DayColumn(0); _DayColumns[i].Date = startDate.AddDays(i); float x2 = (i == _NumberOfColumns - 1) ? r.Right - 1 : x1 + dcWidth; if (IsLayoutNeeded(i) == true) _DayColumns[i].Bounds = new Rectangle((int) x1, r.Y, (int) x2 - (int) x1, r.Height); x1 = x2; } } #endregion #region UpdateView /// /// Updates our connection model view /// 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 ModelWeekDayViewConnector(CalendarModel, this); SubItems.Insert(0, _AllDayPanel); } } } #endregion #region ResetView /// /// Disconnects and resets the Model connection /// internal override void ResetView() { _AllDayPanel.ResetView(); base.ResetView(); } #endregion #region UpdateAllDayPanelItems /// /// Updates our AllDayPanel items /// private void UpdateAllDayPanelItems() { if (NeedRecalcLayout == true) { // Initiate a RecalcSize for the panel _AllDayPanel.WidthInternal = ClientRect.Width; _AllDayPanel.HeightInternal = MaximumAllDayPanelHeight; _AllDayPanel.RecalcSize(); // Set the panel's bounding rect accordingly Rectangle r = ClientRect; r.Width = _AllDayPanel.WidthInternal; r.Y += DayOfWeekHeaderHeight; r.Height = _AllDayPanel.HeightInternal; _AllDayPanel.Bounds = r; } } private bool IsLayoutNeeded(int col) { return (NeedRecalcLayout == true || _DayColumns[col].NeedRecalcLayout == true); } #endregion #region UpdateDayColumns /// /// Calculates and updates DayColumn bounds /// /// Start date /// End date protected void UpdateDayColumns(DateTime startDate, DateTime endDate) { // Establish our current TimeSlice range GetTimeSliceData(); // Updating display info on each column Rectangle r = ViewRect; r.Y += _VScrollPos; r.Height = (int) (TimeSliceHeight * NumberOfSlices); for (int i = 0; i < _NumberOfColumns; i++) { _DayColumns[i].TimeSliceHeight = TimeSliceHeight; if (IsLayoutNeeded(i) == true) { _DayColumns[i].Bounds = new Rectangle(_DayColumns[i].Bounds.X, r.Y, _DayColumns[i].Bounds.Width, r.Height); InvalidateRect(_DayColumns[i].Bounds); } } } #region GetTimeSliceData private void GetTimeSliceData() { _LocalStartSlice = 0; _LocalNumberOfSlices = (HoursPerDay * MinutesPerHour) / TimeSlotDuration + 1; if (CalendarView.ShowOnlyWorkDayHours == true) { WorkTime startTime = new WorkTime(23, 59); WorkTime endTime = new WorkTime(0, 0); for (int i = 0; i < NumberOfColumns; i++) { DayColumn dc = _DayColumns[i]; if (dc.WorkStartTime.IsEmpty == false || dc.WorkEndTime.IsEmpty == false) { if (dc.WorkStartTime <= dc.WorkEndTime) { if (dc.WorkStartTime < startTime) startTime = dc.WorkStartTime; if (dc.WorkEndTime > endTime) endTime = dc.WorkEndTime; } else { startTime = new WorkTime(0, 0); endTime = new WorkTime(23, 59); break; } } } if (endTime > startTime) { int startMinutes = (startTime.Hour * MinutesPerHour) + startTime.Minute; int endMinutes = (endTime.Hour * MinutesPerHour) + endTime.Minute; _LocalStartSlice = startMinutes / TimeSlotDuration; _LocalNumberOfSlices = (endMinutes - startMinutes) / TimeSlotDuration + 1; } if (StartSlice >= 0) { int endSlice = _LocalStartSlice + _LocalNumberOfSlices - 1; if (_LocalStartSlice > StartSlice) _LocalStartSlice = StartSlice; if (StartSlice + NumberOfSlices > endSlice) endSlice = StartSlice + NumberOfSlices - 1; _LocalNumberOfSlices = endSlice - _LocalStartSlice + 1; } } StartSlice = _LocalStartSlice; NumberOfSlices = _LocalNumberOfSlices; TimeSliceHeight = (float)ViewRect.Height / NumberOfActiveSlices; } #endregion #endregion #region UpdateCalendarItems /// /// Updates our CalendarItems list /// private void UpdateCalendarItems() { List list = new List(); for (int i = 0; i < _NumberOfColumns; i++) { if (IsLayoutNeeded(i) == true) { if (_DayColumns[i].CalendarItems.Count > 0) { List items = SortCalendarItems(i); list.Clear(); for (int j = 0; j < items.Count; j++) { ColumnList colList = GetColList(list, items[j]); colList.AddColumnSlot(items[j], 0); } foreach (ColumnList colList in list) colList.CountColumns(); CalcAppointmentBounds(i, list); } _DayColumns[i].NeedRecalcLayout = false; } } } #region GetColList private ColumnList GetColList(List list, CalendarItem item) { int id = CalendarView.DoGetAppointmentGroupId(item, -1); int index; if (GetColListIndex(list, id, out index) == true) return (list[index]); ColumnList clist = new ColumnList(id); if (index < list.Count) list.Insert(index, clist); else list.Add(clist); return (clist); } #region GetColListIndex private bool GetColListIndex(List list, int id, out int index) { for (index=0; index < list.Count; index++) { ColumnList colList = list[index]; if (colList.Id == id) return (true); if (colList.Id > id) break; } return (false); } #endregion #endregion #region SortCalendarItems /// /// Sorts the DayColumn CalendarItem list /// /// DayColumn index private List SortCalendarItems(int col) { List items = new List(); items.AddRange(_DayColumns[col].CalendarItems); if (items.Count > 0) { items.Sort( delegate(CalendarItem c1, CalendarItem c2) { if (c1.StartTime > c2.StartTime) return (1); if (c1.StartTime < c2.StartTime) return (-1); if (c1.EndTime - c1.StartTime > c2.EndTime - c2.StartTime) return (1); if (c1.EndTime - c1.StartTime < c2.EndTime - c2.StartTime) return (-1); int result = 0; CalendarView.DoDetailSortEvent(this, c1, c2, ref result); return (result); } ); } return (items); } #endregion #region CalcAppointmentBounds /// /// Calculates normal appointment bounds /// /// DayColumn column /// Accumulated ColumnList private void CalcAppointmentBounds(int col, List list) { Rectangle r = _DayColumns[col].Bounds; r.X++; r.Width -= 8; for (int k = 0; k < list.Count; k++) { ColumnList colList = list[k]; Rectangle r3 = r; float dx3 = (float)r3.Width / list.Count; r3.X += (int)(dx3 * k); r3.Width = (int)dx3; for (int i = 0; i < colList.SList.Count; i++) { for (int j = 0; j < colList.SList[i].Count; j++) { Rectangle r2 = r3; SlotItem si = colList.SList[i][j]; CalendarItem item = si.CItem; float dx = (float)r2.Width / si.Count; r2.X += (int)(dx * i); if (si.SList != null && si.SList.Count == 1) r2.Width = (int)(dx * (si.SList[0].Column - si.Column)); else if (si.SList == null) r2.Width = r3.Width - (r2.X - r3.X); else r2.Width = (int)dx; DateTime startTime = item.StartTime; if (startTime.Date < _DayColumns[col].Date) startTime = _DayColumns[col].Date; DateTime endTime = item.EndTime; if (endTime > _DayColumns[col].Date.AddDays(1)) endTime = _DayColumns[col].Date.AddDays(1); DateTime date = startTime.Date; TimeSpan ts1 = startTime.AddMinutes(-StartSlice * TimeSlotDuration) - date; TimeSpan ts2 = endTime - startTime; int pos = (int)(ts1.TotalMinutes / TimeSlotDuration * TimeSliceHeight); int height = (int)Math.Round(ts2.TotalMinutes / TimeSlotDuration * TimeSliceHeight); AppointmentView view = item as AppointmentView; if (view != null) { Font font = view.Font ?? CalendarView.Font; if (font != null) height = Math.Max(font.Height + 6, height); } r2.Y = r.Y + (int)pos; r2.Height = height; // Now that we have calculated the items height and // width, invoke a Recalc on the item item.WidthInternal = r2.Width; item.HeightInternal = r2.Height - 1; item.RecalcSize(); // Set our bounds for the item r2.Width = item.WidthInternal; r2.Height = item.HeightInternal; if (item.Bounds != r2) { InvalidateRect(item.Bounds); InvalidateRect(r2); } item.Bounds = r2; // Set it's display state item.Displayed = r2.IntersectsWith(ClientRect); } } } } #endregion #endregion #endregion #region Paint processing #region Root paint code /// /// Paint processing /// /// ItemPaintArgs public override void Paint(ItemPaintArgs e) { Graphics g = e.Graphics; // Set our current color table _ViewColor.SetColorTable(); // Only draw something if we have something to draw if (_DayColumns != null) { // Calculate our drawing ranges int dayStart, dayEnd; int sliceStart, sliceEnd; int dayCount = GetDayRange(e, out dayStart, out dayEnd); int sliceCount = GetSliceRange(e, out sliceStart, out sliceEnd); // Draw our calendar parts if (dayCount > 0) DrawDayOfTheWeekHeader(e, dayStart, dayEnd); if (sliceCount > 0 && dayCount > 0) { // Set our clipping region Rectangle r = ViewRect; r.X = ClientRect.X; r.Width = ClientRect.Width; Region regSave = g.Clip; g.SetClip(r, CombineMode.Intersect); // Draw our slices and appointments DrawSlices(e, sliceStart, sliceEnd, dayStart, dayEnd); DrawTimeIndicators(g, sliceStart, sliceEnd, eTimeIndicatorLevel.Bottom); if (Connector != null && Connector.IsConnected) DrawWeekAppointments(e, dayStart, dayEnd); DrawTimeIndicators(g, sliceStart, sliceEnd, eTimeIndicatorLevel.Top); // Restore our original clip region g.Clip = regSave; } // Initiate the painting of our AllDay Panel _AllDayPanel.Paint(e); // Update our Alt-Key window UpdatePosWin(ViewRect); } // Let the base painting take place base.Paint(e); } #region Clip range routines /// /// Calculates the range of days needed to be drawn /// to satisfy the specified paint request /// /// ItemPaintArgs /// [out] Day start index /// [out] Day end index /// Day range count (end - start) private int GetDayRange(ItemPaintArgs e, out int dayStart, out int dayEnd) { // Calc our starting index int start = 0; while (start < _NumberOfColumns) { if (_DayColumns[start].Bounds.Right > e.ClipRectangle.X) break; start++; } // Calc our ending index int end = start; while (end < _NumberOfColumns) { if (_DayColumns[end].Bounds.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); } /// /// Calculates the range of slices needed to be drawn /// to satisfy the specified paint request /// /// ItemPaintArgs /// [out] Slice start index /// [out] Slice end index /// Slice range count (end - start) internal int GetSliceRange(ItemPaintArgs e, out int sliceStart, out int sliceEnd) { // Calc our starting index int start = 0; Rectangle v = ViewRect; while (start < NumberOfSlices) { Rectangle r = GetSliceRect(0, start); if (r.Bottom > v.Top) { if (r.Bottom > e.ClipRectangle.Y) break; } start++; } // Calc our ending index int end = start; while (end < NumberOfSlices) { Rectangle r = GetSliceRect(0, end); if (r.Y >= e.ClipRectangle.Bottom) break; end++; } // Set the user supplied 'out' values, and // return the range count to the caller if (end - start == 0) { sliceStart = 0; sliceEnd = 0; return (0); } sliceStart = start; sliceEnd = end - 1; return (end - start); } private bool SliceIsSelected(int col, int slice) { int nslice = col * NumberOfActiveSlices + slice; return (nslice >= _SelectedSliceStart && nslice < _SelectedSliceEnd); } #endregion #endregion #region DayOfTheWeek header drawing #region DrawDayOfTheWeekHeader /// /// Draws the top Day of the week header /// /// ItemPaintArgs /// Start day index /// End day index private void DrawDayOfTheWeekHeader(ItemPaintArgs e, int dayStart, int dayEnd) { Graphics g = e.Graphics; Rectangle r = new Rectangle( _DayColumns[dayStart].Bounds.X, ClientRect.Y, _DayColumns[dayEnd].Bounds.Right - _DayColumns[dayStart].Bounds.X, DayOfWeekHeaderHeight); if (r.Width > 0 && r.Height > 0) { // 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 int nowHeader = -1; using (Brush br = _ViewColor.BrushPart((int) eCalendarWeekDayPart.DayHeaderBackground, r)) { using (Pen pen = new Pen( _ViewColor.GetColor((int) eCalendarWeekDayPart.DayHeaderBorder))) { for (int i = dayStart; i <= dayEnd; i++) { if (CalendarView.HighlightCurrentDay == true && _DayColumns[i].Date.Date.Equals(DateTime.Now.Date)) { nowHeader = i; continue; } DrawColumnHeader(g, i, type, r, br, pen, eCalendarWeekDayPart.DayHeaderForeground); } } } // Draw the current "Now" header if (nowHeader >= 0) { using (Brush br = _ViewColor.BrushPart((int) eCalendarWeekDayPart.NowDayHeaderBackground, r)) { using (Pen pen = new Pen( _ViewColor.GetColor((int) eCalendarWeekDayPart.NowDayHeaderBorder))) { DrawColumnHeader(g, nowHeader, type, r, br, pen, eCalendarWeekDayPart.NowDayHeaderForeground); } } } } } #region DrawColumnHeader /// /// DrawColumnHeader /// /// /// /// /// /// /// /// private void DrawColumnHeader(Graphics g, int i, DaysOfTheWeek.eDayType type, Rectangle r, Brush br, Pen pen, eCalendarWeekDayPart part) { r.X = _DayColumns[i].Bounds.X; r.Width = _DayColumns[i].Bounds.Width; g.FillRectangle(br, r); g.DrawRectangle(pen, r); Rectangle t = r; if (CalendarView.DoPreRenderWeekDayHeader(g, this, i, t) == false) { // Draw the header text int n = i % DaysInWeek; eTextFormat tf = eTextFormat.VerticalCenter | eTextFormat.NoPadding; r.Inflate(-2, 0); r.X += 1; TextDrawing.DrawString(g, _DayColumns[i].Date.Day.ToString(), BoldFont, Color.Black, r, tf); r.X += _DayColumnSize[n].Width; r.Width -= _DayColumnSize[n].Width; if (type != DaysOfTheWeek.eDayType.None) { tf |= eTextFormat.HorizontalCenter; TextDrawing.DrawString(g, DaysOfTheWeek.DayText[(int) type][n], Font, _ViewColor.GetColor((int) part), r, tf); } CalendarView.DoPostRenderWeekDayHeader(g, this, i, t); } } #endregion #endregion #region GetDaysOfTheWeekType /// /// Get the index for our day of the week text /// /// Graphics handle /// Index to header text private DaysOfTheWeek.eDayType GetDaysOfTheWeekType(Graphics g) { // Resize our DayColumn day text if it // hasn't been resized previously if (_DayColumnSize == null) { _DayColumnSize = new Size[_NumberOfColumns]; for (int i = 0; i < _NumberOfColumns; i++) { _DayColumnSize[i] = TextDrawing.MeasureString(g, _DayColumns[i].Date.Day.ToString(), BoldFont, 0, eTextFormat.NoPadding); } } // Determine if the current DayRect bounds // are constrained by the text threshold DaysOfTheWeek.MeasureText(g, Font); for (int i = 0; i < _NumberOfColumns; i++) { if (_DayColumns[i].Bounds.Width < _DayColumnSize[i].Width + DaysOfTheWeek.DaySize[(int)DaysOfTheWeek.eDayType.Short][i % 7].Width) { return (DaysOfTheWeek.eDayType.None); } } for (int i = 0; i < _NumberOfColumns; i++) { if (_DayColumns[i].Bounds.Width < _DayColumnSize[i].Width + DaysOfTheWeek.DaySize[(int)DaysOfTheWeek.eDayType.Long][i % 7].Width) { return (DaysOfTheWeek.eDayType.Short); } } return (DaysOfTheWeek.eDayType.Long); } #endregion #endregion #region DrawSlices #region DrawSlices /// /// Draws Normal Appointment time slices /// /// ItemPaintArgs /// Start slice /// End slice /// Day start /// Day end private void DrawSlices(ItemPaintArgs e, int sliceStart, int sliceEnd, int dayStart, int dayEnd) { Graphics g = e.Graphics; DaySlot[,] daySlots = GetDaySlots(sliceStart, sliceEnd, dayStart, dayEnd); DrawContent(g, sliceStart, sliceEnd, dayStart, dayEnd, daySlots); DrawDaySlot(g, sliceStart, sliceEnd, dayStart, dayEnd, daySlots, false); DrawBorders(g, sliceStart, sliceEnd, dayStart, dayEnd, daySlots); DrawDaySlot(g, sliceStart, sliceEnd, dayStart, dayEnd, daySlots, true); } #endregion #region GetDaySlots /// /// Gets the array of DaySlot information /// /// /// /// /// /// array of DaySlots private DaySlot[,] GetDaySlots(int sliceStart, int sliceEnd, int dayStart, int dayEnd) { DaySlot[,] daySlots = new DaySlot[dayEnd - dayStart + 1, sliceEnd - sliceStart + 1]; for (int i = dayStart; i <= dayEnd; i++) { for (int j = sliceStart; j <= sliceEnd; j++) { DaySlot daySlot = new DaySlot(); daySlots[i - dayStart, j - sliceStart] = daySlot; daySlot.Bounds = GetSliceRect(i, j); daySlot.Selected = SliceIsSelected(i, j); if (j <= sliceEnd && CalendarView.HasViewDisplayCustomizations == true) { int start = ((StartSlice + j) * TimeSlotDuration) % 1440; int end = Math.Min(start + TimeSlotDuration, 1439); WorkTime wkStart = new WorkTime(start / MinutesPerHour, start % MinutesPerHour); WorkTime wkEnd = new WorkTime(end / MinutesPerHour, end % MinutesPerHour); daySlot.Appearance = CalendarView.ViewDisplayCustomizations.GetDaySlotAppearance( OwnerKey, _DayColumns[i].Date, wkStart, wkEnd); } } } return (daySlots); } #endregion #region DrawContent /// /// Time slice content drawing /// /// Graphics /// Start slice /// End slice /// Day start /// Day end /// private void DrawContent(Graphics g, int sliceStart, int sliceEnd, int dayStart, int dayEnd, DaySlot[,] daySlots) { // Loop through each day in each week, displaying // the associated day content for (int i = dayStart; i <= dayEnd; i++) { for (int j = sliceStart; j <= sliceEnd; j++) { DaySlot daySlot = daySlots[i - dayStart, j - sliceStart]; DaySlotAppearance dsa = daySlot.Appearance; if (CalendarView.DoPreRenderWeekDaySlotBackground(g, this, i, j, daySlot.Bounds) == false) { if (dsa != null && daySlot.Selected == false) { using (Brush br = new SolidBrush(dsa.BackColor)) g.FillRectangle(br, daySlot.Bounds); continue; } g.FillRectangle(GetContentBrush(daySlot, i, j), daySlot.Bounds); } CalendarView.DoPostRenderWeekDaySlotBackground(g, this, i, j, daySlot.Bounds); } } } #region GetContentBrush /// /// Gets the background content brush /// for the given time slice /// /// /// Column index /// Time slice /// Background brush private Brush GetContentBrush(DaySlot daySlot, int col, int slice) { int start = (StartSlice + slice) * TimeSlotDuration; if (slice < NumberOfActiveSlices) { if (daySlot.Selected == true) return (SelectedBrush); WorkTime wkStart = new WorkTime(start / MinutesPerHour, start % MinutesPerHour); if (_DayColumns[col].IsWorkTime(wkStart) == true) return (WorkBrush); if (_DayColumns[col].IsBusyTime(wkStart) == true) return (BusyBrush); } else { return (AllDayBrush); } return (OffWorkBrush); } #endregion #endregion #region DrawDaySlot /// /// Initiates DaySlot drawing /// /// /// /// /// /// /// /// On top of borders private void DrawDaySlot(Graphics g, int sliceStart, int sliceEnd, int dayStart, int dayEnd, DaySlot[,] daySlots, bool onTop) { List dsaList = null; Rectangle dRect = Rectangle.Empty; for (int i = dayStart; i <= dayEnd; i++) { DaySlot lastDaySlot = null; for (int j = sliceStart; j <= sliceEnd; j++) { DaySlot daySlot = daySlots[i - dayStart, j - sliceStart]; Rectangle r = daySlot.Bounds; DaySlotAppearance dsa = daySlot.Appearance; if (lastDaySlot != null && (lastDaySlot.Appearance != dsa || lastDaySlot.Selected != daySlot.Selected)) { FlushDaySlotText(g, i, dsaList, ref dRect, lastDaySlot.Selected); } lastDaySlot = daySlot; if (dsa != null) { if (dsa.OnTop == onTop) { if (daySlot.Selected == true) { if (dsa.ShowTextWhenSelected == true) dRect = dRect.IsEmpty ? r : Rectangle.Union(dRect, r); } else { dRect = dRect.IsEmpty ? r : Rectangle.Union(dRect, r); } if (dsaList == null) dsaList = new List(); if (dsaList.Contains(dsa) == false) dsaList.Add(dsa); } continue; } } if (lastDaySlot != null) FlushDaySlotText(g, i, dsaList, ref dRect, lastDaySlot.Selected); } } #region FlushDaySlotText /// /// Flushes out pending DaySlot drawing /// /// /// /// /// Display rect /// private void FlushDaySlotText(Graphics g, int dayCol, List dsaList, ref Rectangle dRect, bool selected) { if (dsaList != null && dsaList.Count > 0) { if (dRect.IsEmpty == false) DrawDaySlotText(g, dayCol, dsaList, dRect, selected); dsaList.Clear(); dRect = Rectangle.Empty; } } #endregion #region DrawDaySlotText /// /// Draws the DaySlot Text /// /// /// /// /// /// private void DrawDaySlotText(Graphics g, int dayCol, IEnumerable dsaList, Rectangle cRect, bool selected) { foreach (DaySlotAppearance dsa in dsaList) { DateTime startTime = GetSlotTime(dayCol, dsa.StartTime); DateTime endTime = GetSlotTime(dayCol, dsa.EndTime); DateTime e = endTime.AddMinutes(-1); WorkTime wkEnd = new WorkTime(e.Hour, e.Minute); int start = GetWorkTimeSlice(dsa.StartTime); int end = GetWorkTimeSlice(wkEnd); Rectangle r = GetSliceRect(dayCol, start); r = Rectangle.Union(r, GetSliceRect(dayCol, end)); Region rgnSave = g.Clip; g.SetClip(cRect, CombineMode.Intersect); string text = dsa.Text; if (CalendarView.DoRenderDaySlotAppearanceText(g, r, dsa, startTime, endTime, selected, ref text) == false) { if (String.IsNullOrEmpty(dsa.Text) == false) { eTextFormat tf = GetTextFormat(dsa.TextAlignment); Font font = dsa.Font ?? Font; Color color = (selected == true) ? (dsa.SelectedTextColor.IsEmpty ? Color.Black : dsa.SelectedTextColor) : (dsa.TextColor.IsEmpty ? Color.Black : dsa.TextColor); TextDrawing.DrawString(g, text, font, color, r, tf); } } g.Clip = rgnSave; } } #region GetSlotTime private DateTime GetSlotTime(int dayCol, WorkTime wkTime) { DateTime time = _DayColumns[dayCol].Date; time = time.AddHours(wkTime.Hour); time = time.AddMinutes(wkTime.Minute); return (time); } #endregion #region GetWorkTimeSlice private int GetWorkTimeSlice(WorkTime wkTime) { int slice = ((wkTime.Hour * MinutesPerHour) + wkTime.Minute) / TimeSlotDuration; return (slice - StartSlice); } #region GetTextFormat private eTextFormat GetTextFormat(ContentAlignment alignment) { eTextFormat tf = eTextFormat.WordBreak; switch (alignment) { case ContentAlignment.TopLeft: tf |= eTextFormat.Top | eTextFormat.Left; break; case ContentAlignment.TopCenter: tf |= eTextFormat.Top | eTextFormat.HorizontalCenter; break; case ContentAlignment.TopRight: tf |= eTextFormat.Top | eTextFormat.Right; break; case ContentAlignment.MiddleLeft: tf |= eTextFormat.VerticalCenter | eTextFormat.Left; break; case ContentAlignment.MiddleCenter: tf |= eTextFormat.VerticalCenter | eTextFormat.HorizontalCenter; break; case ContentAlignment.MiddleRight: tf |= eTextFormat.VerticalCenter | eTextFormat.Right; break; case ContentAlignment.BottomLeft: tf |= eTextFormat.Bottom | eTextFormat.Left; break; case ContentAlignment.BottomCenter: tf |= eTextFormat.Bottom | eTextFormat.HorizontalCenter; break; case ContentAlignment.BottomRight: tf |= eTextFormat.Bottom | eTextFormat.Right; break; } return (tf); } #endregion #endregion #endregion #endregion #region DrawTimeIndicators #region DrawTimeIndicators /// /// Draw view TimeIndicators /// /// /// /// private void DrawTimeIndicators(Graphics g, int sliceStart, int sliceEnd, eTimeIndicatorLevel level) { DateTime start = _DayColumns[0].Date; DateTime end = _DayColumns[_NumberOfColumns - 1].Date.AddDays(1); Rectangle r = Rectangle.Union(GetSliceRect(0, sliceStart), GetSliceRect(0, sliceEnd)); for (int i = 0; i < CalendarView.TimeIndicators.Count; i++) { TimeIndicator ti = CalendarView.TimeIndicators[i]; if (ti.IndicatorLevel == level) { if (ti.IndicatorArea == eTimeIndicatorArea.All || ti.IndicatorArea == eTimeIndicatorArea.Content) { if (ti.IsVisible(CalendarView, this)) { DateTime time = ti.IndicatorDisplayTime; if (time >= start && time < end) DrawTimeIndicator(g, r, ti); } } } } } #endregion #region DrawTimeIndicator #region DrawTimeIndicator /// /// Draws individual view TimeIndicator /// /// /// /// private void DrawTimeIndicator(Graphics g, Rectangle sRect, TimeIndicator ti) { Rectangle r = GetIndicatorRect(ti); if (r.IntersectsWith(sRect) == true) { if (r.Height > 0) { ColorDef cdef = GetIndicatorColor(ti); if (cdef != null) { using (Brush br = _ViewColor.BrushPart(cdef, r)) { if (br is LinearGradientBrush) ((LinearGradientBrush) br).WrapMode = WrapMode.TileFlipX; g.FillRectangle(br, r); } } } Color color = GetIndicatorBorder(ti); if (color.IsEmpty == false) { using (Pen pen = new Pen(color)) g.DrawLine(pen, r.X + 1, r.Bottom, r.Right - 1, r.Bottom); } } } #endregion #region GetIndicatorRect /// /// Gets the TimeIndicator rectangle /// /// /// internal override Rectangle GetIndicatorRect(TimeIndicator ti) { return (GetIndicatorRect(ti, ti.IndicatorDisplayTime)); } /// /// Gets the TimeIndicator rectangle for the /// given DataTime /// /// /// /// internal override Rectangle GetIndicatorRect(TimeIndicator ti, DateTime time) { DateTime startTime = GetTime(_DayColumns[0].Date, 0, 0); DateTime endTime = GetTime(_DayColumns[NumberOfColumns - 1].Date, NumberOfActiveSlices, 0); if (time >= startTime && time < endTime) { int offset = (int) (time.Hour * SlotsPerHour * TimeSliceHeight + (TimeSliceHeight * time.Minute) / TimeSlotDuration); offset -= (int) (StartSlice * TimeSliceHeight); Rectangle r = ViewRect; r.Width -= 1; r.Y = _DayColumns[0].Bounds.Y + offset - ti.Thickness; r.Height = ti.Thickness; return (r); } return (Rectangle.Empty); } #endregion #region GetIndicatorColor /// /// Gets the Indicator Back color /// /// /// private ColorDef GetIndicatorColor(TimeIndicator ti) { ColorDef cdef = ti.IndicatorColor; if (cdef == null || cdef.IsEmpty == true) cdef = _ViewColor.GetColorDef((int)eCalendarWeekDayPart.TimeIndicator); return (cdef); } #endregion #region GetIndicatorBorder /// /// Gets the Indicator Border color /// /// /// private Color GetIndicatorBorder(TimeIndicator ti) { return (ti.BorderColor.IsEmpty == false ? ti.BorderColor : _ViewColor.GetColor((int)eCalendarWeekDayPart.TimeIndicatorBorder)); } #endregion #endregion #endregion #region DrawBorders #region DrawBorders /// /// Draws time slice borders /// /// Graphics /// Start slice /// End slice /// Day start /// Day end /// private void DrawBorders(Graphics g, int sliceStart, int sliceEnd, int dayStart, int dayEnd, DaySlot[,] daySlots) { // Draw the horizontal and vertical borders, and // the current "Now" border DrawHorizontalBorders(g, sliceStart, sliceEnd, dayStart, dayEnd, daySlots); DrawVerticalBorders(g, sliceStart, sliceEnd, dayStart, dayEnd); if (CalendarView.HighlightCurrentDay == true) DrawNowBorder(g, dayStart, dayEnd); } #endregion #region DrawHorizontalBorders /// /// Draws horizontal borders /// /// /// /// /// /// /// private void DrawHorizontalBorders(Graphics g, int sliceStart, int sliceEnd, int dayStart, int dayEnd, DaySlot[,] daySlots) { if (CalendarView.HasViewDisplayCustomizations == true) { int n = MinutesPerHour / TimeSlotDuration; Color hourBorderColor = _ViewColor.GetColor((int)eCalendarWeekDayPart.DayHourBorder); Color halfHourBorderColor = _ViewColor.GetColor((int)eCalendarWeekDayPart.DayHalfHourBorder); for (int i = dayStart; i <= dayEnd; i++) { for (int j = sliceStart; j <= sliceEnd; j++) { DaySlot daySlot = daySlots[i - dayStart, j - sliceStart]; Rectangle r = daySlot.Bounds; DaySlotAppearance dsa = daySlot.Appearance; Point pt1 = r.Location; Point pt2 = new Point(r.Right - 1, r.Y); if (dsa != null && daySlot.Selected == false) { using (Pen pen = new Pen(j % n == 0 ? dsa.HourBorderColor : dsa.HalfHourBorderColor)) g.DrawLine(pen, pt1, pt2); continue; } using (Pen pen = new Pen(j % n == 0 ? hourBorderColor : halfHourBorderColor)) g.DrawLine(pen, pt1, pt2); } } } else { using (Pen pen1 = new Pen( _ViewColor.GetColor((int) eCalendarWeekDayPart.DayHourBorder))) { using (Pen pen2 = new Pen( _ViewColor.GetColor((int) eCalendarWeekDayPart.DayHalfHourBorder))) { Point pt1 = new Point(_DayColumns[dayStart].Bounds.X, 0); Point pt2 = new Point(_DayColumns[dayEnd].Bounds.Right - 1, 0); int n = MinutesPerHour/TimeSlotDuration; for (int i = sliceStart; i <= sliceEnd; i++) { Rectangle r = GetSliceRect(0, i); pt1.Y = pt2.Y = r.Y; g.DrawLine((i%n) == 0 ? pen1 : pen2, pt1, pt2); } } } } } #endregion #region DrawVerticalBorders /// /// Draws the vertical borders /// /// /// /// /// /// private void DrawVerticalBorders(Graphics g, int sliceStart, int sliceEnd, int dayStart, int dayEnd) { Rectangle r1 = GetSliceRect(0, sliceStart); Rectangle r2 = GetSliceRect(0, sliceEnd); using (Pen pen1 = new Pen( _ViewColor.GetColor((int)eCalendarWeekDayPart.DayViewBorder))) { Point pt1 = new Point(0, r1.Y); Point pt2 = new Point(0, r2.Bottom); for (int i = dayStart; i <= dayEnd; i++) { pt1.X = pt2.X = _DayColumns[i].Bounds.X; g.DrawLine(pen1, pt1, pt2); } pt1.X = pt2.X = _DayColumns[dayEnd].Bounds.Right; g.DrawLine(pen1, pt1, pt2); } } #endregion #region DrawNowBorder /// /// Draws the Current-Day Now border /// /// /// /// private void DrawNowBorder(Graphics g, int dayStart, int dayEnd) { // Draw the "Current" day border for (int i = dayStart; i <= dayEnd; i++) { if (_DayColumns[i].Date.Date.Equals(DateTime.Now.Date)) { Rectangle r = _DayColumns[i].Bounds; using (Pen pen = new Pen( _ViewColor.GetColor((int)eCalendarWeekDayPart.NowDayHeaderBorder))) { g.DrawRectangle(pen, r); } break; } } } #endregion #endregion #endregion #region DrawWeekAppointments /// /// Initiates the drawing of weekly appointments /// /// ItemPaintArgs /// Day start index /// Day end index private void DrawWeekAppointments(ItemPaintArgs e, int dayStart, int dayEnd) { if (e.ClipRectangle.IntersectsWith(ViewRect) == true) { // Loop through each day in each week, displaying // the associated day content List selItems = null; for (int i = 0; i <= dayEnd; i++) { List items = _DayColumns[i].CalendarItems; if (items != null && items.Count > 0) { int right = _DayColumns[i].Bounds.Right - 1; for (int j = 0; j < items.Count; j++) { CalendarItem item = items[j]; if ((item.Displayed == true) && (i >= dayStart || item.Bounds.Right > right)) { if (item.IsSelected == false) { item.Paint(e); } else { if (selItems == null) selItems = new List(); selItems.Add(item); } } } } } if (selItems != null) { foreach (CalendarItem item in selItems) item.Paint(e); } } } #endregion #endregion #region Mouse routines #region MouseDown processing /// /// MouseDown event processing /// /// public override void InternalMouseDown(MouseEventArgs objArg) { // Forward on the event base.InternalMouseDown(objArg); if (SelectedItem != null) _WasAllDayItem = IsAllDayItem(SelectedItem); if (objArg.Button == MouseButtons.Left) { if (IsTabMoving == false) { // Locate where the event took place if (InPanelResize(objArg.Location) == true) { MyCursor = Cursors.HSplit; _IsPanelResizing = true; } else if (ViewRect.Contains(objArg.Location) == true) { int col, slice; if (GetPointItem(objArg.Location, out col, out slice, true)) { MyCursor = GetContentCursor(); if (ProcessCilButtonDown(col, objArg) == false) ProcessDvlButtonDown(col, slice); IsMouseDown = true; } IsCopyDrag = false; } } } } #region CalendarItem MouseDown processing /// /// CalendarItem left mouseDown processing /// /// DayColumn col index /// MouseEventArgs private bool ProcessCilButtonDown(int col, MouseEventArgs objArg) { CalendarItem item = m_HotSubItem as CalendarItem; if (item != null) { _WasAllDayItem = IsAllDayItem(item); 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) { _LastCol = col; _LastBounds = item.Bounds; _LastPointOffset = objArg.Location; _LastMovePoint = objArg.Location; _LastMoveCol = -1; _LastDm = int.MinValue; if (IsResizing == false && IsMoving == false) { OldStartTime = item.StartTime; OldEndTime = item.EndTime; OldOwnerKey = OwnerKey; } // Flag appropriate action if (item.HitArea == CalendarItem.eHitArea.TopResize) IsStartResizing = true; else if (item.HitArea == CalendarItem.eHitArea.BottomResize) IsEndResizing = true; else if (item.HitArea == CalendarItem.eHitArea.Move) IsMoving = true; // Update our initial PosWin display UpdatePosWin(ViewRect); } } return (true); } return (false); } #endregion #region DayView MouseDown processing /// /// Handles DayView left MouseDown events /// /// DayColumn col index /// Time slice private void ProcessDvlButtonDown(int col, int slice) { DateTime startDate = GetTime(_DayColumns[col].Date, slice, 0); DateTime endDate = startDate.AddMinutes(TimeSlotDuration); ExtendSelection(ref startDate, ref endDate); CalendarView.DateSelectionStart = startDate; CalendarView.DateSelectionEnd = endDate; SelectedItem = null; } #endregion #endregion #region MouseUp processing /// /// MouseUp event processing /// /// MouseEventArgs public override void InternalMouseUp(MouseEventArgs objArg) { base.InternalMouseUp(objArg); CancelScrollTimer(); // Reset our panel resizing flag _IsPanelResizing = false; if (SelectedItem != null && (IsAllDayItem(SelectedItem) != _WasAllDayItem)) { ReloadView(); } } #endregion #region MouseMove processing #region InternalMouseMove /// /// MouseMove event processing /// /// MouseEventArgs 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) { if (_IsPanelResizing == true) { MyCursor = Cursors.HSplit; ProcessPanelMove(objArg); } else { if (InPanelResize(objArg.Location) == true) { MyCursor = Cursors.HSplit; } else { MyCursor = GetContentCursor(); if (objArg.Button == MouseButtons.Left) ProcessContentMove(objArg); } } } } #endregion #region InPanelResize /// /// Determines if the mouse is in the /// panel resize area /// /// Mouse location /// true if in the resize area private bool InPanelResize(Point pt) { if (CalendarView.IsMultiCalendar == true) { Rectangle r = ViewRect; if (pt.X > r.Left && pt.X < r.Right && pt.Y > r.Y - 3 && pt.Y < r.Y + 3) { return (true); } } return (false); } #endregion #region ProcessPanelMove /// /// Processes the actual panel resizing /// /// MouseEventArgs private void ProcessPanelMove(MouseEventArgs objArg) { if (_IsPanelResizing == true) { Point pt = objArg.Location; if (pt.Y < ClientRect.Y + DayOfWeekHeaderHeight) pt.Y = ClientRect.Y + DayOfWeekHeaderHeight; else if (pt.Y > ClientRect.Bottom - 50) pt.Y = ClientRect.Bottom - 50; int n = pt.Y - (ClientRect.Y + DayOfWeekHeaderHeight); CalendarView.FixedAllDayPanelHeight = n; } } #endregion #region ProcessContentMove /// /// Processes content mouse moves /// /// MouseEventArgs private void ProcessContentMove(MouseEventArgs objArg) { // Locate where the event took place // and process it accordingly int col, slice; if (GetPointItem(objArg.Location, out col, out slice, false)) { // The slice is visible, so no need to // enable scrolling - just process the event EnableViewScrolling(false); ProcessMouseMove(col, slice, objArg); } else if (IsMouseDown == true) { if (DragDropAppointment(objArg) == false) { // The selected slice is not visible, // so we need to enable scrolling EnableViewScrolling(true); // Only process the event if the user is selecting // time slice cells (auto moving apps is intrusive looking) if (DateSelectionAnchor != null) { if (col >= 0) { if (slice < 0) slice = 0; ProcessDvMouseMove(col, slice); } } } } } #region DragDropAppointment /// /// Initiates a user "DragDrop" operation - if enabled /// /// /// True if operation started private bool DragDropAppointment(MouseEventArgs objArgs) { if (IsMoving == true && CanDrag == true) { Point pt = objArgs.Location; BaseView bv = CalendarView.GetViewFromPoint(pt); WeekDayView wv = bv as WeekDayView; if (wv != null && wv != this) { eViewArea area = bv.GetViewAreaFromPoint(pt); if (area == eViewArea.InContent) { if (CalendarView.DoAppointmentViewChanging(SelectedItem, wv.OwnerKey, SelectedItem.StartTime, SelectedItem.EndTime, eViewOperation.AppointmentMove, IsNewCopyDrag) == false) { DragCopy(); ClearMouseStates(); CancelScrollTimer(); if (PosWin != null) PosWin.Hide(); AppointmentView av = SelectedItem as AppointmentView; if (av != null) return (wv.DragAppointment(this, av, objArgs.Location)); CustomCalendarItem ci = SelectedItem as CustomCalendarItem; if (ci != null) return (wv.DragCustomItem(this, ci, objArgs.Location)); } } } } return (false); } #region DragCustomItem private bool DragCustomItem(WeekDayView pv, CustomCalendarItem ci, Point pt) { // Set the new owner and selected view, and // recalc the new layout if (ci.BaseCalendarItem != null) ci = ci.BaseCalendarItem; ci.OwnerKey = OwnerKey; _LastMoveCol = 0; _LastDm = int.MinValue; if (NumberOfColumns > 1) { DateTime sd = ci.StartTime; TimeSpan ts = ci.EndTime.Subtract(ci.StartTime); if (Bounds.X > pv.Bounds.X) { ci.StartTime = new DateTime(_DayColumns[0].Date.Year, _DayColumns[0].Date.Month, _DayColumns[0].Date.Day, sd.Hour, sd.Minute, 0); } else { _LastMoveCol = NumberOfColumns - 1; ci.StartTime = new DateTime(_DayColumns[NumberOfColumns - 1].Date.Year, _DayColumns[NumberOfColumns - 1].Date.Month, _DayColumns[NumberOfColumns - 1].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, pt); return (true); } #endregion #region DragAppointment /// /// Drags the given appointment from one view to another /// /// Previous view /// Item to move private bool DragAppointment(WeekDayView pv, AppointmentView av, Point pt) { // Set the new owner and selected view, and // recalc the new layout av.Appointment.OwnerKey = OwnerKey; _LastMoveCol = 0; _LastDm = int.MinValue; if (NumberOfColumns > 1) { DateTime sd = av.Appointment.StartTime; if (Bounds.X > pv.Bounds.X) { av.Appointment.MoveTo( new DateTime(_DayColumns[0].Date.Year, _DayColumns[0].Date.Month, _DayColumns[0].Date.Day, sd.Hour, sd.Minute, 0)); } else { _LastMoveCol = NumberOfColumns - 1; av.Appointment.MoveTo( new DateTime(_DayColumns[NumberOfColumns - 1].Date.Year, _DayColumns[NumberOfColumns - 1].Date.Month, _DayColumns[NumberOfColumns - 1].Date.Day, sd.Hour, sd.Minute, 0)); } } NeedRecalcLayout = true; RecalcSize(); CalendarView.SelectedOwnerIndex = this.DisplayedOwnerKeyIndex; // Get the new view AppointmentView view = GetAppointmentView(av.Appointment); if (view != null) SetNewDragItem(pv, view, pt); return (true); } #endregion #region SetNewDragItem private void SetNewDragItem(WeekDayView pv, CalendarItem view, Point pt) { _LastBounds = pv._LastBounds; _LastMovePoint = pv._LastMovePoint; _LastPointOffset = pv._LastPointOffset; int dy = _LastPointOffset.Y - _LastBounds.Y; CalendarView.CalendarPanel.InternalMouseMove(new MouseEventArgs(MouseButtons.None, 0, view.Bounds.X, view.Bounds.Y - dy, 0)); MouseEventArgs args = new MouseEventArgs(MouseButtons.Left, 1, view.Bounds.X, view.Bounds.Y + dy, 0); IsMoving = true; InternalMouseMove(args); CalendarView.CalendarPanel.InternalMouseDown(args); SelectedItem = view; IsNewCopyDrag = true; } #endregion #endregion #endregion #region GetContentCursor /// /// Gets the cursor /// /// Cursor private Cursor GetContentCursor() { CalendarItem item = m_HotSubItem as CalendarItem; if (item != null) { switch (item.HitArea) { case CalendarItem.eHitArea.TopResize: case CalendarItem.eHitArea.BottomResize: return (Cursors.SizeNS); case CalendarItem.eHitArea.Move: return (IsMoving ? Cursors.SizeAll : DefaultCursor); } } return (DefaultCursor); } #endregion #region ProcessMouseMove /// /// Processes user MouseMove /// /// DayColumn /// Slice /// private void ProcessMouseMove(int col, int slice, MouseEventArgs objArg) { if (DateSelectionAnchor != null) { ProcessDvMouseMove(col, slice); } else if (SelectedItem != null) { if (objArg.Location.Equals(_LastMovePoint) == false) { if (IsMoving == true) ProcessItemMove(col, slice, objArg); else if (IsStartResizing == true) ProcessItemTopResize(col, slice, objArg); else if (IsEndResizing == true) ProcessItemBottomResize(col, slice, objArg); _LastMovePoint = objArg.Location; } } } #endregion #region DayView mouseMove processing /// /// Processes DayView mouseMove events /// /// DayColumn col index /// Time slice private void ProcessDvMouseMove(int col, int slice) { DateTime date = GetTime(_DayColumns[col].Date, slice, 0); // Let the user select forwards or backwards if (date >= DateSelectionAnchor) { CalendarView.DateSelectionStart = DateSelectionAnchor.Value; CalendarView.DateSelectionEnd = date.AddMinutes(TimeSlotDuration); } else { CalendarView.DateSelectionStart = date; CalendarView.DateSelectionEnd = DateSelectionAnchor.Value.AddMinutes(TimeSlotDuration); } } #endregion #region CalendarItem MouseMove processing #region ProcessItemMove /// /// Processes CalendarItem mouseMove events /// /// DayColumn col index /// Time slice /// private void ProcessItemMove(int col, int slice, MouseEventArgs objArg) { // Calculate our new item date int dm = GetDeltaMinutes(slice, true, objArg); if (_LastDm == int.MinValue) _LastDm = dm; int ddm = dm - _LastDm; if (_LastMoveCol == -1) _LastMoveCol = col; if (col != _LastMoveCol) ddm += ((col - _LastMoveCol) * HoursPerDay * MinutesPerHour); _LastDm = dm; _LastMoveCol = col; DateTime newDate = SelectedItem.StartTime.AddMinutes(ddm); TimeSpan ts = SelectedItem.EndTime - SelectedItem.StartTime; if (newDate != SelectedItem.StartTime) { if (CalendarView.AllDayDisplayMode != eAllDayDisplayMode.None) { // Make sure we don't cross day boundaries DateTime start = GetTime(_DayColumns[col].Date, 0, 0); DateTime end = start.AddMinutes(NumberOfActiveSlices * TimeSlotDuration); if (newDate < start) newDate = start; if (newDate + ts > end) newDate -= (newDate + ts) - end; } // If we have a new date, set our item to it if (newDate != SelectedItem.StartTime) { if (DragCopy() == false) { try { if (SelectedItem is CustomCalendarItem) CalendarView.CustomItems.BeginUpdate(); else CalendarModel.BeginUpdate(); // Make the move if (CalendarView.DoAppointmentViewChanging(SelectedItem, null, newDate, newDate + ts, eViewOperation.AppointmentMove, IsCopyDrag) == false) { SelectedItem.StartTime = newDate; SelectedItem.EndTime = newDate + ts; InvalidateItems(col); } } finally { if (SelectedItem is CustomCalendarItem) CalendarView.CustomItems.EndUpdate(); else CalendarModel.EndUpdate(); } } else { _LastMoveCol = _LastCol; } } } } #endregion #endregion #region CalendarItem MouseResize processing #region ProcessItemTopResize /// /// Processes CalendarItem left resizing /// /// Time slice /// private void ProcessItemTopResize(int col, int slice, MouseEventArgs objArg) { int dm = GetDeltaMinutes(slice, true, objArg); DateTime newStartTime; if (CalendarView.AllDayDisplayMode != eAllDayDisplayMode.None) { newStartTime = new DateTime( SelectedItem.StartTime.Year, SelectedItem.StartTime.Month, SelectedItem.StartTime.Day); newStartTime = GetTime(newStartTime, 0, dm); } else { newStartTime = GetTime(_DayColumns[col].Date.Date, 0, dm); if (newStartTime < _DayColumns[0].Date) newStartTime = _DayColumns[0].Date; } if (newStartTime != SelectedItem.StartTime && newStartTime < SelectedItem.EndTime) { if ((SelectedItem.EndTime - newStartTime).TotalMinutes < 0) newStartTime = SelectedItem.EndTime.AddMinutes(-1); ResizeItem(_LastCol, newStartTime, SelectedItem.EndTime); } } #endregion #region ProcessItemBottomResize /// /// Processes CalendarItem right resizing /// /// Time slice /// private void ProcessItemBottomResize(int col, int slice, MouseEventArgs objArg) { int dm = GetDeltaMinutes(slice, false, objArg); DateTime newEndTime; DateTime end; if (CalendarView.AllDayDisplayMode != eAllDayDisplayMode.None) { newEndTime = new DateTime( SelectedItem.StartTime.Year, SelectedItem.StartTime.Month, SelectedItem.StartTime.Day); if (newEndTime < _DayColumns[0].Date) newEndTime = _DayColumns[0].Date; newEndTime = GetTime(newEndTime, 0, dm); end = GetTime(_DayColumns[_LastCol].Date, NumberOfActiveSlices, 0); } else { newEndTime = GetTime(_DayColumns[col].Date.Date, 0, dm); if (newEndTime < _DayColumns[0].Date) newEndTime = _DayColumns[0].Date; end = GetTime(_DayColumns[_DayColumns.Length - 1].Date, NumberOfActiveSlices, 0); } if (newEndTime > end) newEndTime = end; if (newEndTime != SelectedItem.EndTime && newEndTime > SelectedItem.StartTime) { if ((newEndTime - SelectedItem.StartTime).TotalMinutes < 0) newEndTime = SelectedItem.StartTime.AddMinutes(1); ResizeItem(_LastCol, SelectedItem.StartTime, newEndTime); } } #endregion #region ResizeItem /// /// Initiates the resize of the selected item /// /// /// /// private void ResizeItem(int col, DateTime startTime, DateTime endTime) { // Let the user cancel the operation if desired if (CalendarView.DoAppointmentViewChanging(SelectedItem, null, startTime, endTime, eViewOperation.AppointmentResize, IsNewCopyDrag) == false) { InvalidateItems(col); SelectedItem.StartTime = startTime; SelectedItem.EndTime = endTime; } } #endregion #endregion #region GetDeltaMinutes /// /// Gets the changes in minutes /// from the last mouse operation (move or resize) /// /// Current slice /// Flag denoting top or bottom delta /// MouseEventArgs /// Delta minutes private int GetDeltaMinutes(int slice, bool ftop, MouseEventArgs objArg) { // Calculate our delta minutes Rectangle t = GetSliceRect(0, slice); int dm = (objArg.Location.Y - _LastPointOffset.Y); dm += ftop ? _LastBounds.Top - t.Top : _LastBounds.Bottom - t.Bottom; dm = (int)(TimeSlotDuration * dm / TimeSliceHeight); // If the Alt key is not pressed, then round // our value off to the nearest slice if ((Control.ModifierKeys & Keys.Alt) != Keys.Alt) { slice += (dm / TimeSlotDuration); dm = 0; } dm += (slice * TimeSlotDuration); // Make sure we don't cross our day boundaries if (CalendarView.AllDayDisplayMode != eAllDayDisplayMode.None) { if (ftop == true) { if (dm < 0) dm = 0; } else { dm += TimeSlotDuration; if (dm >= MinutesPerHour * HoursPerDay) dm = MinutesPerHour * HoursPerDay - 1; } } return (dm); } #endregion #region InvalidateItems /// /// Invalidates altered DayColumns /// /// Current column internal void InvalidateItems(int col) { if (SelectedItem.IsRecurring == false) { _DayColumns[_LastCol].NeedRecalcLayout = true; _DayColumns[col].NeedRecalcLayout = true; InvalidateRect(_DayColumns[col].Bounds, true); if (_LastCol != col) InvalidateRect(_DayColumns[_LastCol].Bounds); } else { NeedRecalcLayout = true; } _LastCol = col; } #endregion #region View Scrolling support #region EnableViewScrolling /// /// Routine to enable or disable view scrolling /// /// true to enable private void EnableViewScrolling(bool enable) { if (enable == true) { if (VsPanel.ScrollBar.Maximum > VsPanel.ScrollBar.LargeChange) { if (_ScrollViewTimer == null) { _ScrollViewTimer = new Timer(); _ScrollViewTimer.Interval = 10; _ScrollViewTimer.Tick += ScrollViewTimerTick; _ScrollViewTimer.Start(); } } } else { CancelScrollTimer(); } } #endregion #region CancelScrollTimer /// /// Cancels the view scroll timer /// private void CancelScrollTimer() { // Dispose of our scroll timer if (_ScrollViewTimer != null) { _ScrollViewTimer.Stop(); _ScrollViewTimer.Tick -= ScrollViewTimerTick; _ScrollViewTimer = null; } } #endregion #region ScrollAmount /// /// Determines the amount to scroll (which is /// based loosely upon the delta magnitude) /// /// Point delta /// Scroll amount private int ScrollAmount(int delta) { int dy = Math.Abs(delta); int amt = (dy < 16 ? 2 : dy < 32 ? 8 : 32); return (delta < 0 ? -amt : amt); } #endregion #region ScrollViewTimer_Tick /// /// Handles view scroll timer ticks /// /// object /// EventArgs private void ScrollViewTimerTick(object sender, EventArgs e) { Control c = (Control)this.GetContainerControl(true); if (c != null) { // Calculate our delta Point pt = c.PointToClient(Cursor.Position); Rectangle r = ViewRect; int dy = (pt.Y < r.Top) ? ScrollAmount(pt.Y - r.Top) : (pt.Y >= r.Bottom) ? ScrollAmount(pt.Y - r.Bottom) : 0; // Scroll if necessary if (dy != 0) { int value = VsPanel.ScrollBar.Value + dy; value = Math.Max(value, 0); value = Math.Min(value, VsPanel.ScrollBar.Maximum); if (VsPanel.ScrollBar.Value != value) { VsPanel.ScrollBar.Value = value; if (PosWin != null) PosWin.Hide(); InternalMouseMove(new MouseEventArgs(MouseButtons.Left, 0, pt.X, pt.Y, 0)); } } } } #endregion #endregion #endregion #endregion #region InternalKeyDown #region InternalKeyDown /// /// Processes KeyDown events /// /// 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, -CalendarView.TimeSlotDuration); break; case Keys.Down: case Keys.Down | Keys.Shift: case Keys.Down | Keys.Control: case Keys.Down | Keys.Control | Keys.Shift: ProcessUpDownKey(objArg, CalendarView.TimeSlotDuration); 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: ProcessPageUpDownKey(objArg, -1); break; case Keys.PageDown: case Keys.PageDown | Keys.Shift: case Keys.PageDown | Keys.Control: case Keys.PageDown | Keys.Control | Keys.Shift: ProcessPageUpDownKey(objArg, 1); break; } } #endregion #region ProcessUpDownKey /// /// Processes Up and Down key events /// /// /// 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.AddMinutes(-TimeSlotDuration); startDate = startDate.AddMinutes(dy); DateTime viewStart = GetTime(DayColumns[0].Date, 0, 0); DateTime viewEnd = viewStart.AddMinutes(NumberOfActiveSlices * TimeSlotDuration); endDate = startDate.AddMinutes(TimeSlotDuration); if (startDate >= viewStart && endDate <= viewEnd) { ExtendSelection(ref startDate, ref endDate); CalendarView.DateSelectionStart = startDate; CalendarView.DateSelectionEnd = endDate; EnsureSelectionVisible(); } } objArg.Handled = true; } #endregion #region ProcessLeftRightKey /// /// Processes Left and Right key events /// /// /// protected virtual void ProcessLeftRightKey(KeyEventArgs objArg, int dx) { if (CalendarView.WeekDayCanExtendRange == true) { DateTime oldDate = CalendarView.DayViewDate; DateTime newDate = CalendarView.DayViewDate.AddDays(dx); if (CalendarView.DoViewDateChanging(this, oldDate, oldDate, ref newDate, ref newDate) == false) { if (ValidDateSelection()) { dx = (newDate - oldDate).Days; DateTime startDate = CalendarView.DateSelectionStart.Value; DateTime endDate = CalendarView.DateSelectionEnd.Value; startDate = startDate.AddDays(dx); endDate = endDate.AddDays(dx); CalendarView.DateSelectionStart = startDate; CalendarView.DateSelectionEnd = endDate; DateSelectionAnchor = DateSelectionAnchor.Value.AddDays(dx); } CalendarView.DayViewDate = CalendarView.DayViewDate.AddDays(dx); } } objArg.Handled = true; } #endregion #region ProcessHomeKey /// /// Processes Home key events /// /// protected virtual void ProcessHomeKey(KeyEventArgs objArg) { int col = GetHomeEndCol(); if (col >= 0) { DateTime startDate = GetTime(DayColumns[col].Date, 0, 0); if ((objArg.Modifiers & Keys.Control) != Keys.Control) { WorkTime wt = DayColumns[col].WorkStartTime; if (wt.IsEmpty == false) startDate = DayColumns[col].Date.AddMinutes(wt.Hour * 60 + wt.Minute); } DateTime endDate = startDate.AddMinutes(TimeSlotDuration); ExtendSelection(ref startDate, ref endDate); CalendarView.DateSelectionStart = startDate; CalendarView.DateSelectionEnd = endDate; EnsureSelectionVisible(); } objArg.Handled = true; } #endregion #region ProcessEndKey /// /// Processes End Key events /// /// protected virtual void ProcessEndKey(KeyEventArgs objArg) { int col = GetHomeEndCol(); if (col >= 0) { DateTime startDate = GetTime(DayColumns[col].Date, NumberOfActiveSlices, 0); if ((objArg.Modifiers & Keys.Control) != Keys.Control) { WorkTime wt = DayColumns[col].WorkEndTime; if (wt.IsEmpty == false) startDate = DayColumns[col].Date.AddMinutes(wt.Hour * 60 + wt.Minute); } DateTime endDate = startDate; startDate = startDate.AddMinutes(-TimeSlotDuration); ExtendSelection(ref startDate, ref endDate); CalendarView.DateSelectionStart = startDate; CalendarView.DateSelectionEnd = endDate; EnsureSelectionVisible(); } objArg.Handled = true; } #endregion #region ProcessPageUpDownKey /// /// Processes Page Up and Down key events /// /// /// Paging direction (-1, 1) protected virtual void ProcessPageUpDownKey(KeyEventArgs objArg, int dy) { if (ValidDateSelection()) { DateTime startDate = CalendarView.DateSelectionStart.Value; DateTime endDate = CalendarView.DateSelectionEnd.Value; int col = GetColumnFromDate(startDate); if ((uint)col < DayColumns.Length) { DateTime viewStart = GetTime(DayColumns[col].Date, 0, 0); DateTime viewEnd = viewStart.AddMinutes(NumberOfActiveSlices * TimeSlotDuration); if (startDate.Equals(DateSelectionAnchor.Value) == true) startDate = endDate.AddMinutes(-TimeSlotDuration); startDate = (dy < 0) ? GetPageUpStartDate(viewStart, startDate) : GetPageDownStartDate(viewStart, viewEnd, startDate); endDate = startDate.AddMinutes(TimeSlotDuration); if (startDate >= viewStart && endDate <= viewEnd) { ExtendSelection(ref startDate, ref endDate); CalendarView.DateSelectionStart = startDate; CalendarView.DateSelectionEnd = endDate; EnsureSelectionVisible(); } } } objArg.Handled = true; } private DateTime GetPageUpStartDate( DateTime viewStart, DateTime startDate) { DateTime fosDate = viewStart.AddMinutes(TimeSlotDuration*FirstOnScreenSlice); if (startDate.Equals(fosDate) == false) return (fosDate); startDate = startDate.AddMinutes(-TimeSlotDuration * OnScreenSlices); if (startDate < viewStart) startDate = viewStart; return (startDate); } private DateTime GetPageDownStartDate( DateTime viewStart, DateTime viewEnd, DateTime startDate) { DateTime eosDate = viewStart.AddMinutes(TimeSlotDuration * LastOnScreenSlice); if (startDate.Equals(eosDate) == false) return (eosDate); startDate = eosDate.AddMinutes(TimeSlotDuration * OnScreenSlices); if (startDate > viewEnd) startDate = viewEnd; return (startDate); } #endregion #region GetHomeEndCol /// /// Gets the Home and End column from the current /// selection range /// /// private int GetHomeEndCol() { if (ValidDateSelection() == true) { if (CalendarView.DateSelectionStart.Equals(DateSelectionAnchor.Value) == true) return (GetColumnFromDate(DateSelectionEnd.Value.AddMinutes(-TimeSlotDuration))); return (GetColumnFromDate(DateSelectionStart.Value)); } return ((NumberOfColumns == 1) ? 0 : -1); } #endregion #region GetColumnFromDate /// /// Gets the view column from the given date /// /// /// The DayColumns index, or -1 if invalid. public int GetColumnFromDate(DateTime date) { for (int i = 0; i < DayColumns.Length; i++) { DateTime dc = DayColumns[i].Date.Date; if (dc <= date && dc.AddDays(1) > date) return (i); } return (-1); } #endregion #region EnsureSelectionVisible /// /// Ensures the given selection is visible /// protected virtual void EnsureSelectionVisible() { DateTime start = CalendarView.DateSelectionStart.Value; DateTime end = CalendarView.DateSelectionEnd.Value; bool refreshed = start.Equals(DateSelectionAnchor) ? EnsureDateVisible(end.AddMinutes(-CalendarView.TimeSlotDuration)) : EnsureDateVisible(start); if (refreshed == false) Refresh(); } #endregion #region EnsureDateVisible /// /// Ensures the given date is visible /// /// /// protected virtual bool EnsureDateVisible(DateTime date) { if (CalendarView.WeekDayVScrollPanel.ScrollBar.Maximum > CalendarView.WeekDayVScrollPanel.ScrollBar.LargeChange) { Rectangle r = ViewRect; int offset = (int)(date.Hour * CalendarView.SlotsPerHour * CalendarView.TimeSliceHeight + (CalendarView.TimeSliceHeight * date.Minute) / CalendarView.TimeSlotDuration); offset -= (int)(CalendarView.StartSlice * CalendarView.TimeSliceHeight); int top = CalendarView.WeekDayVScrollPanel.ScrollBar.Value; int bottom = top + r.Height; if (offset < top || offset + CalendarView.TimeSliceHeight > bottom) { if (offset + CalendarView.TimeSliceHeight > bottom) offset -= (int)(r.Height - CalendarView.TimeSliceHeight); offset = Math.Min(offset, CalendarView.WeekDayVScrollPanel.ScrollBar.Maximum); offset = Math.Max(offset, 0); CalendarView.WeekDayVScrollPanel.ScrollBar.Value = offset; return (true); } return (false); } return (true); } #endregion #endregion #region TimeSlice support routines #region GetPointItem /// /// Gets the column and slice index item for /// the given point /// /// Point /// [out] DayColumn column /// [out] Time slice /// /// Item visible state private bool GetPointItem(Point pt, out int col, out int slice, bool partial) { slice = -1; if ((col = GetPointCol(pt)) >= 0) { slice = GetPointSlice(pt, col); if (slice >= 0 && slice < NumberOfActiveSlices) return (IsSliceVisible(col, slice, partial)); } return (false); } #endregion #region IsSliceVisible /// /// Determines if a given slice is visible /// /// DayColumn /// Slice in question /// Partially visible is ok /// Slice visibility private bool IsSliceVisible(int col, int slice, bool partial) { Rectangle r = GetSliceRect(col, slice); Rectangle t = ViewRect; if (partial == true) { if (r.Bottom < t.Top) return (false); if (r.Top > t.Bottom) return (false); } else { if (r.Top < t.Top) return (false); if (r.Bottom > t.Bottom) return (false); } return (true); } #endregion #region GetSliceRect /// /// Gets the given slice rectangle /// /// Column /// Slice /// Bounding rectangle private Rectangle GetSliceRect(int col, int slice) { if ((uint)col < _DayColumns.Length) { Rectangle r = _DayColumns[col].Bounds; float n = slice * TimeSliceHeight; r.Y += (int)(n); r.Height = (int)(n + TimeSliceHeight) - (int)n; return (r); } return (Rectangle.Empty); } #endregion #region GetPointCol /// /// Gets the col index for the given point /// /// Point /// Column private int GetPointCol(Point pt) { for (int i = 0; i < _NumberOfColumns; i++) { if (pt.X >= _DayColumns[i].Bounds.X && pt.X < _DayColumns[i].Bounds.Right) { return (i); } } return (-1); } #endregion #region GetPointSlice /// /// Gets the slice index for the given point /// /// Point /// /// Slice index private int GetPointSlice(Point pt, int col) { int s1 = (int)(-_VScrollPos / TimeSliceHeight); Rectangle r = GetSliceRect(col, s1); if (pt.Y < r.Top) return (s1 - 1); for (int i = s1; i < NumberOfActiveSlices; i++) { r = GetSliceRect(col, i); if (pt.Y >= r.Top && pt.Y < r.Bottom) return (i); } return (NumberOfActiveSlices - 1); } #endregion #region GetTime /// /// Gets the DateTime adjusted by the given /// slice and minutes delta /// /// /// /// /// private DateTime GetTime(DateTime date, int slice, int minutes) { return (date.AddMinutes((StartSlice + slice) * TimeSlotDuration + minutes)); } #endregion #endregion #region IDisposable Members protected override void Dispose(bool disposing) { if (disposing == true && IsDisposed == false) { ResetView(); BusyBrush = null; WorkBrush = null; OffWorkBrush = null; SelectedBrush = null; HookEvents(false); } base.Dispose(disposing); } #endregion #region Copy object support /// /// Returns copy of the item. /// public override BaseItem Copy() { WeekDayView objCopy = new WeekDayView(this.CalendarView, this.ECalendarView); CopyToItem(objCopy); return (objCopy); } /// /// Copies the WeekDayView specific properties to new instance of the item. /// /// New WeekDayView instance protected override void CopyToItem(BaseItem copy) { WeekDayView objCopy = copy as WeekDayView; base.CopyToItem(objCopy); } #endregion #region DaySlot class def private class DaySlot { public Rectangle Bounds; public bool Selected; public DaySlotAppearance Appearance; } #endregion } } #endif