home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d56 / RMCTL.ZIP / rmCalendar.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-22  |  32KB  |  1,152 lines

  1. {================================================================================
  2. Copyright (C) 1997-2001 Mills Enterprise
  3.  
  4. Unit     : rmCalendar
  5. Purpose  : Replacement for the windows comctrl calendar.
  6.            Also has CalendarCombo.
  7. Date     : 01-01-1999
  8. Author   : Ryan J. Mills
  9. Version  : 1.80
  10. ================================================================================
  11. }
  12. unit rmCalendar;
  13.  
  14. interface
  15.  
  16. {$I CompilerDefines.INC}
  17.  
  18. uses
  19.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  20.   StdCtrls, ExtCtrls, Grids, rmBtnEdit, Buttons, rmScrnCtrls, rmmsglist;
  21.  
  22. type
  23.   TCurrentDateValue = (cdvYear, cdvMonth, cdvDay);
  24.  
  25.   TrmCustomCalendar = class(TCustomPanel)
  26.   private
  27.     { Private declarations }
  28.     fCalendarGrid: TDrawGrid;
  29.     fLabel1: TLabel;
  30.     fShowWeekends: boolean;
  31.     fWeekendBkColor: TColor;
  32.     fWeekendColor: TColor;
  33.     wYear, //Working Year
  34.       wMonth, //Working Month
  35.       wDay, //Working Day
  36.       wfdow, //Working First Day of the Month (index into sun, mon, tue...)
  37.       wdom: word; //Working Days of Month
  38.     fSelectionValid,
  39.       fBoldSysdate: boolean;
  40.     fSelectedDate,
  41.       fMinSelectDate,
  42.       fMaxSelectDate,
  43.       fworkingdate: TDate;
  44.     fOnWorkingDateChange: TNotifyEvent;
  45.     fOnSelectedDateChange: TNotifyEvent;
  46.     fCalendarFont: TFont;
  47.     fUseDateRanges: boolean;
  48.     procedure SetWeekendBkColor(const Value: TColor);
  49.     procedure SetWeekendColor(const Value: TColor);
  50.     procedure setShowWeekends(const Value: boolean);
  51.     procedure SetSelectedDate(const Value: TDate);
  52.     procedure SetWorkingDate(const Value: TDate);
  53.     procedure SetCalendarFont(const Value: TFont);
  54.     procedure SetMaxDate(const Value: TDate);
  55.     procedure SetMinDate(const Value: TDate);
  56.     procedure SetUseDateRanges(const Value: boolean);
  57.     procedure GetRowColInfo(wDate: TDate; var Row, Col: integer);
  58.     function CheckDateRange(wDate: TDate): TDate;
  59.  
  60.     function ValidateDOW(row, col: integer; var daynumber: integer): boolean;
  61.     function MyEncodeDate(year, month, day: word): TDateTime;
  62.     function CurrentDateValue(Value: TCurrentDateValue): word;
  63.  
  64.     procedure wmSize(var Msg: TMessage); message WM_Size;
  65.     procedure CalendarSelectDate(Sender: TObject; Col, Row: Integer;
  66.       var CanSelect: Boolean);
  67.     procedure SetBoldSystemDate(const Value: boolean);
  68.   protected
  69.     { Protected declarations }
  70.     procedure SetCellSizes;
  71.     procedure PaintCalendarCell(Sender: TObject; Col, Row: Longint; Rect: TRect; State: TGridDrawState);
  72.  
  73.     procedure CalendarDblClick(Sender: TObject); virtual;
  74.     procedure CalendarGridKeyPress(Sender: TObject; var Key: Char); virtual;
  75.     procedure CalendarKeyMovement(Sender: TObject; var Key: Word; Shift: TShiftState); virtual;
  76.  
  77.     property BoldSystemDate : boolean read fboldsysdate write SetBoldSystemDate default true;
  78.     property UseDateRanges: boolean read fUseDateRanges write SetUseDateRanges default false;
  79.     property MinDate: TDate read fMinSelectDate write SetMinDate;
  80.     property MaxDate: TDate read fMaxSelectDate write SetMaxDate;
  81.     property CalendarFont: TFont read fCalendarFont write SetCalendarFont;
  82.     property SelectedDate: TDate read fSelectedDate write SetSelectedDate;
  83.     property WorkingDate: TDate read fworkingdate;
  84.     property ShowWeekends: boolean read fShowWeekends write SetShowWeekends default true;
  85.     property WeekendColor: TColor read fWeekendColor write SetWeekendColor default clTeal;
  86.     property WeekendBkColor: TColor read fWeekendBkColor write SetWeekendBkColor default $E1E1E1;
  87.     property OnWorkingDateChange: TNotifyEvent read fOnWorkingDateChange write fOnWorkingDateChange;
  88.     property OnSelectedDateChange: TNotifyEvent read fOnSelectedDateChange write fOnSelectedDateChange;
  89.   public
  90.     { Public declarations }
  91.     constructor create(AOwner: TComponent); override;
  92.     destructor destroy; override;
  93.     procedure NextMonth;
  94.     procedure PrevMonth;
  95.     procedure NextYear;
  96.     procedure PrevYear;
  97.   end;
  98.  
  99.   TrmCalendar = class(TrmCustomCalendar)
  100.   public
  101.     { Public declarations }
  102.   published
  103.     { Published declarations }
  104.     property Align;
  105.     property Anchors;
  106.     property BorderStyle default bsSingle;
  107.     property BevelInner default bvNone;
  108.     property BevelOuter default bvNone;
  109.  
  110.     property CalendarFont;
  111.     property SelectedDate;
  112.     property WorkingDate;
  113.     property ShowWeekends;
  114.     property WeekendColor;
  115.     property WeekendBkColor;
  116.     property UseDateRanges;
  117.     property MinDate;
  118.     property MaxDate;
  119.     property OnWorkingDateChange;
  120.     property OnSelectedDateChange;
  121.   end;
  122.  
  123.   TrmScreenCalendar = class(TrmCalendar)
  124.   private
  125.     { Private declarations }
  126.     fPanel: TPanel;
  127.     fBtn1, fBtn2: TSpeedButton;
  128.     LastState: Word;
  129.     fmsg: TrmMsgEvent;
  130.     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  131.     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  132.     procedure WMMouseMove(var Message: TWMMouse); message WM_MOUSEMOVE;
  133.   protected
  134.     { Protected declarations }
  135.     procedure CreateParams(var Params: TCreateParams); override;
  136.     procedure CreateWnd; override;
  137.     procedure VisibleChanging; override;
  138.     procedure DoBtnClick(Sender: TObject);
  139.     procedure DoPanelSize(Sender: TObject);
  140.   public
  141.     { Public declarations }
  142.     constructor create(AOwner: TComponent); override;
  143.  
  144.     procedure CalendarKeyMovement(Sender: TObject; var Key: Word; Shift: TShiftState); override;
  145.     procedure SetFocus; override;
  146.     procedure HandleMessage(var msg: TMessage);
  147.     procedure WndProc(var Message: TMessage); override;
  148.   published
  149.     { Published declarations }
  150.   end;
  151.  
  152.   TrmCustomComboCalendar = class(TrmCustomBtnEdit)
  153.   private
  154.   { Private declarations }
  155.     fCalendar: TrmScreenCalendar;
  156.     fSelectedDate: TDate;
  157.     fDateFormat: string;
  158.     fDropDownWidth: integer;
  159.     fmsg: TrmMsgEvent;
  160.     procedure SetDate(value: TDate);
  161.     procedure SetDateFormat(value: string);
  162.     function GetDate: TDate;
  163.     procedure SetSelectDate(Sender: TObject);
  164.     procedure ToggleCalendar(Sender: TObject);
  165.     procedure DoMyExit(Sender: Tobject);
  166.     function GetCalendar: TrmCalendar;
  167.     procedure wmKillFocus(var Message: TMessage); message wm_killfocus;
  168.   protected
  169.     { Protected declarations }
  170.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  171.     property SelectedDate: TDate read GetDate write SetDate;
  172.     property DateFormat: string read fDateformat write SetDateFormat;
  173.     property DropDownWidth: integer read fDropDownWidth write fDropDownWidth default 0;
  174.     property Calendar: TrmCalendar read GetCalendar;
  175.   public
  176.     { Public declarations }
  177.     constructor Create(AOwner: TComponent); override;
  178.     destructor Destroy; override;
  179.     procedure WndProc(var Message: TMessage); override;
  180.   end;
  181.  
  182.   TrmComboCalendar = class(TrmCustomComboCalendar)
  183.   published
  184.     { Published declarations }
  185.     property SelectedDate;
  186.     property DateFormat;
  187.  
  188. {$IFDEF D4_OR_HIGHER}
  189.     property Anchors;
  190.     property Constraints;
  191. {$ENDIF}
  192.     property AutoSelect;
  193.     property AutoSize;
  194.     property BtnWidth;
  195.     property BorderStyle;
  196.     property Calendar;
  197.     property Color;
  198.     property Ctl3D;
  199.     property DragCursor;
  200.     property DragMode;
  201.     property DropDownWidth;
  202.     property EditorEnabled;
  203.     property Enabled;
  204.     property Font;
  205.     property MaxLength;
  206.     property ParentColor;
  207.     property ParentCtl3D;
  208.     property ParentFont;
  209.     property ParentShowHint;
  210.     property PopupMenu;
  211.     property ShowHint;
  212.     property TabOrder;
  213.     property TabStop;
  214.     property Visible;
  215.  
  216.     property OnChange;
  217.     property OnClick;
  218.     property OnDblClick;
  219.     property OnDragDrop;
  220.     property OnDragOver;
  221.     property OnEndDrag;
  222.     property OnEnter;
  223.     property OnExit;
  224.     property OnKeyDown;
  225.     property OnKeyPress;
  226.     property OnKeyUp;
  227.     property OnMouseDown;
  228.     property OnMouseMove;
  229.     property OnMouseUp;
  230.     property OnStartDrag;
  231.   end;
  232.  
  233. implementation
  234.  
  235. uses
  236.   rmSpeedBtns;
  237.  
  238. const
  239.   DaysOfMonth: array[0..12] of integer = (31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); //Wrapped for proper month calculations...
  240.   WeekDay: array[1..7] of string = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
  241.   MonthOfYear: array[1..12] of string = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
  242.  
  243. { TrmCustomCalendar }
  244.  
  245. constructor TrmCustomCalendar.create(AOwner: TComponent);
  246. begin
  247.   inherited create(AOwner);
  248.  
  249.   BorderWidth := 1;
  250.   BorderStyle := bsSingle;
  251.   BevelOuter := bvNone;
  252.   BevelInner := bvNone;
  253.   width := 205;
  254.   height := 158;
  255.   fUseDateRanges := false;
  256.   fMinSelectDate := Now - 365; //Default it to be 1 year back
  257.   fMaxSelectDate := Now + 365; //Default it to be 1 year ahead
  258.   fBoldSysDate := true;
  259.  
  260.   fCalendarFont := tfont.create;
  261.   fCalendarFont.assign(self.font);
  262.  
  263.   fLabel1 := TLabel.create(self);
  264.   with fLabel1 do
  265.   begin
  266.     ParentFont := false;
  267.     Parent := self;
  268.     Align := alTop;
  269.     Caption := MonthOfYear[CurrentDateValue(cdvMonth)] + ' ' + inttostr(CurrentDateValue(cdvYear));
  270.     Alignment := taCenter;
  271.     Font.Size := self.font.size + 4;
  272.     Font.Style := [fsBold];
  273.     TabStop := false;
  274.   end;
  275.  
  276.   fCalendarGrid := TDrawGrid.Create(self);
  277.   with FCalendarGrid do
  278.   begin
  279.     ParentFont := false;
  280.     Parent := self;
  281.     Align := alClient;
  282.     BorderStyle := bsNone;
  283.     ColCount := 7;
  284.     FixedCols := 0;
  285.     RowCount := 7;
  286.     ScrollBars := ssNone;
  287.     Options := [];
  288.     OnDrawCell := PaintCalendarCell;
  289.     OnSelectCell := CalendarSelectDate;
  290.     OnDblClick := CalendarDblClick;
  291.     OnKeyPress := CalendarGridKeyPress;
  292.     OnKeyDown := CalendarKeyMovement;
  293.   end;
  294.  
  295.   fShowWeekends := true;
  296.   fWeekendColor := clTeal;
  297.   fWeekendBkColor := $E1E1E1;
  298.  
  299.   SetCellSizes;
  300.   SelectedDate := Now;
  301. end;
  302.  
  303. destructor TrmCustomCalendar.destroy;
  304. begin
  305.   fCalendarGrid.free;
  306.   fLabel1.free;
  307.   fCalendarFont.free;
  308.   inherited;
  309. end;
  310.  
  311. procedure TrmCustomCalendar.PaintCalendarCell(Sender: TObject; Col, Row: Integer;
  312.   Rect: TRect; State: TGridDrawState);
  313. var
  314.   TextToPaint: string;
  315.   xpos, ypos, wdom, Daynumber: integer;
  316.   NewDayNumber: integer;
  317. begin
  318.   case row of
  319.     0:
  320.       begin
  321.         fCalendarGrid.canvas.brush.color := clbtnface;
  322.         if ((col = 0) or (col = 6)) and fShowWeekends then
  323.           fCalendarGrid.canvas.font.color := fWeekendColor
  324.         else
  325.           fCalendarGrid.canvas.font.color := clbtntext;
  326.         TextToPaint := WeekDay[col + 1];
  327.       end;
  328.   else
  329.     begin
  330.       if ValidateDOW(row, col, DayNumber) then
  331.       begin
  332.         if (gdFocused in state) then fSelectionValid := true;
  333.         TextToPaint := inttostr(DayNumber);
  334.         if (gdSelected in state) then
  335.         begin
  336.           fCalendarGrid.canvas.font.color := clHighlightText;
  337.           fCalendarGrid.canvas.brush.color := clHighlight;
  338.           fworkingdate := MyEncodeDate(wYear, wMonth, DayNumber);
  339.         end
  340.         else
  341.         begin
  342.           if (((col = 0) or (col = 6)) and fShowWeekends) then
  343.           begin
  344.             fCalendarGrid.canvas.font.color := fWeekendColor;
  345.             fCalendarGrid.canvas.brush.color := fweekendBkColor;
  346.           end
  347.           else
  348.           begin
  349.             fCalendarGrid.canvas.font.color := clWindowText;
  350.             fCalendarGrid.canvas.brush.color := clwindow;
  351.           end;
  352.         end;
  353.       end
  354.       else
  355.       begin
  356.         fCalendarGrid.canvas.font.color := clBtnFace;
  357.         fCalendarGrid.canvas.brush.color := clWindow;
  358.         wdom := DaysOfMonth[wmonth];
  359.         if (IsLeapYear(wyear)) and (wmonth = 2) then inc(wdom);
  360.         if daynumber > wdom then
  361.         begin
  362.           NewDayNumber := daynumber - wdom;
  363.           if NewDayNumber > wdom then
  364.           begin
  365.             fCalendarGrid.canvas.brush.color := clInactiveCaption;
  366.             fCalendarGrid.canvas.brush.style := bsDiagCross;
  367.             fCalendarGrid.canvas.pen.Style := psClear;
  368.             fCalendarGrid.canvas.Rectangle(rect.left, rect.Top, rect.right + 1, rect.bottom + 1);
  369.             fCalendarGrid.canvas.brush.style := bsClear;
  370.             NewDayNumber := DayNumber;
  371.           end;
  372.         end
  373.         else
  374.         begin
  375.           if (wmonth = 3) and IsLeapYear(wyear) then
  376.           begin
  377.             NewDayNumber := (daynumber + DaysOfMonth[wmonth - 1] + 1);
  378.             if (NewDayNumber > DaysOfMonth[wmonth - 1] + 1) then
  379.             begin
  380.               fCalendarGrid.canvas.brush.color := clInactiveCaption;
  381.               fCalendarGrid.canvas.brush.style := bsDiagCross;
  382.               fCalendarGrid.canvas.pen.Style := psClear;
  383.               fCalendarGrid.canvas.Rectangle(rect.left, rect.Top, rect.right + 1, rect.bottom + 1);
  384.               fCalendarGrid.canvas.brush.style := bsClear;
  385.               NewDayNumber := DayNumber;
  386.             end;
  387.           end
  388.           else
  389.           begin
  390.             NewDayNumber := (daynumber + DaysOfMonth[wmonth - 1]);
  391.             if (NewDayNumber > DaysOfMonth[wmonth - 1]) then
  392.             begin
  393.               fCalendarGrid.canvas.brush.color := clInactiveCaption;
  394.               fCalendarGrid.canvas.brush.style := bsDiagCross;
  395.               fCalendarGrid.canvas.pen.Style := psClear;
  396.               fCalendarGrid.canvas.Rectangle(rect.left, rect.Top, rect.right + 1, rect.bottom + 1);
  397.               fCalendarGrid.canvas.brush.style := bsClear;
  398.               NewDayNumber := DayNumber;
  399.             end;
  400.           end;
  401.         end;
  402.  
  403.         TextToPaint := inttostr(NewDayNumber);
  404.       end;
  405.       if (fboldsysdate) and (CurrentDateValue(cdvYear) = wyear) and (CurrentDateValue(cdvMonth) = wmonth) and (CurrentDateValue(cdvDay) = daynumber) then
  406.         fCalendarGrid.canvas.font.Style := [fsBold]
  407.       else
  408.         fCalendarGrid.canvas.font.Style := [];
  409.     end;
  410.   end;
  411.   xpos := rect.Left + ((rect.right - rect.left) shr 1) - (fCalendarGrid.canvas.textwidth(TextToPaint) shr 1);
  412.   ypos := rect.Top + ((rect.bottom - rect.top) shr 1) - (fCalendarGrid.canvas.textheight(TextToPaint) shr 1);
  413.   if TextToPaint <> '' then
  414.      fCalendarGrid.canvas.TextRect(rect, xpos, ypos, TextToPaint);
  415. end;
  416.  
  417. procedure TrmCustomCalendar.SetCellSizes;
  418. var
  419.   loop: integer;
  420.   h, w: integer;
  421.   mh, mw: integer;
  422. begin
  423.   h := fCalendarGrid.Height div 7;
  424.   mh := fCalendarGrid.Height mod 7;
  425.   w := fCalendarGrid.Width div 7;
  426.   mw := fCalendarGrid.Width mod 7;
  427.  
  428.   for loop := 0 to 6 do
  429.   begin
  430.     if mw > 0 then
  431.     begin
  432.       dec(mw);
  433.       fCalendarGrid.ColWidths[loop] := w + 1;
  434.     end
  435.     else
  436.       fCalendarGrid.ColWidths[loop] := w;
  437.  
  438.     if mh > 0 then
  439.     begin
  440.       dec(mh);
  441.       fCalendarGrid.RowHeights[loop] := h + 1;
  442.     end
  443.     else
  444.       fCalendarGrid.RowHeights[loop] := h;
  445.   end;
  446. end;
  447.  
  448. procedure TrmCustomCalendar.SetWeekendBkColor(const Value: TColor);
  449. begin
  450.   fWeekendBkColor := value;
  451.   fCalendarGrid.invalidate;
  452. end;
  453.  
  454. procedure TrmCustomCalendar.SetWeekendColor(const Value: TColor);
  455. begin
  456.   fWeekendColor := value;
  457.   fCalendarGrid.invalidate;
  458. end;
  459.  
  460. procedure TrmCustomCalendar.SetShowWeekends(const Value: boolean);
  461. begin
  462.   fShowWeekends := value;
  463.   fCalendarGrid.invalidate;
  464. end;
  465.  
  466. procedure TrmCustomCalendar.wmSize(var Msg: TMessage);
  467. begin
  468.   inherited;
  469.   SetCellSizes;
  470. end;
  471.  
  472. function TrmCustomCalendar.ValidateDOW(row, col: integer;
  473.   var daynumber: integer): boolean;
  474. begin
  475.   daynumber := ((col + ((row - 1) * 7)) - wfdow) + 2;
  476.   if (daynumber >= 1) and (daynumber <= wdom) then
  477.     result := true
  478.   else
  479.     result := false;
  480.  
  481.   if result and fUseDateRanges then
  482.   begin
  483.     result := (MyEncodeDate(wYear, wMonth, daynumber) >= fMinSelectDate) and
  484.       (MyEncodeDate(wYear, wMonth, daynumber) <= fMaxSelectDate);
  485.   end;
  486. end;
  487.  
  488. function TrmCustomCalendar.MyEncodeDate(year, month, day: word): TDateTime;
  489. begin
  490.   if day > DaysOfMonth[month] then
  491.   begin
  492.     if (month = 2) and IsLeapYear(year) and (day >= 29) then
  493.       day := 29
  494.     else
  495.       day := DaysOfMonth[month];
  496.   end;
  497.   result := encodedate(year, month, day);
  498. end;
  499.  
  500. function TrmCustomCalendar.CurrentDateValue(
  501.   Value: TCurrentDateValue): word;
  502. var
  503.   y, m, d: word;
  504. begin
  505.   decodeDate(Now, y, m, d);
  506.   case value of
  507.     cdvYear: result := y;
  508.     cdvMonth: result := m;
  509.     cdvDay: result := d;
  510.   else
  511.     raise exception.create('Unknown parameter');
  512.   end;
  513. end;
  514.  
  515. procedure TrmCustomCalendar.SetSelectedDate(const Value: TDate);
  516. var
  517.   row, col: integer;
  518. begin
  519.   fSelectedDate := CheckDateRange(value);
  520.  
  521.   GetRowColInfo(fSelectedDate, row, Col);
  522.   DecodeDate(fSelectedDate, wYear, wMonth, wDay);
  523.   wdom := DaysOfMonth[wmonth];
  524.   wfdow := DayOfWeek(MyEncodeDate(wyear, wmonth, 1));
  525.   if (isleapyear(wyear)) and (wmonth = 2) then inc(wdom);
  526.  
  527.   fLabel1.Caption := MonthOfYear[wMonth] + ' ' + inttostr(wYear);
  528.  
  529.   fCalendarGrid.Selection := TGridRect(rect(col, row, col, row));
  530.   fCalendarGrid.Invalidate;
  531.  
  532.   if fworkingdate <> fSelectedDate then
  533.   begin
  534.     fworkingdate := fSelectedDate;
  535.     if assigned(fOnWorkingDateChange) then
  536.       fOnWorkingDateChange(self);
  537.   end;
  538.  
  539.   if assigned(fOnSelectedDateChange) then
  540.     fOnSelectedDateChange(self);
  541. end;
  542.  
  543. procedure TrmCustomCalendar.CalendarDblClick(Sender: TObject);
  544. begin
  545.   if fSelectionValid then
  546.     SetSelectedDate(fWorkingDate);
  547. end;
  548.  
  549. procedure TrmCustomCalendar.CalendarGridKeyPress(Sender: TObject;
  550.   var Key: Char);
  551. begin
  552.   if (key = #13) and fSelectionValid then
  553.     SetSelectedDate(fWorkingDate);
  554. end;
  555.  
  556. procedure TrmCustomCalendar.CalendarKeyMovement(Sender: TObject;
  557.   var Key: Word; Shift: TShiftState);
  558. var
  559.   sday, smonth, syear: word;
  560.   dummy: boolean;
  561.   row, col: integer;
  562. begin
  563.   fCalendarGrid.setfocus;
  564.   if key in [vk_left, vk_right, vk_up, vk_down] then
  565.     decodedate(fworkingdate, syear, smonth, sday);
  566.   case key of
  567.     vk_Left:
  568.       begin
  569.         if ssCtrl in Shift then
  570.         begin
  571.           PrevMonth;
  572.           Key := 0;
  573.         end
  574.         else
  575.         begin
  576.           if (fCalendarGrid.col - 1 = -1) then
  577.           begin
  578.             if sDay - 1 >= 1 then
  579.             begin
  580.               GetRowColInfo(MyEncodeDate(sYear, sMonth, sDay - 1), Row, Col);
  581.               CalendarSelectDate(self, Col, Row, dummy);
  582.             end;
  583.             Key := 0;
  584.           end;
  585.         end;
  586.       end;
  587.     vk_Right:
  588.       begin
  589.         if ssCtrl in Shift then
  590.         begin
  591.           NextMonth;
  592.           Key := 0;
  593.         end
  594.         else
  595.         begin
  596.           if (fCalendarGrid.col + 1 = 7) then
  597.           begin
  598.             if sDay + 1 <= wdom then
  599.             begin
  600.               GetRowColInfo(MyEncodeDate(sYear, sMonth, sDay + 1), Row, Col);
  601.               CalendarSelectDate(self, Col, Row, dummy);
  602.             end;
  603.             Key := 0;
  604.           end;
  605.         end;
  606.       end;
  607.     vk_Up:
  608.       begin
  609.         if ssCtrl in Shift then
  610.         begin
  611.           PrevYear;
  612.           key := 0;
  613.         end
  614.         else
  615.         begin
  616.         end;
  617.       end;
  618.     vk_Down:
  619.       begin
  620.         if ssCtrl in Shift then
  621.         begin
  622.           NextYear;
  623.           key := 0;
  624.         end
  625.         else
  626.         begin
  627.         end;
  628.       end;
  629.   end;
  630. end;
  631.  
  632. procedure TrmCustomCalendar.CalendarSelectDate(Sender: TObject; Col,
  633.   Row: Integer; var CanSelect: Boolean);
  634. var
  635.   day: integer;
  636. begin
  637.   canselect := ValidateDOW(row, col, day);
  638.   if canselect then
  639.     SetWorkingDate(MyEncodeDate(wyear, wmonth, day));
  640. end;
  641.  
  642. procedure TrmCustomCalendar.SetCalendarFont(const Value: TFont);
  643. begin
  644.   fCalendarFont.assign(value);
  645.   fCalendarGrid.font.assign(fCalendarFont);
  646.   fLabel1.font.assign(fCalendarFont);
  647.   fLabel1.Font.size := fLabel1.Font.size + 4;
  648.   fLabel1.Font.Style := fLabel1.Font.Style + [fsBold];
  649. end;
  650.  
  651. procedure TrmCustomCalendar.SetMaxDate(const Value: TDate);
  652. var
  653.   wDate: TDate;
  654. begin
  655.   wDate := trunc(value);
  656.   if wDate <> fMaxSelectDate then
  657.   begin
  658.     if wDate <= fMinSelectDate then
  659.       raise Exception.Create('MaxDate value can''t be less than or equal to the MinDate value');
  660.     fMaxSelectDate := wDate;
  661.     if UseDateRanges and (SelectedDate > fMaxSelectDate) then
  662.       SelectedDate := fMaxSelectDate;
  663.     fCalendarGrid.Invalidate;
  664.   end;
  665. end;
  666.  
  667. procedure TrmCustomCalendar.SetMinDate(const Value: TDate);
  668. var
  669.   wDate: TDate;
  670. begin
  671.   wDate := trunc(value);
  672.   if wDate <> fMinSelectDate then
  673.   begin
  674.     if wDate >= fMaxSelectDate then
  675.       raise Exception.Create('MinDate value can''t be greater than or equal to the MaxDate value');
  676.     fMinSelectDate := wDate;
  677.     if UseDateRanges and (SelectedDate < fMinSelectDate) then
  678.       SelectedDate := fMinSelectDate;
  679.     fCalendarGrid.Invalidate;
  680.   end;
  681. end;
  682.  
  683. procedure TrmCustomCalendar.SetUseDateRanges(const Value: boolean);
  684. begin
  685.   if value <> fUseDateRanges then
  686.   begin
  687.     fUseDateRanges := Value;
  688.  
  689.     if fUseDateRanges then
  690.     begin
  691.       if SelectedDate < fMinSelectDate then
  692.         SelectedDate := fMinSelectDate;
  693.  
  694.       if SelectedDate > fMaxSelectDate then
  695.         SelectedDate := fMaxSelectDate;
  696.     end;
  697.     fCalendarGrid.Invalidate;
  698.   end;
  699. end;
  700.  
  701. procedure TrmCustomCalendar.NextMonth;
  702. var
  703.   sday, smonth, syear: word;
  704. begin
  705.   decodedate(fworkingdate, syear, smonth, sday);
  706.   inc(sMonth);
  707.   if sMonth > 12 then
  708.   begin
  709.     sMonth := 1;
  710.     inc(sYear);
  711.   end;
  712.   SetWorkingDate(MyEncodeDate(sYear, sMonth, sDay));
  713. end;
  714.  
  715. procedure TrmCustomCalendar.NextYear;
  716. var
  717.   sday, smonth, syear: word;
  718. begin
  719.   decodedate(fworkingdate, syear, smonth, sday);
  720.   SetWorkingDate(MyEncodeDate(sYear + 1, sMonth, sDay));
  721. end;
  722.  
  723. procedure TrmCustomCalendar.PrevMonth;
  724. var
  725.   sday, smonth, syear: word;
  726. begin
  727.   decodedate(fworkingdate, syear, smonth, sday);
  728.  
  729.   dec(sMonth);
  730.   if sMonth < 1 then
  731.   begin
  732.     sMonth := 12;
  733.     dec(sYear);
  734.   end;
  735.  
  736.   SetWorkingDate(MyEncodeDate(sYear, sMonth, sDay));
  737. end;
  738.  
  739. procedure TrmCustomCalendar.PrevYear;
  740. var
  741.   sday, smonth, syear: word;
  742. begin
  743.   decodedate(fworkingdate, syear, smonth, sday);
  744.   SetWorkingDate(MyEncodeDate(sYear - 1, sMonth, sDay));
  745. end;
  746.  
  747. procedure TrmCustomCalendar.GetRowColInfo(wDate: TDate; var Row,
  748.   Col: integer);
  749. var
  750.   wyear, wmonth, wday: word;
  751.   wfdow: integer;
  752. begin
  753.   decodedate(wDate, wYear, wMonth, wDay);
  754.   wfdow := DayOfWeek(MyEncodeDate(wyear, wmonth, 1));
  755.   row := (((wday - 2) + wfdow) div 7) + 1;
  756.   col := (((wday - 2) + wfdow) mod 7);
  757. end;
  758.  
  759. function TrmCustomCalendar.CheckDateRange(wDate: TDate): TDate;
  760. begin
  761.   if fUseDateRanges then
  762.   begin
  763.     result := trunc(wDate);
  764.  
  765.     if (result < fMinSelectDate) then
  766.       result := fMinSelectDate;
  767.  
  768.     if (result > fMaxSelectDate) then
  769.       result := fMaxSelectDate;
  770.   end
  771.   else
  772.     result := trunc(wDate);
  773. end;
  774.  
  775. procedure TrmCustomCalendar.SetWorkingDate(const Value: TDate);
  776. var
  777.   row, col: integer;
  778. begin
  779.   fworkingdate := CheckDateRange(value);
  780.  
  781.   GetRowColInfo(fWorkingDate, row, col);
  782.  
  783.   DecodeDate(fworkingdate, wYear, wMonth, wDay);
  784.   wdom := DaysOfMonth[wmonth];
  785.   wfdow := DayOfWeek(MyEncodeDate(wyear, wmonth, 1));
  786.   if (isleapyear(wyear)) and (wmonth = 2) then inc(wdom);
  787.  
  788.   fLabel1.Caption := MonthOfYear[wMonth] + ' ' + inttostr(wYear);
  789.  
  790.   fCalendarGrid.Selection := TGridRect(rect(col, row, col, row));
  791.   fCalendarGrid.Invalidate;
  792.   if assigned(fOnWorkingDateChange) then
  793.     fOnWorkingDateChange(self);
  794. end;
  795.  
  796. procedure TrmCustomCalendar.SetBoldSystemDate(const Value: boolean);
  797. begin
  798.   fboldsysdate := Value;
  799.   invalidate;
  800. end;
  801.  
  802. { TrmCustomComboCalendar }
  803.  
  804. constructor TrmCustomComboCalendar.Create(AOwner: TComponent);
  805. begin
  806.   inherited create(aowner);
  807.  
  808.   OnBtn1Click := ToggleCalendar;
  809.   OnExit := DoMyExit;
  810.   readonly := true;
  811.   fDateformat := 'mm/dd/yyyy';
  812.   fDropDownWidth := 0;
  813.  
  814.   UseDefaultGlyphs := false;
  815.  
  816.   with GetButton(1) do
  817.   begin
  818.     Font.name := 'Marlett';
  819.     font.size := 10;
  820.     Font.color := clBtnText;
  821.     Caption := '6';
  822.     Glyph := nil;
  823.   end;
  824.  
  825.   if not (csdesigning in componentstate) then
  826.   begin
  827.     fCalendar := TrmScreenCalendar.create(owner);
  828.     with fCalendar do
  829.     begin
  830.       parent := self;
  831.       width := self.width;
  832.       visible := false;
  833.       OnSelectedDateChange := SetSelectDate;
  834.     end;
  835.   end;
  836.  
  837.   SelectedDate := Now;
  838. end;
  839.  
  840. destructor TrmCustomComboCalendar.Destroy;
  841. begin
  842.   fCalendar.free;
  843.   inherited destroy;
  844. end;
  845.  
  846. function TrmCustomComboCalendar.GetDate: TDate;
  847. begin
  848.   result := fSelectedDate;
  849. end;
  850.  
  851. procedure TrmCustomComboCalendar.SetDate(value: TDate);
  852. begin
  853.   if trunc(value) <> fSelectedDate then
  854.      fSelectedDate := trunc(value);
  855.   Text := formatdatetime(fDateFormat, fSelectedDate);
  856. end;
  857.  
  858. procedure TrmCustomComboCalendar.SetDateFormat(value: string);
  859. begin
  860.   if value = '' then value := 'mm/dd/yyyy';
  861.   fDateFormat := value;
  862.   text := formatdatetime(fDateFormat, SelectedDate);
  863. end;
  864.  
  865. procedure TrmCustomComboCalendar.SetSelectDate(Sender: TObject);
  866. var
  867.   wVisible: boolean;
  868. begin
  869.   wVisible := fCalendar.visible;
  870.   if fCalendar.visible then
  871.     fCalendar.Hide;
  872.   SelectedDate := fCalendar.WorkingDate;
  873.   if wVisible and Self.CanFocus then
  874.     self.setfocus;
  875. end;
  876.  
  877. procedure TrmCustomComboCalendar.ToggleCalendar(Sender: TObject);
  878. var
  879.   CP, SP: TPoint;
  880. begin
  881.   CP.X := Left;
  882.   CP.Y := Top + Height;
  883.   SP := parent.ClientToScreen(CP);
  884.  
  885.   SetFocus;
  886.   SelectAll;
  887.  
  888.   with fCalendar do
  889.   begin
  890.     if fDropDownWidth = 0 then
  891.       Width := self.width
  892.     else
  893.       width := fDropDownWidth;
  894.     fCalendar.SelectedDate := self.SelectedDate;
  895.  
  896.     Left := SP.X;
  897.     if assigned(screen.ActiveForm) then
  898.     begin
  899.       if (SP.Y + fCalendar.height < screen.activeForm.Monitor.Height) then
  900.         fCalendar.Top := SP.Y
  901.       else
  902.         fCalendar.Top := (SP.Y - self.height) - fCalendar.height;
  903.     end
  904.     else
  905.     begin
  906.       if (SP.Y + fCalendar.height < screen.Height) then
  907.         fCalendar.Top := SP.Y
  908.       else
  909.         fCalendar.Top := (SP.Y - self.height) - fCalendar.height;
  910.     end;
  911.     Show;
  912.     SetWindowPos(handle, hwnd_topMost, 0, 0, 0, 0, swp_nosize or swp_NoMove);
  913.   end; { Calendar }
  914. end;
  915.  
  916. procedure TrmCustomComboCalendar.WndProc(var Message: TMessage);
  917. begin
  918.   if assigned(fmsg) then
  919.   try
  920.     fmsg(message);
  921.   except
  922.   end;
  923.  
  924.   case Message.Msg of
  925.     WM_CHAR,
  926.       WM_KEYDOWN,
  927.       WM_KEYUP:
  928.       if fCalendar.visible then
  929.       begin
  930.         fcalendar.HandleMessage(message);
  931.         if message.result = 0 then exit;
  932.       end;
  933.   end;
  934.   inherited WndProc(Message);
  935. end;
  936.  
  937. procedure TrmCustomComboCalendar.DoMyExit(Sender: Tobject);
  938. begin
  939.   if fCalendar.visible then
  940.     fCalendar.Hide;
  941. end;
  942.  
  943. procedure TrmCustomComboCalendar.KeyDown(var Key: Word; Shift: TShiftState);
  944. begin
  945.   if ((Key = VK_DOWN) and (ssAlt in Shift)) or
  946.     ((key = VK_F4) and (shift = [])) then
  947.     ToggleCalendar(self)
  948.   else
  949.     inherited KeyDown(Key, Shift);
  950. end;
  951.  
  952. function TrmCustomComboCalendar.GetCalendar: TrmCalendar;
  953. begin
  954.   result := fCalendar;
  955. end;
  956.  
  957. procedure TrmCustomComboCalendar.wmKillFocus(var Message: TMessage);
  958. begin
  959.   inherited;
  960.   if fCalendar.visible then
  961.     fCalendar.Hide;
  962. end;
  963.  
  964. { TrmScreenCalendar }
  965.  
  966. constructor TrmScreenCalendar.create(AOwner: TComponent);
  967. begin
  968.   inherited create(Aowner);
  969.   BorderWidth := 0;
  970.   fPanel := TPanel.create(self);
  971.   LastState := 0;
  972.   with fPanel do
  973.   begin
  974.     Parent := self;
  975.     Align := alBottom;
  976.     fBtn1 := TSpeedButton.create(self);
  977.     with fBtn1 do
  978.     begin
  979.       Parent := fPanel;
  980.       Flat := true;
  981.       Caption := '- Month';
  982.       Font.Name := 'Small Font';
  983.       Font.Size := 7;
  984.       font.color := clbtnText;
  985.       Tag := 1;
  986.       OnClick := DoBtnClick;
  987.     end;
  988.     fBtn2 := TSpeedButton.create(self);
  989.     with fBtn2 do
  990.     begin
  991.       Parent := fPanel;
  992.       Flat := true;
  993.       Caption := '+ Month';
  994.       Font.Name := 'Small Font';
  995.       Font.Size := 7;
  996.       font.color := clbtnText;
  997.       Tag := 2;
  998.       OnClick := DoBtnClick;
  999.     end;
  1000.     OnResize := DoPanelSize;
  1001.     BevelInner := bvNone;
  1002.     BevelOuter := bvNone;
  1003.     Caption := '';
  1004.     Height := 20;
  1005.   end;
  1006. end;
  1007.  
  1008. procedure TrmScreenCalendar.CreateParams(var Params: TCreateParams);
  1009. begin
  1010.   inherited CreateParams(Params);
  1011.   with Params do
  1012.   begin
  1013.     Style := Style or WS_BORDER;
  1014.     ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
  1015.     WindowClass.Style := CS_SAVEBITS;
  1016.   end;
  1017. end;
  1018.  
  1019. procedure TrmScreenCalendar.CreateWnd;
  1020. begin
  1021.   inherited CreateWnd;
  1022.   Windows.SetParent(Handle, 0);
  1023.   CallWindowProc(DefWndProc, Handle, wm_SetFocus, 0, 0);
  1024. end;
  1025.  
  1026. procedure TrmScreenCalendar.SetFocus;
  1027. begin
  1028.   inherited;
  1029.   fCalendarGrid.SetFocus;
  1030. end;
  1031.  
  1032. procedure TrmScreenCalendar.VisibleChanging;
  1033. begin
  1034.   if Visible = false then
  1035.     SetCaptureControl(self)
  1036.   else
  1037.     ReleaseCapture;
  1038.   inherited;
  1039. end;
  1040.  
  1041. procedure TrmScreenCalendar.HandleMessage(var msg: TMessage);
  1042. var
  1043.   state: short;
  1044. begin
  1045.   state := GetKeyState(vk_control);
  1046.   if (state and $8000 <> 0) then
  1047.   begin
  1048.     fBtn1.Caption := '- Year';
  1049.     fBtn2.Caption := '+ Year';
  1050.   end
  1051.   else
  1052.   begin
  1053.     fBtn1.Caption := '- Month';
  1054.     fBtn2.Caption := '+ Month';
  1055.   end;
  1056.   msg.result := SendMessage(fCalendarGrid.Handle, msg.msg, msg.wparam, msg.lparam);
  1057. end;
  1058.  
  1059. procedure TrmScreenCalendar.CMMouseLeave(var Message: TMessage);
  1060. begin
  1061.   inherited;
  1062.   SetCaptureControl(Self);
  1063. end;
  1064.  
  1065. procedure TrmScreenCalendar.WMLButtonDown(var Message: TWMLButtonDown);
  1066. begin
  1067.   if not ptInRect(clientrect, point(message.xpos, message.ypos)) then
  1068.     Visible := false;
  1069.   inherited;
  1070. end;
  1071.  
  1072. procedure TrmScreenCalendar.WMMouseMove(var Message: TWMMouse);
  1073. begin
  1074.   if ptInRect(clientrect, point(message.xpos, message.ypos)) then
  1075.     ReleaseCapture;
  1076.   inherited;
  1077. end;
  1078.  
  1079. procedure TrmScreenCalendar.CalendarKeyMovement(Sender: TObject;
  1080.   var Key: Word; Shift: TShiftState);
  1081. begin
  1082.   case key of
  1083.     VK_ESCAPE:
  1084.       begin
  1085.         key := 0;
  1086.         visible := false;
  1087.         if owner is TWinControl then
  1088.           TWinControl(owner).setfocus;
  1089.       end;
  1090.   else
  1091.     inherited CalendarKeyMovement(sender, key, shift);
  1092.   end;
  1093. end;
  1094.  
  1095. procedure TrmScreenCalendar.WndProc(var Message: TMessage);
  1096. begin
  1097.   if assigned(fmsg) then
  1098.   try
  1099.     fmsg(message);
  1100.   except
  1101.   end;
  1102.  
  1103.   case Message.Msg of
  1104.     WM_CaptureKeyDown:
  1105.       begin
  1106.         Message.msg := wm_KeyDown;
  1107.       end;
  1108.     WM_CaptureKeyup:
  1109.       begin
  1110.         Message.msg := wm_KeyUp;
  1111.       end;
  1112.   end;
  1113.   inherited WndProc(Message);
  1114. end;
  1115.  
  1116. procedure TrmScreenCalendar.DoBtnClick(Sender: TObject);
  1117. var
  1118.   state: Word;
  1119. begin
  1120.   if Sender is TSpeedButton then
  1121.   begin
  1122.     state := GetKeyState(vk_control);
  1123.     case TSpeedButton(Sender).Tag of
  1124.       1:
  1125.         begin
  1126.           if (state and $8000 <> 0) then
  1127.             PrevYear
  1128.           else
  1129.             PrevMonth;
  1130.         end;
  1131.       2:
  1132.         begin
  1133.           if (state and $8000 <> 0) then
  1134.             NextYear
  1135.           else
  1136.             NextMonth;
  1137.         end;
  1138.     else
  1139.               //This should never happen.....
  1140.     end;
  1141.   end;
  1142. end;
  1143.  
  1144. procedure TrmScreenCalendar.DoPanelSize(Sender: TObject);
  1145. begin
  1146.   fBtn1.SetBounds(2, 2, 45, 16);
  1147.   fBtn2.SetBounds(fPanel.Width - 47, 2, 45, 16);
  1148. end;
  1149.  
  1150. end.
  1151.  
  1152.