{*********************************************************} {* VPCALENDAR.PAS 1.03 *} {*********************************************************} {* ***** BEGIN LICENSE BLOCK ***** *} {* Version: MPL 1.1 *} {* *} {* The contents of this file are subject to the Mozilla Public License *} {* Version 1.1 (the "License"); you may not use this file except in *} {* compliance with the License. You may obtain a copy of the License at *} {* http://www.mozilla.org/MPL/ *} {* *} {* Software distributed under the License is distributed on an "AS IS" basis, *} {* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *} {* for the specific language governing rights and limitations under the *} {* License. *} {* *} {* The Original Code is TurboPower Visual PlanIt *} {* *} {* The Initial Developer of the Original Code is TurboPower Software *} {* *} {* Portions created by TurboPower Software Inc. are Copyright (C) 2002 *} {* TurboPower Software Inc. All Rights Reserved. *} {* *} {* Contributor(s): *} {* *} {* ***** END LICENSE BLOCK ***** *} unit VpCalendar; { Calendar component } {$IF FPC_FullVersion >= 30200} {$WARN 6058 off : Call to subroutine "$1" marked as inline is not inlined} {$IFEND} {$I vp.inc} interface uses {$IFDEF LCL} LMessages, LCLProc, LCLType, LCLIntf, FileUtil, {$ELSE} Windows, Messages, {$ENDIF} SysUtils, Types, Buttons, Classes, Controls, Forms, Graphics, Menus, VpConst, VpBase, VpSR, VpMisc, VpBaseDS, VpException; type TVpCalDisplayOption = (cdoShortNames, cdoShowYear, cdoShowInactive, cdoShowRevert, cdoShowToday, cdoShowNavBtns, cdoHideActive, cdoHighlightSat, cdoHighlightSun, cdoHighlightHolidays); TVpCalDisplayOptions = set of TVpCalDisplayOption; TVpCalColorArray = array[0..10] of TColor; TVpCalColorScheme = (cscalCustom, cscalClassic, cscalWindows, cscalGold, cscalOcean, cscalRose); TVpCalSchemeArray = array[TVpCalColorScheme] of TVpCalColorArray; TRowArray = array[0..8] of Integer; TColArray = array[0..6] of Integer; const {ActiveDay, DayNames, Days, InactiveDays, MonthAndYear, Weekend, EventDays, ActiveDayBorder, ActiveDayText} CalScheme : TVpCalSchemeArray = ( // Active BG DayNames Days Inact.Days Month/Year Weekend Event Background Active border Active text Holidays (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), (clWindow, clWindowText, clWindowText, clSilver, clWindowText, clRed, clWindowText, clWindow, clWindowText, clWindowText, clRed), // classic (clBlue, clMaroon, clBlack, clMedGray, clBlue, clRed, clBlack, clDefault, clBlack, clWhite, clRed), // windows (clMaroon, clBlack, clYellow, clSilver, clBlack, $7777FF, clWhite, clOlive, clBlack, clYellow, $7777FF), // gold (clBlue, clSilver, clAqua, clBlue, clSilver, clRed, clWhite, clNavy, clNavy, clWhite, clRed), // ocean ($007500EA, clBlack, clFuchsia, clMedGray, clBlack, clRed, clMaroon, $00D9B3FF, clMaroon, clWhite, clRed) // rose ); calDefWeekStarts = dtSunday; { default start of the week } type TVpCalColors = class(TPersistent) private FUpdating: Boolean; FOnChange: TNotifyEvent; SettingScheme: Boolean; function GetColor(Index: Integer): TColor; procedure SetColor(Index: Integer; Value: TColor); procedure SetColorScheme(Value: TVpCalColorScheme); protected procedure DoOnChange; public FCalColors: TVpCalColorArray; FColorScheme: TVpCalColorScheme; procedure Assign(Source: TPersistent); override; procedure BeginUpdate; procedure EndUpdate; property OnChange: TNotifyEvent read FOnChange write FOnChange; published property ActiveDay: TColor index 0 read GetColor write SetColor; property ActiveDayBorder: TColor index 8 read GetColor write SetColor; property ActiveDayText: TColor index 9 read GetColor write SetColor; property Background: TColor index 7 read GetColor write SetColor; property ColorScheme: TVpCalColorScheme read FColorScheme write SetColorScheme; property DayNames: TColor index 1 read GetColor write SetColor; property Days: TColor index 2 read GetColor write SetColor; property InactiveDays: TColor index 3 read GetColor write SetColor; property MonthAndYear: TColor index 4 read GetColor write SetColor; property Weekend: TColor index 5 read GetColor write SetColor; property EventDays: TColor index 6 read GetColor write SetColor; property Holidays: TColor index 10 read GetColor write SetColor; end; type TDateChangeEvent = procedure(Sender: TObject; Date: TDateTime) of object; TCalendarDateEvent = procedure(Sender: TObject; ADate: TDateTime; const Rect: TRect) of object; TGetHighlightEvent = procedure(Sender: TObject; ADate: TDateTime; var Color: TColor) of object; TGetDateEnabledEvent = procedure(Sender: TObject; ADate: TDateTime; var Enabled: Boolean) of object; TVpCustomCalendar = class(TVpLinkableControl) private FDefaultPopup : TPopupMenu; FExternalPopup: TPopupMenu; protected {private} {$IFNDEF LCL} FBorderStyle : TBorderStyle; {$ENDIF} FBrowsing : Boolean; FColors : TVpCalColors; FOptions : TVpCalDisplayOptions; FDate : TDateTime; FDay : Integer; {calendar day} FDateFormat : TVpDateFormat; FDayNameWidth : TVpDayNameWidth; FDrawHeader : Boolean; {true to draw day name header} FMonth : Integer; {calendar month} FReadOnly : Boolean; {true if in read only mode} FWantDblClicks : Boolean; {true to include cs_dblclks style} FWeekStarts : TVpDayType; {the day that begins the week} FYear : Integer; {calendar year} FLastRenderX : Integer; FLastRenderY : Integer; {event variables} FOnChange : TDateChangeEvent; FOnDrawDate : TCalendarDateEvent; FOnDrawItem : TCalendarDateEvent; FOnGetDateEnabled: TGetDateEnabledEvent; FOnGetHighlight : TGetHighlightEvent; FOnHoliday : TVpHolidayEvent; {internal variables} clInLinkHandler : Boolean; clBtnLeft : TSpeedButton; clBtnRevert : TSpeedButton; clBtnRight : TSpeedButton; clBtnToday : TSpeedButton; clInPopup : Boolean; clBtnNextYear : TSpeedButton; clBtnPrevYear : TSpeedButton; clCalendar : array[1..49] of Byte; {current month grid} clDay : Word; clFirst : Byte; {index for first day in current month} clLast : Byte; {index for last day in current month} clMonth : Word; clRowCol : array[0..8, 0..6] of TRect; {cell TRect info} cSettingScheme : Boolean; clYear : Word; clWidth : Integer; {client width - margins} clMask : array[0..MaxDateLen] of AnsiChar; {default date mask} clPopup : Boolean; {true if being created as a popup} clRevertDate : TDateTime; {date on entry} clRowCount : Integer; {7 if no header, otherwise 8} clStartRow : Integer; {first row number} calMargin : Integer; {property methods} function GetDay: Integer; function GetMonth: Integer; function GetYear: Integer; {$IFNDEF LCL} procedure SetBorderStyle(Value: TBorderStyle); reintroduce; {$ENDIF} procedure SetColor(Value: TColor); override; procedure SetDate(Value: TDateTime); procedure SetDateFormat(Value: TVpDateFormat); procedure SetDayNameWidth(Value: TVpDayNameWidth); procedure SetDisplayOptions(Value: TVpCalDisplayOptions); procedure SetDrawHeader(Value: Boolean); procedure SetWantDblClicks(Value: Boolean); procedure SetWeekStarts(Value: TVpDayType); { Popup menu } function GetPopupMenu: TPopupMenu; override; procedure InitializeDefaultPopup; procedure SetPopupMenu(AValue: TPopupMenu); procedure PopupToday(Sender: TObject); procedure PopupNextMonth(Sender: TObject); procedure PopupPrevMonth(Sender: TObject); procedure PopupNextYear(Sender: TObject); procedure PopupPrevYear(Sender: TObject); {internal methods} procedure calChangeMonth(Sender: TObject); procedure calColorChange(Sender: TObject); function calGetCurrentRectangle: TRect; {-get bounding rectangle for the current calendar day} function calGetValidDate(ADate: TDateTime; Delta: Integer): TDateTime; procedure calRebuildCalArray(ADate: TDateTime); {-recalculate the contents of the calendar array} procedure CalculateSizes(WorkCanvas: TCanvas; Angle: TVpRotationAngle; Rect: TRect; out Row: TRowArray; out Col: TColArray; DisplayOnly: Boolean); procedure calRecalcSize (DisplayOnly: Boolean); {-calcualte new sizes for rows and columns} class function GetControlClassDefaultSize: TSize; override; procedure Hookup; {VCL control methods} procedure CMEnter(var Msg: {$IFDEF DELPHI}TMessage{$ELSE}TLMessage{$ENDIF}); message CM_ENTER; procedure CMExit(var Msg: {$IFDEF DELPHI}TMessage{$ELSE}TLMessage{$ENDIF}); message CM_EXIT; procedure CMFontChanged(var Msg: {$IFDEF DELPHI}TMessage{$ELSE}TLMessage{$ENDIF}); message CM_FONTCHANGED; {windows message methods} {$IFDEF DELPHI} procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE; procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS; {$ELSE} procedure WMEraseBkgnd(var Msg: TLMEraseBkgnd); message LM_ERASEBKGND; // procedure WMGetDlgCode(var Msg: TLMGetDlgCode); message LM_GETDLGCODE; procedure WMKillFocus(var Msg: TLMKillFocus); message LM_KILLFOCUS; {$ENDIF} procedure calBtnClick(Sender: TObject); procedure CreateParams(var Params: TCreateParams); override; procedure CreateWnd; override; procedure DoOnChange(Value: TDateTime); dynamic; function DoOnGetDateEnabled(ADate: TDateTime): Boolean; dynamic; {$IFDEF LCL} function DoMouseWheel(Shift: TShiftState; Delta: Integer; MousePos: TPoint): Boolean; override; {$ELSE} procedure DoOnMouseWheel(Shift: TShiftState; Delta, XPos, YPos: SmallInt); override; {$ENDIF} function IsReadOnly: Boolean; dynamic; {-return true if the calendar is in read-only mode} procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyPress(var Key: Char); override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure Paint; override; public constructor Create(AOwner: TComponent); override; constructor CreateEx(AOwner: TComponent; AsPopup: Boolean); virtual; destructor Destroy; override; procedure LoadLanguage; procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override; function GetControlType: TVpItemType; override; procedure IncDay(Delta: Integer); procedure IncMonth(Delta: Integer); procedure IncYear(Delta: Integer); function IsHoliday(ADate: TDate; out AHolidayName: String): Boolean; procedure PaintToCanvas(ACanvas: TCanvas; ARect: TRect; Angle: TVpRotationAngle; ADate: TDateTime); procedure RenderToCanvas(RenderCanvas: TCanvas; RenderIn: TRect; Angle: TVpRotationAngle; Scale: Extended; RenderDate: TDateTime; StartLine: Integer; StopLine: Integer; UseGran: TVpGranularity; DisplayOnly: Boolean); override; procedure SetToday; { LinkHandler is the method which is called by the ControlLink component, } { it is used to synchronize the calendar's date with other Visual PlanIt } { controls do not call the LinkHandler procedure programatically. } procedure LinkHandler(Sender: TComponent; NotificationType: TVpNotificationType; const Value: Variant); override; property Browsing : Boolean read FBrowsing; property Canvas; property CurrentRectangle: TRect read calGetCurrentRectangle; property Day: Integer read GetDay; property Month: Integer read GetMonth; property Year: Integer read GetYear; {properties} property Align; property Anchors; {$IFDEF LCL} property BorderSpacing; {$ENDIF} property BorderStyle default bsNone; //: TBorderStyle read FBorderStyle write SetBorderStyle default bsNone; property Color; property Colors: TVpCalColors read FColors write FColors; property Date: TDateTime read FDate write SetDate; property DateFormat: TVpDateFormat read FDateFormat write SetDateFormat default dfLong; property DayNameWidth: TVpDayNameWidth read FDayNameWidth write SetDayNameWidth default 3; property Options: TVpCalDisplayOptions read FOptions write SetDisplayOptions default [cdoHighlightSat, cdoHighlightSun, cdoShortNames, cdoShowNavBtns, cdoShowRevert, cdoShowToday, cdoShowYear]; property ReadOnly: Boolean read FReadOnly write FReadOnly default false; property WantDblClicks: Boolean read FWantDblClicks write SetWantDblClicks default true; property WeekStarts: TVpDayType read FWeekStarts write SetWeekStarts default dtSunday; {events} property OnChange: TDateChangeEvent read FOnChange write FOnChange; property OnDrawDate: TCalendarDateEvent read FOnDrawDate write FOnDrawDate; property OnDrawItem: TCalendarDateEvent read FOnDrawItem write FOnDrawItem; property OnGetDateEnabled: TGetDateEnabledEvent read FOnGetDateEnabled write FOnGetDateEnabled; property OnGetHighlight: TGetHighlightEvent read FOnGetHighlight write FOnGetHighlight; property OnHoliday: TVpHolidayEvent read FOnHoliday write FOnHoliday; end; TVpCalendar = class(TVpCustomCalendar) published {properties} {$IFDEF VERSION4} property Anchors; property Constraints; property DragKind; {$ENDIF} property Align; {$IFDEF LCL} property BorderSpacing; {$ENDIF} property BorderStyle; property Color; property Colors; property Cursor; property DateFormat; property DayNameWidth; property DragCursor; property DragMode; property Enabled; property Font; property Options; property ParentFont; property ParentShowHint; property PopupMenu; property ReadOnly; property ShowHint; property TabOrder; property TabStop; property Visible; property WantDblClicks; property WeekStarts; {events} property AfterEnter; property AfterExit; property OnChange; property OnClick; property OnDblClick; property OnDragDrop; property OnDragOver; property OnDrawDate; property OnDrawItem; property OnEndDrag; property OnEnter; property OnExit; property OnGetDateEnabled; property OnGetHighlight; property OnHoliday; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnStartDrag; end; implementation uses {$IFDEF LCL} DateUtils, {$ENDIF} VpCalendarPainter; const CAL_MARGIN = 4; {left, right, and top margin} function SumOf(const A: array of Integer; First, Last: Integer): Integer; var I : Integer; begin Result := 0; for I := First to Last do Result := Result + A[I]; end; {*** TVpCalColors ***} procedure TVpCalColors.Assign(Source: TPersistent); begin if Source is TVpCalColors then begin FCalColors := TVpCalColors(Source).FCalColors; FColorScheme := TVpCalColors(Source).FColorScheme; FOnChange := TVpCalColors(Source).FOnChange; end else inherited Assign(Source); end; procedure TVpCalColors.BeginUpdate; begin FUpdating := True; end; procedure TVpCalColors.EndUpdate; begin FUpdating := False; DoOnChange; end; procedure TVpCalColors.DoOnChange; begin if not FUpdating and Assigned(FOnChange) then FOnChange(Self); if not SettingScheme then FColorScheme := cscalCustom; end; function TVpCalColors.GetColor(Index: Integer) : TColor; begin Result := FCalColors[Index]; end; procedure TVpCalColors.SetColor(Index: Integer; Value: TColor); begin if Value <> FCalColors[Index] then begin FCalColors[Index] := Value; DoOnChange; end; end; procedure TVpCalColors.SetColorScheme(Value: TVpCalColorScheme); begin if Value <> FColorScheme then begin SettingScheme := True; try FColorScheme := Value; if Value <> cscalCustom then begin FCalColors := CalScheme[Value]; DoOnChange; end; finally SettingScheme := False; end; end; end; (******************************************************************************) { TVpCustomCalendar } (******************************************************************************) constructor TVpCustomCalendar.Create(AOwner: TComponent); begin inherited Create(AOwner); {$IFDEF LCL} ControlStyle := ControlStyle + [csClickEvents] - [csCaptureMouse]; {$ELSE} ControlStyle := ControlStyle + [csClickEvents, csFramed] - [csCaptureMouse]; {$ENDIF} // Height := 140; TabStop := True; // Width := 200; calMargin := ScaleX(CAL_MARGIN, DesignTimeDPI); {$IFNDEF LCL} Font.Name := 'MS Sans Serif'; Font.Size := 8; {$ENDIF} BorderStyle := bsNone; FDayNameWidth := 3; FDateFormat := dfLong; FOptions := [cdoShortNames, cdoShowYear, cdoShowRevert, cdoShowToday, cdoShowNavBtns, cdoHighlightSun, cdoHighlightSat]; FWantDblClicks := True; FWeekStarts := dtSunday; FLastRenderX := 0; FLastRenderY := 0; clInLinkHandler := false; {create navigation buttons} clBtnLeft := TSpeedButton.Create(Self); clBtnLeft.Parent := Self; {$IFDEF NEW_ICONS} LoadGlyphFromRCDATA(clBtnLeft.Glyph, 'VpLArrow', 16, 24, 32); {$ELSE} clBtnLeft.Glyph.LoadFromResourceName(HINSTANCE,'VPLEFTARROW'); //soner geändert: clBtnLeft.Glyph.Handle := LoadBaseBitmap('VPLEFTARROW'); {$ENDIF} clBtnLeft.OnClick := calBtnClick; clBtnLeft.Hint := RSPrevMonth; clBtnLeft.ShowHint := True; clBtnRight := TSpeedButton.Create(Self); clBtnRight.Parent := Self; {$IFDEF NEW_ICONS} LoadGlyphFromRCDATA(clBtnRight.Glyph, 'VpRArrow', 16, 24, 32); {$ELSE} clBtnRight.Glyph.LoadFromResourceName(HINSTANCE,'VPRIGHTARROW'); //soner geändert: clBtnRight.Glyph.Handle := LoadBaseBitmap('VPRIGHTARROW'); {$ENDIF} clBtnRight.OnClick := calBtnClick; clBtnRight.Hint := RSNextMonth; clBtnRight.ShowHint := True; clBtnNextYear := TSpeedButton.Create(Self); clBtnNextYear.Parent := Self; {$IFDEF NEW_ICONS} LoadGlyphFromRCDATA(clBtnNextYear.Glyph, 'VpRArrows', 16, 24, 32); {$ELSE} clBtnNextYear.Glyph.LoadFromResourceName(HINSTANCE,'VPRIGHTARROWS'); //soner geöndert: clBtnNextYear.Glyph.Handle := LoadBaseBitmap('VPRIGHTARROWS'); {$ENDIF} clBtnNextYear.OnClick := calBtnClick; clBtnNextYear.Hint := RSNextYear; clBtnNextYear.ShowHint := True; clBtnPrevYear := TSpeedButton.Create(Self); clBtnPrevYear.Parent := Self; {$IFDEF NEW_ICONS} LoadGlyphFromRCData(clBtnPrevYear.Glyph, 'VpLArrows', 16, 24, 32); {$ELSE} clBtnPrevYear.Glyph.LoadFromResourceName(HINSTANCE,'VPLEFTARROWS'); //soner geöndert: clBtnPrevYear.Glyph.Handle := LoadBaseBitmap('VPLEFTARROWS'); {$ENDIF} clBtnPrevYear.OnClick := calBtnClick; clBtnPrevYear.Hint := RSPrevYear; clBtnPrevYear.ShowHint := True; {create "revert" button} clBtnRevert := TSpeedButton.Create(Self); clBtnRevert.Parent := Self; {$IFDEF NEW_ICONS} LoadGlyphFromRCData(clBtnRevert.Glyph, 'VpRevert', 16, 24, 32); {$ELSE} clBtnRevert.Glyph.LoadFromResourceName(HINSTANCE,'VPREVERT'); //soner geändert: clBtnRevert.Glyph.Handle := LoadBaseBitmap('VPREVERT'); {$ENDIF} clBtnRevert.OnClick := calBtnClick; clBtnRevert.Hint := RSCalendarRevert; clBtnRevert.ShowHint := True; {create "today" button} clBtnToday := TSpeedButton.Create(Self); clBtnToday.Parent := Self; {$IFDEF NEW_ICONS} LoadGlyphFromRCData(clBtnToday.Glyph, 'VpToday', 16, 24, 32); {$ELSE} clBtnToday.Glyph.LoadFromResourceName(HINSTANCE,'VPTODAY'); //soner geändert: clBtnToday.Glyph.Handle := LoadBaseBitmap('VPTODAY'); {$ENDIF} clBtnToday.OnClick := calBtnClick; clBtnToday.Hint := RSToday; clBtnToday.ShowHint := True; // Assign default color scheme FColors := TVpCalColors.Create; FColors.OnChange := calColorChange; FColors.FCalColors := CalScheme[cscalWindows]; // Assign default international support object FDrawHeader := True; clRowCount := 8; clStartRow := 0; // Popup menu FDefaultPopup := TPopupMenu.Create(Self); FDefaultPopup.Name := 'default'; InitializeDefaultPopup; Self.PopupMenu := FDefaultPopup; // Initial size of the control with GetControlClassDefaultSize do SetInitialBounds(0, 0, CX, CY); Hookup; end; constructor TVpCustomCalendar.CreateEx(AOwner: TComponent; AsPopup: Boolean); begin clPopup := AsPopup; Create(AOwner); end; destructor TVpCustomCalendar.Destroy; begin FColors.Free; FColors := nil; FDefaultPopup.Free; inherited Destroy; end; procedure TVpCustomCalendar.calBtnClick(Sender: TObject); var Key: Word; begin SetFocus; Key := 0; if Sender = clBtnLeft then begin Key := VK_PRIOR; KeyDown(Key, []); end else if Sender = clBtnRevert then begin Key := VK_ESCAPE; KeyDown(Key, []); end else if Sender = clBtnRight then begin Key := VK_NEXT; KeyDown(Key, []); end else if Sender = clBtnToday then begin Key := VK_BACK; KeyDown(Key, [ssAlt]); end else if Sender = clBtnNextYear then begin Key := VK_NEXT; KeyDown(Key, [ssCtrl]); end else if Sender = clBtnPrevYear then begin Key := VK_PRIOR; KeyDown(Key, [ssCtrl]); end; end; procedure TVpCustomCalendar.calChangeMonth(Sender: TObject); var Y, M, D: Word; MO: Integer; MI: TMenuItem; begin MI := (Sender as TMenuItem); DecodeDate(FDate, Y, M, D); MO := MI.Tag; {set month and year} if (MO > M) and (MI.HelpContext < 3) then Dec(Y) else if (MO < M) and (MI.HelpContext > 3) then Inc(Y); M := M + MO; {set day} if D > DaysInAMonth(Y, MO) then D := DaysInAMonth(Y, MO); SetDate(calGetValidDate(EncodeDate(Y, MO, D)-1, +1)); if (Assigned(FOnChange)) then FOnChange(Self, FDate); end; {=====} procedure TVpCustomCalendar.calColorChange(Sender: TObject); begin Invalidate; end; { Get bounding rectangle for the current date} function TVpCustomCalendar.calGetCurrentRectangle: TRect; var Idx : Integer; R, C: Integer; begin // Index into the month grid Idx := clFirst + Pred(clDay) + 13; R := (Idx div 7); C := (Idx mod 7); Result := clRowCol[R,C]; end; function TVpCustomCalendar.calGetValidDate(ADate: TDateTime; Delta: Integer): TDateTime; var I, X: Integer; Valid: Boolean; Fwd: Boolean; begin Valid := false; Fwd := false; X := Delta; I := 1; while not Valid and (I < 1000) do begin {If the date is valid then yay!} if (DoOnGetDateEnabled(ADate + (X * I))) then begin Valid := true; Fwd := True; end {otherwise check the other direction} else if (DoOnGetDateEnabled(ADate - (X * I))) then begin valid := true; end else Inc(I); end; if Valid then if Fwd then Result := ADate + (X * I) else Result := ADate - (X * I) else raise(EVpCalendarError.Create(RSInvalidDate)); end; procedure TVpCustomCalendar.calRebuildCalArray(ADate: TDateTime); var Day1: TVpDayType; I, J: Integer; begin HandleNeeded; DecodeDate(ADate, clYear, clMonth, clDay); {get the first day of the current month and year} Day1 := TVpDayType(SysUtils.DayOfWeek(EncodeDate(clYear, clMonth, 1)) -1); {find its index} I := Byte(Day1) - Byte(WeekStarts) + 1; if I < 1 then Inc(I, 7); clFirst := I; {find the index of the last day in the month} clLast := clFirst + DaysInAMonth(clYear, clMonth) {%H-}- 1; {initialize the first part of the calendar} if clMonth = 1 then J := DaysInAMonth(clYear - 1, 12) else J := DaysInAMonth(clYear, clMonth-1); for I := clFirst-1 downto 1 do begin clCalendar[I] := J; Dec(J); end; {initialize the rest of the calendar} J := 1; for I := clFirst to 49 do begin clCalendar[I] := J; if I = clLast then J := 1 else Inc(J); end; end; procedure TVpCustomCalendar.CalculateSizes(WorkCanvas: TCanvas; Angle: TVpRotationAngle; Rect: TRect; out Row: TRowArray; out Col: TColArray; DisplayOnly: Boolean); {-calcualte new sizes for rows and columns} var R: Integer; C: Integer; D1: Integer; D2: Integer; CH: Integer; RH: Integer; LR: Integer; begin if (Angle = ra90) or (Angle = ra270) then clWidth := Rect.Bottom - Rect.Top - 2*calMargin else clWidth := Rect.Right - Rect.Left - 2*calMargin; {store row and column sizes} for C := 0 to 6 do Col[C] := clWidth div 7; if (FDrawHeader) then begin {button and date row} Row[0] := Round(1.4 * WorkCanvas.TextHeight('Yy')); {day name row} Row[1] := Round(1.5 * WorkCanvas.TextHeight('Yy')) end else begin {button and date row} Row[0] := Round(1.3 * WorkCanvas.TextHeight('Yy')); {day name row} Row[1] := 0; end; if (Angle = ra90) or (Angle = ra270) then CH := Rect.Right - Rect.Left - 2*calMargin - Row[0] - Row[1] else CH := Rect.Bottom - Rect.Top - 2*calMargin - Row[0] - Row[1]; if ((not (cdoShowRevert in Options)) and (not (cdoShowToday in Options))) or DisplayOnly then LR := 7 else LR := 8; RH := CH div (LR - 1); for R := 2 to 8 do Row[R] := RH; {distribute any odd horizontal space equally among the columns} for C := 0 to clWidth mod 7 do Inc(Col[C]); {distribute odd vertical space to top 2 rows} D1 := 0; for R := 0 to LR do D1 := D1 + Row[R]; if (Angle = ra90) or (Angle = ra270) then D1 := Rect.Right - Rect.Left - D1 - 2*calMargin else D1 := Rect.Bottom - Rect.Top - D1 - 2*calMargin; D2 := D1 div 2; D1 := D1 - D2; Row[0] := Row[0] + D1; if (FDrawHeader) then Row[1] := Row[1] + D2; {initialize each cells TRect structure using} {the row heights from the Row[] array and the} {column widths from the Col[] array} for R := clStartRow to 7 do begin for C := 0 to 6 do begin clRowCol[R, C].Left := SumOf(Col, 0, C-1) + calMargin; clRowCol[R, C].Right := SumOf(Col, 0, C) + calMargin; clRowCol[R, C].Top := SumOf(Row, 0, R-1) + calMargin; clRowCol[R, C].Bottom := SumOf(Row, 0, R) + calMargin; end; end; end; { Calculate new sizes for rows and columns } procedure TVpCustomCalendar.calRecalcSize(DisplayOnly: Boolean); var Row: TRowArray; Col: TColArray; begin if not HandleAllocated then Exit; {clear row/col position structure} FillChar(clRowCol, SizeOf(clRowCol), #0); {set the way the buttons should look} clBtnLeft.Flat := {not Ctl3D and} not clPopup; clBtnRevert.Flat := {not Ctl3D and} not clPopup; clBtnRight.Flat := {not Ctl3D and} not clPopup; clBtnToday.Flat := {not Ctl3D and} not clPopup; clBtnNextYear.Flat := {not Ctl3D and} not clPopup; clBtnPrevYear.Flat := {not Ctl3D and} not clPopup; clBtnRevert.Visible := cdoShowRevert in FOptions; clBtnToday.Visible := cdoShowToday in FOptions; clBtnLeft.Visible := (cdoShowNavBtns in FOptions); clBtnRight.Visible := (cdoShowNavBtns in FOptions); clBtnNextYear.Visible := (cdoShowNavBtns in FOptions); clBtnPrevYear.Visible := (cdoShowNavBtns in FOptions); CalculateSizes(Canvas, ra0, Rect (0, 0, Width, Height), Row, Col, DisplayOnly); {position and size the left and right month buttons} {position and size the next and prev year buttons} clBtnNextYear.Height := Row[0] - calMargin; clBtnNextYear.Width := Col[1] - calMargin; if clBtnNextYear.Width < clBtnNextYear.Glyph.Width + 3 then clBtnNextYear.Width := clBtnNextYear.Glyph.Width + 3; clBtnNextYear.Top := calMargin; clBtnNextYear.Left := ClientWidth - calMargin - clBtnNextYear.Width; clBtnPrevYear.Height := Row[0] - calMargin; clBtnPrevYear.Width := Col[5] - calMargin; if clBtnPrevYear.Width < clBtnPrevYear.Glyph.Width + 3 then clBtnPrevYear.Width := clBtnPrevYear.Glyph.Width + 3; clBtnPrevYear.Top := calMargin; clBtnPrevYear.Left := calMargin; clBtnLeft.Height := Row[0] - calMargin; clBtnLeft.Width := Col[0] - calMargin; if clBtnLeft.Width < clBtnLeft.Glyph.Width + 3 then clBtnLeft.Width := clBtnLeft.Glyph.Width + 3; clBtnLeft.Top := calMargin; clBtnLeft.Left := clBtnPrevYear.Left + clBtnPrevYear.Width; clBtnRight.Height := Row[0] - calMargin; clBtnRight.Width := Col[6] - calMargin; if clBtnRight.Width < clBtnRight.Glyph.Width + 3 then clBtnRight.Width := clBtnRight.Glyph.Width + 3; clBtnRight.Top := calMargin; clBtnRight.Left := clBtnNextYear.Left - clBtnRight.Width; {position and size "today" button} clBtnToday.Height := Row[8]; clBtnToday.Width := Col[5] + Col[6] - calMargin; clBtnToday.Top := ClientHeight - calMargin - clBtnToday.Height + 1; clBtnToday.Left := ClientWidth - calMargin - clBtnToday.Width; {position and size "revert" button} clBtnRevert.Height := Row[8]; clBtnRevert.Width := Col[5] + Col[6] - calMargin; clBtnRevert.Top := ClientHeight - calMargin - clBtnRevert.Height + 1; clBtnRevert.Left := clBtnToday.Left - clBtnRevert.Width - calMargin; end; procedure TVpCustomCalendar.CMEnter(var Msg: {$IFDEF DELPHI}TMessage{$ELSE}TLMessage{$ENDIF}); var R : TRect; begin inherited; clRevertDate := FDate; {invalidate the active date to ensure that the focus rect is painted} R := calGetCurrentRectangle; InvalidateRect(Handle, @R, False); end; procedure TVpCustomCalendar.CMExit(var Msg: {$IFDEF DELPHI}TMessage{$ELSE}TLMessage{$ENDIF}); var R : TRect; begin inherited; {invalidate the active date to ensure that the focus rect is painted} R := calGetCurrentRectangle; InvalidateRect(Handle, @R, False); end; {=====} procedure TVpCustomCalendar.CMFontChanged(var Msg: {$IFDEF DELPHI}TMessage{$ELSE}TLMessage{$ENDIF}); begin inherited; if csLoading in ComponentState then Exit; calRecalcSize(False); Invalidate; end; procedure TVpCustomCalendar.CreateParams(var Params: TCreateParams); {$IFNDEF LCL} const BorderStyles: array[TBorderStyle] of LongInt = (0, WS_BORDER); {$ENDIF} begin inherited CreateParams(Params); {$IFNDEF LCL} with Params do begin Style := LongInt(Style) or BorderStyles[FBorderStyle]; if clPopup then begin WindowClass.Style := WindowClass.Style or CS_SAVEBITS; end; end; {$ENDIF} if NewStyleControls and ({Ctl3D or }clPopup) and (BorderStyle = bsSingle) then begin if not clPopup then Params.Style := Params.Style and not WS_BORDER; Params.ExStyle := Params.ExStyle or WS_EX_CLIENTEDGE; end; {set style to reflect desire for double clicks} if FWantDblClicks then ControlStyle := ControlStyle + [csDoubleClicks] else ControlStyle := ControlStyle - [csDoubleClicks]; end; {=====} procedure TVpCustomCalendar.CreateWnd; begin inherited CreateWnd; calRecalcSize(False); {if not set, get current date} if FDate = 0 then SetDate(calGetValidDate(SysUtils.Date-1, +1)); end; procedure TVpCustomCalendar.DoOnChange(Value: TDateTime); begin if Assigned(FOnChange) then FOnChange(Self, Value); end; {=====} function TVpCustomCalendar.DoOnGetDateEnabled(ADate: TDateTime) : Boolean; begin Result := True; if Assigned(FOnGetDateEnabled) then FOnGetDateEnabled(Self, ADate, Result); end; {=====} {$IFDEF LCL} function TVpCustomCalendar.DoMouseWheel(Shift: TShiftState; Delta: Integer; MousePos: TPoint): Boolean; {$ELSE} procedure TVpCustomCalendar.DoMouseWheel(Shift: TShiftState; Delta, XPos, YPos: SmallInt); {$ENDIF} const WHEEL_DELTA = 120; // in unit Windows. var key: Word; begin {$IFDEF LCL} Result := inherited DoMouseWheel(Shift, Delta, MousePos); {$ELSE} inherited DoOnMouseWheel(Shift, Delta, XPos, YPos); {$ENDIF} if Abs(Delta) = WHEEL_DELTA then begin {inc/dec month} if Delta < 0 then Key := VK_NEXT else Key := VK_PRIOR; KeyDown(Key, []); end else if Abs(Delta) > WHEEL_DELTA then begin {inc/dec year} if Delta < 0 then Key := VK_NEXT else Key := VK_PRIOR; KeyDown(Key, [ssCtrl]); end else if Abs(Delta) < WHEEL_DELTA then begin {inc/dec Week} if Delta < 0 then Key := VK_DOWN else Key := VK_UP; KeyDown(Key, []); end; end; function TVpCustomCalendar.IsReadOnly: Boolean; begin Result := ReadOnly; end; class function TVpCustomCalendar.GetControlClassDefaultSize: TSize; begin Result.CX := 200; Result.CY := 180; end; { If the component is being dropped on a form at designtime, then automatically hook up to the first datastore component found. } procedure TVpCustomCalendar.HookUp; var I: Integer; begin if csDesigning in ComponentState then for I := 0 to pred(Owner.ComponentCount) do begin if (Owner.Components[I] is TVpCustomDataStore) then begin DataStore := TVpCustomDataStore(Owner.Components[I]); Exit; end; end; end; procedure TVpCustomCalendar.KeyDown(var Key: Word; Shift: TShiftState); var Y: Word; M: Word; D: Word; HD: TDateTime; PopupPoint: TPoint; begin // inherited KeyDown(Key, Shift); if IsReadOnly then Exit; HD := FDate; case Key of VK_LEFT: if Shift = [] then SetDate(calGetValidDate(FDate, -1)) else if ssCtrl in Shift then IncMonth(-1) else if ssShift in Shift then IncYear(-1); VK_RIGHT: if Shift = [] then SetDate(calGetValidDate(FDate, +1)) else if ssCtrl in Shift then IncMonth(1) else if ssShift in Shift then IncYear(1); VK_UP: if Shift = [] then SetDate(calGetValidDate(FDate, -7)) else if ssCtrl in Shift then IncYear(-1) else if ssShift in Shift then IncMonth(-1); VK_DOWN: if Shift = [] then SetDate(calGetValidDate(FDate, +7)) else if ssCtrl in Shift then IncYear(1) else if ssShift in Shift then IncMonth(1); VK_HOME: if ssCtrl in Shift then begin DecodeDate(FDate, Y, M, D); SetDate(calGetValidDate(EncodeDate(Y, 1, 1)-1, +1)); end else if Shift = [] then begin DecodeDate(FDate, Y, M, D); SetDate(calGetValidDate(EncodeDate(Y, M, 1)-1, +1)); end; VK_END: if ssCtrl in Shift then begin DecodeDate(FDate, Y, M, D); SetDate(calGetValidDate(EncodeDate(Y, 12, DaysInAMonth(Y, 12))+1, -1)); end else if Shift = [] then begin DecodeDate(FDate, Y, M, D); SetDate(calGetValidDate(EncodeDate(Y, M, DaysInAMonth(Y, M))+1, -1)); end; VK_PRIOR: if ssCtrl in Shift then begin IncYear(-1); end else if Shift = [] then begin IncMonth(-1); end; VK_NEXT: if ssCtrl in Shift then begin IncYear(1); end else if Shift = [] then begin IncMonth(1); end; VK_BACK: if ssAlt in Shift then SetDate(calGetValidDate(SysUtils.Date-1, +1)); VK_ESCAPE: if Shift = [] then SetDate(calGetValidDate(clRevertDate-1, +1)); VK_F10: if (ssShift in Shift) and not (Assigned (PopupMenu)) then begin PopupPoint := GetClientOrigin; FDefaultPopup.Popup (PopupPoint.x + 10, PopupPoint.y + 10); end; VK_APPS: if not Assigned (PopupMenu) then begin PopupPoint := GetClientOrigin; FDefaultPopup.Popup (PopupPoint.x + 10, PopupPoint.y + 10); end; else inherited; end; Key := 0; if HD <> FDate then begin FBrowsing := True; try DoOnChange(FDate); finally FBrowsing := False; end; end; end; {=====} procedure TVpCustomCalendar.KeyPress(var Key: Char); begin inherited KeyPress(Key); if IsReadOnly then Exit; case Key of '+' : SetDate(calGetValidDate(FDate, +1)); '-' : SetDate(calGetValidDate(FDate, -1)); #13 : DoOnChange(FDate); {date selected} #32 : DoOnChange(FDate); {date selected} ^Z : SetDate(calGetValidDate(SysUtils.Date-1, +1)); end; end; {=====} procedure TVpCustomCalendar.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var Yr, M, D: Word; Yr2, M2, D2: Word; R, C: Integer; OldIdx, NewIdx: Integer; Re: TRect; Ignore: Boolean; ClientOrigin: TPoint; begin inherited; if (not Assigned (PopupMenu)) and (Button = mbRight) then begin if not focused then SetFocus; ClientOrigin := GetClientOrigin; FDefaultPopup.Popup (X + ClientOrigin.x, Y + ClientOrigin.y); Exit; end; {exit if this click happens when the popup menu is active} if clInPopup or (not Visible) then Exit; SetFocus; inherited MouseDown(Button, Shift, X, Y); if IsReadOnly then Exit; {if we have the mouse captured, see if a button was clicked} if GetCapture = Handle then begin if (cdoShowNavBtns in Options) then begin Re := clBtnLeft.ClientRect; Re.TopLeft := ScreenToClient(clBtnLeft.ClientToScreen(Re.TopLeft)); Re.BottomRight := ScreenToClient(clBtnLeft.ClientToScreen(Re.BottomRight)); if PtInRect(Re, Point(X, Y)) then begin clBtnLeft.Click; Exit; end; Re := clBtnRight.ClientRect; Re.TopLeft := ScreenToClient(clBtnRight.ClientToScreen(Re.TopLeft)); Re.BottomRight := ScreenToClient(clBtnRight.ClientToScreen(Re.BottomRight)); if PtInRect(Re, Point(X, Y)) then begin clBtnRight.Click; Exit; end; Re := clBtnNextYear.ClientRect; Re.TopLeft := ScreenToClient(clBtnNextYear.ClientToScreen(Re.TopLeft)); Re.BottomRight := ScreenToClient(clBtnNextYear.ClientToScreen(Re.BottomRight)); if PtInRect(Re, Point(X, Y)) then begin clBtnNextYear.Click; Exit; end; Re := clBtnPrevYear.ClientRect; Re.TopLeft := ScreenToClient(clBtnPrevYear.ClientToScreen(Re.TopLeft)); Re.BottomRight := ScreenToClient(clBtnPrevYear.ClientToScreen(Re.BottomRight)); if PtInRect(Re, Point(X, Y)) then begin clBtnPrevYear.Click; Exit; end; end; if (cdoShowRevert in Options) then begin Re := clBtnRevert.ClientRect; Re.TopLeft := ScreenToClient(clBtnRevert.ClientToScreen(Re.TopLeft)); Re.BottomRight := ScreenToClient(clBtnRevert.ClientToScreen(Re.BottomRight)); if PtInRect(Re, Point(X, Y)) then begin clBtnRevert.Click; Exit; end; end; if (cdoShowToday in Options) then begin Re := clBtnToday.ClientRect; Re.TopLeft := ScreenToClient(clBtnToday.ClientToScreen(Re.TopLeft)); Re.BottomRight := ScreenToClient(clBtnToday.ClientToScreen(Re.BottomRight)); if PtInRect(Re, Point(X, Y)) then begin clBtnToday.Click; Exit; end; end; end; {save current date} DecodeDate(FDate, Yr, M, D); M2 := M; {calculate the row and column clicked on} for R := 2 to 8 do begin for C := 0 to 6 do begin if PtInRect(clRowCol[R,C], Point(X, Y)) then begin {convert to an index} NewIdx := ((R-2) * 7) + Succ(C); OldIdx := clFirst + Pred(clDay); Ignore := False; if NewIdx <> OldIdx then begin {see if this date is disabled - selection not allowed} if not DoOnGetDateEnabled(FDate+(NewIdx-OldIdx)) then Break; DecodeDate(FDate+(NewIdx-OldIdx), Yr2, M2, D2); if not (cdoShowInactive in FOptions) then begin {will this change the month?} if M2 <> M then Ignore := True; end; {convert to a date and redraw} if not Ignore then SetDate(FDate+(NewIdx-OldIdx)); end; if (not Ignore) and (Button = mbLeft) then begin if M2 <> M then begin FBrowsing := True; try DoOnChange(FDate); finally FBrowsing := False; end; end else DoOnChange(FDate); end; Break; end; end; end; end; {=====} procedure TVpCustomCalendar.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var P: TPoint; M: TPopUpMenu; MI: TMenuItem; I: Integer; J: Integer; K: Integer; MO: Integer; YR: Word; MM: Word; DA: Word; HC: Boolean; begin inherited MouseUp(Button, Shift, X, Y); if (PopUpMenu = nil) and (Button = mbRight) and (Y < clRowCol[1,0].Top) {above day names} and (X > clBtnPrevYear.Left + clBtnNextYear.Width) and (X < clBtnNextYear.Left) then begin if not Focused and CanFocus then SetFocus; M := TPopupMenu.Create(Self); try DecodeDate(FDate, YR, MM, DA); MO := MM; {convert to integer to avoid wrap-around errors with words} {determine the starting month} I := MO - 3; if I < 1 then I := MO - 3 + 12; {determine the ending month + 1} J := MO + 4; if J > 12 then J := MO + 4 - 12; K := 0; {create the menu items} repeat MI := TMenuItem.Create(M); MI.Caption := FormatSettings.LongMonthNames[I]; MI.Enabled := Enabled; MI.OnClick := calChangeMonth; MI.Tag := I; MI.HelpContext := K; M.Items.Add(MI); Inc(I); Inc(K); if I > 12 then I := 1; until I = J; HC := GetCapture = Handle; P.X := X-20; P.Y := Y - (GetSystemMetrics(SM_CYMENU)*7) div 2; P := ClientToScreen(P); {move the mouse to cause the menu item to highlight} {$IFDEF DELPHI} PostMessage(Handle, WM_MOUSEMOVE, 0, MAKELONG(P.X,P.Y+1)); {$ELSE} PostMessage(Handle, LM_MOUSEMOVE, 0, MAKELONG(P.X,P.Y+1)); {$ENDIF} clInPopup := True; try M.PopUp(P.X, P.Y); Application.ProcessMessages; {capture the mouse again} if clPopup and HC then SetCapture(Handle); finally clInPopup := false; end; finally M.Free; end; end; end; { Changes the day by Delta (signed) days } procedure TVpCustomCalendar.IncDay(Delta: Integer); begin if Delta > 0 then SetDate(calGetValidDate(FDate+Delta-1, +1)) else SetDate(calGetValidDate(FDate+Delta+1, -1)); end; { Changes the month by Delta (signed) months } procedure TVpCustomCalendar.IncMonth(Delta: Integer); begin SetDate(SysUtils.IncMonth(FDate, Delta)); end; procedure TVpCustomCalendar.IncYear(Delta: Integer); begin SetDate(DateUtils.IncYear(FDate, Delta)); end; function TVpCustomCalendar.IsHoliday(ADate: TDate; out AHolidayName: String): Boolean; begin Result := false; AHolidayName := ''; if Assigned(FOnHoliday) then begin FOnHoliday(Self, trunc(ADate), AHolidayName); Result := AHolidayName <> ''; end else if Assigned(FControlLink) then Result := FControlLink.IsHoliday(ADate, AHolidayName); end; procedure TVpCustomCalendar.Paint; begin RenderToCanvas( Canvas, // Paint Canvas Rect (0, 0, Width, Height), // Paint Rectangle ra0, 1, // Scale Date, // Date -1, // Start At -1, // End At gr30Min, False); // Display Only end; procedure TVpCustomCalendar.LinkHandler(Sender: TComponent; NotificationType: TVpNotificationType; const Value: Variant); begin clInLinkHandler := true; try if NotificationType = neDateChange then Date := Value else if NotificationType = neInvalidate then Invalidate; finally clInLinkHandler := false; end; end; function TVpCustomCalendar.GetDay: Integer; begin Result := clDay; end; function TVpCustomCalendar.GetMonth: Integer; begin Result := clMonth; end; function TVpCustomCalendar.GetYear: Integer; begin Result := clYear; end; function TVpCustomCalendar.GetControlType: TVpItemType; begin Result := itCalendar; end; procedure TVpCustomCalendar.LoadLanguage; var item: TMenuItem; begin for item in FDefaultPopup.Items do if item is TVpMenuItem then TVpMenuItem(item).Translate; end; procedure TVpCustomCalendar.PaintToCanvas(ACanvas: TCanvas; ARect: TRect; Angle: TVpRotationAngle; ADate: TDateTime); begin RenderToCanvas(ACanvas, ARect, Angle, 1, ADate, -1, -1, gr30Min, True); end; procedure TVpCustomCalendar.RenderToCanvas(RenderCanvas: TCanvas; RenderIn: TRect; Angle: TVpRotationAngle; Scale: Extended; RenderDate: TDateTime; StartLine: Integer; StopLine: Integer; UseGran: TVpGranularity; DisplayOnly: Boolean); var painter: TVpCalendarPainter; begin painter := TVpCalendarPainter.Create(Self, RenderCanvas); try painter.RenderToCanvas(RenderIn, Angle, Scale, RenderDate, StartLine, StopLine, UseGran, DisplayOnly); finally painter.Free; end; end; {$IFNDEF LCL} procedure TVpCustomCalendar.SetBorderStyle(Value: TBorderStyle); begin if Value <> FBorderStyle then begin FBorderStyle := Value; Invalidate; end; end; {$ENDIF} procedure TVpCustomCalendar.SetColor(Value: TColor); begin Colors.Background := Value; end; procedure TVpCustomCalendar.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); begin inherited SetBounds(ALeft, ATop, AWidth, AHeight); if csLoading in ComponentState then Exit; calRecalcSize(False); end; procedure TVpCustomCalendar.SetDate(Value: TDateTime); var R: TRect; Y: Word; M: Word; D: Word; begin if Value <> FDate then begin {determine if the new date is in the same month} DecodeDate(Value, Y, M, D); if (clYear = Y) and (clMonth = M) then begin {invalidate the old date} R := calGetCurrentRectangle; InvalidateRect(Handle, @R, False); end else Invalidate; DecodeDate(Value, clYear, clMonth, clDay); FDate := Value; calRebuildCalArray (FDate); {invalidate the new date} R := calGetCurrentRectangle; InvalidateRect(Handle, @R, False); if (not clInLinkHandler) and (ControlLink <> nil) then ControlLink.Notify(self, neDateChange, Date); end; end; procedure TVpCustomCalendar.SetDateFormat(Value: TVpDateFormat); begin if Value <> FDateFormat then begin FDateFormat := Value; Invalidate; end; end; procedure TVpCustomCalendar.SetDayNameWidth(Value: TVpDayNameWidth); begin if Value <> FDayNameWidth then begin FDayNameWidth := Value; Invalidate; end; end; procedure TVpCustomCalendar.SetDisplayOptions(Value: TVpCalDisplayOptions); begin if Value <> FOptions then begin FOptions := Value; if csDesigning in ComponentState then begin if cdoShowRevert in Options then clBtnRevert.Parent := Self else clBtnRevert.Parent := nil; if cdoShowToday in Options then clBtnToday.Parent := Self else clBtnToday.Parent := nil; if cdoShowNavBtns in Options then begin clBtnLeft.Parent := Self; clBtnRight.Parent := Self; clBtnNextYear.Parent := Self; clBtnPrevYear.Parent := Self; end else begin clBtnLeft.Parent := nil; clBtnRight.Parent := nil; clBtnNextYear.Parent := nil; clBtnPrevYear.Parent := nil; end; end; calRecalcSize (False); Invalidate; end; end; { Set the DrawHeader property value } procedure TVpCustomCalendar.SetDrawHeader(Value: Boolean); begin if Value <> FDrawHeader then begin FDrawHeader := Value; if FDrawHeader then begin clStartRow := 0; clRowCount := 8; end else begin clStartRow := 2; clRowCount := 7; end; calRecalcSize (False); Refresh; end; end; { Set the calendar to todays date } procedure TVpCustomCalendar.SetToday; begin Date := Now; end; procedure TVpCustomCalendar.SetWantDblClicks(Value: Boolean); begin if Value <> FWantDblClicks then begin FWantDblClicks := Value; RecreateWnd(Self); { *Converted from RecreateWnd* } end; end; procedure TVpCustomCalendar.SetWeekStarts(Value: TVpDayType); begin if Value <> FWeekStarts then begin FWeekStarts := Value; if csLoading in ComponentState then Exit; calRebuildCalArray (FDate); Invalidate; end; end; {$IFDEF DELPHI} procedure TVpCustomCalendar.WMEraseBkgnd(var Msg: TWMEraseBkgnd); begin Msg.Result := 1; {don't erase background, just say we did. Shhhhhhh!} end; procedure TVpCustomCalendar.WMGetDlgCode(var Msg: TWMGetDlgCode); begin Msg.Result := DLGC_WANTARROWS; end; procedure TVpCustomCalendar.WMKillFocus(var Msg: TWMKillFocus); begin inherited; Invalidate; end; {$ELSE} procedure TVpCustomCalendar.WMEraseBkgnd(var Msg: TLMEraseBkgnd); begin Msg.Result := 1; {don't erase background, just say we did. Shhhhhhh!} end; { procedure TVpCustomCalendar.WMGetDlgCode(var Msg: TLMGetDlgCode); begin Msg.Result := DLGC_WANTARROWS; end; } {=====} procedure TVpCustomCalendar.WMKillFocus(var Msg: TLMKillFocus); begin inherited; Invalidate; end; {$ENDIF} function TVpCustomCalendar.GetPopupMenu: TPopupMenu; begin if FExternalPopup = nil then Result := FDefaultPopup else Result := FExternalPopup; end; procedure TVpCustomCalendar.SetPopupMenu(AValue: TPopupMenu); begin if (AValue = nil) or (AValue = FDefaultPopup) then FExternalPopup := nil else FExternalPopup := AValue; end; procedure TVpCustomCalendar.InitializeDefaultPopup; var NewItem: TVpMenuItem; begin if RSToday <> '' then begin NewItem := TVpMenuItem.Create (Self); NewItem.Kind := mikToday; NewItem.OnClick := PopupToday; FDefaultPopup.Items.Add(NewItem); end; if RSNextMonth <> '' then begin NewItem := TVpMenuItem.Create (Self); NewItem.Kind := mikNextMonth; NewItem.OnClick := PopupNextMonth; FDefaultPopup.Items.Add(NewItem); end; if RSPrevMonth <> '' then begin NewItem := TVpMenuItem.Create (Self); NewItem.Kind := mikPrevMonth; NewItem.OnClick := PopupPrevMonth; FDefaultPopup.Items.Add(NewItem); end; if RSNextYear <> '' then begin NewItem := TVpMenuItem.Create (Self); NewItem.Kind := mikNextYear; NewItem.OnClick := PopupNextYear; FDefaultPopup.Items.Add(NewItem); end; if RSPrevYear <> '' then begin NewItem := TVpMenuItem.Create (Self); NewItem.Kind := mikPrevYear; NewItem.OnClick := PopupPrevYear; FDefaultPopup.Items.Add(NewItem); end; end; procedure TVpCustomCalendar.PopupToday(Sender: TObject); begin SetDate(Now); end; procedure TVpCustomCalendar.PopupNextMonth(Sender: TObject); begin IncMonth(1); end; procedure TVpCustomCalendar.PopupPrevMonth(Sender: TObject); begin IncMonth(-1); end; procedure TVpCustomCalendar.PopupNextYear(Sender: TObject); begin IncYear(1); end; procedure TVpCustomCalendar.PopupPrevYear(Sender: TObject); begin IncYear(-1); end; end.