/// <summary> /// Handles the appoinment overlaps badly. /// </summary> /// <param name="day">The day.</param> private static void handleOverlaps(DayWithHourRegion day) { //TODO: work out overlaps through a better process if (day.Appointments.Count > 0) { for (int j = 0; j < day.Appointments.Count; j++) { AppointmentWithHourRegion app = day.Appointments[j] as AppointmentWithHourRegion; //if we have overlaps, things get nasty if (app.HasOverlaps) { foreach (AppointmentWithHourRegion overlapApp in app.OverlappingAppointments) { //if another appointment overlaps if (!overlapApp.Bounds.IsEmpty && overlapApp.Bounds.IntersectsWith(new Rectangle(app.Bounds.X, app.Bounds.Y, app.Bounds.Width, app.Bounds.Height)) ) { //if the app width is bigger, trim it if (app.Bounds.Width >= overlapApp.Bounds.Width) { //if current app x starts after the other app x if (app.Bounds.X >= overlapApp.Bounds.X) { app.Bounds = new Rectangle( app.Bounds.X + app.Bounds.Width / 4, app.Bounds.Y, app.Bounds.Width - app.Bounds.Width / 4, app.Bounds.Height); } else { app.Bounds = new Rectangle( app.Bounds.X, app.Bounds.Y, app.Bounds.Width - app.Bounds.Width / 4, app.Bounds.Height); } } } if (app.Bounds.X + app.Bounds.Width > day.Bounds.X + day.Bounds.Width) { Rectangle rect = app.Bounds; rect.Width = day.Bounds.X + day.Bounds.Width - app.Bounds.X; app.Bounds = rect; } } } } } }
/// <summary> /// Calculate the appointment bounds. This works out the size and /// shape that the appointments will take up on the screen, /// and handles any other calculations such as overlaps. This method /// is called from OnPaint only when the property BoundsValidAppointment /// is set to false (this property is set to false in cases such as /// when the control has been resized or the appointment list has /// changed). /// </summary> protected override void CalculateAppointmentBounds(Graphics graphics) { //int appSeparator = 3; //recalculate the appointments foreach (DayWithHourRegion day in this.DayRegions) { //clear day and hour appointment regions day.Appointments.Clear(); foreach (HourRegion hour in day.Hours) { hour.Appointments.Clear(); } //TODO: cater for overlapping multiple timeslots foreach (Appointment app in Appointments) { if (app.DateStart.Year == day.Date.Year && app.DateStart.DayOfYear == day.Date.DayOfYear) { AppointmentWithHourRegion appRegion = new AppointmentWithHourRegion(app); day.Appointments.Add(appRegion); foreach (HourRegion hour in day.Hours) { if (app.DateStart.Hour == hour.Hour) // && app.DateStart.Hour <= hour.Hour) { hour.Appointments.Add(appRegion); } } } } foreach (AppointmentWithHourRegion appt1 in day.Appointments) { foreach (AppointmentWithHourRegion appt2 in day.Appointments) { if (appt1 != appt2 && appt1.Appointment.DateEnd != appt2.Appointment.DateStart && appt1.Appointment.DateStart != appt2.Appointment.DateEnd && ( appt2.Appointment.DateStart == appt1.Appointment.DateStart || appt2.Appointment.DateEnd == appt1.Appointment.DateEnd || (appt2.Appointment.DateStart < appt1.Appointment.DateEnd && appt2.Appointment.DateStart > appt1.Appointment.DateStart) || (appt2.Appointment.DateEnd < appt1.Appointment.DateEnd && appt2.Appointment.DateEnd > appt1.Appointment.DateStart) || (appt1.Appointment.DateEnd < appt2.Appointment.DateEnd && appt1.Appointment.DateEnd > appt2.Appointment.DateStart) ) ) { appt1.HasOverlaps = true; appt2.HasOverlaps = true; if (!appt1.OverlappingAppointments.Contains(appt2)) { appt1.OverlappingAppointments.Add(appt2); } if (!appt2.OverlappingAppointments.Contains(appt1)) { appt2.OverlappingAppointments.Add(appt1); } } } } //roughly work out appt bounds and starting slot for (int i = 0; i < day.Hours.Count; i++) { HourRegion hour = day.Hours[i]; int apptY = hour.Bounds.Y; if (hour.Appointments.Count > 0) { int hourX = hour.Bounds.X; int apptX = hourX; for (int j = 0; j < hour.Appointments.Count; j++) { AppointmentWithHourRegion app = hour.Appointments[j]; //work out starting slot int startMinute = app.Appointment.DateStart.Minute; if (startMinute >= 0 && startMinute < 15) { app.StartingSlot = 0; } else if (startMinute >= 15 && startMinute < 30) { app.StartingSlot = 1; } else if (startMinute >= 30 && startMinute < 45) { app.StartingSlot = 2; } else if (startMinute >= 45 && startMinute < 60) { app.StartingSlot = 3; } //work out duration and therefore height TimeSpan span = app.Appointment.DateEnd.Subtract(app.Appointment.DateStart); int tempApptHeight = ((span.Hours * 60 + span.Minutes) / 15) * hour.Bounds00.Height; int tempApptY = apptY + (app.StartingSlot * hour.Bounds00.Height); int apptWidth = hour.Bounds.Width; //if we have overlaps, things get nasty if (app.HasOverlaps) { int hourAppWidth = apptWidth / hour.Appointments.Count; apptWidth = hourAppWidth; } app.Bounds = new Rectangle(apptX, tempApptY, apptWidth, tempApptHeight); //set the bounds apptX += apptWidth; } } } //go over again a few times to resolve overlaps for (int i = 0; i < 5; i++) { handleOverlaps(day); } } BoundsValidAppointment = true; }