614 lines
16 KiB
C#

#if FRAMEWORK20
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
namespace DevComponents.DotNetBar.Schedule
{
public class AllDayPanel : BaseItem
{
#region Private variables
private WeekDayView _WeekDayView; // Assoc WeekDayView
private List<CalendarItem> // CalendarItems list
_CalendarItems = new List<CalendarItem>();
private VScrollBarAdv _VScrollBar; // Vertical scroll bar
private int _VScrollPos; // Vertical scrollbar pos
private int _PanelHeight; // Panel height (current)
private int _MaximumPanelHeight; // Panel height (max)
#endregion
/// <summary>
/// Constructor
/// </summary>
/// <param name="weekDayView">WeekDayView</param>
public AllDayPanel(WeekDayView weekDayView)
{
// Save the provided weekDayView and
// tell the system we are a container
_WeekDayView = weekDayView;
SetIsContainer(true);
SubItems.AllowParentRemove = false;
}
#region Public properties
/// <summary>
/// Gets and sets the panel bounding rectangle
/// </summary>
public override Rectangle Bounds
{
get { return (base.Bounds); }
set
{
base.Bounds = value;
UpdateVScrollBar();
}
}
/// <summary>
/// Gets the DayPanel Height
/// </summary>
public int PanelHeight
{
get { return (_PanelHeight); }
}
/// <summary>
/// Gets the panel's CalendarItem list
/// </summary>
public List<CalendarItem> CalendarItems
{
get { return (_CalendarItems); }
}
/// <summary>
/// Gets WeekDayView
/// </summary>
public WeekDayView WeekDayView
{
get { return (_WeekDayView); }
}
#endregion
#region Private properties
/// <summary>
/// gets the Fixed AllDayPanel height
/// </summary>
private int FixedAllDayPanelHeight
{
get { return (_WeekDayView.CalendarView.FixedAllDayPanelHeight); }
}
/// <summary>
/// gets the Maximum AllDayPanel height
/// </summary>
private int MaximumAllDayPanelHeight
{
get { return (_WeekDayView.CalendarView.MaximumAllDayPanelHeight); }
}
/// <summary>
/// Gets the Appointment height
/// </summary>
private int AppointmentPadding
{
get { return (6); }
}
/// <summary>
/// Gets the width of a vertical scrollbar
/// </summary>
private int VsWidth
{
get { return (SystemInformation.VerticalScrollBarWidth); }
}
#endregion
#region RecalcSize
/// <summary>
/// Performs panel recalc support
/// </summary>
public override void RecalcSize()
{
// Reset our panel heights
_PanelHeight = 0;
_MaximumPanelHeight = 0;
if (_CalendarItems.Count > 0)
{
// Sort the items
List<CalendarItem> items = SortCalendarItems();
// Go through our CalendarItems on a per column basis
// accumulating extended appointment data
ulong[] acc = new ulong[DaysInWeek];
int maxAcc = -1;
for (int i = 0; i < items.Count; i++)
{
int freeAcc = CalcAppointmentBounds(items[i], acc);
if (freeAcc > maxAcc)
maxAcc = freeAcc;
}
// Determine our current panel height from our processed data
if (_WeekDayView.CalendarView.IsMultiCalendar == false)
{
_MaximumPanelHeight = (maxAcc + 1) * _WeekDayView.AppointmentHeight;
// Set out current and maximum panel heights
_MaximumPanelHeight += AppointmentPadding;
_PanelHeight = _MaximumPanelHeight;
if (_PanelHeight > MaximumAllDayPanelHeight)
_PanelHeight = MaximumAllDayPanelHeight;
}
}
// Take into account the FixedAllDayPanelHeight setting
if (_WeekDayView.CalendarView.IsMultiCalendar == true)
{
_PanelHeight = (FixedAllDayPanelHeight >= 0) ? FixedAllDayPanelHeight : 50;
_MaximumPanelHeight = _PanelHeight;
}
else if (FixedAllDayPanelHeight >= 0)
{
_PanelHeight = FixedAllDayPanelHeight;
}
HeightInternal = _PanelHeight;
base.RecalcSize();
}
#region SortCalendarItems
/// <summary>
/// Sorts the CalendarItems
/// </summary>
private List<CalendarItem> SortCalendarItems()
{
List<CalendarItem> items =
new List<CalendarItem>(_CalendarItems.Count);
items.AddRange(_CalendarItems);
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);
return (0);
}
);
return (items);
}
#endregion
#region CalcAppointmentBounds
const int DaysInWeek = 7;
/// <summary>
/// Calculates the display bounds for the AppointmentView
/// </summary>
/// <param name="item">CalendarItem</param>
/// <param name="acc">Row accumulator</param>
private int CalcAppointmentBounds(CalendarItem item, ulong[] acc)
{
// Determine the starting day index for
// the given appointment
int ns = GetDayIndex(item);
// Calculate the top and height for the item
Rectangle r = _WeekDayView.DayColumns[ns].Bounds;
r.Width = 0;
r.Y = _WeekDayView.ClientRect.Y + _WeekDayView.DayOfWeekHeaderHeight + _VScrollPos + 2;
r.Height = _WeekDayView.AppointmentHeight;
int maxAcc = -1;
// Determine the ending day index
DateTime st = _WeekDayView.DayColumns[ns].Date;
int ne = ns + (item.EndTime - st).Days;
if (item.EndTime.Hour > 0 || item.EndTime.Minute > 0 || item.EndTime.Second > 0)
ne++;
if (ne > DaysInWeek)
ne = DaysInWeek;
int freeAcc = GetFreeAcc(ns, ne, acc);
if (freeAcc >= 0)
{
ulong u = (1ul << freeAcc);
for (int i = ns; i < ne; i++)
{
if (i < _WeekDayView.NumberOfColumns)
r.Width += _WeekDayView.DayColumns[i].Bounds.Width;
acc[i] |= u;
}
r.Y += (freeAcc * _WeekDayView.AppointmentHeight);
if (freeAcc > maxAcc)
maxAcc = freeAcc;
}
else
{
r.Y = _WeekDayView.DayColumns[0].Bounds.Bottom;
}
DateTime start = _WeekDayView.DayColumns[0].Date;
DateTime end = _WeekDayView.DayColumns[_WeekDayView.DayColumns.Length - 1].Date;
// Check to see if we can only display
// a partial representation for the view
if (item.EndTime >= start && item.StartTime < end)
{
int hpad = 4;
if (item.StartTime >= start)
{
r.X += hpad;
r.Width -= hpad;
}
if (item.EndTime <= end)
r.Width -= hpad;
}
// Now that we have calculated the items height and
// width, invoke a Recalc on the item
item.WidthInternal = r.Width;
item.HeightInternal = r.Height - 1;
item.RecalcSize();
// Set our bounds for the item
r.Width = item.WidthInternal;
r.Height = item.HeightInternal;
item.Bounds = r;
// Set it's display state
item.Displayed = true;
return (maxAcc);
}
#region GetFreeAcc
private int GetFreeAcc(int ns, int ne, ulong[] acc)
{
for (int i = 0; i < sizeof(ulong) * 8; i++)
{
if (CheckFreeAcc(ns, ne, acc, i) == true)
return (i);
}
return (-1);
}
#region CheckFreeAcc
private bool CheckFreeAcc(int ns, int ne, ulong[] acc, int n)
{
for (int i = ns; i < ne; i++)
{
ulong u = acc[i];
if ((u & (1ul << n)) != 0)
return (false);
}
return (true);
}
#endregion
#endregion
#region GetDayIndex
/// <summary>
/// Gets the starting day index for the given appointment
/// </summary>
/// <returns>Day of week index (0-6)</returns>
private int GetDayIndex(CalendarItem item)
{
DateTime date = _WeekDayView.DayColumns[0].Date;
for (int i = 0; i < _WeekDayView.DayColumns.Length; i++)
{
date = date.AddDays(1);
if (date > item.StartTime)
return (i);
}
return (0);
}
#endregion
#endregion
#endregion
#region Scrollbar routines
#region UpdateVScrollBar
/// <summary>
/// Updates our vertical scrollbar
/// </summary>
private void UpdateVScrollBar()
{
if (_PanelHeight > 0 && _PanelHeight < _MaximumPanelHeight)
{
// If we don't have one already, allocate it
if (_VScrollBar == null)
{
_VScrollBar = new VScrollBarAdv();
_VScrollBar.Width = VsWidth;
Control c = (Control)this.GetContainerControl(true);
if (c != null)
c.Controls.Add(_VScrollBar);
_VScrollBar.ValueChanged += _VExtScrollBar_ValueChanged;
}
// Initialize the scrollbar
_VScrollBar.Location = new Point(Bounds.Right + 1, Bounds.Y);
_VScrollBar.Height = _PanelHeight;
_VScrollBar.SmallChange = _PanelHeight / 2;
_VScrollBar.LargeChange = _WeekDayView.AppointmentHeight * 2;
_VScrollBar.Maximum = _MaximumPanelHeight -
_VScrollBar.Height + _VScrollBar.LargeChange;
if (_VScrollBar.Visible == false)
{
_VScrollPos = 0;
_VScrollBar.Value = 0;
_VScrollBar.Show();
_VScrollBar.BringToFront();
}
else
{
if (_VScrollBar.Value > _VScrollBar.Maximum - _VScrollBar.LargeChange)
_VScrollBar.Value = _VScrollBar.Maximum - _VScrollBar.LargeChange;
}
_VScrollBar.Refresh();
}
else if (_VScrollBar != null)
{
_VScrollPos = 0;
_VScrollBar.ValueChanged -= _VExtScrollBar_ValueChanged;
_VScrollBar.Dispose();
_VScrollBar = null;
}
}
#endregion
#region _VExtScrollBar_ValueChanged
/// <summary>
/// Processes Extended appointments scrollBar changes
/// </summary>
/// <param name="sender">object</param>
/// <param name="e">EventArgs</param>
void _VExtScrollBar_ValueChanged(object sender, EventArgs e)
{
int vdelta = -_VScrollBar.Value - _VScrollPos;
if (vdelta != 0)
{
_VScrollPos = -_VScrollBar.Value;
// Now that we have calculated the items height and
// width, invoke a Recalc on the item
for (int i = 0; i < _CalendarItems.Count; i++)
{
CalendarItem item = _CalendarItems[i];
Rectangle r = item.Bounds;
r.Y += vdelta;
item.Bounds = r;
}
Refresh();
}
}
#endregion
#endregion
#region Reset / update view
/// <summary>
/// Resets the AllDayPanel view
/// </summary>
public void ResetView()
{
_VScrollPos = 0;
if (_VScrollBar != null)
{
_VScrollBar.ValueChanged -= _VExtScrollBar_ValueChanged;
_VScrollBar.Dispose();
_VScrollBar = null;
}
}
/// <summary>
/// Updates the AllDayPanel view
/// </summary>
public void UpdateView()
{
if (_WeekDayView.IsViewSelected == true)
{
if (_VScrollBar != null)
_VScrollBar.Show();
}
else
{
if (_VScrollBar != null)
_VScrollBar.Hide();
}
}
#endregion
#region Paint processing
/// <summary>
/// Draws extended appointments
/// </summary>
/// <param name="e">ItemPaintArgs</param>
public override void Paint(ItemPaintArgs e)
{
Graphics g = e.Graphics;
if (e.ClipRectangle.IntersectsWith(Bounds))
{
Region regSave = g.Clip;
g.SetClip(Bounds, CombineMode.Intersect);
using (Brush br =
_WeekDayView.WeekDayColor.BrushPart(
(int) eCalendarWeekDayPart.DayAllDayEventBackground, Bounds))
{
g.FillRectangle(br, Bounds);
}
using (Pen pen = new Pen(
_WeekDayView.WeekDayColor.GetColor((int) eCalendarWeekDayPart.DayViewBorder)))
{
g.DrawLine(pen, Bounds.X, Bounds.Y, Bounds.X, Bounds.Bottom);
g.DrawLine(pen, Bounds.Right - 1, Bounds.Y, Bounds.Right - 1, Bounds.Bottom);
}
// Loop through each day in each week, displaying
// the associated day content
int selItem = -1;
for (int i = 0; i < _CalendarItems.Count; i++)
{
// Initiate the paint
if (_CalendarItems[i].Displayed == true)
{
if (_CalendarItems[i].IsSelected == true)
selItem = i;
else
_CalendarItems[i].Paint(e);
}
}
if (selItem >= 0)
_CalendarItems[selItem].Paint(e);
// Restore the original clip region
g.Clip = regSave;
}
}
#endregion
#region Copy implementation
/// <summary>
/// Returns copy of the item.
/// </summary>
public override BaseItem Copy()
{
AllDayPanel objCopy = new AllDayPanel(WeekDayView);
CopyToItem(objCopy);
return (objCopy);
}
/// <summary>
/// Copies the AllDayPanel specific properties to new instance of the item.
/// </summary>
/// <param name="copy">New AllDayPanel instance</param>
protected override void CopyToItem(BaseItem copy)
{
AllDayPanel objCopy = copy as AllDayPanel;
base.CopyToItem(objCopy);
}
#endregion
}
}
#endif