{********************************************************************} { } { Developer Express Visual Component Library } { ExpressScheduler } { } { Copyright (c) 2003-2009 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 cxSchedulerDayView; {$I cxVer.inc} interface uses Windows, Forms, Classes, SysUtils, Math, StdCtrls, Graphics, {$IFDEF DELPHI6}DateUtils, {$ENDIF} Controls, ExtCtrls, cxControls, cxGraphics, cxStyles, cxGeometry, Menus, cxLookAndFeelPainters, cxSchedulerCustomControls, cxSchedulerCustomResourceView, cxSchedulerUtils, cxSchedulerStorage, cxSchedulerStrs; const cxDefaultTimeScale = 30; cxScrollInterval = 25; cxScrollZoneSize = 10; cxcsHeaderContainer = 0; cxcsSelectedHeaderContainer = 1; cxcsTimeLine = 2; cxcsTimeRuler = 3; cxcsMaxDayViewValue = cxcsTimeRuler; //for PS cxcsDayViewStyleFirst = cxcsHeaderContainer; cxcsDayViewStyleLast = cxcsMaxDayViewValue; type TcxSchedulerDayViewViewInfo = class; TcxEventLayoutInfo = class; TcxCalculateEventLayout = class; TcxSchedulerDayViewHitTest = class; TcxSchedulerDayViewController = class; TcxSchedulerTimeRulerPopupMenu = class; IcxSchedulerTimeRulerParams = interface ['{FEAA09ED-8FE1-4968-9BCB-0FC26B13A391}'] function GetTimeRulerParams: TcxViewParams; end; { TcxSchedulerDayViewStyles } TcxSchedulerDayViewStyles = class(TcxStyles) private FScheduler: TcxCustomScheduler; function GetPainter: TcxCustomLookAndFeelPainterClass; protected procedure Changed(AIndex: Integer); override; procedure GetDefaultViewParams(Index: Integer; AData: TObject; out AParams: TcxViewParams); override; property Painter: TcxCustomLookAndFeelPainterClass read GetPainter; public constructor Create(AOwner: TPersistent); override; procedure Assign(Source: TPersistent); override; function GetHeaderContainerParams(const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem; ASelected: Boolean): TcxViewParams; function GetTimeRulerParams: TcxViewParams; function GetTimeLineParams: TcxViewParams; // define colors functions property Scheduler: TcxCustomScheduler read FScheduler; published property HeaderContainer: TcxStyle index cxcsHeaderContainer read GetValue write SetValue; property SelectedHeaderContainer: TcxStyle index cxcsSelectedHeaderContainer read GetValue write SetValue; property TimeLine: TcxStyle index cxcsTimeLine read GetValue write SetValue; property TimeRuler: TcxStyle index cxcsTimeRuler read GetValue write SetValue; end; { TcxSchedulerDayView } TcxSchedulerCustomDrawContainerEvent = procedure(Sender: TObject; ACanvas: TcxCanvas; AViewInfo: TcxSchedulerContainerCellViewInfo; var ADone: Boolean) of object; TcxSchedulerCustomDrawTimeRulerEvent = procedure(Sender: TObject; ACanvas: TcxCanvas; AViewInfo: TcxSchedulerTimeRulerCellViewInfo; var ADone: Boolean) of object; TcxSchedulerDayView = class(TcxSchedulerCustomResourceView) private FAutoContentHeight: Boolean; FEventShadows: Boolean; FStyles: TcxSchedulerDayViewStyles; FTimeRulerPopupMenu: TcxSchedulerTimeRulerPopupMenu; FTimeScale: Integer; FOnCustomDrawContainer: TcxSchedulerCustomDrawContainerEvent; FOnCustomDrawTimeRuler: TcxSchedulerCustomDrawTimeRulerEvent; function GetHitTest: TcxSchedulerDayViewHitTest; function GetViewInfo: TcxSchedulerDayViewViewInfo; procedure SetAutoContentHeight(AValue: Boolean); procedure SetEventShadows(AValue: Boolean); procedure SetStyles(AValue: TcxSchedulerDayViewStyles); procedure SetTimeRulerPopupMenu(AValue: TcxSchedulerTimeRulerPopupMenu); procedure SetTimeScale(AValue: Integer); protected // store interface procedure GetProperties(AProperties: TStrings); override; procedure GetPropertyValue(const AName: string; var AValue: Variant); override; procedure SetPropertyValue(const AName: string; const AValue: Variant); override; // procedure CreateSubClasses; override; procedure DestroySubClasses; override; function CreateController: TcxSchedulerSubControlController; override; function CreateHitTest: TcxSchedulerSubControlHitTest; override; function CreatePainter: TcxSchedulerSubControlPainter; override; function CreateStyles: TcxSchedulerDayViewStyles; virtual; function CreateTimeRulerPopupMenu: TcxSchedulerTimeRulerPopupMenu; virtual; function CreateViewAdapter: TcxCustomResourceViewAdapter; override; function CreateViewInfo: TcxSchedulerSubControlViewInfo; override; procedure DoCustomDrawContainer(ACell: TcxSchedulerContainerCellViewInfo; var ADone: Boolean); virtual; procedure DoCustomDrawTimeRuler(ACell: TcxSchedulerTimeRulerCellViewInfo; var ADone: Boolean); virtual; function DoShowPopupMenu(X, Y: Integer): Boolean; override; function EventContentSelected(AEvent: TcxSchedulerControlEvent): Boolean; override; function GetTimeIncrement: TDateTime; override; function IsDayView: Boolean; override; procedure MakeEventVisible(AEvent: TcxSchedulerControlEvent; const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem); override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure ScrollVisibleDays(AScrollUp: Boolean); override; procedure TimeChanged; override; procedure VisibleChanged; override; property ViewInfo: TcxSchedulerDayViewViewInfo read GetViewInfo; public constructor Create(AOwner: TcxCustomScheduler); override; procedure Assign(Source: TPersistent); override; procedure MakeWorkTimeVisible; property HitTest: TcxSchedulerDayViewHitTest read GetHitTest; property Scheduler; property WorkDays; property WorkStart; property WorkFinish; published property CanShow; //before active property Active; property AutoContentHeight: Boolean read FAutoContentHeight write SetAutoContentHeight default False; property EventShadows: Boolean read FEventShadows write SetEventShadows default True; property GroupingKind; property Styles: TcxSchedulerDayViewStyles read FStyles write SetStyles; property TimeRulerPopupMenu: TcxSchedulerTimeRulerPopupMenu read FTimeRulerPopupMenu write SetTimeRulerPopupMenu; property TimeScale: Integer read FTimeScale write SetTimeScale default cxDefaultTimeScale; property OnCustomDrawContainer: TcxSchedulerCustomDrawContainerEvent read FOnCustomDrawContainer write FOnCustomDrawContainer; property OnCustomDrawTimeRuler: TcxSchedulerCustomDrawTimeRulerEvent read FOnCustomDrawTimeRuler write FOnCustomDrawTimeRuler; end; { TcxSchedulerDayViewAdapter } TcxSchedulerDayViewAdapter = class(TcxCustomResourceViewAdapter) protected FTopIndex: Integer; procedure Store; override; procedure Restore; override; end; { TcxSchedulerDayViewViewInfo } TcxSchedulerDayViewViewInfo = class(TcxSchedulerCustomResourceViewViewInfo) private function GetAutoHeight: Boolean; function GetColumnInGroup: Integer; function GetContentHeight: Integer; function GetDayView: TcxSchedulerDayView; function GetGroupCount: Integer; function GetPrintRowCount: Integer; function GetLinePerHour: Integer; procedure SetLargeFont(AFont: TFont); protected FAdditionalTimeZone: Integer; FBackground: TcxSchedulerBackgroundCellViewInfo; FColCount: Integer; FContentOffset: Integer; FCurrentTimeZone: Integer; FEventLayout: TcxCalculateEventLayout; FHeaderLineCount: Integer; FHeaderLineHeight: Integer; FHeaderOffsetLeft: Integer; FIsContainerSelected: Boolean; FLargeFont: TFont; FPrintStartRow: Integer; FPrintFinishRow: Integer; FRowCount: Integer; FTimeRulerCells: TcxSchedulerViewInfoCellList; FTopIndex: Integer; FTimeScale: Integer; FUnusedRowCount: Integer; FVisibleRowCount: Integer; function AddContentCell(const ARect: TRect; const AStart, AFinish: TDateTime; AResourceIndex: Integer): TcxSchedulerContentCellViewInfo; override; procedure AddContainerCell(AColumn: Integer; const ABounds: TRect); procedure AddHeaderContainerEvent(AEvent: TcxSchedulerControlEvent; AContainer: TcxSchedulerContainerCellViewInfo; AColIndex: Integer); procedure AddMoreEventsButton(const AIndex, ARowIndex: Integer; AIsTop: Boolean); procedure CalculateBackground; virtual; procedure CalculateContent; virtual; procedure CalculateEvents; virtual; procedure CalculateEventsForColumn(AIndex: Integer; AContainer: TcxSchedulerContainerCellViewInfo; AEvents: TcxSchedulerEventList); virtual; procedure CalculateHeaderEvents; virtual; procedure CalculateHeaderLineCount; procedure CalculateHeaders; virtual; procedure CalculateMetrics; override; procedure CalculateMetricsForPrinting; procedure CalculatePrintRows; procedure CalculateTimeLine; virtual; procedure CalculateUnusedRowCount; function CheckDisplayRows(var AStartRow, AFinishRow: Integer): Boolean; procedure CheckEventRowsVisibility(AEvent: TcxSchedulerControlEvent; AStartRow, AFinishRow: Integer); procedure Clear; override; function CreateContentEventViewData(AEventInfo: TcxEventLayoutInfo; AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData; function CreateHeaderEventViewData(AEvent: TcxSchedulerControlEvent; const ABounds: TRect; const AStart, AFinish: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData; function CreateEventLayout: TcxCalculateEventLayout; virtual; procedure DoCalculate; override; procedure ExtractEvents(ASource, ADest: TcxSchedulerEventList; AIndex: Integer); function GetContentParams(const ATime: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxViewParams; override; function GetColumnDate(AIndex: Integer): TDateTime; function GetColumnResource(AIndex: Integer): TcxSchedulerResourceViewInfo; function GetColumnResourceIndex(AIndex: Integer): Integer; function GetContainer(AIndex: Integer): TcxSchedulerContainerCellViewInfo; virtual; function GetContainerCount: Integer; virtual; function GetDayHeaderHeight: Integer; override; function GetEventSlotDisplayText(AEvent: TcxSchedulerControlEvent): string; function GetTimeLineParams: TcxViewParams; override; function GetTimeRulerParams: TcxViewParams; function GetTimeRow(const ATime: TDateTime; AIsStart: Boolean): Integer; function GetRowTime(AColumn, ARow: Integer): TDateTime; function IsColumnEvent(AEvent: TcxSchedulerEvent; AIndex: Integer; IsHeaderEvent: Boolean): Boolean; function IsContainerSelected(AResource: TcxSchedulerStorageResourceItem; ADate: TDateTime): Boolean; function IsEventVisible(AEvent: TcxSchedulerEvent): Boolean; overload; function IsEventVisible(var AStartRow, AStopRow: Integer): Boolean; overload; function IsHourVisible(AIndex: Integer): Boolean; function IsRowVisible(AIndex: Integer): Boolean; procedure MakeTimeVisible(const ATime: TDateTime); override; procedure OnClickMoreButton(Sender: TcxSchedulerMoreEventsButtonViewInfo); override; procedure SetColumnTimeLineStyle(AViewInfo: TcxSchedulerEventCellViewInfo; AColIndex: Integer); property ColCount: Integer read FColCount; property ColumnInGroup: Integer read GetColumnInGroup; property ContainerCount: Integer read GetContainerCount; property Containers[AIndex: Integer]: TcxSchedulerContainerCellViewInfo read GetContainer; property GroupCount: Integer read GetGroupCount; public constructor Create(AOwner: TcxSchedulerSubControl); override; destructor Destroy; override; procedure CalculateHitTest(AHitTest: TcxSchedulerCustomResourceViewHitTest); override; procedure InitScrollBarsParameters; override; procedure ScrollVertical(AScrollCode: TScrollCode; var AScrollPos: Integer); override; property AutoHeight: Boolean read GetAutoHeight; property Background: TcxSchedulerBackgroundCellViewInfo read FBackground; property ContentHeight: Integer read GetContentHeight; property DayView: TcxSchedulerDayView read GetDayView; property HeaderContainerCells: TcxSchedulerViewInfoCellList read FHeaderContainerCells; property HeaderLineHeight: Integer read FHeaderLineHeight; property LargeFont: TFont read FLargeFont write SetLargeFont; property LinePerHour: Integer read GetLinePerHour; property PrintRowCount: Integer read GetPrintRowCount; property PrintFinishRow: Integer read FPrintFinishRow; property PrintStartRow: Integer read FPrintStartRow; property TimeScale: Integer read FTimeScale; property TimeRulerCells: TcxSchedulerViewInfoCellList read FTimeRulerCells; property TopIndex: Integer read FTopIndex; property UnusedRowCount: Integer read FUnusedRowCount; property VisibleRowCount: Integer read FVisibleRowCount; end; { TcxSchedulerDayViewHitTest } TcxSchedulerDayViewHitTest = class(TcxSchedulerCustomResourceViewHitTest) private function GetContainerCell: TcxSchedulerContainerCellViewInfo; function GetTimeRulerCell: TcxSchedulerTimeRulerCellViewInfo; public property ContainerCell: TcxSchedulerContainerCellViewInfo read GetContainerCell; property HitAtContainer: Boolean index htcContainer read GetBitState; property HitAtTimeRuler: Boolean index htcTimeRuler read GetBitState; property TimeRulerCell: TcxSchedulerTimeRulerCellViewInfo read GetTimeRulerCell; property HitAtTimeZoneLabel; property TimeZone; end; { TcxDayViewDragEventHelper } TcxDayViewDragEventHelper = class(TcxDragEventHelper) private FStartInHeader: Boolean; function GetController: TcxSchedulerDayViewController; function GetHitTest: TcxSchedulerDayViewHitTest; protected function GetOriginHitTestMask: Int64; override; procedure GetOriginState; override; function InHeader: Boolean; virtual; function IsAtOrigin: Boolean; override; procedure SetCloneEventsTimeDelta(AStart, ACurrent: TDateTime; AInHeader: Boolean); procedure UpdateClonesTime; override; procedure UpdateEventProperties; override; procedure UpdateEventStates; property Controller: TcxSchedulerDayViewController read GetController; property HitTest: TcxSchedulerDayViewHitTest read GetHitTest; end; { TcxDayViewEventSizing } TcxDayViewEventSizing = class(TcxEventSizingHelper) private FFixedBoundTime: TDateTime; function GetController: TcxSchedulerDayViewController; function GetHitTest: TcxSchedulerDayViewHitTest; protected function GetDragCursor(Accepted: Boolean): TCursor; override; function GetOriginHitTestMask: Int64; override; // Event handling procedure CalcAllDayEvent; override; function GetFinishTime: TDateTime; override; procedure GetOriginState; override; function GetSizingTime: TDateTime; function GetStartTime: TDateTime; override; property Controller: TcxSchedulerDayViewController read GetController; property HitTest: TcxSchedulerDayViewHitTest read GetHitTest; end; { TcxSchedulerDayNavigation } TcxSchedulerDayNavigation = class(TcxSchedulerCustomResourceViewNavigation) private function GetDayView: TcxSchedulerDayView; function GetSelectedDays: TcxSchedulerDateList; function GetViewInfo: TcxSchedulerDayViewViewInfo; protected FSelRow: Integer; function ColCount: Integer; procedure DoNextColumn(AGoToNext: Boolean; AColumn: Integer; const ATime: TDateTime; AResource: TcxSchedulerStorageResourceItem); virtual; function DoNextPage(AGoForward: Boolean; var ATime: TDateTime; var AResource: TcxSchedulerStorageResourceItem): Boolean; virtual; function GetColumnByDate(const ADate: TDateTime; AResource: TObject): Integer; function GetColumnDate(AColumn: Integer): TDateTime; function GetColumnResource(AColumn: Integer): TcxSchedulerStorageResourceItem; function GetRowTime(const ARow: Integer; AFinish: Boolean = False): TDateTime; function GetTimeRow(const ATime: TDateTime): Integer; public procedure KeyDown(var AKey: Word; AShift: TShiftState); override; procedure ValidateSelection(var ASelStart, ASelFinish: TDateTime; var AResource: TcxSchedulerStorageResourceItem); override; property DayView: TcxSchedulerDayView read GetDayView; property SelectedDays: TcxSchedulerDateList read GetSelectedDays; property ViewInfo: TcxSchedulerDayViewViewInfo read GetViewInfo; end; { TcxSchedulerDayViewController } TcxSchedulerDayViewController = class(TcxSchedulerCustomResourceViewController) private FPos: TPoint; FTimer: TTimer; procedure CheckUpdateEventBounds; function GetHitTest: TcxSchedulerDayViewHitTest; function GetViewInfo: TcxSchedulerDayViewViewInfo; protected FIsEditingBeforeMouseDown: Boolean; procedure BeforeMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure CancelScroll; override; procedure CheckScrolling(const APos: TPoint); override; procedure CheckTimeRulerTime; function CreateDragEventHelper: TcxDragEventHelper; override; function CreateNavigation: TcxSchedulerViewNavigation; override; function CreateResizeEventHelper: TcxEventSizingHelper; override; procedure InitTimer(AllowStart: Boolean; AScrollCode: TScrollCode); virtual; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure OnTimer(Sender: TObject); virtual; property HitTest: TcxSchedulerDayViewHitTest read GetHitTest; property ViewInfo: TcxSchedulerDayViewViewInfo read GetViewInfo; public constructor Create(AOwner: TcxSchedulerSubControl); override; destructor Destroy; override; end; { TcxSchedulerDayViewPainter } TcxSchedulerDayViewPainter = class(TcxSchedulerCustomViewPainter) private function GetView: TcxSchedulerDayView; function GetViewInfo: TcxSchedulerDayViewViewInfo; protected procedure DrawContainerCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual; procedure DrawDayViewEventCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual; procedure DrawTimeRulerCell(AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); virtual; public procedure Paint; override; property View: TcxSchedulerDayView read GetView; property ViewInfo: TcxSchedulerDayViewViewInfo read GetViewInfo; end; { TcxEventLayoutInfo } TcxEventLayoutInfo = class private protected ColStart, ColEnd, ColCount: Integer; Event: TcxSchedulerControlEvent; FDisplayRect: TRect; FFinishTime: TDateTime; FStartTime: TDateTime; IsBreakEvent: Boolean; RowCount: Integer; StartRow, StopRow: Integer; function ShadowSize: Integer; procedure CalculateDisplayRect(AWidth, ARowHeight: Integer); procedure CalculateTimes(const ADate: TDateTime; AScale: Integer); public constructor Create(AEvent: TcxSchedulerControlEvent; const ADate: TDateTime; AScale: Integer); virtual; property DisplayRect: TRect read FDisplayRect; property Finish: TDateTime read FFinishTime; property Start: TDateTime read FStartTime; end; { TcxCalculateEventLayout } TcxCalculateEventLayout = class(TList) private FDate: TDateTime; FLeft: Integer; FRowHeight: Integer; FTimeScale: Integer; FTop: Integer; FWidth: Integer; function GetInfo(AIndex: Integer): TcxEventLayoutInfo; protected FViewInfo: TcxSchedulerDayViewViewInfo; procedure CalculateColCount(AInfo: TcxEventLayoutInfo); virtual; procedure CalculateColEnd(AInfo: TcxEventLayoutInfo); virtual; procedure CalculateColStart(AInfo: TcxEventLayoutInfo; AIndex: Integer); virtual; function CreateEventInfo(AEvent: TcxSchedulerControlEvent): TcxEventLayoutInfo; function Intersect(AInfo1, AInfo2: TcxEventLayoutInfo): Boolean; procedure SetColCount(AInfo: TcxEventLayoutInfo); public procedure Add(AEvent: TcxSchedulerControlEvent); procedure Calculate; procedure Clear; override; procedure SetParams(const ADate: TDateTime; ATimeScale, ARowHeight: Integer; ALeft, ATop, AWidth: Integer); property Date: TDateTime read FDate write FDate; property Infos[Index: Integer]: TcxEventLayoutInfo read GetInfo; property Left: Integer read FLeft; property RowHeight: Integer read FRowHeight; property TimeScale: Integer read FTimeScale; property Top: Integer read FTop; property Width: Integer read FWidth; end; { TcxSchedulerTimeRulerPopupMenu } TcxSchedulerTimeRulerPopupMenuItem = (rpmiNewEvent, rpmiNewAllDayEvent, rpmiNewReccuringEvent, rpmi60min, rpmi30min, rpmi15min, rpmi10min, rpmi6min, rpmi5min); TcxSchedulerTimeRulerPopupMenuItems = set of TcxSchedulerTimeRulerPopupMenuItem; TcxSchedulerTimeRulerPopupMenuPopupEvent = procedure ( Sender: TcxSchedulerTimeRulerPopupMenu; ABuiltInMenu: TPopupMenu; var AHandled: Boolean) of object; TcxSchedulerTimeRulerPopupMenuClickEvent = procedure ( Sender: TcxSchedulerTimeRulerPopupMenu; AItem: TcxSchedulerTimeRulerPopupMenuItem; var AHandled: Boolean) of object; TcxSchedulerTimeRulerPopupMenu = class(TcxSchedulerCustomContentPopupMenu) private FItems: TcxSchedulerTimeRulerPopupMenuItems; FOnPopup: TcxSchedulerTimeRulerPopupMenuPopupEvent; FOnClick: TcxSchedulerTimeRulerPopupMenuClickEvent; function GetDayView: TcxSchedulerDayView; protected procedure CreateItems; override; procedure DoExecute(ACommand: Integer); override; function DoOnClick(ACommand: Integer): Boolean; override; function DoOnPopup: Boolean; override; function IsValidCommand(ACommand: Integer): Boolean; override; property DayView: TcxSchedulerDayView read GetDayView; public constructor Create(AScheduler: TcxCustomScheduler); override; procedure Assign(Source: TPersistent); override; procedure Execute(AItem: TcxSchedulerTimeRulerPopupMenuItem); function GetMenuItem(AItem: TcxSchedulerTimeRulerPopupMenuItem): TMenuItem; published property Items: TcxSchedulerTimeRulerPopupMenuItems read FItems write FItems default [rpmiNewEvent, rpmiNewAllDayEvent, rpmiNewReccuringEvent, rpmi60min, rpmi30min, rpmi15min, rpmi10min, rpmi6min, rpmi5min]; property PopupMenu; property UseBuiltInPopupMenu; property OnClick: TcxSchedulerTimeRulerPopupMenuClickEvent read FOnClick write FOnClick; property OnPopup: TcxSchedulerTimeRulerPopupMenuPopupEvent read FOnPopup write FOnPopup; end; implementation uses cxDateUtils, cxClasses, cxLibraryConsts; const RulerScales: array[0..5] of Integer = (60, 30, 15, 10, 6, 5); function GetTimeMinutes(const ATime: TDateTime): Integer; var H, M, S, MS: Word; begin DecodeTime(ATime, H, M, S, MS); Result := H * 60 + M; end; { TcxSchedulerDayViewStyles } constructor TcxSchedulerDayViewStyles.Create(AOwner: TPersistent); begin inherited Create(AOwner); FScheduler := TcxSchedulerDayView(GetOwner).Scheduler; end; procedure TcxSchedulerDayViewStyles.Assign(Source: TPersistent); var I: Integer; begin if Source is TcxSchedulerDayViewStyles then begin for I := 0 to cxcsMaxDayViewValue do SetValue(I, TcxSchedulerDayViewStyles(Source).GetValue(I)) end; inherited Assign(Source); end; procedure TcxSchedulerDayViewStyles.Changed(AIndex: Integer); begin TcxSchedulerDayView(GetOwner).Refresh; end; procedure TcxSchedulerDayViewStyles.GetDefaultViewParams(Index: Integer; AData: TObject; out AParams: TcxViewParams); begin AParams.Bitmap := nil; AParams.Font := Scheduler.Font; AParams.TextColor := clBlack; AParams.Color := Scheduler.Color; case Index of cxcsHeaderContainer: begin AParams.Color := Painter.DefaultHeaderBackgroundColor; AParams.TextColor := Painter.DefaultHeaderBackgroundTextColor; end; cxcsSelectedHeaderContainer: begin AParams.Color := Painter.DefaultContentColor; AParams.TextColor := Painter.DefaultContentTextColor; end; cxcsTimeLine: begin AParams.Color := clWhite; AParams.TextColor := clBtnText; end; cxcsTimeRuler: begin AParams.Color := Painter.DefaultSchedulerControlColor; AParams.TextColor := Painter.DefaultHeaderTextColor; end; end; end; function TcxSchedulerDayViewStyles.GetHeaderContainerParams( const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem; ASelected: Boolean): TcxViewParams; begin GetDefaultViewParams(cxcsHeaderContainer + Byte(ASelected), nil, Result); CombineParamsWithStyle(GetValue(cxcsHeaderContainer + Byte(ASelected)), [], Result); end; function TcxSchedulerDayViewStyles.GetTimeLineParams: TcxViewParams; begin GetDefaultViewParams(cxcsTimeLine, nil, Result); CombineParamsWithStyle(TimeLine, [], Result); Result.TextColor := Scheduler.OptionsView.DayBorderColor; if Result.TextColor = clDefault then Result.TextColor := clWindowText; end; function TcxSchedulerDayViewStyles.GetTimeRulerParams: TcxViewParams; begin GetDefaultViewParams(cxcsTimeRuler, nil, Result); CombineParamsWithStyle(TimeRuler, [], Result); end; function TcxSchedulerDayViewStyles.GetPainter: TcxCustomLookAndFeelPainterClass; begin Result := TcxSchedulerDayView(GetOwner).LookAndFeelPainter; end; //procedures function cxCompareTime(const ATime1, ATime2: TDateTime): Integer; begin Result := 0; if ATime1 < ATime2 then Result := -1 else if ATime1 > ATime2 then Result := 1; end; function cxCompareButtons(AItem1, AItem2: TcxSchedulerMoreEventsButtonViewInfo): Integer; begin Result := Byte(AItem1 <> nil) - Byte(AItem2 <> nil); if Result = 0 then Result := Byte(not AItem1.IsDown) - Byte(not AItem2.IsDown); if Result = 0 then begin if AItem1.IsDown then Result := cxCompareTime(AItem1.DateTime, AItem2.DateTime) else Result := cxCompareTime(AItem2.DateTime, AItem1.DateTime) end; end; function cxCompareEventViewInfoOrders( AInfo1, AInfo2: TcxSchedulerEventCellViewInfo): Integer; var AAllDay1, AAllDay2: Boolean; AEvent1, AEvent2: TcxSchedulerEvent; begin Result := Byte(AInfo2.Visible) - Byte(AInfo1.Visible); if Result = 0 then Result := Byte(AInfo1.Selected) - Byte(AInfo2.Selected); if Result = 0 then Result := Byte(AInfo2.Hidden) - Byte(AInfo1.Hidden); if Result = 0 then begin AEvent1 := AInfo1.Event; AEvent2 := AInfo2.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 Result := 0; end; end; { TcxEventLayoutInfo } constructor TcxEventLayoutInfo.Create(AEvent: TcxSchedulerControlEvent; const ADate: TDateTime; AScale: Integer); var AFinish: Integer; begin Event := AEvent; AFinish := Round(TimeOf(Event.Finish) / MinuteToTime); StartRow := Round(TimeOf(AEvent.Start) / MinuteToTime) div AScale; StopRow := AFinish div AScale; if (StopRow <> StartRow) and (AFinish mod AScale = 0) then Dec(StopRow); if DateOf(Event.Start) <> DateOf(Event.Finish) then begin if DateOf(ADate) = DateOf(Event.Start) then StopRow := 24 * 60 div AScale - 1 else StartRow := 0; end; IsBreakEvent := (StopRow = 24 * 60 div AScale - 1); end; function TcxEventLayoutInfo.ShadowSize: Integer; begin Result := TcxSchedulerPainterHelper.ShadowSize; end; procedure TcxEventLayoutInfo.CalculateDisplayRect( AWidth, ARowHeight: Integer); begin FDisplayRect := Rect(MulDiv(AWidth, ColStart, ColCount), StartRow * ARowHeight, MulDiv(AWidth, ColEnd, ColCount) - ShadowSize, (StopRow + 1) * ARowHeight + Byte(IsBreakEvent)); end; procedure TcxEventLayoutInfo.CalculateTimes( const ADate: TDateTime; AScale: Integer); begin FFinishTime := ADate + (StopRow + 1) * AScale * MinuteToTime; FStartTime := ADate + StartRow * AScale * MinuteToTime; end; { TcxCalculateEventLayout } procedure TcxCalculateEventLayout.Add(AEvent: TcxSchedulerControlEvent); var AEventInfo: TcxEventLayoutInfo; begin AEventInfo := CreateEventInfo(AEvent); if AEventInfo <> nil then inherited Add(AEventInfo); end; procedure TcxCalculateEventLayout.Calculate; var I: Integer; AInfo: TcxEventLayoutInfo; begin for I := 0 to Count - 1 do begin AInfo := Infos[I]; CalculateColCount(AInfo); CalculateColStart(AInfo, I); SetColCount(AInfo); end; // Find ColEnd for events for I := 0 to Count - 1 do CalculateColEnd(Infos[I]); for I := 0 to Count - 1 do begin AInfo := Infos[I]; AInfo.CalculateDisplayRect(FWidth, FRowHeight); OffsetRect(AInfo.FDisplayRect, Left, Top - Byte(not FViewInfo.HasVisibleBounds)); AInfo.CalculateTimes(FDate, FTimeScale); end; end; procedure TcxCalculateEventLayout.Clear; var I: Integer; begin for I := Count - 1 downto 0 do Infos[I].Free; inherited Clear; end; procedure TcxCalculateEventLayout.SetParams(const ADate: TDateTime; ATimeScale, ARowHeight: Integer; ALeft, ATop, AWidth: Integer); begin FDate := ADate; FTimeScale := ATimeScale; FRowHeight := ARowHeight; FLeft := ALeft; FTop := ATop; FWidth := AWidth; end; procedure TcxCalculateEventLayout.CalculateColCount( AInfo: TcxEventLayoutInfo); var I, J: Integer; begin for I := AInfo.StartRow to AInfo.StopRow do begin AInfo.ColEnd := 0; for J := 0 to Count - 1 do if (I >= Infos[J].StartRow) and (I <= Infos[J].StopRow) then Inc(AInfo.ColEnd); if AInfo.ColCount < AInfo.ColEnd then AInfo.ColCount := AInfo.ColEnd; end; end; procedure TcxCalculateEventLayout.CalculateColEnd( AInfo: TcxEventLayoutInfo); var I: Integer; AEventInfo: TcxEventLayoutInfo; begin AInfo.ColEnd := AInfo.ColCount; for I := 0 to Count - 1 do begin AEventInfo := Infos[I]; if (AEventInfo.ColStart > AInfo.ColStart) and (AEventInfo.ColStart < AInfo.ColEnd) and Intersect(AInfo, AEventInfo) then begin AInfo.ColEnd := AEventInfo.ColStart; if AInfo.ColEnd = AInfo.ColStart + 1 then Break; end; end; end; procedure TcxCalculateEventLayout.CalculateColStart( AInfo: TcxEventLayoutInfo; AIndex: Integer); var I: Integer; begin repeat AInfo.ColEnd := AInfo.ColStart; for I := AIndex - 1 downto 0 do if (Infos[I].ColStart = AInfo.ColStart) and Intersect(Infos[I], AInfo) then begin Inc(AInfo.ColStart); Break; end; until (AInfo.ColStart = AInfo.ColEnd) or (AInfo.ColStart = (AInfo.ColCount - 1)); end; function TcxCalculateEventLayout.CreateEventInfo( AEvent: TcxSchedulerControlEvent): TcxEventLayoutInfo; begin Result := TcxEventLayoutInfo.Create(AEvent, FDate, FTimeScale); with FViewInfo do if HasVisibleBounds and not IsEventVisible(Result.StartRow, Result.StopRow) then FreeAndNil(Result); end; function TcxCalculateEventLayout.Intersect( AInfo1, AInfo2: TcxEventLayoutInfo): Boolean; begin Result := (AInfo1.StartRow <= AInfo2.StopRow) and (AInfo2.StartRow <= AInfo1.StopRow); end; procedure TcxCalculateEventLayout.SetColCount( AInfo: TcxEventLayoutInfo); var I: Integer; begin for I := 0 to Count - 1 do begin if (Infos[I].ColCount < AInfo.ColCount) and Intersect(Infos[I], AInfo) then begin Infos[I].ColCount := AInfo.ColCount; SetColCount(Infos[I]); end; end; end; function TcxCalculateEventLayout.GetInfo( AIndex: Integer): TcxEventLayoutInfo; begin Result := TcxEventLayoutInfo(List^[AIndex]); end; { TcxSchedulerDayView } constructor TcxSchedulerDayView.Create(AOwner: TcxCustomScheduler); begin inherited Create(AOwner); FTimeScale := cxDefaultTimeScale; FEventShadows := True; end; procedure TcxSchedulerDayView.Assign(Source: TPersistent); begin if Source is TcxSchedulerDayView then begin FEventShadows := TcxSchedulerDayView(Source).FEventShadows; FTimeScale := TcxSchedulerDayView(Source).FTimeScale; TimeRulerPopupMenu := TcxSchedulerDayView(Source).TimeRulerPopupMenu; end; inherited Assign(Source); end; procedure TcxSchedulerDayView.MakeWorkTimeVisible; begin if Visible then ViewInfo.FTopIndex := (HourOf(WorkStart) * 60 + MinuteOf(WorkStart)) div TimeScale; end; procedure TcxSchedulerDayView.GetProperties(AProperties: TStrings); begin inherited GetProperties(AProperties); AProperties.Add('TimeScale') end; procedure TcxSchedulerDayView.GetPropertyValue(const AName: string; var AValue: Variant); begin inherited GetPropertyValue(AName, AValue); if AName = 'TimeScale' then AValue := TimeScale; end; procedure TcxSchedulerDayView.SetPropertyValue(const AName: string; const AValue: Variant); begin inherited SetPropertyValue(AName, AValue); if AName = 'TimeScale' then TimeScale := AValue; end; procedure TcxSchedulerDayView.CreateSubClasses; begin FStyles := CreateStyles; inherited CreateSubClasses; FTimeRulerPopupMenu := CreateTimeRulerPopupMenu; end; procedure TcxSchedulerDayView.DestroySubClasses; begin FTimeRulerPopupMenu.Free; inherited DestroySubClasses; FStyles.Free; end; function TcxSchedulerDayView.CreateController: TcxSchedulerSubControlController; begin Result := TcxSchedulerDayViewController.Create(Self); end; function TcxSchedulerDayView.CreateHitTest: TcxSchedulerSubControlHitTest; begin Result := TcxSchedulerDayViewHitTest.Create(Self); end; function TcxSchedulerDayView.CreatePainter: TcxSchedulerSubControlPainter; begin Result := TcxSchedulerDayViewPainter.Create(Self); end; function TcxSchedulerDayView.CreateStyles: TcxSchedulerDayViewStyles; begin Result := TcxSchedulerDayViewStyles.Create(Self); end; function TcxSchedulerDayView.CreateTimeRulerPopupMenu: TcxSchedulerTimeRulerPopupMenu; begin Result := TcxSchedulerTimeRulerPopupMenu.Create(Scheduler); end; function TcxSchedulerDayView.CreateViewAdapter: TcxCustomResourceViewAdapter; begin Result := TcxSchedulerDayViewAdapter.Create(Self); end; function TcxSchedulerDayView.CreateViewInfo: TcxSchedulerSubControlViewInfo; begin Result := TcxSchedulerDayViewViewInfo.Create(Self); end; procedure TcxSchedulerDayView.DoCustomDrawContainer( ACell: TcxSchedulerContainerCellViewInfo; var ADone: Boolean); begin if Assigned(FOnCustomDrawContainer) then FOnCustomDrawContainer(Self, Canvas, ACell, ADone); end; procedure TcxSchedulerDayView.DoCustomDrawTimeRuler( ACell: TcxSchedulerTimeRulerCellViewInfo; var ADone: Boolean); begin if Assigned(FOnCustomDrawTimeRuler) then FOnCustomDrawTimeRuler(Self, Canvas, ACell, ADone); end; function TcxSchedulerDayView.DoShowPopupMenu(X, Y: Integer): Boolean; begin if HitTest.HitAtTimeRuler then Result := TimeRulerPopupMenu.Popup(X, Y) else Result := inherited DoShowPopupMenu(X, Y); end; function TcxSchedulerDayView.EventContentSelected( AEvent: TcxSchedulerControlEvent): Boolean; begin Result := AEvent.AllDayEvent or (AEvent.Duration >= 1); end; function TcxSchedulerDayView.GetTimeIncrement: TDateTime; begin Result := TimeOf(TimeScale * MinuteToTime); end; function TcxSchedulerDayView.IsDayView: Boolean; begin Result := True; end; procedure TcxSchedulerDayView.MakeEventVisible(AEvent: TcxSchedulerControlEvent; const ADate: TDateTime; AResource: TcxSchedulerStorageResourceItem); var I, DH: Integer; R, R1: TRect; AViewInfo: TcxSchedulerEventCellViewInfo; begin // if Event date out of bounds then need scroll if Visible and AEvent.AllDayEvent or (AEvent.Duration >= 1) then Exit; for I := 0 to 1 do begin if FindEventViewInfo(AEvent, ADate, AResource, AViewInfo) and not AViewInfo.Hidden then begin if not AViewInfo.Visible then DH := ViewInfo.GetTimeRow(AViewInfo.ContentStart, True) else begin DH := 0; R := AViewInfo.Bounds; R1 := AViewInfo.ClipRect; if cxRectIsEqual(R, R1) then Exit; if R.Top < R1.Top then DH := (R.Top - R1.Top) div ViewInfo.FContentLineHeight else if (I = 0) and (R.Bottom > R1.Bottom) then DH := (R.Bottom - R1.Bottom) div ViewInfo.FContentLineHeight; Inc(DH, ViewInfo.FTopIndex); end; if ViewInfo.FTopIndex <> DH then begin ViewInfo.FTopIndex := DH; LayoutChanged; end; end; end; end; procedure TcxSchedulerDayView.Notification(AComponent: TComponent; Operation: TOperation); begin if (Operation = opRemove) and (AComponent = TimeRulerPopupMenu.PopupMenu) then TimeRulerPopupMenu.PopupMenu := nil; end; procedure TcxSchedulerDayView.ScrollVisibleDays(AScrollUp: Boolean); begin ScrollSelectedDays(Byte(AScrollUp) * 2 - 1); end; procedure TcxSchedulerDayView.TimeChanged; begin Invalidate; end; procedure TcxSchedulerDayView.VisibleChanged; begin MakeWorkTimeVisible; inherited VisibleChanged; end; function TcxSchedulerDayView.GetHitTest: TcxSchedulerDayViewHitTest; begin Result := TcxSchedulerDayViewHitTest(inherited HitTest); end; function TcxSchedulerDayView.GetViewInfo: TcxSchedulerDayViewViewInfo; begin Result := TcxSchedulerDayViewViewInfo(inherited ViewInfo) end; procedure TcxSchedulerDayView.SetAutoContentHeight(AValue: Boolean); begin if AValue <> FAutoContentHeight then begin FAutoContentHeight := AValue; Changed; end; end; procedure TcxSchedulerDayView.SetEventShadows(AValue: Boolean); begin if AValue <> FEventShadows then begin FEventShadows := AValue; Changed; end; end; procedure TcxSchedulerDayView.SetStyles(AValue: TcxSchedulerDayViewStyles); begin FStyles.Assign(AValue); end; procedure TcxSchedulerDayView.SetTimeRulerPopupMenu( AValue: TcxSchedulerTimeRulerPopupMenu); begin FTimeRulerPopupMenu.Assign(AValue); end; procedure TcxSchedulerDayView.SetTimeScale( AValue: Integer); begin AValue := Min(60, Max(5, AValue)); AValue := 60 div Max(1, 60 div AValue); if AValue <> FTimeScale then begin FTimeScale := AValue; MakeWorkTimeVisible; Refresh; end; end; { TcxSchedulerDayViewAdapter } procedure TcxSchedulerDayViewAdapter.Store; begin FTopIndex := TcxSchedulerDayViewViewInfo(ViewInfo).FTopIndex; end; procedure TcxSchedulerDayViewAdapter.Restore; begin TcxSchedulerDayViewViewInfo(ViewInfo).FTopIndex := FTopIndex; end; { TcxSchedulerDayViewViewInfo } constructor TcxSchedulerDayViewViewInfo.Create( AOwner: TcxSchedulerSubControl); begin inherited Create(AOwner); FLargeFont := TFont.Create; FTimeRulerCells := TcxSchedulerViewInfoCellList.Create; FCells.Insert(1, FTimeRulerCells); end; destructor TcxSchedulerDayViewViewInfo.Destroy; begin FBackground.Free; FLargeFont.Free; inherited Destroy; end; procedure TcxSchedulerDayViewViewInfo.CalculateHitTest( AHitTest: TcxSchedulerCustomResourceViewHitTest); begin inherited CalculateHitTest(AHitTest); TimeRulerCells.CalculateHitTest(AHitTest); end; procedure TcxSchedulerDayViewViewInfo.InitScrollBarsParameters; begin if (FVisibleRowCount = 0) or (FVisibleRowCount >= FRowCount) or (cxRectWidth(Bounds) <= 0) then DayView.SetScrollBarInfo(sbVertical, 0, 2, 1, 1, 0, False, True) else DayView.SetScrollBarInfo(sbVertical, 0, FRowCount - 2, 1, FVisibleRowCount, TopIndex, True, True); end; procedure TcxSchedulerDayViewViewInfo.ScrollVertical( AScrollCode: TScrollCode; var AScrollPos: Integer); begin if not (AScrollCode in [scPosition, scTrack]) then AScrollPos := TopIndex; case AScrollCode of scLineUp: Dec(AScrollPos, 1); scLineDown: Inc(AScrollPos, 1); scPageUp: Dec(AScrollPos, VisibleRowCount); scPageDown: Inc(AScrollPos, VisibleRowCount); scTop: AScrollPos := 0; scBottom: AScrollPos := FRowCount; end; if AScrollPos + VisibleRowCount >= (FRowCount - 1) then AScrollPos := FRowCount - VisibleRowCount - 1; if AScrollPos < 0 then AScrollPos := 0; if FTopIndex <> AScrollPos then begin FTopIndex := AScrollPos; DayView.LayoutChanged; AScrollPos := FTopIndex; end; end; function TcxSchedulerDayViewViewInfo.AddContentCell( const ARect: TRect; const AStart, AFinish: TDateTime; AResourceIndex: Integer): TcxSchedulerContentCellViewInfo; var R: TRect; P: TcxViewParams; begin R := Bounds; R.Top := FContentOffset; if cxRectIntersect(R, ARect) then P := GetContentParams(AStart, Resources[AResourceIndex]) else FillChar(P, SizeOf(P), 0); CreateCellInstance(ContentCellClass, ARect, R, P, Result); Result.SetTime(AStart, AFinish); AssignResourceID(Result, AResourceIndex); ContentCells.Add(Result); end; procedure TcxSchedulerDayViewViewInfo.AddContainerCell( AColumn: Integer; const ABounds: TRect); var ACell: TcxSchedulerContainerCellViewInfo; AParams: TcxViewParams; ASelected: Boolean; AResource: TcxSchedulerStorageResourceItem; ADate: TDateTime; begin ADate := GetColumnDate(AColumn); AResource := GetResourceItemByIndex(GetColumnResourceIndex(AColumn)); ASelected := IsContainerSelected(AResource, ADate); AParams := DayView.Styles.GetHeaderContainerParams(ADate, AResource, ASelected); CreateCellInstance(TcxSchedulerContainerCellViewInfo, ABounds, AParams, ACell); ACell.DateTime := ADate; ACell.Selected := ASelected; AssignResourceID(ACell, GetColumnResourceIndex(AColumn)); Inc(AColumn); if (AColumn = FColCount) or (HasSeparator and (GroupingKind <> gkNone) and (AColumn mod ColumnInGroup = 0)) then ACell.Borders := [bBottom] else ACell.Borders := [bBottom, bRight]; if HasVisibleBounds and (AColumn = FColCount) then ACell.Borders := [bBottom, bRight]; FHeaderContainerCells.Add(ACell); end; procedure TcxSchedulerDayViewViewInfo.AddHeaderContainerEvent( AEvent: TcxSchedulerControlEvent; AContainer: TcxSchedulerContainerCellViewInfo; AColIndex: Integer); var AHeight, I, J, ATop, ALine: Integer; ABounds: TRect; ACell: TcxSchedulerEventCellViewInfo; ANextContainer: TcxSchedulerContainerCellViewInfo; begin ANextContainer := AContainer; ALine := AContainer.LineCount + 1; J := AColIndex; for I := AColIndex + 1 to ContainerCount - 1 do if IsColumnEvent(AEvent, I, True) and (AContainer.Resource = GetColumnResource(I)) then begin J := I; ANextContainer := Containers[I]; ANextContainer.LineCount := ALine; end else Break; AHeight := FHeaderLineHeight + cxTextOffset; ATop := Bounds.Top + DayHeaderHeight + FResourceHeaderHeight * Byte(GroupingKind <> gkNone); ABounds := Rect(AContainer.Bounds.Left + cxTextOffset * 2, ATop + cxTextOffset + AContainer.LineCount * AHeight, ANextContainer.Bounds.Right - cxTextOffset * 2 - Byte(bRight in ANextContainer.Borders), ATop + (AContainer.LineCount + 1) * AHeight ); AContainer.LineCount := ALine; ACell := AddEventCell(CreateHeaderEventViewData(AEvent, ABounds, AContainer.DateTime, ANextContainer.DateTime + 1, AContainer.Resource)); if not (AEvent.AllDayEvent and AEvent.IsClone) then for I := AColIndex to J do SetColumnTimeLineStyle(ACell, I); end; procedure TcxSchedulerDayViewViewInfo.AddMoreEventsButton( const AIndex, ARowIndex: Integer; AIsTop: Boolean); var R: TRect; begin R := Bounds; R.Top := FContentOffset; R.Right := FHeaderOffsetLeft; AddButton(R, ARowIndex / FRowCount, AIndex, not AIsTop) end; procedure TcxSchedulerDayViewViewInfo.CalculateBackground; procedure CreateBackgroundCell(const ABounds: TRect); begin if ABounds.Top < ABounds.Bottom then begin CreateCellInstance(TcxSchedulerBackgroundCellViewInfo, ABounds, Styles.GetBackgroundParams, FBackground); FBackground.Borders := [bTop]; end; end; procedure CreateBackgroundCellSlots(const ABounds: TRect); var R: TRect; AEventIndex, I, J, K: Integer; AEvent: TcxSchedulerControlEvent; ASlot: TcxSchedulerBackgroundSlotCellViewInfo; const ABorders: array[Boolean] of TcxBorders = ([bRight, bTop], [bTop]); begin if ABounds.Top >= ABounds.Bottom then Exit; TcxSchedulerTimeRulerCellViewInfo( TimeRulerCells[TimeRulerCells.Count - 1]).SetBottom(ABounds.Top); for J := -1 to ColCount - 1 do begin for I := 0 to UnusedRowCount - 1 do begin R := cxRectSetTop(ABounds, ABounds.Top + I * FContentLineHeight, FContentLineHeight); if J = -1 then R.Right := FHeaderOffsetLeft else with GetContainer(J) do R := cxRectSetLeft(R, Bounds.Left, cxRectWidth(Bounds)); if J = ColCount - 1 then Dec(R.Right); ASlot := AddBackgroundSlot(R, ABorders[J = ColCount - 1], IntToStr(I)); if J >= 0 then begin AEventIndex := 0; for K := 0 to Events.Count - 1 do begin AEvent := Events[K]; if IsColumnEvent(AEvent, J, False) and not IsEventVisible(AEvent) then begin if AEventIndex = I then begin ASlot.DisplayText := GetEventSlotDisplayText(AEvent); Break; end; Inc(AEventIndex); end; end; end; end; end; end; var R: TRect; begin FreeAndNil(FBackground); if AutoHeight and not HasVisibleBounds then Exit; R := Bounds; if HasVisibleBounds then begin R.Top := FContentOffset + (PrintFinishRow - PrintStartRow + 1) * FContentLineHeight; CreateBackgroundCellSlots(R); end else begin R.Top := FContentOffset + FRowCount * FContentLineHeight; CreateBackgroundCell(R); end; end; procedure TcxSchedulerDayViewViewInfo.CalculateContent; var I, J: Integer; ACell: TcxSchedulerContentCellViewInfo; AColor: TColor; ARect, ABounds: TRect; AIndex: Integer; AResource: TcxSchedulerStorageResourceItem; begin ABounds := Bounds; ABounds.TopLeft := Point(FHeaderOffsetLeft, FContentOffset); for I := 0 to FColCount - 1 do begin AIndex := GetColumnResourceIndex(I); AResource := GetResourceItemByIndex(AIndex); AColor := StylesAdapter.GetContentParams(GetColumnDate(I), True, AResource).Color; ARect := cxRectSetTop(Containers[I].Bounds, ABounds.Top - TopIndex * ContentLineHeight, ContentLineHeight); if not HasVisibleBounds then begin if (ColumnInGroup > 1) or ((ColumnInGroup = 1) and (DayView.OptionsView.GroupSeparatorWidth = 0)) then begin if (I + 1) mod ColumnInGroup <> 0 then Dec(ARect.Right, 1); if ((I mod ColumnInGroup > 0) or not HasSeparator) then Dec(ARect.Left); end; end; for J := 0 to FRowCount - 1 do begin if IsRowVisible(J) then begin ACell := AddContentCell(ARect, GetRowTime(I, J), GetRowTime(I, J + 1), AIndex); ACell.Borders := []; if I = 0 then ACell.TimeLineBorders := [bRight]; if HasSeparator and (I mod ColumnInGroup = 0) then ACell.TimeLineBorders := ACell.TimeLineBorders * LookAndFeelPainter.HeaderBorders([nLeft]); ACell.ShowTimeLine := True; if HasVisibleBounds and (I < (FColCount - 1)) then ACell.Borders := [bRight]; if not HasVisibleBounds or (J <> PrintFinishRow) then ACell.Borders := ACell.Borders + [bBottom]; ACell.BorderColor := PainterHelper.GetSeparatorColor( AColor, (J + 1) mod LinePerHour = 0, DayView.IsWorkTime(AResource, ACell.TimeStart)); ACell.TimeLineParams := DayView.Styles.GetTimeLineParams; end; OffsetRect(ARect, 0, FContentLineHeight); end; end; end; procedure TcxSchedulerDayViewViewInfo.CalculateEvents; var I: Integer; AList: TcxSchedulerEventList; AContainer: TcxSchedulerContainerCellViewInfo; begin AList := TcxSchedulerEventList.Create; try for I := 0 to ContainerCount - 1 do begin AContainer := Containers[I]; // for source events AList.Clear; ExtractEvents(Events, AList, I); CalculateEventsForColumn(I, AContainer, AList); // for clones AList.Clear; ExtractEvents(Events.Clones, AList, I); CalculateEventsForColumn(I, AContainer, AList); end; finally AList.Free; end; end; procedure TcxSchedulerDayViewViewInfo.CalculateEventsForColumn(AIndex: Integer; AContainer: TcxSchedulerContainerCellViewInfo; AEvents: TcxSchedulerEventList); var I: Integer; AViewData: TcxSchedulerEventViewData; AInfo: TcxEventLayoutInfo; begin if AEvents.Count = 0 then Exit; FEventLayout.Clear; I := Byte(((AIndex mod ColumnInGroup <> 0) or not HasSeparator) and not (ColCount = 1)); FEventLayout.SetParams(DateOf(AContainer.DateTime), TimeScale, FContentLineHeight, AContainer.Bounds.Left - I, FContentOffset - TopIndex * FContentLineHeight, cxRectWidth(AContainer.Bounds)); for I := 0 to AEvents.Count - 1 do FEventLayout.Add(TcxSchedulerControlEvent(AEvents[I])); FEventLayout.Calculate; for I := 0 to FEventLayout.Count - 1 do begin AInfo := FEventLayout.Infos[I]; CheckEventRowsVisibility(AInfo.Event, AInfo.StartRow, AInfo.StopRow + 1); AViewData := CreateContentEventViewData(AInfo, AContainer.Resource); if HasVisibleBounds and (FColCount > 1) then if (AIndex mod ColumnInGroup > 0) or ((ColumnInGroup = 1) and (DayView.OptionsView.GroupSeparatorWidth = 0)) then OffsetRect(AViewData.Bounds, 1, 0); AViewData.DrawShadows := DayView.EventShadows; AddEventCell(AViewData); end; end; procedure TcxSchedulerDayViewViewInfo.CalculateHeaderEvents; var I, J: Integer; begin for I := 0 to ContainerCount - 1 do for J := 0 to Events.AbsoluteCount - 1 do begin if IsColumnEvent(Events.AbsoluteItems[J], I, True) and ((I = 0) or (GetColumnResourceIndex(I) <> GetColumnResourceIndex(I - 1)) or not IsColumnEvent(Events.AbsoluteItems[J], I - 1, True)) then AddHeaderContainerEvent(Events.AbsoluteItems[J], Containers[I], I); end; end; procedure TcxSchedulerDayViewViewInfo.CalculateHeaderLineCount; var I, J, ALineCount, ANextLineCount: Integer; AEvent: TcxSchedulerControlEvent; begin FHeaderLineCount := 1; ANextLineCount := 0; for I := 0 to FColCount - 1 do begin ALineCount := ANextLineCount; ANextLineCount := 0; for J := 0 to Events.AbsoluteCount - 1 do begin AEvent := Events.AbsoluteItems[J]; if IsColumnEvent(AEvent, I, True) then begin if FHideClones and AEvent.IsClone then Continue else begin if (I = 0) or not IsColumnEvent(AEvent, I - 1, True) then Inc(ALineCount); if (I < (FColCount - 1)) and IsColumnEvent(AEvent, I + 1, True) then ANextLineCount := ALineCount; end; end; end; FHeaderLineCount := Max(FHeaderLineCount, ALineCount); end; end; procedure TcxSchedulerDayViewViewInfo.CalculateHeaders; var I, J, W: Integer; AHeaderBounds, AGroupBounds: TRect; const ANeighbors: array[TcxSchedulerGroupingKind, 0..1] of TcxNeighbors = (([], []), ([], []), ([nTop], []), ([], [nTop])); begin AGroupBounds := cxRectSetHeight(Bounds, Byte(GroupByResource) * FResourceHeaderHeight + Byte(GroupByDate) * DayHeaderHeight); AHeaderBounds := cxRectSetTop(Bounds, AGroupBounds.Bottom, Byte(GroupByDate) * FResourceHeaderHeight + Byte(not GroupByDate) * DayHeaderHeight); W := Bounds.Right - FHeaderOffsetLeft - (GroupCount - 1) * SeparatorWidth; for I := 0 to GroupCount - 1 do begin AGroupBounds.Left := MulDiv(W, I, GroupCount) + FHeaderOffsetLeft + SeparatorWidth * I; AGroupBounds.Right := MulDiv(W, I + 1, GroupCount) + FHeaderOffsetLeft + SeparatorWidth * I; for J := 0 to ColumnInGroup - 1 do begin AHeaderBounds.Left := AGroupBounds.Left + MulDiv(cxRectWidth(AGroupBounds), J, ColumnInGroup); AHeaderBounds.Right := AGroupBounds.Left + MulDiv(cxRectWidth(AGroupBounds), J + 1, ColumnInGroup); if GroupByDate then AddResourceHeader(J, AHeaderBounds).DateTime := GetColumnDate(I * ColumnInGroup + J) else AddDayHeader(GetColumnDate(I * ColumnInGroup + J), AHeaderBounds, GetColumnResourceIndex(I * ColumnInGroup + J)); AddContainerCell(I * ColumnInGroup + J, cxRectSetTop(AHeaderBounds, Bounds.Top, FContentOffset - Bounds.Top)); end; if GroupByResource then AddResourceHeader(I, AGroupBounds) else if GroupByDate then AddDayHeader(Days[I], AGroupBounds, -1); if HasSeparator then AddGroupVertSeparator(AGroupBounds.Right); end; ProcessCheckBorders(ResourceHeaderCells, False, ANeighbors[GroupingKind, 0]); ProcessDateToDisplayText(True); ProcessCheckBorders(DayHeaderCells, False, ANeighbors[GroupingKind, 1]); end; procedure TcxSchedulerDayViewViewInfo.CalculateMetrics; function GetExtraContentOffset: Integer; begin Result := FHeaderLineCount * (FContentLineHeight + cxTextOffset) + 1; if AutoHeight or (FVisibleRowCount < FRowCount + FHeaderLineCount) then Inc(Result, ContentHeight - FVisibleRowCount * FContentLineHeight); end; begin inherited CalculateMetrics; FHeaderLineHeight := FContentLineHeight; FAdditionalTimeZone := -1; FCurrentTimeZone := DayView.OptionsView.CurrentTimeZone; if FCurrentTimeZone = -1 then FCurrentTimeZone := DayView.DateTimeHelper.CurrentTimeZone; if DayView.OptionsView.ShowAdditionalTimeZone then begin FAdditionalTimeZone := DayView.OptionsView.AdditionalTimeZone; if FAdditionalTimeZone = -1 then FAdditionalTimeZone := DayView.DateTimeHelper.CurrentTimeZone; end; FColCount := DayCount; if GroupingKind <> gkNone then FColCount := FColCount * ResourceCount; CalculateHeaderLineCount; LargeFont := GetTimeRulerParams.Font; CalculateHeaderLineCount; if not HasVisibleBounds then begin FTimeScale := DayView.TimeScale; FRowCount := 24 * 60 div TimeScale; FContentOffset := DayHeaderHeight + cxTextOffset + Byte(GroupingKind <> gkNone) * FResourceHeaderHeight; end else CalculateMetricsForPrinting; FVisibleRowCount := Max(1, ContentHeight div FContentLineHeight); if HasVisibleBounds then Exit; if AutoHeight and (FVisibleRowCount > (FRowCount + FHeaderLineCount)) then begin FContentLineHeight := ContentHeight div (FRowCount + FHeaderLineCount); FVisibleRowCount := FRowCount + FHeaderLineCount; end; Inc(FContentOffset, GetExtraContentOffset); FVisibleRowCount := Min(FRowCount, Max(1, ContentHeight div FContentLineHeight)); while (FTopIndex > 0) and ((FTopIndex + FVisibleRowCount) > (FRowCount - 1)) do Dec(FTopIndex); end; procedure TcxSchedulerDayViewViewInfo.CalculateMetricsForPrinting; var AContentHeight: Integer; HeightAdjusted: Boolean; begin FContentOffset := Byte(GroupingKind <> gkNone) * FResourceHeaderHeight * Byte(ResourceCount >= 1) + FHeaderLineCount * (FHeaderLineHeight + cxTextOffset) + cxTextOffset; if (GroupingKind = gkByResource) or (SelectedDays.Count > 1) then Inc(FContentOffset, DayHeaderHeight); CalculateUnusedRowCount; FTimeScale := DayView.TimeScale; AContentHeight := Bounds.Bottom - Bounds.Top - FContentOffset; HeightAdjusted := AContentHeight < FContentLineHeight; while not HeightAdjusted do begin CalculatePrintRows; FTopIndex := PrintStartRow; HeightAdjusted := AContentHeight >= FContentLineHeight * PrintRowCount; if not HeightAdjusted then begin if FTimeScale < 60 then FTimeScale := FTimeScale * 2 else if UnusedRowCount > 0 then Dec(FUnusedRowCount) else Break; end; end; CalculatePrintRows; if HeightAdjusted then begin FContentLineHeight := AContentHeight div PrintRowCount; Inc(FContentOffset, AContentHeight - FContentLineHeight * PrintRowCount); end; end; procedure TcxSchedulerDayViewViewInfo.CalculatePrintRows; function GetTimeRow(ATime: TDateTime; IsFinish: Boolean): Integer; begin Result := HourOf(ATime) * 60 + MinuteOf(ATime); if IsFinish and (Result mod FTimeScale <> 0) then Result := Result div FTimeScale + 1 else Result := Result div FTimeScale - Byte(IsFinish); end; begin FRowCount := 24 * 60 div FTimeScale; FPrintStartRow := GetTimeRow(PrintFrom, False); FPrintFinishRow := GetTimeRow(PrintTo, True); end; procedure TcxSchedulerDayViewViewInfo.CalculateTimeLine; var ABounds, R: TRect; I: Integer; AViewParams: TcxViewParams; ACommonCell, ARulerCell: TcxSchedulerTimeRulerCellViewInfo; begin R := cxRectSetTop(Bounds, FContentOffset); AViewParams := GetTimeRulerParams; FHeaderOffsetLeft := R.Left + TcxSchedulerTimeRulerCellViewInfo.CalculateWidth( 1 + Byte(FAdditionalTimeZone >= 0), LinePerHour, AViewParams.Font, LargeFont); R.Right := FHeaderOffsetLeft; // add common area CreateCellInstance(TcxSchedulerTimeRulerCellViewInfo, cxRectSetTop(R, 0, R.Top), AViewParams, ACommonCell); ACommonCell.Calculate(DayView.OptionsView.CurrentTimeZoneLabel, DayView.OptionsView.AdditionalTimeZoneLabel, FCurrentTimeZone, FAdditionalTimeZone); // add ruler cells R := cxRectSetTop(R, R.Top - TopIndex * FContentLineHeight, LinePerHour * FContentLineHeight); ABounds := Bounds; ABounds.Top := FContentOffset; FTimeRulerCells.Add(ACommonCell); for I := 0 to 23 do begin if IsHourVisible(I) then begin CreateCellInstance(TcxSchedulerTimeRulerCellViewInfo, R, ABounds, AViewParams, ARulerCell); ARulerCell.Calculate(I, LinePerHour, FCurrentTimeZone, FAdditionalTimeZone, LargeFont); FTimeRulerCells.Add(ARulerCell); end; R := cxRectSetTop(R, R.Bottom); end; end; procedure TcxSchedulerDayViewViewInfo.CalculateUnusedRowCount; var I, J: Integer; AEvent: TcxSchedulerEvent; AColRowCount: Integer; begin FUnusedRowCount := 3; for I := 0 to ColCount - 1 do begin AColRowCount := 0; for J := 0 to Events.Count - 1 do begin AEvent := Events[J]; if IsColumnEvent(AEvent, I, False) and not IsEventVisible(AEvent) then Inc(AColRowCount); end; FUnusedRowCount := Max(FUnusedRowCount, AColRowCount); end; end; procedure TcxSchedulerDayViewViewInfo.Clear; begin inherited Clear; FTimeRulerCells.Clear; end; function TcxSchedulerDayViewViewInfo.CheckDisplayRows( var AStartRow, AFinishRow: Integer): Boolean; begin Result := not HasVisibleBounds or ((AStartRow <= PrintFinishRow) and (PrintStartRow <= AFinishRow)); if Result then begin AStartRow := Max(AStartRow, PrintStartRow); AFinishRow := Min(AFinishRow, PrintFinishRow); end; end; procedure TcxSchedulerDayViewViewInfo.CheckEventRowsVisibility( AEvent: TcxSchedulerControlEvent; AStartRow, AFinishRow: Integer); begin if AStartRow < FTopIndex then AddMoreEventsButton(-1, AStartRow, True); if (AFinishRow > (FTopIndex + VisibleRowCount)) then begin if AFinishRow < FRowCount then AddMoreEventsButton(-1, AFinishRow, False) else if AStartRow > (FTopIndex + VisibleRowCount) then AddMoreEventsButton(-1, AStartRow, False); end; end; procedure TcxSchedulerDayViewViewInfo.DoCalculate; begin if HasVisibleBounds then Inc(FBounds.Right); FEventLayout := CreateEventLayout; inherited DoCalculate; with DayView.Scheduler do begin FIsContainerSelected := (GetTimeMinutes(SelFinish) = 0) and (GetTimeMinutes(SelStart) = 0); end; try CalculateTimeLine; CalculateHeaders; CalculateContent; CalculateEvents; CalculateHeaderEvents; CalculateBackground; finally FEventLayout.Free; FButtons.Sort(TListSortCompare(@cxCompareButtons)); FEventCells.Sort(TListSortCompare(@cxCompareEventViewInfoOrders)); end; end; function TcxSchedulerDayViewViewInfo.CreateContentEventViewData( AEventInfo: TcxEventLayoutInfo; AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData; begin Result := CreateEventViewData(AEventInfo.Event, AEventInfo.DisplayRect, AEventInfo.Start, AEventInfo.Finish, AResource); Result.VisibleRect.TopLeft := Point(FHeaderOffsetLeft, FContentOffset); Result.ShowTimeLine := True; end; function TcxSchedulerDayViewViewInfo.CreateHeaderEventViewData( AEvent: TcxSchedulerControlEvent; const ABounds: TRect; const AStart, AFinish: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxSchedulerEventViewData; begin Result := CreateEventViewData(AEvent, ABounds, AStart, AFinish, AResource); Result.VisibleRect := cxRect(FHeaderOffsetLeft, DayHeaderHeight, Bounds.Right, FContentOffset); Result.ShowTimeLine := False; end; function TcxSchedulerDayViewViewInfo.CreateEventLayout: TcxCalculateEventLayout; begin Result := TcxCalculateEventLayout.Create; Result.FViewInfo := Self; end; procedure TcxSchedulerDayViewViewInfo.ExtractEvents( ASource, ADest: TcxSchedulerEventList; AIndex: Integer); var I: Integer; begin for I := 0 to ASource.Count - 1 do if IsColumnEvent(ASource[I], AIndex, False) then ADest.Add(ASource[I]); end; function TcxSchedulerDayViewViewInfo.GetContentParams(const ATime: TDateTime; AResource: TcxSchedulerResourceViewInfo): TcxViewParams; begin Result := inherited GetContentParams(ATime, AResource); if not HiddenSelection and not FIsContainerSelected and IsTimeSelected(ATime, AResource) then Result := GetSelectionParams(Result); end; function TcxSchedulerDayViewViewInfo.GetColumnDate( AIndex: Integer): TDateTime; begin if GroupingKind = gkByDate then AIndex := AIndex div ResourceCount else if GroupingKind = gkByResource then AIndex := AIndex mod DayCount; Result := Days[AIndex]; end; function TcxSchedulerDayViewViewInfo.GetColumnResource( AIndex: Integer): TcxSchedulerResourceViewInfo; begin Result := Resources[GetColumnResourceIndex(AIndex)]; end; function TcxSchedulerDayViewViewInfo.GetColumnResourceIndex( AIndex: Integer): Integer; begin Result := -1; if ResourceCount > 0 then begin if GroupingKind = gkByDate then Result := AIndex mod ResourceCount else if GroupingKind = gkByResource then Result := AIndex div DayCount; end; end; function TcxSchedulerDayViewViewInfo.GetContainer( AIndex: Integer): TcxSchedulerContainerCellViewInfo; begin Result := TcxSchedulerContainerCellViewInfo(HeaderContainerCells[AIndex]); end; function TcxSchedulerDayViewViewInfo.GetContainerCount: Integer; begin Result := HeaderContainerCells.Count; end; function TcxSchedulerDayViewViewInfo.GetDayHeaderHeight: Integer; begin Result := inherited GetDayHeaderHeight; if (SelectedDays.Count = 1) and HasVisibleBounds and (GroupingKind <> gkByResource) then Result := 0; end; function TcxSchedulerDayViewViewInfo.GetEventSlotDisplayText( AEvent: TcxSchedulerControlEvent): string; begin Result := DoGetEventDisplayText(AEvent); with DateTimeHelper do begin Result := TimeToStr(AEvent.Start) + '-' + TimeToStr(AEvent.Finish) + ' ' + Result; end; end; function TcxSchedulerDayViewViewInfo.GetTimeLineParams: TcxViewParams; begin Result := DayView.Styles.GetTimeLineParams; end; function TcxSchedulerDayViewViewInfo.GetTimeRulerParams: TcxViewParams; var AIntf: IcxSchedulerTimeRulerParams; begin if Supports(StylesAdapter, IcxSchedulerTimeRulerParams, AIntf) then Result := AIntf.GetTimeRulerParams else Result := DayView.Styles.GetTimeRulerParams; end; function TcxSchedulerDayViewViewInfo.GetTimeRow( const ATime: TDateTime; AIsStart: Boolean): Integer; var ACount: Double; begin ACount := Min(FRowCount - 1, TimeOf(ATime) / MinuteToTime / TimeScale); Result := Round(ACount); if not AIsStart and (TimeOf(ACount) = 0) then Dec(Result); end; function TcxSchedulerDayViewViewInfo.GetRowTime( AColumn, ARow: Integer): TDateTime; begin Result := GetColumnDate(AColumn) + (ARow * TimeScale) * MinuteToTime; end; function TcxSchedulerDayViewViewInfo.IsColumnEvent(AEvent: TcxSchedulerEvent; AIndex: Integer; IsHeaderEvent: Boolean): Boolean; begin Result := AEvent.IsDayEvent(GetColumnDate(AIndex)) and (IsHeaderEvent = (AEvent.AllDayEvent or (AEvent.Duration >= 1))); if Result then Result := AEvent.IsResourceEvent(GetResourceItemByIndex( GetColumnResourceIndex(AIndex)), ShowEventsWithoutResource); end; function TcxSchedulerDayViewViewInfo.IsContainerSelected( AResource: TcxSchedulerStorageResourceItem; ADate: TDateTime): Boolean; begin Result := False; with DayView.Scheduler do begin if SelectedEventCount > 0 then Exit; if (AResource = SelResource) and (DateOf(ADate + 1) <= DateOf(SelFinish)) then begin if DateOf(ADate) > DateOf(SelStart) then Result := True else Result := (DateOf(ADate) = DateOf(SelStart)) and (GetTimeMinutes(SelStart) = 0); end; end; Result := Result and CanSelected; end; function TcxSchedulerDayViewViewInfo.IsEventVisible( AEvent: TcxSchedulerEvent): Boolean; begin Result := (TimeOf(AEvent.Start) <= PrintTo) and (TimeOf(AEvent.Finish) >= PrintFrom); end; function TcxSchedulerDayViewViewInfo.IsEventVisible( var AStartRow, AStopRow: Integer): Boolean; begin Result := (AStopRow >= PrintStartRow) and (AStartRow <= PrintFinishRow); if Result then begin AStopRow := Min(PrintFinishRow, AStopRow); AStartRow := Max(PrintStartRow, AStartRow); end; end; function TcxSchedulerDayViewViewInfo.IsHourVisible(AIndex: Integer): Boolean; begin Result := not HasVisibleBounds or ((PrintStartRow div LinePerHour <= AIndex) and (AIndex <= PrintFinishRow div LinePerHour)); end; function TcxSchedulerDayViewViewInfo.IsRowVisible(AIndex: Integer): Boolean; begin Result := not HasVisibleBounds or ((AIndex >= PrintStartRow) and (AIndex <= PrintFinishRow)); end; procedure TcxSchedulerDayViewViewInfo.MakeTimeVisible( const ATime: TDateTime); var ARow: Integer; begin ARow := GetTimeRow(ATime, True); if (ARow < FTopIndex) or (ARow >= (FTopIndex + VisibleRowCount)) then begin if ARow < FTopIndex then FTopIndex := ARow else FTopIndex := Max(0, (ARow + 1) - VisibleRowCount); end; end; procedure TcxSchedulerDayViewViewInfo.OnClickMoreButton( Sender: TcxSchedulerMoreEventsButtonViewInfo); var ARow: Integer; begin ARow := Min(FRowCount, Max(0, Round(Sender.DateTime * FRowCount))); if not Sender.IsDown then FTopIndex := ARow else FTopIndex := Max(0, ARow - VisibleRowCount); View.LayoutChanged; end; procedure TcxSchedulerDayViewViewInfo.SetColumnTimeLineStyle( AViewInfo: TcxSchedulerEventCellViewInfo; AColIndex: Integer); var ACell: TcxSchedulerContentCellViewInfo; I, AOffset, StartRow, StopRow, ACount: Integer; begin if AViewInfo.Event.Start <= GetColumnDate(AColIndex) then StartRow := 0 else StartRow := GetTimeRow(AViewInfo.Event.Start, True); if (AViewInfo.Event.Finish - 1) >= GetColumnDate(AColIndex) then StopRow := FRowCount - 1 else StopRow := GetTimeRow(AViewInfo.Event.Finish, False); AOffset := 0; if HasVisibleBounds then begin ACount := PrintFinishRow - PrintStartRow + 1; if (StartRow > PrintFinishRow) or (StopRow < PrintStartRow) then Exit; StartRow := Max(0, StartRow - PrintStartRow); StopRow := Min(PrintFinishRow - StartRow, StopRow - PrintStartRow); AOffset := PrintStartRow; end else ACount := FRowCount; Inc(StartRow, AColIndex * ACount); Inc(StopRow, AColIndex * ACount); Dec(AOffset, AColIndex * ACount); for I := StartRow to StopRow do begin if not IsRowVisible(I + AOffset) then Continue; ACell := TcxSchedulerContentCellViewInfo(ContentCells[I]); if ACell.TimeEvent = nil then ACell.TimeEvent := AViewInfo; end; end; function TcxSchedulerDayViewViewInfo.GetAutoHeight: Boolean; begin Result := DayView.AutoContentHeight or HasVisibleBounds; end; function TcxSchedulerDayViewViewInfo.GetColumnInGroup: Integer; begin Result := DayCount; if GroupingKind = gkByDate then Result := ResourceCount; end; function TcxSchedulerDayViewViewInfo.GetContentHeight: Integer; begin Result := Bounds.Bottom - FContentOffset; end; function TcxSchedulerDayViewViewInfo.GetDayView: TcxSchedulerDayView; begin Result := TcxSchedulerDayView(Owner); end; function TcxSchedulerDayViewViewInfo.GetGroupCount: Integer; begin if GroupingKind = gkByDate then Result := DayCount else if GroupingKind = gkByResource then Result := ResourceCount else Result := 1; end; function TcxSchedulerDayViewViewInfo.GetPrintRowCount: Integer; begin Result := FPrintFinishRow - FPrintStartRow + UnusedRowCount + 1; end; function TcxSchedulerDayViewViewInfo.GetLinePerHour: Integer; begin Result := 60 div TimeScale; end; procedure TcxSchedulerDayViewViewInfo.SetLargeFont(AFont: TFont); begin FLargeFont.Assign(AFont); FLargeFont.Size := AFont.Size * 2; end; { TcxSchedulerDayViewHitTest } function TcxSchedulerDayViewHitTest.GetContainerCell: TcxSchedulerContainerCellViewInfo; begin if HitAtContainer then Result := TcxSchedulerContainerCellViewInfo(FHitObject) else Result := nil; end; function TcxSchedulerDayViewHitTest.GetTimeRulerCell: TcxSchedulerTimeRulerCellViewInfo; begin if HitAtTimeRuler then Result := TcxSchedulerTimeRulerCellViewInfo(FHitObject) else Result := nil; end; { TcxDayViewDragEventHelper } function TcxDayViewDragEventHelper.GetOriginHitTestMask: Int64; const Mask = (1 shl htcControl) or (1 shl htcDayHeader) or (1 shl htcTimeRuler) or (1 shl htcContainer) or (1 shl htcContent); begin Result := Mask; end; procedure TcxDayViewDragEventHelper.GetOriginState; begin inherited GetOriginState; FStartInHeader := FStartHitFlags and (1 shl htcContainer) <> 0; end; function TcxDayViewDragEventHelper.InHeader: Boolean; begin with HitTest do Result := HitAtDayHeader or HitAtContainer; end; function TcxDayViewDragEventHelper.IsAtOrigin: Boolean; begin Result := inherited IsAtOrigin or ((FStartInHeader and InHeader) and (Controller.StartDragHitTime = HitTest.Time) and ((FStartResource = nil) or (FStartResource = HitTest.Resource))); end; procedure TcxDayViewDragEventHelper.SetCloneEventsTimeDelta(AStart, ACurrent: TDateTime; AInHeader: Boolean); var I: Integer; ADelta: TDateTime; begin for I := 0 to Clones.Count - 1 do begin with Clones[I] do begin AllDayEvent := AInHeader; if AInHeader then begin ADelta := DateOf(AStart) - DateOf(ACurrent); if not IsHeaderEvent(Source) then Duration := 1 else Duration := Source.Duration; MoveTo(DateOf(Source.Start) - ADelta); end else if not IsHeaderEvent(Source) then begin Duration := Source.Duration; MoveTo(Source.Start - (AStart - ACurrent)); end else begin Duration := cxHalfHour; MoveTo(ACurrent); end; end; end; end; procedure TcxDayViewDragEventHelper.UpdateClonesTime; begin with HitTest do begin if HitAtTimeRuler then // correct event's times SetCloneEventsTimeDelta(Controller.StartDragHitTime, DateOf(Controller.StartDragHitTime) + Time, False) else SetCloneEventsTimeDelta(Controller.StartDragHitTime, Time, InHeader); end; end; procedure TcxDayViewDragEventHelper.UpdateEventProperties; begin inherited UpdateEventProperties; UpdateEventStates; end; procedure TcxDayViewDragEventHelper.UpdateEventStates; const States: array[Boolean] of Byte = (tlsBusy, tlsFree); var I: Integer; AEvent: TcxSchedulerControlEvent; begin for I := 0 to Clones.Count - 1 do begin AEvent := Clones[I]; if (AEvent.AllDayEvent <> AEvent.Source.AllDayEvent) and ((AEvent.AllDayEvent and (AEvent.Source.State = tlsBusy)) or (not AEvent.AllDayEvent and (AEvent.Source.State = tlsFree))) then AEvent.State := States[AEvent.AllDayEvent]; end; end; function TcxDayViewDragEventHelper.GetController: TcxSchedulerDayViewController; begin Result := TcxSchedulerDayViewController(inherited Controller); end; function TcxDayViewDragEventHelper.GetHitTest: TcxSchedulerDayViewHitTest; begin Result := TcxSchedulerDayViewHitTest(inherited HitTest); end; { TcxDayViewEventSizing } function TcxDayViewEventSizing.GetDragCursor(Accepted: Boolean): TCursor; const Cursors: array[Boolean] of TCursor = (crSchedulerVertResize, crSchedulerHorzResize); begin Result := Cursors[IsHeaderEvent(Event) and HitTest.HitAtContainer]; end; function TcxDayViewEventSizing.GetOriginHitTestMask: Int64; const Mask = (1 shl htcControl) or (1 shl htcDayHeader) or (1 shl htcTimeRuler) or (1 shl htcContainer) or (1 shl htcContent); begin Result := Mask; end; procedure TcxDayViewEventSizing.CalcAllDayEvent; begin with Event do begin AllDayEvent := (HitTest.HitAtContainer or (TimeOf(GetSizingTime) = 0)) and (Source.AllDayEvent or (TimeOf(FFixedBoundTime) = 0)); if Controller.DragKind = edkResizeStart then Finish := FFixedBoundTime else Start := FFixedBoundTime; end; end; function TcxDayViewEventSizing.GetFinishTime: TDateTime; begin Result := HitTest.Time; if HitTest.HitAtTimeRuler then Result := Result + DateOf(Event.Finish) else if HitTest.HitAtContent then Result := Result + TcxSchedulerDayView(Scheduler.CurrentView).TimeScale * MinuteToTime else if (Controller.DragKind = edkResizeEnd) and not Event.AllDayEvent and HitTest.HitAtContainer and (TimeOf(Result) = 0) then Result := Result + 1; end; procedure TcxDayViewEventSizing.GetOriginState; begin inherited GetOriginState; with Event do begin if Controller.DragKind = edkResizeStart then FFixedBoundTime := Finish else FFixedBoundTime := Start; end; end; function TcxDayViewEventSizing.GetSizingTime: TDateTime; begin if Controller.DragKind = edkResizeStart then Result := GetStartTime else Result := GetFinishTime; end; function TcxDayViewEventSizing.GetStartTime: TDateTime; begin Result := HitTest.Time; if HitTest.HitAtTimeRuler then Result := Result + DateOf(Event.Start); end; function TcxDayViewEventSizing.GetController: TcxSchedulerDayViewController; begin Result := TcxSchedulerDayViewController(inherited Controller); end; function TcxDayViewEventSizing.GetHitTest: TcxSchedulerDayViewHitTest; begin Result := TcxSchedulerDayViewHitTest(inherited HitTest); end; { TcxSchedulerDayNavigation } procedure TcxSchedulerDayNavigation.KeyDown( var AKey: Word; AShift: TShiftState); var ATime, ATimeDelta: TDateTime; begin FSelRow := GetTimeRow(FCurrentAnchor); ATime := DateOf(FCurrentAnchor); ATimeDelta := 0; case AKey of VK_UP: begin if FSelRow = 0 then Exit else ATimeDelta := GetRowTime(FSelRow - 1); end; VK_DOWN: begin if FSelRow >= ViewInfo.FRowCount - 1 then Exit else ATimeDelta := GetRowTime(FSelRow + 1); end; VK_HOME: if not (ssCtrl in AShift) then ATimeDelta := TimeOf(DayView.WorkStart); VK_END: begin if ssCtrl in AShift then ATimeDelta := 1 - DayView.GetTimeIncrement else ATimeDelta := TimeOf(DayView.WorkFinish) - DayView.GetTimeIncrement; end; VK_LEFT, VK_RIGHT: begin DoNextColumn(AKey = VK_RIGHT, GetColumnByDate(ATime, ResourceObject), ATime, FCurrentResource); Exit; end; VK_NEXT, VK_PRIOR: if not DoNextPage(AKey = VK_NEXT, ATime, FCurrentResource) then Exit; end; ATime := ATime + ATimeDelta; ViewInfo.MakeTimeVisible(ATime); SetSelAnchor(ATime, AShift, FCurrentResource); end; procedure TcxSchedulerDayNavigation.ValidateSelection(var ASelStart, ASelFinish: TDateTime; var AResource: TcxSchedulerStorageResourceItem); var I: Integer; AStart, AFinish, ADate: TDateTime; begin inherited ValidateSelection(ASelStart, ASelFinish, AResource); AStart := DateOf(Min(ASelFinish, ASelStart)); AFinish := DateOf(Max(ASelFinish, ASelStart)); for I := 0 to ViewInfo.DayCount - 1 do begin ADate := ViewInfo.Days[I]; if (ADate >= AStart) and (ADate <= AFinish) then Exit end; ASelFinish := GetColumnDate(0) + TimeOf(ASelFinish); ASelStart := ASelFinish; end; function TcxSchedulerDayNavigation.ColCount: Integer; begin Result := ViewInfo.ColCount; end; procedure TcxSchedulerDayNavigation.DoNextColumn(AGoToNext: Boolean; AColumn: Integer; const ATime: TDateTime; AResource: TcxSchedulerStorageResourceItem); const AColInc: array[Boolean] of Integer = (-1, 1); begin if (AGoToNext and (AColumn = ColCount - 1)) or (not AGoToNext and (AColumn = 0)) then begin DayView.ScrollVisibleDays(not AGoToNext); ReplaceDate(ATime + AColInc[AGoToNext], GetColumnResource(AColumn)); end else begin Inc(AColumn, AColInc[AGoToNext]); if (AResource <> GetColumnResource(AColumn)) then ReplaceDate(GetColumnDate(AColumn), GetColumnResource(AColumn)) else if not (ssShift in FShift) then ReplaceDate(GetColumnDate(AColumn), GetColumnResource(AColumn)) else SetSelAnchor(GetColumnDate(AColumn) + TimeOf(FCurrentAnchor), FShift, AResource); end; end; function TcxSchedulerDayNavigation.DoNextPage(AGoForward: Boolean; var ATime: TDateTime; var AResource: TcxSchedulerStorageResourceItem): Boolean; var ARow: Integer; begin if AGoForward then Result := FSelRow < (ViewInfo.FRowCount - 1) else Result := FSelRow > 0; if Result then begin if AGoForward then begin ARow := Min(FSelRow + ViewInfo.VisibleRowCount, ViewInfo.FRowCount - 1); ViewInfo.FTopIndex := Min(ViewInfo.FTopIndex + ViewInfo.VisibleRowCount, ViewInfo.FRowCount - 1) end else begin ARow := Max(0, FSelRow - ViewInfo.VisibleRowCount); ViewInfo.FTopIndex := Max(0, ViewInfo.FTopIndex - ViewInfo.VisibleRowCount); end; ATime := ATime + GetRowTime(ARow); end; end; function TcxSchedulerDayNavigation.GetColumnByDate( const ADate: TDateTime; AResource: TObject): Integer; begin for Result := 0 to ViewInfo.ColCount - 1 do with ViewInfo do begin if (GetColumnDate(Result) >= DateOf(ADate)) and (GetColumnResource(Result) = AResource) then Exit; end; Result := 0; end; function TcxSchedulerDayNavigation.GetColumnDate(AColumn: Integer): TDateTime; begin Result := ViewInfo.GetColumnDate(AColumn); end; function TcxSchedulerDayNavigation.GetColumnResource( AColumn: Integer): TcxSchedulerStorageResourceItem; begin Result := GetResourceFromViewInfo(ViewInfo.Containers[AColumn].Resource); end; function TcxSchedulerDayNavigation.GetRowTime( const ARow: Integer; AFinish: Boolean = False): TDateTime; begin Result := RoundTime((ARow + Byte(AFinish)) * DayView.TimeScale * MinuteToTime); end; function TcxSchedulerDayNavigation.GetTimeRow(const ATime: TDateTime): Integer; begin Result := ViewInfo.GetTimeRow(ATime, True); end; function TcxSchedulerDayNavigation.GetDayView: TcxSchedulerDayView; begin Result := ViewInfo.DayView; end; function TcxSchedulerDayNavigation.GetSelectedDays: TcxSchedulerDateList; begin Result := ViewInfo.SelectedDays; end; function TcxSchedulerDayNavigation.GetViewInfo: TcxSchedulerDayViewViewInfo; begin Result := TcxSchedulerDayViewViewInfo(inherited ViewInfo); end; { TcxSchedulerDayViewController } constructor TcxSchedulerDayViewController.Create( AOwner: TcxSchedulerSubControl); begin inherited Create(AOwner); FTimer := TTimer.Create(nil); end; destructor TcxSchedulerDayViewController.Destroy; begin FTimer.Free; inherited Destroy; end; procedure TcxSchedulerDayViewController.BeforeMouseDown( Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin FIsEditingBeforeMouseDown := IsEditing; inherited BeforeMouseDown(Button, Shift, X, Y); if HitTest.HitAtTimeRuler then HitTest.SetHitTime(htcTime, TimeOf(HitTest.Time) + DateOf(DateOf(Navigation.SelAnchor))); end; procedure TcxSchedulerDayViewController.CancelScroll; begin InitTimer(False, scEndScroll); end; procedure TcxSchedulerDayViewController.CheckScrolling(const APos: TPoint); var ACanScroll: Boolean; AScrollCode: TScrollCode; R: TRect; begin R := ViewInfo.Bounds; R.Top := ViewInfo.FContentOffset; FPos := APos; ACanScroll := cxRectPtIn(R, APos); AScrollCode := TScrollCode(FTimer.Tag); if (APos.Y >= R.Top) and (APos.Y < (R.Top + cxScrollZoneSize)) then AScrollCode := scLineUp else if (APos.Y < R.Bottom) and (APos.Y >= (R.Bottom - cxScrollZoneSize)) then AScrollCode := scLineDown else ACanScroll := False; if (ACanScroll <> FTimer.Enabled) or (Integer(AScrollCode) <> FTimer.Tag) then InitTimer(ACanScroll, AScrollCode); end; procedure TcxSchedulerDayViewController.CheckTimeRulerTime; begin if HitTest.HitAtTime and HitTest.HitAtTimeRuler and (DragEventHelper = nil) then HitTest.SetHitTime(htcTime, DateOf(Navigation.SelAnchor) + TimeOf(HitTest.Time)); end; function TcxSchedulerDayViewController.CreateDragEventHelper: TcxDragEventHelper; begin Result := TcxDayViewDragEventHelper.Create(Scheduler); end; function TcxSchedulerDayViewController.CreateNavigation: TcxSchedulerViewNavigation; begin Result := TcxSchedulerDayNavigation.Create(View); end; function TcxSchedulerDayViewController.CreateResizeEventHelper: TcxEventSizingHelper; begin Result := TcxDayViewEventSizing.Create(Scheduler); end; procedure TcxSchedulerDayViewController.InitTimer( AllowStart: Boolean; AScrollCode: TScrollCode); begin if AllowStart and FIsEditingBeforeMouseDown then begin FIsEditingBeforeMouseDown := False; AllowStart := False; end; if not AllowStart then FTimer.OnTimer := nil else FTimer.OnTimer := OnTimer; FTimer.Enabled := AllowStart; FTimer.Interval := cxScrollInterval; FTimer.Tag := Integer(AScrollCode); end; procedure TcxSchedulerDayViewController.MouseDown( Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if (Button = mbLeft) and (DragKind in [edkNone]) and HitTest.HitAtContainer and not HitTest.HitAtDayHeader and not HitTest.HitAtEvent then begin CloseInplaceEdit; UnselectEvents; with HitTest.ContainerCell do begin Navigation.ReplaceSelParams(DateTime, DateTime + 1 - Navigation.TimeIncrement, HitTest.Resource); FStartSelAnchor := DateTime - Navigation.TimeIncrement; end; if (Shift = [ssLeft, ssDouble]) and CanCreateEventUsingDialog then Scheduler.CreateEventUsingDialog else View.Refresh; end else begin if HitTest.HitAtTimeRuler then HitTest.SetHitTime(htcTime, TimeOf(HitTest.Time) + DateOf(DateOf(Navigation.SelAnchor))); inherited MouseDown(Button, Shift, X, Y); end; end; procedure TcxSchedulerDayViewController.MouseMove( Shift: TShiftState; X, Y: Integer); var AStart, AFinish: TDateTime; begin CheckTimeRulerTime; if (ssLeft in Shift) and (DragKind in [edkNone]) and HitTest.HitAtContainer and not HitTest.HitAtDayHeader then begin InitTimer(False, scEndScroll); AStart := DateOf(Navigation.SelRealStart); AFinish := HitTest.ContainerCell.DateTime; HitTest.SetBitState(htcTime, False); HitTest.SetBitState(htcContainer, False); if Navigation.SelResource = HitTest.Resource then begin if AFinish >= AStart then Navigation.ReplaceSelParams(AStart, AFinish + 1 - Navigation.TimeIncrement) else Navigation.ReplaceSelParams(AStart + 1 - Navigation.TimeIncrement, AFinish); end else Navigation.ReplaceSelParams(AStart, AStart + 1 - Navigation.TimeIncrement, Navigation.SelResource); View.Refresh; Exit; end; inherited MouseMove(Shift, X, Y); if not (ssLeft in Shift) then Exit; if ssLeft in Shift then CheckScrolling(cxPoint(X, Y)) else CancelScroll; end; procedure TcxSchedulerDayViewController.MouseUp( Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin CancelScroll; inherited MouseUp(Button, Shift, X, Y); end; procedure TcxSchedulerDayViewController.OnTimer(Sender: TObject); function GetShiftState: TShiftState; const Buttons: array[Boolean] of Integer = (VK_LBUTTON, VK_RBUTTON); begin Result := []; if GetAsyncKeyState(Buttons[GetSystemMetrics(SM_SWAPBUTTON) <> 0]) < 0 then Include(Result, ssLeft); if GetAsyncKeyState(VK_CONTROL) < 0 then Include(Result, ssCtrl); end; var APos: Integer; AShift: TShiftState; begin AShift := GetShiftState; if not (ssLeft in AShift) then begin CancelScroll; SetCaptureControl(nil); end else begin APos := ViewInfo.FTopIndex; ViewInfo.ScrollVertical(TScrollCode(FTimer.Tag), APos); MouseMove(AShift, FPos.X, FPos.Y); if (DragKind in [edkResizeStart, edkResizeEnd]) then CheckUpdateEventBounds; end; end; procedure TcxSchedulerDayViewController.CheckUpdateEventBounds; var ASizingHelper: TcxEventSizingHelper; begin if (Scheduler.DragAndDropState = ddsInProcess) and (Scheduler.DragAndDropObject is TcxSchedulerDragAndDropObject) then begin ASizingHelper := TcxSchedulerDragAndDropObject(Scheduler.DragAndDropObject).SizingHelper; if ASizingHelper is TcxDayViewEventSizing then TcxDayViewEventSizing(ASizingHelper).UpdateEventBounds; end; end; function TcxSchedulerDayViewController.GetHitTest: TcxSchedulerDayViewHitTest; begin Result := TcxSchedulerDayView(View).HitTest; end; function TcxSchedulerDayViewController.GetViewInfo: TcxSchedulerDayViewViewInfo; begin Result := TcxSchedulerDayView(View).ViewInfo; end; { TcxSchedulerDayViewPainter } procedure TcxSchedulerDayViewPainter.Paint; begin inherited Paint; ViewInfo.ContentCells.Draw(Canvas, DrawContentCell); ViewInfo.HeaderContainerCells.Draw(Canvas, DrawContainerCell); ViewInfo.EventCells.Draw(Canvas, DrawDayViewEventCell); ViewInfo.ResourceHeaderCells.Draw(Canvas, DrawResourceHeaderCell); ViewInfo.GroupSeparatorCells.Draw(Canvas, DrawGroupSeparatorCell); ViewInfo.DayHeaderCells.Draw(Canvas, DrawHeaderCell); ViewInfo.TimeRulerCells.Draw(Canvas, DrawTimeRulerCell); ViewInfo.Buttons.Draw(Canvas, DrawButtonCell); DrawBackgroundCell(ViewInfo.Background); end; procedure TcxSchedulerDayViewPainter.DrawContainerCell( AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); begin View.DoCustomDrawContainer( TcxSchedulerContainerCellViewInfo(AItem), ADone); end; procedure TcxSchedulerDayViewPainter.DrawDayViewEventCell( AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); begin DrawEventCell(AItem, ADone); end; procedure TcxSchedulerDayViewPainter.DrawTimeRulerCell( AItem: TcxSchedulerCustomViewInfoItem; var ADone: Boolean); begin View.DoCustomDrawTimeRuler( TcxSchedulerTimeRulerCellViewInfo(AItem), ADone); end; function TcxSchedulerDayViewPainter.GetView: TcxSchedulerDayView; begin Result := ViewInfo.DayView; end; function TcxSchedulerDayViewPainter.GetViewInfo: TcxSchedulerDayViewViewInfo; begin Result := TcxSchedulerDayViewViewInfo(inherited ViewInfo); end; { TcxSchedulerTimeRulerPopupMenu } constructor TcxSchedulerTimeRulerPopupMenu.Create( AScheduler: TcxCustomScheduler); begin inherited Create(AScheduler); FItems := [rpmiNewEvent, rpmiNewAllDayEvent, rpmiNewReccuringEvent, rpmi60min, rpmi30min, rpmi15min, rpmi10min, rpmi6min, rpmi5min]; end; procedure TcxSchedulerTimeRulerPopupMenu.Assign(Source: TPersistent); begin inherited Assign(Source); if Source is TcxSchedulerTimeRulerPopupMenu then begin Items := TcxSchedulerTimeRulerPopupMenu(Source).Items; OnClick := TcxSchedulerTimeRulerPopupMenu(Source).OnClick; OnPopup := TcxSchedulerTimeRulerPopupMenu(Source).OnPopup; end; end; procedure TcxSchedulerTimeRulerPopupMenu.Execute( AItem: TcxSchedulerTimeRulerPopupMenuItem); begin ExecuteCommand(Ord(AItem)); end; function TcxSchedulerTimeRulerPopupMenu.GetMenuItem( AItem: TcxSchedulerTimeRulerPopupMenuItem): TMenuItem; begin Result := FindItemByCommand(Root, Ord(AItem)); end; procedure TcxSchedulerTimeRulerPopupMenu.CreateItems; function GetChecked(ACommand: Integer): Boolean; var AIndex: Integer; begin Result := False; AIndex := ACommand - Ord(rpmi60min); if (AIndex < 0) or (AIndex > 5) then Exit; Result := DayView.TimeScale = RulerScales[AIndex]; end; procedure CreateRulerItem(const ACaption: string; AItem: TcxSchedulerTimeRulerPopupMenuItem); var ACommand: Integer; begin if AItem in Items then begin ACommand := Ord(AItem); CreateSubItem(Root, ACaption, ACommand, -1, True, GetChecked(ACommand)); end; end; begin CreateNewEventItems(rpmiNewEvent in FItems, rpmiNewAllDayEvent in FItems, rpmiNewReccuringEvent in FItems, Ord(rpmiNewEvent), Ord(rpmiNewAllDayEvent), Ord(rpmiNewReccuringEvent)); if Items * [rpmi60min, rpmi30min, rpmi15min, rpmi10min, rpmi6min, rpmi5min] <> [] then begin AddValidSeparator(Root); CreateRulerItem(cxGetResourceString(@scxpm60Minutes), rpmi60min); CreateRulerItem(cxGetResourceString(@scxpm30Minutes), rpmi30min); CreateRulerItem(cxGetResourceString(@scxpm15Minutes), rpmi15min); CreateRulerItem(cxGetResourceString(@scxpm10Minutes), rpmi10min); CreateRulerItem(cxGetResourceString(@scxpm6Minutes), rpmi6min); CreateRulerItem(cxGetResourceString(@scxpm5Minutes), rpmi5min); end; end; procedure TcxSchedulerTimeRulerPopupMenu.DoExecute(ACommand: Integer); var AIndex: Integer; begin if ACommand in [Ord(rpmiNewEvent), Ord(rpmiNewAllDayEvent), Ord(rpmiNewReccuringEvent)] then inherited DoExecute(ACommand) else begin AIndex := ACommand - Ord(rpmi60min); if AIndex in [0..5] then DayView.TimeScale := RulerScales[AIndex]; end; end; function TcxSchedulerTimeRulerPopupMenu.DoOnClick( ACommand: Integer): Boolean; begin Result := False; if Assigned(FOnClick) then FOnClick(Self, TcxSchedulerTimeRulerPopupMenuItem(ACommand), Result); end; function TcxSchedulerTimeRulerPopupMenu.DoOnPopup: Boolean; begin Result := False; if Assigned(FOnPopup) then FOnPopup(Self, InternalMenu, Result); end; function TcxSchedulerTimeRulerPopupMenu.IsValidCommand( ACommand: Integer): Boolean; begin Result := (ACommand >= Ord(rpmiNewEvent)) and (ACommand <= Ord(rpmi5min)); end; function TcxSchedulerTimeRulerPopupMenu.GetDayView: TcxSchedulerDayView; begin Result := Scheduler.CurrentView as TcxSchedulerDayView; end; end.