{********************************************************************}
{                                                                    }
{       Developer Express Visual Component Library                   }
{                   ExpressScheduler                                 }
{                                                                    }
{       Copyright (c) 2003-2005 Developer Express Inc.               }
{       ALL RIGHTS RESERVED                                          }
{                                                                    }
{   The entire contents of this file is protected by U.S. and        }
{   International Copyright Laws. Unauthorized reproduction,         }
{   reverse-engineering, and distribution of all or any portion of   }
{   the code contained in this file is strictly prohibited and may   }
{   result in severe civil and criminal penalties and will be        }
{   prosecuted to the maximum extent possible under the law.         }
{                                                                    }
{   RESTRICTIONS                                                     }
{                                                                    }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES            }
{   (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE     }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS    }
{   LICENSED TO DISTRIBUTE THE EXPRESSSCHEDULER AND ALL ACCOMPANYING }
{   VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.              }
{                                                                    }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED       }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE         }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE        }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT   }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                       }
{                                                                    }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON        }
{   ADDITIONAL RESTRICTIONS.                                         }
{                                                                    }
{********************************************************************}

unit cxSchedulerCustomResourceView;

{$I cxVer.inc}

interface

uses
  Windows, Graphics, SysUtils, StdCtrls, Classes, Forms, Controls, cxClasses, cxGraphics,
{$IFDEF DELPHI6}
  DateUtils, Variants,
{$ENDIF} cxGeometry, Math, cxStyles, cxEdit, cxContainer,
  cxSchedulerStorage, cxSchedulerUtils, cxSchedulerCustomControls, cxLookAndFeelPainters,
  cxDateUtils, ImgList, cxEditUtils;

const
  // default values
  cxTimeLineWidth: Integer = 7;
  cxEventImagesOffset = 1;
  cxEventBorderWidth = 1;

  cxHitDelta: Integer = 4;

  // hittest constants
  htcButton         = $3;
  htcContainer      = $4;
  htcTimeRuler      = $5;
  htcTimeZoneLabel =  $6;
  htcContent        = $7;
  htcDayHeader      = $8;
  htcGroupSeparator = $9;
  htcResourceHeader = $10;

type
  TcxSchedulerCustomViewInfoItem = class;
  TcxSchedulerCustomResourceViewViewInfo = class;
  TcxSchedulerCustomResourceViewHitTest = class;
  TcxSchedulerBackgroundCellViewInfo = class;
  TcxSchedulerContentCellViewInfo = class;
  TcxSchedulerDayHeaderCellViewInfo = class;
  TcxSchedulerEventCellViewInfo = class;
  TcxSchedulerGroupSeparatorCellViewInfo = class;
  TcxSchedulerHeaderCellViewInfo = class;
  TcxSchedulerMoreEventsButtonViewInfo = class;
  TcxSchedulerResourceViewInfo = class;
  TcxCustomResourceViewAdapter = class;
  TcxSchedulerEventLayoutBuilder = class;
  TcxSchedulerEventImages = class;

  // custom draw event types definition

  TcxSchedulerCustomDrawBackgroundEvent = procedure(Sender: TObject; ACanvas: TcxCanvas;
    AViewInfo: TcxSchedulerBackgroundCellViewInfo; var ADone: Boolean) of object;

  TcxSchedulerCustomDrawButtonEvent = procedure(Sender: TObject; ACanvas: TcxCanvas;
    AViewInfo: TcxSchedulerMoreEventsButtonViewInfo; var ADone: Boolean) of object;

  TcxSchedulerCustomDrawDayHeaderEvent = procedure(Sender: TObject; ACanvas: TcxCanvas;
    AViewInfo: TcxSchedulerDayHeaderCellViewInfo; var ADone: Boolean) of object;

  TcxSchedulerCustomDrawResourceHeaderEvent = procedure(Sender: TObject; ACanvas: TcxCanvas;
    AViewInfo: TcxSchedulerHeaderCellViewInfo; var ADone: Boolean) of object;

  TcxSchedulerCustomDrawContentEvent = procedure(Sender: TObject; ACanvas: TcxCanvas;
    AViewInfo: TcxSchedulerContentCellViewInfo; var ADone: Boolean) of object;

  TcxSchedulerCustomDrawEventEvent = procedure(Sender: TObject; ACanvas: TcxCanvas;
    AViewInfo: TcxSchedulerEventCellViewInfo; var ADone: Boolean) of object;

  TcxSchedulerCustomDrawGroupSeparatorEvent = procedure(Sender: TObject; ACanvas: TcxCanvas;
    AViewInfo: TcxSchedulerGroupSeparatorCellViewInfo; var ADone: Boolean) of object;

  { IcxSchedulerCommonViewItemsPainter }

  IcxSchedulerCommonViewItemsPainter = interface
  ['{0702AB17-C2F1-479D-B809-C3B972F8A334}']
    procedure DoCustomDrawBackground(
      AViewInfo: TcxSchedulerBackgroundCellViewInfo; var ADone: Boolean);
    procedure DoCustomDrawButton(
      AViewInfo: TcxSchedulerMoreEventsButtonViewInfo; var ADone: Boolean);
    procedure DoCustomDrawContent(
      AViewInfo: TcxSchedulerContentCellViewInfo; var ADone: Boolean);
    procedure DoCustomDrawDayHeader(
      AViewInfo: TcxSchedulerDayHeaderCellViewInfo; var ADone: Boolean);
    procedure DoCustomDrawEvent(
      AViewInfo: TcxSchedulerEventCellViewInfo; var ADone: Boolean);
    procedure DoCustomDrawGroupSeparator(
      AViewInfo: TcxSchedulerGroupSeparatorCellViewInfo; var ADone: Boolean);
    procedure DoCustomDrawResourceHeader(
      AViewInfo: TcxSchedulerHeaderCellViewInfo; var ADone: Boolean);
  end;

  { IcxSchedulerEventImages }

  IcxSchedulerEventImages = interface
  ['{4C5A8F8B-5356-4D2B-9972-507A7D60954A}']
    procedure DoInitEventImages(AEvent: TcxSchedulerControlEvent;
      AImages: TcxSchedulerEventImages);
    function GetImages: TImageList;
    function SupportEventImages: Boolean;
  end;

  { TcxSchedulerViewInfoCellList }

  TcxSchedulerCustomDrawItemProc = procedure(
    AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean) of object;

  TcxSchedulerViewInfoCellList = class(TList)
  private
    function GetItem(AIndex: Integer): TcxSchedulerCustomViewInfoItem;
  public
    function CalculateHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest): Boolean;
    procedure Clear; override;
    procedure Draw(ACanvas: TcxCanvas; ADrawItemProc: TcxSchedulerCustomDrawItemProc);
    
    property Items[Index: Integer]: TcxSchedulerCustomViewInfoItem read GetItem; default;
  end;

  { TcxSchedulerCustomViewInfoItem }

  TcxSchedulerCustomViewInfoItem = class
  private
    function GetBitmap: TBitmap;
    function GetColor: TColor;
    function GetDateTimeHelper: TcxSchedulerDateTimeHelperClass;
    function GetPainterHelper: TcxSchedulerPainterHelperClass;
    function GetTextColor: TColor;
    procedure SetBitmap(AValue: TBitmap);
    procedure SetColor(AValue: TColor);
    procedure SetTextColor(AValue: TColor);
  protected
    FBackgroundDrawing: Boolean;
    FBounds: TRect;
    FBorders: TcxBorders;
    FCanvas: TcxCanvas;
    FClipRect: TRect;
    FClipRgn: TcxRegion;
    FClipRef: Integer;
    FDateTime: TDateTime;
    FDisplayText: string;
    FHasClipping: Boolean;
    FPainter: TcxCustomLookAndFeelPainterClass;
    FSavedClipRgn: TcxRegion;
    FTransparent: Boolean;
    FViewParams: TcxViewParams;
    FVisible: Boolean;
    FDayBorderColor: TColor;
    procedure CalculateCellBounds(const ABounds, AVisibleRect: TRect);
    procedure ClippingCreate(AHasClipping: Boolean); virtual;
    procedure ClippingRestore;
    procedure DoDraw; virtual; abstract;
    function DrawBackground(ACanvas: TcxCanvas; const ABounds: TRect): Boolean; virtual;
    procedure DrawFrame(const ARect: TRect; ABorders: TcxBorders = [];
      ABorderColor: TColor = clDefault; ALineWidth: Integer = 1);
    procedure DrawRect(const ARect: TRect; ABorders: TcxBorders = [];
      ABorderColor: TColor = clDefault; ALineWidth: Integer = 1);
    procedure DrawText(const ARect: TRect; const AText: string;
      AFlags: Integer; AFont: TFont = nil; AColor: TColor = clDefault);
    function GetFont: TFont; virtual;
    function GetHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest; var ABreak: Boolean): Boolean; virtual;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); virtual;
    procedure RotateBitmap(ABitmap: TBitmap; ARotationAngle: TcxRotationAngle; AFlipHorizontally: Boolean = False);
    // custom draw support
    procedure AfterCustomDraw(ACanvas: TcxCanvas); virtual;
    procedure BeforeCustomDraw(ACanvas: TcxCanvas); virtual;

    // class item settings
    property DateTimeHelper: TcxSchedulerDateTimeHelperClass read GetDateTimeHelper;
    property DisplayText: string read FDisplayText write FDisplayText;
    property PainterHelper: TcxSchedulerPainterHelperClass read GetPainterHelper;
  public
    constructor Create(APainter: TcxCustomLookAndFeelPainterClass;
      const ABounds, AVisibleRect: TRect; const AViewParams: TcxViewParams); virtual;
    destructor Destroy; override;
    procedure Draw(ACanvas: TcxCanvas); virtual;

    property Borders: TcxBorders read FBorders write FBorders;
    property Bounds: TRect read FBounds;
    property Bitmap: TBitmap read GetBitmap write SetBitmap;
    property Canvas: TcxCanvas read FCanvas;
    property ClipRect: TRect read FClipRect;
    property Color: TColor read GetColor write SetColor;
    property Font: TFont read GetFont;
    property Painter: TcxCustomLookAndFeelPainterClass read FPainter;
    property TextColor: TColor read GetTextColor write SetTextColor;
    property Transparent: Boolean read FTransparent write FTransparent;
    property ViewParams: TcxViewParams read FViewParams;
    property Visible: Boolean read FVisible;
  end;

  { TcxSchedulerBackgroundCellViewInfo }

  TcxSchedulerBackgroundCellViewInfo = class(TcxSchedulerCustomViewInfoItem)
  protected
    procedure DoDraw; override;
  end;

//  TcxSchedulerContentCellViewInfo = class;


  TcxSchedulerCustomViewInfoItemClass = class of TcxSchedulerCustomViewInfoItem;

  { TcxSchedulerCustomResourceViewInfoItem }

  TcxSchedulerCustomResourceViewInfoItem = class(TcxSchedulerCustomViewInfoItem)
  private
    FIsResourceAssigned: Boolean;
    FTimeFinish: TDateTime;
    FResource: TcxSchedulerResourceViewInfo;
  protected
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;

    property DateTime: TDateTime read FDateTime write FDateTime;
    property IsResourceAssigned: Boolean read FIsResourceAssigned;
    property Resource: TcxSchedulerResourceViewInfo read FResource write FResource;
    property TimeFinish: TDateTime read FTimeFinish;
  end;

  { TcxSchedulerHeaderCellViewInfo }

  TcxSchedulerHeaderCellViewInfo = class(TcxSchedulerCustomResourceViewInfoItem)
  private
    function GetHeight: Integer;
    function GetWidth: Integer;
  protected
    DisplayBounds: TRect;
    FAlignHorz: TAlignment;
    FAlignVert: TcxAlignmentVert;
    FAutoHeight: Boolean;
    FButtonState: TcxButtonState;
    FCachedBitmap: TBitmap;
    FDrawRotatedBackground: Boolean;
    FImageIndex: Integer;
    FImagePosition: TcxSchedulerHeaderImagePosition;
    FImages: TImageList;
    FImageRectAssigned: Boolean;
    FImageRect: TRect;
    FIsResourceHeader: Boolean;
    FMultiLine: Boolean;
    FNeighbors: TcxNeighbors;
    FRotateBitmap: TBitmap;
    FRotateHeader: Boolean;
    FRotateText: Boolean;
    FSelected: Boolean;
    FSelectionColor: TColor;
    FSelectionRect: TRect;
    FSelectionTextColor: TColor;
    FShowEndEllipsis: Boolean;
    FTextRect: TRect;
    procedure CalculateImageLayout;
    procedure CheckNeighbor(APrevCell: TcxSchedulerHeaderCellViewInfo);
    function CheckSelection: Boolean; virtual;
    procedure DoDraw; override;
    procedure DrawCaption(ACanvas: TcxCanvas = nil);
    procedure DrawHorizontalHeader; virtual;
    function DrawRotateBackground(ACanvas: TcxCanvas; const ABounds: TRect): Boolean; virtual;
    procedure DrawVerticalHeader; virtual;
    function GetTextOutcxFlags: Integer;
    function GetTextOutFlags: Integer;
    function HasImage: Boolean;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
    procedure TextOut(ACanvas: TcxCanvas; const AText: string; R: TRect);
    procedure ValidateSelection;

    property Height: Integer read GetHeight;
    property Width: Integer read GetWidth;
  public
    constructor Create(APainter: TcxCustomLookAndFeelPainterClass;
      const ABounds, AVisibleRect: TRect; const AViewParams: TcxViewParams); override;
    destructor Destroy; override;
    procedure Calculate(const AText: string); virtual;
    procedure Draw(ACanvas: TcxCanvas); override;

    property AlignHorz: TAlignment read FAlignHorz write FAlignHorz;
    property AlignVert: TcxAlignmentVert read FAlignVert write FAlignVert;
    property AutoHeight: Boolean read FAutoHeight;
    property DateTime: TDateTime read FDateTime write FDateTime;
    property ImageIndex: Integer read FImageIndex;
    property ImagePosition: TcxSchedulerHeaderImagePosition read FImagePosition;
    property ImageRect: TRect read FImageRect;
    property Images: TImageList read FImages;
    property IsResourceHeader: Boolean read FIsResourceHeader;
    property MultiLine: Boolean read FMultiLine write FMultiLine;
    property Neighbors: TcxNeighbors read FNeighbors write FNeighbors;
    property RotateHeader: Boolean read FRotateHeader write FRotateHeader;
    property RotateText: Boolean read FRotateText write FRotateText;
    property Selected: Boolean read FSelected write FSelected;
    property SelectionColor: TColor read FSelectionColor write FSelectionColor;
    property SelectionTextColor: TColor read FSelectionTextColor write FSelectionTextColor;
    property ShowEndEllipsis: Boolean read FShowEndEllipsis write FShowEndEllipsis;
    property TextRect: TRect read FTextRect;
    property Bounds;
    property DisplayText;
    property Painter;
    property Resource;
  end;

  { TcxSchedulerDayHeaderCellViewInfo }

  TcxSchedulerDayHeaderCellViewInfo = class(TcxSchedulerHeaderCellViewInfo)
  private
    FCompressed: Boolean;
  protected
    function CheckSelection: Boolean; override;
    procedure DoDraw; override;
    function DrawBackground(ACanvas: TcxCanvas; const ABounds: TRect): Boolean; override;
  public
    function ConvertDateToDisplayText(AType: Integer = 0): Integer; virtual;
    
    property Compressed: Boolean read FCompressed write FCompressed;
  end;

  { TcxSchedulerWeekDayHeaderCellViewInfo }

  TcxSchedulerWeekDayHeaderCellViewInfo = class(TcxSchedulerDayHeaderCellViewInfo)
  protected
    function GetDayText(AType: Integer): string;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
  public
    function ConvertDateToDisplayText(AType: Integer = 0): Integer; override;
  end;

  { TcxSchedulerContainerCellViewInfo }

  TcxSchedulerContainerCellViewInfo = class(TcxSchedulerCustomResourceViewInfoItem)
  protected
    FLineCount: Integer;
    FSelected: Boolean;
    procedure DoDraw; override;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
  public
    property LineCount: Integer read FLineCount write FLineCount;
    property DateTime;
    property Resource;
    property Selected: Boolean read FSelected write FSelected;
  end;

  { TcxSchedulerTimeRulerCellViewInfo }

  TcxSchedulerTimeRulerCellViewInfo = class(TcxSchedulerCustomViewInfoItem)
  private
    FLastVisibleHour: Boolean;
    function GetBoundsRect(AType: Boolean): TRect;
    function GetDisplayText(AType: Boolean): string;
    function GetHasAdditionalTimeZone: Boolean;
  protected
    FAdditionalTimeZone: Integer;
    FBounds: array[Boolean] of TRect;
    FDisplayTexts: array[Boolean] of string;
    FHour: Integer;
    FLargeFont: TFont;
    FLineCount: Integer;
    FShowMinutes: Boolean;
    FTimeZone: Integer;
    procedure CalculateDisplayInfo;
    procedure DoDraw; override;
    procedure DrawTimeZone(const ABounds: TRect; const AText: string; AIsCurrent: Boolean); virtual;
    procedure DrawTimeZoneLabel(const ABounds: TRect; const AText: string; ABorders: TcxBorders); virtual;
    procedure DrawCurrentTime(const AStart: TDateTime; ABounds: TRect);
    function GetAdditionalTime: TDateTime;
    function GetTimeDisplayText(const ATime: TDateTime): string;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
    //
    procedure AfterCustomDraw(ACanvas: TcxCanvas); override;
  public
    class function CalculateWidth(ATimeZoneCount, ALineCount: Integer; AFont1, AFont2: TFont): Integer;
    procedure Calculate(const ALabel1, ALabel2: string; ATimeZone, AAdditionalTimeZone: Integer); overload; virtual;
    procedure Calculate(AHour, ALineCount: Integer; ATimeZone, AAdditionalTimeZone: Integer; ALargeFont: TFont); overload; virtual;
    procedure SetBottom(AValue: Integer);

    property AdditionalTimeZone: Integer read FAdditionalTimeZone;
    property Bounds[ACurrentTimeZone: Boolean]: TRect read GetBoundsRect;
    property DisplayTexts[ACurrentTimeZone: Boolean]: string read GetDisplayText;
    property HasAdditionalTimeZone: Boolean read GetHasAdditionalTimeZone;
    property Hour: Integer read FHour;
    property LargeFont: TFont read FLargeFont;
    property LastVisibleHour: Boolean read FLastVisibleHour write FLastVisibleHour;  
    property LineCount: Integer read FLineCount;
    property ShowMinutes: Boolean read FShowMinutes write FShowMinutes;
    property TimeZone: Integer read FTimeZone;
  end;

  { TcxSchedulerContentCellViewInfo }

  TcxSchedulerContentCellViewInfo = class(TcxSchedulerCustomResourceViewInfoItem)
  protected
    FBorderColor: TColor;
    FDontPrint: Boolean;
    FLineCount: Integer;
    FShowTimeLine: Boolean;
    FTimeEvent: TcxSchedulerEventCellViewInfo;
    FTimeLineBorders: TcxBorders;
    FTimeLineParams: TcxViewParams;
    procedure DoDraw; override;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
  public
    constructor Create(APainter: TcxCustomLookAndFeelPainterClass;
      const ABounds, AVisibleRect: TRect; const AViewParams: TcxViewParams); override;
    procedure SetTime(const ATimeStart, ATimeFinish: TDateTime);
    
    property BorderColor: TColor read FBorderColor write FBorderColor;
    property DontPrint: Boolean read FDontPrint write FDontPrint;
    property LineCount: Integer read FLineCount write FLineCount;
    property ShowTimeLine: Boolean read FShowTimeLine write FShowTimeLine;
    property TimeEvent: TcxSchedulerEventCellViewInfo read FTimeEvent write FTimeEvent;
    property TimeLineBorders: TcxBorders read FTimeLineBorders write FTimeLineBorders;
    property TimeLineParams: TcxViewParams read FTimeLineParams write FTimeLineParams;
    property TimeStart: TDateTime read FDateTime;
    property TimeFinish;
    property Resource;
  end;

  TcxSchedulerContentCellViewInfoClass = class of TcxSchedulerContentCellViewInfo;

 { TcxSchedulerBackgroundSlotCellViewInfo }

  TcxSchedulerBackgroundSlotCellViewInfo = class(TcxSchedulerContentCellViewInfo)
  protected
    procedure DoDraw; override;
  public
    property DisplayText;
  end;

  { TcxSchedulerMonthDayContentCellViewInfo }

  TcxSchedulerMonthDayContentCellViewInfo = class(TcxSchedulerContentCellViewInfo)
  private
    FSelected: Boolean;
    FSelectionColor: TColor;
    FSelectionTextColor: TColor;
    FTextHeight: Integer;
    function GetIsToday: Boolean;
    procedure SetSmallTextFont(AFont: TFont);
  protected
    FTextRect: TRect;
    FSmallFont: Boolean;
    FSmallFontCreated: Boolean;
    FSmallTextFont: TFont;
    procedure DoDraw; override;
    function GetLongDisplayText: string; virtual;
    property IsToday: Boolean read GetIsToday;
  public
    destructor Destroy; override;
    procedure SetContentState(AsDayOfMonth: Boolean; ASelected: Boolean;
      ATextHeight: Integer; const ASelectionParams: TcxViewParams);
    function UpdateSelection(ASelected: Boolean): Boolean;

    property DisplayText;
    property SmallFont: Boolean read FSmallFont;
    property SmallTextFont: TFont read FSmallTextFont write SetSmallTextFont;
    property Selected: Boolean read FSelected;
    property SelectionColor: TColor read FSelectionColor write FSelectionColor;
    property SelectionTextColor: TColor read FSelectionTextColor write FSelectionTextColor;
    property TextHeight: Integer read FTextHeight write FTextHeight;
  end;

  TcxSchedulerEventImagesLayout = (eilAuto, eilHorizontal, eilVertical);

  { TcxSchedulerEventViewData }

  TcxSchedulerEventViewData = class
  public
    AlwaysShowTime: Boolean;
    AutoHeight: Boolean;
    Bitmap: TBitmap;
    BorderColor: TColor;
    Bounds: TRect;
    Canvas: TcxCanvas;
    Caption: string;
    ContentFinish: TDateTime;
    ContentStart: TDateTime;
    DrawShadows: Boolean;
    EditProperties: TcxCustomEditProperties;
    EditStyle: TcxCustomEditStyle;
    Event: TcxSchedulerControlEvent;
    ImagesLayout: TcxSchedulerEventImagesLayout;
    LineHeight: Integer;
    MaxHeight: Integer;
    Painter: TcxCustomLookAndFeelPainterClass;
    Resource: TcxSchedulerResourceViewInfo;
    ShowFinishTime: Boolean;
    ShowStartTime: Boolean;
    ShowTimeAsClock: Boolean;
    ShowTimeLine: Boolean;
    StartLine: Integer;
    TimeLineParams: TcxViewParams;
    ViewParams: TcxViewParams;
    VisibleRect: TRect;
  end;

  { TcxSchedulerEventCellViewInfo }

  TcxSchedulerEventCellViewInfo = class(TcxSchedulerCustomViewInfoItem)
  private
    FEventFinish: TDateTime;
    FEventStart: TDateTime;
    FIsHeaderEvent: Boolean;
    function CalculateMessageHeight(const R: TRect): Integer;
    function GetBorderColor: TColor;
    function GetCaption: string;
    function GetCaptionBounds(const R: TRect): TRect;
    function GetContentFinish: TDateTime;
    function GetContentStart: TDateTime;
    function GetEvent: TcxSchedulerControlEvent;
    function GetIsHeaderEvent: Boolean;
    function GetMessage: string;
    function GetResourceInfo: TcxSchedulerResourceViewInfo;
    function GetResourceItem: TcxSchedulerStorageResourceItem;
    function GetSelected: Boolean;
    function GetShowingState(AIndex: Integer): Boolean;
    procedure SetBorderColor(AValue: TColor);
  protected
    FCaptionRect: TRect;
    FEditViewInfo: TcxCustomEditViewInfo;
    FFinishRect: TRect;
    FFinishText: string;
    FHidden: Boolean;
    FImages: TcxSchedulerEventImages;
    FMessageRect: TRect;
    FHintNeeded: Boolean;
    FHintNeededCalculated: Boolean;
    FSeparatorColor: TColor;
    FShowMessage: Boolean;
    FStartRect: TRect;
    FStartText: string;
    FEventTimeRect: TRect;
    FTimeLineRect: TRect;
    FIsDetailCaption: Boolean;
    FIsDetailInfo: Boolean;
    ViewData: TcxSchedulerEventViewData;
    procedure AssignEditStyle(AEditStyle: TcxCustomEditStyle);
    procedure BeforeCustomDraw(ACanvas: TcxCanvas); override;
    procedure Calculate;
    procedure CalculateBorders; virtual;
    procedure CalculateCaptions; virtual;
    procedure CalculateDetailInfo; virtual;
    procedure CalculateNeedHint;
    procedure CalculateEditViewInfo;
    procedure CalculateShowTimeAsClock; virtual;
    //items layout

    function CalculateAutoLayoutImagesAutoHeight(AVisibleImages: TList): Integer;
    function CalculateHorizontalImagesAutoHeight: Integer;
    procedure CalculateMessageAutoLayout(var AHeight: Integer);
    function CalculateVerticalImagesAutoHeight: Integer;

    procedure CalculateItemsLayout; virtual;
    procedure CalculateDetailViewEventLayout;
    procedure CalculateHeaderEventLayout;
    procedure CalculateNonDetailEventLayout;
    procedure CalculateEventTimeAsClockLayout(const ABounds: TRect;
      const ACaptionWidth, AImagesWidth: Integer; var ALeft: Integer); virtual;
    procedure CalculateEventTimeAsTextLayout(const ABounds: TRect;
      const ACaptionWidth, AImagesWidth: Integer; var ALeft: Integer); virtual;
    function CalculateNonDetailEventImages(const ACaptionWidth: Integer;
      out AImagesWidth: Integer): TRect; virtual;
    function CalculateSingleLineImages(const ABounds: TRect; ARightLimit: Integer = 0): Integer;
    function SetItemRect(AShowItem: Boolean; const ABounds: TRect;
      AVertOffset: Integer; var APos: Integer): TRect;
    //time visibility
    procedure CalculateEventTimeVisibility; virtual;
    procedure CalculateDetailEventTimeVisibility; virtual;
    procedure CalculateNonDetailEventTimeVisibility; virtual;
    procedure CalculateVisibility; virtual;
    function CanAutoHideStandardImages: Boolean; virtual;

    procedure DoDraw; override;
    procedure DrawCaption;
    procedure DrawContent; virtual;
    procedure DrawImages;
    procedure DrawMessageSeparator;
    procedure DrawTime;
    function GetCaptionAutoHeight(const R: TRect): Integer;
    function GetEditingRect: TRect; virtual;
    function GetForceShowClockInHeaderEvent: Boolean; virtual;
    function GetHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest; var ABreak: Boolean): Boolean; override;
    function GetImagesBounds: TRect;
    function GetImagesVerticalOffset(AImageHeight: Integer; AIsAbsolute: Boolean): Integer;
    function GetMessageRect(const ACaptionRect: TRect; AHasImages: Boolean): TRect;
    procedure Initialize; virtual;
    //hittest
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
    procedure InitHitTestForHorzEvent(AHitTest: TcxSchedulerCustomResourceViewHitTest);

    procedure InitStandardEventImages;
    function IsHorzSizing: Boolean; virtual;
    function IsNeedDrawTime: Boolean; virtual;
    function IsTimeLineVisible: Boolean; virtual;
    function TruncTime(const ATime: TDateTime): TDateTime;

    property EventFinish: TDateTime read FEventFinish;
    property EventStart: TDateTime read FEventStart;
    property IsHeaderEvent: Boolean read FIsHeaderEvent;
    property IsDetailCaption: Boolean read FIsDetailCaption;
  public
    constructor Create(AViewData: TcxSchedulerEventViewData); reintroduce; virtual;
    destructor Destroy; override;

    procedure Draw(ACanvas: TcxCanvas; ABitmap: TBitmap); reintroduce; overload;
    procedure DrawState(ACanvas: TcxCanvas; const ARect: TRect; ABorders: TcxBorders; ABorderColor: TColor); overload;
    function MeasureHeight(ACanvas: TcxCanvas): Integer; virtual;
    procedure MoveTo(X, Y: Integer); virtual;

    property BorderColor: TColor read GetBorderColor write SetBorderColor;
    property Caption: string read GetCaption;
    property CaptionRect: TRect read FCaptionRect;
    property ClipRect: TRect read FClipRect;
    property ClipRgn: TcxRegion read FClipRgn write FClipRgn;
    property ContentFinish: TDateTime read GetContentFinish;
    property ContentStart: TDateTime read GetContentStart;
    property EditingRect: TRect read GetEditingRect;
    property EditViewInfo: TcxCustomEditViewInfo read FEditViewInfo;
    property Event: TcxSchedulerControlEvent read GetEvent;
    property EventTimeRect: TRect read FEventTimeRect;
    property EventViewData: TcxSchedulerEventViewData read ViewData;
    property FinishRect: TRect read FFinishRect;
    property FinishText: string read FFinishText;
    property Hidden: Boolean read FHidden write FHidden;
    property Images: TcxSchedulerEventImages read FImages;
    property IsDetailInfo: Boolean read FIsDetailInfo;
    property Message: string read GetMessage;
    property MessageRect: TRect read FMessageRect;
    property ResourceInfo: TcxSchedulerResourceViewInfo read GetResourceInfo;
    property ResourceItem: TcxSchedulerStorageResourceItem read GetResourceItem;
    property Selected: Boolean read GetSelected;
    property SeparatorColor: TColor read FSeparatorColor write FSeparatorColor;
    property ShowFinishTime: Boolean index 0 read GetShowingState;
    property ShowMessage: Boolean read FShowMessage;
    property ShowStartTime: Boolean index 1 read GetShowingState;
    property ShowTimeAsClock: Boolean index 2 read GetShowingState;
    property ShowTimeLine: Boolean index 3 read GetShowingState;
    property StartRect: TRect read FStartRect;
    property StartText: string read FStartText;
    property TimeLineRect: TRect read FTimeLineRect write FTimeLineRect;
    property Visible: Boolean read FVisible;
  end;

  { TcxSchedulerMoreEventsButtonViewInfo }

  TcxSchedulerMoreEventsButtonClick = procedure (Sender: TcxSchedulerMoreEventsButtonViewInfo) of object;

  TcxSchedulerMoreEventsButtonViewInfo = class(TcxSchedulerCustomResourceViewInfoItem)
  protected
    FIsDown: Boolean;
    FOnClick: TcxSchedulerMoreEventsButtonClick;
    procedure DoDraw; override;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
    property OnClick: TcxSchedulerMoreEventsButtonClick read FOnClick write FOnClick;
  public
    procedure Click; virtual;

    property IsDown: Boolean read FIsDown;
    property DateTime;
    property Resource;
  end;

  { TcxSchedulerGroupSeparatorCellViewInfo }

  TcxSchedulerGroupSeparatorCellViewInfo = class(TcxSchedulerCustomViewInfoItem)
  private
    FDrawRotatedBackground: Boolean;
    FRotated: Boolean;
    function DrawRotateBackground(ACanvas: TcxCanvas; const ABounds: TRect): Boolean;
  protected
    FRotateBitmap: TBitmap;
    procedure DoDraw; override;
    procedure InitHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override;
  public
    destructor Destroy; override;
    property Rotated: Boolean read FRotated write FRotated;
  end;

  { TcxSchedulerResourceViewInfo }

  TcxSchedulerResourceViewInfo = class
  protected
    FCaption: string;
    FColor: TColor;
    FImageIndex: Integer;
    FImagePosition: TcxSchedulerHeaderImagePosition;
    FImages: TImageList;
    FResourceID: Variant;
    FResourceItem: TcxSchedulerStorageResourceItem;
    FTextRect: TRect;
  public
    constructor Create(AResource: TcxSchedulerStorageResourceItem); virtual;

    property Caption: string read FCaption;
    property Color: TColor read FColor;
    property ImageIndex: Integer read FImageIndex;
    property ImagePosition: TcxSchedulerHeaderImagePosition read FImagePosition;
    property Images: TImageList read FImages;
    property ResourceID: Variant read FResourceID;
    property ResourceItem: TcxSchedulerStorageResourceItem read FResourceItem;
    property TextRect: TRect read FTextRect write FTextRect; 
  end;

  { TcxSchedulerCustomResourceView }

  TcxSchedulerCustomResourceView = class(TcxSchedulerCustomView)
  private
    FAdapter: TcxCustomResourceViewAdapter;
    FGroupingKind: TcxSchedulerGroupingKind;
    FEventImagesLayout: TcxSchedulerEventImagesLayout;
    FShowEndTime: Boolean;
    FShowTimeAsClock: Boolean;
    FOnCustomDrawBackground: TcxSchedulerCustomDrawBackgroundEvent;
    FOnCustomDrawButton: TcxSchedulerCustomDrawButtonEvent;
    FOnCustomDrawContent: TcxSchedulerCustomDrawContentEvent;
    FOnCustomDrawDayHeader: TcxSchedulerCustomDrawDayHeaderEvent;
    FOnCustomDrawEvent: TcxSchedulerCustomDrawEventEvent;
    FOnCustomDrawGroupSeparator: TcxSchedulerCustomDrawGroupSeparatorEvent;
    FOnCustomDrawResourceHeader: TcxSchedulerCustomDrawResourceHeaderEvent;
    function GetViewInfo: TcxSchedulerCustomResourceViewViewInfo;
    procedure SetEventImagesLayout(const AValue: TcxSchedulerEventImagesLayout);
    procedure SetGroupingKind(AValue: TcxSchedulerGroupingKind);
    procedure SetShowEndTime(const AValue: Boolean);
    procedure SetShowTimeAsClock(const AValue: Boolean);
  protected
    procedure CalculateViewInfo; override;
    procedure CheckGroupingKind(AStyle: TcxSchedulerGroupingKind;
      var ActuallyStyle: TcxSchedulerGroupingKind); virtual;
    function CreateController: TcxSchedulerSubControlController; override;
    function CreateHitTest: TcxSchedulerSubControlHitTest; override;
    function CreateViewAdapter: TcxCustomResourceViewAdapter; virtual;
    procedure CreateSubClasses; override;
    procedure DestroySubClasses; override;
    procedure DoCustomDrawBackground(
      AViewInfo: TcxSchedulerBackgroundCellViewInfo; var ADone: Boolean); virtual;
    procedure DoCustomDrawButton(
      AViewInfo: TcxSchedulerMoreEventsButtonViewInfo; var ADone: Boolean); virtual;
    procedure DoCustomDrawContent(
      AViewInfo: TcxSchedulerContentCellViewInfo; var ADone: Boolean); virtual;
    procedure DoCustomDrawDayHeader(
      AViewInfo: TcxSchedulerDayHeaderCellViewInfo; var ADone: Boolean); virtual;
    procedure DoCustomDrawEvent(
      AViewInfo: TcxSchedulerEventCellViewInfo; var ADone: Boolean); virtual;
    procedure DoCustomDrawGroupSeparator(
      AViewInfo: TcxSchedulerGroupSeparatorCellViewInfo; var ADone: Boolean); virtual;
    procedure DoCustomDrawResourceHeader(
      AViewInfo: TcxSchedulerHeaderCellViewInfo; var ADone: Boolean); virtual;
    procedure DoLayoutChanged; override;
    function DoShowPopupMenu(X, Y: Integer): Boolean; override;
    function FindEventViewInfo(AEvent: TcxSchedulerEvent; const ADate: TDateTime;
      AResource: TcxSchedulerStorageResourceItem; var AViewInfo: TcxSchedulerEventCellViewInfo): Boolean;
    function GetCommonViewItemsPainter: IcxSchedulerCommonViewItemsPainter; virtual;
    function GetCompressWeekEnd: Boolean; virtual;
    function GetEditRectForEvent(AEvent: TcxSchedulerControlEvent; const ADate: TDateTime;
      AResource: TcxSchedulerStorageResourceItem): TRect; override;
    function GetEventVisibility(AEvent: TcxSchedulerControlEvent): Boolean; override;
    function GetGroupingKind: TcxSchedulerGroupingKind; override;
    procedure InitScrollBarsParameters; override;
    function IsShowResources: Boolean; override;
    procedure Scroll(AScrollBarKind: TScrollBarKind;
      AScrollCode: TScrollCode; var AScrollPos: Integer); override;

    property Adapter: TcxCustomResourceViewAdapter read FAdapter write FAdapter;
    property EventImagesLayout: TcxSchedulerEventImagesLayout read FEventImagesLayout write SetEventImagesLayout;
    property ShowEndTime: Boolean read FShowEndTime write SetShowEndTime default True;
    property ShowTimeAsClock: Boolean read FShowTimeAsClock write SetShowTimeAsClock default False;
    property ViewInfo: TcxSchedulerCustomResourceViewViewInfo read GetViewInfo;

    property OnCustomDrawBackground: TcxSchedulerCustomDrawBackgroundEvent read FOnCustomDrawBackground write FOnCustomDrawBackground;
    property OnCustomDrawButton: TcxSchedulerCustomDrawButtonEvent read FOnCustomDrawButton write FOnCustomDrawButton;
    property OnCustomDrawContent: TcxSchedulerCustomDrawContentEvent read FOnCustomDrawContent write FOnCustomDrawContent;
    property OnCustomDrawDayHeader: TcxSchedulerCustomDrawDayHeaderEvent read FOnCustomDrawDayHeader write FOnCustomDrawDayHeader;
    property OnCustomDrawEvent: TcxSchedulerCustomDrawEventEvent read FOnCustomDrawEvent write FOnCustomDrawEvent;
    property OnCustomDrawGroupSeparator: TcxSchedulerCustomDrawGroupSeparatorEvent read FOnCustomDrawGroupSeparator write FOnCustomDrawGroupSeparator;
    property OnCustomDrawResourceHeader: TcxSchedulerCustomDrawResourceHeaderEvent read FOnCustomDrawResourceHeader write FOnCustomDrawResourceHeader;
  public
    constructor Create(AOwner: TcxCustomScheduler); override;
    procedure Assign(Source: TPersistent); override;

    property GroupingKind: TcxSchedulerGroupingKind read FGroupingKind write SetGroupingKind default gkDefault;
  end;

  { TcxCustomResourceViewAdapter }

  TcxCustomResourceViewAdapter = class
  private
    FView: TcxSchedulerCustomResourceView;

    function GetCells: TcxObjectList;
    function GetContentLineHeight: Integer;
    function GetPainterHelper: TcxSchedulerPainterHelperClass;
    function GetResourceNavigator: TcxSchedulerResourceNavigator;
    function GetResources: TcxSchedulerStorageResourceItems;
    function GetScheduler: TcxCustomScheduler;
    function GetViewInfo: TcxSchedulerCustomResourceViewViewInfo;

  protected
    function CanCalculate: Boolean; virtual;
    function GetCompressWeekends: Boolean; virtual;
    function GetDontPrintWeekEnds: Boolean; virtual;
    function GetHideSelection: Boolean; virtual;
    function GetPageBounds: TRect; virtual;
    function GetPagesPerWeek: Byte; virtual;
    function GetPrimaryPage: Boolean; virtual;
    function GetPrintExactlyOneMonth: Boolean; virtual;
    function GetPrintRange(Index: Integer): TDateTime; virtual;
    function GetStylesAdapter: IcxSchedulerStylesAdapter; virtual;
    function GetView: TcxSchedulerCustomResourceView; virtual;

    procedure AfterCalculatePage; virtual;
    procedure BeforeCalculatePage; virtual;
    procedure DoInitialize(var ASelectedDays: TcxSchedulerDateList;
       var AEvents: TcxSchedulerCachedEventList); virtual;
    function GetPageHeaderText: string; virtual;
    procedure Store; virtual;
    procedure Restore; virtual;

    property Scheduler: TcxCustomScheduler read GetScheduler;
    property PainterHelper: TcxSchedulerPainterHelperClass read GetPainterHelper;
    property ResourceNavigator: TcxSchedulerResourceNavigator read GetResourceNavigator;
    property ViewInfo: TcxSchedulerCustomResourceViewViewInfo read GetViewInfo;

  public
    constructor Create(AView: TcxSchedulerCustomResourceView); virtual;

    procedure Calculate; overload;

    procedure GetPageResources(AResources: TcxObjectList); virtual;
    procedure GetPageDays(APageIndex: Integer; ADays: TcxSchedulerDateList);
    procedure Invalidate; virtual;

    property Cells: TcxObjectList read GetCells;
    property ContentLineHeight: Integer read GetContentLineHeight;
    property DontPrintWeekEnd: Boolean read GetDontPrintWeekEnds;
    property PagesPerWeek: Byte read GetPagesPerWeek;
    property PrintExactlyOneMonth: Boolean read GetPrintExactlyOneMonth;
    property PrintFrom: TDateTime index 0 read GetPrintRange;
    property PrintTo: TDateTime index 1 read GetPrintRange;
    property Resources: TcxSchedulerStorageResourceItems read GetResources;
    property StylesAdapter: IcxSchedulerStylesAdapter read GetStylesAdapter;
    property View: TcxSchedulerCustomResourceView read GetView;
  end;

  TcxCustomResourceViewAdapterClass = class of TcxCustomResourceViewAdapter;

  { TcxSchedulerEventImages }

  TcxSchedulerEventImageType = (eitReminder, eitRecurrence, eitCustomOccurrence, eitCustom);

  { TcxSchedulerEventImageItem }

  TcxSchedulerEventImageItem = class(TCollectionItem)
  private
    FAutoHide: Boolean;
    FImageType: TcxSchedulerEventImageType;
    FImageIndex: Integer;
    FImages: TImageList;
    FVisible: Boolean;
    function GetHeight: Integer;
    function GetWidth: Integer;
  protected
    FBounds: TRect;
    FHidden: Boolean;
  public
    constructor Create(Collection: TCollection); override;

    property AutoHide: Boolean read FAutoHide write FAutoHide;
    property Bounds: TRect read FBounds;
    property Height: Integer read GetHeight;
    property ImageIndex: Integer read FImageIndex;
    property ImageType: TcxSchedulerEventImageType read FImageType;
    property Images: TImageList read FImages;
    property Visible: Boolean read FVisible write FVisible;
    property Width: Integer read GetWidth;
  end;

  { TcxSchedulerEventImages }

  TcxSchedulerEventImages = class(TCollection)
  private
    FForceVisibleHeight: Integer;
    FForceVisibleWidth: Integer;
    FImages: TImageList;
    FLayout: TcxSchedulerEventImagesLayout;
    FItemHeight: Integer;
    FItemWidth: Integer;
    FTotalVisibleHeight: Integer;
    FTotalVisibleWidth: Integer;
    FTotalVisibleImageCount: Integer;
    FVisibleImageCount: Integer;
    function GetImageItem(AIndex: Integer): TcxSchedulerEventImageItem;
  protected
    function Calculate(const R: TRect): Integer;
    procedure CalculateForCols(AVisibleImages: TList; const ATopLeft: TPoint; AColCount: Integer);
    function CalculateImages(const R: TRect): Integer;
    function CalculateSingleColumnImages(const R: TRect): Integer;
    function CalculateSingleLineImages(const R: TRect; ARightLimit: Integer = 0): Integer;
    function Offset(ADeltaX, ADeltaY: Integer): Integer;
    function CreateVisibleList: TList;
    procedure Init(AImages: TImageList);
    procedure SetItemBounds(AItem: TcxSchedulerEventImageItem; ALeft, ATop: Integer);

    property ItemHeight: Integer read FItemHeight;
    property ItemWidth: Integer read FItemWidth;
    property ForceVisibleHeight: Integer read FForceVisibleHeight;
    property ForceVisibleWidth: Integer read FForceVisibleWidth;
    property TotalVisibleHeight: Integer read FTotalVisibleHeight;
    property TotalVisibleWidth: Integer read FTotalVisibleWidth;
    property TotalVisibleImageCount: Integer read FTotalVisibleImageCount;
    property VisibleImageCount: Integer read FVisibleImageCount;
  public
    constructor Create(ALayout: TcxSchedulerEventImagesLayout);
    function Add(AImageIndex: Integer; AutoHide: Boolean = True): TcxSchedulerEventImageItem;
    function AddStandardImage(AImageType: TcxSchedulerEventImageType;
      AutoHide: Boolean = True): TcxSchedulerEventImageItem;

    property Items[Index: Integer]: TcxSchedulerEventImageItem read GetImageItem; default;
    property Layout: TcxSchedulerEventImagesLayout read FLayout write FLayout;
  end;

  { TcxSchedulerCustomResourceViewViewInfo }

  TcxSchedulerCustomResourceViewViewInfo = class(TcxSchedulerCustomViewViewInfo)
  private
    function GetClones: TcxSchedulerEventList;
    function GetDay(AIndex: Integer): TDateTime;
    function GetDayCount: Integer;
    function GetShowEventsWithoutResource: Boolean;
    function GetGroupByDate: Boolean;
    function GetGroupByResource: Boolean;
    function GetGroupingKind: TcxSchedulerGroupingKind;
    function GetHasSeparator: Boolean;
    function GetHasVisibleBounds: Boolean; 
    function GetHiddenSelection: Boolean;
    function GetResource(AIndex: Integer): TcxSchedulerResourceViewInfo;
    function GetResourceCaption(AIndex: Integer): string;
    function GetResourceCount: Integer;
    function GetResourceHeaders: TcxSchedulerResourceHeaders;
    function GetPrintRange(Index: Integer): TDateTime;
    function GetSeparatorWidth: Integer;
    function GetView: TcxSchedulerCustomResourceView;
  protected
    FAdapter: TcxCustomResourceViewAdapter;
    FButtons: TcxSchedulerViewInfoCellList;
    FCanSelected: Boolean;
    FCells: TcxObjectList;
    FContentCells: TcxSchedulerViewInfoCellList;
    FContentFontHeight: Integer; 
    FContentLineHeight: Integer;
    FDayBorderColor: TColor;
    FDayHeaderCells: TcxSchedulerViewInfoCellList;
    FDayHeaderHeight: Integer;
    FEventCells: TcxSchedulerViewInfoCellList;
    FEventImages: IcxSchedulerEventImages;
    FGroupSeparatorCells: TcxSchedulerViewInfoCellList;
    FGroupSeparatorParams: TcxViewParams;
    FGroupingKind: TcxSchedulerGroupingKind;
    FHasVisibleBounds: Boolean;
    FHeaderContainerCells: TcxSchedulerViewInfoCellList;
    FHideClones: Boolean;
    FHideSelection: Boolean;
    FHideSource: Boolean;
    FResources: TcxObjectList;
    FResourceHeaderCells: TcxSchedulerViewInfoCellList;
    FResourceHeaderHeight: Integer;
    FResourceImages: TImageList;
    FSelectionParams: TcxViewParams;
    FSelStart: TDateTime;
    FSelFinish: TDateTime;
    FSelResource: TcxSchedulerResourceViewInfo;
    FStylesAdapter: IcxSchedulerStylesAdapter;
    FTimeLineParams: TcxViewParams;
    // for page splitting
    FPageBounds: TRect;
    FPagesPerWeek: Byte;
    FPrimaryPage: Boolean;
    FPrintWeekEnds: Boolean;
    FUseResourceImages: Boolean;
    ScreenCanvas: TcxCanvas;

    function AddBackgroundSlot(const ABounds: TRect; ABorders: TcxBorders;
      const AText: string = ''): TcxSchedulerBackgroundSlotCellViewInfo; virtual;
    function AddButton(ABounds: TRect; const ADateTime: TDateTime;
      AResourceIndex: Integer; AIsDown: Boolean): TcxSchedulerMoreEventsButtonViewInfo; virtual;
    function AddContentCell(const ARect: TRect; const AStart, AFinish: TDateTime;
      AResourceIndex: Integer): TcxSchedulerContentCellViewInfo; virtual;
    function AddDayHeader(const ADate: TDateTime; const ABounds: TRect;
      AResourceIndex: Integer): TcxSchedulerDayHeaderCellViewInfo; overload; virtual;
    function AddDayHeader(const ADate: TDateTime; ATop, ALeft, ARight: Integer;
      AResourceIndex: Integer): TcxSchedulerDayHeaderCellViewInfo; overload;
    function AddEventCell(
      AViewData: TcxSchedulerEventViewData; AImmediateCalculate: Boolean = True): TcxSchedulerEventCellViewInfo; virtual;
    function AddGroupHorzSeparator(APos: Integer): TcxSchedulerGroupSeparatorCellViewInfo; virtual;
    function AddGroupSeparator(const ABounds: TRect): TcxSchedulerGroupSeparatorCellViewInfo; virtual;
    function AddGroupVertSeparator(APos: Integer): TcxSchedulerGroupSeparatorCellViewInfo; virtual;
    function AddResourceHeader(const AIndex: Integer;
      const ABounds: TRect): TcxSchedulerHeaderCellViewInfo; virtual;
    procedure AfterCalculate; override;
    procedure AssignResourceID(ACell: TcxSchedulerCustomResourceViewInfoItem; AIndex: Integer);
    procedure CalculateMetrics; virtual;
    procedure CalculateResourceHeadersAutoHeight(AWidth: Integer); virtual;
    function CalculateResourceHeaderWidth: Integer; virtual; 
    procedure Clear; override;
    function ContentCellClass: TcxSchedulerContentCellViewInfoClass; virtual;
    procedure CreateCellInstance(AClass: TcxSchedulerCustomViewInfoItemClass;
      const ABounds: TRect; const AViewParams: TcxViewParams; var Instance); overload;
    procedure CreateCellInstance(AClass: TcxSchedulerCustomViewInfoItemClass;
      const ABounds, AVisibleBounds: TRect; const AViewParams: TcxViewParams; var Instance); overload;
    function CreateEventViewData(AEvent: TcxSchedulerControlEvent; const ABounds: TRect;
      const AStart, AFinish: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData; virtual;
    function CreateEventCellViewInfo(AViewData: TcxSchedulerEventViewData): TcxSchedulerEventCellViewInfo; virtual;
    procedure DoCalculate; override;
    procedure DoMoreEventsButtonClick(Sender: TcxSchedulerMoreEventsButtonViewInfo); virtual;
    procedure ExtractResources; virtual;
    function GetBounds: TRect; override;
    function GetContentParams(const ATime: TDateTime;
      AResource: TcxSchedulerResourceViewInfo): TcxViewParams; virtual;
    function GetDayHeaderHeight: Integer; virtual;
    function GetResourceHeaderWidth: Integer;
    function GetResourceImagesSize: TSize; virtual;
    function GetResourcesContentWidth: Integer; virtual;
    function GetSelectionParams(const AParams: TcxViewParams): TcxViewParams;
    function GetSeparatorCount: Integer; virtual;
    function GetTimeLineParams: TcxViewParams; virtual;
    function GetFontHeight(AStyle: TcxStyle): Integer; overload;
    function GetFontHeight(const AParams: TcxViewParams): Integer; overload;
    function GetPageHeaderText: string; virtual;
    function GetResourceItemByIndex(AIndex: Integer): TcxSchedulerStorageResourceItem;
    function GetResourceViewInfoByItem(AItem: TcxSchedulerStorageResourceItem): TcxSchedulerResourceViewInfo;
    function HasStorage: Boolean;
    procedure HideCloneEventsOnDragDrop;
    procedure HideSourceEventsOnDragDrop;
    function IsTimeSelected(ATime: TDateTime; AResource: TObject): Boolean; virtual;
    procedure MakeTimeVisible(const ATime: TDateTime); virtual;
    procedure OnMoreEventsButtonClick(Sender: TcxSchedulerMoreEventsButtonViewInfo);
    procedure ProcessDateToDisplayText(ArrangeByType: Boolean = False); virtual;
    procedure ProcessCheckBorders(AList: TcxSchedulerViewInfoCellList;
      AHasCommonArea: Boolean; ANeighbors: TcxNeighbors = [];
      AExcludeBorders: TcxBorders = []; AAddBorders: TcxBorders = []);
    function SetAdapter(Adapter: TcxCustomResourceViewAdapter): TcxCustomResourceViewAdapter;
    procedure SetResourceTextRect(AResource: TcxSchedulerStorageResourceItem; const ARect: TRect);

    property View: TcxSchedulerCustomResourceView read GetView;
  public
    constructor Create(AOwner: TcxSchedulerSubControl); override;
    destructor Destroy; override;
    procedure Calculate; override;
    procedure CalculateHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); virtual;
    procedure InitScrollBarsParameters; virtual;
    procedure ScrollHorizontal(AScrollCode: TScrollCode; var AScrollPos: Integer); virtual;
    procedure ScrollVertical(AScrollCode: TScrollCode; var AScrollPos: Integer); virtual;
    procedure SetEventsVisibility(AShowSources, AShowClones: Boolean; AForceRepaint: Boolean = False); override;

    property Adapter: TcxCustomResourceViewAdapter read FAdapter;
    property Buttons: TcxSchedulerViewInfoCellList read FButtons;
    property CanSelected: Boolean read FCanSelected;
    property Clones: TcxSchedulerEventList read GetClones;
    property ContentCells: TcxSchedulerViewInfoCellList read FContentCells;
    property ContentLineHeight: Integer read FContentLineHeight;
    property DayCount: Integer read GetDayCount;
    property DayHeaderCells: TcxSchedulerViewInfoCellList read FDayHeaderCells;
    property DayHeaderHeight: Integer read GetDayHeaderHeight;
    property Days[Index: Integer]: TDateTime read GetDay;
    property EventCells: TcxSchedulerViewInfoCellList read FEventCells;
    property ShowEventsWithoutResource: Boolean read GetShowEventsWithoutResource;
    property GroupByDate: Boolean read GetGroupByDate;
    property GroupByResource: Boolean read GetGroupByResource;
    property GroupSeparatorCells: TcxSchedulerViewInfoCellList read FGroupSeparatorCells;
    property GroupSeparatorParams: TcxViewParams read FGroupSeparatorParams;
    property GroupingKind: TcxSchedulerGroupingKind read FGroupingKind;
    property HasSeparator: Boolean read GetHasSeparator;
    property HasVisibleBounds: Boolean read FHasVisibleBounds;
    property HeaderContainerCells: TcxSchedulerViewInfoCellList read FHeaderContainerCells;
    property HideSelection: Boolean read FHideSelection;
    property PagesPerWeek: Byte read FPagesPerWeek;
    property PrimaryPage: Boolean read FPrimaryPage;
    property PrintFrom: TDateTime index 0 read GetPrintRange;
    property PrintTo: TDateTime index 1 read GetPrintRange;
    property PrintWeekEnds: Boolean read FPrintWeekEnds;
    property Resources[AIndex: Integer]: TcxSchedulerResourceViewInfo read GetResource;
    property ResourceCaptions[AIndex: Integer]: string read GetResourceCaption;
    property ResourceCount: Integer read GetResourceCount;
    property ResourceHeaders: TcxSchedulerResourceHeaders read GetResourceHeaders;
    property ResourceHeaderCells: TcxSchedulerViewInfoCellList read FResourceHeaderCells;
    property ResourceHeaderHeight: Integer read FResourceHeaderHeight;
    property ResourceImages: TImageList read FResourceImages;  
    property SelFinish: TDateTime read FSelFinish;
    property SelResource: TcxSchedulerResourceViewInfo read FSelResource;
    property SelStart: TDateTime read FSelStart;
    property SeparatorWidth: Integer read GetSeparatorWidth;
    property StylesAdapter: IcxSchedulerStylesAdapter read FStylesAdapter;
    property HiddenSelection: Boolean read GetHiddenSelection;
    property UseResourceImages: Boolean read FUseResourceImages;
  end;

  { TcxSchedulerCustomResourceViewNavigation }

  TcxSchedulerCustomResourceViewNavigation = class(TcxSchedulerViewNavigation)
  private
    function GetIsFirstResource: Boolean;
    function GetIsLastResource: Boolean;
    function GetGroupingKind: TcxSchedulerGroupingKind;
    function GetResourceObject: TcxSchedulerResourceViewinfo;
    function GetViewInfo: TcxSchedulerCustomResourceViewViewInfo;
  protected
    function GetNextResource(AGoToForward: Boolean): TcxSchedulerStorageResourceItem;
    function GetResourceItem: TcxSchedulerStorageResourceItem; override;
    function GetResourceFromViewInfo(AInfo: TcxSchedulerResourceViewInfo): TcxSchedulerStorageResourceItem;
    function RoundTime(const ADateTime: TDateTime): TDateTime;
  public
    procedure ValidateSelection(var ASelStart, ASelFinish: TDateTime;
      var AResource: TcxSchedulerStorageResourceItem); override;
    property IsFirstResource: Boolean read GetIsFirstResource;
    property IsLastResource: Boolean read GetIsLastResource;
    property GroupingKind: TcxSchedulerGroupingKind read GetGroupingKind;
    property ResourceItem: TcxSchedulerStorageResourceItem read GetResourceItem;
    property ResourceObject: TcxSchedulerResourceViewInfo read GetResourceObject;
    property ViewInfo: TcxSchedulerCustomResourceViewViewInfo read GetViewInfo;
  end;

  { TcxSchedulerCustomResourceViewController }

  TcxSchedulerCustomResourceViewController = class(TcxSchedulerViewController)
  private
    function GetHitTest: TcxSchedulerCustomResourceViewHitTest;
  protected
    function CreateNavigation: TcxSchedulerViewNavigation; override;
    function GetCursor(X, Y: Integer): TCursor; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;

    property HitTest: TcxSchedulerCustomResourceViewHitTest read GetHitTest;
  end;

  { TcxSchedulerCustomResourceViewHitTest }

  TcxSchedulerCustomResourceViewHitTest = class(TcxSchedulerViewHitTest)
  private
    function GetContentCell: TcxSchedulerContentCellViewInfo;
    function GetHeaderCell: TcxSchedulerHeaderCellViewInfo;
    function GetView: TcxSchedulerCustomResourceView;
  protected
    FButton: TcxSchedulerMoreEventsButtonViewInfo;
    FDragKind: TcxEventDragKind;
    FEventCell: TcxSchedulerEventCellViewInfo;
    FHitObject: TObject;
    FTimeZone: Integer;
    function CanMoveEvent(AEvent: TcxSchedulerControlEvent): Boolean; virtual;
    function CanResizeEvent(AEvent: TcxSchedulerControlEvent): Boolean; virtual;
    procedure Clear; override;
    procedure DoCalculate; override;
    function GetHitEvent: TcxSchedulerControlEvent; override;
    procedure SetHitTime(AItemFlag: Integer; const ATime: TDateTime); virtual;
    procedure SetResource(AResource: TcxSchedulerResourceViewInfo);
    procedure ValidateDragKind; virtual;

    property View: TcxSchedulerCustomResourceView read GetView;
    property HitAtTimeZoneLabel: Boolean index htcTimeZoneLabel read GetBitState;
    property TimeZone: Integer read FTimeZone;
  public
    function GetDragKind: TcxEventDragKind; override;
    procedure SetDragKind(AValue: TcxEventDragKind);

    property Button: TcxSchedulerMoreEventsButtonViewInfo read FButton;
    property ContentCell: TcxSchedulerContentCellViewInfo read GetContentCell;
    property EventCell: TcxSchedulerEventCellViewInfo read FEventCell;
    property HeaderCell: TcxSchedulerHeaderCellViewInfo read GetHeaderCell;
    property HitAtButton: Boolean index htcButton read GetBitState;
    property HitAtContent: Boolean index htcContent read GetBitState;
    property HitAtDayHeader: Boolean index htcDayHeader read GetBitState;
    property HitAtGroupSeparator: Boolean index htcGroupSeparator read GetBitState;
    property HitAtResourceHeader: Boolean index htcResourceHeader read GetBitState;
  end;

 { TcxSchedulerCustomViewPainter }

  TcxSchedulerCustomViewPainter = class(TcxSchedulerSubControlPainter)
  private
    function GetView: TcxSchedulerCustomResourceView;
  protected
    FPainter: IcxSchedulerCommonViewItemsPainter;
    procedure DrawBackgroundCell(AItem: TcxSchedulerBackgroundCellViewInfo); virtual;
    procedure DrawButtonCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual;
    procedure DrawContentCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual;
    procedure DrawEventCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual;
    procedure DrawGroupSeparatorCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual;
    procedure DrawHeaderCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual;
    procedure DrawResourceHeaderCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual;
  public
    constructor Create(AOwner: TcxSchedulerSubControl); override;
    procedure Paint; override;

    property Painter: IcxSchedulerCommonViewItemsPainter read FPainter;
    property View: TcxSchedulerCustomResourceView read GetView;
  end;

  { TcxSchedulerEventPlace }

  TcxSchedulerEventPlace = class
  public
    ColFinish: Integer;
    ColStart: Integer;
    Resource: TObject; 
    Data: TObject;
    Event: TcxSchedulerEvent;
    LineFinish: Integer;
    LineStart: Integer;
    procedure AlignPosition(APlace: TcxSchedulerEventPlace);
    function IntersectHorz(APlace: TcxSchedulerEventPlace): Boolean;
    function IntersectVert(APlace: TcxSchedulerEventPlace): Boolean;
    procedure ResetPosition;
  end;

  { TcxSchedulerEventLayoutBuilder }

  TcxSchedulerEventLayoutBuilderGetEventPlaceProc = function(Sender: TcxSchedulerEventLayoutBuilder;
    AEvent: TcxSchedulerControlEvent; out AStartCol, AFinishCol: Integer; out ALineCount: Integer): Boolean of object;

  TcxSchedulerEventLayoutBuilder = class
  private
    FEventPlaces: TcxObjectList;
    function GetEventPlace(AIndex: Integer): TcxSchedulerEventPlace;
    function GetEventPlaceCount: Integer;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    function AddEventPlace(AEvent: TcxSchedulerEvent;
      AStartCol, AFinishCol: Integer; ALineCount: Integer = 1; AResource: TObject = nil): TcxSchedulerEventPlace;
    procedure Clear;
    procedure Calculate;
    procedure CalculateEx(AEventsList: TcxSchedulerFilteredEventList;
      APlaceInfoProc: TcxSchedulerEventLayoutBuilderGetEventPlaceProc);
    property EventPlaceCount: Integer read GetEventPlaceCount;
    property EventPlaces[Index: Integer]: TcxSchedulerEventPlace read GetEventPlace;
  end;

function MakeTextOutcxFlags(AlignHorz: TAlignment;
  AlignVert: TcxAlignmentVert; AMultiline: Boolean = False): Integer;

implementation

uses
  cxEditTextUtils;

type
  TcxCustomEditStyleAccess = class(TcxCustomEditStyle);

const
  AlignmentsHorz: array[TAlignment] of Integer =
    (cxAlignLeft, cxAlignRight, cxAlignHCenter);
  AlignmentsVert: array[TcxAlignmentVert] of Integer =
    (cxAlignTop, cxAlignBottom, cxAlignVCenter);
  MultiLines: array[Boolean] of Integer = (0, cxWordBreak);
{$IFDEF USECXTEXTOUT}
  cxTextOutFlags: array[Boolean] of Cardinal = (
    CXTO_LEFT or CXTO_CENTER_VERTICALLY or CXTO_WORDBREAK,
    CXTO_LEFT or CXTO_TOP or CXTO_WORDBREAK or CXTO_EDITCONTROL);

function MakeTextOutFlags(AlignHorz: TAlignment;
  AlignVert: TcxAlignmentVert; AMultiline: Boolean = False): Integer;
const
  Horz: array[TAlignment] of Integer =
    (CXTO_LEFT, CXTO_RIGHT, CXTO_CENTER_HORIZONTALLY);
  Vert: array[TcxAlignmentVert] of Integer =
    (CXTO_TOP, CXTO_BOTTOM, CXTO_CENTER_VERTICALLY);
begin
  Result := CXTO_PREVENT_LEFT_EXCEED or CXTO_PREVENT_TOP_EXCEED or
    Horz[AlignHorz] or Vert[AlignVert] + CXTO_SINGLELINE;
  if AMultiline then
  begin
    Result := CXTO_PREVENT_LEFT_EXCEED or CXTO_PREVENT_TOP_EXCEED or
      Horz[AlignHorz] or Vert[AlignVert] or CXTO_WORDBREAK;
  end;
end;
{$ELSE}
  cxDrawTextFlags: array[Boolean] of Cardinal = (
    cxAlignLeft or cxAlignVCenter or cxSingleLine,
    cxAlignLeft or cxAlignTop or cxWordBreak or cxDontBreakChars);
{$ENDIF}

function MakeTextOutcxFlags(AlignHorz: TAlignment;
  AlignVert: TcxAlignmentVert; AMultiline: Boolean = False): Integer;
begin
  Result := AlignmentsHorz[AlignHorz] or cxDontBreakChars or
    AlignmentsVert[AlignVert] or MultiLines[AMultiline];
end;

function MakeRect(ALeft, ATop: Integer; ASize: TSize): TRect;
begin
  Result.Left := ALeft;
  Result.Top := ATop;
  Result.Right := ALeft + ASize.cx;
  Result.Bottom := ATop + ASize.cy;
end;

function GetTrueMultilineTextHeight(ACanvas: TcxCanvas; const S: string; ABounds: TRect): Integer;
var
  ARowCount: Integer;
  ATextFlags: Cardinal;
  ATextParams: TcxTextParams;
  ATextRows: TcxTextRows;
begin
  ABounds.Bottom := 30000;
  ATextFlags := CXTO_CALCROWCOUNT or CXTO_LEFT or CXTO_TOP or CXTO_WORDBREAK or CXTO_EDITCONTROL;
  ATextParams := cxCalcTextParams(ACanvas.Canvas, ATextFlags);
  cxMakeTextRows(ACanvas.Canvas, PChar(S), ABounds, ATextParams, ATextRows, ARowCount);
  Result := ATextParams.RowHeight * Max(ARowCount, 1);
  ATextRows := nil;
end;

{ TcxSchedulerViewInfoCellList }

function TcxSchedulerViewInfoCellList.CalculateHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest): Boolean;
var
  I: Integer;
begin
  Result := False;
  for I := 0 to Count - 1 do
    if Items[I].GetHitTest(AHitTest, Result) and Result then Exit;
end;

procedure TcxSchedulerViewInfoCellList.Clear;
var
  I: Integer;
begin
  for I := Count - 1 downto 0 do
    Items[I].Free;
  inherited Clear;
end;

procedure TcxSchedulerViewInfoCellList.Draw(
  ACanvas: TcxCanvas; ADrawItemProc: TcxSchedulerCustomDrawItemProc);
var
  I: Integer;
  ADone: Boolean;
  AItem: TcxSchedulerCustomViewInfoItem;
  ASavedFont: TFont;
begin
  for I := 0 to Count - 1 do
  begin
    AItem := Items[I];
    if AItem.FVisible then
    begin
      ASavedFont := AItem.FViewParams.Font;
      AItem.BeforeCustomDraw(ACanvas);
      ADone := False;
      if AItem.FHasClipping then
      begin
        AItem.FCanvas := ACanvas;
        AItem.ClippingCreate(AItem.FHasClipping);
        ADrawItemProc(AItem, ADone);
        AItem.ClippingRestore;
      end
      else
        ADrawItemProc(AItem, ADone);
      AItem.AfterCustomDraw(ACanvas);
      if not ADone then AItem.Draw(ACanvas);
      AItem.FViewParams.Font := ASavedFont;
    end;
  end;
// need Optimize if custom draw not supported do not need
// custom draw canvas preparation
 
//  SelectClipRgn(ACanvas.Handle, 0);
// TODO: draw and custom draw events 
end;

function TcxSchedulerViewInfoCellList.GetItem(
  AIndex: Integer): TcxSchedulerCustomViewInfoItem;
begin
  Result := List^[AIndex];
end;

{ TcxSchedulerCustomViewInfoItem }

constructor TcxSchedulerCustomViewInfoItem.Create(
  APainter: TcxCustomLookAndFeelPainterClass;
  const ABounds, AVisibleRect: TRect; const AViewParams: TcxViewParams);
begin
  FPainter := APainter;
  FDateTime := NullDate;
  FViewParams := AViewParams;
  CalculateCellBounds(ABounds, AVisibleRect);
end;

destructor TcxSchedulerCustomViewInfoItem.Destroy;
begin
  FClipRgn.Free;
  inherited Destroy;
end;

procedure TcxSchedulerCustomViewInfoItem.Draw(ACanvas: TcxCanvas);
var
  ATransparent: Boolean;
  APrevCanvas: TcxCanvas;
  APrevParams: TcxViewParams;
begin
  if not FVisible then Exit;
  ATransparent := Transparent;
  APrevCanvas := FCanvas;
  ACanvas.GetParams(APrevParams);
  FCanvas := ACanvas;
  DoDraw;
  ACanvas.SetParams(APrevParams);
  FCanvas := APrevCanvas;
  Transparent := ATransparent;               
end;

procedure TcxSchedulerCustomViewInfoItem.CalculateCellBounds(
  const ABounds, AVisibleRect: TRect);
begin
  FBounds := ABounds;
  FVisible := cxRectIntersect(FClipRect, ABounds, AVisibleRect);
  FHasClipping := FVisible and not cxRectIsEqual(FClipRect, ABounds);
end;

procedure TcxSchedulerCustomViewInfoItem.ClippingCreate(AHasClipping: Boolean);
begin
  Inc(FClipRef);
  if not AHasClipping or (FClipRef > 1) then Exit;
  if FClipRgn = nil then
    FClipRgn := TcxRegion.Create(FClipRect);
  FSavedClipRgn := Canvas.GetClipRegion;
  Canvas.SetClipRegion(FClipRgn, roSet, False);
end;

procedure TcxSchedulerCustomViewInfoItem.ClippingRestore;
begin
  Dec(FClipRef);
  if (FClipRef = 0) and (FSavedClipRgn <> nil) then
  begin
    Canvas.SetClipRegion(FSavedClipRgn, roSet, True);
    FSavedClipRgn := nil;
  end;
end;

function TcxSchedulerCustomViewInfoItem.DrawBackground(
  ACanvas: TcxCanvas; const ABounds: TRect): Boolean;
begin
  Result := Transparent or Assigned(Bitmap) and not Bitmap.Empty;
  if Result and not Transparent then
    ACanvas.FillRect(ABounds, Bitmap);
end;

procedure TcxSchedulerCustomViewInfoItem.DrawFrame(
  const ARect: TRect; ABorders: TcxBorders = [];
  ABorderColor: TColor = clDefault; ALineWidth: Integer = 1);
begin
  Canvas.FrameRect(ARect, ABorderColor, ALineWidth, ABorders);
end;

procedure TcxSchedulerCustomViewInfoItem.DrawRect(
  const ARect: TRect; ABorders: TcxBorders = [];
  ABorderColor: TColor = clDefault; ALineWidth: Integer = 1);
begin
  if Transparent then
    Canvas.FrameRect(ARect, ABorderColor, ALineWidth, ABorders)
  else
    Canvas.FillRect(ARect, FViewParams, ABorders,  ABorderColor, ALineWidth);
end;

procedure TcxSchedulerCustomViewInfoItem.DrawText(
  const ARect: TRect; const AText: string; AFlags: Integer; AFont: TFont = nil; AColor: TColor = clDefault);
begin
  if AFont = nil then
    Canvas.Font := FViewParams.Font
  else
    Canvas.Font := AFont;
  if AColor <> clDefault then
    Canvas.Font.Color := AColor;
  Canvas.Brush.Style := bsClear;
  Canvas.DrawTexT(AText, ARect, AFlags);
end;

function TcxSchedulerCustomViewInfoItem.GetFont: TFont;
begin
  Result := FViewParams.Font;
end;

function TcxSchedulerCustomViewInfoItem.GetHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest; var ABreak: Boolean): Boolean;
begin
  Result := FVisible and PtInRect(FClipRect, AHitTest.HitPoint);
  ABreak := Result;
  if Result then
    InitHitTest(AHitTest);
end;

procedure TcxSchedulerCustomViewInfoItem.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  AHitTest.FHitObject := Self;
end;

procedure TcxSchedulerCustomViewInfoItem.RotateBitmap(
  ABitmap: TBitmap; ARotationAngle: TcxRotationAngle; AFlipHorizontally: Boolean = False);
var
  PDest, PDestStart: ^DWORD;
  PSource, PSourceStart: ^DWord;
  PBuffer: Pointer;
  XSource, YSource: Integer;
  LineCopyingDirection: Integer;
  TempVar: Integer;
begin
  if ABitmap.Empty then Exit;
  case ARotationAngle of
    ra0:
      if AFlipHorizontally then
      begin
        with ABitmap do
        begin
          GetMem(PBuffer, Width * 4);
          for YSource := 0 to Height - 1 do
          begin
            PSourceStart := ScanLine[YSource];
            PSource := PSourceStart;
            Inc(PSource, Width - 1);
            PDest := PBuffer;
            for XSource := 0 to Width - 1 do
            begin
              PDest^ := PSource^;
              Inc(PDest);
              Dec(PSource);
            end;
            Move(PBuffer^, PSourceStart^, Width * 4);
          end;
        end;
        FreeMem(PBuffer);
      end;
    raPlus90, raMinus90:

      with ABitmap do
      begin
        GetMem(PBuffer, Width * Height * 4);

        LineCopyingDirection := 0;
        PDestStart := PBuffer;
        case ARotationAngle of
          raPlus90:
            begin
              Inc(PDestStart, Height * (Width - 1));
              LineCopyingDirection := 1;
            end;
          raMinus90:
            begin
              Inc(PDestStart, Height - 1);
              LineCopyingDirection := -1;
            end;
        end;

        for YSource := 0 to Height - 1 do
        begin
          PSource := ScanLine[YSource];
          PDest := PDestStart;
          if AFlipHorizontally then
          begin
            Inc(PSource, Width - 1);
            for XSource := 0 to Width - 1 do
            begin
              PDest^ := PSource^;
              Dec(PDest, Height * LineCopyingDirection);
              Dec(PSource);
            end
          end
          else
            for XSource := 0 to Width - 1 do
            begin
              PDest^ := PSource^;
              Dec(PDest, Height * LineCopyingDirection);
              Inc(PSource);
            end;
          Inc(PDestStart, LineCopyingDirection);
        end;

        TempVar := Width;
        Width := Height;
        Height := TempVar;
        if Width = Height then
        begin
          Width := Width + 1;
          Width := Width - 1;
        end;

        PDest := PBuffer;
        for YSource := 0 to Height - 1 do
        begin
          Move(PDest^, ScanLine[YSource]^, Width * 4);
          Inc(PDest, Width);
        end;

        FreeMem(PBuffer);
      end;

  end;
end;

// custom draw support
procedure TcxSchedulerCustomViewInfoItem.AfterCustomDraw(ACanvas: TcxCanvas);
begin
  ACanvas.GetParams(FViewParams);
end;

procedure TcxSchedulerCustomViewInfoItem.BeforeCustomDraw(ACanvas: TcxCanvas);
begin
  ACanvas.SetParams(FViewParams);
end;

function TcxSchedulerCustomViewInfoItem.GetBitmap: TBitmap;
begin
  Result := FViewParams.Bitmap;
end;

function TcxSchedulerCustomViewInfoItem.GetColor: TColor;
begin
  Result := FViewParams.Color;
end;

function TcxSchedulerCustomViewInfoItem.GetDateTimeHelper: TcxSchedulerDateTimeHelperClass;
begin
  Result := cxSchedulerUtils.DateTimeHelper;
end;

function TcxSchedulerCustomViewInfoItem.GetPainterHelper: TcxSchedulerPainterHelperClass;
begin
  Result := TcxSchedulerHelpersFactory.PainterHelperClass;
end;

function TcxSchedulerCustomViewInfoItem.GetTextColor: TColor;
begin
  Result := FViewParams.TextColor;
end;

procedure TcxSchedulerCustomViewInfoItem.SetBitmap(
  AValue: TBitmap);
begin
  FViewParams.Bitmap := AValue;
end;

procedure TcxSchedulerCustomViewInfoItem.SetColor(
  AValue: TColor);
begin
  FViewParams.Color := AValue;
end;

procedure TcxSchedulerCustomViewInfoItem.SetTextColor(
  AValue: TColor);
begin
  FViewParams.TextColor := AValue;
end;


{ TcxSchedulerBackgroundCellViewInfo }

procedure TcxSchedulerBackgroundCellViewInfo.DoDraw;
begin
  DrawRect(Bounds, Borders, clBtnShadow);
end;

{ TcxSchedulerCustomResourceViewInfoItem }

procedure TcxSchedulerCustomResourceViewInfoItem.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  if IsResourceAssigned then
  begin
    AHitTest.SetResource(FResource);
    AHitTest.SetBitState(htcResource, True);
  end;
end;

{ TcxSchedulerHeaderCellViewInfo }

constructor TcxSchedulerHeaderCellViewInfo.Create(
  APainter: TcxCustomLookAndFeelPainterClass;
  const ABounds, AVisibleRect: TRect; const AViewParams: TcxViewParams);
begin
  inherited Create(APainter, ABounds, AVisibleRect, AViewParams);
  FImageIndex := -1;
  FButtonState := cxbsDefault;
  FAlignHorz := taCenter;
  FAlignVert := vaCenter;
  FBorders := cxBordersAll;
  FTextRect := cxRectInflate(FBounds, -cxTextOffset, 0);
end;

destructor TcxSchedulerHeaderCellViewInfo.Destroy;
begin
  FCachedBitmap.Free;
  FRotateBitmap.Free;
  inherited Destroy;
end;

procedure TcxSchedulerHeaderCellViewInfo.Calculate(const AText: string);
begin
  FDisplayText := AText;
end;

procedure TcxSchedulerHeaderCellViewInfo.Draw(ACanvas: TcxCanvas);
var
  ATransparent: Boolean;
  ASavedCanvas: TCanvas;
begin
  if not FVisible then Exit;
  ValidateSelection;
  FBackgroundDrawing := False;
  ATransparent := Transparent;
  if FCachedBitmap = nil then
  begin
    FCachedBitmap := cxCreateBitmap(cxRectSize(Bounds), pf32Bit);
    if Transparent then
      BitBlt(FCachedBitmap.Canvas.Handle, 0, 0, FCachedBitmap.Width,
        FCachedBitmap.Height, ACanvas.Handle, Bounds.Left, Bounds.Top, srcCopy);
    SetWindowOrgEx(FCachedBitmap.Canvas.Handle, FBounds.Left, FBounds.Top, nil);
    ASavedCanvas := ACanvas.Canvas;
    FCanvas := ACanvas;
    FCanvas.Canvas := FCachedBitmap.Canvas;
    CalculateImageLayout;
    if RotateText or RotateHeader then
      DrawVerticalHeader
    else
      DrawHorizontalHeader;
    ACanvas.Canvas := ASavedCanvas;
    SetWindowOrgEx(FCachedBitmap.Canvas.Handle, 0, 0, nil);
  end;
  ACanvas.Draw(FBounds.Left, FBounds.Top, FCachedBitmap);
  FCanvas := nil;
  Transparent := ATransparent;
end;

procedure TcxSchedulerHeaderCellViewInfo.CalculateImageLayout;
const
  Alignments: array[TcxSchedulerHeaderImagePosition] of TAlignment =
    (taLeftJustify, taCenter, taRightJustify, taCenter);
var
  ATopLeft: TPoint;
  ATextSize, AImageSize: TSize;
  ABounds: TRect;
begin
  FImageRectAssigned := FImageRectAssigned or not HasImage;
  if FImageRectAssigned then
  begin
    FTextRect := cxRectInflate(PainterHelper.ExcludeBorders(Bounds, Borders), -cxTextOffset, 0);
    if not HasImage and RotateHeader then
    begin
      if RotateText then
        FTextRect := MakeRect(0, 0, cxSize(Height, Width))
      else
        FTextRect := MakeRect(0, 0, cxSize(Width, Height));
      InflateRect(FTextRect, -(cxTextOffset + 1), -(cxTextOffset + 1));
    end;
    DisplayBounds := FTextRect; 
    Exit;
  end;
  FTextRect := cxTextRect(PainterHelper.ExcludeBorders(Bounds, Borders));
  FImageRectAssigned := True;
  FAlignHorz := Alignments[ImagePosition];
  FAlignVert := vaTop;
  MultiLine := AutoHeight;
  // calculate text and image extents
  AImageSize := cxSize(Images.Width, Images.Height);
  if RotateHeader and RotateText then
  begin
    AImageSize := cxSize(Images.Height, Images.Width);
    ABounds := MakeRect(0, 0, cxSize(Height - 2, Width - 2));
    FTextRect := cxTextRect(ABounds);
  end
  else
  begin
    ABounds := Bounds;
    if RotateHeader then
    begin
      OffsetRect(ABounds, -ABounds.Left, -ABounds.Top);
      FTextRect := cxTextRect(ABounds);
    end;
  end;
  DisplayBounds := cxRectInflate(ABounds, -1, -1); 
  if AutoHeight and (ImagePosition in [ipLeft, ipRight]) then
    Dec(FTextRect.Right, AImageSize.cx + cxTextOffset * 2);
  if Length(DisplayText) > 0 then
  begin
//    Canvas.Font.Assign(Font);
//    Canvas.TextExtent(DisplayText, FTextRect, GetTextOutcxFlags);
    FTextRect.Right := FTextRect.Left + cxRectWidth(Resource.FTextRect);
    FTextRect.Bottom := FTextRect.Top + cxRectHeight(Resource.FTextRect);
  end
  else
    FTextRect := cxNullRect;
  ATextSize := cxRectSize(FTextRect);                       
  ATopLeft := cxPointOffset(cxRectCenter(ABounds), 1, -1 + Byte(RotateHeader));
  if ImagePosition in [ipLeft, ipRight] then
  begin
    Dec(ATopLeft.X, (AImageSize.cx + ATextSize.cx + cxTextOffset) div 2);
    FTextRect := MakeRect(ATopLeft.X, ATopLeft.y - ATextSize.cy div 2, ATextSize);
    FImageRect := MakeRect(ATopLeft.X, ATopLeft.y - AImageSize.cy div 2, AImageSize);
  end
  else
  begin
    Dec(ATopLeft.Y, (AImageSize.cy + ATextSize.cy + cxTextOffset) div 2);
    FTextRect := MakeRect(ATopLeft.x - ATextSize.cx div 2, ATopLeft.y, ATextSize);
    FImageRect := MakeRect(ATopLeft.x - AImageSize.cx div 2, ATopLeft.y, AImageSize);
  end;
  // calculate text bounds
  if Length(DisplayText) > 0 then
  begin
    case ImagePosition of
      ipLeft:
        OffsetRect(FTextRect, AImageSize.cx + cxTextOffset, 0);
      ipTop:
        OffsetRect(FTextRect, 0, AImageSize.cy + cxTextOffset);
      ipRight:
        OffsetRect(FImageRect, ATextSize.cx + cxTextOffset, 0);
      ipBottom:
        OffsetRect(FImageRect, 0, ATextSize.cy + cxTextOffset);
    end;
  end;
end;

procedure TcxSchedulerHeaderCellViewInfo.CheckNeighbor(
  APrevCell: TcxSchedulerHeaderCellViewInfo);
begin
  if (APrevCell = nil) or (APrevCell.RotateHeader <> RotateHeader)  then Exit;
  if (RotateHeader and (APrevCell.Bounds.Bottom <> Bounds.Top)) or
    (not RotateHeader and (APrevCell.Bounds.Right <> Bounds.Left)) then
    Exclude(APrevCell.FBorders, bRight);
end;

function TcxSchedulerHeaderCellViewInfo.CheckSelection: Boolean;
begin
  Result := False;
end;

procedure TcxSchedulerHeaderCellViewInfo.DoDraw;
begin
  if Transparent and (DisplayText = '') then Exit;
  Painter.DrawHeader(Canvas, Bounds, TextRect, Neighbors, Borders,
    FButtonState, AlignHorz, AlignVert, MultiLine, ShowEndEllipsis, DisplayText,
    Font, TextColor, Color, DrawBackground, not (nRight in Neighbors));
end;

procedure TcxSchedulerHeaderCellViewInfo.DrawCaption(ACanvas: TcxCanvas = nil);
var
  ABitmap: TBitmap;
  ARgn: TcxRegion;
begin
  if ACanvas = nil then
    ACanvas := Canvas;
  ARgn := ACanvas.GetClipRegion;
  try
    ACanvas.Brush.Style := bsClear;
    ACanvas.IntersectClipRect(DisplayBounds);
    ACanvas.Font := Font;
    ACanvas.Font.Color := TextColor;
    ACanvas.DrawTexT(DisplayText, TextRect, GetTextOutcxFlags);
    if FImageRectAssigned and HasImage then
    begin
      if not RotateText then
        ACanvas.DrawImage(Images, FImageRect.Left, FImageRect.Top, ImageIndex)
      else
      begin                          //todo: 
        ABitmap := TBitmap.Create;
        try
          ABitmap.Width := Images.Width;
          ABitmap.Height := Images.Height;
          RotateBitmap(ABitmap, raMinus90);
          BitBlt(ABitmap.Canvas.Handle, 0, 0, Images.Height, Images.Width, ACanvas.Handle,
            FImageRect.Left, FImageRect.Top, srcCopy);
          RotateBitmap(ABitmap, raPlus90);
          Images.Draw(ABitmap.Canvas, 0, 0, ImageIndex{$IFDEF DELPHI6}, dsNormal, itImage {$ENDIF});
          RotateBitmap(ABitmap, raMinus90);
          ACanvas.Draw(FImageRect.Left, FImageRect.Top, ABitmap);
        finally
          ABitmap.Free;
        end; 
      end;
    end;
  finally
    ACanvas.SetClipRegion(ARgn, roSet);
  end;
end;

procedure TcxSchedulerHeaderCellViewInfo.DrawHorizontalHeader;
var
  AText: string;
begin
  AText := DisplayText;
  FDisplayText := '';
  DoDraw;
  if not FBackgroundDrawing and Selected then
    cxAlphaBlend(FCachedBitmap, FSelectionRect, ColorToRgb(SelectionColor));
  DisplayText := AText;
  DrawCaption;
end;

function TcxSchedulerHeaderCellViewInfo.DrawRotateBackground(
  ACanvas: TcxCanvas; const ABounds: TRect): Boolean;
begin
  Result := FDrawRotatedBackground;
end;

procedure TcxSchedulerHeaderCellViewInfo.DrawVerticalHeader;

  procedure CreateRotatedBitmap;
  begin
    with Bounds do
      FRotateBitmap := cxCreateTrueColorBitmap(Right - Left, Bottom - Top);
    FRotateBitmap.PixelFormat := pf32bit;
    FRotateBitmap.Canvas.Lock;
    if Transparent then
    begin
      BitBlt(FRotateBitmap.Canvas.Handle, 0, 0, FRotateBitmap.Width,
      FRotateBitmap.Height, Canvas.Handle, Bounds.Left, Bounds.Top, srcCopy);
    end;
  end;

var
  R: TRect;
  ABitmapCanvas: TcxCanvas;
begin
  if FRotateBitmap = nil then
  begin
    CreateRotatedBitmap;
    ABitmapCanvas := TcxCanvas.Create(FRotateBitmap.Canvas);
    try
      ABitmapCanvas.WindowOrg := Bounds.TopLeft;
      FDrawRotatedBackground := DrawBackground(ABitmapCanvas, Bounds);

      RotateBitmap(FRotateBitmap, raPlus90, True);

      R := cxRect(0, 0, FRotateBitmap.Width, FRotateBitmap.Height);
      if not Transparent then
        Painter.DrawHeader(ABitmapCanvas, R, cxRectInflate(R, -cxTextOffset, -cxTextOffset),
          Neighbors, Borders, cxbsNormal, taCenter, vaCenter, False, False, '',
          Font, TextColor, Color, DrawRotateBackground);

      if RotateText then
      begin
        RotateBitmap(FRotateBitmap, ra0, True);
        DrawCaption(ABitmapCanvas);
        RotateBitmap(FRotateBitmap, raPlus90);
      end
      else
      begin
        RotateBitmap(FRotateBitmap, raPlus90, True);
        R.BottomRight := cxPoint(R.Bottom, R.Right);
        DrawCaption(ABitmapCanvas);
      end;
    finally
      FRotateBitmap.Canvas.Unlock;
      ABitmapCanvas.Free;
    end;
  end;
  Canvas.Draw(Bounds.Left, Bounds.Top, FRotateBitmap);
end;

function TcxSchedulerHeaderCellViewInfo.GetTextOutcxFlags: Integer;
begin
  Result := MakeTextOutcxFlags(AlignHorz, AlignVert, AutoHeight);
end;

function TcxSchedulerHeaderCellViewInfo.GetTextOutFlags: Integer;
const
  Horz: array[TAlignment] of Integer =
    (CXTO_LEFT, CXTO_RIGHT, CXTO_CENTER_HORIZONTALLY);
  Vert: array[TcxAlignmentVert] of Integer =
    (CXTO_TOP, CXTO_BOTTOM, CXTO_CENTER_VERTICALLY);
begin
  Result := CXTO_PREVENT_LEFT_EXCEED or CXTO_PREVENT_TOP_EXCEED or
    Horz[AlignHorz] or Vert[AlignVert] + CXTO_SINGLELINE;
  if AutoHeight then
  begin
    Result := CXTO_PREVENT_LEFT_EXCEED or CXTO_PREVENT_TOP_EXCEED or
      Horz[AlignHorz] or Vert[AlignVert] or CXTO_WORDBREAK;
  end;
end;

function TcxSchedulerHeaderCellViewInfo.HasImage: Boolean;
begin
  Result := ImageIndex >=0
end;

procedure TcxSchedulerHeaderCellViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  inherited InitHitTest(AHitTest);
  if IsResourceAssigned then
    AHitTest.SetBitState(htcResourceHeader, True);
  if DateTime <> NullDate then
    AHitTest.SetHitTime(htcDayHeader, DateTime);
end;

procedure TcxSchedulerHeaderCellViewInfo.TextOut(ACanvas: TcxCanvas;
  const AText: string; R: TRect);
begin
  if Length(AText) = 0 then Exit;
  if not FImageRectAssigned then
    R := cxRectInflate(R, -1, -(cxTextOffset + 1));
  with ACanvas.Canvas do
  begin
    Font := FViewParams.Font;
    Font.Color := FViewParams.TextColor;
    cxTextOut(Handle, PChar(AText), R, GetTextOutFlags);
  end;
end;

procedure TcxSchedulerHeaderCellViewInfo.ValidateSelection;
begin
  if CheckSelection and (Date = DateOf(FDateTime)) then
    FButtonState := cxbsHot;
  if Selected then
  begin
    if Selected then
      TextColor := FSelectionTextColor;
    FSelectionRect := PainterHelper.ExcludeBorders(Bounds, Borders);
    if FButtonState = cxbsHot then
    begin
      FSelectionRect.Left := Max(FSelectionRect.Left, FSelectionRect.Right -
        PainterHelper.TextWidth(Font, DisplayText) - cxTextOffset * 2);
    end;
  end;
end;

function TcxSchedulerHeaderCellViewInfo.GetHeight: Integer;
begin
  Result := Bounds.Bottom - Bounds.Top;
end;

function TcxSchedulerHeaderCellViewInfo.GetWidth: Integer;
begin
  Result := Bounds.Right - Bounds.Left;
end;

{ TcxSchedulerDayHeaderCellViewInfo }

function TcxSchedulerDayHeaderCellViewInfo.ConvertDateToDisplayText(
  AType: Integer = 0): Integer;
begin
  Result := AType - 1;
  repeat
    Inc(Result);
    if cxRectWidth(FTextRect) <= 0 then Exit;
    FDisplayText := DateTimeHelper.DayToStr(FDateTime, Result, Compressed);
  until (Result = DateTimeHelper.DayToStrFormatCount - 1) or
    (cxTextWidth(Font, DisplayText) <= cxRectWidth(FTextRect) - 2{lcm!!!});
end;

function TcxSchedulerDayHeaderCellViewInfo.CheckSelection: Boolean;
begin
  Result := True; 
end;

procedure TcxSchedulerDayHeaderCellViewInfo.DoDraw;
begin
  if Selected and not (FButtonState = cxbsHot) then
  begin
    Color := FSelectionColor;
    TextColor := FSelectionTextColor;
  end;
  inherited DoDraw;
end;

function TcxSchedulerDayHeaderCellViewInfo.DrawBackground(
  ACanvas: TcxCanvas; const ABounds: TRect): Boolean;
var
  R: TRect;
begin
  FBackgroundDrawing := True; 
  Result := inherited DrawBackground(ACanvas, ABounds);
  if Result then Exit;
  R := PainterHelper.ExcludeBorders(Bounds, Borders);
  if FButtonState = cxbsHot then
    PainterHelper.DrawGradientRect(Canvas, Color, R);
  if Selected then
  begin
    Canvas.SetBrushColor(SelectionColor);
    Canvas.FillRect(FSelectionRect);
  end;
  Result := (FButtonState = cxbsHot) or Selected;
end;

{ TcxSchedulerWeekDayHeaderCellViewInfo }

function TcxSchedulerWeekDayHeaderCellViewInfo.ConvertDateToDisplayText(
  AType: Integer = 0): Integer;
begin
  Result := AType - 1;
  repeat
    Inc(Result);
    FDisplayText := GetDayText(Result);
  until (Result = 3) or (cxTextWidth(Font, DisplayText) <= cxRectWidth(FTextRect));
  if (DateOf(FDateTime) + 1) > 7 then
    Result := 0;
end;

procedure TcxSchedulerWeekDayHeaderCellViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  inherited InitHitTest(AHitTest);
  AHitTest.SetBitState(htcTime, False);
end;

function TcxSchedulerWeekDayHeaderCellViewInfo.GetDayText(
  AType: Integer): string;
var
  ADay: Integer;
begin
  //DELPHI8! check Trunc()
  ADay := Trunc(FDateTime) + 1;
  if ADay > 7 then
  begin
    case AType of
      0:
        Result := LongDayNames[7]+ '/' + LongDayNames[1];
      1:
        Result := ShortDayNames[7]+ '/' + ShortDayNames[1];
    else
      Result := AnsiUpperCase(LongDayNames[7][1]+ '/' + LongDayNames[1][1]);
    end;
  end
  else
    case AType of
      0:
        Result := LongDayNames[ADay];
      1:
        Result := ShortDayNames[ADay];
    else
      Result := AnsiUpperCase(LongDayNames[ADay][1]);
    end;
end;

{ TcxSchedulerContainerCellViewInfo }

procedure TcxSchedulerContainerCellViewInfo.DoDraw;
begin
  DrawRect(Bounds, Borders, FDayBorderColor);
end;

procedure TcxSchedulerContainerCellViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  inherited InitHitTest(AHitTest);
  AHitTest.FHitObject := Self;
  AHitTest.SetHitTime(htcContainer, DateTime);
end;

{ TcxSchedulerTimeRulerCellViewInfo }

procedure TcxSchedulerTimeRulerCellViewInfo.Calculate(
  const ALabel1, ALabel2: string; ATimeZone, AAdditionalTimeZone: Integer);
begin
  Calculate(-1, 1, ATimeZone, AAdditionalTimeZone, nil);
  FDisplayTexts[True] := ALabel1;
  FDisplayTexts[False] := ALabel2;
end;

procedure TcxSchedulerTimeRulerCellViewInfo.Calculate(AHour, ALineCount: Integer;
  ATimeZone, AAdditionalTimeZone: Integer; ALargeFont: TFont);
begin
  FHour := AHour;
  FLineCount := ALineCount;
  FAdditionalTimeZone := AAdditionalTimeZone;
  FTimeZone := ATimeZone;
  FLargeFont := ALargeFont;
  if FVisible then
    CalculateDisplayInfo;
end;

procedure TcxSchedulerTimeRulerCellViewInfo.SetBottom(AValue: Integer);
begin
  FClipRect.Bottom := AValue;
end;

class function TcxSchedulerTimeRulerCellViewInfo.CalculateWidth(
  ATimeZoneCount, ALineCount: Integer; AFont1, AFont2: TFont): Integer;
begin
  if ALineCount = 1 then
    Result := TcxSchedulerPainterHelper.TextWidth(AFont1, ' 24:PM')
  else
  begin
    Result := TcxSchedulerPainterHelper.TextWidth(AFont1, ' 24') +
      cxTextWidth(AFont2, 'pm') + cxTextOffset;
  end;
  Inc(Result, cxTextOffset shl 2);
  if ATimeZoneCount > 1 then
    Result := Result shl 1;
end;

procedure TcxSchedulerTimeRulerCellViewInfo.CalculateDisplayInfo;
begin
  FBounds[True] := inherited Bounds;
  FDateTime := Hour * HourToTime;
  if Hour >= 0 then
    FDisplayTexts[True] := GetTimeDisplayText(FDateTime);
  FBounds[False] := inherited Bounds;
  if HasAdditionalTimeZone then
  begin
    FBounds[True].Left := cxRectCenter(inherited Bounds).X;
    FBounds[False].Right := FBounds[True].Left;
    if Hour >= 0 then
      FDisplayTexts[False] := GetTimeDisplayText(GetAdditionalTime);
  end;
end;

procedure TcxSchedulerTimeRulerCellViewInfo.DoDraw;
var
  ACurrentTimeZone: Boolean;
const
  ABorders: array[Boolean] of TcxBorders = ([bBottom], [bBottom, bRight]);
begin
  ClippingCreate(FHasClipping);
  for ACurrentTimeZone := not HasAdditionalTimeZone to True do
  begin
    if Hour >= 0 then
      DrawTimeZone(Bounds[ACurrentTimeZone],
        DisplayTexts[ACurrentTimeZone], ACurrentTimeZone)
    else
      DrawTimeZoneLabel(Bounds[ACurrentTimeZone],
        DisplayTexts[ACurrentTimeZone], ABorders[ACurrentTimeZone]);
  end;
  ClippingRestore;
end;

procedure TcxSchedulerTimeRulerCellViewInfo.DrawTimeZoneLabel(
  const ABounds: TRect; const AText: string; ABorders: TcxBorders);
begin
  DrawRect(ABounds, ABorders, clBtnShadow);
  DrawText(cxTextRect(ABounds), AText, cxAlignBottom or cxAlignLeft, Font, TextColor); 
end;

procedure TcxSchedulerTimeRulerCellViewInfo.DrawTimeZone(
  const ABounds: TRect; const AText: string; AIsCurrent: Boolean);
var
  J, LH: Integer;
  S: string;
  R, R1, TextR: TRect;
const
  cxRightCenterAlign: Integer = cxAlignVCenter or cxAlignRight or cxDontClip;
  cxRightTopAlign: Integer = cxAlignTop or cxAlignRight or cxDontClip;
begin
  LH := cxRectHeight(inherited Bounds) div LineCount;
  DrawRect(ABounds, [bRight], clBtnShadow);
  R := cxRectSetHeight(ABounds, LH);
  R.Left := (R.Left + R.Right) div 2 + cxTextOffset shl 1;
  Dec(R.Right, 6);
  for J := 0 to LineCount - 2 do
  begin
    Canvas.FrameRect(R, clBtnShadow, 1, [bBottom]);
    OffsetRect(R, 0, LH);
  end;
  Canvas.Brush.Style := bsClear;
  TextR := cxRectInflate(PainterHelper.ExcludeBorders(ABounds,
    [bRight, bBottom]), -5, -cxTextOffset);
  if AIsCurrent then
    DrawCurrentTime(FDateTime, ABounds);
  if LineCount > 1 then
  begin
    J := Length(AText);
    DrawText(Rect(TextR.Left, TextR.Top, R.Left - cxTextOffset, TextR.Bottom),
      Copy(AText, 1, J - 3), cxRightTopAlign, LargeFont, TextColor);
    R1 := Rect(R.Left, TextR.Top, TextR.Right, TextR.Top + LH - 3);
    DrawText(R1, Copy(AText, J - 1, 2), cxAlignCenter, Font, TextColor);
    if ShowMinutes and AIsCurrent then
      for J := 1 to LineCount - 1 do
      begin
        OffsetRect(R1, 0, LH);
        S := IntToStr(MulDiv(60, J, LineCount));
        if Length(S) < 2 then
          S := '0' + S;
        DrawText(R1, S, cxAlignCenter, Font, TextColor);
      end;
  end
  else
    DrawText(TextR, AText, cxRightCenterAlign, Font, TextColor);
  R.Left := ABounds.Left + 5;
  if (Hour <> 23) and not LastVisibleHour then
    DrawFrame(R, [bBottom], clBtnShadow)
  else
    DrawFrame(ABounds, [bBottom], clBtnShadow);
end;

procedure TcxSchedulerTimeRulerCellViewInfo.DrawCurrentTime(
  const AStart: TDateTime; ABounds: TRect);
var
  Y: Integer;
  ANow: TDateTime;
begin
  ANow := TimeOf(Now) - TimeOf(AStart);
  if (ANow < 0) or (ANow >= HourToTime) then Exit;
  Y := Round(ABounds.Top + (ANow * cxRectHeight(ABounds)) / HourToTime);
  Dec(Y, 3);
  Dec(ABounds.Right);
  if Y < ABounds.Top then
    Y := ABounds.Top;
  PainterHelper.DrawGradientRect(Canvas, Color, cxRectSetTop(ABounds, Y - 6, 6));
  Canvas.Brush.Style := bsClear;
end;

function TcxSchedulerTimeRulerCellViewInfo.GetAdditionalTime: TDateTime;
begin
  Result := DateTimeHelper.ConvertToAnotherTimeZone(
    Hour * HourToTime + Date, TimeZone, AdditionalTimeZone);
end;

function TcxSchedulerTimeRulerCellViewInfo.GetTimeDisplayText(
  const ATime: TDateTime): string;
var
  APos: Integer;
begin
  Result := DateTimeHelper.TimeToStr(ATime);
  if LineCount > 1 then
  begin
    APos := Pos(TimeSeparator, Result);
    if APos = 0 then
      APos := Pos(' ', Result);
    if APos = 0 then
      APos := Length(Result) - 2;
    Result := Copy(Result, 1, APos - 1) + ' ' + AnsiLowerCase(Copy(Result, APos + 1, 2));
  end;
end;

procedure TcxSchedulerTimeRulerCellViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
var
  LH: Integer;
  ACurrentTimeZone: Boolean;
  ATime, ATimePerLine: TDateTime;
begin
  inherited InitHitTest(AHitTest);
  if Hour >= 0 then
  begin
    LH := cxRectHeight(inherited Bounds) div FLineCount;
    ATimePerLine := 60 / FLineCount * MinuteToTime;
    ATime := (AHitTest.HitY - inherited Bounds.Top) div LH * ATimePerLine + FHour * HourToTime;
    AHitTest.SetHitTime(htcTimeRuler, ATime);
  end
  else
    AHitTest.SetBitState(htcTimeZoneLabel, True);
  for ACurrentTimeZone := not HasAdditionalTimeZone to True do
    if PtInRect(Bounds[ACurrentTimeZone], AHitTest.HitPoint) then
    begin
      if ACurrentTimeZone then
        AHitTest.FTimeZone := TimeZone
      else
        AHitTest.FTimeZone := AdditionalTimeZone;
    end;
end;

procedure TcxSchedulerTimeRulerCellViewInfo.AfterCustomDraw(ACanvas: TcxCanvas);
begin
  FViewParams.TextColor := ACanvas.Font.Color;
  FViewParams.Color := ACanvas.Brush.Color;
end;

function TcxSchedulerTimeRulerCellViewInfo.GetBoundsRect(
  AType: Boolean): TRect;
begin
  Result := FBounds[AType];
end;

function TcxSchedulerTimeRulerCellViewInfo.GetDisplayText(
  AType: Boolean): string;
begin
  Result := FDisplayTexts[AType];
end;

function TcxSchedulerTimeRulerCellViewInfo.GetHasAdditionalTimeZone: Boolean;
begin
  Result := AdditionalTimeZone >= 0;
end;

{ TcxSchedulerContentCellViewInfo }

constructor TcxSchedulerContentCellViewInfo.Create(
  APainter: TcxCustomLookAndFeelPainterClass;
  const ABounds, AVisibleRect: TRect; const AViewParams: TcxViewParams);
begin
  inherited Create(APainter, ABounds, AVisibleRect, AViewParams);
  FTimeLineBorders := [bLeft, bRight];
  BorderColor := clDefault; 
end;

procedure TcxSchedulerContentCellViewInfo.SetTime(
  const ATimeStart, ATimeFinish: TDateTime);
begin
  FDateTime := ATimeStart;
  FTimeFinish := ATimeFinish;
end;

procedure TcxSchedulerContentCellViewInfo.DoDraw;
var
  R: TRect;
begin
  if BorderColor = clDefault then
    BorderColor := FDayBorderColor;
  if FShowTimeLine then
  begin
    R := Bounds;
    Inc(R.Left, cxTimeLineWidth);
    DrawRect(R, Borders, BorderColor);
    R := cxRectSetRight(R, R.Left, cxTimeLineWidth);
    if FTimeEvent = nil then
      Canvas.FillRect(R, FTimeLineParams, FTimeLineBorders, FTimeLineParams.TextColor)
    else
      FTimeEvent.DrawState(Canvas, R, FTimeLineBorders, FTimeLineParams.TextColor);
  end
  else
    DrawRect(Bounds, Borders, BorderColor);
end;

procedure TcxSchedulerContentCellViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  inherited InitHitTest(AHitTest);
  AHitTest.SetHitTime(htcContent, FDateTime);
  AHitTest.FHitObject := Self;
end;

{ TcxSchedulerBackgroundSlotCellViewInfo }

procedure TcxSchedulerBackgroundSlotCellViewInfo.DoDraw;
begin
  inherited DoDraw;
end;

{ TcxSchedulerMonthDayContentCellViewInfo }

destructor TcxSchedulerMonthDayContentCellViewInfo.Destroy;
begin
  if FSmallFontCreated then
    FreeAndNil(FSmallTextFont);
  inherited Destroy;
end;

procedure TcxSchedulerMonthDayContentCellViewInfo.SetContentState(
  AsDayOfMonth: Boolean; ASelected: Boolean;
  ATextHeight: Integer; const ASelectionParams: TcxViewParams);
begin
  FSelectionColor := ASelectionParams.Color;
  FSelectionTextColor := ASelectionParams.TextColor;
  FTextRect := PainterHelper.ExcludeBorders(Bounds, Borders);
  if AsDayOfMonth then
    FDisplayText := IntToStr(DayOf(TimeStart))
  else
    FDisplayText := GetLongDisplayText;
  FSelected := ASelected;
  FTextRect.Bottom := Min(FTextRect.Bottom, FTextRect.Top + ATextHeight);
  if not SmallFont then
    FTextRect.Left := Max(FTextRect.Left,
      FTextRect.Right - PainterHelper.TextWidth(Font, DisplayText)) - cxTextOffset * 2
  else
  begin
    if FSmallTextFont = nil then
    begin
      SmallTextFont := TFont.Create;
      FSmallFontCreated := True;
      FSmallTextFont.Assign(Font);
      FSmallTextFont.Size := Round(Font.Size * 2 / 3);
    end;
    FTextRect.Left := Max(FTextRect.Left, FTextRect.Right -
      PainterHelper.TextWidth(FSmallTextFont, DisplayText)) - cxTextOffset;
  end;
end;

function TcxSchedulerMonthDayContentCellViewInfo.UpdateSelection(ASelected: Boolean): Boolean;
begin
  Result := FSelected <> ASelected;
  if Result then
    FSelected := ASelected; 
end;

procedure TcxSchedulerMonthDayContentCellViewInfo.DoDraw;
const
  TextFlags = CXTO_PREVENT_LEFT_EXCEED or CXTO_PREVENT_TOP_EXCEED or
              CXTO_CENTER_VERTICALLY or CXTO_RIGHT;
var
  R: TRect;
  AColor: Integer; 
begin
  inherited DoDraw;
  if DisplayText <> '' then
  begin
    R := PainterHelper.ExcludeBorders(Bounds, Borders);
    R.Bottom := FTextRect.Bottom;
    if not Transparent and IsToday then
      PainterHelper.DrawGradientRect(Canvas, Color, R);
    if Selected then
    begin
      Inc(R.Top);
      InflateRect(R, -1, 0);
      Canvas.SetBrushColor(SelectionColor);
      if not IsToday then
        Canvas.FillRect(R)
      else
      begin
        R := FTextRect;
        R.Left := Max(Bounds.Left, (R.Left - cxTextOffset * 2));
        Inc(R.Bottom);
        InflateRect(R, -1, -1);
        Canvas.FillRect(R);
      end;
    end;
    if SmallFont then
      Canvas.Font := SmallTextFont
    else
      Canvas.Font := Font;
    if Selected then
      AColor := SelectionTextColor
    else
      AColor := TextColor;
    Canvas.Brush.Style := bsClear;
    AColor := Windows.SetTextColor(Canvas.Handle, ColorToRgb(AColor));
    cxTextOut(Canvas.Handle, PChar(DisplayText),
      FTextRect, TextFlags, 0, 0, cxTextOffset + 1);
    Windows.SetTextColor(Canvas.Handle, AColor);
  end;
end;

function TcxSchedulerMonthDayContentCellViewInfo.GetLongDisplayText: string;
begin
  Result := LongMonthNames[MonthOf(TimeStart)] + ', ' + IntToStr(DayOf(TimeStart));
  if cxTextWidth(Font, Result) >= (cxRectWidth(FTextRect) div 2) then
    Result := ShortMonthNames[MonthOf(TimeStart)] + ' ' + IntToStr(DayOf(TimeStart));
end;

function TcxSchedulerMonthDayContentCellViewInfo.GetIsToday: Boolean;
begin
  Result := Date = TimeStart;
end;

procedure TcxSchedulerMonthDayContentCellViewInfo.SetSmallTextFont(AFont: TFont);
begin
  if FSmallFontCreated then
     FreeAndNil(FSmallFont);
  FSmallTextFont := AFont;
end;

{ TcxSchedulerEventCellViewInfo }

constructor TcxSchedulerEventCellViewInfo.Create(
  AViewData: TcxSchedulerEventViewData);
begin
  inherited Create(AViewData.Painter, AViewData.Bounds,
    AViewData.VisibleRect, AViewData.ViewParams);
  ViewData := AViewData;
  FSeparatorColor := clBtnShadow;
  FCanvas := AViewData.Canvas;
  FImages := TcxSchedulerEventImages.Create(AViewData.ImagesLayout);
  Initialize;
end;

destructor TcxSchedulerEventCellViewInfo.Destroy;
begin
  ViewData.Free;
  FImages.Free;
  FEditViewInfo.Free;
  inherited Destroy;
end;

procedure TcxSchedulerEventCellViewInfo.Draw(
  ACanvas: TcxCanvas; ABitmap: TBitmap);
begin
  ViewData.Bitmap := ABitmap;
  inherited Draw(ACanvas);
end;

procedure TcxSchedulerEventCellViewInfo.DrawState(ACanvas: TcxCanvas;
  const ARect: TRect; ABorders: TcxBorders; ABorderColor: TColor);
begin
  PainterHelper.DrawState(ACanvas, ARect, Event.State, ABorders, ABorderColor);
end;

function TcxSchedulerEventCellViewInfo.MeasureHeight(ACanvas: TcxCanvas): Integer;
var
  L: TList;
begin
  Canvas.Font := Font;
  FIsHeaderEvent := GetIsHeaderEvent;
  CalculateVisibility;
  FCaptionRect := cxRectInflate(Bounds, -(cxTextOffset + 1), -(cxTextOffset + 1));
  L := Images.CreateVisibleList;
  try
    case Images.Layout of
      eilHorizontal:
        Result := CalculateHorizontalImagesAutoHeight;
      eilVertical:
        Result := CalculateVerticalImagesAutoHeight;
      else //eilAuto:;
        Result := CalculateAutoLayoutImagesAutoHeight(L);
    end;
  finally
    L.Free;
  end;
  Result := Max(ViewData.LineHeight, Result);
end;

procedure TcxSchedulerEventCellViewInfo.MoveTo(X, Y: Integer);

  procedure ShiftRect(var R: TRect);
  begin
    if not cxRectIsEmpty(R) then OffsetRect(R, X, Y);
  end;

var
  I: Integer;
begin
  ShiftRect(ViewData.Bounds);
  CalculateCellBounds(ViewData.Bounds, ViewData.VisibleRect);
  if not Visible or Hidden then Exit;
  ShiftRect(FCaptionRect);
  ShiftRect(FFinishRect);
  ShiftRect(FMessageRect);
  ShiftRect(FStartRect);
  ShiftRect(FEventTimeRect);
  ShiftRect(FTimeLineRect);
  if FShowMessage then
    CalculateEditViewInfo;
  for I := 0 to Images.Count - 1 do
    ShiftRect(Images[0].FBounds);
end;

procedure TcxSchedulerEventCellViewInfo.AssignEditStyle(
  AEditStyle: TcxCustomEditStyle);
var
  AStyle: TcxCustomEditStyleAccess;
begin
  AStyle := TcxCustomEditStyleAccess(AEditStyle);
  AStyle.FAssignedValues := AStyle.FAssignedValues -
    [svFont] + [svColor, svButtonTransparency];
  AStyle.StyleData.Font := Font;
  AStyle.StyleData.Color := Color;
  AStyle.StyleData.FontColor := TextColor;
  AStyle.ButtonTransparency :=  ebtHideInactive;
  AStyle.Changed;
end;

procedure TcxSchedulerEventCellViewInfo.BeforeCustomDraw(ACanvas: TcxCanvas);
begin
  FViewParams := ViewData.ViewParams;
  inherited BeforeCustomDraw(ACanvas);
end;

procedure TcxSchedulerEventCellViewInfo.Calculate;
begin
  Canvas.Font := Font;
  CalculateItemsLayout;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateBorders;
begin
end;

procedure TcxSchedulerEventCellViewInfo.CalculateCaptions;
begin
  FStartText := DateTimeHelper.TimeToStrEx(EventStart);
  FFinishText := DateTimeHelper.TimeToStrEx(EventFinish);
end;

procedure TcxSchedulerEventCellViewInfo.CalculateDetailInfo;
begin
  FIsDetailInfo := ViewData.AutoHeight or (not IsHeaderEvent and
    ((TimeOf(ContentFinish) <> 0) or (TimeOf(ContentStart) <> 0)));
  FIsDetailCaption := FIsDetailInfo and not IsHeaderEvent;
  FShowMessage := IsDetailInfo and (Length(Message) > 0);
end;

procedure TcxSchedulerEventCellViewInfo.CalculateNeedHint;
var
  R: TRect;
begin
  if FHintNeededCalculated then Exit; 
  R := FCaptionRect;
{$IFDEF USECXTEXTOUT}
  with TcxScreenCanvas.Create do
  try
    Font := Self.Font;
    cxTextOut(Canvas, PChar(ViewData.Caption), R, CXTO_CALCRECT or cxTextOutFlags[IsDetailCaption]);
  finally
    Free;
  end;
{$ELSE}
  Canvas.TextExtent(ViewData.Caption, R, cxDrawTextFlags[IsDetailCaption]);
{$ENDIF}
  FHintNeeded := (FCaptionRect.Right < R.Right) or (FCaptionRect.Bottom < R.Bottom);
  FHintNeededCalculated := True; 
end;

procedure TcxSchedulerEventCellViewInfo.CalculateEditViewInfo;
var
  AProperties: TcxCustomEditProperties;
  AEditViewData: TcxCustomEditViewData;
begin
  if not ViewData.AutoHeight then
  begin
    FMessageRect := GetMessageRect(CaptionRect, Images.VisibleImageCount > 0);
    FCaptionRect.Bottom := Min(FMessageRect.Top, Bounds.Bottom - cxTextOffset);
  end;
  if cxRectIsEmpty(FMessageRect) then
  begin
    FShowMessage := False;
    Exit;
  end;
  if FEditViewInfo = nil then
    FEditViewInfo := TcxCustomEditViewInfo(ViewData.EditProperties.GetViewInfoClass.Create);
  AProperties := ViewData.EditProperties;
  AEditViewData := AProperties.CreateViewData(ViewData.EditStyle, True);
  try
    Include(AEditViewData.PaintOptions, epoAutoHeight);
    AssignEditStyle(ViewData.EditStyle);
    AEditViewData.ContentOffset := cxSimpleRect;
    AEditViewData.EditValueToDrawValue(Canvas, Message, FEditViewInfo);
    AEditViewData.CalculateEx(Canvas, FMessageRect,
      cxInvalidPoint, cxmbNone, [], FEditViewInfo, False);
  finally
    AEditViewData.Free;
  end;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateShowTimeAsClock;
begin
  ViewData.ShowTimeAsClock := IsHeaderEvent or
    (ViewData.ShowTimeAsClock and not IsDetailInfo);
end;

function TcxSchedulerEventCellViewInfo.CalculateAutoLayoutImagesAutoHeight(
  AVisibleImages: TList): Integer;

  function GetEventTextsHeight(const AWidth: Integer): Integer;
  var
    R: TRect;
  begin
    R := cxRect(0, 0, AWidth, MaxInt);
    Result := GetCaptionAutoHeight(R) + 2 * cxTextOffset;
    if ShowMessage then
    begin
      Inc(R.Right, 3);
      Inc(Result, CalculateMessageHeight(R) + 1);
    end;
  end;

  function GetColCountForRowCount(ARowCount: Integer): Integer;
  begin
    Result := Images.TotalVisibleImageCount div ARowCount;
    if (Images.TotalVisibleImageCount mod ARowCount) > 0 then
      Inc(Result);
    Result := Max(1, Result);
  end;
var
  I, ANewColCount, ACaptionWidth, ASpaceWidth, AImagesHeight,
  AImagesWidth, AImagesColCount, AImagesRowCount,
  ATextsHeight: Integer;
begin
  ASpaceWidth := cxRectWidth(Bounds) - 2 * cxTextOffset;
  ACaptionWidth := Canvas.TextWidth(Caption);
  if (Images.TotalVisibleImageCount < 2) or
   (ASpaceWidth >= Images.TotalVisibleWidth + cxEventImagesGap + ACaptionWidth) then
  begin
    Result := CalculateHorizontalImagesAutoHeight;
    Exit;
  end;
  AImagesWidth := 0;
  AImagesRowCount := 1;
  AImagesColCount := 0;
  for I := 1 to Images.TotalVisibleImageCount do
  begin
    AImagesRowCount := I;
    AImagesHeight := Min(Images.TotalVisibleImageCount, (AImagesRowCount + 1)) *
      (Images.ItemHeight + cxEventImagesGap) + 4;
    ANewColCount := GetColCountForRowCount(AImagesRowCount);
    if ANewColCount <> AImagesColCount then
    begin
      AImagesColCount := ANewColCount;
      AImagesWidth := AImagesColCount * (Images.ItemWidth + cxEventImagesGap) + 1;
      if ASpaceWidth <= AImagesWidth then Continue;
      ATextsHeight := GetEventTextsHeight(ASpaceWidth - AImagesWidth);
      if ATextsHeight < AImagesHeight then Break;
    end
    else Continue;
  end;
  Result := AImagesRowCount * (Images.ItemHeight + cxEventImagesGap) + 1;
  Images.CalculateForCols(AVisibleImages,
    cxPointOffset(Bounds.TopLeft, cxEventImagesOffset + cxEventBorderWidth,
    cxEventImagesOffset + cxEventBorderWidth), AImagesColCount);
  Inc(FCaptionRect.Left,  AImagesWidth);
  CalculateMessageAutoLayout(Result);
end;

function TcxSchedulerEventCellViewInfo.CalculateHorizontalImagesAutoHeight: Integer;
var
  ARightLimit, ACaptionWidth, ACaptionHeight, AMessageHeight, ASpaceWidth,
  AMessageTop, AImagesWidth: Integer;
  AImagesRect, R: TRect;
begin
  Result := Images.ItemHeight + cxTextOffset;
  ASpaceWidth := cxRectWidth(Bounds) - 2 * cxTextOffset;
  ACaptionWidth := Canvas.TextWidth(Caption);
  AImagesRect := cxRectInflate(Bounds, -cxTextOffset, -cxTextOffset);
  if Images.ForceVisibleWidth + cxEventImagesGap >= ASpaceWidth then
  begin
    FCaptionRect := cxNullRect;
    Images.CalculateSingleLineImages(AImagesRect);
    AMessageTop := Bounds.Top + cxTextOffset + Result + cxEventImagesGap;
  end
  else
  begin
    ARightLimit := 0;
    if not (Images.TotalVisibleWidth + cxEventImagesGap + ACaptionWidth <= ASpaceWidth) then
    begin
      R := FCaptionRect;
      R.Left := Min(AImagesRect.Left + Images.TotalVisibleWidth, R.Right - 1);
      Canvas.TextExtent(Caption, R, cxWordBreak or cxDontBreakChars);
      if R.Right > FCaptionRect.Right then
      begin
        ACaptionWidth := cxRectWidth(R);
        Dec(AImagesRect.Right, ACaptionWidth);
        ARightLimit := Bounds.Right - cxTextOffset - cxRectWidth(R);
      end;
    end;
    AImagesWidth := Images.CalculateSingleLineImages(AImagesRect, ARightLimit);
    if AImagesWidth > 0 then Inc(AImagesWidth);
    Inc(FCaptionRect.Left, AImagesWidth);
    ACaptionHeight := GetCaptionAutoHeight(CaptionRect);
    FCaptionRect.Bottom := FCaptionRect.Top + ACaptionHeight;
    Result := Max(Result, ACaptionHeight + 2 * cxTextOffset);
    AMessageTop := FCaptionRect.Top + Result;
  end;
  if FShowMessage then
  begin
    FMessageRect := cxRect(Bounds.Left + cxEventImagesGap, AMessageTop - 1, Bounds.Right - 1, 0);
    AMessageHeight := CalculateMessageHeight(FMessageRect);
    FMessageRect.Bottom := FMessageRect.Top + AMessageHeight;
    Inc(Result, AMessageHeight + 1);
    CalculateEditViewInfo;
  end;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateMessageAutoLayout(var AHeight: Integer);
var
  ACaptionHeight, AMessageHeight, AMessageTop: Integer;
begin
  if not cxRectIsEmpty(CaptionRect) then
  begin
    ACaptionHeight := GetCaptionAutoHeight(CaptionRect);
    FCaptionRect.Bottom := CaptionRect.Top + ACaptionHeight;
    Inc(ACaptionHeight, 2 * cxTextOffset);
    AHeight := Max(AHeight, ACaptionHeight);
    if FShowMessage then
    begin
      AMessageTop := FCaptionRect.Top +  ACaptionHeight - 1;
      FMessageRect := cxRect(FCaptionRect.Left - 2, AMessageTop, Bounds.Right - 1, 0);
      AMessageHeight := CalculateMessageHeight(FMessageRect);
      FMessageRect.Bottom := FMessageRect.Top + AMessageHeight;
      AHeight := Max(AHeight, ACaptionHeight + AMessageHeight);
      CalculateEditViewInfo;
    end;
  end
  else FShowMessage := False;
end;

function TcxSchedulerEventCellViewInfo.CalculateVerticalImagesAutoHeight: Integer;
var
  AImagesRect: TRect;
begin
  Result := Images.ItemHeight + cxTextOffset;
  if Images.TotalVisibleHeight > 0 then
  begin
    AImagesRect := cxRectInflate(Bounds, -cxTextOffset, -cxTextOffset);
    AImagesRect.Bottom := AImagesRect.Top + Images.TotalVisibleHeight;
    if (cxRectWidth(AImagesRect) > Images.ItemWidth + cxEventImagesGap) or
       (Images.ForceVisibleHeight > 0) then
    begin
      Inc(FCaptionRect.Left, Images.ItemWidth + cxTextOffset);
      Result := Images.TotalVisibleHeight + cxEventImagesGap;
    end;
    Images.CalculateSingleColumnImages(AImagesRect);
  end;
  CalculateMessageAutoLayout(Result);
end;

procedure TcxSchedulerEventCellViewInfo.CalculateItemsLayout;
begin
  if IsDetailInfo then
    CalculateDetailViewEventLayout
  else
    CalculateHeaderEventLayout;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateDetailViewEventLayout;
var
  AImagesWidth: Integer;
begin
  FCaptionRect := cxRectInflate(Bounds, -cxTextOffset, -(cxTextOffset + 1));
  AImagesWidth := Images.Calculate(GetImagesBounds);
  Images.Offset(0, GetImagesVerticalOffset(Images.ItemHeight, False));
  Inc(FCaptionRect.Left, AImagesWidth + cxEventImagesGap);
  if FShowMessage then CalculateEditViewInfo;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateHeaderEventLayout;
var
  ACaptionRect: TRect;
  ALeft, AWidth, AImagesWidth, ACaptionWidth, AVertOffset: Integer;
  ACanShowClock: Boolean;
  R: TRect;

  procedure CalculateCaption;
  var
    R: TRect;
  begin
    InflateRect(ACaptionRect, -cxTextOffset, 0);
    R := cxRectSetLeft(cxRectInflate(Bounds, -1, -1), 0,
      cxRectWidth(ACaptionRect) - (ACaptionWidth + cxTextOffset));
    AImagesWidth := Images.CalculateSingleLineImages(R);
    if AImagesWidth <> 0 then Inc(AImagesWidth, cxTextOffset);
    AWidth := AImagesWidth + ACaptionWidth;
  end;

begin
  FCaptionRect := cxRectInflate(Bounds, -cxTextOffset, -1);
  R := cxRect(0, 0, EventImages.Width, EventImages.Height);
  AVertOffset := GetImagesVerticalOffset(R.Bottom, True);
  ACaptionWidth := Canvas.TextWidth(ViewData.Caption);
  ACaptionRect := FCaptionRect;
  ACanShowClock := cxRectWidth(ACaptionRect) >= EventImages.Width + cxEventImagesGap;
  if ShowStartTime and ACanShowClock then
  begin
    FStartRect := cxRectOffset(R, Bounds.Left + (cxEventBorderWidth + cxEventImagesOffset), AVertOffset);
    ACaptionRect.Left := FStartRect.Right;
  end;
  if ShowFinishTime and ACanShowClock then
  begin
    FFinishRect := cxRectOffset(R, Bounds.Right - R.Right - (cxEventBorderWidth + cxEventImagesOffset), AVertOffset);
    ACaptionRect.Right := FFinishRect.Left;
  end;
  CalculateCaption;
  if (ShowStartTime or ShowFinishTime) and
    (ACaptionWidth + Images.TotalVisibleWidth > cxRectWidth(ACaptionRect)) and
    not GetForceShowClockInHeaderEvent then
  begin
    FStartRect := cxEmptyRect;
    FFinishRect := cxEmptyRect;
    ViewData.ShowStartTime := False;
    ViewData.ShowFinishTime := False;
    ACaptionRect := FCaptionRect;
    CalculateCaption;
  end;
  with ACaptionRect do
    ALeft := Max(Left + ((Right - Left - AWidth) div 2), ACaptionRect.Left);
  Images.Offset(ALeft, GetImagesVerticalOffset(Images.ItemHeight, False));
  ACaptionRect.Left := ALeft + AImagesWidth;
  FCaptionRect := ACaptionRect;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateNonDetailEventLayout;
var
  R: TRect;
  ALeft, ACaptionWidth, AImagesWidth: Integer;
begin
  FCaptionRect := cxRectInflate(Bounds, -cxTextOffset, -1);
  ALeft := CaptionRect.Left;
  ACaptionWidth := Canvas.TextWidth(ViewData.Caption);
  R := CalculateNonDetailEventImages(ACaptionWidth, AImagesWidth);
  if ShowFinishTime or ShowStartTime then
  begin
    if ShowTimeAsClock then
      CalculateEventTimeAsClockLayout(R, ACaptionWidth, AImagesWidth, ALeft)
    else
      CalculateEventTimeAsTextLayout(R, ACaptionWidth, AImagesWidth, ALeft);
  end;
  AImagesWidth := Images.Offset(ALeft - FCaptionRect.Left,
    GetImagesVerticalOffset(Images.ItemHeight, False));
  if AImagesWidth > 0 then Inc(AImagesWidth);
  Inc(ALeft, AImagesWidth + cxEventImagesOffset);
  FCaptionRect.Left := ALeft;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateEventTimeAsClockLayout(
  const ABounds: TRect; const ACaptionWidth, AImagesWidth: Integer; var ALeft: Integer);
var
  R: TRect;
  AVertOffset: Integer;
begin
  R := cxRectBounds(0, 0, TcxSchedulerPainterHelper.IconsWidth,
    TcxSchedulerPainterHelper.IconsHeight);
  AVertOffset := GetImagesVerticalOffset(R.Bottom, True);
  FStartRect := SetItemRect(ShowStartTime, R, AVertOffset, ALeft);
  FFinishRect := SetItemRect(ShowFinishTime, R, AVertOffset, ALeft);
  Inc(ALeft);
end;

procedure TcxSchedulerEventCellViewInfo.CalculateEventTimeAsTextLayout(
  const ABounds: TRect; const ACaptionWidth, AImagesWidth: Integer; var ALeft: Integer);
var
  ASpaceWidth, AWidth: Integer;
  R: TRect;
begin
  ASpaceWidth := cxRectWidth(ABounds) - AImagesWidth;
  with Canvas.TextExtent('00:00') do
    R := cxRectBounds(ABounds.Left, 0, CX, CY);
  if not Is24HourTimeFormat then
    R := cxRectSetWidth(R, Max(Canvas.TextWidth('00:00' + TimeAMString),
      Canvas.TextWidth('00:00' + TimePMString)));
  AWidth := cxRectWidth(R);
  if ASpaceWidth >= AWidth then
  begin
    FStartRect := cxRect(ALeft, FCaptionRect.Top, ALeft + AWidth, FCaptionRect.Bottom);
    Inc(AWidth, Canvas.TextWidth('0') div 2);
    Inc(ALeft, AWidth);
    Dec(ASpaceWidth, AWidth);
    if ShowFinishTime and (ASpaceWidth >= AWidth) then
    begin
      FFinishRect := cxRectOffset(FStartRect, AWidth, 0);
      Inc(ALeft, AWidth);
    end;
  end;
end;

function TcxSchedulerEventCellViewInfo.CalculateNonDetailEventImages(
  const ACaptionWidth: Integer; out AImagesWidth: Integer): TRect;
begin
  Result := GetImagesBounds;
  AImagesWidth := CalculateSingleLineImages(Result);
end;

function TcxSchedulerEventCellViewInfo.CalculateSingleLineImages(
  const ABounds: TRect; ARightLimit: Integer = 0): Integer;
begin
  Result := Images.CalculateSingleLineImages(ABounds, ARightLimit);
end;

function TcxSchedulerEventCellViewInfo.SetItemRect(AShowItem: Boolean;
  const ABounds: TRect; AVertOffset: Integer; var APos: Integer): TRect;
begin
  Result := cxNullRect;
  if AShowItem then
  begin
    if ((APos + cxRectWidth(ABounds)) <= cxRectCenter(FBounds).X) then
    begin
      Result := cxRectOffset(ABounds, APos, AVertOffset);
      APos := Result.Right + cxTextOffset;
    end;
  end
end;

procedure TcxSchedulerEventCellViewInfo.CalculateEventTimeVisibility;
begin
  if IsDetailInfo then
    CalculateDetailEventTimeVisibility
  else
    CalculateNonDetailEventTimeVisibility;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateDetailEventTimeVisibility;
begin
  ViewData.ShowFinishTime := (IsDetailCaption and ViewData.AlwaysShowTime) or
    ((ViewData.ContentFinish > EventFinish) and (ViewData.ContentStart <> EventFinish)) or
    (ViewData.ContentStart < EventStart);
  ViewData.ShowStartTime := ViewData.ShowFinishTime;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateNonDetailEventTimeVisibility;
begin
  if Event.AllDayEvent then
  begin
    ViewData.ShowFinishTime := False;
    ViewData.ShowStartTime := False;
  end
  else
  begin
    ViewData.ShowFinishTime := (ViewData.ContentFinish >= EventFinish) and
      (ViewData.ShowFinishTime or (Event.Duration >= 1));
    ViewData.ShowStartTime := (ContentStart <= EventStart);
  end;
end;

procedure TcxSchedulerEventCellViewInfo.CalculateVisibility;
begin
  if ViewData.ShowTimeLine then
  begin
    if Selected then
      FVisible := cxRectIntersect(FClipRect, cxRectInflate(Bounds, 0, cxTimeLineWidth), ViewData.VisibleRect);
  end
  else
    FVisible := FVisible and (FClipRect.Bottom = FBounds.Bottom);
  CalculateDetailInfo;
  CalculateShowTimeAsClock;
  CalculateEventTimeVisibility;
  CalculateBorders;
end;

function TcxSchedulerEventCellViewInfo.CanAutoHideStandardImages: Boolean;
begin
  Result := False;
end;

procedure TcxSchedulerEventCellViewInfo.DoDraw;
begin
  if FHidden then Exit;
  ClippingCreate(True);
  DrawContent;
  ClippingRestore;
end;

procedure TcxSchedulerEventCellViewInfo.DrawCaption;
begin
  if cxRectIsEmpty(FCaptionRect) or (ViewData.Caption = '') then Exit;
{$IFDEF USECXTEXTOUT}
  cxTextOut(Canvas.Canvas, PChar(ViewData.Caption), FCaptionRect, cxTextOutFlags[IsDetailCaption]);
{$ELSE}
  Canvas.Brush.Style := bsClear;
  Canvas.DrawText(ViewData.Caption, FCaptionRect, cxDrawTextFlags[IsDetailCaption]);
  Canvas.Brush.Style := bsSolid;
{$ENDIF}
end;

procedure TcxSchedulerEventCellViewInfo.DrawContent;
begin
  DrawRect(FBounds, FBorders, ViewData.BorderColor);
  if not Event.IsEditing then
    DrawImages;
  if IsNeedDrawTime then
    DrawTime;
  DrawCaption;
  if FShowMessage then
  begin
    FEditViewInfo.Transparent := True;
    FEditViewInfo.TextColor := TextColor;
    FEditViewInfo.PaintEx(Canvas);
    DrawMessageSeparator;
  end;
end;

procedure TcxSchedulerEventCellViewInfo.DrawImages;
var
  I: Integer;
  ASaveRgn: TcxRegion;
begin
  with Images do
  begin
    if Count = 0 then Exit;
    ASaveRgn := Canvas.GetClipRegion;
    Canvas.IntersectClipRect(cxRectInflate(Bounds, -1, -1));
    for I := 0 to Count - 1 do
      with Items[I] do
        if Visible and not FHidden then
        begin
          Images.DrawingStyle := dsTransparent;
          Canvas.DrawImage(Images, Bounds.Left, Bounds.Top, ImageIndex);
        end;
    Canvas.SetClipRegion(ASaveRgn, roSet);
  end;
end;

procedure TcxSchedulerEventCellViewInfo.DrawMessageSeparator;
var
  R: TRect;
begin
  R := cxRectInflate(MessageRect, -(1 + Byte(not ShowTimeLine)), 1, -2, 0);
  Canvas.FrameRect(R, SeparatorColor, 1, [bTop]);
end;

procedure TcxSchedulerEventCellViewInfo.DrawTime;
const
  RightJustify = cxAlignRight or cxAlignVCenter or cxSingleLine;
begin
  if ShowTimeAsClock then
  begin
    if ShowStartTime then
      PainterHelper.DrawClock(Canvas, FStartRect, Event.Start, FViewParams);
    if ShowFinishTime then
      PainterHelper.DrawClock(Canvas, FFinishRect, Event.Finish, FViewParams);
  end
  else
  begin
    DrawText(FStartRect, FStartText, RightJustify);
    DrawText(FFinishRect, FFinishText, RightJustify);
  end;
end;

function TcxSchedulerEventCellViewInfo.GetCaptionAutoHeight(const R: TRect): Integer;
begin
  if (Caption <> '') and not cxRectIsEmpty(CaptionRect) then
    Result := GetTrueMultilineTextHeight(Canvas, ViewData.Caption, R)
  else
    Result := Canvas.FontHeight(Font);
end;

function TcxSchedulerEventCellViewInfo.GetEditingRect: TRect;
begin
  cxRectIntersect(Result, PainterHelper.ExcludeBorders(Bounds, Borders), FClipRect);
  with Result do
  begin
    if IsDetailCaption then
    begin
      Inc(Left, cxTextOffset - Byte(bLeft in Borders));
      Dec(Right);
    end
    else
      Inc(Left);      
  end;
end;

function TcxSchedulerEventCellViewInfo.GetForceShowClockInHeaderEvent: Boolean;
begin
  Result := True;
end;

function TcxSchedulerEventCellViewInfo.GetHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest; var ABreak: Boolean): Boolean;
begin
  Result := inherited GetHittest(AHitTest, ABreak);
  Result := Result and not Hidden;
  if Result and not Hidden and ShowTimeLine and Selected then
    ABreak := not PtInRect(CaptionRect, AHitTest.HitPoint) and not
      PtInRect(MessageRect, AHitTest.HitPoint)
  else
    ABreak := False;
end;

function TcxSchedulerEventCellViewInfo.GetImagesBounds: TRect;
begin
  with Bounds do
    Result := cxRect(Left + cxEventBorderWidth + cxEventImagesOffset - Byte(ViewData.ShowTimeLine),
      Top + cxEventBorderWidth,
      (Left + Right - cxTextOffset) div 2,
      Bottom - (cxEventBorderWidth + cxEventImagesOffset));
end;

function TcxSchedulerEventCellViewInfo.GetImagesVerticalOffset(
  AImageHeight: Integer; AIsAbsolute: Boolean): Integer;
begin
  Result := cxEventImagesOffset;
  if not FIsDetailCaption then
    Result := Max(Result, (cxRectHeight(Bounds) - 2 * cxEventBorderWidth - AImageHeight) div 2);
  if AIsAbsolute then
    Inc(Result, Bounds.Top + cxEventBorderWidth);
end;

function TcxSchedulerEventCellViewInfo.GetMessageRect(const ACaptionRect: TRect;
  AHasImages: Boolean): TRect;
var
  ACaptionBottom: Integer;
  R: TRect;
begin
  if not cxRectIsEmpty(ACaptionRect) then
  begin
    R := GetCaptionBounds(ACaptionRect);
    ACaptionBottom := R.Bottom + cxTextOffset; //bottom text offset
  end
  else
    ACaptionBottom := Bounds.Top + cxTextOffset;
  if AHasImages then
    ACaptionBottom := Max(ACaptionBottom, Bounds.Top + Images.ItemHeight);
  Inc(ACaptionBottom); //horz line
  Result.Top := ACaptionBottom;
  Result.Bottom := Bounds.Bottom;
  Result.Right := Bounds.Right - 1;
  if Images.Layout = eilHorizontal then
    Result.Left := Bounds.Left + cxEventBorderWidth
  else
    Result.Left := R.Left - cxTextOffset;
end;

procedure TcxSchedulerEventCellViewInfo.Initialize;
begin
  FBorders := cxBordersAll;
  FEventStart := TruncTime(Event.Start);
  FEventFinish := TruncTime(Event.Finish);
  FIsHeaderEvent := GetIsHeaderEvent;
  FStartRect := cxNullRect;
  FFinishRect := cxNullRect;
  FTimeLineRect := cxNullRect;
  ViewData.ShowTimeLine := ViewData.ShowTimeLine and IsTimeLineVisible;
  InitStandardEventImages;
  CalculateVisibility;
  CalculateCaptions;
end;

procedure TcxSchedulerEventCellViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  AHitTest.FEventCell := Self;
  AHitTest.FEventBounds := FClipRect;
  AHitTest.FDragKind := edkMoveEvent;
  CalculateNeedHint;
  AHitTest.FNeedShowHint := FHintNeeded;
end;

procedure TcxSchedulerEventCellViewInfo.InitHitTestForHorzEvent(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  if (bLeft in Borders) and ((AHitTest.HitX - Bounds.Left) <= cxHitDelta) then
    AHitTest.FDragKind := edkResizeStart
  else
    if (bRight in Borders) and ((Bounds.Right - AHitTest.HitX) <= cxHitDelta) then
      AHitTest.FDragKind := edkResizeEnd;
end;

procedure TcxSchedulerEventCellViewInfo.InitStandardEventImages;
var
  AutoHide: Boolean;
begin
  AutoHide := CanAutoHideStandardImages;
  with Event do
  begin
    if Reminder and Storage.IsReminderAvailable and Storage.Reminders.Active then
      Images.AddStandardImage(eitReminder, AutoHide);
    case EventType of
      etOccurrence: Images.AddStandardImage(eitRecurrence, AutoHide);
      etCustom: Images.AddStandardImage(eitCustomOccurrence, AutoHide);
    end;
  end;
end;

function TcxSchedulerEventCellViewInfo.IsHorzSizing: Boolean;
begin
  Result := True;
end;

function TcxSchedulerEventCellViewInfo.IsNeedDrawTime: Boolean;
begin
  Result := ViewData.ShowFinishTime or ViewData.ShowStartTime;
end;

function TcxSchedulerEventCellViewInfo.IsTimeLineVisible: Boolean;
begin
  Result := False;
end;

function TcxSchedulerEventCellViewInfo.TruncTime(
  const ATime: TDateTime): TDateTime;
begin
  Result := DateTimeHelper.RoundTime(ATime);
end;

function TcxSchedulerEventCellViewInfo.GetContentFinish: TDateTime;
begin
  Result := ViewData.ContentFinish;
end;

function TcxSchedulerEventCellViewInfo.CalculateMessageHeight(const R: TRect): Integer;

  function CreateEditViewData: TcxCustomEditViewData;
  begin
    with ViewData do
      Result := EditProperties.CreateViewData(EditStyle, True);
  end;

var
  AEditViewData: TcxCustomEditViewData;
  ASize: TcxEditSizeProperties;
begin
  AEditViewData := CreateEditViewData;
  try
    AssignEditStyle(ViewData.EditStyle);
    AEditViewData.ContentOffset := cxSimpleRect;
    ASize.MaxLineCount := 0;
    ASize.Height := -1; 
    ASize.Width := cxRectWidth(R);
    Result := AEditViewData.GetEditSize(Canvas, Message, ASize).cy;
  finally
    AEditViewData.Free;
  end;
end;

function TcxSchedulerEventCellViewInfo.GetBorderColor: TColor;
begin
  Result := ViewData.BorderColor;
end;

function TcxSchedulerEventCellViewInfo.GetCaption: string;
begin
  Result := ViewData.Caption;
end;

function TcxSchedulerEventCellViewInfo.GetCaptionBounds(const R: TRect): TRect;
{$IFDEF USECXTEXTOUT}
var
  ARowCount: Integer;
  ATextFlags: Cardinal;
  ATextParams: TcxTextParams;
  ATextRows: TcxTextRows;
{$ENDIF}
begin
  Result := R;
{$IFDEF USECXTEXTOUT}
  with TcxScreenCanvas.Create do
  try
    Font := Self.Font;
    ATextFlags := CXTO_CALCROWCOUNT or cxTextOutFlags[True];
    Result.Bottom := MaxInt;
    ATextParams := cxCalcTextParams(Canvas, ATextFlags);
    cxMakeTextRows(Canvas, PChar(ViewData.Caption), Result, ATextParams, ATextRows, ARowCount, 0);
    Result.Bottom := Result.Top + ARowCount * TextHeight('Wg');
    ATextRows := nil;
  finally
    Free;
  end;
{$ELSE}
  if Length(ViewData.Caption) > 0 then
    Canvas.TextExtent(ViewData.Caption, Result, cxDrawTextFlags[IsDetailCaption])
  else
    Canvas.TextExtent('Wg', Result, cxDrawTextFlags[IsDetailCaption]);
{$ENDIF}
end;

function TcxSchedulerEventCellViewInfo.GetContentStart: TDateTime;
begin
  Result := ViewData.ContentStart;
end;

function TcxSchedulerEventCellViewInfo.GetEvent: TcxSchedulerControlEvent;
begin
  Result := ViewData.Event;
end;

function TcxSchedulerEventCellViewInfo.GetIsHeaderEvent: Boolean;
begin
  Result := Event.AllDayEvent or ((Event.Finish - Event.Start) >= 1);
end;

function TcxSchedulerEventCellViewInfo.GetMessage: string;
begin
  Result := Event.Message;
end;

function TcxSchedulerEventCellViewInfo.GetResourceInfo: TcxSchedulerResourceViewInfo;
begin
  Result := ViewData.Resource;
end;

function TcxSchedulerEventCellViewInfo.GetResourceItem: TcxSchedulerStorageResourceItem;
begin
  Result := nil;
  if ResourceInfo <> nil then
    Result := ResourceInfo.ResourceItem;
end;

function TcxSchedulerEventCellViewInfo.GetSelected: Boolean;
begin
  Result := Event.Selected;
end;

function TcxSchedulerEventCellViewInfo.GetShowingState(
  AIndex: Integer): Boolean;
begin
  case AIndex of
    0: Result := ViewData.ShowFinishTime;
    1: Result := ViewData.ShowStartTime;
    2: Result := ViewData.ShowTimeAsClock;
    3: Result := ViewData.ShowTimeLine;
  else
    Result := False;
  end;
end;

procedure TcxSchedulerEventCellViewInfo.SetBorderColor(AValue: TColor);
begin
  ViewData.BorderColor := AValue;
end;

{ TcxSchedulerMoreEventsButtonViewInfo }

procedure TcxSchedulerMoreEventsButtonViewInfo.Click;
begin
  if Assigned(FOnClick) then
    FOnClick(Self);
end;

procedure TcxSchedulerMoreEventsButtonViewInfo.DoDraw;
begin
  MoreEventButtonGlyphs.DrawingStyle := dsTransparent;
  Canvas.DrawImage(MoreEventButtonGlyphs, Bounds.Left, Bounds.Top, Byte(not IsDown));
end;

procedure TcxSchedulerMoreEventsButtonViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  inherited InitHitTest(AHitTest);
  AHitTest.SetBitState(htcButton, True);
  AHitTest.FButton := Self;
  if Int(DateTime) > 0 then
    AHitTest.SetHitTime(htcTime, Int(DateTime));
end;

{ TcxSchedulerGroupSeparatorCellViewInfo }

destructor TcxSchedulerGroupSeparatorCellViewInfo.Destroy;
begin
  FreeAndNil(FRotateBitmap);
  inherited Destroy;
end;

procedure TcxSchedulerGroupSeparatorCellViewInfo.DoDraw;

  procedure CreateRotatedBitmap;
  begin
    with Bounds do
      FRotateBitmap := cxCreateTrueColorBitmap(Right - Left, Bottom - Top);
    FRotateBitmap.PixelFormat := pf32bit;
    FRotateBitmap.Canvas.Lock;
  end;

var
  ABitmapCanvas: TcxCanvas;
begin
  if not Rotated then
    Painter.DrawHeader(Canvas, Bounds, Bounds, [nRight, nLeft], cxBordersAll, cxbsNormal,
      taLeftJustify, vaCenter, False, False, '', nil, clNone, Color, DrawBackground)
  else
  begin
    if FRotateBitmap = nil then
    begin
      CreateRotatedBitmap;
      ABitmapCanvas := TcxCanvas.Create(FRotateBitmap.Canvas);
      try
        ABitmapCanvas.WindowOrg := Bounds.TopLeft;
        FDrawRotatedBackground := DrawBackground(ABitmapCanvas, Bounds);

        RotateBitmap(FRotateBitmap, raPlus90, True);

        Painter.DrawHeader(ABitmapCanvas, Rect(0, 0, FRotateBitmap.Width,
          FRotateBitmap.Height), cxNullRect, [nRight, nLeft], cxBordersAll,
          cxbsNormal, taCenter, vaCenter, False, False, '', nil, clNone, Color,
          DrawRotateBackground);

        RotateBitmap(FRotateBitmap, raPlus90, True);
      finally
        FRotateBitmap.Canvas.Unlock;
        ABitmapCanvas.Free;
      end;
    end;
    Canvas.Draw(Bounds.Left, Bounds.Top, FRotateBitmap);
  end;
end;

procedure TcxSchedulerGroupSeparatorCellViewInfo.InitHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  AHitTest.SetBitState(htcGroupSeparator, True);
end;

function TcxSchedulerGroupSeparatorCellViewInfo.DrawRotateBackground(
  ACanvas: TcxCanvas; const ABounds: TRect): Boolean;
begin
  Result := FDrawRotatedBackground;
end;

{ TcxSchedulerResourceViewInfo }

constructor TcxSchedulerResourceViewInfo.Create(
  AResource: TcxSchedulerStorageResourceItem);
begin
  FResourceItem := AResource;
  FColor := AResource.Color;
  FResourceID := AResource.ResourceID;
  FCaption := AResource.Resources.GetResourceName(FResourceItem);
  FImages := AResource.Resources.Images;
  FImageIndex := AResource.ActualImageIndex;
end;

{ TcxSchedulerCustomResourceView }

constructor TcxSchedulerCustomResourceView.Create(
  AOwner: TcxCustomScheduler);
begin
  inherited Create(AOwner);
  FShowEndTime := True;
end;

procedure TcxSchedulerCustomResourceView.Assign(Source: TPersistent);
begin
  if Source is TcxSchedulerCustomResourceView then
  begin
    ShowEndTime := TcxSchedulerCustomResourceView(Source).ShowEndTime;
    ShowTimeAsClock := TcxSchedulerCustomResourceView(Source).ShowTimeAsClock;
    FGroupingKind := TcxSchedulerCustomResourceView(Source).GroupingKind;
  end;
  inherited Assign(Source);  
end;

procedure TcxSchedulerCustomResourceView.CalculateViewInfo;
begin
  Adapter.Calculate;
end;

procedure TcxSchedulerCustomResourceView.CheckGroupingKind(
  AStyle: TcxSchedulerGroupingKind; var ActuallyStyle: TcxSchedulerGroupingKind);
begin
  ActuallyStyle := AStyle;
end;

function TcxSchedulerCustomResourceView.CreateController: TcxSchedulerSubControlController;
begin
  Result := TcxSchedulerCustomResourceViewController.Create(Self);
end;

function TcxSchedulerCustomResourceView.CreateHitTest: TcxSchedulerSubControlHitTest;
begin
  Result := TcxSchedulerCustomResourceViewHitTest.Create(Self);
end;

function TcxSchedulerCustomResourceView.CreateViewAdapter: TcxCustomResourceViewAdapter;
begin
  Result := TcxCustomResourceViewAdapter.Create(Self);
end;

procedure TcxSchedulerCustomResourceView.CreateSubClasses;
begin
  inherited CreateSubClasses;
  FAdapter := CreateViewAdapter;
  ViewInfo.FAdapter := FAdapter;
end;

procedure TcxSchedulerCustomResourceView.DestroySubClasses;
var
  Adapter: TObject;
begin
  Adapter := ViewInfo.FAdapter;
  inherited DestroySubClasses;
  Adapter.Free;
end;

procedure TcxSchedulerCustomResourceView.DoCustomDrawBackground(
  AViewInfo: TcxSchedulerBackgroundCellViewInfo; var ADone: Boolean);
begin
  if Assigned(FOnCustomDrawBackground) then
    FOnCustomDrawBackground(Self, Canvas, AViewInfo, ADone);
end;

procedure TcxSchedulerCustomResourceView.DoCustomDrawButton(
  AViewInfo: TcxSchedulerMoreEventsButtonViewInfo; var ADone: Boolean);
begin
  if Assigned(FOnCustomDrawButton) then
    FOnCustomDrawButton(Self, Canvas, AViewInfo, ADone);
end;

procedure TcxSchedulerCustomResourceView.DoCustomDrawContent(
  AViewInfo: TcxSchedulerContentCellViewInfo; var ADone: Boolean);
begin
  if Assigned(FOnCustomDrawContent) then
    FOnCustomDrawContent(Self, Canvas, AViewInfo, ADone);
end;

procedure TcxSchedulerCustomResourceView.DoCustomDrawDayHeader(
  AViewInfo: TcxSchedulerDayHeaderCellViewInfo; var ADone: Boolean);
begin
  if Assigned(FOnCustomDrawDayHeader) then
    FOnCustomDrawDayHeader(Self, Canvas, AViewInfo, ADone);
end;

procedure TcxSchedulerCustomResourceView.DoCustomDrawEvent(
  AViewInfo: TcxSchedulerEventCellViewInfo; var ADone: Boolean);
begin
  if Assigned(FOnCustomDrawEvent) then
    FOnCustomDrawEvent(Self, Canvas, AViewInfo, ADone);
end;

procedure TcxSchedulerCustomResourceView.DoCustomDrawGroupSeparator(
  AViewInfo: TcxSchedulerGroupSeparatorCellViewInfo; var ADone: Boolean);
begin
  if Assigned(FOnCustomDrawGroupSeparator) then
    FOnCustomDrawGroupSeparator(Self, Canvas, AViewInfo, ADone);
end;

procedure TcxSchedulerCustomResourceView.DoCustomDrawResourceHeader(
  AViewInfo: TcxSchedulerHeaderCellViewInfo; var ADone: Boolean);
begin
  if Assigned(FOnCustomDrawResourceHeader) then
    FOnCustomDrawResourceHeader(Self, Canvas, AViewInfo, ADone);
end;

procedure TcxSchedulerCustomResourceView.DoLayoutChanged;
begin
  inherited DoLayoutChanged;
end;

function TcxSchedulerCustomResourceView.DoShowPopupMenu(X, Y: Integer): Boolean;
begin
  if HitTest.HitAtEvent then
    Result := not Controller.IsEditing and Scheduler.EventPopupMenu.Popup(X, Y)
  else
    Result := Scheduler.ContentPopupMenu.Popup(X, Y)
end;

function TcxSchedulerCustomResourceView.FindEventViewInfo(AEvent: TcxSchedulerEvent;
  const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem;
  var AViewInfo: TcxSchedulerEventCellViewInfo): Boolean;
var
  I: Integer;
begin
  Result := False;
  for I := 0 to ViewInfo.EventCells.Count - 1 do
  begin
    AViewInfo := TcxSchedulerEventCellViewInfo(ViewInfo.EventCells[I]);
    if AViewInfo.Event = AEvent then
    begin
      Result := True;
      with AViewInfo do 
      begin
        if (AResource = nil) or (ResourceItem = AResource) then
          if (ADate = NullDate) or ((DateOf(ContentStart) = ADate) or (IsHeaderEvent and
            (ADate >= DateOf(ContentStart)) and (ADate < DateOf(ContentFinish)))) then Break;
      end;
    end;
  end;
end;

function TcxSchedulerCustomResourceView.GetCommonViewItemsPainter: IcxSchedulerCommonViewItemsPainter;
begin
  if not Supports(TObject(Scheduler), IcxSchedulerCommonViewItemsPainter, Result) then
    Result := nil;
end;

function TcxSchedulerCustomResourceView.GetCompressWeekEnd: Boolean;
begin
  Result := False; 
end;

function TcxSchedulerCustomResourceView.GetEditRectForEvent(
  AEvent: TcxSchedulerControlEvent; const ADate: TDateTime;
  AResource: TcxSchedulerStorageResourceItem): TRect;
var
  AViewInfo: TcxSchedulerEventCellViewInfo;
begin
  if FindEventViewInfo(AEvent, ADate, AResource, AViewInfo) then
    Result := AViewInfo.EditingRect
  else
    Result := inherited GetEditRectForEvent(AEvent, ADate, AResource);
end;

procedure TcxSchedulerCustomResourceView.InitScrollBarsParameters;
begin
  ViewInfo.InitScrollBarsParameters;
end;

function TcxSchedulerCustomResourceView.GetEventVisibility(
  AEvent: TcxSchedulerControlEvent): Boolean;
var
  AViewInfo: TcxSchedulerEventCellViewInfo;
begin
  Result := FindEventViewInfo(AEvent, NullDate, nil, AViewInfo)
end;

function TcxSchedulerCustomResourceView.GetGroupingKind: TcxSchedulerGroupingKind;
begin
  Result := GroupingKind;
  if Result = gkDefault then
    Result := OptionsView.GroupingKind;
end;

function TcxSchedulerCustomResourceView.IsShowResources: Boolean;
var
  AKind: TcxSchedulerGroupingKind;
begin
  Result := inherited IsShowResources;
  if Result then
  begin
    AKind := GroupingKind;
    if AKind = gkDefault then
      AKind := OptionsView.GroupingKind;
    Result := AKind <> gkNone;
  end;
end;

procedure TcxSchedulerCustomResourceView.Scroll(AScrollBarKind: TScrollBarKind;
  AScrollCode: TScrollCode; var AScrollPos: Integer);
begin
  if AScrollBarKind = sbHorizontal then
    ViewInfo.ScrollHorizontal(AScrollCode, AScrollPos)
  else
    ViewInfo.ScrollVertical(AScrollCode, AScrollPos);
  inherited Scroll(AScrollBarKind, AScrollCode, AScrollPos);
end;

function TcxSchedulerCustomResourceView.GetViewInfo: TcxSchedulerCustomResourceViewViewInfo;
begin
  Result := TcxSchedulerCustomResourceViewViewInfo(inherited ViewInfo);
end;

procedure TcxSchedulerCustomResourceView.SetEventImagesLayout(
  const AValue: TcxSchedulerEventImagesLayout);
begin
  if FEventImagesLayout <> AValue then
  begin
    FEventImagesLayout := AValue;
    LayoutChanged;
  end;
end;

procedure TcxSchedulerCustomResourceView.SetGroupingKind(
  AValue: TcxSchedulerGroupingKind);
begin
  CheckGroupingKind(AValue, AValue);
  if (FGroupingKind <> AValue) then
  begin
    FGroupingKind := AValue;
    LayoutChanged;
  end;
end;

procedure TcxSchedulerCustomResourceView.SetShowEndTime(
  const AValue: Boolean);
begin
  if FShowEndTime <> AValue then
  begin
    FShowEndTime := AValue;
    LayoutChanged;
  end;
end;

procedure TcxSchedulerCustomResourceView.SetShowTimeAsClock(
  const AValue: Boolean);
begin
  if FShowTimeAsClock <> AValue then
  begin
    FShowTimeAsClock := AValue;
    LayoutChanged;
  end;
end;

{ TcxCustomResourceViewAdapter }

constructor TcxCustomResourceViewAdapter.Create(
  AView: TcxSchedulerCustomResourceView);
begin
  FView := AView;
end;

procedure TcxCustomResourceViewAdapter.Calculate;
var
  FPrevAdapter: TcxCustomResourceViewAdapter;
begin
  FPrevAdapter := FView.ViewInfo.SetAdapter(Self);
  FPrevAdapter.Store;
  try
    BeforeCalculatePage;
    FView.ViewInfo.Calculate;
    AfterCalculatePage;
  finally
    FView.ViewInfo.SetAdapter(FPrevAdapter);
    if (FPrevAdapter <> Self) and FView.Active then
    begin
      FPrevAdapter.Restore;
      FView.ViewInfo.Calculate;
    end;
    FView.ViewInfo.FStylesAdapter := nil;
  end;
end;

procedure TcxCustomResourceViewAdapter.GetPageResources(
  AResources: TcxObjectList);
var
  ACount, I: Integer;
  AResourceViewInfo: TcxSchedulerResourceViewInfo;
begin
  if Resources = nil then Exit;
  Scheduler.ValidateFirstVisibleResourceIndex;
  ACount := Resources.VisibleResourceCount;
  with Scheduler.OptionsView do
  begin
    if (ResourcesPerPage > 0) and (ACount > ResourcesPerPage) then
      ACount := ResourcesPerPage;
  end;
  for I := 0 to ACount - 1 do
  begin
    AResourceViewInfo := TcxSchedulerResourceViewInfo.Create(
      Resources.VisibleResources[Scheduler.FirstVisibleResourceIndex + I]);
    AResources.Add(AResourceViewInfo);
  end;
end;

procedure TcxCustomResourceViewAdapter.GetPageDays(
  APageIndex: Integer; ADays: TcxSchedulerDateList);
begin
end;

procedure TcxCustomResourceViewAdapter.Invalidate;
begin
end;

function TcxCustomResourceViewAdapter.CanCalculate: Boolean;
begin
  Result := View.Active;
end;

function TcxCustomResourceViewAdapter.GetCompressWeekends: Boolean;
begin
  Result := View.GetCompressWeekEnd;
end;

function TcxCustomResourceViewAdapter.GetDontPrintWeekEnds: Boolean;
begin
  Result := False; 
end;

function TcxCustomResourceViewAdapter.GetHideSelection: Boolean;
begin
  Result := View.OptionsView.HideSelection and not View.Scheduler.IsFocused;
end;

function TcxCustomResourceViewAdapter.GetPageBounds: TRect;
begin
  Result := View.ClientRect;
end;

function TcxCustomResourceViewAdapter.GetPagesPerWeek: Byte;
begin
  Result := 1;
end;

function TcxCustomResourceViewAdapter.GetPrimaryPage: Boolean;
begin
  Result := True;
end;

function TcxCustomResourceViewAdapter.GetPrintExactlyOneMonth: Boolean; 
begin
  Result := False;
end;

function TcxCustomResourceViewAdapter.GetPrintRange(
  Index: Integer): TDateTime;
begin
  Result := NullDate;
end;

function TcxCustomResourceViewAdapter.GetStylesAdapter: IcxSchedulerStylesAdapter;
begin
  Result := FView.Styles;
end;

function TcxCustomResourceViewAdapter.GetView: TcxSchedulerCustomResourceView;
begin
  Result := FView;
end;

procedure TcxCustomResourceViewAdapter.AfterCalculatePage;
begin
end;

procedure TcxCustomResourceViewAdapter.BeforeCalculatePage;
begin
end;

procedure TcxCustomResourceViewAdapter.DoInitialize(
  var ASelectedDays: TcxSchedulerDateList; var AEvents: TcxSchedulerCachedEventList);
begin
  ASelectedDays := View.Scheduler.SelectedDays;
  AEvents := ViewInfo.GetSchedulerEventsList;
end;

function TcxCustomResourceViewAdapter.GetPageHeaderText: string;
begin
  Result := ViewInfo.GetPageHeaderText;
end;

procedure TcxCustomResourceViewAdapter.Store;
begin
end;

procedure TcxCustomResourceViewAdapter.Restore;
begin
end;

function TcxCustomResourceViewAdapter.GetCells: TcxObjectList;
begin
  Result := ViewInfo.FCells;
end;

function TcxCustomResourceViewAdapter.GetContentLineHeight: Integer;
var
  AEventHeight, AIconHeight: Integer;
  AImages: TImageList;
begin
  with View do
  begin
    AEventHeight := OptionsView.EventHeight;
    AImages := Scheduler.EventImages;
  end;
  with ViewInfo do
  begin
    Result := GetFontHeight(StylesAdapter.GetEventParams(nil)) + 2 * cxTextOffset;
    if AEventHeight = 0 then
    begin
      if AImages <> nil then
        AIconHeight := Max(PainterHelper.IconsHeight, AImages.Height)
      else
        AIconHeight := PainterHelper.IconsHeight;
      Result := Max(AIconHeight + cxTextOffset + 2 * cxEventImagesOffset, Result);
    end
    else
      Result := Max(AEventHeight, Result);
  end;
end;

function TcxCustomResourceViewAdapter.GetPainterHelper: TcxSchedulerPainterHelperClass;
begin
  Result := TcxSchedulerHelpersFactory.PainterHelperClass;
end;

function TcxCustomResourceViewAdapter.GetResourceNavigator: TcxSchedulerResourceNavigator;
begin
  Result := View.Scheduler.ResourceNavigator;
end;

function TcxCustomResourceViewAdapter.GetResources: TcxSchedulerStorageResourceItems;
begin
  Result := View.Resources;
end;

function TcxCustomResourceViewAdapter.GetScheduler: TcxCustomScheduler;
begin
  Result := View.Scheduler;
end;

function TcxCustomResourceViewAdapter.GetViewInfo: TcxSchedulerCustomResourceViewViewInfo;
begin
  Result := View.ViewInfo;
end;


{ TcxSchedulerEventImageItem }

constructor TcxSchedulerEventImageItem.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FAutoHide := True;
  FImageIndex := -1;
  FVisible := True;
end;

function TcxSchedulerEventImageItem.GetHeight: Integer;
begin
  Result := Images.Height;
end;

function TcxSchedulerEventImageItem.GetWidth: Integer;
begin
  Result := Images.Width;
end;

{ TcxSchedulerEventImages }

constructor TcxSchedulerEventImages.Create(
  ALayout: TcxSchedulerEventImagesLayout);
begin
  inherited Create(TcxSchedulerEventImageItem);
  FLayout := ALayout;
  FItemHeight := EventImages.Height;
  FItemWidth := EventImages.Width;
end;

function TcxSchedulerEventImages.Add(AImageIndex: Integer;
  AutoHide: Boolean = True): TcxSchedulerEventImageItem;
begin
  if (FImages = nil) or ((AImageIndex < 0) or (AImageIndex >= FImages.Count)) then
  begin
    Result := nil;
    Exit;
  end;
  Result := TcxSchedulerEventImageItem(inherited Add);
  Result.FImageIndex := AImageIndex;
  Result.AutoHide := AutoHide;
  Result.FImageType := eitCustom;
  Result.FImages := FImages;
end;

function TcxSchedulerEventImages.AddStandardImage(
  AImageType: TcxSchedulerEventImageType;
  AutoHide: Boolean = True): TcxSchedulerEventImageItem;
const
  Indexes: array[TcxSchedulerEventImageType] of TImageIndex = (4, 2, 3, -1);
begin
  Result := TcxSchedulerEventImageItem(inherited Add);
  Result.AutoHide := AutoHide;
  Result.FImageType := AImageType;
  Result.FImages := EventImages;
  Result.FImageIndex := Indexes[AImageType];
end;

function TcxSchedulerEventImages.Calculate(const R: TRect): Integer;
begin
  case FLayout of
    eilAuto: Result := CalculateImages(R);
    eilHorizontal: Result := CalculateSingleLineImages(R);
  else
    Result := CalculateSingleColumnImages(R);
  end;
end;

procedure TcxSchedulerEventImages.CalculateForCols(AVisibleImages: TList;
  const ATopLeft: TPoint; AColCount: Integer);
var
  ARow, ACol, AIndex: Integer;
begin
  AIndex := 0;
  ACol := 0;
  ARow := 0;
  while AIndex < TotalVisibleImageCount do
  begin
    SetItemBounds(TcxSchedulerEventImageItem(AVisibleImages[AIndex]),
      ATopLeft.X + ACol * (ItemWidth + cxEventImagesGap),
      ATopLeft.Y + ARow * (ItemHeight + cxEventImagesGap));
    if ACol = AColCount - 1 then
    begin
      ACol := 0;
      Inc(ARow);
    end
    else Inc(ACol);
    Inc(AIndex);
  end;
end;

function TcxSchedulerEventImages.CalculateImages(const R: TRect): Integer;
var
  I, AWidth, AHeight, ACount, ARows, AColIndex,
  ARowIndex: Integer;
  L: TList;
  RS: TSize;

  procedure CheckAutoHideItems;
  var
    I: Integer;
    AItem: TcxSchedulerEventImageItem;
  begin
    if ACount >= L.Count then Exit;
    for I := L.Count - 1 downto 0 do
    begin
      AItem := TcxSchedulerEventImageItem(L[I]);
      if AItem.AutoHide then
      begin
        AItem.FHidden := True;
        L.Delete(I);
        if ACount >= L.Count then break;
      end;
    end;
  end;

begin
  AHeight := ItemHeight + cxEventImagesGap;
  RS := cxRectSize(R);
  ARows := Max(1, RS.cy div AHeight);
  if ARows = 1 then
  begin
    Result := CalculateSingleLineImages(R);
    Exit;
  end;
  Result := 0;
  L := CreateVisibleList;
  try
    if L.Count = 0 then Exit;
    AWidth := ItemWidth + cxEventImagesGap;
    ACount := Max(1, RS.cx div AWidth) * ARows;
    CheckAutoHideItems;
    AColIndex := 0;
    ARowIndex := 0;
    for I := 0 to L.Count - 1 do
    begin
      SetItemBounds(TcxSchedulerEventImageItem(L[I]),
        R.Left + AColIndex * AWidth,
        R.Top + ARowIndex * AHeight);
      Result := Max(Result, (AColIndex + 1) * AWidth);
      Inc(ARowIndex);
      if ARowIndex = ARows then
      begin
        Inc(AColIndex);
        ARowIndex := 0;
      end;
    end;
    FVisibleImageCount := L.Count;
  finally
    L.Free;
  end;
end;

function TcxSchedulerEventImages.CalculateSingleLineImages(const R: TRect; ARightLimit: Integer = 0): Integer;
var
  I, ALeft, AImageWidth, ATotalWidth, ARectWidth: Integer;
  L: TList;
  AItem: TcxSchedulerEventImageItem;

  procedure CheckAutoHideItems;
  var
    I: Integer;
    AItem: TcxSchedulerEventImageItem;
  begin
    if ARectWidth >= ATotalWidth then Exit;
    if ARightLimit > 0 then
      ARectWidth := Min(ARightLimit, Max(ARectWidth, ForceVisibleWidth));
    for I := L.Count - 1 downto 0 do
    begin
      AItem := TcxSchedulerEventImageItem(L.List^[I]);
      if AItem.AutoHide then
      begin
        AItem.FHidden := True;
        Dec(ATotalWidth, AImageWidth);
        L.Delete(I);
        if ARectWidth >= ATotalWidth then break;
      end;
    end;
  end;

begin
  Result := 0;
  L := CreateVisibleList;
  try
    if L.Count = 0 then Exit;
    ATotalWidth := TotalVisibleWidth;
    ARectWidth := R.Right - R.Left;
    AImageWidth := ItemWidth + cxEventImagesGap;
    CheckAutoHideItems;
    ALeft := R.Left;
    for I := 0 to L.Count - 1 do
    begin
      AItem := TcxSchedulerEventImageItem(L.List^[I]);
      SetItemBounds(AItem, ALeft, R.Top);
      Inc(ALeft, AImageWidth);
      Inc(Result, AImageWidth);
    end;
    FVisibleImageCount := L.Count;
  finally
    L.Free;
  end;
end;

function TcxSchedulerEventImages.CalculateSingleColumnImages(const R: TRect): Integer;
var
  I, ATop, AWidth, AHeight, ATotalHeight: Integer;
  RS: TSize;
  L: TList;

  procedure CheckAutoHideItems;
  var
    I: Integer;
    AItem: TcxSchedulerEventImageItem;
  begin
    if RS.cy + cxEventImagesGap >= ATotalHeight then Exit;
    for I := L.Count - 1 downto 0 do
    begin
      AItem := TcxSchedulerEventImageItem(L.List^[I]);
      if AItem.AutoHide then
      begin
        AItem.FHidden := True;
        Dec(ATotalHeight, AHeight);
        L.Delete(I);
        if RS.cy + cxEventImagesGap >= ATotalHeight then break;
      end;
    end;
  end;

  function CanAutoHideAllItems: Boolean;
  var
    I: Integer;
  begin
    Result := True;
    for I := 0 to L.Count - 1 do
      if not TcxSchedulerEventImageItem(L.List^[I]).AutoHide then
      begin
        Result := False;
        break;
      end;
  end;

begin
  Result := 0;
  L := CreateVisibleList;
  try
    if L.Count = 0 then Exit;
    ATotalHeight := TotalVisibleHeight;
    RS := cxRectSize(R);
    AWidth := ItemWidth + cxEventImagesGap;
    if (RS.cx < AWidth) and CanAutoHideAllItems then Exit;
    AHeight := ItemHeight + cxEventImagesGap;
    CheckAutoHideItems;
    if L.Count = 0 then Exit;
    Result := AWidth;
    ATop := R.Top;
    for I := 0 to L.Count - 1 do
    begin
      SetItemBounds(TcxSchedulerEventImageItem(L.List^[I]), R.Left, ATop);
      Inc(ATop, AHeight);
    end;
    FVisibleImageCount := L.Count;
  finally
    L.Free;
  end;
end;

function TcxSchedulerEventImages.CreateVisibleList: TList;
var
  I: Integer;
  AItem: TcxSchedulerEventImageItem;
begin
  FVisibleImageCount := 0;
  FForceVisibleHeight := 0;
  FForceVisibleWidth := 0;
  FTotalVisibleImageCount := 0;
  Result := TList.Create;
  for I := 0 to Count - 1 do
  begin
    AItem := Items[I];
    if AItem.Visible then
    begin
      Inc(FTotalVisibleImageCount);
      if not AItem.AutoHide then
      begin
        Inc(FForceVisibleHeight, ItemHeight + cxEventImagesGap);
        Inc(FForceVisibleWidth, ItemWidth + cxEventImagesGap);
      end;
      AItem.FHidden := False;
      Result.Add(AItem);
    end
    else AItem.FHidden := True;
  end;
  FTotalVisibleWidth := (ItemWidth + cxEventImagesGap) * Result.Count;
  FTotalVisibleHeight := (ItemHeight + cxEventImagesGap) * Result.Count;
end;

procedure TcxSchedulerEventImages.Init(AImages: TImageList);
begin
  FVisibleImageCount := 0;
  FImages := AImages;
  if (FImages <> nil) then
  begin
    if FImages.Height > FItemHeight then FItemHeight := FImages.Height;
    if FImages.Width > FItemWidth then FItemWidth := FImages.Width;
  end;
end;

function TcxSchedulerEventImages.Offset(ADeltaX, ADeltaY: Integer): Integer;
var
  I: Integer;
begin
  Result := 0;
  for I := 0 to Count - 1 do
    with Items[I] do
    begin
      if not FHidden then
      begin
        FBounds := cxRectOffset(FBounds, ADeltaX, ADeltaY);
        Inc(Result, ItemWidth + cxEventImagesGap);
      end;
    end;
end;

procedure TcxSchedulerEventImages.SetItemBounds(
  AItem: TcxSchedulerEventImageItem; ALeft, ATop: Integer);
begin
  Inc(ALeft, Max(0, (ItemWidth - AItem.Width) div 2));
  Inc(ATop, Max(0, (ItemHeight - AItem.Height) div 2));
  AItem.FBounds := cxRectBounds(ALeft, ATop, AItem.Width, AItem.Height);
end;

function TcxSchedulerEventImages.GetImageItem(
  AIndex: Integer): TcxSchedulerEventImageItem;
begin
  Result := TcxSchedulerEventImageItem(inherited Items[AIndex]);
end;

{ TcxSchedulerCustomResourceViewViewInfo }

constructor TcxSchedulerCustomResourceViewViewInfo.Create(
  AOwner: TcxSchedulerSubControl);
begin
  inherited Create(AOwner);
  FCells := TcxObjectList.Create;
  FResources := TcxObjectList.Create;
  FGroupSeparatorCells := TcxSchedulerViewInfoCellList.Create;
  FButtons := TcxSchedulerViewInfoCellList.Create;
  FContentCells := TcxSchedulerViewInfoCellList.Create;
  FEventCells := TcxSchedulerViewInfoCellList.Create;
  FDayHeaderCells := TcxSchedulerViewInfoCellList.Create;
  FResourceHeaderCells := TcxSchedulerViewInfoCellList.Create;
  FHeaderContainerCells := TcxSchedulerViewInfoCellList.Create;
  FCells.Add(FEventCells);
  FCells.Add(FGroupSeparatorCells);
  FCells.Add(FDayHeaderCells);
  FCells.Add(FResourceHeaderCells);
  FCells.Add(FContentCells);
  FCells.Add(FHeaderContainerCells);
end;

destructor TcxSchedulerCustomResourceViewViewInfo.Destroy;
begin
  FEventImages := nil;
  FResources.Free;
  FButtons.Free;
  FCells.Free;
  inherited Destroy;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.Calculate;
begin
  ScreenCanvas := TcxScreenCanvas.Create;
  try
    Supports(TObject(View.Scheduler), IcxSchedulerEventImages, FEventImages);
    FPrimaryPage := Adapter.GetPrimaryPage;
    Adapter.DoInitialize(FSelectedDays, FEvents);
    FHasVisibleBounds := GetHasVisibleBounds;
    FPrintWeekEnds := not Adapter.DontPrintWeekEnd;
    FPagesPerWeek := Adapter.PagesPerWeek;
    FPageBounds := Adapter.GetPageBounds;
    FCanSelected := not Adapter.GetHideSelection;
    inherited Calculate;
  finally
    FreeAndNil(ScreenCanvas); 
  end;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.CalculateHitTest(
  AHitTest: TcxSchedulerCustomResourceViewHitTest);
begin
  FEventCells.CalculateHitTest(AHitTest);
  if not FDayHeaderCells.CalculateHitTest(AHitTest) then
    if not FResourceHeaderCells.CalculateHitTest(AHitTest) then
      if not FHeaderContainerCells.CalculateHitTest(AHitTest) then
        if not FButtons.CalculateHitTest(AHitTest) then
          if not FContentCells.CalculateHitTest(AHitTest) then
            FGroupSeparatorCells.CalculateHitTest(AHitTest);
  if AHitTest.HitAtButton and AHitTest.HitAtEvent then
  begin
    AHitTest.FHitObject := nil;
    AHitTest.FEventCell := nil;
  end;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.InitScrollBarsParameters;
begin
  CheckResourceNavigator;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.ScrollHorizontal(
  AScrollCode: TScrollCode; var AScrollPos: Integer);
begin
end;

procedure TcxSchedulerCustomResourceViewViewInfo.ScrollVertical(
  AScrollCode: TScrollCode; var AScrollPos: Integer);
begin
end;

procedure TcxSchedulerCustomResourceViewViewInfo.SetEventsVisibility(
  AShowSources, AShowClones: Boolean; AForceRepaint: Boolean = False);
var
  ARepaint: Boolean;
begin
  ARepaint := AForceRepaint or (FHideSource <> not AShowSources) or
    (FHideClones <> not AShowClones);
  FHideSource := not AShowSources;
  FHideClones := not AShowClones;
  if ARepaint then View.Refresh;
end;

function TcxSchedulerCustomResourceViewViewInfo.AddButton(
  ABounds: TRect; const ADateTime: TDateTime; AResourceIndex: Integer;
  AIsDown: Boolean): TcxSchedulerMoreEventsButtonViewInfo;
begin
  ABounds := cxRectInflate(ABounds, -cxTextOffset, -cxTextOffset);
  ABounds.Left := ABounds.Right - PainterHelper.MoreButtonWidth;
  if AIsDown then
    ABounds.Top := ABounds.Bottom - PainterHelper.MoreButtonHeight
  else
    ABounds.Bottom := ABounds.Top + PainterHelper.MoreButtonHeight;
  if DateOf(ADateTime) = 0 then
    CreateCellInstance(TcxSchedulerMoreEventsButtonViewInfo, ABounds,
      Styles.GetBackgroundParams, Result)
  else
    CreateCellInstance(TcxSchedulerMoreEventsButtonViewInfo, ABounds,
      GetContentParams(ADateTime, nil), Result);
  Result.FIsDown := AIsDown;
  Result.FDateTime := ADateTime;
  Result.FOnClick := OnMoreEventsButtonClick;
  AssignResourceID(Result, AResourceIndex);
  FButtons.Add(Result);
end;

function TcxSchedulerCustomResourceViewViewInfo.AddBackgroundSlot(const ABounds: TRect;
  ABorders: TcxBorders; const AText: string = ''): TcxSchedulerBackgroundSlotCellViewInfo;
begin
  CreateCellInstance(TcxSchedulerBackgroundSlotCellViewInfo, ABounds,
    Styles.GetBackgroundParams, Result);
  Result.FBorders := ABorders;
  AssignResourceID(Result, -1);
  ContentCells.Add(Result);
end;

function TcxSchedulerCustomResourceViewViewInfo.AddContentCell(const ARect: TRect;
  const AStart, AFinish: TDateTime; AResourceIndex: Integer): TcxSchedulerContentCellViewInfo;
begin
  CreateCellInstance(ContentCellClass, ARect,
    GetContentParams(AStart, Resources[AResourceIndex]), Result);
  Result.SetTime(AStart, AFinish);
  AssignResourceID(Result, AResourceIndex);
  ContentCells.Add(Result);
end;

function TcxSchedulerCustomResourceViewViewInfo.AddDayHeader(
  const ADate: TDateTime; const ABounds: TRect;
  AResourceIndex: Integer): TcxSchedulerDayHeaderCellViewInfo;
begin
  CreateCellInstance(TcxSchedulerDayHeaderCellViewInfo, ABounds,
    StylesAdapter.GetDayHeaderParams(ADate), Result);
  Result.DateTime := ADate;
  AssignResourceID(Result, AResourceIndex);
  FDayHeaderCells.Add(Result);
end;

function TcxSchedulerCustomResourceViewViewInfo.AddDayHeader(
  const ADate: TDateTime; ATop, ALeft, ARight: Integer;
  AResourceIndex: Integer): TcxSchedulerDayHeaderCellViewInfo;
begin
  Result := AddDayHeader(ADate,
    cxRect(ALeft, ATop, ARight, ATop + FDayHeaderHeight), AResourceIndex);
end;

function TcxSchedulerCustomResourceViewViewInfo.AddEventCell(
  AViewData: TcxSchedulerEventViewData;
  AImmediateCalculate: Boolean = True): TcxSchedulerEventCellViewInfo;
begin
  Result := CreateEventCellViewInfo(AViewData);
  if (FEventImages <> nil) and FEventImages.SupportEventImages then
  begin
    Result.Images.Init(FEventImages.GetImages);
    FEventImages.DoInitEventImages(AViewData.Event, Result.Images);
  end;
  if AImmediateCalculate then Result.Calculate;
  EventCells.Add(Result);
end;

function TcxSchedulerCustomResourceViewViewInfo.AddGroupHorzSeparator(
  APos: Integer): TcxSchedulerGroupSeparatorCellViewInfo;
begin
  Result := AddGroupSeparator(cxRectSetTop(Bounds, APos, SeparatorWidth));
  if Result <> nil then
    Result.Rotated := True;
end;

function TcxSchedulerCustomResourceViewViewInfo.AddGroupSeparator(
  const ABounds: TRect): TcxSchedulerGroupSeparatorCellViewInfo;
begin
  Result := nil;
  if not HasSeparator then Exit;
  CreateCellInstance(TcxSchedulerGroupSeparatorCellViewInfo, ABounds,
    FGroupSeparatorParams, Result);
  GroupSeparatorCells.Add(Result);
end;

function TcxSchedulerCustomResourceViewViewInfo.AddGroupVertSeparator(
  APos: Integer): TcxSchedulerGroupSeparatorCellViewInfo;
begin
  Result := AddGroupSeparator(cxRectSetLeft(Bounds, APos, SeparatorWidth));
end;

function TcxSchedulerCustomResourceViewViewInfo.AddResourceHeader(
  const AIndex: Integer; const ABounds: TRect): TcxSchedulerHeaderCellViewInfo;
begin
  CreateCellInstance(TcxSchedulerHeaderCellViewInfo, ABounds,
    StylesAdapter.GetResourceHeaderParams(GetResourceItemByIndex(AIndex)), Result);
  if AIndex >= 0 then
  begin
    Result.FDisplayText := ResourceCaptions[AIndex];
    AssignResourceID(Result, AIndex);
    with Resources[AIndex] do
    begin
      Result.FAutoHeight := ResourceHeaders.MultilineCaptions;
      Result.FImageIndex := ImageIndex;
      Result.FImagePosition := ImagePosition;
      Result.FImages := Images;
    end;
  end;
  ResourceHeaderCells.Add(Result);
  Result.FIsResourceHeader := True;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.AfterCalculate;
begin
  inherited AfterCalculate;
  if FHideClones then
    HideCloneEventsOnDragDrop;
  if FHideSource then
    HideSourceEventsOnDragDrop;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.AssignResourceID(
  ACell: TcxSchedulerCustomResourceViewInfoItem; AIndex: Integer);
begin
  if AIndex >= 0 then
    ACell.Resource := Resources[AIndex];
  ACell.FIsResourceAssigned := AIndex >= 0;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.CalculateMetrics;
begin
  FHideSelection := View.OptionsView.HideSelection and not View.Scheduler.IsFocused;
  FGroupSeparatorParams := Styles.GetGroupSeparatorParams;
  FTimeLineParams := GetTimeLineParams;
  FSelectionParams := Styles.GetSelectionParams;
  FContentLineHeight := Adapter.GetContentLineHeight;
  FContentFontHeight := cxTextHeight(StylesAdapter.GetContentParams(Now, nil).Font) + cxTextOffset * 2;  
  FDayHeaderHeight :=
    LookAndFeelPainter.HeaderHeight(GetFontHeight(StylesAdapter.GetDayHeaderStyle));
  FResourceHeaderHeight :=
    LookAndFeelPainter.HeaderHeight(GetFontHeight(StylesAdapter.GetResourceHeaderStyle));
  FUseResourceImages := HasStorage and View.Scheduler.Storage.Resources.AreImagesUsed;
  if HasStorage then
    FResourceImages := View.Scheduler.Storage.Resources.Images
  else
    FResourceImages := nil;
  if HasStorage then
  begin
    if ResourceHeaders.Height = 0 then
      CalculateResourceHeadersAutoHeight(GetResourceHeaderWidth - cxTextOffset * 3)
    else
      FResourceHeaderHeight := ResourceHeaders.Height;
  end;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.CalculateResourceHeadersAutoHeight(
  AWidth: Integer);

  function CalculateResourceHeight(AResource: TcxSchedulerStorageResourceItem;
    AWidth: Integer): Integer;
  var
    R: TRect;
    AFont: TFont;
    AText: string;
    AHasImage: Boolean;
  begin
    AFont := Styles.GetResourceHeaderParams(AResource).Font;
    AHasImage := UseResourceImages and (AResource.ActualImageIndex >= 0);
    if AHasImage and (ResourceHeaders.ImagePosition in [ipLeft, ipRight]) then
      AWidth := Max(0, AWidth - (GetResourceImagesSize.cx + cxTextOffset * 2));
    R := Rect(0, 0, Max(AWidth, 2), 0);
    AText := AResource.Resources.GetResourceName(AResource);
    ScreenCanvas.Font.Assign(AFont);
    ScreenCanvas.TextExtent(AText, R,
      MakeTextOutcxFlags(taLeftJustify, vaCenter, ResourceHeaders.MultilineCaptions));
    Result := R.Bottom - R.Top + cxTextOffset * 3;
    SetResourceTextRect(AResource, R);
    if AHasImage then
    begin
      if (ResourceHeaders.ImagePosition in [ipTop, ipBottom]) then
        Inc(Result, GetResourceImagesSize.cy + cxTextOffset * 4)
      else
        Result := Max(Result, GetResourceImagesSize.cy + cxTextOffset * 3);
    end;
  end;

var
  I: Integer;
begin
  AWidth := Max(0, AWidth);
  for I := 0 to Adapter.Resources.VisibleResourceCount - 1 do
    FResourceHeaderHeight := Max(FResourceHeaderHeight, CalculateResourceHeight(
      Adapter.Resources.VisibleResources[I], AWidth));
end;

function TcxSchedulerCustomResourceViewViewInfo.CalculateResourceHeaderWidth: Integer;
var
  I: Integer;
  AWidth: Integer;

  function CalculateWidth(AResource: TcxSchedulerStorageResourceItem): Integer;
  var
    R: TRect;
    AText: string;
    AHasImage: Boolean;
    AViewParams: TcxViewParams;
  begin
    AViewParams := StylesAdapter.GetResourceHeaderParams(AResource);
    Result := 0;
    AHasImage := AResource.ActualImageIndex >= 0;
    AText := AResource.Resources.GetResourceName(AResource);
    if Length(AText) > 0 then
    begin
      R := Rect(0, 0, FResourceHeaderHeight, AWidth);
      if AHasImage and (ResourceHeaders.ImagePosition in [ipTop, ipBottom]) then
        Dec(R.Bottom, ResourceImages.Height + cxTextOffset * 3);
      ScreenCanvas.Font.Assign(AViewParams.Font);
      ScreenCanvas.TextExtent(AText, R, MakeTextOutcxFlags(taLeftJustify,
        vaCenter, ResourceHeaders.MultilineCaptions));
      Result := R.Right - R.Left + cxTextOffset * 3;
      SetResourceTextRect(AResource, R);
      if AHasImage and (ResourceHeaders.ImagePosition in [ipTop, ipBottom]) then
        Result := Max(Result, ResourceImages.Width + cxTextOffset * 4);
    end;
    if AHasImage and (ResourceHeaders.ImagePosition in [ipLeft, ipRight]) then
      Inc(Result, ResourceImages.Width + cxTextOffset * 4);
  end;

begin
  AWidth := GetResourceHeaderWidth - cxTextOffset * 3;
  Result := FResourceHeaderHeight;
  for I := 0 to Adapter.Resources.VisibleResourceCount - 1 do
    Result := Max(Result, CalculateWidth(Adapter.Resources.VisibleResources[I]));
end;

procedure TcxSchedulerCustomResourceViewViewInfo.Clear;
begin
  FResources.Clear;
  GroupSeparatorCells.Clear;
  Buttons.Clear;
  ContentCells.Clear;
  EventCells.Clear;
  DayHeaderCells.Clear;
  ResourceHeaderCells.Clear;
  HeaderContainerCells.Clear;
end;

function TcxSchedulerCustomResourceViewViewInfo.ContentCellClass: TcxSchedulerContentCellViewInfoClass;
begin
  Result := TcxSchedulerContentCellViewInfo
end;

procedure TcxSchedulerCustomResourceViewViewInfo.CreateCellInstance(
  AClass: TcxSchedulerCustomViewInfoItemClass; const ABounds: TRect;
  const AViewParams: TcxViewParams; var Instance);
begin
  CreateCellInstance(AClass, ABounds, Bounds, AViewParams, Instance);
end;

procedure TcxSchedulerCustomResourceViewViewInfo.CreateCellInstance(
  AClass: TcxSchedulerCustomViewInfoItemClass; const ABounds,
  AVisibleBounds: TRect; const AViewParams: TcxViewParams; var Instance);
begin
  Pointer(Instance) := AClass.Create(LookAndFeelPainter,
    ABounds, AVisibleBounds, AViewParams);
  TcxSchedulerCustomViewInfoItem(Instance).FDayBorderColor := FDayBorderColor;
end;

function TcxSchedulerCustomResourceViewViewInfo.CreateEventViewData(
  AEvent: TcxSchedulerControlEvent; const ABounds: TRect;
  const AStart, AFinish: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData;
var
  ALocation: string;
begin
  Result := TcxSchedulerEventViewData.Create;
  Result.Bounds := ABounds;
  Result.VisibleRect := Bounds;
  Result.Canvas := View.Canvas;
  Result.ContentStart := DateTimeHelper.RoundTime(AStart);
{$IFNDEF DEBUGPAINT}
  Result.Bitmap := View.Bitmap;
{$ENDIF}
  Result.BorderColor := View.OptionsView.EventBorderColor;
  Result.ContentFinish := DateTimeHelper.RoundTime(AFinish);
  Result.Event := AEvent;
  Result.ShowTimeAsClock := View.ShowTimeAsClock;
  Result.TimeLineParams := FTimeLineParams;
  Result.ShowFinishTime := View.ShowEndTime;
  Result.Painter := LookAndFeelPainter;
  Result.ViewParams := StylesAdapter.GetEventParams(AEvent);
  Result.EditProperties := View.GetEditProperties(AEvent);
  Result.EditStyle := View.GetEditStyle(AEvent);
  Result.Resource := AResource;
  Result.Caption := DoGetEventDisplayText(AEvent);
  Result.ImagesLayout := View.EventImagesLayout;
  ALocation := Trim(AEvent.Location);
  if ALocation <> '' then
    Result.Caption := Result.Caption + ' (' + ALocation + ')';
  Result.LineHeight := FContentLineHeight;
end;

function TcxSchedulerCustomResourceViewViewInfo.CreateEventCellViewInfo(
  AViewData: TcxSchedulerEventViewData): TcxSchedulerEventCellViewInfo;
begin
  Result := TcxSchedulerEventCellViewInfo.Create(AViewData);
end;

procedure TcxSchedulerCustomResourceViewViewInfo.DoCalculate;
begin
  FDayBorderColor := View.OptionsView.DayBorderColor;
  if FDayBorderColor = clDefault then
    FDayBorderColor := clWindowText;
  ExtractResources;
  FGroupingKind := GetGroupingKind;
  if FGroupingKind = gkNone then
    FResources.Clear;
  if SelectedDays.Count = 0 then
    SelectedDays.Add(Date);
  with View.Controller.Navigation do
    Self.FSelResource := GetResourceViewInfoByItem(SelResource);
  if (FSelResource = nil) and (ResourceCount > 0) then
    FSelResource := Resources[0];
  CalculateMetrics;
  View.Controller.Navigation.CheckSelection;
  with View.Controller.Navigation do
  begin
    Self.FSelStart := DateTimeHelper.RoundTime(Min(SelStart, SelFinish));
    Self.FSelFinish := DateTimeHelper.RoundTime(Max(SelStart, SelFinish));
  end;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.DoMoreEventsButtonClick(
  Sender: TcxSchedulerMoreEventsButtonViewInfo);
begin
end;

procedure TcxSchedulerCustomResourceViewViewInfo.ExtractResources;
var
  I: Integer;
begin
  FResources.Clear;
  Adapter.GetPageResources(FResources);
  for I := 0 to FResources.Count - 1 do
    Resources[I].FImagePosition := ResourceHeaders.ImagePosition;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetBounds: TRect;
begin
  Result := FPageBounds;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetContentParams(
  const ATime: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxViewParams;
begin
  if AResource = nil then
    Result := StylesAdapter.GetContentParams(ATime, nil)
  else
    Result := StylesAdapter.GetContentParams(ATime, AResource.ResourceItem)
end;

function TcxSchedulerCustomResourceViewViewInfo.GetDayHeaderHeight: Integer;
begin
  Result := FDayHeaderHeight;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourceHeaderWidth: Integer;
begin
  Result := GetResourcesContentWidth;
  if ResourceCount > 0 then
    Result := Max(0, (Result - SeparatorWidth * GetSeparatorCount) div ResourceCount);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourceImagesSize: TSize;
begin
  if ResourceImages = nil then
    Result := TSize(cxNullSize)
  else
    Result := cxSize(ResourceImages.Width, ResourceImages.Height);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourcesContentWidth: Integer;
begin
  Result := FBounds.Bottom - FBounds.Top - FDayHeaderHeight;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetTimeLineParams: TcxViewParams;
begin
  Result := StylesAdapter.GetContentParams(NullDate, nil)
end;

function TcxSchedulerCustomResourceViewViewInfo.GetSelectionParams(
  const AParams: TcxViewParams): TcxViewParams;
begin
  Result := AParams;
  if View.Scheduler.Focused or not HideSelection then
  begin
    Result := FSelectionParams;
    Result.Bitmap := nil;
  end;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetSeparatorCount: Integer;
begin
  Result := ResourceCount - 1;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetFontHeight(
  AStyle: TcxStyle): Integer;
begin
  if (AStyle = nil) or not (cxStyles.svFont in AStyle.AssignedValues) then
    Result := PainterHelper.TextHeight(DefaultFont)
  else
    Result := PainterHelper.TextHeight(AStyle.Font);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetFontHeight(
  const AParams: TcxViewParams): Integer;
begin
  Result := PainterHelper.TextHeight(AParams.Font);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetPageHeaderText: string;
begin
  Result := FormatDateTime(LongDateFormat, Days[0]);
  if Days[0] <> Days[DayCount - 1] then
    Result := Result + ' - ' + FormatDateTime(LongDateFormat, Days[DayCount - 1]);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourceItemByIndex(
  AIndex: Integer): TcxSchedulerStorageResourceItem;
begin
  Result := nil;
  if AIndex >= 0 then
    Result := Resources[AIndex].ResourceItem;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourceViewInfoByItem(
  AItem: TcxSchedulerStorageResourceItem): TcxSchedulerResourceViewInfo;
var
  I: Integer;
begin
  Result := nil;
  for I := 0 to ResourceCount - 1 do
    if Resources[I].ResourceItem = AItem then
      Result := Resources[I];
end;

function TcxSchedulerCustomResourceViewViewInfo.HasStorage: Boolean;
begin
  Result := View.Scheduler.Storage <> nil;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.ProcessCheckBorders(
  AList: TcxSchedulerViewInfoCellList; AHasCommonArea: Boolean;
  ANeighbors: TcxNeighbors = []; AExcludeBorders: TcxBorders = [];
  AAddBorders: TcxBorders = []);
var
  I: Integer;
  DrawCommonBorders: Boolean;
  ACell, APrevCell: TcxSchedulerHeaderCellViewInfo;
begin
  DrawCommonBorders :=
    LookAndFeelPainter.HeaderBorders([nLeft..nBottom]) = cxBordersAll;
  APrevCell := nil;
  for I := 0 to AList.Count - 1 do
  begin
    ACell := TcxSchedulerHeaderCellViewInfo(AList[I]);
    ACell.FNeighbors := [nLeft, nRight];
    if (I = 0) and not ACell.RotateHeader then
    begin
      Exclude(ACell.FNeighbors, nLeft);
      if AHasCommonArea then
        Include(ACell.FNeighbors, nBottom);
    end;
    ACell.FNeighbors := ACell.FNeighbors + ANeighbors;
    ACell.FBorders := LookAndFeelPainter.HeaderBorders(ACell.FNeighbors);
    if not DrawCommonBorders then
    begin
      ACell.CheckNeighbor(APrevCell);
      ACell.FBorders := ACell.FBorders - AExcludeBorders + AAddBorders;
    end;
    if I = (AList.Count - 1) then
    begin
      Exclude(ACell.FBorders, bRight);
      Exclude(ACell.FNeighbors, nRight);
    end; 
    APrevCell := ACell;
  end;
end;

function TcxSchedulerCustomResourceViewViewInfo.SetAdapter(
  Adapter: TcxCustomResourceViewAdapter): TcxCustomResourceViewAdapter;
begin
  Result := FAdapter;
  FAdapter := Adapter;
  FStylesAdapter := FAdapter.GetStylesAdapter;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.SetResourceTextRect(
  AResource: TcxSchedulerStorageResourceItem; const ARect: TRect);
var
  I: Integer;
begin
  for I := 0 to ResourceCount - 1 do
    if Resources[I].ResourceItem = AResource then
    begin
      Resources[I].FTextRect := ARect;
      Break;
    end;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.ProcessDateToDisplayText(
  ArrangeByType: Boolean = False);
var
  I: Integer;
  AType: Integer;
begin
  AType := 0;
  for I := 0 to FDayHeaderCells.Count - 1 do
    AType := Max(TcxSchedulerDayHeaderCellViewInfo(
      FDayHeaderCells[I]).ConvertDateToDisplayText, AType);
  if ArrangeByType and (AType > 0) then
  begin
    for I := 0 to FDayHeaderCells.Count - 1 do
      TcxSchedulerDayHeaderCellViewInfo(
         FDayHeaderCells[I]).ConvertDateToDisplayText(AType);
  end;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.HideCloneEventsOnDragDrop;
var
  I: Integer;
  AEventCell: TcxSchedulerEventCellViewInfo;
begin
  for I := 0 to EventCells.Count - 1 do
  begin
    AEventCell := TcxSchedulerEventCellViewInfo(EventCells[I]);
    if Events.Clones.IndexOf(AEventCell.Event) <> -1 then
      AEventCell.Hidden := True;
  end;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.HideSourceEventsOnDragDrop;
var
  I, J: Integer;
  AEventCell: TcxSchedulerEventCellViewInfo;
begin
  for I := 0 to EventCells.Count - 1 do
  begin
    AEventCell := TcxSchedulerEventCellViewInfo(EventCells[I]);
    for J := 0 to Events.Clones.Count - 1 do
      if TcxSchedulerControlEvent(Events.Clones[J]).Source = AEventCell.Event then
      begin
        AEventCell.Hidden := True;
        Break;
      end;
  end;
end;

function TcxSchedulerCustomResourceViewViewInfo.IsTimeSelected(
  ATime: TDateTime; AResource: TObject): Boolean;
begin
  ATime := DateTimeHelper.RoundTime(ATime);
  Result := not HideSelection and ((AResource = FSelResource) and
    (ATime >= SelStart) and (ATime <= SelFinish));
  Result := Result and CanSelected;
end;

procedure TcxSchedulerCustomResourceViewViewInfo.MakeTimeVisible(
  const ATime: TDateTime);
begin
end;

procedure TcxSchedulerCustomResourceViewViewInfo.OnMoreEventsButtonClick(
  Sender: TcxSchedulerMoreEventsButtonViewInfo);
begin
  if not DoSchedulerMoreEventsButtonClick then
    DoMoreEventsButtonClick(Sender);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetClones: TcxSchedulerEventList;
begin
  Result := View.EventList.Clones;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetDay(AIndex: Integer): TDateTime;
begin
  Result := Integer(SelectedDays.List^[AIndex]);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetDayCount: Integer;
begin
  Result := SelectedDays.Count;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetShowEventsWithoutResource: Boolean;
begin
  Result := View.OptionsView.ShowEventsWithoutResource or (FGroupingKind = gkNone);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetGroupByDate: Boolean;
begin
  Result := GroupingKind = gkByDate;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetGroupByResource: Boolean;
begin
  Result := GroupingKind = gkByResource;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetGroupingKind: TcxSchedulerGroupingKind;
begin
  Result := View.GroupingKind;
  if Result = gkDefault then
    Result := View.OptionsView.GroupingKind;
  if ResourceCount = 0 then
    Result := gkNone
  else
    if Result = gkDefault then
      Result := gkByResource;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetHasSeparator: Boolean;
begin
  Result := (SeparatorWidth > 0) and (GroupingKind <> gkNone);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetHasVisibleBounds: Boolean;
begin
  Result := (PrintFrom <> NullDate) and (PrintTo <> NullDate)
end;

function TcxSchedulerCustomResourceViewViewInfo.GetHiddenSelection: Boolean;
begin
  Result := View.Controller.IsEditing or (Events.Selection.Count > 0);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResource(
  AIndex: Integer): TcxSchedulerResourceViewInfo;
begin
  if AIndex < 0 then
    Result := nil
  else
    Result := TcxSchedulerResourceViewInfo(FResources[AIndex]);
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourceCaption(
  AIndex: Integer): string;
begin
  Result := Resources[AIndex].Caption;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourceCount: Integer;
begin
  Result := FResources.Count;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetResourceHeaders: TcxSchedulerResourceHeaders;
begin
  Result := View.OptionsView.ResourceHeaders;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetPrintRange(
  Index: Integer): TDateTime;
begin
  Result := Adapter.GetPrintRange(Index)
end;

function TcxSchedulerCustomResourceViewViewInfo.GetSeparatorWidth: Integer;
begin
  Result := View.OptionsView.GroupSeparatorWidth;
end;

function TcxSchedulerCustomResourceViewViewInfo.GetView: TcxSchedulerCustomResourceView;
begin
  Result := TcxSchedulerCustomResourceView(Owner);
end;

{ TcxSchedulerCustomResourceViewNavigation }

procedure TcxSchedulerCustomResourceViewNavigation.ValidateSelection(
  var ASelStart, ASelFinish: TDateTime;
  var AResource: TcxSchedulerStorageResourceItem);
begin
  AResource := ResourceItem;
end;

function TcxSchedulerCustomResourceViewNavigation.GetNextResource(
  AGoToForward: Boolean): TcxSchedulerStorageResourceItem;
var
  AIndex: Integer;
begin
  Result := ResourceItem;
  AIndex := ViewInfo.FResources.IndexOf(ResourceObject) + Byte(AGoToForward) * 2 - 1;
  if (AIndex < 0) or (AIndex >= ViewInfo.FResources.Count) then Exit;
  Result := ViewInfo.GetResourceItemByIndex(AIndex);
end;

function TcxSchedulerCustomResourceViewNavigation.GetResourceItem: TcxSchedulerStorageResourceItem;
begin
  Result := nil;
  if ResourceObject <> nil then
    Result := ResourceObject.ResourceItem;
end;

function TcxSchedulerCustomResourceViewNavigation.GetResourceFromViewInfo(
  AInfo: TcxSchedulerResourceViewInfo): TcxSchedulerStorageResourceItem;
begin
  Result := nil;
  if AInfo <> nil then
    Result := AInfo.ResourceItem;
end;

function TcxSchedulerCustomResourceViewNavigation.RoundTime(
  const ADateTime: TDateTime): TDateTime;
begin
  Result := DateTimeHelper.RoundTime(ADateTime);
end;

function TcxSchedulerCustomResourceViewNavigation.GetIsFirstResource: Boolean;
begin
  Result := ViewInfo.FResources.IndexOf(ResourceObject) <= 0;
end;

function TcxSchedulerCustomResourceViewNavigation.GetIsLastResource: Boolean;
begin
  Result := ViewInfo.FResources.IndexOf(ResourceObject) =
    (ViewInfo.FResources.Count - 1);
end;

function TcxSchedulerCustomResourceViewNavigation.GetGroupingKind: TcxSchedulerGroupingKind;
begin
  Result := ViewInfo.FGroupingKind;
end;

function TcxSchedulerCustomResourceViewNavigation.GetResourceObject: TcxSchedulerResourceViewinfo;
begin
  Result := ViewInfo.FSelResource;
end;

function TcxSchedulerCustomResourceViewNavigation.GetViewInfo: TcxSchedulerCustomResourceViewViewInfo;
begin
  Result := TcxSchedulerCustomResourceView(View).ViewInfo;
end;

{ TcxSchedulerCustomResourceViewController }

function TcxSchedulerCustomResourceViewController.CreateNavigation: TcxSchedulerViewNavigation;
begin
  Result := TcxSchedulerCustomResourceViewNavigation.Create(View);
end;

function TcxSchedulerCustomResourceViewController.GetCursor(X, Y: Integer): TCursor;
const
  Cursors: array[Boolean] of TCursor = (crSchedulerVertResize, crSchedulerHorzResize);
begin
  with HitTest do
    case GetDragKind of
      edkEventDragRect:
        Result := crSchedulerSplitAll;
      edkResizeStart, edkResizeEnd:
        Result := Cursors[EventCell.IsHorzSizing];
    else
      Result := inherited GetCursor(X, Y);
    end;
end;

procedure TcxSchedulerCustomResourceViewController.MouseDown(
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  inherited MouseDown(Button, Shift, X, Y);
  with HitTest do
    if HitAtButton then Button.Click;
end;

function TcxSchedulerCustomResourceViewController.GetHitTest: TcxSchedulerCustomResourceViewHitTest;
begin
  Result := TcxSchedulerCustomResourceViewHitTest(inherited HitTest);
end;

{ TcxSchedulerCustomResourceViewHitTest }

function TcxSchedulerCustomResourceViewHitTest.GetDragKind: TcxEventDragKind;
begin
  ValidateDragKind;
  Result := FDragKind;
end;

procedure TcxSchedulerCustomResourceViewHitTest.SetDragKind(
  AValue: TcxEventDragKind);
begin
  FDragKind := AValue;
  ValidateDragKind;
end;

function TcxSchedulerCustomResourceViewHitTest.CanMoveEvent(
  AEvent: TcxSchedulerControlEvent): Boolean;
var
  AResource: TcxSchedulerStorageResourceItem;
begin
  Result := Scheduler.EventOperations.Moving;
  if Result then
  begin
    AResource := AEvent.GetResourceItem;
    Result := (AResource = nil) or not AResource.ReadOnly;
  end;
end;

function TcxSchedulerCustomResourceViewHitTest.CanResizeEvent(
  AEvent: TcxSchedulerControlEvent): Boolean;
var
  AResource: TcxSchedulerStorageResourceItem;
begin
  Result := Scheduler.EventOperations.Sizing;
  if Result then
  begin
    AResource := AEvent.GetResourceItem;
    Result := (AResource = nil) or not AResource.ReadOnly;
  end;
end;

procedure TcxSchedulerCustomResourceViewHitTest.Clear;
begin
  FDragKind := edkNone;
  FEventCell := nil;
  FResource := nil;
  FHitObject := nil;
  inherited Clear;
end;

procedure TcxSchedulerCustomResourceViewHitTest.DoCalculate;
begin
  inherited DoCalculate;
  if HitAtControl then
    View.ViewInfo.CalculateHitTest(Self);
end;

function TcxSchedulerCustomResourceViewHitTest.GetHitEvent: TcxSchedulerControlEvent;
begin
  Result := inherited GetHitEvent;
  if FEventCell <> nil then
    Result := FEventCell.Event;
end;

procedure TcxSchedulerCustomResourceViewHitTest.SetHitTime(
  AItemFlag: Integer; const ATime: TDateTime);
begin
  SetBitState(AItemFlag, True);
  SetBitState(htcTime, True);
  FTime := ATime;
end;

procedure TcxSchedulerCustomResourceViewHitTest.SetResource(
  AResource: TcxSchedulerResourceViewInfo);
begin
  if AResource = nil then
    FResource := nil
  else
    FResource := AResource.ResourceItem;
end;

procedure TcxSchedulerCustomResourceViewHitTest.ValidateDragKind;
begin
  if (Event = nil) or ((FDragKind in [edkEventDragRect, edkMoveEvent]) and not CanMoveEvent(Event)) or
     ((FDragKind in [edkResizeStart, edkResizeEnd]) and not CanResizeEvent(Event)) then
    FDragKind := edkNone;
end;

function TcxSchedulerCustomResourceViewHitTest.GetContentCell: TcxSchedulerContentCellViewInfo;
begin
  if HitAtContent then
    Result := TcxSchedulerContentCellViewInfo(FHitObject)
  else
    Result := nil;
end;

function TcxSchedulerCustomResourceViewHitTest.GetHeaderCell: TcxSchedulerHeaderCellViewInfo;
begin
  if HitAtDayHeader or HitAtResourceHeader then
    Result := TcxSchedulerHeaderCellViewInfo(FHitObject)
  else
    Result := nil;
end;

function TcxSchedulerCustomResourceViewHitTest.GetView: TcxSchedulerCustomResourceView;
begin
  Result := TcxSchedulerCustomResourceView(inherited Owner);
end;

{ TcxSchedulerCustomViewPainter }

constructor TcxSchedulerCustomViewPainter.Create(
  AOwner: TcxSchedulerSubControl);
begin
  inherited Create(AOwner);
  FPainter := View.GetCommonViewItemsPainter;
end;

procedure TcxSchedulerCustomViewPainter.Paint;
begin
end;

procedure TcxSchedulerCustomViewPainter.DrawBackgroundCell(
  AItem: TcxSchedulerBackgroundCellViewInfo);
var
  ADone: Boolean;
begin
  if AItem = nil then Exit;
  ADone := False;
  AItem.BeforeCustomDraw(Canvas);
  if Painter <> nil then
    Painter.DoCustomDrawBackground(AItem, ADone);
  if not ADone then
    View.DoCustomDrawBackground(AItem, ADone);
  AItem.AfterCustomDraw(Canvas);
  if not ADone then
    AItem.Draw(Canvas);
end;

procedure TcxSchedulerCustomViewPainter.DrawButtonCell(
  AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
  if Painter <> nil then
    Painter.DoCustomDrawButton(TcxSchedulerMoreEventsButtonViewInfo(AItem), ADone);
  if not ADone then
    View.DoCustomDrawButton(TcxSchedulerMoreEventsButtonViewInfo(AItem), ADone);
end;

procedure TcxSchedulerCustomViewPainter.DrawContentCell(
  AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
  if Painter <> nil then
    Painter.DoCustomDrawContent(TcxSchedulerContentCellViewInfo(AItem), ADone);
  if not ADone then
    View.DoCustomDrawContent(TcxSchedulerContentCellViewInfo(AItem), ADone);
end;

procedure TcxSchedulerCustomViewPainter.DrawEventCell(
  AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
  with TcxSchedulerEventCellViewInfo(AItem) do
    if Hidden or not Visible then Exit; 
  if Painter <> nil then
    Painter.DoCustomDrawEvent(TcxSchedulerEventCellViewInfo(AItem), ADone);
  if not ADone then
    View.DoCustomDrawEvent(TcxSchedulerEventCellViewInfo(AItem), ADone);
end;

procedure TcxSchedulerCustomViewPainter.DrawHeaderCell(
  AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
  if Painter <> nil then
    Painter.DoCustomDrawDayHeader(TcxSchedulerDayHeaderCellViewInfo(AItem), ADone);
  if not ADone then
    View.DoCustomDrawDayHeader(TcxSchedulerDayHeaderCellViewInfo(AItem), ADone);
end;

procedure TcxSchedulerCustomViewPainter.DrawGroupSeparatorCell(
  AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
  if Painter <> nil then
    Painter.DoCustomDrawGroupSeparator(TcxSchedulerGroupSeparatorCellViewInfo(AItem), ADone);
  if not ADone then
    View.DoCustomDrawGroupSeparator(TcxSchedulerGroupSeparatorCellViewInfo(AItem), ADone);
end;

procedure TcxSchedulerCustomViewPainter.DrawResourceHeaderCell(
  AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean);
begin
  if Painter <> nil then
    Painter.DoCustomDrawResourceHeader(TcxSchedulerHeaderCellViewInfo(AItem), ADone);
  if not ADone then
    View.DoCustomDrawResourceHeader(TcxSchedulerHeaderCellViewInfo(AItem), ADone);
end;

function TcxSchedulerCustomViewPainter.GetView: TcxSchedulerCustomResourceView;
begin
  Result := TcxSchedulerCustomResourceView(Owner);
end;

{ TcxSchedulerEventPlace }

procedure TcxSchedulerEventPlace.AlignPosition(APlace: TcxSchedulerEventPlace);
begin
  LineFinish := APlace.LineFinish + 1 + (LineFinish - LineStart);
  LineStart := APlace.LineFinish + 1;
end;

function TcxSchedulerEventPlace.IntersectHorz(APlace: TcxSchedulerEventPlace): Boolean;
begin
  Result := (APlace.Resource = Resource) and (APlace.ColFinish >= ColStart) and
    (APlace.ColStart <= ColFinish);
end;

function TcxSchedulerEventPlace.IntersectVert(APlace: TcxSchedulerEventPlace): Boolean;
begin
  Result := (APlace.Resource = Resource) and (APlace.LineFinish >= LineStart) and
    (APlace.LineStart <= LineFinish);
end;

procedure TcxSchedulerEventPlace.ResetPosition;
begin
  LineFinish := LineFinish - LineStart;
  LineStart := 0;
end;

function cxCompareEventPlaces(AEventPlace1, AEventPlace2: TcxSchedulerEventPlace): Integer;
var
  AAllDay1, AAllDay2: Boolean;
  AEvent1, AEvent2: TcxSchedulerEvent;
begin
  Result := Integer(AEventPlace1.Resource) - Integer(AEventPlace1.Resource);
  if Result <> 0 then Exit;
  AEvent1 := AEventPlace1.Event;
  AEvent2 := AEventPlace2.Event;
  AAllDay1 := AEvent1.AllDayEvent or (AEvent1.Duration >= 1);
  AAllDay2 := AEvent2.AllDayEvent or (AEvent2.Duration >= 1);
  Result := Byte(AAllDay2) - Byte(AAllDay1);
  if Result <> 0 then Exit;
  if AEvent1.Start < AEvent2.Start then
    Result := -1
  else
    if AEvent1.Start > AEvent2.Start then
      Result := 1
    else
      if AEvent1.Finish > AEvent2.Finish then
        Result := -1
      else
        if AEvent1.Finish < AEvent2.Finish then
          Result := 1
        else
          if AEvent1.RecordIndex < AEvent2.RecordIndex then
            Result := -1
          else
            if AEvent1.RecordIndex > AEvent2.RecordIndex then
              Result := 1
            else
              Result := 0;
end;

{ TcxSchedulerEventLayoutBuilder }

constructor TcxSchedulerEventLayoutBuilder.Create;
begin
  FEventPlaces := TcxObjectList.Create;
end;

destructor TcxSchedulerEventLayoutBuilder.Destroy;
begin
  FreeAndNil(FEventPlaces);
  inherited Destroy;
end;

function TcxSchedulerEventLayoutBuilder.AddEventPlace(AEvent: TcxSchedulerEvent;
  AStartCol, AFinishCol: Integer; ALineCount: Integer = 1; AResource: TObject = nil): TcxSchedulerEventPlace;
begin
  Result := TcxSchedulerEventPlace.Create;
  Result.ColStart := AStartCol;
  Result.ColFinish := AFinishCol;
  Result.Event := AEvent;
  Result.LineFinish := ALineCount - 1;
  Result.Resource := AResource; 
  FEventPlaces.Add(Result);
end;

procedure TcxSchedulerEventLayoutBuilder.Clear;
begin
  FEventPlaces.Clear;
end;

procedure TcxSchedulerEventLayoutBuilder.Calculate;
var
  I, J, K: Integer;
  ACurPlace: TcxSchedulerEventPlace;
begin
  FEventPlaces.Sort(TListSortCompare(@cxCompareEventPlaces));
  for I := 1 to EventPlaceCount - 1 do
  begin
    J := I;
    K := I;
    ACurPlace := EventPlaces[I];
    repeat
      Dec(J);
      if ACurPlace.IntersectHorz(EventPlaces[J]) then K := J;
    until J = 0;
    ACurPlace.ResetPosition;
    J := K;
    while J < I do
    begin
      if ACurPlace.IntersectHorz(EventPlaces[J]) and ACurPlace.IntersectVert(EventPlaces[J]) then
      begin
        ACurPlace.AlignPosition(EventPlaces[J]);
        J := K;
      end
      else
        Inc(J);
    end;
  end;
end;

procedure TcxSchedulerEventLayoutBuilder.CalculateEx(AEventsList: TcxSchedulerFilteredEventList;
  APlaceInfoProc: TcxSchedulerEventLayoutBuilderGetEventPlaceProc);
var
  AEvent: TcxSchedulerControlEvent;
  I, AStartCol, AFinishCol, ALineCount: Integer;
begin
  Clear;
  for I := 0 to AEventsList.Count - 1 do
  begin
    AEvent := AEventsList[I];
    ALineCount := 1;
    if APlaceInfoProc(Self, AEventsList[I], AStartCol, AFinishCol, ALineCount) then
      AddEventPlace(AEvent, AStartCol, AFinishCol, ALineCount);
  end;
  Calculate;
end;

function TcxSchedulerEventLayoutBuilder.GetEventPlace(AIndex: Integer): TcxSchedulerEventPlace;
begin
  Result := TcxSchedulerEventPlace(FEventPlaces.List^[AIndex]);
end;

function TcxSchedulerEventLayoutBuilder.GetEventPlaceCount: Integer;
begin
  Result := FEventPlaces.Count;
end;

end.
