3356 lines
100 KiB
C#
3356 lines
100 KiB
C#
#if FRAMEWORK20
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Windows.Forms;
|
|
using DevComponents.DotNetBar.ScrollBar;
|
|
using DevComponents.Schedule.Model;
|
|
|
|
namespace DevComponents.DotNetBar.Schedule
|
|
{
|
|
public class TimeLineView : BaseView
|
|
{
|
|
#region Static variables
|
|
|
|
static private AppointmentColor _appointmentColor = new AppointmentColor();
|
|
|
|
#endregion
|
|
|
|
#region Private variables
|
|
|
|
private CalendarWeekDayColor _ViewColor = // View display color table
|
|
new CalendarWeekDayColor(eCalendarColor.Automatic);
|
|
|
|
private List<CalendarItem>
|
|
_CalendarItems = new List<CalendarItem>();
|
|
|
|
private Point _LastMovePoint; // Last mouse move Point
|
|
private Point _LastPointOffset; // Last Point offset
|
|
private Rectangle _LastBounds; // MouseDown item bounds
|
|
|
|
private int _SelectedColStart; // Column start selection
|
|
private int _SelectedColEnd; // Column end selection
|
|
|
|
private Timer _ScrollViewTimer; // Timer used to implement auto view scrolling
|
|
private int _ScrollDwell; // Scroll dwell (pause, throttle) counter
|
|
|
|
private Color _WorkColor; // Cached Brush colors
|
|
private Color _OffWorkColor;
|
|
private Color _SelectedColor;
|
|
|
|
private Brush _WorkBrush; // Cached Brushes
|
|
private Brush _OffWorkBrush;
|
|
private Brush _SelectedBrush;
|
|
|
|
private int _HScrollPos; // Horizontal scroll position
|
|
|
|
private List<ColumnList> _CondensedColList;
|
|
private List<int> _CollateLines = new List<int>();
|
|
|
|
private bool _ModelReloaded = true;
|
|
|
|
#endregion
|
|
|
|
public TimeLineView(CalendarView calendarView, eCalendarView eCalendarView)
|
|
: base(calendarView, eCalendarView)
|
|
{
|
|
// Set our non-client drawing info and CalendarColor
|
|
|
|
NClientData = new NonClientData(
|
|
eTabOrientation.Vertical,
|
|
(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);
|
|
|
|
if (calendarView.TimeLineHScrollPanel.ScrollBar != null)
|
|
{
|
|
_HScrollPos = -calendarView.TimeLineHScrollPanel.ScrollBar.Value *
|
|
calendarView.TimeLineColumnWidth;
|
|
}
|
|
}
|
|
|
|
#region Public properties
|
|
|
|
#region CalendarItems
|
|
|
|
/// <summary>
|
|
/// Gets array of CalendarItems
|
|
/// </summary>
|
|
public List<CalendarItem> CalendarItems
|
|
{
|
|
get { return (_CalendarItems); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region StartDate
|
|
|
|
/// <summary>
|
|
/// Start date - readonly
|
|
/// </summary>
|
|
public new DateTime StartDate
|
|
{
|
|
get { return (base.StartDate); }
|
|
internal set { base.StartDate = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region EndDate
|
|
|
|
/// <summary>
|
|
/// End date - readonly
|
|
/// </summary>
|
|
public new DateTime EndDate
|
|
{
|
|
get { return (base.EndDate); }
|
|
internal set { base.EndDate = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ColumnWidth
|
|
|
|
/// <summary>
|
|
/// Gets the ColumnWidth
|
|
/// </summary>
|
|
public int ColumnWidth
|
|
{
|
|
get { return (CalendarView.TimeLineColumnWidth); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region BaseInterval
|
|
|
|
/// <summary>
|
|
/// Gets the BaseInterval (interval in total minutes)
|
|
/// </summary>
|
|
public double BaseInterval
|
|
{
|
|
get { return (CalendarView.BaseInterval); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TimeLineColumnCount
|
|
|
|
/// <summary>
|
|
/// Gets the number of Columns
|
|
/// </summary>
|
|
public int TimeLineColumnCount
|
|
{
|
|
get { return (CalendarView.TimeLineColumnCount); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MinAppointmentWidth
|
|
|
|
/// <summary>
|
|
/// Gets the MinAppointmentWidth
|
|
/// </summary>
|
|
public int MinAppointmentWidth
|
|
{
|
|
get { return (CalendarView.TimeLineMinAppointmentWidth); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Private properties
|
|
|
|
#region ShowCondensed
|
|
|
|
/// <summary>
|
|
/// Gets the CondensedView visibility state
|
|
/// </summary>
|
|
private bool ShowCondensed
|
|
{
|
|
get
|
|
{
|
|
if (CalendarView.TimeLineCondensedViewVisibility == eCondensedViewVisibility.Hidden)
|
|
return (false);
|
|
|
|
if (CalendarView.TimeLineCondensedViewHeight < 10)
|
|
return (false);
|
|
|
|
if (CalendarView.TimeLineCondensedViewVisibility == eCondensedViewVisibility.AllResources)
|
|
return (true);
|
|
|
|
return (CalendarView.SelectedOwnerIndex == DisplayedOwnerKeyIndex);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Cached Brushes
|
|
|
|
#region WorkBrush
|
|
|
|
/// <summary>
|
|
/// Gets and sets the Work time brush
|
|
/// </summary>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Gets and sets the Off-hours work time brush
|
|
/// </summary>
|
|
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 SelectedBrush
|
|
|
|
/// <summary>
|
|
/// Gets and sets the selected brush
|
|
/// </summary>
|
|
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
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Internal Properties
|
|
|
|
/// <summary>
|
|
/// Gets the first visible timeline column
|
|
/// </summary>
|
|
internal int FirstVisibleColumn
|
|
{
|
|
get { return (-_HScrollPos / ColumnWidth); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the condensed time line height
|
|
/// </summary>
|
|
internal int CondensedLineHeight
|
|
{
|
|
get { return (CalendarView.TimeLineCondensedViewHeight); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets and sets the model reload state
|
|
/// </summary>
|
|
internal bool ModelReloaded
|
|
{
|
|
get { return (_ModelReloaded); }
|
|
set { _ModelReloaded = value; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Hook / Unhook Events
|
|
|
|
/// <summary>
|
|
/// Routine hooks all necessary events for this control
|
|
/// </summary>
|
|
/// <param name="hook">True to hook, false to unhook</param>
|
|
private void HookEvents(bool hook)
|
|
{
|
|
if (hook == true)
|
|
{
|
|
CalendarView.SelectedViewChanged += SelectedViewChanged;
|
|
CalendarView.SelectedOwnerChanged += SelectedOwnerChanged;
|
|
|
|
CalendarView.TimeLineViewStartDateChanged += TimeLineViewStartDateChanged;
|
|
CalendarView.TimeLineViewEndDateChanged += TimeLineViewEndDateChanged;
|
|
CalendarView.TimeLineIntervalChanged += TimeLineIntervalChanged;
|
|
CalendarView.TimeLineIntervalPeriodChanged += TimeLineIntervalPeriodChanged;
|
|
CalendarView.TimeLineCondensedViewVisibilityChanged += TimeLineCondensedViewVisibilityChanged;
|
|
|
|
CalendarView.TimeLineHScrollPanel.ScrollPanelChanged += ScrollPanelChanged;
|
|
}
|
|
else
|
|
{
|
|
CalendarView.SelectedViewChanged -= SelectedViewChanged;
|
|
CalendarView.SelectedOwnerChanged -= SelectedOwnerChanged;
|
|
|
|
CalendarView.TimeLineViewStartDateChanged -= TimeLineViewStartDateChanged;
|
|
CalendarView.TimeLineViewEndDateChanged -= TimeLineViewEndDateChanged;
|
|
CalendarView.TimeLineIntervalChanged -= TimeLineIntervalChanged;
|
|
CalendarView.TimeLineIntervalPeriodChanged -= TimeLineIntervalPeriodChanged;
|
|
CalendarView.TimeLineCondensedViewVisibilityChanged -= TimeLineCondensedViewVisibilityChanged;
|
|
|
|
CalendarView.TimeLineHScrollPanel.ScrollPanelChanged -= ScrollPanelChanged;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Event handling routines
|
|
|
|
#region SelectedViewChanged
|
|
|
|
/// <summary>
|
|
/// Processes view changes
|
|
/// </summary>
|
|
/// <param name="sender">object</param>
|
|
/// <param name="e">SelectedViewEventArgs</param>
|
|
void SelectedViewChanged(object sender, SelectedViewEventArgs e)
|
|
{
|
|
// Update our IsViewSelected state
|
|
|
|
IsViewSelected = (e.NewValue == ECalendarView);
|
|
|
|
if (IsViewSelected == true)
|
|
{
|
|
AutoSyncViewDate(e.OldValue);
|
|
UpdateDateSelection();
|
|
}
|
|
else
|
|
{
|
|
ResetView();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SelectedOwnerChanged
|
|
|
|
void SelectedOwnerChanged(object sender, SelectedOwnerChangedEventArgs e)
|
|
{
|
|
if (CalendarView.TimeLineStretchRowHeight == true)
|
|
{
|
|
if (CalendarView.TimeLineCondensedViewVisibility == eCondensedViewVisibility.SelectedResource)
|
|
NeedRecalcLayout = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TimeLineViewStartDateChanged
|
|
|
|
/// <summary>
|
|
/// Processes StartDate changes
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
void TimeLineViewStartDateChanged(object sender, DateChangeEventArgs e)
|
|
{
|
|
StartDate = e.NewValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TimeLineViewEndDateChanged
|
|
|
|
/// <summary>
|
|
/// Processes EndDate changes
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
void TimeLineViewEndDateChanged(object sender, DateChangeEventArgs e)
|
|
{
|
|
EndDate = e.NewValue;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TimeLineIntervalPeriodChanged
|
|
|
|
/// <summary>
|
|
/// Handles IntervalPeriodChange notification
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
void TimeLineIntervalPeriodChanged(object sender, TimeLineIntervalPeriodChangedEventArgs e)
|
|
{
|
|
NeedRecalcSize = true;
|
|
NeedRecalcLayout = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TimeLineIntervalChanged
|
|
|
|
/// <summary>
|
|
/// Handles IntervalChange notification
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
void TimeLineIntervalChanged(object sender, TimeLineIntervalChangedEventArgs e)
|
|
{
|
|
NeedRecalcSize = true;
|
|
NeedRecalcLayout = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TimeLineCondensedViewVisibilityChanged
|
|
|
|
void TimeLineCondensedViewVisibilityChanged(
|
|
object sender, TimeLineCondensedViewVisibilityChangedEventArgs e)
|
|
{
|
|
if (CalendarView.TimeLineStretchRowHeight == true)
|
|
NeedRecalcLayout = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ScrollPanelChanged
|
|
|
|
/// <summary>
|
|
/// Handles ScrollPanel change notification
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
void ScrollPanelChanged(object sender, EventArgs e)
|
|
{
|
|
TimeLineHScrollPanel panel = sender as TimeLineHScrollPanel;
|
|
|
|
if (panel != null)
|
|
{
|
|
HScrollBarAdv hScrollBar = panel.ScrollBar;
|
|
|
|
_HScrollPos = -hScrollBar.Value * CalendarView.TimeLineColumnWidth;
|
|
|
|
// Redraw our view
|
|
|
|
if (Displayed == true)
|
|
{
|
|
NeedRecalcLayout = true;
|
|
|
|
InvalidateRect(true);
|
|
Refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
#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 (pt.X >= ClientRect.X)
|
|
{
|
|
// CondensedView
|
|
|
|
if (ShowCondensed == true)
|
|
{
|
|
if (GetCondensedRect().Contains(pt) == true)
|
|
return (eViewArea.InCondensedView);
|
|
}
|
|
|
|
return (eViewArea.InContent);
|
|
}
|
|
|
|
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
|
|
/// </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 col;
|
|
|
|
if (GetPointItem(pt, out col, true) == true)
|
|
{
|
|
startDate = CalendarView.TimeLineAddInterval(StartDate, col);
|
|
endDate = CalendarView.TimeLineAddInterval(startDate, 1);
|
|
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (ci.IsSelected == true)
|
|
{
|
|
if (SelectedItem != null && ci != SelectedItem)
|
|
SelectedItem.IsSelected = false;
|
|
|
|
SelectedItem = ci;
|
|
}
|
|
else
|
|
{
|
|
if (ci == SelectedItem)
|
|
SelectedItem = null;
|
|
}
|
|
|
|
// Make sure the selection is reflected
|
|
// in the condensed view (if present)
|
|
|
|
if (ShowCondensed == true)
|
|
InvalidateRect(GetCondensedRect());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the current selected item
|
|
/// </summary>
|
|
/// <param name="pci">Previous CalendarItem</param>
|
|
/// <param name="nci">New CalendarItem</param>
|
|
/// <returns>New selected CalendarItem</returns>
|
|
protected override CalendarItem SetSelectedItem(CalendarItem pci, CalendarItem nci)
|
|
{
|
|
if (nci != null)
|
|
nci.IsSelected = true;
|
|
|
|
else if (pci != null)
|
|
pci.IsSelected = false;
|
|
|
|
return (nci);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateDateSelection
|
|
|
|
/// <summary>
|
|
/// Updates our slice selection range to reflect
|
|
/// the given date selection start and end values
|
|
/// </summary>
|
|
protected override void UpdateDateSelection()
|
|
{
|
|
if (IsViewSelected == true)
|
|
{
|
|
// Get the new absolute slice selection range
|
|
|
|
int colStart = GetDateCol(DateSelectionStart);
|
|
int colEnd = GetDateCol(DateSelectionEnd);
|
|
|
|
// Limit our range to only those columns
|
|
// that are visible on the screen
|
|
|
|
int c1 = -_HScrollPos / ColumnWidth;
|
|
int c2 = c1 + ClientRect.Width / ColumnWidth + 1;
|
|
|
|
if (c2 > c1)
|
|
{
|
|
ProcessSelRange(colStart, colEnd, c1, c2);
|
|
|
|
// Save our new selection range
|
|
|
|
_SelectedColStart = colStart;
|
|
_SelectedColEnd = colEnd;
|
|
}
|
|
|
|
if (ShowCondensed == true)
|
|
{
|
|
Rectangle r = GetCondensedRect();
|
|
|
|
this.InvalidateRect(r);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes the selection time column range
|
|
/// </summary>
|
|
/// <param name="colStart">Column range start</param>
|
|
/// <param name="colEnd">Column range end</param>
|
|
/// <param name="c1">Column start limit</param>
|
|
/// <param name="c2">Column end limit</param>
|
|
private void ProcessSelRange(int colStart, int colEnd, int c1, int c2)
|
|
{
|
|
bool[] oldSelected = SelectedColumns(c1, c2, _SelectedColStart, _SelectedColEnd);
|
|
bool[] newSelected = SelectedColumns(c1, c2, colStart, colEnd);
|
|
|
|
// Invalidate those slices whose
|
|
// selection status changed
|
|
|
|
Rectangle r = GetColRect(c1);
|
|
|
|
if (r.Width > 0 && r.Height > 0)
|
|
{
|
|
for (int i = 0; i < c2 - c1; i++)
|
|
{
|
|
if (oldSelected[i] != newSelected[i])
|
|
InvalidateRect(r);
|
|
|
|
r.X += ColumnWidth;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets an array of column selection values
|
|
/// over the given range of columns
|
|
/// </summary>
|
|
/// <param name="c1">Column start limit</param>
|
|
/// <param name="c2">Column end limit</param>
|
|
/// <param name="colStart">Slice range start</param>
|
|
/// <param name="colEnd">Slice range end</param>
|
|
/// <returns>Array of selection values</returns>
|
|
private bool[] SelectedColumns(int c1, int c2, int colStart, int colEnd)
|
|
{
|
|
// Calculate our number of entries and
|
|
// allocate our IsSelected array accordingly
|
|
|
|
int n = c2 - c1;
|
|
bool[] sel = new bool[n + 1];
|
|
|
|
// Loop through the range of entries determining if
|
|
// the specific col is within the selection range
|
|
|
|
for (int i = 0; i < n; i++)
|
|
sel[i] = (c1 + i >= colStart && c1 + i < colEnd);
|
|
|
|
// Return the array to the caller
|
|
|
|
return (sel);
|
|
}
|
|
|
|
#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);
|
|
|
|
// Update our Model connection view,
|
|
// CalendarItems, and DateSelection
|
|
|
|
UpdateView();
|
|
UpdateDateSelection();
|
|
}
|
|
|
|
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>
|
|
protected virtual void NormalizeDates(out DateTime startDate, out DateTime endDate)
|
|
{
|
|
startDate = this.StartDate;
|
|
endDate = this.EndDate;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateView
|
|
|
|
/// <summary>
|
|
/// Updates our connection model view
|
|
/// </summary>
|
|
private void UpdateView()
|
|
{
|
|
// Make sure we have a model connection
|
|
|
|
if (Connector == null)
|
|
{
|
|
if (CalendarModel != null)
|
|
Connector = new ModelTimeLineViewConnector(CalendarModel, this);
|
|
}
|
|
else
|
|
{
|
|
// The timeline range could have changed, so let
|
|
// the connection refresh the data if needed
|
|
|
|
((ModelTimeLineViewConnector)Connector).RefreshData(false);
|
|
}
|
|
|
|
// We have a connection, so update our CalendarItems
|
|
|
|
if (Connector != null)
|
|
{
|
|
UpdateCalendarItems();
|
|
|
|
if (ShowCondensed == true)
|
|
UpdateCondensedColumnList();
|
|
|
|
CalendarView.DoViewLoadComplete(this);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ResetView
|
|
|
|
/// <summary>
|
|
/// Disconnects and resets the Model connection
|
|
/// </summary>
|
|
internal override void ResetView()
|
|
{
|
|
_ModelReloaded = true;
|
|
|
|
base.ResetView();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region UpdateCalendarItems
|
|
|
|
/// <summary>
|
|
/// Updates our CalendarItems list
|
|
/// </summary>
|
|
private void UpdateCalendarItems()
|
|
{
|
|
if (NeedRecalcLayout == true)
|
|
{
|
|
_CollateLines.Clear();
|
|
|
|
if (_CalendarItems.Count > 0)
|
|
{
|
|
List<CalendarItem> items = SortCalendarItems(_CalendarItems);
|
|
|
|
if (CalendarView.HasTimeLineGetRowCollateIdCallout)
|
|
{
|
|
SortedDictionary<int, List<CalendarItem>> ditems = CollateCalendarItems(items);
|
|
|
|
int dy = 0;
|
|
|
|
foreach (KeyValuePair<int, List<CalendarItem>> kvp in ditems)
|
|
{
|
|
ColumnList colList = new ColumnList();
|
|
|
|
for (int i = 0; i < kvp.Value.Count; i++)
|
|
colList.AddColumnSlot(kvp.Value[i], 0);
|
|
|
|
colList.CountColumns();
|
|
|
|
dy = CalcAppointmentBounds(colList, dy, true);
|
|
|
|
_CollateLines.Add(dy);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ColumnList colList = new ColumnList();
|
|
|
|
for (int i = 0; i < items.Count; i++)
|
|
colList.AddColumnSlot(items[i], 0);
|
|
|
|
colList.CountColumns();
|
|
|
|
CalcAppointmentBounds(colList, 0, false);
|
|
}
|
|
}
|
|
|
|
NeedRecalcLayout = false;
|
|
|
|
InvalidateRect();
|
|
}
|
|
}
|
|
|
|
#region CollateCalendarItems
|
|
|
|
private SortedDictionary<int, List<CalendarItem>>
|
|
CollateCalendarItems(List<CalendarItem> items)
|
|
{
|
|
SortedDictionary<int, List<CalendarItem>> citems =
|
|
new SortedDictionary<int, List<CalendarItem>>();
|
|
|
|
for (int i = 0; i < items.Count; i++)
|
|
{
|
|
if (items[i].CollateId < 0)
|
|
{
|
|
TimeLineGetRowCollateIdEventArgs e =
|
|
new TimeLineGetRowCollateIdEventArgs(items[i]);
|
|
|
|
CalendarView.DoTimeLineGetRowCollateId(e);
|
|
|
|
items[i].CollateId = e.CollateId;
|
|
}
|
|
|
|
int collateId = items[i].CollateId;
|
|
|
|
if (citems.ContainsKey(collateId) == false)
|
|
citems.Add(collateId, new List<CalendarItem>());
|
|
|
|
citems[collateId].Add(items[i]);
|
|
}
|
|
|
|
return (citems);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SortCalendarItems
|
|
|
|
/// <summary>
|
|
/// Sorts the provided CalendarItems
|
|
/// </summary>
|
|
/// <returns>Sorted CalendarItems</returns>
|
|
private List<CalendarItem> SortCalendarItems(IEnumerable<CalendarItem> clist)
|
|
{
|
|
List<CalendarItem> items = new List<CalendarItem>();
|
|
|
|
items.AddRange(clist);
|
|
|
|
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 < c2.EndTime)
|
|
return (1);
|
|
|
|
if (c1.EndTime > c2.EndTime)
|
|
return (-1);
|
|
|
|
int result = 0;
|
|
CalendarView.DoDetailSortEvent(this, c1, c2, ref result);
|
|
|
|
return (result);
|
|
}
|
|
);
|
|
}
|
|
|
|
return (items);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalcAppointmentBounds
|
|
|
|
/// <summary>
|
|
/// Calculates normal appointment bounds
|
|
/// </summary>
|
|
/// <param name="colList">Accumulated ColumnList</param>
|
|
/// <param name="dy"></param>
|
|
/// <param name="collate"></param>
|
|
private int CalcAppointmentBounds(ColumnList colList, int dy, bool collate)
|
|
{
|
|
if (colList.SList.Count > 0)
|
|
{
|
|
// If we are stretching the rows height, then calculate
|
|
// the default row height and the row spread, to evenly
|
|
// distribute the fill remainder
|
|
|
|
bool stretchRow = (collate == false &&
|
|
CalendarView.TimeLineStretchRowHeight == true);
|
|
|
|
int height = GetColRect(0).Height;
|
|
|
|
int rowSpread;
|
|
int rowHeight = GetColumnRowHeight(colList.SList.Count, stretchRow, height, out rowSpread) - 2;
|
|
|
|
for (int i = 0; i < colList.SList.Count; i++)
|
|
{
|
|
int maxRowHeight = 0;
|
|
|
|
for (int j = 0; j < colList.SList[i].Count; j++)
|
|
{
|
|
SlotItem sitem = colList.SList[i][j];
|
|
CalendarItem item = sitem.CItem;
|
|
|
|
Rectangle r = new Rectangle();
|
|
|
|
r.Y = ClientRect.Y + dy;
|
|
r.Height = rowHeight;
|
|
|
|
if (stretchRow == false)
|
|
r.Height = GetRowHeight(item, rowHeight);
|
|
|
|
TimeSpan ts1 = item.StartTime - StartDate;
|
|
TimeSpan ts2 = item.EndTime - item.StartTime;
|
|
|
|
int pos = (int) ((ts1.TotalMinutes * ColumnWidth) / BaseInterval);
|
|
int width = (int) ((ts2.TotalMinutes * ColumnWidth) / BaseInterval);
|
|
|
|
if (CalendarView.TimeLinePeriod == eTimeLinePeriod.Years)
|
|
{
|
|
int years = item.StartTime.Year - StartDate.Year;
|
|
|
|
pos = (years * ColumnWidth) / CalendarView.TimeLineInterval;
|
|
}
|
|
|
|
if (width < MinAppointmentWidth)
|
|
width = MinAppointmentWidth;
|
|
|
|
if (width < 4)
|
|
width = 4;
|
|
|
|
r.X = ClientRect.X + pos + _HScrollPos;
|
|
r.Width = width;
|
|
|
|
Rectangle p = ClientRect;
|
|
int hpad = CalendarView.TimeLineHorizontalPadding;
|
|
|
|
if (r.Left >= p.Left)
|
|
{
|
|
r.X += hpad;
|
|
r.Width -= hpad;
|
|
}
|
|
|
|
if (r.Right <= p.Right)
|
|
r.Width -= hpad;
|
|
|
|
if (i < rowSpread)
|
|
r.Height++;
|
|
|
|
if (item.StartTime != item.EndTime)
|
|
{
|
|
if (r.Height + 2 > maxRowHeight)
|
|
maxRowHeight = r.Height + 2;
|
|
}
|
|
|
|
if (stretchRow == true)
|
|
{
|
|
if (CalendarView.TimeLineStretchRowHeightMode == TimeLineStretchRowHeightMode.Full)
|
|
{
|
|
if (sitem.SList == null)
|
|
{
|
|
r.Height = height - dy - 2;
|
|
}
|
|
else
|
|
{
|
|
int n = GetColumnCount(sitem);
|
|
|
|
r.Height = (rowHeight + 1) * n - 1;
|
|
|
|
for (int k = 0; k < n; k++)
|
|
{
|
|
if (i + k >= rowSpread)
|
|
break;
|
|
|
|
r.Height++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
r.Height++;
|
|
|
|
item.Bounds = r;
|
|
|
|
// Set it's display state
|
|
|
|
item.Displayed = r.IntersectsWith(ClientRect);
|
|
}
|
|
|
|
dy += maxRowHeight;
|
|
}
|
|
}
|
|
|
|
return (dy);
|
|
}
|
|
|
|
#region GetColumnCount
|
|
|
|
private int GetColumnCount(SlotItem sitem)
|
|
{
|
|
int column = int.MaxValue;
|
|
|
|
for (int i = 0; i < sitem.SList.Count; i++)
|
|
{
|
|
if (sitem.SList[i].Column < column)
|
|
column = sitem.SList[i].Column;
|
|
}
|
|
|
|
return (column - sitem.Column);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetColumnRowHeight
|
|
|
|
private int GetColumnRowHeight(int count, bool stretchRow, int height, out int rowSpread)
|
|
{
|
|
rowSpread = 0;
|
|
|
|
int rowHeight = AppointmentHeight;
|
|
|
|
if (stretchRow == true)
|
|
{
|
|
rowHeight = height / count;
|
|
|
|
if (rowHeight < AppointmentHeight)
|
|
rowHeight = AppointmentHeight;
|
|
else
|
|
rowSpread = height - (count * rowHeight);
|
|
}
|
|
|
|
return (rowHeight);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetRowHeight
|
|
|
|
/// <summary>
|
|
/// Get the RowHeight for the given CalendarItem
|
|
/// </summary>
|
|
/// <param name="item">CalendarItem</param>
|
|
/// <param name="height">Calculated height</param>
|
|
/// <returns></returns>
|
|
private int GetRowHeight(CalendarItem item, int height)
|
|
{
|
|
TimeLineGetRowHeightEventArgs e =
|
|
new TimeLineGetRowHeightEventArgs(item, height);
|
|
|
|
CalendarView.DoTimeLineGetRowHeight(e);
|
|
|
|
return (e.Height);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region UpdateCondensedColumnList
|
|
|
|
/// <summary>
|
|
/// Updates the condensed view column list
|
|
/// </summary>
|
|
internal void UpdateCondensedColumnList()
|
|
{
|
|
if (_ModelReloaded == true && Connector != null)
|
|
{
|
|
_CondensedColList = new List<ColumnList>();
|
|
|
|
List<CalendarItem> items = new List<CalendarItem>();
|
|
|
|
// Get our appointment collection
|
|
|
|
GetCondensedAppts(items);
|
|
GetCondensedCustomItems(items);
|
|
|
|
// If we have any items, sort them and
|
|
// create a corresponding ColumnList
|
|
|
|
if (items.Count > 0)
|
|
{
|
|
items = SortCalendarItems(items);
|
|
|
|
if (CalendarView.HasTimeLineGetRowCollateIdCallout)
|
|
{
|
|
SortedDictionary<int, List<CalendarItem>> ditems = CollateCalendarItems(items);
|
|
|
|
foreach (KeyValuePair<int, List<CalendarItem>> kvp in ditems)
|
|
{
|
|
ColumnList colList = new ColumnList();
|
|
|
|
for (int i = 0; i < kvp.Value.Count; i++)
|
|
colList.AddColumnSlot(kvp.Value[i], 0);
|
|
|
|
colList.CountColumns();
|
|
|
|
_CondensedColList.Add(colList);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_CondensedColList.Add(new ColumnList());
|
|
|
|
for (int i = 0; i < items.Count; i++)
|
|
_CondensedColList[0].AddColumnSlot(items[i], 0);
|
|
|
|
_CondensedColList[0].CountColumns();
|
|
}
|
|
}
|
|
|
|
_ModelReloaded = false;
|
|
}
|
|
}
|
|
|
|
#region GetCondensedAppts
|
|
|
|
private void GetCondensedAppts(List<CalendarItem> items)
|
|
{
|
|
List<Appointment> appts =
|
|
((ModelTimeLineViewConnector)Connector).ListAppts;
|
|
|
|
if (appts != null && appts.Count > 0)
|
|
{
|
|
int n = Math.Min(appts.Count, 500);
|
|
n = Math.Max(appts.Count / n, 1);
|
|
|
|
for (int i = 0; i < appts.Count; i += n)
|
|
{
|
|
if (IsAppointmentVisible(appts[i]) == true)
|
|
{
|
|
CalendarItem ci = new CalendarItem();
|
|
|
|
ci.StartTime = appts[i].StartTime;
|
|
ci.EndTime = appts[i].EndTime;
|
|
ci.ModelItem = appts[i];
|
|
|
|
items.Add(ci);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if an appointment is visible
|
|
/// for the given DisplayOwner
|
|
/// </summary>
|
|
/// <param name="app"></param>
|
|
/// <returns></returns>
|
|
private bool IsAppointmentVisible(Appointment app)
|
|
{
|
|
if (string.IsNullOrEmpty(DisplayedOwnerKey))
|
|
return (true);
|
|
|
|
return (app.OwnerKey == DisplayedOwnerKey);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetCondensedCustomItems
|
|
|
|
private void GetCondensedCustomItems(List<CalendarItem> items)
|
|
{
|
|
for (int i = 0; i < CalendarView.CustomItems.Count; i++)
|
|
{
|
|
CustomCalendarItem item = CalendarView.CustomItems[i];
|
|
|
|
if (IsCustomItemVisible(item) == true &&
|
|
(item.StartTime < EndDate && item.EndTime > StartDate))
|
|
{
|
|
CalendarItem ci = new CalendarItem();
|
|
|
|
ci.StartTime = item.StartTime;
|
|
ci.EndTime = item.EndTime;
|
|
ci.ModelItem = item;
|
|
|
|
items.Add(ci);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool IsCustomItemVisible(CustomCalendarItem item)
|
|
{
|
|
if (string.IsNullOrEmpty(Connector.DisplayOwnerKey))
|
|
return (true);
|
|
|
|
return (item.OwnerKey.Equals(Connector.DisplayOwnerKey));
|
|
}
|
|
|
|
#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)
|
|
{
|
|
Graphics g = e.Graphics;
|
|
|
|
// Set our current color table
|
|
|
|
_ViewColor.SetColorTable();
|
|
|
|
// calculate our Column count and range
|
|
|
|
int colStart, colEnd;
|
|
|
|
if (GetColRange(e, out colStart, out colEnd) > 0)
|
|
{
|
|
Region rgnSave = g.Clip;
|
|
|
|
g.SetClip(ClientRect, CombineMode.Intersect);
|
|
|
|
// Draw the TimeLine
|
|
|
|
DrawTimeLine(g, colStart, colEnd);
|
|
DrawTimeIndicators(g, colStart, colEnd, eTimeIndicatorLevel.Bottom);
|
|
|
|
if (Connector != null && ShowCondensed == true)
|
|
DrawCondensedLine(g);
|
|
|
|
// If we have a model connection then
|
|
// draw our appointments
|
|
|
|
if (Connector != null && Connector.IsConnected)
|
|
{
|
|
Rectangle r = ClientRect;
|
|
r.X += 1;
|
|
|
|
if (ShowCondensed == true)
|
|
{
|
|
Rectangle r2 = GetCondensedRect();
|
|
|
|
if (r.Bottom > r2.Top)
|
|
r.Height -= (r.Bottom - r2.Top);
|
|
}
|
|
|
|
g.SetClip(r, CombineMode.Intersect);
|
|
|
|
DrawAppointments(e);
|
|
}
|
|
|
|
DrawTimeIndicators(g, colStart, colEnd, eTimeIndicatorLevel.Top);
|
|
|
|
g.Clip = rgnSave;
|
|
|
|
// Update our pos window
|
|
|
|
UpdatePosWin(ClientRect);
|
|
}
|
|
|
|
// Let the base painting take place
|
|
|
|
base.Paint(e);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DrawTimeLine
|
|
|
|
/// <summary>
|
|
/// Initiates the drawing of the TimeLine
|
|
/// </summary>
|
|
/// <param name="g">Graphics</param>
|
|
/// <param name="colStart">Starting column</param>
|
|
/// <param name="colEnd">Ending column</param>
|
|
private void DrawTimeLine(Graphics g, int colStart, int colEnd)
|
|
{
|
|
int n = colEnd - colStart;
|
|
|
|
eSlotDisplayState[] states = new eSlotDisplayState[n + 1];
|
|
|
|
for (int i = 0; i <= n; i++)
|
|
states[i] = GetSlotState(colStart + i);
|
|
|
|
DrawContent(g, colStart, colEnd, states);
|
|
DrawBorder(g, colStart, colEnd, states);
|
|
}
|
|
|
|
#region DrawContent
|
|
|
|
/// <summary>
|
|
/// Draws the content area of the TimeLine
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="colStart">Starting column</param>
|
|
/// <param name="colEnd">Ending column</param>
|
|
/// <param name="states"></param>
|
|
private void DrawContent(Graphics g,
|
|
int colStart, int colEnd, eSlotDisplayState[] states)
|
|
{
|
|
Rectangle r = GetColRect(colStart);
|
|
|
|
if (CalendarView.HasTimeLineSlotBackgroundCallout == true)
|
|
{
|
|
for (int i = colStart; i <= colEnd; i++)
|
|
{
|
|
int n = i - colStart;
|
|
|
|
DateTime startTime = StartDate.AddMinutes(i * BaseInterval);
|
|
DateTime endTime = startTime.AddMinutes(BaseInterval);
|
|
|
|
if (CalendarView.DoTimeLineViewPreRenderSlotBackground(
|
|
g, this, startTime, endTime, r, ref states[n]) == false)
|
|
{
|
|
g.FillRectangle(GetContentBrush(states[n]), r);
|
|
|
|
DrawCollateLines(g, r);
|
|
|
|
CalendarView.DoTimeLineViewPostRenderSlotBackground(
|
|
g, this, startTime, endTime, r, states[n]);
|
|
}
|
|
|
|
r.X += ColumnWidth;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Rectangle t = r;
|
|
|
|
for (int i = 0; i <= colEnd - colStart; i++)
|
|
{
|
|
g.FillRectangle(GetContentBrush(states[i]), t);
|
|
|
|
t.X += ColumnWidth;
|
|
}
|
|
|
|
r.Width += (t.Right - r.Right);
|
|
|
|
DrawCollateLines(g, r);
|
|
}
|
|
}
|
|
|
|
#region DrawCollateLines
|
|
|
|
private void DrawCollateLines(Graphics g, Rectangle r)
|
|
{
|
|
if (CalendarView.TimeLineShowCollateLines == true &&
|
|
_CollateLines.Count > 1)
|
|
{
|
|
using (Pen pen = new Pen(
|
|
_ViewColor.GetColor((int) eCalendarWeekDayPart.DayHalfHourBorder)))
|
|
{
|
|
for (int i = 0; i < _CollateLines.Count - 1; i++)
|
|
{
|
|
int y = _CollateLines[i];
|
|
|
|
g.DrawLine(pen, r.X, r.Y + y, r.Right, r.Y + y);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetSlotState
|
|
|
|
/// <summary>
|
|
/// GetSlotState
|
|
/// </summary>
|
|
/// <param name="col"></param>
|
|
/// <returns></returns>
|
|
private eSlotDisplayState GetSlotState(int col)
|
|
{
|
|
eSlotDisplayState state = eSlotDisplayState.None;
|
|
|
|
if (DisplayedOwnerKeyIndex == CalendarView.SelectedOwnerIndex)
|
|
{
|
|
if (col >= _SelectedColStart && col < _SelectedColEnd)
|
|
state |= eSlotDisplayState.Selected;
|
|
}
|
|
|
|
DateTime date = StartDate.AddMinutes(col * CalendarView.BaseInterval);
|
|
WorkTime workTime = new WorkTime(date.Hour, date.Minute);
|
|
|
|
if (IsWorkTime((int)date.DayOfWeek, workTime) == true)
|
|
state |= eSlotDisplayState.Work;
|
|
|
|
return (state);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetContentBrush
|
|
|
|
/// <summary>
|
|
/// Gets the background content brush
|
|
/// for the given time slice
|
|
/// </summary>
|
|
/// <returns>Background brush</returns>
|
|
private Brush GetContentBrush(eSlotDisplayState state)
|
|
{
|
|
if ((state & eSlotDisplayState.Selected) == eSlotDisplayState.Selected)
|
|
return (SelectedBrush);
|
|
|
|
if ((state & eSlotDisplayState.Work) == eSlotDisplayState.Work)
|
|
return (WorkBrush);
|
|
|
|
return (OffWorkBrush);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IsWorkTime
|
|
|
|
/// <summary>
|
|
/// Determines if the given time is tagged as a "Work time"
|
|
/// </summary>
|
|
/// <param name="day">Day of week</param>
|
|
/// <param name="time">WorkTime to test</param>
|
|
/// <returns>true if specified "time" is a Work time</returns>
|
|
private bool IsWorkTime(int day, WorkTime time)
|
|
{
|
|
ModelTimeLineViewConnector tlc =
|
|
(ModelTimeLineViewConnector)Connector;
|
|
|
|
WorkTime workStartTime = tlc.DayInfo[day].WorkStartTime;
|
|
WorkTime workEndTime = tlc.DayInfo[day].WorkEndTime;
|
|
|
|
return (time >= workStartTime && time < workEndTime);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region DrawBorder
|
|
|
|
/// <summary>
|
|
/// Draws the TimeLine border
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="colStart">Starting column</param>
|
|
/// <param name="colEnd">Ending column</param>
|
|
/// <param name="states"></param>
|
|
private void DrawBorder(Graphics g,
|
|
int colStart, int colEnd, eSlotDisplayState[] states)
|
|
{
|
|
Rectangle r = GetColRect(colStart);
|
|
|
|
// Draw the vertical borders
|
|
|
|
if (CalendarView.TimeLinePeriod == eTimeLinePeriod.Minutes)
|
|
DrawHalfHourBorders(g, colStart, colEnd, r, states);
|
|
else
|
|
DrawHourBorders(g, colStart, colEnd, r, states);
|
|
|
|
// Now draw the horizontal border
|
|
|
|
r.Width = (colEnd - colStart + 1) * ColumnWidth;
|
|
r.Height = ClientRect.Height;
|
|
|
|
Color color = _ViewColor.GetColor((int)eCalendarWeekDayPart.DayViewBorder);
|
|
|
|
if (CalendarView.DoTimeLineViewRenderViewBorder(g, this, colStart, colEnd, r, color) == false)
|
|
{
|
|
using (Pen pen1 = new Pen(color))
|
|
{
|
|
Point pt1 = new Point(r.X, r.Bottom - 1);
|
|
Point pt2 = new Point(r.Right - 1, pt1.Y);
|
|
|
|
g.DrawLine(pen1, pt1, pt2);
|
|
|
|
if (CalendarView.TimeLineShowPeriodHeader == false &&
|
|
CalendarView.TimeLineShowIntervalHeader == false)
|
|
{
|
|
pt1 = new Point(r.X, r.Top);
|
|
pt2 = new Point(r.Right - 1, pt1.Y);
|
|
|
|
g.DrawLine(pen1, pt1, pt2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region DrawHalfHourBorders
|
|
|
|
/// <summary>
|
|
/// DrawHalfHourBorders
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="colStart"></param>
|
|
/// <param name="colEnd"></param>
|
|
/// <param name="bounds"></param>
|
|
/// <param name="states"></param>
|
|
private void DrawHalfHourBorders(Graphics g,
|
|
int colStart, int colEnd, Rectangle bounds, eSlotDisplayState[] states)
|
|
{
|
|
// Draw the vertical hour and half hour borders
|
|
|
|
using (Pen pen1 = new Pen(
|
|
_ViewColor.GetColor((int)eCalendarWeekDayPart.DayHourBorder)))
|
|
{
|
|
using (Pen pen2 = new Pen(
|
|
_ViewColor.GetColor((int)eCalendarWeekDayPart.DayHalfHourBorder)))
|
|
{
|
|
Point pt1 = new Point(bounds.X, ClientRect.Y);
|
|
Point pt2 = new Point(bounds.X, ClientRect.Bottom - 1);
|
|
|
|
int n = 60 / CalendarView.TimeLineInterval;
|
|
int start = -_HScrollPos / ColumnWidth;
|
|
|
|
for (int i = colStart; i <= colEnd; i++)
|
|
{
|
|
bool isHour = (i == start || (i % n) == 0);
|
|
Pen pen = (isHour ? pen1 : pen2);
|
|
|
|
if (CalendarView.DoTimeLineViewRenderSlotBorder(
|
|
g, this, i, isHour, states[i - colStart], pt1, pt2, pen) == false)
|
|
{
|
|
g.DrawLine((isHour ? pen1 : pen2), pt1, pt2);
|
|
}
|
|
|
|
pt1.X = pt2.X = (pt1.X + ColumnWidth);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DrawHourBorders
|
|
|
|
/// <summary>
|
|
/// DrawHourBorders
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="colStart"></param>
|
|
/// <param name="colEnd"></param>
|
|
/// <param name="bounds"></param>
|
|
/// <param name="states"></param>
|
|
private void DrawHourBorders(Graphics g,
|
|
int colStart, int colEnd, Rectangle bounds, eSlotDisplayState[] states)
|
|
{
|
|
// Draw the vertical hour borders
|
|
|
|
using (Pen pen = new Pen(
|
|
_ViewColor.GetColor((int)eCalendarWeekDayPart.DayHourBorder)))
|
|
{
|
|
Point pt1 = new Point(bounds.X, ClientRect.Y);
|
|
Point pt2 = new Point(bounds.X, ClientRect.Bottom - 1);
|
|
|
|
for (int i = colStart; i <= colEnd; i++)
|
|
{
|
|
if (CalendarView.DoTimeLineViewRenderSlotBorder(
|
|
g, this, i, true, states[i - colStart], pt1, pt2, pen) == false)
|
|
{
|
|
g.DrawLine(pen, pt1, pt2);
|
|
}
|
|
|
|
pt1.X = pt2.X = (pt1.X + ColumnWidth);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region DrawTimeIndicators
|
|
|
|
#region DrawTimeIndicators
|
|
|
|
/// <summary>
|
|
/// Draws view TimeIndicators
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="colStart"></param>
|
|
/// <param name="colEnd"></param>
|
|
private void DrawTimeIndicators(Graphics g,
|
|
int colStart, int colEnd, eTimeIndicatorLevel level)
|
|
{
|
|
DateTime start = CalendarView.TimeLineAddInterval(StartDate, colStart);
|
|
DateTime end = CalendarView.TimeLineAddInterval(StartDate, colEnd);
|
|
|
|
Rectangle r = Rectangle.Union(GetColRect(colStart), GetColRect(colEnd));
|
|
|
|
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, start, r, ti);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DrawTimeIndicator
|
|
|
|
#region DrawTimeIndicator
|
|
|
|
/// <summary>
|
|
/// Draws individual view TimeIndicator
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="startDate"></param>
|
|
/// <param name="sRect"></param>
|
|
/// <param name="ti"></param>
|
|
private void DrawTimeIndicator(Graphics g,
|
|
DateTime startDate, Rectangle sRect, TimeIndicator ti)
|
|
{
|
|
Rectangle r = GetIndicatorRect(ti, startDate, sRect);
|
|
|
|
if (r.IntersectsWith(sRect) == true)
|
|
{
|
|
if (r.Width > 0)
|
|
{
|
|
ColorDef cdef = GetIndicatorColor(ti);
|
|
|
|
if (cdef != null)
|
|
{
|
|
float angle = cdef.Angle - 90;
|
|
|
|
using (Brush br = _ViewColor.BrushPart(cdef, r, angle))
|
|
{
|
|
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.Right, r.Top, r.Right, r.Bottom - 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetIndicatorColor
|
|
|
|
/// <summary>
|
|
/// Gets the Indicator Back color
|
|
/// </summary>
|
|
/// <param name="ti"></param>
|
|
/// <returns></returns>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Gets the Indicator Border color
|
|
/// </summary>
|
|
/// <param name="ti"></param>
|
|
/// <returns></returns>
|
|
private Color GetIndicatorBorder(TimeIndicator ti)
|
|
{
|
|
return (ti.BorderColor.IsEmpty == false ? ti.BorderColor :
|
|
_ViewColor.GetColor((int)eCalendarWeekDayPart.TimeIndicatorBorder));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetIndicatorRect
|
|
|
|
/// <summary>
|
|
/// Gets the TimeIndicator Rectangle
|
|
/// </summary>
|
|
/// <param name="ti"></param>
|
|
/// <param name="startDate"></param>
|
|
/// <param name="sRect"></param>
|
|
/// <returns></returns>
|
|
private Rectangle GetIndicatorRect(
|
|
TimeIndicator ti, DateTime startDate, Rectangle sRect)
|
|
{
|
|
double x = ColumnWidth / CalendarView.BaseInterval;
|
|
|
|
int offset = (int)((ti.IndicatorDisplayTime - startDate).TotalMinutes * x);
|
|
|
|
sRect.X += (offset - ti.Thickness - 1);
|
|
sRect.Width = ti.Thickness;
|
|
|
|
return (sRect);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the TimeIndicator Rectangle
|
|
/// </summary>
|
|
/// <param name="ti"></param>
|
|
/// <returns></returns>
|
|
internal override Rectangle GetIndicatorRect(TimeIndicator ti)
|
|
{
|
|
return (GetIndicatorRect(ti, ti.IndicatorDisplayTime));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the TimeIndicator Rectangle for the given date
|
|
/// </summary>
|
|
/// <param name="ti"></param>
|
|
/// <param name="time"></param>
|
|
/// <returns></returns>
|
|
internal override Rectangle GetIndicatorRect(TimeIndicator ti, DateTime time)
|
|
{
|
|
int colStart = -_HScrollPos / ColumnWidth;
|
|
DateTime startDate = CalendarView.TimeLineAddInterval(StartDate, colStart);
|
|
|
|
double x = ColumnWidth / CalendarView.BaseInterval;
|
|
int offset = (int)((time - startDate).TotalMinutes * x);
|
|
|
|
Rectangle r = GetColRect(colStart);
|
|
|
|
r.X += (offset - ti.Thickness - 1);
|
|
r.Width = ti.Thickness;
|
|
|
|
return (r);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region DrawCondensedLine
|
|
|
|
/// <summary>
|
|
/// Draws the condensed TimeLine
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
private void DrawCondensedLine(Graphics g)
|
|
{
|
|
TimeSpan ts0 = EndDate - StartDate;
|
|
float scale = (float)(ClientRect.Width / (ts0.TotalMinutes + BaseInterval));
|
|
|
|
Rectangle r = GetCondensedRect();
|
|
|
|
using (GraphicsPath path = GetCondensedViewPath(r, scale))
|
|
{
|
|
using (Brush br =
|
|
_ViewColor.BrushPart((int)eCalendarWeekDayPart.CondensedViewBackground, r))
|
|
{
|
|
g.FillRectangle(br, r);
|
|
}
|
|
|
|
g.FillPath(Brushes.White, path);
|
|
|
|
DrawCondensedContent(g, r, scale);
|
|
DrawCondensedAppointments(g, scale);
|
|
|
|
g.DrawPath(Pens.Gray, path);
|
|
}
|
|
}
|
|
|
|
#region DrawCondensedContent
|
|
|
|
/// <summary>
|
|
/// Draws the Condensed Content area
|
|
/// </summary>
|
|
/// <param name="g"></param>
|
|
/// <param name="vRect"></param>
|
|
/// <param name="scale"></param>
|
|
private void DrawCondensedContent(Graphics g, Rectangle vRect, float scale)
|
|
{
|
|
using (Pen pen = new Pen(
|
|
_ViewColor.GetColor((int)eCalendarWeekDayPart.DayHourBorder)))
|
|
{
|
|
int selCols = _SelectedColEnd - _SelectedColStart;
|
|
|
|
if (selCols > 0)
|
|
{
|
|
Rectangle r = vRect;
|
|
|
|
r.X += (int)(_SelectedColStart * BaseInterval * scale);
|
|
r.Width = (int)(selCols * BaseInterval * scale);
|
|
|
|
using (Brush br =
|
|
_ViewColor.BrushPart((int)eCalendarWeekDayPart.DayOffWorkHoursBackground, r))
|
|
{
|
|
g.FillRectangle(br, r);
|
|
}
|
|
|
|
g.DrawRectangle(pen, r);
|
|
}
|
|
|
|
g.DrawLine(pen, vRect.Left, vRect.Y, vRect.Right, vRect.Y);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetCondensedViewPath
|
|
|
|
/// <summary>
|
|
/// Gets the condensed view display path
|
|
/// </summary>
|
|
/// <param name="scale">Scale factor</param>
|
|
/// <param name="vRect">Condensed view rect</param>
|
|
/// <returns>Path</returns>
|
|
private GraphicsPath GetCondensedViewPath(Rectangle vRect, float scale)
|
|
{
|
|
int pos = (int)(FirstVisibleColumn * BaseInterval * scale);
|
|
int width = (int)((BaseInterval * ClientRect.Width) / ColumnWidth * scale);
|
|
|
|
Rectangle r = new
|
|
Rectangle(ClientRect.X + pos, vRect.Y, width, vRect.Height);
|
|
|
|
r.Inflate(0, -1);
|
|
|
|
return (DisplayHelp.GetRoundedRectanglePath(r, 2, 2, 2, 2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DrawCondensedAppointments
|
|
|
|
/// <summary>
|
|
/// Draws condensed appointments
|
|
/// </summary>
|
|
/// <param name="g">Graphics</param>
|
|
/// <param name="scale">Scale factor</param>
|
|
private void DrawCondensedAppointments(Graphics g, float scale)
|
|
{
|
|
// Display each item
|
|
|
|
SmoothingMode saveMode = g.SmoothingMode;
|
|
g.SmoothingMode = SmoothingMode.None;
|
|
|
|
int dy = 3;
|
|
|
|
foreach (ColumnList clist in _CondensedColList)
|
|
{
|
|
for (int i = 0; i < clist.SList.Count; i++)
|
|
{
|
|
for (int j = 0; j < clist.SList[i].Count; j++)
|
|
{
|
|
CalendarItem item = clist.SList[i][j].CItem;
|
|
|
|
TimeSpan ts1 = item.StartTime - StartDate;
|
|
TimeSpan ts2 = item.EndTime - item.StartTime;
|
|
|
|
int pos = (int)(ts1.TotalMinutes * scale);
|
|
int width = (int)(ts2.TotalMinutes * scale);
|
|
|
|
if (width < 4)
|
|
width = 4;
|
|
|
|
Point pt1 = new Point(ClientRect.X + pos,
|
|
ClientRect.Bottom - CondensedLineHeight + (i * 3) + dy);
|
|
|
|
Point pt2 = new Point(pt1.X + width, pt1.Y);
|
|
|
|
using (Pen pen = GetCondensedPen(item.ModelItem))
|
|
g.DrawLine(pen, pt1, pt2);
|
|
}
|
|
}
|
|
|
|
dy += (clist.SList.Count * 3);
|
|
}
|
|
|
|
g.SmoothingMode = saveMode;
|
|
}
|
|
|
|
#region GetCondensedPen
|
|
|
|
/// <summary>
|
|
/// Gets the appointments condensed pen
|
|
/// </summary>
|
|
/// <param name="o">Appointment object</param>
|
|
/// <returns></returns>
|
|
private Pen GetCondensedPen(object o)
|
|
{
|
|
string category = null;
|
|
|
|
if (o is Appointment)
|
|
category = (o as Appointment).CategoryColor;
|
|
|
|
else if (o is CustomCalendarItem)
|
|
category = (o as CustomCalendarItem).CategoryColor;
|
|
|
|
if (category != null)
|
|
{
|
|
// Check to see if we have any user defined
|
|
// AppointmentCategoryColors
|
|
|
|
if (CalendarView.HasCategoryColors == true)
|
|
{
|
|
AppointmentCategoryColor acc =
|
|
CalendarView.CategoryColors[category];
|
|
|
|
if (acc != null)
|
|
{
|
|
ColorDef cdef = acc.BackColor;
|
|
|
|
return (new Pen(cdef.Colors[cdef.Colors.Length - 1], 2));
|
|
}
|
|
}
|
|
|
|
if (category.Equals(Appointment.CategoryBlue))
|
|
return (GetCategoryPen(eAppointmentPart.BlueBackground));
|
|
|
|
if (category.Equals(Appointment.CategoryGreen))
|
|
return (GetCategoryPen(eAppointmentPart.GreenBackground));
|
|
|
|
if (category.Equals(Appointment.CategoryOrange))
|
|
return (GetCategoryPen(eAppointmentPart.OrangeBackground));
|
|
|
|
if (category.Equals(Appointment.CategoryPurple))
|
|
return (GetCategoryPen(eAppointmentPart.PurpleBackground));
|
|
|
|
if (category.Equals(Appointment.CategoryRed))
|
|
return (GetCategoryPen(eAppointmentPart.RedBackground));
|
|
|
|
if (category.Equals(Appointment.CategoryYellow))
|
|
return (GetCategoryPen(eAppointmentPart.YellowBackground));
|
|
}
|
|
|
|
return (GetCategoryPen(eAppointmentPart.DefaultBackground));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetCategoryPen
|
|
|
|
/// <summary>
|
|
/// GetCategoryPen
|
|
/// </summary>
|
|
/// <param name="part"></param>
|
|
/// <returns></returns>
|
|
private Pen GetCategoryPen(eAppointmentPart part)
|
|
{
|
|
ColorDef cdef = _appointmentColor.GetColorDef((int)part);
|
|
|
|
return (new Pen(cdef.Colors[cdef.Colors.Length - 1], 2));
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region DrawAppointments
|
|
|
|
/// <summary>
|
|
/// Draws TimeLine appointments
|
|
/// </summary>
|
|
/// <param name="e"></param>
|
|
private void DrawAppointments(ItemPaintArgs e)
|
|
{
|
|
List<CalendarItem> items = CalendarItems;
|
|
|
|
if (items.Count > 0)
|
|
{
|
|
// Loop through each CalendarItem in the week
|
|
|
|
int selItem = -1;
|
|
|
|
for (int i = 0; i < items.Count; i++)
|
|
{
|
|
// If we can display the item, then initiate the paint
|
|
|
|
if (items[i].Displayed == true)
|
|
{
|
|
if (e.ClipRectangle.IsEmpty ||
|
|
e.ClipRectangle.IntersectsWith(items[i].DisplayRectangle))
|
|
{
|
|
if (items[i].IsSelected == true)
|
|
selItem = i;
|
|
else
|
|
items[i].Paint(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selItem >= 0)
|
|
{
|
|
for (int i = 0; i < items.Count; i++)
|
|
{
|
|
// If we can display the item, then initiate the paint
|
|
|
|
if (items[i].Displayed == true)
|
|
{
|
|
if (e.ClipRectangle.IsEmpty ||
|
|
e.ClipRectangle.IntersectsWith(items[i].DisplayRectangle))
|
|
{
|
|
if (items[i].IsSelected == true)
|
|
items[i].Paint(e);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetColRange
|
|
|
|
/// <summary>
|
|
/// Calculates the range of columns needed to be drawn
|
|
/// to satisfy the specified paint request
|
|
/// </summary>
|
|
/// <param name="e">ItemPaintArgs</param>
|
|
/// <param name="colStart">[out] Column start index</param>
|
|
/// <param name="colEnd">[out] Column end index</param>
|
|
/// <returns>Column range count (end - start)</returns>
|
|
private int GetColRange(ItemPaintArgs e, out int colStart, out int colEnd)
|
|
{
|
|
// Calc our starting index
|
|
|
|
int start = -_HScrollPos / ColumnWidth;
|
|
int x = ClientRect.X + start * ColumnWidth + _HScrollPos;
|
|
|
|
while (start < TimeLineColumnCount)
|
|
{
|
|
if (x + ColumnWidth > e.ClipRectangle.X)
|
|
break;
|
|
|
|
x += ColumnWidth;
|
|
|
|
start++;
|
|
}
|
|
|
|
// Calc our ending index
|
|
|
|
int end = start;
|
|
|
|
while (end < TimeLineColumnCount)
|
|
{
|
|
if (x >= e.ClipRectangle.Right)
|
|
break;
|
|
|
|
x += ColumnWidth;
|
|
|
|
end++;
|
|
}
|
|
|
|
end++;
|
|
|
|
// Set the user supplied 'out' values, and
|
|
// return the range count to the caller
|
|
|
|
if (end - start == 0)
|
|
{
|
|
colStart = 0;
|
|
colEnd = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
colStart = start;
|
|
colEnd = end;
|
|
|
|
return (end - start);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetColRect
|
|
|
|
/// <summary>
|
|
/// Gets the display rectangle for the given column
|
|
/// </summary>
|
|
/// <param name="col">Column</param>
|
|
/// <returns>Display rectangle</returns>
|
|
private Rectangle GetColRect(int col)
|
|
{
|
|
Rectangle r = ClientRect;
|
|
|
|
r.X += ((col * ColumnWidth) + _HScrollPos);
|
|
r.Width = ColumnWidth;
|
|
|
|
r.Height -= 1;
|
|
|
|
if (ShowCondensed == true)
|
|
r.Height -= (CondensedLineHeight - 1);
|
|
|
|
return (r);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetCondensedRect
|
|
|
|
/// <summary>
|
|
/// Gets the CondensedView rectangle
|
|
/// </summary>
|
|
/// <returns>CondensedView rectangle</returns>
|
|
private Rectangle GetCondensedRect()
|
|
{
|
|
Rectangle r = ClientRect;
|
|
|
|
r.X += 1;
|
|
r.Width -= 1;
|
|
|
|
r.Y = r.Bottom - CondensedLineHeight;
|
|
r.Height = CondensedLineHeight - 1;
|
|
|
|
return (r);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDateCol
|
|
|
|
/// <summary>
|
|
/// Gets the absolute column value for the given date
|
|
/// </summary>
|
|
/// <param name="selDate">Selection date</param>
|
|
/// <returns>Absolute column</returns>
|
|
private int GetDateCol(DateTime? selDate)
|
|
{
|
|
if (selDate.HasValue)
|
|
{
|
|
TimeSpan ts = selDate.Value - StartDate;
|
|
|
|
return (int)(ts.TotalMinutes / CalendarView.BaseInterval);
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
#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
|
|
|
|
if (ClientRect.Contains(objArg.Location) == true)
|
|
{
|
|
if (PointInCondensedView(objArg.Location) == true)
|
|
{
|
|
// User is mousing in the CondensedView area
|
|
|
|
MyCursor = Cursors.Hand;
|
|
|
|
ProcessCvlButtonDown(objArg);
|
|
|
|
IsCondMoving = true;
|
|
}
|
|
else
|
|
{
|
|
int col;
|
|
|
|
if (GetPointItem(objArg.Location, out col, true) == true)
|
|
{
|
|
// User is mouseing in the Content area
|
|
|
|
MyCursor = GetContentCursor();
|
|
|
|
if (ProcessCilButtonDown(objArg) == false)
|
|
ProcessTvlButtonDown(col);
|
|
|
|
IsMouseDown = true;
|
|
}
|
|
|
|
IsCopyDrag = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#region CondensedView MouseDown processing
|
|
|
|
/// <summary>
|
|
/// Handles CondensedView Left Button Down events
|
|
/// </summary>
|
|
/// <param name="objArg"></param>
|
|
private void ProcessCvlButtonDown(MouseEventArgs objArg)
|
|
{
|
|
ProcessCvlPoint(objArg);
|
|
}
|
|
|
|
#region ProcessCvlPoint
|
|
|
|
/// <summary>
|
|
/// Processes CondensedView point selection
|
|
/// </summary>
|
|
/// <param name="objArg"></param>
|
|
private void ProcessCvlPoint(MouseEventArgs objArg)
|
|
{
|
|
TimeSpan ts0 = EndDate - StartDate;
|
|
|
|
float scale = (float)((ClientRect.Width + 2) / ts0.TotalMinutes);
|
|
int width = (int)((BaseInterval * ClientRect.Width) / ColumnWidth * scale);
|
|
|
|
double x = (objArg.Location.X - ClientRect.X - (width / 2)) / scale;
|
|
int col = (int)(x / BaseInterval);
|
|
|
|
// Make sure we stay within our bounds, and
|
|
// then set our new scroll value accordingly
|
|
|
|
HScrollBarAdv hScrollBar = CalendarView.TimeLineHScrollPanel.ScrollBar;
|
|
|
|
if (col < hScrollBar.Minimum)
|
|
col = hScrollBar.Minimum;
|
|
|
|
if (col > hScrollBar.Maximum - hScrollBar.LargeChange)
|
|
col = hScrollBar.Maximum - hScrollBar.LargeChange;
|
|
|
|
hScrollBar.Value = col;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region CalendarItem MouseDown processing
|
|
|
|
/// <summary>
|
|
/// CalendarItem left mouseDown processing
|
|
/// </summary>
|
|
/// <param name="objArg">MouseEventArgs</param>
|
|
private bool ProcessCilButtonDown(MouseEventArgs objArg)
|
|
{
|
|
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)
|
|
{
|
|
_LastBounds = item.Bounds;
|
|
_LastPointOffset = objArg.Location;
|
|
_LastMovePoint = objArg.Location;
|
|
|
|
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)
|
|
IsMoving = true;
|
|
|
|
// Update our initial PosWin display
|
|
|
|
UpdatePosWin(ClientRect);
|
|
}
|
|
}
|
|
|
|
return (true);
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region TimeLineView MouseDown processing
|
|
|
|
/// <summary>
|
|
/// Handles TimeLineView left MouseDown events
|
|
/// </summary>
|
|
/// <param name="col">Column index</param>
|
|
private void ProcessTvlButtonDown(int col)
|
|
{
|
|
DateTime startDate = CalendarView.TimeLineAddInterval(StartDate, col);
|
|
DateTime endDate = CalendarView.TimeLineAddInterval(startDate, 1);
|
|
|
|
ExtendSelection(ref startDate, ref endDate);
|
|
|
|
CalendarView.DateSelectionStart = startDate;
|
|
CalendarView.DateSelectionEnd = endDate;
|
|
|
|
SelectedItem = null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region MouseUp processing
|
|
|
|
/// <summary>
|
|
/// MouseUp event processing
|
|
/// </summary>
|
|
/// <param name="objArg">MouseEventArgs</param>
|
|
public override void InternalMouseUp(MouseEventArgs objArg)
|
|
{
|
|
base.InternalMouseUp(objArg);
|
|
|
|
// Cancel our scroll timer
|
|
|
|
CancelScrollTimer();
|
|
}
|
|
|
|
#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)
|
|
{
|
|
if (IsCondMoving == true || PointInCondensedView(objArg.Location) == true)
|
|
{
|
|
// The user in the CondensedView area
|
|
|
|
MyCursor = Cursors.Hand;
|
|
|
|
if (IsCondMoving == true)
|
|
ProcessCvlMouseMove(objArg);
|
|
}
|
|
else
|
|
{
|
|
// The user in the Content area
|
|
|
|
MyCursor = GetContentCursor();
|
|
|
|
if (objArg.Button == MouseButtons.Left)
|
|
ProcessContentMove(objArg);
|
|
}
|
|
}
|
|
}
|
|
|
|
#region ProcessCvlMouseMove
|
|
|
|
/// <summary>
|
|
/// Handles CondensedView mouse moves
|
|
/// </summary>
|
|
/// <param name="objArg"></param>
|
|
private void ProcessCvlMouseMove(MouseEventArgs objArg)
|
|
{
|
|
ProcessCvlPoint(objArg);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessContentMove
|
|
|
|
/// <summary>
|
|
/// Processes content mouse moves
|
|
/// </summary>
|
|
/// <param name="objArg">MouseEventArgs</param>
|
|
private void ProcessContentMove(MouseEventArgs objArg)
|
|
{
|
|
// Locate where the event took place
|
|
// and process it accordingly
|
|
|
|
int col;
|
|
|
|
if (GetPointItem(objArg.Location, out col, false) == true)
|
|
{
|
|
// The col is visible, so no need to
|
|
// enable scrolling - just process the event
|
|
|
|
EnableViewScrolling(false);
|
|
|
|
ProcessMouseMove(col, objArg);
|
|
}
|
|
else if (IsMouseDown == true)
|
|
{
|
|
// Check to see if the user is performing
|
|
// a "DragDrop" operation
|
|
|
|
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 cells (auto moving apps is intrusive looking)
|
|
|
|
if (DateSelectionAnchor != null)
|
|
ProcessMouseMove(col, objArg);
|
|
}
|
|
}
|
|
}
|
|
|
|
#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);
|
|
TimeLineView tlv = bv as TimeLineView;
|
|
|
|
if (tlv != null && tlv != this)
|
|
{
|
|
eViewArea area = bv.GetViewAreaFromPoint(pt);
|
|
|
|
if (area == eViewArea.InContent)
|
|
{
|
|
if (CalendarView.DoAppointmentViewChanging(SelectedItem, tlv.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 (tlv.DragAppointment(this, av));
|
|
|
|
CustomCalendarItem ci = SelectedItem as CustomCalendarItem;
|
|
|
|
if (ci != null)
|
|
return (tlv.DragCustomItem(this, ci));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (false);
|
|
}
|
|
|
|
#region DragCustomItem
|
|
|
|
private bool DragCustomItem(TimeLineView pv, CustomCalendarItem ci)
|
|
{
|
|
// Set the new owner and selected view, and
|
|
// recalc the new layout
|
|
|
|
ci.OwnerKey = OwnerKey;
|
|
|
|
NeedRecalcLayout = true;
|
|
RecalcSize();
|
|
|
|
CalendarView.SelectedOwnerIndex = this.DisplayedOwnerKeyIndex;
|
|
|
|
// Get the new view
|
|
|
|
CustomCalendarItem view = GetCustomCalendarItem(ci);
|
|
|
|
if (view != null)
|
|
SetNewDragItem(pv, view);
|
|
|
|
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">Item to drag</param>
|
|
private bool DragAppointment(TimeLineView pv, AppointmentView av)
|
|
{
|
|
// Set the new owner and selected view, and
|
|
// recalc the new layout
|
|
|
|
av.Appointment.OwnerKey = OwnerKey;
|
|
|
|
NeedRecalcLayout = true;
|
|
RecalcSize();
|
|
|
|
CalendarView.SelectedOwnerIndex = this.DisplayedOwnerKeyIndex;
|
|
|
|
// Get the new view
|
|
|
|
AppointmentView view = GetAppointmentView(av.Appointment);
|
|
|
|
if (view != null)
|
|
SetNewDragItem(pv, view);
|
|
|
|
return (true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region SetNewDragItem
|
|
|
|
private void SetNewDragItem(TimeLineView pv, CalendarItem view)
|
|
{
|
|
_LastBounds = pv._LastBounds;
|
|
_LastMovePoint = pv._LastMovePoint;
|
|
_LastPointOffset = pv._LastPointOffset;
|
|
|
|
int dx = _LastPointOffset.X - _LastBounds.X;
|
|
|
|
CalendarView.CalendarPanel.InternalMouseMove(new
|
|
MouseEventArgs(MouseButtons.None, 0, view.Bounds.X + dx, view.Bounds.Y, 0));
|
|
|
|
MouseEventArgs args = new
|
|
MouseEventArgs(MouseButtons.Left, 1, view.Bounds.X + dx, view.Bounds.Y, 0);
|
|
|
|
IsMoving = true;
|
|
|
|
InternalMouseMove(args);
|
|
CalendarView.CalendarPanel.InternalMouseDown(args);
|
|
|
|
SelectedItem = view;
|
|
|
|
IsCopyDrag = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetContentCursor
|
|
/// <summary>
|
|
/// Gets the cursor
|
|
/// </summary>
|
|
/// <returns>Cursor</returns>
|
|
private Cursor GetContentCursor()
|
|
{
|
|
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 ProcessMouseMove
|
|
|
|
/// <summary>
|
|
/// Processes user MouseMove
|
|
/// </summary>
|
|
/// <param name="col">DayColumn</param>
|
|
/// <param name="objArg"></param>
|
|
private void ProcessMouseMove(int col, MouseEventArgs objArg)
|
|
{
|
|
if (DateSelectionAnchor != null)
|
|
{
|
|
ProcessTvMouseMove(col);
|
|
}
|
|
else if (SelectedItem != null)
|
|
{
|
|
if (objArg.Location.Equals(_LastMovePoint) == false)
|
|
{
|
|
if (IsMoving == true)
|
|
ProcessItemMove(col, objArg);
|
|
|
|
else if (IsStartResizing == true)
|
|
ProcessItemLeftResize(col, objArg);
|
|
|
|
else if (IsEndResizing == true)
|
|
ProcessItemRightResize(col, objArg);
|
|
|
|
_LastMovePoint = objArg.Location;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessTvMouseMove
|
|
|
|
/// <summary>
|
|
/// Processes TimeLineView mouseMove events
|
|
/// </summary>
|
|
/// <param name="col">Column</param>
|
|
private void ProcessTvMouseMove(int col)
|
|
{
|
|
if (DateSelectionAnchor != null)
|
|
{
|
|
DateTime date = CalendarView.TimeLineAddInterval(StartDate, col);
|
|
|
|
// Let the user select forwards or backwards
|
|
|
|
if (date >= DateSelectionAnchor)
|
|
{
|
|
CalendarView.DateSelectionStart = DateSelectionAnchor.Value;
|
|
CalendarView.DateSelectionEnd = CalendarView.TimeLineAddInterval(date, 1);
|
|
}
|
|
else
|
|
{
|
|
CalendarView.DateSelectionStart = date;
|
|
CalendarView.DateSelectionEnd = CalendarView.TimeLineAddInterval(DateSelectionAnchor.Value, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalendarItem MouseMove processing
|
|
|
|
/// <summary>
|
|
/// Processes CalendarItem mouseMove events
|
|
/// </summary>
|
|
/// <param name="col">Column</param>
|
|
/// <param name="objArg">MouseEventArgs</param>
|
|
private void ProcessItemMove(int col, MouseEventArgs objArg)
|
|
{
|
|
// Calculate our new item date
|
|
|
|
DateTime newDate;
|
|
|
|
if (CalendarView.TimeLinePeriod == eTimeLinePeriod.Years)
|
|
{
|
|
newDate = StartDate.AddYears(
|
|
GetDeltaYears(col, true, objArg));
|
|
}
|
|
else
|
|
{
|
|
newDate = StartDate.AddMinutes(
|
|
GetDeltaMinutes(col, true, objArg));
|
|
}
|
|
|
|
if (newDate != SelectedItem.StartTime)
|
|
{
|
|
if (DragCopy() == false)
|
|
{
|
|
TimeSpan ts = SelectedItem.EndTime - SelectedItem.StartTime;
|
|
|
|
try
|
|
{
|
|
if (SelectedItem is CustomCalendarItem)
|
|
CalendarView.CustomItems.BeginUpdate();
|
|
else
|
|
CalendarModel.BeginUpdate();
|
|
|
|
// Make the move
|
|
|
|
if (CalendarView.DoAppointmentViewChanging(SelectedItem, null, newDate,
|
|
newDate + ts, eViewOperation.AppointmentMove, IsNewCopyDrag) == false)
|
|
{
|
|
SelectedItem.StartTime = newDate;
|
|
SelectedItem.EndTime = newDate + ts;
|
|
|
|
NeedRecalcLayout = true;
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (SelectedItem is CustomCalendarItem)
|
|
CalendarView.CustomItems.EndUpdate();
|
|
else
|
|
CalendarModel.EndUpdate();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region CalendarItem MouseResize processing
|
|
|
|
/// <summary>
|
|
/// Processes CalendarItem left resizing
|
|
/// </summary>
|
|
/// <param name="col">Column</param>
|
|
/// <param name="objArg"></param>
|
|
private void ProcessItemLeftResize(int col, MouseEventArgs objArg)
|
|
{
|
|
DateTime date = (CalendarView.TimeLinePeriod == eTimeLinePeriod.Years) ?
|
|
StartDate.AddYears(GetDeltaYears(col, true, objArg)) :
|
|
StartDate.AddMinutes(GetDeltaMinutes(col, true, objArg));
|
|
|
|
if (date < SelectedItem.EndTime && SelectedItem.StartTime != date)
|
|
ResizeItem(date, SelectedItem.EndTime);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes CalendarItem right resizing
|
|
/// </summary>
|
|
/// <param name="col">Column</param>
|
|
/// <param name="objArg"></param>
|
|
private void ProcessItemRightResize(int col, MouseEventArgs objArg)
|
|
{
|
|
DateTime date = (CalendarView.TimeLinePeriod == eTimeLinePeriod.Years) ?
|
|
StartDate.AddYears(GetDeltaYears(col, false, objArg)) :
|
|
StartDate.AddMinutes(GetDeltaMinutes(col, false, objArg));
|
|
|
|
if (date > SelectedItem.StartTime && SelectedItem.EndTime != date)
|
|
ResizeItem(SelectedItem.StartTime, date);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initiates the resize of the selected item
|
|
/// </summary>
|
|
/// <param name="startTime"></param>
|
|
/// <param name="endTime"></param>
|
|
private void ResizeItem(DateTime startTime, DateTime endTime)
|
|
{
|
|
// Let the user cancel the operation if desired
|
|
|
|
if (CalendarView.DoAppointmentViewChanging(SelectedItem, null, startTime,
|
|
endTime, eViewOperation.AppointmentResize, IsNewCopyDrag) == false)
|
|
{
|
|
SelectedItem.StartTime = startTime;
|
|
SelectedItem.EndTime = endTime;
|
|
|
|
NeedRecalcLayout = true;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDeltaMinutes
|
|
|
|
/// <summary>
|
|
/// Gets the change from the last offset (in minutes)
|
|
/// </summary>
|
|
/// <param name="col">Column</param>
|
|
/// <param name="left">Are we going left or right</param>
|
|
/// <param name="objArg">MouseEventArgs</param>
|
|
/// <returns>Change in mnutes</returns>
|
|
private double GetDeltaMinutes(int col, bool left, MouseEventArgs objArg)
|
|
{
|
|
// Calculate our delta minutes
|
|
|
|
Rectangle r = GetColRect(col);
|
|
|
|
double dm = (objArg.Location.X - _LastPointOffset.X);
|
|
|
|
dm += left ? _LastBounds.Left - r.Left
|
|
: _LastBounds.Right - r.Right;
|
|
|
|
dm = BaseInterval * dm / ColumnWidth;
|
|
|
|
// If the Alt key is not pressed, then round
|
|
// our value off to the nearest column
|
|
|
|
if ((Control.ModifierKeys & Keys.Alt) != Keys.Alt)
|
|
{
|
|
col += (int)(dm / BaseInterval);
|
|
dm = 0;
|
|
}
|
|
|
|
dm += (col * BaseInterval);
|
|
|
|
// Make sure we don't cross our day boundaries
|
|
|
|
if (left == true)
|
|
{
|
|
if (dm < 0)
|
|
dm = 0;
|
|
}
|
|
else
|
|
{
|
|
dm += BaseInterval;
|
|
}
|
|
|
|
return (dm);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region GetDeltaYears
|
|
|
|
/// <summary>
|
|
/// Gets the change from the last offset (in years)
|
|
/// </summary>
|
|
/// <param name="col">Column</param>
|
|
/// <param name="left">Are we going left or right</param>
|
|
/// <param name="objArg">MouseEventArgs</param>
|
|
/// <returns>Change in years</returns>
|
|
private int GetDeltaYears(int col, bool left, MouseEventArgs objArg)
|
|
{
|
|
// Calculate our delta minutes
|
|
|
|
Rectangle r = GetColRect(col);
|
|
|
|
int dm = (objArg.Location.X - _LastPointOffset.X);
|
|
|
|
dm += left ? _LastBounds.Left - r.Left
|
|
: _LastBounds.Right - r.Right;
|
|
|
|
dm = CalendarView.TimeLineInterval * dm / ColumnWidth;
|
|
|
|
// If the Alt key is not pressed, then round
|
|
// our value off to the nearest column
|
|
|
|
if ((Control.ModifierKeys & Keys.Alt) != Keys.Alt)
|
|
{
|
|
col += dm / CalendarView.TimeLineInterval;
|
|
dm = 0;
|
|
}
|
|
|
|
dm += (col * CalendarView.TimeLineInterval);
|
|
|
|
// Make sure we don't cross our day boundaries
|
|
|
|
if (left == true)
|
|
{
|
|
if (dm < 0)
|
|
dm = 0;
|
|
}
|
|
else
|
|
{
|
|
dm += CalendarView.TimeLineInterval;
|
|
}
|
|
|
|
return (dm);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region View Scrolling support
|
|
|
|
/// <summary>
|
|
/// Routine to enable or disable view scrolling
|
|
/// </summary>
|
|
/// <param name="enable">true to enable</param>
|
|
private void EnableViewScrolling(bool enable)
|
|
{
|
|
if (enable == true)
|
|
{
|
|
if (_ScrollViewTimer == null)
|
|
{
|
|
_ScrollViewTimer = new Timer();
|
|
|
|
_ScrollViewTimer.Interval = 10;
|
|
_ScrollViewTimer.Tick += ScrollViewTimerTick;
|
|
_ScrollViewTimer.Start();
|
|
}
|
|
|
|
_ScrollDwell = 0;
|
|
}
|
|
else
|
|
{
|
|
CancelScrollTimer();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancels the view scroll timer
|
|
/// </summary>
|
|
private void CancelScrollTimer()
|
|
{
|
|
// Dispose of our scroll timer
|
|
|
|
if (_ScrollViewTimer != null)
|
|
{
|
|
_ScrollViewTimer.Stop();
|
|
_ScrollViewTimer.Tick -= ScrollViewTimerTick;
|
|
|
|
_ScrollViewTimer = null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines the amount to scroll (which is
|
|
/// based loosely upon the delta magnitude)
|
|
/// </summary>
|
|
/// <param name="delta">Point delta</param>
|
|
/// <returns>Scroll amount</returns>
|
|
private int ScrollAmount(int delta)
|
|
{
|
|
_ScrollDwell++;
|
|
|
|
int dx = Math.Abs(delta);
|
|
int n = (dx < 16 ? 8 : dx < 32 ? 4 : 1);
|
|
|
|
if (_ScrollDwell % n == 0)
|
|
return (delta < 0 ? -1 : 1);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles view scroll timer ticks
|
|
/// </summary>
|
|
/// <param name="sender">object</param>
|
|
/// <param name="e">EventArgs</param>
|
|
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 = ClientRect;
|
|
|
|
int n = r.X + (ClientRect.Width / ColumnWidth) * ColumnWidth;
|
|
|
|
int dx = (pt.X < r.Left) ? ScrollAmount(pt.X - r.Left) :
|
|
(pt.X >= n) ? ScrollAmount(pt.X - n) : 0;
|
|
|
|
// Make sure we stay within our upper bounds
|
|
|
|
if (dx < 0)
|
|
{
|
|
if (CalendarView.TimeLineHScrollPanel.ScrollBar.Value + dx < 0)
|
|
dx = -CalendarView.TimeLineHScrollPanel.ScrollBar.Value;
|
|
}
|
|
else
|
|
{
|
|
int maxValue = CalendarView.TimeLineHScrollPanel.ScrollBar.Maximum -
|
|
CalendarView.TimeLineHScrollPanel.ScrollBar.LargeChange;
|
|
|
|
if (CalendarView.TimeLineHScrollPanel.ScrollBar.Value + dx > maxValue)
|
|
dx = maxValue - CalendarView.TimeLineHScrollPanel.ScrollBar.Value;
|
|
}
|
|
|
|
// Scroll if necessary
|
|
|
|
if (dx != 0)
|
|
{
|
|
CalendarView.TimeLineHScrollPanel.ScrollBar.Value += dx;
|
|
|
|
if (PosWin != null)
|
|
PosWin.Hide();
|
|
|
|
InternalMouseMove(new
|
|
MouseEventArgs(MouseButtons.Left, 0, pt.X, pt.Y, 0));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region GetPointItem
|
|
|
|
/// <summary>
|
|
/// Gets the item column at the given point
|
|
/// </summary>
|
|
/// <param name="pt">Point in question</param>
|
|
/// <param name="col">[out] Column</param>
|
|
/// <param name="partial">True if partial hits are ok</param>
|
|
/// <returns>True if valid item</returns>
|
|
private bool GetPointItem(Point pt, out int col, bool partial)
|
|
{
|
|
int start = -_HScrollPos / ColumnWidth;
|
|
int end = start + ClientRect.Width / ColumnWidth;
|
|
|
|
Rectangle r = GetColRect(start);
|
|
|
|
for (int i = start; i <= end; i++)
|
|
{
|
|
if (r.Contains(pt) == true)
|
|
{
|
|
col = i;
|
|
|
|
return (IsColVisible(r, partial));
|
|
}
|
|
|
|
r.X += ColumnWidth;
|
|
}
|
|
|
|
col = (pt.X < ClientRect.X) ? 0 : TimeLineColumnCount;
|
|
|
|
return (false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Determines if a given column is visible
|
|
/// </summary>
|
|
/// <param name="r">Display rectangle</param>
|
|
/// <param name="partial">True if partial visibility is ok</param>
|
|
/// <returns>True if visible</returns>
|
|
private bool IsColVisible(Rectangle r, bool partial)
|
|
{
|
|
if (partial == true)
|
|
{
|
|
if (r.Right < ClientRect.Left)
|
|
return (false);
|
|
|
|
if (r.Left > ClientRect.Right)
|
|
return (false);
|
|
}
|
|
else
|
|
{
|
|
if (r.Left < ClientRect.Left)
|
|
return (false);
|
|
|
|
if (r.Right > ClientRect.Right)
|
|
return (false);
|
|
}
|
|
|
|
return (true);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PointInCondensedView
|
|
|
|
/// <summary>
|
|
/// Determines if the given point in in
|
|
/// the CondensedView area
|
|
/// </summary>
|
|
/// <param name="pt"></param>
|
|
/// <returns></returns>
|
|
private bool PointInCondensedView(Point pt)
|
|
{
|
|
if (ShowCondensed == true)
|
|
return (GetCondensedRect().Contains(pt));
|
|
|
|
return (false);
|
|
}
|
|
|
|
#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:
|
|
objArg.Handled = true;
|
|
break;
|
|
|
|
case Keys.Down:
|
|
case Keys.Down | Keys.Shift:
|
|
case Keys.Down | Keys.Control:
|
|
case Keys.Down | Keys.Control | Keys.Shift:
|
|
objArg.Handled = true;
|
|
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;
|
|
}
|
|
}
|
|
|
|
#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())
|
|
{
|
|
// ReSharper disable PossibleInvalidOperationException
|
|
|
|
DateTime startDate = CalendarView.DateSelectionStart.Value;
|
|
DateTime endDate = CalendarView.DateSelectionEnd.Value;
|
|
|
|
if (startDate.Equals(DateSelectionAnchor.Value) == true)
|
|
startDate = CalendarView.TimeLineAddInterval(endDate, -1);
|
|
|
|
// ReSharper restore PossibleInvalidOperationException
|
|
|
|
startDate = CalendarView.TimeLineAddInterval(startDate, dx);
|
|
endDate = CalendarView.TimeLineAddInterval(startDate, 1);
|
|
|
|
DateTime viewStart = CalendarView.TimeLineViewScrollStartDate;
|
|
DateTime viewEnd = CalendarView.TimeLineViewScrollEndDate;
|
|
|
|
if (startDate < viewStart)
|
|
{
|
|
CalendarView.TimeLineViewScrollStartDate = startDate;
|
|
}
|
|
else if (endDate > viewEnd)
|
|
{
|
|
CalendarView.TimeLineViewScrollStartDate =
|
|
CalendarView.TimeLineAddInterval(CalendarView.TimeLineViewScrollStartDate, 1);
|
|
}
|
|
|
|
ExtendSelection(ref startDate, ref endDate);
|
|
|
|
CalendarView.DateSelectionStart = startDate;
|
|
CalendarView.DateSelectionEnd = endDate;
|
|
}
|
|
|
|
objArg.Handled = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ProcessHomeKey
|
|
|
|
/// <summary>
|
|
/// Handles Home key events
|
|
/// </summary>
|
|
/// <param name="objArg"></param>
|
|
protected virtual void ProcessHomeKey(KeyEventArgs objArg)
|
|
{
|
|
DateTime startDate = CalendarView.TimeLineViewScrollStartDate;
|
|
DateTime endDate = CalendarView.TimeLineAddInterval(startDate, 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)
|
|
{
|
|
DateTime endDate = CalendarView.TimeLineViewScrollEndDate;
|
|
DateTime startDate = CalendarView.TimeLineAddInterval(endDate, -1);
|
|
|
|
ExtendSelection(ref startDate, ref endDate);
|
|
|
|
CalendarView.DateSelectionStart = startDate;
|
|
CalendarView.DateSelectionEnd = endDate;
|
|
|
|
SelectedItem = null;
|
|
|
|
objArg.Handled = true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region IDisposable Members
|
|
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing == true && IsDisposed == false)
|
|
{
|
|
ResetView();
|
|
|
|
WorkBrush = null;
|
|
OffWorkBrush = null;
|
|
SelectedBrush = null;
|
|
|
|
HookEvents(false);
|
|
}
|
|
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
#endif |