From 705a6878ac3fec5f237503f08deb74825838007f Mon Sep 17 00:00:00 2001 From: wp_xxyyzz Date: Wed, 22 Jun 2016 14:43:43 +0000 Subject: [PATCH] tvplanit: Refactor painting code of TVpDayView (new helper unit TVpDayViewPainter) git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@4804 8e941d3f-bd1b-0410-a28a-d453659cc2b4 --- .../tvplanit/packages/laz_visualplanit.lpk | 6 +- components/tvplanit/source/vpdayview.pas | 66 +- .../tvplanit/source/vpdayviewpainter.pas | 1829 +++++++++++++++++ 3 files changed, 1875 insertions(+), 26 deletions(-) create mode 100644 components/tvplanit/source/vpdayviewpainter.pas diff --git a/components/tvplanit/packages/laz_visualplanit.lpk b/components/tvplanit/packages/laz_visualplanit.lpk index 976020aed..5e252cb9d 100644 --- a/components/tvplanit/packages/laz_visualplanit.lpk +++ b/components/tvplanit/packages/laz_visualplanit.lpk @@ -32,7 +32,7 @@ Portions created by TurboPower Software Inc. are Copyright (C) 2002 TurboPower S Contributor(s): "/> - + @@ -290,6 +290,10 @@ Contributor(s): "/> + + + + diff --git a/components/tvplanit/source/vpdayview.pas b/components/tvplanit/source/vpdayview.pas index 170ea7cc5..40bce9317 100644 --- a/components/tvplanit/source/vpdayview.pas +++ b/components/tvplanit/source/vpdayview.pas @@ -489,7 +489,7 @@ type implementation uses - SysUtils, Math, Forms, Dialogs, VpEvntEditDlg; + SysUtils, Math, Forms, Dialogs, VpEvntEditDlg, VpDayViewPainter; (*****************************************************************************) { TVpTGInPlaceEdit } @@ -2265,6 +2265,21 @@ end; procedure TVpDayView.RenderToCanvas(RenderCanvas: TCanvas; RenderIn: TRect; Angle: TVpRotationAngle; Scale: Extended; RenderDate: TDateTime; StartLine, StopLine: Integer; UseGran: TVpGranularity; DisplayOnly: Boolean); +var + painter: TVpDayViewPainter; +begin + dvPainting := true; + painter := TVpDayviewPainter.Create(Self, RenderCanvas); + try + painter.RenderToCanvas(RenderIn, Angle, Scale, RenderDate, StartLine, + StopLine, UseGran, DisplayOnly); + finally + painter.Free; + dvPainting := false; + end; +end; + +(* var TextWidth: Integer; ColHeadRect: TRect; @@ -2674,8 +2689,8 @@ var end; end; - (* original version - { Draws the all-day events at the top of the DayView in a special manner } + { original version + // Draws the all-day events at the top of the DayView in a special manner procedure DrawAllDayEvents; var ADEventsList : TList; @@ -2693,8 +2708,8 @@ var if (DataStore = nil) or (DataStore.Resource = nil) then Exit; - { Collect all of the events for this range and determine the maximum } - { number of all day events for the range of days covered by the control. } + // Collect all of the events for this range and determine the maximum + // number of all day events for the range of days covered by the control. MaxADEvents := 0; ADEventsList := TList.Create; @@ -2702,17 +2717,17 @@ var TempList := TList.Create; try for I := 0 to pred(RealNumDays) do begin - { skip weekends } + // skip weekends if ((DayOfWeek (RenderDate + i) = 1) or (DayOfWeek (RenderDate + i) = 7)) and (not FIncludeWeekends) then Continue; - { get the all day events for the day specified by RenderDate + I } + // get the all day events for the day specified by RenderDate + I DataStore.Resource.Schedule.AllDayEventsByDate(RenderDate + I, TempList); - { Iterate through these events and place them in ADEventsList } + // Iterate through these events and place them in ADEventsList Skip := false; for J := 0 to pred(TempList.Count) do begin if AdEventsList.Count > 0 then begin @@ -2736,31 +2751,31 @@ var end; if MaxADEvents > 0 then begin - { Set attributes } + // Set attributes RenderCanvas.Brush.Color := RealADEventBkgColor; RenderCanvas.Font.Assign (AllDayEventAttributes.Font); - { Measure the AllDayEvent TextHeight } + // Measure the AllDayEvent TextHeight ADTextHeight := RenderCanvas.TextHeight(VpProductName) + TextMargin; - { Build the AllDayEvent rect based on the value of MaxADEvents } + // Build the AllDayEvent rect based on the value of MaxADEvents ADEventsRect.Bottom := AdEventsRect.Top + (MaxADEvents * ADTextHeight) + TextMargin * 2; - { Clear the AllDayEvents area } + // Clear the AllDayEvents area TpsFillRect(RenderCanvas, Angle, RenderIn, ADEventsRect); StartsBeforeRange := false; - { Cycle through the all day events and draw them appropriately } + // Cycle through the all day events and draw them appropriately for I := 0 to pred(ADEventsList.Count) do begin Event := ADEventsList[I]; - { set the top of the event's rect } + // set the top of the event's rect AdEventRect.Top := ADEventsRect.Top + TextMargin + (I * ADTextHeight); - { see if the event began before the start of the range } + // see if the event began before the start of the range if (Event.StartTime < trunc(RenderDate)) then StartsBeforeRange := true; @@ -2793,14 +2808,14 @@ var ADEventRect.Bottom); dvEventArray[EventCount].Event := Event; Inc (EventCount); - end; { for I := 0 to pred(ADEventsList.Count) do ... } + end; // for I := 0 to pred(ADEventsList.Count) do ... - end; { if MaxADEvents > 0 } + end; // if MaxADEvents > 0 finally ADEventsList.Free; end; - end; *) + end; } procedure DrawEvents(RenderDate: TDateTime; Col: Integer); @@ -2861,12 +2876,12 @@ var Event2 := EventArray[K].Event; { if the Tmp event overlaps with Event, then check it's Width divisor } - (* -- original + {-- original if (TimeInRange(Event2.StartTime, Event1.StartTime, Event1.EndTime, false) or TimeInRange(Event2.EndTime, Event1.StartTime, Event1.EndTime, false)) or ((Event2.StartTime <= Event1.StartTime) and (Event2.EndTime >= Event1.EndTime)) - *) + } if TimeInRange(frac(Event2.StartTime), frac(Event1.StartTime), frac(Event1.EndTime), false) or TimeInRange(frac(Event2.EndTime), frac(Event1.StartTime), frac(Event1.EndTime), false) or ((frac(Event2.StartTime) <= frac(Event1.StartTime)) and (frac(Event2.EndTime) >= frac(Event1.EndTime))) @@ -3225,8 +3240,8 @@ var { if we have hit the end of the events, then bail out } if Event = nil then Break; - (* -- original - { remove the date portion from the start and end times } + { -- original + // remove the date portion from the start and end times EventSTime := Event.StartTime; EventETime := Event.EndTime; if trunc(EventSTime) < trunc(RenderDate) then //First Event @@ -3235,12 +3250,12 @@ var EventETime := 0.999+trunc(RenderDate); EventSTime := EventSTime - RenderDate; EventETime := EventETime - RenderDate; - { Find the line on which this event starts } + // Find the line on which this event starts EventSLine := GetStartLine(EventSTime, Granularity); - { Handle End Times of Midnight } + // 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 } EventSTime := Event.StartTime; @@ -3992,6 +4007,7 @@ begin dvPainting := false; end; +*) {=====} {.$IFNDEF LCL} diff --git a/components/tvplanit/source/vpdayviewpainter.pas b/components/tvplanit/source/vpdayviewpainter.pas new file mode 100644 index 000000000..ef31aba9a --- /dev/null +++ b/components/tvplanit/source/vpdayviewpainter.pas @@ -0,0 +1,1829 @@ +unit VpDayViewPainter; + +interface +{$I vp.inc} + + +uses + SysUtils, LCLType, LCLIntf, Types, + Classes, Graphics, VpConst, VPBase, VpData, VpDayView; + +type + { Defines matrix of event records for managing how events overlap with each other. } + TVpDvEventRec = packed record + Event: Pointer; + Level: Integer; + OLLevels: Integer; { Number of levels which overlap with the event represented by this record. } + WidthDivisor: Integer; { Maximum OLEvents of all of this event's overlapping neighbors. } + RealStartTime: TDateTime; + RealEndTime: TDateTime; + end; + + TVpDvEventArray = array of TVpDvEventRec; + + TVpDayViewPainter = class + private + FDayView: TVpDayView; + // Buffered input parameters + FRenderCanvas: TCanvas; + FAngle: TVpRotationAngle; + FScale: Extended; + FRenderDate: TDateTime; + FRenderIn: TRect; + FStartLine: Integer; + FStopLine: Integer; + FUseGran: TVpGranularity; + FDisplayOnly: Boolean; + // local parameters of the old render procedure + TextWidth: Integer; + ColHeadRect: TRect; + CellsRect: TRect; + RowHeadRect: TRect; + ADEventsRect: TRect; + SaveBrushColor: TColor; + SavePenStyle: TPenStyle; + SavePenColor: TColor; + Drawn: Boolean; + ScrollBarOffset: Integer; + EventCount: Integer; + RealWidth: Integer; + RealHeight: Integer; + RealLeft: Integer; + RealRight: Integer; + RealTop: Integer; + RealBottom: Integer; + DayWidth: Integer; + RealNumDays: Integer; + Rgn: HRGN; + RealRowHeight: Integer; + RealColHeadHeight: Integer; + RealRowHeadWidth: Integer; + RealVisibleLines: Integer; + BevelShadow: TColor; + BevelHighlight: TColor; + BevelDarkShadow: TColor; + WindowColor: TColor; + HighlightText: TColor; + RealHeadAttrColor: TColor; + RealRowHeadAttrColor: TColor; + RealLineColor: TColor; + RealColor: TColor; + BevelFace: TColor; + HighlightBkg: TColor; + RealADEventBkgColor: TColor; + ADEventAttrBkgColor: TColor; + ADEventBorderColor: TColor; + // Aliases of protected TVpDayview elements + dvActiveEventRec: TRect; + dvColRectArray: TVpColRectArray; + dvEventArray: TVpEventArray; + dvLineMatrix: TVpLineMatrix; + dvInPlaceEditor: TVpDvInPlaceEdit; + // variables from local procedures for better access + dvBmpRecurring: TBitmap; + dvBmpCategory: TBitmap; + dvBmpAlarm: TBitmap; + dvBmpCustom: TBitmap; + RecurringW: Integer; + RecurringH: Integer; + CategoryW: Integer; + CategoryH: Integer; + AlarmW: Integer; + AlarmH: Integer; + CustomW: Integer; + CustomH: Integer; + + protected + // Buffered input parameters as properties + property Angle: TVpRotationAngle read FAngle; + property DisplayOnly: Boolean read FDisplayOnly; + property RenderCanvas: TCanvas read FRenderCanvas; + property RenderDate: TDateTime read FRenderDate write FRenderDate; + property RenderIn: TRect read FRenderIn; + property Scale: Extended read FScale; + property StartLine: Integer read FStartLine write FStartLine; + property StopLine: Integer read FStopLine; + property UseGran: TVpGranularity read FUseGran; + + protected + function CountOverlappingEvents(Event: TVpEvent; const EArray: TVpDvEventArray): Integer; + procedure CreateBitmaps; + function DetermineIconRect(AEventRect: TRect; AEvent: TVpEvent): TRect; + function GetMaxOLEvents(Event: TVpEvent; const EArray: TVpDvEventArray): Integer; + procedure DrawAllDayEvents; + procedure DrawAllDays; + procedure DrawCells(R: TRect; ColDate: TDateTime; Col: Integer); + procedure DrawColHeader(R: TRect; ARenderDate: TDateTime; Col: Integer); + procedure DrawEvents(ARenderDate: TDateTime; Col: Integer); + procedure DrawIcons(AIconRect: TRect); + procedure DrawRowHeader(R: TRect); + procedure FreeBitmaps; + procedure GetIcons(Event: TVpEvent); + procedure InitializeEventRectangles; + procedure ScaleIcons(EventRect: TRect); + procedure SetMeasurements; + + public + constructor Create(ADayView: TVpDayview; ARenderCanvas: TCanvas); + procedure RenderToCanvas(ARenderIn: TRect; AAngle: TVpRotationAngle; + AScale: Extended; ARenderDate: TDateTime; AStartLine, AStopLine: Integer; + AUseGran: TVpGranularity; ADisplayOnly: Boolean); + + end; + +implementation + +uses + VpCanvasUtils, VpMisc; + +type + TVpDayViewOpener = class(TVpDayView); + +constructor TVpDayViewPainter.Create(ADayView: TVpDayView; ARenderCanvas: TCanvas); +begin + FDayView := ADayView; + FRenderCanvas := ARenderCanvas; + dvActiveEventRec := TVpDayViewOpener(FDayView).dvActiveEventRec; + dvColRectArray := TVpDayViewOpener(FDayView).dvColRectArray; + dvEventArray := TVpDayViewOpener(FDayView).dvEventArray; + dvInPlaceEditor := TVpDayViewOpener(FDayView).dvInplaceEditor; + dvLineMatrix := TVpDayViewOpener(FDayView).dvLineMatrix; +end; + +function TVpDayViewPainter.CountOverlappingEvents(Event: TVpEvent; + const EArray: TVpDvEventArray): Integer; +var + K, SelfLevel: Integer; + Tmp: TVpEvent; + Levels: array of Integer; +begin + { initialize the levels array } + SetLength(Levels, MaxEventDepth); + for K := 0 to pred(MaxEventDepth) do + Levels[K] := 0; + result := 0; + { First, simply count the number of overlapping events. } + K := 0; + SelfLevel := -1; + Tmp := TVpEvent(EArray[K].Event); + while Tmp <> nil do begin + if Tmp = Event then begin + SelfLevel := K; + Inc(K); + Tmp := TVpEvent(EArray[K].Event); + Continue; + end; + + { if the Tmp event's StartTime or EndTime falls within the range of } + { Event... } + if TimeInRange(frac(Tmp.StartTime), frac(Event.StartTime), frac(Event.EndTime), false) or + TimeInRange(frac(Tmp.EndTime), frac(Event.StartTime), frac(Event.EndTime), false) or + { or the Tmp event's StartTime is before or equal to the Event's } + { start time AND its end time is after or equal to the Event's } + { end time, then the events overlap and we will need to increment } + { the value of K. } + ((frac(Tmp.StartTime) <= frac(Event.StartTime)) and (frac(Tmp.EndTime) >= frac(Event.EndTime))) + then begin + { Count this event at this level } + Inc(Levels[EArray[K].Level]); + Inc(result); + end; + + Inc(K); + Tmp := TVpEvent(EArray[K].Event); + end; + { Then adjust count for overlapping events which share a level. } + for K := 0 to pred(MaxEventDepth) do begin + if K = SelfLevel then Continue; + if Levels[K] = 0 then Continue; + result := result - (Levels[K] - 1); + end; +end; + +procedure TVpDayViewPainter.CreateBitmaps; +begin + dvBmpRecurring := TBitmap.Create; + dvBmpCategory := TBitmap.Create; + dvBmpAlarm := TBitmap.Create; + dvBmpCustom := TBitmap.Create; +end; + +function TVpDayViewPainter.DetermineIconRect(AEventRect: TRect; + AEvent: TVpEvent): TRect; +var + MaxHeight: Integer; +begin + Result.Left := AEventRect.Left; + Result.Top := AEventRect.Top; + Result.Bottom := AEventRect.Bottom; + Result.Right := AEventRect.Left + AlarmW + RecurringW + CategoryW + CustomW + 2; + + MaxHeight := AlarmH; + if RecurringH > MaxHeight then + MaxHeight := dvBmpRecurring.Height; + if CategoryH > MaxHeight then + MaxHeight := dvBmpCategory.Height; + if CustomH > MaxHeight then + MaxHeight := dvBmpCustom.Height; + if MaxHeight > AEventRect.Bottom - AEventRect.Top then + MaxHeight := AEventRect.Bottom - AEventRect.Top; + + Result.Bottom := AEventRect.Top + MaxHeight; + if Result.Right > AEventRect.Right then + Result.Right := AEventRect.Right; +end; + +{ returns the maximum OLEvents value from all overlapping neighbors } +function TVpDayViewPainter.GetMaxOLEvents(Event: TVpEvent; const EArray: TVpDvEventArray): Integer; +var + K: Integer; + Tmp: TVpEvent; +begin + result := 1; + K := 0; + Tmp := TVpEvent(EArray[K].Event); + while Tmp <> nil do begin + { if the Tmp event's StartTime or EndTime falls within the range of Event. } + if TimeInRange(frac(Tmp.StartTime), frac(Event.StartTime), frac(Event.EndTime), false) or + TimeInRange(frac(Tmp.EndTime), frac(Event.StartTime), frac(Event.EndTime), false) or + { or the Tmp event's StartTime is before or equal to the Event's } + { start time AND its end time is after or equal to the Event's } + { end time, then the events overlap and we will need to check the } + { value of OLLevels. If it is bigger than result, then modify } + { Result accordingly. } + ((frac(Tmp.StartTime) <= frac(Event.StartTime)) and (frac(Tmp.EndTime) >= frac(Event.EndTime))) + then begin + if EArray[K].OLLevels > result then + Result := EArray[K].OLLevels; + end; + + Inc(K); + Tmp := TVpEvent(EArray[K].Event); + end; +end; + + +{ Draws the all-day events at the top of the DayView in a special manner } +procedure TVpDayViewPainter.DrawAllDayEvents; +var + ADEventsList: TList; + TempList: TList; + I, J, K: Integer; + Event: TVpEvent; + ADEventRect: TRect; + StartsBeforeRange : Boolean; + MaxADEvents: Integer; + Skip: Boolean; + ADTextHeight: Integer; + EventStr: string; + I2: Integer; + DI: Integer; + AllDayWidth: Integer; + OldTop: LongInt; +begin + if (FDayView.DataStore = nil) or (FDayView.DataStore.Resource = nil) then + Exit; + + { Collect all of the events for this range and determine the maximum } + { number of all day events for the range of days covered by the control. } + MaxADEvents := 0; + + AllDayWidth := RealWidth - RealRowHeadWidth - 1 - ScrollBarOffset; + DayWidth := AllDayWidth div FDayView.NumDays; + + ADEventsList := TList.Create; + try + TempList := TList.Create; + try + for I := 0 to pred(RealNumDays) do begin + { skip weekends } + if ((DayOfWeek (RenderDate + i) = 1) or (DayOfWeek (RenderDate + i) = 7)) and + (not FDayView.IncludeWeekends) + then + Continue; + + { get the all day events for the day specified by RenderDate + I } + FDayView.DataStore.Resource.Schedule.AllDayEventsByDate(RenderDate + I, TempList); + + { Iterate through these events and place them in ADEventsList } + Skip := false; + for J := 0 to pred(TempList.Count) do begin + if AdEventsList.Count > 0 then begin + for K := 0 to pred(AdEventsList.Count) do begin + if TVpEvent(AdEventsList[K]) = TVpEvent(TempList[J]) then begin + Skip := true; + Break; + end; + end; + if not Skip then + AdEventsList.Add(TempList[J]); + end else + AdEventsList.Add(TempList[J]); + end; + + if TempList.Count > MaxADEvents then + MaxADEvents := TempList.Count; + end; + finally + TempList.Free; + end; + + if MaxADEvents > 0 then begin + RenderCanvas.Brush.Color := RealADEventBkgColor; + RenderCanvas.Font.Assign(FDayView.AllDayEventAttributes.Font); + + { Measure the AllDayEvent TextHeight } + ADTextHeight := RenderCanvas.TextHeight(VpProductName) + TextMargin; + + { set the top of the event's rect } + OldTop := ADEventsRect.Top; + AdEventRect.Top := OldTop + TextMargin + I * ADTextHeight; + + { Build the AllDayEvent rect based on the value of MaxADEvents } + ADEventsRect.Bottom := AdEventsRect.Top + MaxADEvents * ADTextHeight + TextMargin * 2; + + { Clear the AllDayEvents area } + TpsFillRect(RenderCanvas, Angle, RenderIn, ADEventsRect); + + for I := 0 to pred(RealNumDays) do begin + { Set attributes } + StartsBeforeRange := false; + DI := 0; + { Cycle through the all day events and draw them appropriately } + for I2 := 0 to pred(ADEventsList.Count) do begin + Event := ADEventsList[I2]; + if (trunc(Event.StartTime)<=(trunc(RenderDate)+I)) and + (trunc(Event.EndTime)>=(trunc(RenderDate)+I)) + then begin + { set the top of the event's rect } + AdEventRect.Top := OldTop + TextMargin + DI * ADTextHeight; + inc(DI); + + { see if the event began before the start of the range } + if (Event.StartTime < trunc(RenderDate)) then + StartsBeforeRange := true; + + AdEventRect.Bottom := ADEventRect.Top + ADTextHeight; + AdEventRect.Left := AdEventsRect.Left + DayWidth*I + TextMargin div 2; + AdEventRect.Right := AdEventRect.Left+DayWidth; + + if StartsBeforeRange then + EventStr := '>> ' + else + EventStr := ''; + + EventStr := EventStr + Event.Description; + + RenderCanvas.Brush.Color := ADEventAttrBkgColor; + RenderCanvas.Pen.Color := ADEventBorderColor; + TPSRectangle(RenderCanvas, Angle, RenderIn, + ADEventRect.Left + TextMargin, + ADEventRect.Top + TextMargin div 2, + ADEventRect.Right - TextMargin, + ADEventRect.Top + ADTextHeight + TextMargin div 2 + ); + TPSTextOut(RenderCanvas,Angle, RenderIn, + AdEventRect.Left + TextMargin * 2 + TextMargin div 2, + AdEventRect.Top + TextMargin div 2, + EventStr + ); + + dvEventArray[EventCount].Rec := Rect( + ADEventRect.Left, + ADEventRect.Top - 2, + ADEventRect.Right - TextMargin, + ADEventRect.Bottom + ); + dvEventArray[EventCount].Event := Event; + Inc(EventCount); + end; + end; { for I2 := 0 to pred(ADEventsList.Count) do ... } + end; + end; { if MaxADEvents > 0 } + + finally + ADEventsList.Free; + end; +end; + +procedure TVpDayViewPainter.DrawAllDays; +var + i: Integer; + RPos: Integer; + AllDayWidth: Integer; + ExtraSpace: Integer; + DrawMe: Boolean; + RealDay: Integer; +begin + if RealNumDays = 0 then begin + while (DayOfWeek(RenderDate) = 1) or (DayOfWeek(RenderDate) = 7) do + RenderDate := RenderDate + 1; + RealNumDays := FDayView.NumDays; + end; + AllDayWidth := RealWidth - RealRowHeadWidth - 1 - ScrollBarOffset; + + DayWidth := AllDayWidth div FDayView.NumDays; + ExtraSpace := AllDayWidth mod FDayView.NumDays; + + RPos := RowHeadRect.Right; + + RealDay := 0; + for i := 0 to RealNumDays - 1 do begin + DrawMe := True; + if not FDayView.IncludeWeekends then begin + if (DayOfWeek(RenderDate + i) = 1) or (DayOfWeek(RenderDate + i) = 7) then + DrawMe := False + end; + if DrawMe then begin + { Draw Column Header } + ColHeadRect := Rect(RPos, RealTop + 2, RPos + DayWidth - 1, RealTop + RealColHeadHeight); + if (i = RealNumDays - 1) and (ExtraSpace > 0) then + ColHeadRect.Right := ColHeadRect.Right + ExtraSpace; + + if Assigned(FDayView.OwnerDrawColHeader) then begin + Drawn := false; + FDayView.OwnerDrawColHeader(self, RenderCanvas, ColHeadRect, Drawn); + if not Drawn then + DrawColHeader(ColHeadRect, RenderDate + i, RealDay); + end else + DrawColHeader(ColHeadRect, RenderDate + i, RealDay); + + { Calculate the column rect for this day } + RenderCanvas.Font.Assign(FDayView.Font); + CellsRect := Rect(RPos, ADEventsRect.Bottom + 1, RPos + DayWidth, RealBottom - 2); + if (i = RealNumDays - 1) and (ExtraSpace > 0) then + CellsRect.Right := CellsRect.Right + ExtraSpace; + + { set the ColRectArray } + dvColRectArray[RealDay].Rec := CellsRect; + dvColRectArray[RealDay].Date := RenderDate + i; + + { Draw the cells } + if Assigned(FDayView.OwnerDrawCells) then begin + FDayView.OwnerDrawCells(self, RenderCanvas, CellsRect, RealRowHeight, Drawn); + if not Drawn then + DrawCells(CellsRect, RenderDate + i, RealDay); + end else + DrawCells(CellsRect, RenderDate + i, RealDay); + + { Draw the regular events } + DrawEvents(RenderDate + i, RealDay); + + Inc(RPos, DayWidth); + Inc(RealDay); + end; + end; +end; + +procedure TVpDayViewPainter.DrawCells(R: TRect; ColDate: TDateTime; Col: Integer); +var + I: Integer; + LineRect: TRect; + SavedFont: TFont; + GutterRect: TRect; + LineStartTime: Double; +begin + if StartLine < 0 then + StartLine := FDayView.TopLine; + + { Set GutterRect size } + GutterRect.Left := R.Left; + GutterRect.Top := R.Top; + GutterRect.Bottom := R.Bottom; + GutterRect.Right := GutterRect.Left + Round(FDayView.GutterWidth * Scale); + R.Left := R.Left + Round(FDayView.GutterWidth * Scale) + 1; + + { paint gutter area } + RenderCanvas.Brush.Color := RealColor; + TPSFillRect(RenderCanvas, Angle, RenderIn, GutterRect); + { draw the line down the right side of the gutter } + RenderCanvas.Pen.Color := BevelShadow; + RenderCanvas.Pen.Style := psSolid; + TPSMoveTo(RenderCanvas, Angle, RenderIn, GutterRect.Right, GutterRect.Top); + TPSLineTo(RenderCanvas, Angle, RenderIn, GutterRect.Right, GutterRect.Bottom); + + for I := 0 to FDayView.LineCount - 1 do begin // wp: was withoug -1 + dvLineMatrix[Col, I].Rec.Left := -1; + dvLineMatrix[Col, I].Rec.Top := -1; + dvLineMatrix[Col, I].Rec.Right := -1; + dvLineMatrix[Col, I].Rec.Bottom := -1; + end; + + SavedFont := TFont.Create; + SavedFont.Assign(RenderCanvas.Font); + try + RenderCanvas.Font.Assign(FDayView.Font); + RenderCanvas.Brush.Color := RealColor; + TPSFillRect(RenderCanvas, Angle, RenderIn, R); + + LineRect := Rect(R.left, R.top, R.Right, R.Top + RealRowHeight); + RenderCanvas.Pen.Style := psSolid; + RenderCanvas.Pen.Color := FDayView.LineColor; + + { Paint the client area } + for I := 0 to RealVisibleLines do begin + + if (I > pred(FDayView.LineCount)) then + Break; + + if FDayView.TopLine + i >= FDayView.LineCount then + Break; + + RenderCanvas.Brush.Color := RealColor; + RenderCanvas.Font.Assign(SavedFont); + LineRect.Top := Round (R.Top + (i * RealRowHeight)); + LineRect.Bottom := Round (LineRect.Top + (RealRowHeight)); + if I + StartLine < FDayView.LineCount then + dvLineMatrix[Col, I + StartLine].Rec := LineRect; + + { color-code cells } + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + // !!!! This causes problems at design time - implement a better !!!! + // !!!! Fix - check the value after the component is streamed in !!!! + // !!!! May be a good use for ... loaded or in my message !!!! + // !!!! Handler (the message handler would be better !!!! + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// if ActiveRow = -1 then +// ActiveRow := TopLine; + + if not DisplayOnly then begin + if FDayView.Focused and (FDayView.ActiveCol = col) and + (FDayView.ActiveRow = StartLine + I) + then begin + { Paint background hilight color } + RenderCanvas.Brush.Color := HighlightBkg; + RenderCanvas.Font.Color := HighlightText; + TPSFillRect(RenderCanvas, Angle, RenderIn, LineRect); + end else begin + { paint the active, inactive, weekend, and holiday colors } + + { HOLIDAY COLORS ARE NOT IMPLEMENTED YET } + + { if ColDate is a weekend, then paint all rows the weekend } + { color. } + if (DayOfWeek(ColDate) = 1) or (DayOfWeek(ColDate) = 7) then begin + { this is a weekend } + RenderCanvas.Brush.Color := FDayView.TimeSlotColors.Weekend; + TPSFillRect(RenderCanvas, Angle, RenderIn, LineRect); + end + + else begin + { ColDate is a weekday, so check to see if the active } + { range is set. If it isn't then paint all rows the color } + { corresponding to Weekday. If it is, then paint inactive } + { rows the color corresponding to inactive and the active } + { rows the color corresponding to Active Rows. } + if FDayView.TimeSlotColors.ActiveRange.RangeBegin = FDayView.TimeSlotColors.ActiveRange.RangeEnd then + begin + { there is no active range, so all time slots are to be } + { painted the color of Weekday } + RenderCanvas.Brush.Color := FDayView.TimeSlotColors.Weekday; + TPSFillRect(RenderCanvas, Angle, RenderIn, LineRect); + end + else begin + { there is an active range defined, so we need to see if } + { the current line falls in the active range or not, and } + { paint it accordingly } + LineStartTime := dvLineMatrix[Col, StartLine + I].Time; + if TimeInRange(LineStartTime, + FDayView.TimeSlotColors.ActiveRange.StartTime, + FDayView.TimeSlotColors.ActiveRange.EndTime - (1/MinutesInDay), true) + then begin + RenderCanvas.Brush.Color := FDayView.TimeSlotColors.Active; + TPSFillRect (RenderCanvas, Angle, RenderIn, LineRect); + end else begin + RenderCanvas.Brush.Color := FDayView.TimeSlotColors.Inactive; + TPSFillRect (RenderCanvas, Angle, RenderIn, LineRect); + end; + end; + end; + end; + end; + + { Draw the lines } + if I + StartLine <= FDayView.LineCount then begin + RenderCanvas.Pen.Color := FDayView.LineColor; + TPSMoveTo(RenderCanvas, Angle, RenderIn, LineRect.Left, LineRect.Top); + TPSLineTo(RenderCanvas, Angle, RenderIn, LineRect.Right - 1, LineRect.Top); + TPSMoveTo(RenderCanvas, Angle, RenderIn, LineRect.Left, LineRect.Bottom); + TPSLineTo(RenderCanvas, Angle, RenderIn, LineRect.Right - 1, LineRect.Bottom); + end; + end; + + { Draw a line down the right side of the column to close the } + { cells right sides } + RenderCanvas.Pen.Color := BevelShadow; + RenderCanvas.Pen.Style := psSolid; + TPSMoveTo(RenderCanvas, Angle, RenderIn, R.Right - 1, R.Bottom); + TPSLineTo(RenderCanvas, Angle, RenderIn, R.Right - 1, R.Top - 1); + + RenderCanvas.Font.Assign(SavedFont); + finally + SavedFont.Free; + end; +end; + +procedure TVpDayViewPainter.DrawColHeader(R: TRect; ARenderDate: TDateTime; + Col: Integer); +var + SaveFont: TFont; + DateStr, ResStr: string; + DateStrLen, ResStrLen: integer; + StrHt: Integer; + TextRect: TRect; + X, Y: Integer; +begin + SaveFont := TFont.Create; + try + SaveFont.Assign(RenderCanvas.Font); + { Draw Column Header } + RenderCanvas.Font.Assign(FDayView.HeadAttributes.Font); + RenderCanvas.Brush.Color := RealHeadAttrColor; + RenderCanvas.Pen.Style := psClear; + TPSRectangle(RenderCanvas, Angle, RenderIn, R); + RenderCanvas.Pen.Style := psSolid; + + { Size text rect } + TextRect.TopLeft := R.TopLeft; + TextRect.BottomRight := R.BottomRight; + TextRect.Right := TextRect.Right - 3; + TextRect.Left := TextRect.Left + 2; + + { Fix Date String } + DateStr := FormatDateTime(FDayView.DateLabelFormat, ARenderDate); + DateStrLen := RenderCanvas.TextWidth(DateStr); + StrHt := RenderCanvas.TextHeight(DateStr); + if DateStrLen > TextRect.Right - TextRect.Left then begin + DateStr := GetDisplayString(RenderCanvas, DateStr, 0, TextRect.Right - TextRect.Left); + DateStrLen := RenderCanvas.TextWidth(DateStr); + end; + + if (FDayView.DataStore <> nil) and (FDayView.DataStore.Resource <> nil) + and FDayView.ShowResourceName + then begin + { fix Res String } + ResStr := FDayView.DataStore.Resource.Description; + ResStrLen := RenderCanvas.TextWidth(ResStr); + if ResStrLen > TextRect.Right - TextRect.Left then begin + ResStr := GetDisplayString(RenderCanvas, ResStr, 0, TextRect.Right - TextRect.Left); + ResStrLen := RenderCanvas.TextWidth(ResStr); + end; + { center and write the resource name in the first column } + if (Col = 0) then begin + X := TextRect.Left + (TextRect.Right - TextRect.Left) div 2 - ResStrLen div 2; + Y := TextRect.Top + TextMargin; + TPSTextOut(RenderCanvas, Angle, RenderIn, X, Y, FDayView.DataStore.Resource.Description); + end; + { center and write the date string } + X := TextRect.Left + (TextRect.Right - TextRect.Left) div 2 - DateStrLen div 2; + Y := TextRect.Top + (TextMargin * 2) + StrHt; + TPSTextOut(RenderCanvas, Angle, RenderIn, X, Y, DateStr); + end else begin + { center and write the date string } + Y := TextRect.Top + TextMargin; + X := TextRect.Left + (TextRect.Right - TextRect.Left) div 2 - DateStrLen div 2; + TPSTextOut(RenderCanvas, Angle, RenderIn, X, Y, DateStr); + end; + + {Draw Column Head Borders } + if FDayView.DrawingStyle = dsFlat then begin + RenderCanvas.Pen.Color := BevelShadow; + {bottom} + TPSMoveTo(RenderCanvas, Angle, RenderIn, R.Right, R.Bottom); + TPSLineTo(RenderCanvas, Angle, RenderIn, R.Left - 1, R.Bottom); + {right side} + TPSMoveTo(RenderCanvas, Angle, RenderIn, R.Right, R.Bottom - 4); + TPSLineTo(RenderCanvas, Angle, RenderIn, R.Right, R.Top + 3); + RenderCanvas.Pen.Color := BevelHighlight; + {left side} + TPSMoveTo(RenderCanvas, Angle, RenderIn, R.Left, R.Bottom - 4); + TPSLineTo(RenderCanvas, Angle, RenderIn, R.Left, R.Top + 3); + end + else + if FDayView.DrawingStyle = ds3d then begin + DrawBevelRect( + RenderCanvas, + TPSRotateRectangle(Angle, RenderIn, Rect (R.Left, R.Top, R.Right, R.Bottom)), + BevelHighlight, + BevelDarkShadow + ); + end; + RenderCanvas.Font.Assign(SaveFont); + finally + SaveFont.Free; + end; +end; + +procedure TVpDayViewPainter.DrawEvents(ARenderDate: TDateTime; Col: Integer); +var + I,J, StartPixelOffset, EndPixelOffset: Integer; + Level, EventWidth, EventSLine, EventELine: Integer; + EventLineCount: Integer; + EventSTime, EventETime, ThisTime: Double; + EventDuration, LineDuration, PixelDuration: Double; + StartOffset, EndOffset, STime, ETime: Double; + EventRect, VisibleRect, GutterRect: TRect; + EventString, Format: string; + Event: TVpEvent; + SaveFont: TFont; + SaveColor: TColor; + EventArray: TVpDvEventArray; + EventList: TList; + IconRect: TRect; + { + dvBmpRecurring: TBitmap; + dvBmpCategory: TBitmap; + dvBmpAlarm: TBitmap; + dvBmpCustom: TBitmap; + RecurringW: Integer; + RecurringH: Integer; + CategoryW: Integer; + CategoryH: Integer; + AlarmW: Integer; + AlarmH: Integer; + CustomW: Integer; + CustomH: Integer; + } + {$IFDEF DEBUGDV} + SL : TStringList; + {$ENDIF} + + procedure VerifyMaxWidthDivisors; + var + I, K: Integer; + Event1, Event2: TVpEvent; + begin + for I := 0 to pred(MaxVisibleEvents) do begin + { if we hit a null event, then we're through } + if EventArray[I].Event = nil then + Break; + + { otherwise keep going } + Event1 := EventArray[I].Event; + + { initialize the WidthDivisor for this record } + EventArray[I].WidthDivisor := 1; + + {now iterate through all events and get the maximum OLEvents value of } + { all the overlapping events } + for K := 0 to pred(MaxVisibleEvents) do begin + { if we hit a null event, then we're through } + if EventArray[K].Event = nil then + Break; + + Event2 := EventArray[K].Event; + + { if the Tmp event overlaps with Event, then check it's Width divisor } + (* -- original + if (TimeInRange(Event2.StartTime, Event1.StartTime, Event1.EndTime, false) + or TimeInRange(Event2.EndTime, Event1.StartTime, Event1.EndTime, false)) + or ((Event2.StartTime <= Event1.StartTime) + and (Event2.EndTime >= Event1.EndTime)) + *) + if TimeInRange(frac(Event2.StartTime), frac(Event1.StartTime), frac(Event1.EndTime), false) or + TimeInRange(frac(Event2.EndTime), frac(Event1.StartTime), frac(Event1.EndTime), false) or + ((frac(Event2.StartTime) <= frac(Event1.StartTime)) and (frac(Event2.EndTime) >= frac(Event1.EndTime))) + then begin + if EventArray[I].WidthDivisor < EventArray[K].WidthDivisor then + EventArray[I].WidthDivisor := EventArray[K].WidthDivisor; + end; + end; + end; + end; + +var + OKToDrawEditFrame : Boolean; + TextRegion : HRGN; + WorkRegion1: HRGN; + WorkRegion2: HRGN; + CW: Integer; + EventIsEditing: Boolean; + OldPen: TPen; + OldBrush: TBrush; + OldFont: TFont; +begin + if (FDayView.DataStore = nil) or (FDayView.DataStore.Resource = nil) or + (not FDayView.DataStore.Connected) then + Exit; + + { Save the canvas color and font } + SaveColor := RenderCanvas.Brush.Color; + SaveFont := TFont.Create; + SaveFont.Assign(RenderCanvas.Font); + + { Initialize some stuff } + if FDayView.TimeFormat = tf24Hour then + Format := 'h:nn' + else + Format := 'h:nnam/pm'; + + { 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} + FDayView.DataStore.Resource.Schedule.EventsByDate(ARenderDate, EventList); + + { Discard AllDayEvents, because they are drawn above. } + 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 + if EventArray[I].Event = nil then + Break; + EventArray[I].OLLevels := 1 + { it is necessary to count this event too } + CountOverlappingEvents(TVpEvent(EventArray[I].Event), EventArray); + end; + + { Calculate the largest width divisor of all overlapping events, } + { for each event. } + for I := 0 to pred(MaxVisibleEvents) do begin + if EventArray[I].Event = nil then + Break; + EventArray[I].WidthDivisor := GetMaxOLEvents(TVpEvent(EventArray[I].Event), EventArray); + end; + + {Make one last pass, to make sure that we have set up the width divisors properly } + VerifyMaxWidthDivisors; + +/////// Debug Code ///////// + { Dump a debug report to drive C } + {$IFDEF DEBUGDV} + SL := TStringList.Create; + try + I := 0; + while EventArray[I].Event <> nil do begin + SL.Add('Description: ' + TVpEvent(EventArray[I].Event).Description + + #13#10 + ' Level: ' + IntToStr(EventArray[I].Level) + + #13#10 + ' OLLevels: ' + IntToStr(EventArray[I].OLLevels) + + #13#10 + ' WidthDivisor: ' + IntToStr(EventArray[I].WidthDivisor)); + Inc(I); + end; + SL.SaveToFile('C:\EventList' + IntToStr(Col) + '.txt'); + finally + Sl.Free; + end; + {$ENDIF} +/////// Debug Code ///////// + + { Time to paint 'em. Let's see if we calculated their placements correctly } + IconRect := Rect(0, 0, 0, 0); + CreateBitmaps; + OldFont := TFont.Create; + OldPen := TPen.Create; + OldBrush := TBrush.Create; + try + { get a rectangle of the visible area } + VisibleRect := dvLineMatrix[Col, StartLine].Rec; + VisibleRect.Bottom := FDayView.ClientRect.Bottom; + + STime := dvLineMatrix[0, StartLine].Time; + ETime := dvLineMatrix[0, StartLine + RealVisibleLines].Time; + + LineDuration := GetLineDuration(FDayView.Granularity); + { Determine how much time is represented by one pixel. It is the } + { amount of time represented by one line, divided by the height of } + { a line in pixels. } + if (dvLineMatrix[Col, StartLine].Rec.Bottom - dvLineMatrix[Col, StartLine].Rec.Top) > 0 then + PixelDuration := (LineDuration / (dvLineMatrix[Col, StartLine].Rec.Bottom - dvLineMatrix[Col, StartLine].Rec.Top)) + else + PixelDuration := 0; + + { Iterate through events and paint them } + for I := 0 to pred(MaxVisibleEvents) do begin + { get the next event } + Event := TVpEvent(EventArray[I].Event); + + { if we have hit the end of the events, then bail out } + if Event = nil then + Break; + (* -- 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 } + EventSTime := Event.StartTime; + EventETime := Event.EndTime; + if (EventSTime < trunc(ARenderDate)) and (Event.RepeatCode=rtNone) then //First Event + EventSTime := trunc(ARenderDate) + else if (Event.RepeatCode <> rtNone) then + EventSTime := frac(EventSTime) + trunc(ARenderDate); + if (trunc(EventETime) > trunc(ARenderDate)) and (Event.RepeatCode = rtNone) then //First Event + EventETime := 0.999+trunc(ARenderDate) + else if (Event.RepeatCode<>rtNone) then + EventETime := frac(EventETime) + trunc(ARenderDate); + EventSTime := EventSTime - trunc(ARenderDate); + EventETime := EventETime - trunc(ARenderDate); + { Find the line on which this event starts } + EventSLine := GetStartLine(EventSTime, FDayView.Granularity); + { Handle End Times of Midnight } + if EventETime = 0 then + EventETime := EncodeTime(23, 59, 59, 0); + + { 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 (EventELine < StartLine) or (EventSLine > StartLine + RealVisibleLines) then + Continue; + + { Build the rectangle in which the event will be painted. } + EventRect := 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 := dvLineMatrix[Col, EventELine].Rec.Bottom; + if EventRect.Bottom < VisibleRect.Top then + EventRect.Bottom := VisibleRect.Bottom; + EventWidth := (VisibleRect.Right - VisibleRect.Left) div EventArray[I].WidthDivisor; + + { Slide the rect over to correspond with the level } + if EventArray[I].Level > 0 then + EventRect.Left := EventRect.Left + (EventWidth * EventArray[I].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 } + { paint Event text area clWindow } + if Assigned(FDayView.DataStore) then + RenderCanvas.Brush.Color := FDayView.Datastore.CategoryColorMap.GetCategory(Event.Category).BackgroundColor + else + RenderCanvas.Brush.Color := WindowColor; + TPSFillRect(RenderCanvas, Angle, RenderIn, EventRect); + + { paint the little area to the left of the text the color } + { corresponding to the event's category } + { These colors are used even when printing } + if Assigned(FDayView.DataStore) then + RenderCanvas.Brush.Color := FDayView.DataStore.CategoryColorMap.GetColor(Event.Category); + + { find the pixel offset to use for determining where to start and } + { stop drawing colored area according to the start time and end time of the event. } + StartPixelOffset := 0; + EndPixelOffset := 0; + + if (PixelDuration > 0) and (EventDuration < GetLineDuration(FDayView.Granularity) * EventLineCount) + then begin + if (EventSLine >= StartLine) and (EventSTime > dvLineMatrix[0, EventSLine].Time) + then begin + { Get the start offset in TDateTime format } + StartOffset := EventSTime - dvLineMatrix[0, EventSLine].Time; + + { determine how many pixels to scooch down before painting the event's color code. } + StartPixelOffset := trunc(StartOffset / PixelDuration); + end; + + if (EventELine <= StartLine + RealVisibleLines) and + (EventETime < dvLineMatrix[0, EventELine + 1].Time ) + then begin + { Get the end offset in TDateTime format } + EndOffset := dvLineMatrix[0, EventELine + 1].Time - EventETime; + + { determine how many pixels to scooch down before painting the } + { event's color code. } + EndPixelOffset := trunc(EndOffset / PixelDuration); + end; + end; + + { Paint the gutter inside the EventRect all events } + if (EventArray[I].Level = 0) then + GutterRect.Left := EventRect.Left - Trunc (FDayView.GutterWidth * Scale) + else + GutterRect.Left := EventRect.Left; + GutterRect.Right := GutterRect.Left + Round (FDayView.GutterWidth * Scale); + GutterRect.Top := EventRect.Top + StartPixelOffset; + GutterRect.Bottom := EventRect.Bottom - EndPixelOffset; + + TPSFillRect(RenderCanvas, Angle, RenderIn, GutterRect); + + RenderCanvas.Brush.Color := WindowColor; + + if (dvInPlaceEditor <> nil) and dvInplaceEditor.Visible then begin + if FDayView.ActiveEvent = Event then + EventIsEditing := True + else + EventIsEditing := False; + end else + EventIsEditing := False; + + { build the event string } + IconRect.Left := EventRect.Left; + IconRect.Top := EventRect.Top; + IconRect.Right := EventRect.Left; + IconRect.Bottom := EventRect.Top; + if not DisplayOnly then begin + GetIcons(Event); + if EventArray[I].Level = 0 then begin + ScaleIcons(EventRect); + IconRect := DetermineIconRect(EventRect, Event); + end else begin + ScaleIcons(Rect( + EventRect.Left + FDayView.GutterWidth, + EventRect.Top, + EventRect.Right, + EventRect.Bottom + )); + IconRect := DetermineIconRect(Rect( + EventRect.Left + FDayView.GutterWidth, + EventRect.Top, + EventRect.Right, + EventRect.Bottom + ), + Event + ); + end; + end; + + { wp: Using Canvas here does not look correct... + OldPen.Assign(Canvas.Pen); + OldBrush.Assign(Canvas.Brush); + OldFont.Assign(Canvas.Font); + } + OldPen.Assign(FRenderCanvas.Pen); + OldBrush.Assign(FRenderCanvas.Brush); + OldFont.Assign(FRenderCanvas.Font); + if Assigned(FDayView.OnBeforeDrawEvent) and (EventArray[I].Level = 0) then + FDayView.OnBeforeDrawEvent(Self, Event, FDayView.ActiveEvent = Event, RenderCanvas, EventRect, IconRect) + else if Assigned(FDayView.OnBeforeDrawEvent) then + FDayView.OnBeforeDrawEvent(Self, Event, FDayView.ActiveEvent = Event, RenderCanvas, + Rect(EventRect.Left + FDayView.GutterWidth, EventRect.Top, EventRect.Right, EventRect.Bottom), + IconRect + ); + + if not DisplayOnly then + DrawIcons(IconRect); + + if FDayView.ShowEventTimes then + EventString := FormatDateTime(Format, Event.StartTime) + '-' + + FormatDateTime(Format, Event.EndTime) + ' ' + Event.Description + else + EventString := Event.Description; + + if FDayView.WrapStyle = wsNone then begin + { if the string is longer than the availble space then chop } + { off the and and place those little '...'s at the end } + + if RenderCanvas.TextWidth(EventString) > EventRect.Right - IconRect.Right - Round(FDayView.GutterWidth * Scale) - TextMargin + then + EventString := GetDisplayString( + RenderCanvas, + EventString, + 0, + EventRect.Right - IconRect.Right - Round(FDayView.GutterWidth * Scale) - TextMargin + ); + 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 EventArray[I].Level = 0 then + { don't draw the gutter in the EventRest for level 0 events. } + TPSTextOut(RenderCanvas, + 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 } + TPSPolyline(RenderCanvas, Angle, RenderIn, [ + Point(EventRect.Left, EventRect.Top), + Point(EventRect.Right, EventRect.Top), + Point(EventRect.Right, EventRect.Bottom), + Point(EventRect.Left, EventRect.Bottom), + Point(EventRect.Left, EventRect.Top) + ]); + { don't paint gutter area on level 0 items } + if EventArray[I].Level > 0 then begin + TPSMoveTo(RenderCanvas, Angle, RenderIn, EventRect.Left + Round(FDayView.GutterWidth * Scale), EventRect.Top); + TPSLineTo(RenderCanvas, Angle, RenderIn, EventRect.Left + Round(FDayView.GutterWidth * Scale), EventRect.Bottom); + end; + + if Assigned(FDayView.OnAfterDrawEvent) and (EventArray[I].Level = 0) then + FDayView.OnAfterDrawEvent(Self, Event, FDayView.ActiveEvent = Event, RenderCanvas, EventRect, IconRect) + else + if Assigned(FDayView.OnAfterDrawEvent) then + FDayView.OnAfterDrawEvent(Self, Event, FDayView.ActiveEvent = Event, RenderCanvas, + Rect(EventRect.Left + FDayView.GutterWidth, EventRect.Top, EventRect.Right, EventRect.Bottom), + IconRect + ); + + { Canvas does not look correct here... + Canvas.Brush.Assign(OldBrush); + Canvas.Pen.Assign(OldPen); + Canvas.Font.Assign(OldFont); } + + RenderCanvas.Brush.Assign(OldBrush); + RenderCanvas.Pen.Assign(OldPen); + RenderCanvas.Font.Assign(OldFont); + + dvEventArray[EventCount].Rec := Rect( + EventRect.Left, EventRect.Top, EventRect.Right, EventRect.Bottom + 1 + ); + dvEventArray[EventCount].IconRect := IconRect; + dvEventArray[EventCount].Event := Event; + Inc(EventCount); + end; + + OKToDrawEditFrame := True; + if Assigned(FDayView.ActiveEvent) then + OKToDrawEditFrame := not (FDayView.ActiveEvent.AllDayEvent); + + if (dvInPlaceEditor <> nil) and dvInplaceEditor.Visible and OKToDrawEditFrame then begin + { paint extra borders around the editor } + if Assigned(FDayView.DataStore) then + RenderCanvas.Brush.Color := FDayView.DataStore.CategoryColorMap.GetColor(FDayView.ActiveEvent.Category); + RenderCanvas.Pen.Color := clWindowFrame; + TPSFillRect(RenderCanvas, Angle, RenderIn, + Rect(dvActiveEventRec.Left, dvActiveEventRec.Top - FDayView.GutterWidth, dvActiveEventRec.Right, dvActiveEventRec.Top) + ); + TPSPolyline(RenderCanvas, Angle, RenderIn, [ + Point(dvActiveEventRec.Left, dvActiveEventRec.Top), + Point(dvActiveEventRec.Left, dvActiveEventRec.Top - FDayView.GutterWidth), + Point(dvActiveEventRec.Right, dvActiveEventRec.Top - FDayView.GutterWidth), + Point(dvActiveEventRec.Right, dvActiveEventRec.Top) + ]); + TPSFillRect(RenderCanvas, Angle, RenderIn, Rect( + dvActiveEventRec.Left, + dvActiveEventRec.Bottom, + dvActiveEventRec.Right, + dvActiveEventRec.Bottom + FDayView.GutterWidth + )); + TPSPolyline(RenderCanvas, Angle, RenderIn, [ + Point(dvActiveEventRec.Left, dvActiveEventRec.Bottom), + Point(dvActiveEventRec.Left, dvActiveEventRec.Bottom + FDayView.GutterWidth), + Point(dvActiveEventRec.Right, dvActiveEventRec.Bottom + FDayView.GutterWidth), + Point(dvActiveEventRec.Right, dvActiveEventRec.Bottom) + ]); + end; + + { Clean Up } + finally + try + SetLength(EventArray, 0); + FreeBitmaps; + finally + { restore canvas color and font } + RenderCanvas.Brush.Color := SaveColor; + RenderCanvas.Font.Assign(SaveFont); + SaveFont.Free; + OldFont.Free; + OldPen.Free; + OldBrush.Free; + end; + end; +end; + +procedure TVpDayViewPainter.DrawIcons(AIconRect: TRect); +var + DrawPos: Integer; + + procedure DrawIcon(bmp: TBitmap; w, h: Integer; IncDrawPos: Boolean = false); + begin + if (bmp.Width <> 0) and (bmp.Height <> 0) then + begin + FRenderCanvas.CopyRect( // wp: was FDayview.Canvas -- does not look correct... + Rect(AIconRect.Left + 1, AIconRect.Top +1, AIconRect.Left + w + 1, AIconRect.Top + h + 1), + bmp.Canvas, + Rect(0, 0, bmp.Width, bmp.Height) + ); + if IncDrawPos then + inc(DrawPos, w); + end; + end; + +begin + DrawPos := 1; + DrawIcon(dvBmpCustom, CustomW, CustomH); + DrawIcon(dvBmpCategory, CategoryW, CategoryH); + DrawIcon(dvBmpAlarm, AlarmW, AlarmH); + DrawIcon(dvBmpRecurring, RecurringW, RecurringH, false); +end; + +procedure TVpDayViewPainter.DrawRowHeader(R: TRect); +var + Temp , I: Integer; + LineRect: TRect; + LastHour, Hour: Integer; + MinuteStr, HourStr: string; + SaveFont: TFont; +begin + if StartLine < 0 then + StartLine := FDayView.TopLine; + + SaveFont := TFont.Create; + try + RenderCanvas.Pen.Style := psClear; + RenderCanvas.Brush.Color := RealRowHeadAttrColor; + TPSFillRect(RenderCanvas, Angle, RenderIn, R); + RenderCanvas.Pen.Style := psSolid; + + RenderCanvas.Font.Assign(FDayView.RowHeadAttributes.MinuteFont); + RealVisibleLines := TVpDayViewOpener(FDayView).dvCalcVisibleLines( + R.Bottom - R.Top, + RealColHeadHeight, + RealRowHeight, + Scale, + StartLine, + StopLine + ); + Temp := RenderCanvas.TextWidth('33'); + Temp := Temp + 10; + RenderCanvas.Pen.Style := psSolid; + RenderCanvas.Pen.Color := RealLineColor; + LineRect := Rect(R.Left, R.Top, R.Right, R.Top + RealRowHeight); + Hour := Ord(dvLineMatrix[0, StartLine].Hour); + + for I := 0 to RealVisibleLines do begin + { prevent any extranneous drawing below the last hour } + if (I + FDayView.TopLine >= FDayView.LineCount) or (Hour > 23) then + Break; + + if I = 0 then begin + if Hour < 12 then + MinuteStr := 'am' + else + MinuteStr := 'pm'; + end + else if Ord(Hour) = 12 then + MinuteStr := 'pm' + else + MinuteStr := '00'; + + if FDayView.TimeFormat = tf24Hour then + MinuteStr := '00'; + + { Position the rect } + LineRect.Top := R.Top + i * RealRowHeight; + LineRect.Bottom := LineRect.Top + RealRowHeight; + + if (Hour > 12) and (FDayView.TimeFormat = tf12Hour) then + HourStr := IntToStr(Hour - 12) + else begin + HourStr := IntToStr(Hour); + if (FDayView.TimeFormat = tf12Hour) and (HourStr = '0') then + HourStr := '12'; + end; + + if UseGran = gr60Min then begin + { Paint time } + RenderCanvas.Font.Assign(FDayView.RowHeadAttributes.MinuteFont); + TPSTextOut(RenderCanvas, Angle, RenderIn, + LineRect.Right - RenderCanvas.TextWidth(HourStr + ':' + MinuteStr) - 7, + LineRect.Top + TextMargin, + HourStr + ':' + MinuteStr + ); + LastHour := Hour; + Inc(Hour); + end else begin + { Paint Minute Text} + if dvLineMatrix[0, StartLine + i].Minute = 0 then begin + RenderCanvas.Font.Assign(FDayView.RowHeadAttributes.MinuteFont); + TPSTextOut(RenderCanvas, Angle, RenderIn, + LineRect.Right - RenderCanvas.TextWidth(MinuteStr) - 7, + LineRect.Top + TextMargin, + MinuteStr + ); + { Paint Hour Text } + RenderCanvas.Font.Assign(FDayView.RowHeadAttributes.HourFont); + TPSTextOut(RenderCanvas, Angle, RenderIn, + LineRect.Right - RenderCanvas.TextWidth(HourStr) - 2 - Temp, + LineRect.Top + TextMargin - 2, + HourStr + ); + end; + LastHour := Hour; + Hour := Ord(dvLineMatrix[0, StartLine + i + 1].Hour); + end; + + TPSMoveTo(RenderCanvas, Angle, RenderIn, LineRect.Right-6, LineRect.Bottom); + if LastHour <> Hour then + TPSLineTo(RenderCanvas, Angle, RenderIn, LineRect.Left + 6, LineRect.Bottom) + else + TPSLineTo(RenderCanvas, Angle, RenderIn, LineRect.Right-Temp, LineRect.Bottom); + end; {for} + + { Draw Row Header Borders } + if FDayView.DrawingStyle = dsFlat then begin + DrawBevelRect(RenderCanvas, TPSRotateRectangle (Angle, RenderIn, + Rect(R.Left - 1, R.Top, R.Right - 1, R.Bottom - 2)), + BevelHighlight, + BevelShadow + ); + end + else if FDayView.DrawingStyle = ds3d then begin + DrawBevelRect(RenderCanvas, + TPSRotateRectangle (Angle, RenderIn, Rect(R.Left + 1, R.Top, R.Right - 1, R.Bottom - 3)), + BevelHighlight, + BevelDarkShadow + ); + end; + + RenderCanvas.Font.Assign(SaveFont); + + finally + SaveFont.Free; + end; +end; + +procedure TVpDayViewPainter.FreeBitmaps; +begin + dvBmpRecurring.Free; + dvBmpCategory.Free; + dvBmpAlarm.Free; + dvBmpCustom.Free; +end; + +procedure TVpDayViewPainter.GetIcons(Event: TVpEvent); +var + ShowAlarm: Boolean; + ShowRecurring: Boolean; + ShowCategory: Boolean; + ShowCustom: Boolean; + Icons: TVpDVIcons; + cat: TVpCategoryInfo; + w, h: Integer; +begin + ShowAlarm := False; + ShowRecurring := False; + ShowCategory := False; + ShowCustom := False; + + if Event.AlarmSet then begin + dvBmpAlarm.Assign(FDayView.IconAttributes.AlarmBitmap); + ShowAlarm := (dvBmpAlarm.Width <> 0) and (dvBmpAlarm.Height <> 0); + end; + + if Event.RepeatCode <> rtNone then begin + dvBmpRecurring.Assign (FDayView.IconAttributes.RecurringBitmap); + ShowRecurring := (dvBmpRecurring.Width <> 0) and (dvBmpRecurring.Height <> 0); + end; + + if Assigned(FDayView.DataStore) then begin + if Event.Category < 10 then begin + cat := FDayView.Datastore.CategoryColorMap.GetCategory(Event.Category); + w := cat.Bitmap.Width; + h := cat.Bitmap.Height; + dvBmpCategory.Width := w; + dvBmpCategory.Height := h; + dvBmpCategory.Canvas.CopyRect( + Rect(0, 0, w, h), + cat.Bitmap.Canvas, + Rect(0, 0, w, h) + ); + end else + begin + dvBmpCategory.Width := 0; + dvBmpCategory.Height := 0; + end; + ShowCategory := (dvBmpCategory.Width <> 0) and (dvBmpCategory.Height <> 0); + end; + + dvBmpCustom.Width := 0; + dvBmpCustom.Height := 0; + + if not FDayView.IconAttributes.ShowAlarmBitmap then + ShowAlarm := False; + if not FDayView.IconAttributes.ShowCategoryBitmap then + ShowCategory := False; + if not FDayView.IconAttributes.ShowRecurringBitmap then + ShowRecurring := False; + + if Assigned(FDayView.OnDrawIcons) then begin + Icons[itAlarm].Show := ShowAlarm; + Icons[itAlarm].Bitmap := dvBmpAlarm; + Icons[itRecurring].Show := ShowRecurring; + Icons[itRecurring].Bitmap := dvBmpRecurring; + Icons[itCategory].Show := ShowCategory; + Icons[itCategory].Bitmap := dvBmpCategory; + Icons[itCustom].Show := ShowCustom; + Icons[itCustom].Bitmap := dvBmpCustom; + + FDayView.OnDrawIcons (Self, Event, Icons); + + ShowAlarm := Icons[itAlarm].Show; + ShowRecurring := Icons[itRecurring].Show; + ShowCategory := Icons[itCategory].Show; + ShowCustom := Icons[itCustom].Show; + end; + + if not ShowAlarm then begin + dvBmpAlarm.Width := 0; + dvBmpAlarm.Height := 0; + end; + + if not ShowRecurring then begin + dvBmpRecurring.Width := 0; + dvBmpRecurring.Height := 0; + end; + + if not ShowCategory then begin + dvBmpCategory.Width := 0; + dvBmpCategory.Height := 0; + end; + + if not ShowCustom then begin + dvBmpCustom.Width := 0; + dvBmpCustom.Height := 0; + end; + + AlarmW := dvBmpAlarm.Width; + RecurringW := dvBmpRecurring.Width; + CategoryW := dvBmpCategory.Width; + CustomW := dvBmpCustom.Width; + AlarmH := dvBmpAlarm.Height; + RecurringH := dvBmpRecurring.Height; + CategoryH := dvBmpCategory.Height; + CustomH := dvBmpCustom.Height; +end; + +procedure TVpDayViewPainter.InitializeEventRectangles; +var + I : Integer; +begin + EventCount := 0; + for I := 0 to pred(Length(dvEventArray)) do begin + dvEventArray[I].Rec.Left := -1; + dvEventArray[I].Rec.Top := -1; + dvEventArray[I].Rec.Right := -1; + dvEventArray[I].Rec.Bottom := -1; + dvEventArray[I].Event := nil; + end; +end; + +procedure TVpDayviewPainter.RenderToCanvas(ARenderIn: TRect; + AAngle: TVpRotationAngle; AScale: Extended; ARenderDate: TDateTime; + AStartLine, AStopLine: Integer; AUseGran: TVpGranularity; ADisplayOnly: Boolean); +begin + // Buffer parameters + FRenderIn := ARenderIn; + FAngle := AAngle; + FScale := AScale; + FRenderDate := ARenderDate; + FStartLine := AStartLine; + FStopLine := AStopLine; + FUseGran := AUseGran; + FDisplayOnly := ADisplayOnly; + + // Here begins the original routine... + if DisplayOnly then begin + BevelShadow := clBlack; + BevelHighlight := clBlack; + BevelDarkShadow := clBlack; + BevelFace := clBlack; + WindowColor := clWhite; + HighlightText := clBlack; + RealHeadAttrColor := clSilver; + RealRowHeadAttrColor := clSilver; + RealLineColor := clBlack; + RealColor := clWhite; + HighlightBkg := clWhite; + RealADEventBkgColor := clWhite; + ADEventAttrBkgColor := clWhite; + ADEventBorderColor := clBlack; + end else begin + BevelShadow := clBtnShadow; + BevelHighlight := clBtnHighlight; + BevelDarkShadow := cl3DDkShadow; + BevelFace := clBtnFace; + WindowColor := clWindow; + HighlightText := clHighlightText; + HighlightBkg := clHighlight; + RealHeadAttrColor := FDayView.HeadAttributes.Color; + RealRowHeadAttrColor := FDayView.RowHeadAttributes.Color; + RealLineColor := FDayView.LineColor; + RealColor := FDayView.Color; + RealADEventBkgColor := FDayView.AllDayEventAttributes.BackgroundColor; + ADEventAttrBkgColor := FDayView.AllDayEventAttributes.EventBackgroundColor; + ADEventBorderColor := FDayView.AllDayEventAttributes.EventBorderColor; + end; + + SetMeasurements; + + if StartLine < 0 then + StartLine := FDayView.TopLine; + + if DisplayOnly then + ScrollBarOffset := 2 + else + ScrollBarOffset := 14; + +// dvPainting := true; -- moved to TVpDayView + SavePenStyle := RenderCanvas.Pen.Style; + SaveBrushColor := RenderCanvas.Brush.Color; + SavePenColor := RenderCanvas.Pen.Color; + + Rgn := CreateRectRgn(RenderIn.Left, RenderIn.Top, RenderIn.Right, RenderIn.Bottom); + try + SelectClipRgn(RenderCanvas.Handle, Rgn); + + { Calculate Row Header } + RealRowHeight := TVpDayViewOpener(FDayView).dvCalcRowHeight(Scale, UseGran); + RealColHeadHeight := TVpDayViewOpener(FDayView).dvCalcColHeadHeight(Scale); + + RenderCanvas.Font.Assign(FDayView.RowHeadAttributes.HourFont); + TextWidth := RenderCanvas.TextWidth('33'); + RealRowHeadWidth := TextWidth * 2 + 10; + + { initialize the All Day Events area... } + ADEventsRect.Left := RealLeft + 3 + RealRowHeadWidth; + ADEventsRect.Top := RealTop + RealColHeadHeight; + ADEventsRect.Right := FDayView.ClientRect.Right; + ADEventsRect.Bottom := AdEventsRect.Top; + + { Calculate the RealNumDays (The number of days the control covers) } + RealNumDays := TVpDayViewOpener(FDayView).GetRealNumDays(RenderDate); + + InitializeEventRectangles; + + { Draw the All Day Events } + DrawAllDayEvents; + + { draw the area in the top left corner, where the nav buttons go. } + RowHeadRect := Rect( + RealLeft + 1, + RealTop, + RealLeft + 3 + RealRowHeadWidth, + RealTop + RealColHeadHeight + 2 + ); + + RenderCanvas.Brush.Color := RealHeadAttrColor; + TPSFillRect(RenderCanvas, Angle, RenderIn, RowHeadRect); + + if FDayView.DrawingStyle = ds3d then + DrawBevelRect( + RenderCanvas, + TPSRotateRectangle(Angle, RenderIn, Rect( + RowHeadRect.Left + 1, + RowHeadRect.Top + 2, + RowHeadRect.Right - 2, + RowHeadRect.Bottom - 2 + )), + BevelHighlight, + BevelShadow + ) + else begin + RenderCanvas.Pen.Color := BevelShadow; + TPSMoveTo(RenderCanvas, Angle, RenderIn, RowHeadRect.Right - 2, RowHeadRect.Bottom - 2); + TPSLineTo(RenderCanvas, Angle, RenderIn, RowHeadRect.Left, RowHeadRect.Bottom - 2); + RenderCanvas.Pen.Color := BevelHighlight; + TPSLineTo(RenderCanvas, Angle, RenderIn, RowHeadRect.Left, RowHeadRect.Top); + TPSLineTo(RenderCanvas, Angle, RenderIn, RowHeadRect.Right - 2, RowHeadRect.Top); + RenderCanvas.Pen.Color := BevelShadow; + TPSMoveTo(RenderCanvas, Angle, RenderIn, RowHeadRect.Right - 2, RowHeadRect.Top + 6); + TPSLineTo(RenderCanvas, Angle, RenderIn, RowHeadRect.Right - 2, RowHeadRect.Bottom - 5); + end; + + RenderCanvas.Font.Assign(FDayView.RowHeadAttributes.HourFont); + if FDayView.DrawingStyle = dsFlat then + RowHeadRect := Rect(RealLeft + 2, ADEventsRect.Bottom + 1, RealLeft + 2 + RealRowHeadWidth, RealBottom) + else + RowHeadRect := Rect(RealLeft + 1, ADEventsRect.Bottom + 1, RealLeft + 2 + RealRowHeadWidth, RealBottom); + + if Assigned(FDayView.OwnerDrawRowHeader) then begin + Drawn := false; + FDayView.OwnerDrawRowHeader(self, RenderCanvas, RowHeadRect, RealRowHeight, Drawn); + if not Drawn then + DrawRowHeader(RowHeadRect); + end else + DrawRowHeader(RowHeadRect); + + { Draw the regular events } + DrawAllDays; + + { Draw Borders } + if FDayView.DrawingStyle = dsFlat then begin + { Draw an outer and inner bevel } + DrawBevelRect( + RenderCanvas, + TPSRotateRectangle(Angle, RenderIn, Rect(RealLeft, RealTop, RealRight - 1, RealBottom - 1)), + BevelShadow, + BevelHighlight + ); + DrawBevelRect( + RenderCanvas, + TPSRotateRectangle(Angle, RenderIn, Rect(RealLeft + 1, RealTop + 1, RealRight - 2, RealBottom - 2)), + BevelHighlight, + BevelShadow + ); + end else + if FDayView.DrawingStyle = ds3d then begin + { Draw a 3d bevel } + DrawBevelRect( + RenderCanvas, + TPSRotateRectangle(Angle, RenderIn, Rect(RealLeft, RealTop, RealRight - 1, RealBottom - 1)), + BevelShadow, + BevelHighlight + ); + DrawBevelRect( + RenderCanvas, + TPSRotateRectangle(Angle, RenderIn, Rect(RealLeft + 1, RealTop + 1, RealRight - 2, RealBottom - 2)), + BevelDarkShadow, + BevelFace + ); + end; + + { Place navigation buttons } + { size and place the Today button first. } + with TVpDayViewOpener(FDayView) do begin + dvTodayBtn.Height := trunc(RealColHeadHeight div 2); + if DrawingStyle = dsFlat then begin + dvTodayBtn.Left := 1; + dvTodayBtn.Top := 1; + dvTodayBtn.Width := RealRowHeadWidth + 1; + end else begin + dvTodayBtn.Left := 2; + dvTodayBtn.Top := 2; + dvTodayBtn.Width := RealRowHeadWidth; + end; + { size and place the WeekDown button } + dvWeekDownBtn.Height := dvTodayBtn.Height; + dvWeekDownBtn.Width := trunc(RealRowHeadWidth * 0.25) + 2; + dvWeekDownBtn.Left := dvTodayBtn.Left; + dvWeekDownBtn.Top := dvTodayBtn.Top + dvTodayBtn.Height; + { size and place the DayDown button } + dvDayDownBtn.Height := dvTodayBtn.Height; + dvDayDownBtn.Width := dvWeekDownBtn.Width - 4; + dvDayDownBtn.Left := dvWeekDownBtn.Left + dvWeekDownBtn.Width; + dvDayDownBtn.Top := dvTodayBtn.Top + dvTodayBtn.Height; + { size and place the DayUp button } + dvDayUpBtn.Height := dvTodayBtn.Height; + dvDayUpBtn.Width := dvWeekDownBtn.Width - 4; + dvDayUpBtn.Left := dvDayDownBtn.Left + dvDayDownBtn.Width; + dvDayUpBtn.Top := dvTodayBtn.Top + dvTodayBtn.Height; + { size and place the WeekUp button } + dvWeekUpBtn.Height := dvTodayBtn.Height; + dvWeekUpBtn.Width := dvTodayBtn.Width - dvWeekDownBtn.Width - dvDayDownBtn.Width - dvDayUpBtn.Width; + dvWeekUpBtn.Left := dvDayUpBtn.Left + dvDayUpBtn.Width; + dvWeekUpBtn.Top := dvTodayBtn.Top + dvTodayBtn.Height; + end; + + { Reinstate RenderCanvas settings } + RenderCanvas.Pen.Style := SavePenStyle; + RenderCanvas.Brush.Color := SaveBrushColor; + RenderCanvas.Pen.Color := SavePenColor; + + finally + SelectClipRgn(RenderCanvas.Handle, 0); + DeleteObject(Rgn); + end; +// dvPainting := false; -- moved to TVpDayView +end; + +procedure TVpDayViewPainter.ScaleIcons(EventRect: TRect); +var + h: Integer; +begin + h := EventRect.Bottom - EventRect.Top - 2; + + if (dvBmpAlarm.Height > h) and (dvBmpAlarm.Height * dvBmpAlarm.Width <> 0) + then begin + AlarmW := Trunc((h / dvBmpAlarm.Height) * dvBmpAlarm.Width); + AlarmH := h; + end; + + if (dvBmpRecurring.Height > h) and (dvBmpRecurring.Height * dvBmpRecurring.Width <> 0) + then begin + RecurringW := Trunc((h / dvBmpRecurring.Height) * dvBmpRecurring.Width); + RecurringH := h; + end; + + if (dvBmpCategory.Height > h) and (dvBmpCategory.Height * dvBmpCategory.Width <> 0) + then begin + CategoryW := Trunc((h / dvBmpCategory.Height) * dvBmpCategory.Width); + CategoryH := h; + end; + + if (dvBmpCustom.Height > h) and (dvBmpCustom.Height * dvBmpCustom.Width <> 0) + then begin + CustomW := Trunc((h / dvBmpCustom.Height) * dvBmpCustom.Width); + CustomH := h; + end; +end; + +procedure TVpDayViewPainter.SetMeasurements; +begin + RealWidth := TPSViewportWidth(Angle, RenderIn); + RealHeight := TPSViewportHeight(Angle, RenderIn); + RealLeft := TPSViewportLeft(Angle, RenderIn); + RealRight := TPSViewportRight(Angle, RenderIn); + RealTop := TPSViewportTop(Angle, RenderIn); + RealBottom := TPSViewportBottom(Angle, RenderIn); + TVpDayViewOpener(FDayView).dvCalcColHeadHeight(Scale); +end; + + +end.