Subversion Repositories delphiutils

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. unit FullYearCalendar;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Controls, ComCtrls;
  7.  
  8. // TODO: Buggy if you select a month directly (click at the month name)
  9. //       -- since the months are fixed, this functionality should be disabled by Windows!
  10. // TODO: Multiselect führt zu einem Fehler ...
  11. //       -- Grund: Das springen zum Jahresende und Jahresanfang
  12. //       -- Also: Only 30 days selectable
  13. // TODO: Die wahre Größe für 12 Monate feststellen ... wie?
  14. // TODO: MaxSelectRange sollte 365 oder 366 sein...
  15.  
  16. type
  17.   TFullYearCalendar = class(TMonthCalendar)
  18.   private
  19.     function GetDate: TDate;
  20.     procedure SetDate(Value: TDate);
  21.     function GetDateTime: TDateTime;
  22.     procedure SetDateTime(Value: TDateTime);
  23.     procedure CNNotify(var Message: TWMNotify); message CN_NOTIFY;
  24.   public
  25.     constructor Create(AOwner: TComponent); override;
  26.   protected
  27.     property DateTime: TDateTime read GetDateTime write SetDateTime;
  28.   published
  29.     property Date: TDate read GetDate write SetDate;
  30.   end;
  31.  
  32. procedure Register;
  33.  
  34. implementation
  35.  
  36. uses
  37.   DateUtils, CommCtrl;
  38.  
  39. function TFullYearCalendar.GetDate: TDate;
  40. begin
  41.   result := inherited Date;
  42. end;
  43.  
  44. procedure TFullYearCalendar.SetDate(Value: TDate);
  45. begin
  46.   if YearOf(Value) <> YearOf(Date) then
  47.   begin
  48.     // User has scrolled.
  49.     // The problem is, that the scrolling does not use Date as the source,
  50.     // instead it takes the left top month as source. So, every scrolling
  51.     // would set the month to January!
  52.  
  53.     if MonthOf(DateTime) <> 1 then
  54.     begin
  55.       Value := IncMonth(Value, MonthOf(DateTime)-1);
  56.     end;
  57.   end;
  58.  
  59.   // We want to have January always on left top!
  60.   // Warning: Does not work if the control is too small.
  61.   if not MultiSelect then
  62.   begin
  63.     inherited Date := EndOfTheYear(Value);
  64.     inherited Date := StartOfTheYear(Value);
  65.   end;
  66.  
  67.   // Then jump to our desired date
  68.   inherited Date := Value;
  69. end;
  70.  
  71. function TFullYearCalendar.GetDateTime: TDateTime;
  72. begin
  73.   result := Date;
  74. end;
  75.  
  76. procedure TFullYearCalendar.SetDateTime(Value: TDateTime);
  77. begin
  78.   Date := Value;
  79. end;
  80.  
  81. constructor TFullYearCalendar.Create(AOwner: TComponent);
  82. begin
  83.   inherited Create(AOwner);
  84.  
  85.   // Checked with Windows 2000
  86.   // Warning: Does not work if you use larger fonts!
  87.   // TODO: Is there any way to determinate the real width and height of a full year?
  88. //  Width := 666;
  89. //  Height := 579;
  90.   Width := 724;
  91.   Height := 500;
  92.  
  93.   Constraints.MinWidth := Width;
  94.   Constraints.MinHeight := Height;
  95.  
  96.   // Only jump in years
  97.   MonthDelta := 12;
  98. end;
  99.  
  100. procedure Register;
  101. begin
  102.   RegisterComponents('Beispiele', [TFullYearCalendar]);
  103. end;
  104.  
  105. // Copied from ComCtrls.pas
  106. function IsBlankSysTime(const ST: TSystemTime): Boolean;
  107. type
  108.   TFast = array [0..3] of DWORD;
  109. begin
  110.   Result := (TFast(ST)[0] or TFast(ST)[1] or TFast(ST)[2] or TFast(ST)[3]) = 0;
  111. end;
  112.  
  113. // Copied from ComCtrls.pas - modified
  114. // This is necessary, so that our "Date" will be changed when the user scrolls!
  115. procedure TFullYearCalendar.CNNotify(var Message: TWMNotify);
  116. var
  117.   ST: PSystemTime;
  118.   //I, MonthNo: Integer;
  119.   //CurState: PMonthDayState;
  120. begin
  121.   with Message, NMHdr^ do
  122.   begin
  123.     case code of
  124.       (* MCN_GETDAYSTATE:
  125.         with PNmDayState(NMHdr)^ do
  126.         begin
  127.           FillChar(prgDayState^, cDayState * SizeOf(TMonthDayState), 0);
  128.           if Assigned(FOnGetMonthInfo) then
  129.           begin
  130.             CurState := prgDayState;
  131.             for I := 0 to cDayState - 1 do
  132.             begin
  133.               MonthNo := stStart.wMonth + I;
  134.               if MonthNo > 12 then MonthNo := MonthNo - 12;
  135.               FOnGetMonthInfo(Self, MonthNo, CurState^);
  136.               Inc(CurState);
  137.             end;
  138.           end;
  139.         end; *)
  140.       MCN_SELECT, MCN_SELCHANGE:
  141.         begin
  142.           ST := @PNMSelChange(NMHdr).stSelStart;
  143.           if not IsBlankSysTime(ST^) then
  144.             (*F*)DateTime := SystemTimeToDateTime(ST^);
  145.           if (*F*)MultiSelect then
  146.           begin
  147.             ST := @PNMSelChange(NMHdr).stSelEnd;
  148.             if not IsBlankSysTime(ST^) then
  149.               (*F*)EndDate := SystemTimeToDateTime(ST^);
  150.           end;
  151.         end;
  152.     end;
  153.   end;
  154.   inherited;
  155. end;
  156.  
  157. end.
  158.