tvplanit: More refactoring of event painting in TVpDayView

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4839 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2016-06-26 11:37:20 +00:00
parent 48bdc3b5c6
commit 4af15415ad
2 changed files with 316 additions and 294 deletions

View File

@ -685,7 +685,7 @@ begin
FHeadAttr := TVpCHAttributes.Create(self); FHeadAttr := TVpCHAttributes.Create(self);
FRowHeadAttr := TVpRHAttributes.Create(self); FRowHeadAttr := TVpRHAttributes.Create(self);
FAllDayEventAttr := TVpAllDayEventAttributes.Create(self); FAllDayEventAttr := TVpAllDayEventAttributes.Create(self);
dvClickTimer := TTimer.Create (self); dvClickTimer := TTimer.Create(self);
FIconAttributes := TVpDayViewIconAttributes.Create(Self); FIconAttributes := TVpDayViewIconAttributes.Create(Self);
{ create Nav buttons } { create Nav buttons }
@ -1613,7 +1613,6 @@ end;
procedure TVpDayView.MouseDown(Button: TMouseButton; Shift: TShiftState; procedure TVpDayView.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); X, Y: Integer);
var var
ClientOrigin: TPoint;
i: Integer; i: Integer;
begin begin
inherited MouseDown(Button, Shift, X, Y); inherited MouseDown(Button, Shift, X, Y);
@ -1632,14 +1631,14 @@ begin
dvSetActiveRowByCoord(Point(x, y), True); dvSetActiveRowByCoord(Point(x, y), True);
if not ReadOnly then if not ReadOnly then
EditEventAtCoord(Point(x, y)); EditEventAtCoord(Point(x, y));
end else if y > dvColHeadHeight then end else
dvSetActiveRowByCoord (Point (x, y), True); if y > dvColHeadHeight then
dvSetActiveRowByCoord(Point (x, y), True);
if Assigned(OnClick) then if Assigned(OnClick) then
OnClick(self); OnClick(self);
end end
else else begin
begin
if not focused then if not focused then
SetFocus; SetFocus;
@ -1650,13 +1649,12 @@ begin
dvSetActiveRowByCoord(Point(x, y), True); dvSetActiveRowByCoord(Point(x, y), True);
end; end;
EditEventAtCoord (Point (x, y)); EditEventAtCoord(Point (x, y));
dvClickTimer.Enabled := false; dvClickTimer.Enabled := false;
if not Assigned (PopupMenu) then begin if not Assigned(PopupMenu) then
ClientOrigin := GetClientOrigin; begin
if not Assigned(FActiveEvent) then
if not Assigned (FActiveEvent) then
for i := 0 to FDefaultPopup.Items.Count - 1 do begin for i := 0 to FDefaultPopup.Items.Count - 1 do begin
if (FDefaultPopup.Items[i].Tag = 1) or (ReadOnly) then if (FDefaultPopup.Items[i].Tag = 1) or (ReadOnly) then
FDefaultPopup.Items[i].Enabled := False; FDefaultPopup.Items[i].Enabled := False;
@ -1858,16 +1856,12 @@ begin
if ReadOnly then if ReadOnly then
Exit; Exit;
for I := 0 to pred(Length(dvEventArray)) do begin for I := 0 to pred(Length(dvEventArray)) do begin
if dvEventArray[I].Event = nil then begin FActiveEvent := nil; // wp: shouldn't these be set also if ReadOnly is true?
dvActiveEventRec := Rect(0, 0, 0, 0);
dvActiveIconRec := Rect(0, 0, 0, 0);
if dvEventArray[I].Event = nil then
{ we've hit the end of visible events without finding a match } { we've hit the end of visible events without finding a match }
FActiveEvent := nil;
dvActiveEventRec.Top := 0;
dvActiveEventRec.Bottom := 0;
dvActiveEventRec.Right := 0;
dvActiveEventRec.Left := 0;
dvActiveIconRec := Rect (0, 0, 0, 0);
Exit; Exit;
end;
if (Point.X > dvEventArray[I].Rec.Left) and if (Point.X > dvEventArray[I].Rec.Left) and
(Point.X < dvEventArray[I].Rec.Right) and (Point.X < dvEventArray[I].Rec.Right) and
(Point.Y > dvEventArray[I].Rec.Top) and (Point.Y > dvEventArray[I].Rec.Top) and
@ -1879,13 +1873,6 @@ begin
dvClickTimer.Enabled := true; dvClickTimer.Enabled := true;
result := true; result := true;
Break; Break;
end else begin
FActiveEvent := nil;
dvActiveEventRec.Top := 0;
dvActiveEventRec.Bottom := 0;
dvActiveEventRec.Right := 0;
dvActiveEventRec.Left := 0;
dvActiveIconRec := Rect (0, 0, 0, 0);
end; end;
end; end;
end; end;
@ -2284,8 +2271,7 @@ begin
dvPainting := false; dvPainting := false;
end; end;
end; end;
(*
(*
var var
TextWidth: Integer; TextWidth: Integer;
ColHeadRect: TRect; ColHeadRect: TRect;
@ -4013,7 +3999,7 @@ begin
dvPainting := false; dvPainting := false;
end; end;
*) *)
{=====} {=====}
{.$IFNDEF LCL} {.$IFNDEF LCL}

View File

@ -75,6 +75,8 @@ type
OldFont: TFont; OldFont: TFont;
protected protected
function BuildEventString(AEvent: TVpEvent;
const AEventRect, AIconRect: TRect): String;
function CountOverlappingEvents(Event: TVpEvent; function CountOverlappingEvents(Event: TVpEvent;
const EArray: TVpDvEventArray): Integer; const EArray: TVpDvEventArray): Integer;
procedure CreateBitmaps; procedure CreateBitmaps;
@ -88,12 +90,19 @@ type
procedure DrawEvent(AEvent: TVpEvent; AEventRec: TVpDvEventRec; procedure DrawEvent(AEvent: TVpEvent; AEventRec: TVpDvEventRec;
ARenderDate: TDateTime; Col: Integer); ARenderDate: TDateTime; Col: Integer);
procedure DrawEvents(ARenderDate: TDateTime; Col: Integer); procedure DrawEvents(ARenderDate: TDateTime; Col: Integer);
procedure DrawEventString(const AText: String; const AEventRect, AIconRect: TRect;
ALevel: Integer; AEventIsEditing: Boolean);
procedure DrawIcons(AIconRect: TRect); procedure DrawIcons(AIconRect: TRect);
procedure DrawRowHeader(R: TRect); procedure DrawRowHeader(R: TRect);
procedure FreeBitmaps; procedure FreeBitmaps;
procedure GetIcons(Event: TVpEvent); procedure GetIcons(Event: TVpEvent);
procedure InitColors; procedure InitColors;
procedure InitializeEventRectangles; procedure InitializeEventRectangles;
procedure PopulateEventArray(ARenderDate: TDateTime);
procedure PrepareEventRect(AWidthDivisor, ALevel: Integer;
var AEventRect: TRect; var AEventWidth: Integer);
procedure PrepareEventTimes(AEvent: TVpEvent; ARenderDate: TDateTime;
out AStartTime, AEndTime: TDateTime);
procedure ScaleIcons(EventRect: TRect); procedure ScaleIcons(EventRect: TRect);
procedure SetMeasurements; override; procedure SetMeasurements; override;
@ -120,6 +129,31 @@ begin
FDayView := ADayView; FDayView := ADayView;
end; end;
function TVpDayViewPainter.BuildEventString(AEvent: TVpEvent;
const AEventRect, AIconRect: TRect): String;
var
maxW: Integer;
timeFmt: String;
begin
if FDayView.ShowEventTimes then begin
timeFmt := IfThen(FDayView.TimeFormat = tf24Hour, 'h:nn', 'h:nnam/pm');
Result := Format('%s - %s: %s', [
FormatDateTime(timeFmt, AEvent.StartTime),
FormatDateTime(timeFmt, AEvent.EndTime),
AEvent.Description
]);
end else
Result := AEvent.Description;
if FDayView.WrapStyle = wsNone then begin
{ if the string is longer than the availble space then chop off the end
and place those little '...'s at the end }
maxW := AEventRect.Right - AIconRect.Right - Round(FDayView.GutterWidth * Scale) - TextMargin;
if RenderCanvas.TextWidth(Result) > maxW then
Result := GetDisplayString(RenderCanvas, Result, 0, maxW);
end;
end;
function TVpDayViewPainter.CountOverlappingEvents(Event: TVpEvent; function TVpDayViewPainter.CountOverlappingEvents(Event: TVpEvent;
const EArray: TVpDvEventArray): Integer; const EArray: TVpDvEventArray): Integer;
var var
@ -713,14 +747,8 @@ var
EventRect, GutterRect: TRect; EventRect, GutterRect: TRect;
StartPixelOffset, EndPixelOffset: Integer; StartPixelOffset, EndPixelOffset: Integer;
StartOffset, EndOffset: Double; StartOffset, EndOffset: Double;
timeFmt: String;
EventString: String; EventString: String;
TextRegion : HRGN;
WorkRegion1: HRGN;
WorkRegion2: HRGN;
tmpRect: TRect; tmpRect: TRect;
CW: Integer;
w: Integer;
begin begin
{ Initialize, collect useful information needed later } { Initialize, collect useful information needed later }
EventCategory := FDayView.Datastore.CategoryColorMap.GetCategory(AEvent.Category); EventCategory := FDayView.Datastore.CategoryColorMap.GetCategory(AEvent.Category);
@ -731,74 +759,25 @@ begin
else else
EventIsEditing := false; EventIsEditing := false;
timeFmt := IfThen(FDayView.TimeFormat = tf24Hour, 'h:nn', 'h:nnam/pm');
(* -- original
{ remove the date portion from the start and end times } { remove the date portion from the start and end times }
EventSTime := Event.StartTime; PrepareEventTimes(AEvent, ARenderDate, EventSTime, EventETime);
EventETime := Event.EndTime;
if trunc(EventSTime) < trunc(ARenderDate) then //First Event
EventSTime := 0+trunc(ARenderDate);
if trunc(EventETime) > trunc(ARenderDate) then //First Event
EventETime := 0.999+trunc(ARenderDate);
EventSTime := EventSTime - ARenderDate;
EventETime := EventETime - ARenderDate;
{ Find the line on which this event starts }
EventSLine := GetStartLine(EventSTime, Granularity);
{ Handle End Times of Midnight }
if EventETime = 0 then
EventETime := EncodeTime (23, 59, 59, 0);
*)
{ remove the date portion from the start and end times } { Find the lines on which this event starts and ends }
EventSTime := AEvent.StartTime;
EventETime := AEvent.EndTime;
if (EventSTime < trunc(ARenderDate)) and (AEvent.RepeatCode = rtNone) then // First Event
EventSTime := trunc(ARenderDate)
else if (AEvent.RepeatCode <> rtNone) then
EventSTime := frac(EventSTime) + trunc(ARenderDate);
if (trunc(EventETime) > trunc(ARenderDate)) and (AEvent.RepeatCode = rtNone) then // First Event
EventETime := 0.999 + trunc(ARenderDate)
else if (AEvent.RepeatCode <> rtNone) then
EventETime := frac(EventETime) + trunc(ARenderDate);
EventSTime := EventSTime - trunc(ARenderDate);
EventETime := EventETime - trunc(ARenderDate);
{ Handle End Times of Midnight }
if EventETime = 0 then
EventETime := EncodeTime(23, 59, 59, 0);
{ Find the line on which this event starts }
EventSLine := GetStartLine(EventSTime, FDayView.Granularity); EventSLine := GetStartLine(EventSTime, FDayView.Granularity);
EventELine := GetEndLine(EventETime, FDayView.Granularity);
{ Calculate the number of lines this event will cover }
EventELine := GetEndLine(EventETime {Event.EndTime}, FDayView.Granularity);
EventLineCount := EventELine - EventSLine + 1;
EventDuration := EventETime - EventSTime;
{ If the event doesn't occupy area that is currently visible, then skip it. } { If the event doesn't occupy area that is currently visible, then skip it. }
if (EventELine < StartLine) or (EventSLine > StartLine + RealVisibleLines) then if (EventELine < StartLine) or (EventSLine > StartLine + RealVisibleLines) then
Exit; Exit;
{ Calculate the number of lines this event will cover }
EventLineCount := EventELine - EventSLine + 1;
EventDuration := EventETime - EventSTime;
{ Build the rectangle in which the event will be painted. } { Build the rectangle in which the event will be painted. }
EventRect := TVpDayViewOpener(FDayView).dvLineMatrix[Col, EventSLine].Rec; EventRect := TVpDayViewOpener(FDayView).dvLineMatrix[Col, EventSLine].Rec;
if EventRect.Left < VisibleRect.Left then
EventRect.Left := VisibleRect.Left;
if EventRect.Top < VisibleRect.Top then
EventRect.Top := VisibleRect.Top;
EventRect.Bottom := TVpDayViewOpener(FDayView).dvLineMatrix[Col, EventELine].Rec.Bottom; EventRect.Bottom := TVpDayViewOpener(FDayView).dvLineMatrix[Col, EventELine].Rec.Bottom;
if EventRect.Bottom < VisibleRect.Top then PrepareEventRect(AEventRec.WidthDivisor, AEventRec.Level, EventRect, EventWidth);
EventRect.Bottom := VisibleRect.Bottom;
EventWidth := WidthOf(VisibleRect) div AEventRec.WidthDivisor;
{ Slide the rect over to correspond with the level }
if AEventRec.Level > 0 then
EventRect.Left := EventRect.Left + EventWidth * AEventRec.Level
{ added because level 0 events were one pixel too far to the right }
else
EventRect.Left := EventRect.Left - 1;
EventRect.Right := EventRect.Left + EventWidth - FDayView.GutterWidth;
{ Draw the event rectangle } { Draw the event rectangle }
{ paint Event text area clWindow } { paint Event text area clWindow }
@ -820,14 +799,12 @@ begin
{ stop drawing colored area according to the start time and end time of the event. } { stop drawing colored area according to the start time and end time of the event. }
StartPixelOffset := 0; StartPixelOffset := 0;
EndPixelOffset := 0; EndPixelOffset := 0;
if (PixelDuration > 0) and (EventDuration < GetLineDuration(FDayView.Granularity) * EventLineCount) if (PixelDuration > 0) and (EventDuration < GetLineDuration(FDayView.Granularity) * EventLineCount)
then begin then begin
if (EventSLine >= StartLine) and (EventSTime > TVpDayViewOpener(FDayView).dvLineMatrix[0, EventSLine].Time) if (EventSLine >= StartLine) and (EventSTime > TVpDayViewOpener(FDayView).dvLineMatrix[0, EventSLine].Time)
then begin then begin
{ Get the start offset in TDateTime format } { Get the start offset in TDateTime format }
StartOffset := EventSTime - TVpDayViewOpener(FDayView).dvLineMatrix[0, EventSLine].Time; StartOffset := EventSTime - TVpDayViewOpener(FDayView).dvLineMatrix[0, EventSLine].Time;
{ determine how many pixels to scooch down before painting the event's color code. } { determine how many pixels to scooch down before painting the event's color code. }
StartPixelOffset := trunc(StartOffset / PixelDuration); StartPixelOffset := trunc(StartOffset / PixelDuration);
end; end;
@ -837,7 +814,6 @@ begin
then begin then begin
{ Get the end offset in TDateTime format } { Get the end offset in TDateTime format }
EndOffset := TVpDayViewOpener(FDayView).dvLineMatrix[0, EventELine + 1].Time - EventETime; EndOffset := TVpDayViewOpener(FDayView).dvLineMatrix[0, EventELine + 1].Time - EventETime;
{ determine how many pixels to scooch down before painting the event's color code. } { determine how many pixels to scooch down before painting the event's color code. }
EndPixelOffset := trunc(EndOffset / PixelDuration); EndPixelOffset := trunc(EndOffset / PixelDuration);
end; end;
@ -856,7 +832,6 @@ begin
RenderCanvas.Brush.Color := WindowColor; RenderCanvas.Brush.Color := WindowColor;
{ build the event string }
IconRect.Left := EventRect.Left; IconRect.Left := EventRect.Left;
IconRect.Top := EventRect.Top; IconRect.Top := EventRect.Top;
IconRect.Right := EventRect.Left; IconRect.Right := EventRect.Left;
@ -874,102 +849,25 @@ begin
end; end;
end; end;
{ wp: Using Canvas here does not look correct... OldPen.Assign(RenderCanvas.Pen); // wp: Original code had "Canvas" here which does not look correct
OldPen.Assign(Canvas.Pen);
OldBrush.Assign(Canvas.Brush);
OldFont.Assign(Canvas.Font);
}
OldPen.Assign(RenderCanvas.Pen);
OldBrush.Assign(RenderCanvas.Brush); OldBrush.Assign(RenderCanvas.Brush);
OldFont.Assign(RenderCanvas.Font); OldFont.Assign(RenderCanvas.Font);
if Assigned(FDayView.OnBeforeDrawEvent) and (AEventRec.Level = 0) then
FDayView.OnBeforeDrawEvent(Self, AEvent, FDayView.ActiveEvent = AEvent, RenderCanvas, EventRect, IconRect) if Assigned(FDayView.OnBeforeDrawEvent) then begin
else if Assigned(FDayView.OnBeforeDrawEvent) then tmpRect := EventRect;
FDayView.OnBeforeDrawEvent(Self, AEvent, FDayView.ActiveEvent = AEvent, RenderCanvas, if (AEventRec.Level <> 0) then
Rect(EventRect.Left + FDayView.GutterWidth, EventRect.Top, EventRect.Right, EventRect.Bottom), inc(tmpRect.Left, FDayView.GutterWidth);
IconRect FDayView.OnBeforeDrawEvent(Self, AEvent, FDayView.ActiveEvent = AEvent, RenderCanvas, tmpRect, IconRect);
); end;
if not DisplayOnly then if not DisplayOnly then
DrawIcons(IconRect); DrawIcons(IconRect);
if FDayView.ShowEventTimes then { build the event string }
EventString := Format('%s - %s: %s', [ EventString := BuildEventString(AEvent, EventRect, IconRect);
FormatDateTime(timeFmt, AEvent.StartTime),
FormatDateTime(timeFmt, AEvent.EndTime),
AEvent.Description
])
else
EventString := AEvent.Description;
if FDayView.WrapStyle = wsNone then begin { draw the event string }
{ if the string is longer than the availble space then chop } DrawEventString(EventString, EventRect, IconRect, AEventRec.Level, EventIsEditing);
{ off the and and place those little '...'s at the end }
w := EventRect.Right - IconRect.Right - Round(FDayView.GutterWidth * Scale) - TextMargin;
if RenderCanvas.TextWidth(EventString) > w then
EventString := GetDisplayString(RenderCanvas, EventString, 0, w);
end;
if (FDayView.WrapStyle <> wsNone) and (not EventIsEditing) then begin
if (EventRect.Bottom <> IconRect.Bottom) and (EventRect.Left <> IconRect.Right)
then begin
if FDayView.WrapStyle = wsIconFlow then
begin
WorkRegion1 := CreateRectRgn(IconRect.Right, EventRect.Top, EventRect.Right, IconRect.Bottom);
WorkRegion2 := CreateRectRgn(EventRect.Left + FDayView.GutterWidth, IconRect.Bottom, EventRect.Right, EventRect.Bottom);
TextRegion := CreateRectRgn(IconRect.Right, EventRect.Top, EventRect.Right, IconRect.Bottom);
CombineRgn(TextRegion, WorkRegion1, WorkRegion2, RGN_OR);
end else
TextRegion := CreateRectRgn(IconRect.Right, EventRect.Top, EventRect.Right, EventRect.Bottom);
end else
TextRegion := CreateRectRgn(IconRect.Right + FDayView.GutterWidth, EventRect.Top, EventRect.Right, EventRect.Bottom);
try
CW := RenderTextToRegion(RenderCanvas, Angle, RenderIn, TextRegion, EventString);
{ write the event string to the proper spot in the EventRect }
if CW < Length(EventString) then begin
RenderCanvas.Brush.Color := FDayView.DotDotDotColor;
{ draw dot dot dot }
TPSFillRect(RenderCanvas, Angle, RenderIn,
Rect(EventRect.Right - 20, EventRect.Bottom - 7, EventRect.Right - 17, EventRect.Bottom - 4)
);
TPSFillRect(RenderCanvas, Angle, RenderIn,
Rect(EventRect.Right - 13, EventRect.Bottom - 7, EventRect.Right - 10, EventRect.Bottom - 4));
TPSFillRect(RenderCanvas, Angle, RenderIn,
Rect(EventRect.Right - 6, EventRect.Bottom - 7, EventRect.Right - 3, EventRect.Bottom - 4));
end;
finally
if ((EventRect.Bottom > IconRect.Bottom) and (EventRect.Left > IconRect.Right)) or
(FDayView.WrapStyle = wsIconFlow)
then begin
DeleteObject(WorkRegion1);
DeleteObject(WorkRegion2);
DeleteObject(TextRegion);
end else begin
DeleteObject(TextRegion);
end;
end;
end
else
if (not EventIsEditing) then begin
if AEventRec.Level = 0 then
{ don't draw the gutter in the EventRest for level 0 events. }
TPSTextOut(RenderCanvas, // wp: both cases are the same ?!
Angle,
RenderIn,
IconRect.Right + FDayView.GutterWidth + TextMargin,
EventRect.Top + TextMargin,
EventString
)
else
TPSTextOut(RenderCanvas,
Angle,
RenderIn,
IconRect.Right + FDayView.GutterWidth + TextMargin,
EventRect.Top + TextMargin,
EventString
);
end;
{ paint the borders around the event text area } { paint the borders around the event text area }
TPSPolyline(RenderCanvas, Angle, RenderIn, [ TPSPolyline(RenderCanvas, Angle, RenderIn, [
@ -986,21 +884,14 @@ begin
TPSLineTo(RenderCanvas, Angle, RenderIn, EventRect.Left + Round(FDayView.GutterWidth * Scale), EventRect.Bottom); TPSLineTo(RenderCanvas, Angle, RenderIn, EventRect.Left + Round(FDayView.GutterWidth * Scale), EventRect.Bottom);
end; end;
if Assigned(FDayView.OnAfterDrawEvent) and (AEventRec.Level = 0) then if Assigned(FDayView.OnAfterDrawEvent) then begin
FDayView.OnAfterDrawEvent(Self, AEvent, FDayView.ActiveEvent = AEvent, RenderCanvas, EventRect, IconRect) tmpRect := EventRect;
else if (AEventRec.Level <> 0) then
if Assigned(FDayView.OnAfterDrawEvent) then inc(tmpRect.Left, FDayView.GutterWidth);
FDayView.OnAfterDrawEvent(Self, AEvent, FDayView.ActiveEvent = AEvent, RenderCanvas, FDayView.OnAfterDrawEvent(Self, AEvent, FDayView.ActiveEvent = AEvent, RenderCanvas, tmpRect, IconRect);
Rect(EventRect.Left + FDayView.GutterWidth, EventRect.Top, EventRect.Right, EventRect.Bottom), end;
IconRect
);
{ Canvas does not look correct here... RenderCanvas.Brush.Assign(OldBrush); // wp: Original code had "Canvas" here which does not look correct.
Canvas.Brush.Assign(OldBrush);
Canvas.Pen.Assign(OldPen);
Canvas.Font.Assign(OldFont); }
RenderCanvas.Brush.Assign(OldBrush);
RenderCanvas.Pen.Assign(OldPen); RenderCanvas.Pen.Assign(OldPen);
RenderCanvas.Font.Assign(OldFont); RenderCanvas.Font.Assign(OldFont);
@ -1060,13 +951,10 @@ procedure TVpDayViewPainter.DrawEvents(ARenderDate: TDateTime; Col: Integer);
var var
I,J: Integer; I,J: Integer;
Level: Integer;
Event: TVpEvent; Event: TVpEvent;
SaveFont: TFont; SaveFont: TFont;
SaveColor: TColor; SaveColor: TColor;
EventList: TList;
OKToDrawEditFrame: Boolean; OKToDrawEditFrame: Boolean;
ThisTime: Double;
begin begin
if (FDayView.DataStore = nil) or (FDayView.DataStore.Resource = nil) or if (FDayView.DataStore = nil) or (FDayView.DataStore.Resource = nil) or
(not FDayView.DataStore.Connected) then (not FDayView.DataStore.Connected) then
@ -1077,61 +965,10 @@ begin
SaveFont := TFont.Create; SaveFont := TFont.Create;
SaveFont.Assign(RenderCanvas.Font); SaveFont.Assign(RenderCanvas.Font);
{ set the event array's size }
SetLength(EventArray, MaxVisibleEvents);
{ Initialize the new matrix }
for I := 0 to pred(MaxVisibleEvents) do begin
EventArray[I].Event := nil;
EventArray[I].Level := 0;
EventArray[I].OLLevels := 0;
EventArray[I].WidthDivisor := 0;
end;
EventList := TList.Create;
try
{Get all of the events for this day} {Get all of the events for this day}
FDayView.DataStore.Resource.Schedule.EventsByDate(ARenderDate, EventList); PopulateEventArray(ARenderDate);
{ Discard AllDayEvents, because they are drawn above. } // Count the number of events which all share some of the same time
for I := pred(EventList.Count) downto 0 do begin
Event := EventList[I];
if Event.AllDayEvent then
EventList.Delete(I);
end;
{ Arrange this day's events in the event matrix }
Level := 0;
I := 0;
while EventList.Count > 0 do begin
{ Iterate through the events, and place them all in the proper }
{ place in the EventMatrix, according to their start and end times }
J := 0;
ThisTime := 0.0;
while (J < EventList.Count) and (J < MaxVisibleEvents) do begin
Event := EventList[J];
if frac(Event.StartTime) >= ThisTime then begin
ThisTime := frac(Event.EndTime);
{ Handle end times of midnight }
if ThisTime = 0 then
ThisTime := EncodeTime(23, 59, 59, 0);
EventList.Delete(J);
EventArray[I].Event := Event;
EventArray[I].Level := Level;
Inc(I);
Continue;
end
else
Inc(J);
end;
Inc(Level);
end;
finally
EventList.Free;
end;
{ Count the number of events which all share some of the same time }
for I := 0 to pred(MaxVisibleEvents) do begin for I := 0 to pred(MaxVisibleEvents) do begin
if EventArray[I].Event = nil then if EventArray[I].Event = nil then
Break; Break;
@ -1139,18 +976,17 @@ begin
CountOverlappingEvents(TVpEvent(EventArray[I].Event), EventArray); CountOverlappingEvents(TVpEvent(EventArray[I].Event), EventArray);
end; end;
{ Calculate the largest width divisor of all overlapping events, } // Calculate the largest width divisor of all overlapping events, for each event.
{ for each event. }
for I := 0 to pred(MaxVisibleEvents) do begin for I := 0 to pred(MaxVisibleEvents) do begin
if EventArray[I].Event = nil then if EventArray[I].Event = nil then
Break; Break;
EventArray[I].WidthDivisor := GetMaxOLEvents(TVpEvent(EventArray[I].Event), EventArray); EventArray[I].WidthDivisor := GetMaxOLEvents(TVpEvent(EventArray[I].Event), EventArray);
end; end;
{Make one last pass, to make sure that we have set up the width divisors properly } // Make one last pass, to make sure that we have set up the width divisors properly
VerifyMaxWidthDivisors; VerifyMaxWidthDivisors;
{ Time to paint 'em. Let's see if we calculated their placements correctly } // Time to paint 'em. Let's see if we calculated their placements correctly
IconRect := Rect(0, 0, 0, 0); IconRect := Rect(0, 0, 0, 0);
CreateBitmaps; CreateBitmaps;
OldFont := TFont.Create; OldFont := TFont.Create;
@ -1246,6 +1082,76 @@ begin
DrawIcon(dvBmpRecurring, RecurringW, RecurringH, false); DrawIcon(dvBmpRecurring, RecurringW, RecurringH, false);
end; end;
procedure TVpDayViewPainter.DrawEventString(const AText: String;
const AEventRect, AIconRect: TRect; ALevel: Integer; AEventIsEditing: Boolean);
var
WorkRegion1: HRGN;
WorkRegion2: HRGN;
TextRegion: HRGN;
CW: Integer;
begin
if (FDayView.WrapStyle <> wsNone) and (not AEventIsEditing) then begin
if (AEventRect.Bottom <> AIconRect.Bottom) and (AEventRect.Left <> AIconRect.Right)
then begin
if FDayView.WrapStyle = wsIconFlow then
begin
WorkRegion1 := CreateRectRgn(AIconRect.Right, AEventRect.Top, AEventRect.Right, AIconRect.Bottom);
WorkRegion2 := CreateRectRgn(AEventRect.Left + FDayView.GutterWidth, AIconRect.Bottom, AEventRect.Right, AEventRect.Bottom);
TextRegion := CreateRectRgn(AIconRect.Right, AEventRect.Top, AEventRect.Right, AIconRect.Bottom);
CombineRgn(TextRegion, WorkRegion1, WorkRegion2, RGN_OR);
end else
TextRegion := CreateRectRgn(AIconRect.Right, AEventRect.Top, AEventRect.Right, AEventRect.Bottom);
end else
TextRegion := CreateRectRgn(AIconRect.Right + FDayView.GutterWidth, AEventRect.Top, AEventRect.Right, AEventRect.Bottom);
try
CW := RenderTextToRegion(RenderCanvas, Angle, RenderIn, TextRegion, AText);
{ write the event string to the proper spot in the EventRect }
if CW < Length(AText) then begin
RenderCanvas.Brush.Color := FDayView.DotDotDotColor;
{ draw dot dot dot }
TPSFillRect(RenderCanvas, Angle, RenderIn,
Rect(AEventRect.Right - 20, AEventRect.Bottom - 7, AEventRect.Right - 17, AEventRect.Bottom - 4)
);
TPSFillRect(RenderCanvas, Angle, RenderIn,
Rect(AEventRect.Right - 13, AEventRect.Bottom - 7, AEventRect.Right - 10, AEventRect.Bottom - 4));
TPSFillRect(RenderCanvas, Angle, RenderIn,
Rect(AEventRect.Right - 6, AEventRect.Bottom - 7, AEventRect.Right - 3, AEventRect.Bottom - 4));
end;
finally
if ((AEventRect.Bottom > AIconRect.Bottom) and (AEventRect.Left > AIconRect.Right)) or
(FDayView.WrapStyle = wsIconFlow)
then begin
DeleteObject(WorkRegion1);
DeleteObject(WorkRegion2);
DeleteObject(TextRegion);
end else begin
DeleteObject(TextRegion);
end;
end;
end
else
if (not AEventIsEditing) then begin
if ALevel = 0 then
{ don't draw the gutter in the EventRest for level 0 events. }
TPSTextOut(RenderCanvas, // wp: both cases are the same ?!
Angle,
RenderIn,
AIconRect.Right + FDayView.GutterWidth + TextMargin,
AEventRect.Top + TextMargin,
AText
)
else
TPSTextOut(RenderCanvas,
Angle,
RenderIn,
AIconRect.Right + FDayView.GutterWidth + TextMargin,
AEventRect.Top + TextMargin,
AText
);
end;
end;
procedure TVpDayViewPainter.DrawRowHeader(R: TRect); procedure TVpDayViewPainter.DrawRowHeader(R: TRect);
var var
Temp , I: Integer; Temp , I: Integer;
@ -1711,6 +1617,136 @@ begin
end; end;
end; end;
procedure TVpDayViewPainter.PopulateEventArray(ARenderDate: TDateTime);
var
EventList: TList;
event: TVpEvent;
level: Integer;
I, J: Integer;
thisTime: TTime;
begin
{ Set the event array's max size }
SetLength(EventArray, MaxVisibleEvents); // EventArray is global within painter
{ Initialize the new matrix }
for I := 0 to pred(MaxVisibleEvents) do begin
EventArray[I].Event := nil;
EventArray[I].Level := 0;
EventArray[I].OLLevels := 0;
EventArray[I].WidthDivisor := 0;
end;
EventList := TList.Create;
try
{Get all of the events for this day}
FDayView.DataStore.Resource.Schedule.EventsByDate(ARenderDate, EventList);
{ Discard AllDayEvents, because they are drawn separately. }
for I := pred(EventList.Count) downto 0 do begin
event := EventList[I];
if event.AllDayEvent then
EventList.Delete(I);
end;
{ Arrange this day's events in the event matrix }
level := 0;
I := 0;
while EventList.Count > 0 do begin
{ Iterate through the events, and place them all in the proper }
{ place in the EventMatrix, according to their start and end times }
J := 0;
ThisTime := 0.0;
while (J < EventList.Count) and (J < MaxVisibleEvents) do begin
event := EventList[J];
if frac(event.StartTime) >= thisTime then begin
thisTime := frac(event.EndTime);
{ Handle end times of midnight }
if thisTime = 0 then
thisTime := EncodeTime(23, 59, 59, 0);
EventList.Delete(J);
EventArray[I].Event := event;
EventArray[I].Level := level;
Inc(I);
Continue;
end
else
Inc(J);
end;
Inc(level);
end;
finally
EventList.Free;
end;
end;
procedure TVpDayViewPainter.PrepareEventRect(AWidthDivisor, ALevel: Integer;
var AEventRect: TRect; var AEventWidth: Integer);
begin
if AEventRect.Left < VisibleRect.Left then
AEventRect.Left := VisibleRect.Left;
if AEventRect.Top < VisibleRect.Top then
AEventRect.Top := VisibleRect.Top;
if AEventRect.Bottom < VisibleRect.Top then
AEventRect.Bottom := VisibleRect.Bottom;
AEventWidth := WidthOf(VisibleRect) div AWidthDivisor;
{ Slide the rect over to correspond with the level }
if ALevel > 0 then
AEventRect.Left := AEventRect.Left + AEventWidth * ALevel
{ added because level 0 events were one pixel too far to the right }
else
AEventRect.Left := AEventRect.Left - 1;
AEventRect.Right := AEventRect.Left + AEventWidth - FDayView.GutterWidth;
end;
procedure TVpDayViewPainter.PrepareEventTimes(AEvent: TVpEvent;
ARenderDate: TDateTime; out AStartTime, AEndTime: TDateTime);
begin
(* -- original
{ remove the date portion from the start and end times }
EventSTime := Event.StartTime;
EventETime := Event.EndTime;
if trunc(EventSTime) < trunc(ARenderDate) then //First Event
EventSTime := 0+trunc(ARenderDate);
if trunc(EventETime) > trunc(ARenderDate) then //First Event
EventETime := 0.999+trunc(ARenderDate);
EventSTime := EventSTime - ARenderDate;
EventETime := EventETime - ARenderDate;
{ Find the line on which this event starts }
EventSLine := GetStartLine(EventSTime, Granularity);
{ Handle End Times of Midnight }
if EventETime = 0 then
EventETime := EncodeTime (23, 59, 59, 0);
*)
{ remove the date portion from the start and end times }
AStartTime := AEvent.StartTime;
AEndTime := AEvent.EndTime;
if (AStartTime < trunc(ARenderDate)) and (AEvent.RepeatCode = rtNone) then // First Event
AStartTime := trunc(ARenderDate)
else if (AEvent.RepeatCode <> rtNone) then
AStartTime := frac(AStartTime) + trunc(ARenderDate);
if (trunc(AEndTime) > trunc(ARenderDate)) and (AEvent.RepeatCode = rtNone) then // First Event
// wp: wouldn't this be better?
// AEndtime := trunc(ARenderDate) + 1 - 1.0 / (24 * 60 * 60) // 1 sec before midnight
AEndTime := 0.999 + trunc(ARenderDate)
else if (AEvent.RepeatCode <> rtNone) then
AEndTime := frac(AEndTime) + trunc(ARenderDate);
// Transfer the times to the renderdate.
AStartTime := AStartTime - trunc(ARenderDate);
AEndTime := AEndTime - trunc(ARenderDate);
{ Handle End Times of Midnight }
if AEndTime = 0 then
AEndTime := EncodeTime(23, 59, 59, 0); // wp: Is the date part correct here?
end;
procedure TVpDayViewPainter.ScaleIcons(EventRect: TRect); procedure TVpDayViewPainter.ScaleIcons(EventRect: TRect);
var var
h: Integer; h: Integer;