TvPlanIt: Extend GanttView by hour resolution

git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@8937 8e941d3f-bd1b-0410-a28a-d453659cc2b4
This commit is contained in:
wp_xxyyzz
2023-10-08 22:41:21 +00:00
parent d826f29a29
commit a41f9dbdcb
5 changed files with 561 additions and 152 deletions

View File

@ -2,18 +2,18 @@ object MainForm: TMainForm
Left = 319
Height = 600
Top = 125
Width = 800
Width = 865
Caption = 'MainForm'
ClientHeight = 600
ClientWidth = 800
ClientWidth = 865
LCLVersion = '3.99.0.0'
OnCreate = FormCreate
LCLVersion = '2.3.0.0'
object Splitter1: TSplitter
Cursor = crVSplit
Left = 0
Height = 5
Top = 240
Width = 800
Width = 865
Align = alTop
ResizeAnchor = akTop
end
@ -21,11 +21,11 @@ object MainForm: TMainForm
Left = 0
Height = 66
Top = 534
Width = 800
Width = 865
Align = alBottom
BevelOuter = bvNone
ClientHeight = 66
ClientWidth = 800
ClientWidth = 865
TabOrder = 1
object Button1: TButton
AnchorSideLeft.Control = Panel1
@ -37,8 +37,8 @@ object MainForm: TMainForm
AutoSize = True
BorderSpacing.Around = 6
Caption = 'All events'
OnClick = Button1Click
TabOrder = 0
OnClick = Button1Click
end
object Button2: TButton
AnchorSideLeft.Control = Button1
@ -51,8 +51,8 @@ object MainForm: TMainForm
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Week of selected date only'
OnClick = Button2Click
TabOrder = 1
OnClick = Button2Click
end
object Button3: TButton
AnchorSideLeft.Control = Button2
@ -65,8 +65,8 @@ object MainForm: TMainForm
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Month of selected date only'
OnClick = Button3Click
TabOrder = 2
OnClick = Button3Click
end
object CheckBox1: TCheckBox
AnchorSideLeft.Control = Button3
@ -80,9 +80,9 @@ object MainForm: TMainForm
BorderSpacing.Top = 6
Caption = 'Show weekends'
Checked = True
OnChange = CheckBox1Change
State = cbChecked
TabOrder = 3
OnChange = CheckBox1Change
end
object CheckGroup1: TCheckGroup
AnchorSideTop.Control = Panel1
@ -91,31 +91,34 @@ object MainForm: TMainForm
Left = 581
Height = 54
Top = 6
Width = 185
Width = 241
Anchors = [akTop, akLeft, akBottom]
AutoFill = True
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Show headers'
ChildSizing.LeftRightSpacing = 6
ChildSizing.TopBottomSpacing = 6
ChildSizing.HorizontalSpacing = 12
ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
ChildSizing.EnlargeVertical = crsHomogenousChildResize
ChildSizing.ShrinkHorizontal = crsScaleChilds
ChildSizing.ShrinkVertical = crsScaleChilds
ChildSizing.Layout = cclLeftToRightThenTopToBottom
ChildSizing.ControlsPerLine = 3
ChildSizing.ControlsPerLine = 4
ClientHeight = 34
ClientWidth = 181
Columns = 3
ClientWidth = 237
Columns = 4
Items.Strings = (
'Month'
'Week'
'Day'
'Hours'
)
OnItemClick = CheckGroup1ItemClick
TabOrder = 4
OnItemClick = CheckGroup1ItemClick
Data = {
03000000020202
0400000002020202
}
end
object CheckBox2: TCheckBox
@ -129,9 +132,9 @@ object MainForm: TMainForm
BorderSpacing.Top = 6
Caption = '3D'
Checked = True
OnChange = CheckBox2Change
State = cbChecked
TabOrder = 5
OnChange = CheckBox2Change
end
object Button4: TButton
AnchorSideLeft.Control = Panel1
@ -144,8 +147,8 @@ object MainForm: TMainForm
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Edit Print Formats...'
OnClick = Button4Click
TabOrder = 6
OnClick = Button4Click
end
object Button5: TButton
AnchorSideLeft.Control = Button4
@ -159,8 +162,8 @@ object MainForm: TMainForm
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Print Preview...'
OnClick = Button5Click
TabOrder = 7
OnClick = Button5Click
end
object Button6: TButton
AnchorSideLeft.Control = Button5
@ -174,8 +177,8 @@ object MainForm: TMainForm
AutoSize = True
BorderSpacing.Around = 6
Caption = 'Print'
OnClick = Button6Click
TabOrder = 8
OnClick = Button6Click
end
object VpPrintFormatComboBox1: TVpPrintFormatComboBox
AnchorSideLeft.Control = Button6
@ -197,14 +200,14 @@ object MainForm: TMainForm
Left = 0
Height = 240
Top = 0
Width = 800
Width = 865
Align = alTop
Caption = 'Panel2'
ClientHeight = 240
ClientWidth = 800
ClientWidth = 865
TabOrder = 2
object VpMonthView1: TVpMonthView
Left = 421
Left = 486
Height = 238
Top = 1
Width = 378
@ -220,7 +223,7 @@ object MainForm: TMainForm
Left = 1
Height = 238
Top = 1
Width = 415
Width = 480
PopupMenu = VpDayView1.default
DataStore = VpIniDatastore1
ControlLink = VpControlLink1
@ -235,7 +238,7 @@ object MainForm: TMainForm
NumDays = 2
end
object Splitter2: TSplitter
Left = 416
Left = 481
Height = 238
Top = 1
Width = 5
@ -251,12 +254,12 @@ object MainForm: TMainForm
Printer.MarginUnits = imAbsolutePixel
Printer.PrintFormats = <
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayInc = 0
DayIncUnits = duDay
Elements = <
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayOffset = 0
DayOffsetUnits = duDay
ElementName = 'GanttView'
@ -270,12 +273,12 @@ object MainForm: TMainForm
FormatName = 'Gantt Portrait 0°'
end
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayInc = 0
DayIncUnits = duDay
Elements = <
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayOffset = 0
DayOffsetUnits = duDay
ElementName = 'GanttView rotated 270°'
@ -290,12 +293,12 @@ object MainForm: TMainForm
FormatName = 'Gantt Landscape 270°'
end
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayInc = 0
DayIncUnits = duDay
Elements = <
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayOffset = 0
DayOffsetUnits = duDay
ElementName = 'GanttView rotated 90°'
@ -310,12 +313,12 @@ object MainForm: TMainForm
FormatName = 'Gantt Landscape 90°'
end
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayInc = 10
DayIncUnits = duDay
Elements = <
item
Version = 'v1.7.0'
Version = 'v1.8.0'
DayOffset = 0
DayOffsetUnits = duDay
ElementName = 'GantView'
@ -366,7 +369,7 @@ object MainForm: TMainForm
Top = 296
end
object VpPrintFormatEditDialog1: TVpPrintFormatEditDialog
Version = 'v1.7.0'
Version = 'v1.8.0'
DataStore = VpIniDatastore1
ControlLink = VpControlLink1
Options = []
@ -379,7 +382,7 @@ object MainForm: TMainForm
Top = 56
end
object VpPrintPreviewDialog1: TVpPrintPreviewDialog
Version = 'v1.7.0'
Version = 'v1.8.0'
DataStore = VpIniDatastore1
ControlLink = VpControlLink1
EndDate = 44838.5281092593

View File

@ -77,6 +77,8 @@ begin
FGanttView.Datastore := VpIniDatastore1;
FGanttView.ControlLink := VpControlLink1;
FGanttView.ColHeaderAttributes.Visible := [gchMonth, gchWeek, gchDay];
// FGanttView.StartHour := h_00;
// FGanttView.EndHour := h_23;
Caption := FGanttView.Datastore.ClassName;
CheckGroup1.Checked[0] := gchMonth in FGanttView.ColHeaderAttributes.Visible;

View File

@ -2410,7 +2410,7 @@ begin
Windows.SetFocus(GetNextDlgTabItem(GetParent(Handle), Handle, True));
{$ENDIF}
VK_F10:
if (ssShift in Shift) and not (Assigned (PopupMenu)) then begin
if (ssShift in Shift) and (not Assigned(PopupMenu)) then begin
PopupPoint := GetClientOrigin;
FDefaultPopup.Popup(PopupPoint.x + 10, PopupPoint.y + 10);
end;

View File

@ -41,6 +41,8 @@ type
procedure SetItem(AIndex: Integer; AItem: PVpGanttEventRec);
protected
procedure ClipDates(AEventRec: PVpGanttEventRec);
function FindFirstRecurrence(AEvent: TVpEvent; out AStart, AEnd: TDateTime): Boolean;
function FindNextRecurrence(AEvent: TVpEvent; var AStart, AEnd: TDateTime): Boolean;
public
constructor Create(AStartDate, AEndDate: TDateTime);
destructor Destroy; override;
@ -51,6 +53,12 @@ type
property Items[AIndex: Integer]: PVpGanttEventRec read GetItem write SetItem; default;
end;
TVpGanttHourRec = record
Hour: Integer;
Date: TDateTime;
Rect: TRect;
end;
TVpGanttDayRec = record
Date: TDateTime;
Rect: TRect;
@ -92,16 +100,18 @@ type
property EventFont: TVpFont read FEventFont write SetEventFont;
end;
TVpGanttColHeaderKind = (gchMonth, gchWeek, gchDay);
TVpGanttColHeaderKind = (gchMonth, gchWeek, gchDay, gchHour);
TVpGanttColHeaderKinds = set of TVpGanttColHeaderKind;
TVpGanttColHeaderAttributes = class(TVpGanttHeaderAttributes)
private
FHourFont: TVpFont;
FDayFont: TVpFont;
FMonthFont: TVpFont;
FWeekFont: TVpFont;
FVisible: TVpGanttColHeaderKinds;
procedure SetDayFont(AValue: TVpFont);
procedure SetHourfont(AValue: TVpFont);
procedure SetMonthFont(AValue: TVpFont);
procedure SetVisible(AValue: TVpGanttColHeaderKinds);
procedure SetWeekFont(AValue: TVpFont);
@ -110,6 +120,7 @@ type
destructor Destroy; override;
published
property DayFont: TVpFont read FDayFont write SetDayFont;
property HourFont: TVpFont read FHourFont write SetHourFont;
property MonthFont: TVpFont read FMonthFont write SetMonthFont;
property Visible: TVpGanttColHeaderKinds read FVisible write SetVisible default [gchMonth, gchDay];
property WeekFont: TVpFont read FWeekFont write SetWeekFont;
@ -148,6 +159,7 @@ type
FMonthColHeaderHeight: Integer;
FWeekColHeaderHeight: Integer;
FDayColHeaderHeight: Integer;
FHourColHeaderHeight: Integer;
FTotalColHeaderHeight: Integer;
FTextMargin: Integer;
@ -160,7 +172,7 @@ type
FRowHeaderAttributes: TVpGanttRowHeaderAttributes;
FComponentHint: TTranslateString;
FDateFormat: array[0..2] of String;
FDateFormat: array[0..3] of String;
FDrawingStyle: TVpDrawingStyle;
FDefaultPopup: TPopupMenu;
FExternalPopup: TPopupMenu;
@ -171,6 +183,9 @@ type
FTimeFormat: TVpTimeFormat;
FWeekStartsOn: TVpDayType;
FStartHour: TVpHours;
FEndHour: TVpHours;
FOnAddEvent: TVpOnAddNewEvent;
FOnDeletingEvent: TVpOnDeletingEvent;
FOnHoliday: TVpHolidayEvent;
@ -180,14 +195,18 @@ type
function GetDateFormat(AIndex: Integer): String;
function GetDayRec(AIndex: Integer): TVpGanttDayRec;
function GetEventRec(AIndex: Integer): PVpGanttEventRec;
function GetHourRec(AIndex: Integer): TVpGanttHourRec;
function GetMonthRec(AIndex: Integer): TVpGanttMonthRec;
function GetNumDays: Integer;
function GetNumEvents: Integer;
function GetNumHours: Integer;
function GetNumMonths: Integer;
function GetNumWeeks: Integer;
function GetWeekRec(AIndex: Integer): TVpGanttWeekRec;
function IsStoredColWidth: Boolean;
function IsStoredDateFormat(AIndex: Integer): Boolean;
function IsStoredEndHour: Boolean;
function IsStoredStartHour: Boolean;
procedure SetActiveCol(AValue: Integer);
procedure SetActiveDate(AValue: TDateTime);
procedure SetActiveEvent(AValue: TVpEvent);
@ -196,6 +215,7 @@ type
procedure SetColWidth(AValue: Integer);
procedure SetDateFormat(AIndex: Integer; AValue: String);
procedure SetDrawingStyle(AValue: TVpDrawingStyle);
procedure SetEndHour(AValue: TVpHours);
procedure SetFixedColWidth(AValue: Integer);
procedure SetHolidayColor(AValue: TColor);
procedure SetLeftCol(AValue: Integer);
@ -203,6 +223,7 @@ type
procedure SetOptions(AValue: TVpGanttViewOptions);
procedure SetPopupMenu(AValue: TPopupMenu);
procedure SetSpecialDayMode(AValue: TVpGanttSpecialDayMode);
procedure SetStartHour(AValue: TVpHours);
procedure SetTextMargin(AValue: Integer);
procedure SetTopRow(AValue: Integer);
procedure SetWeekendColor(AValue: TColor);
@ -211,13 +232,16 @@ type
protected
// Needed by the painter
FEventRecords: TVpGanttEventList;
FHourRecords: array of TVpGanttHourRec;
FDayRecords: array of TVpGanttDayRec;
FWeekRecords: array of TVpGanttWeekRec;
FMonthRecords: array of TVpGanttMonthRec;
{ internal methods }
procedure CalcColHeaderHeight;
function CalcDaysWidth(ANumDays: Integer): Integer;
procedure CalcRowHeight;
function ColToDateIndex(ACol: Integer): Integer;
function GetColAtCoord(X: Integer): Integer;
function GetDateOfCol(ACol: Integer): TDateTime;
function GetDateTimeAtCoord(X: Integer): TDateTime;
@ -232,6 +256,7 @@ type
procedure Populate;
procedure PopulateDayRecords;
procedure PopulateEventRecords;
procedure PopulateHourRecords;
procedure PopulateMonthRecords;
procedure PopulateWeekRecords;
procedure ScrollDateIntoView(ADate: TDateTime);
@ -286,6 +311,8 @@ type
function BuildEventString(AEvent: TVpEvent; UseAsHint: Boolean): String;
procedure DeleteActiveEvent(Prompt: Boolean);
function GetControlType: TVpItemType; override;
function HourMode: Boolean;
function HoursPerDay: Integer;
procedure Init;
function IsHoliday(ADate: TDate; out AHolidayName: String): Boolean;
procedure LoadLanguage;
@ -330,16 +357,19 @@ type
// Unscaled dimensions
property RowHeight: Integer read FRowHeight;
property DayColHeaderHeight: Integer read FDayColHeaderHeight;
property HourColHeaderHeight: Integer read FHourColHeaderHeight;
property MonthColHeaderHeight: Integer read FMonthColHeaderHeight;
property TotalColHeaderHeight: Integer read FTotalColHeaderHeight;
property DayRecords[AIndex: Integer]: TVpGanttDayRec read GetDayRec;
property EventRecords[AIndex: Integer]: PVpGanttEventRec read GetEventRec;
property HourRecords[AIndex: Integer]: TVPGanttHourRec read GetHourRec;
property MonthRecords[AIndex: Integer]: TVpGanttMonthRec read GetMonthRec;
property WeekRecords[AIndex: Integer]: TVpGanttWeekRec read GetWeekRec;
property NumDays: Integer read GetNumDays;
property NumEvents: Integer read GetNumEvents;
property NumHours: Integer read GetNumHours;
property NumMonths: Integer read GetNumMonths;
property NumWeeks: Integer read GetNumWeeks;
@ -354,7 +384,9 @@ type
property Color: TColor read FColor write SetColor default DEFAULT_COLOR;
property ColWidth: Integer read FColWidth write SetColWidth stored IsStoredColWidth;
property DayFormat: String index 0 read GetDateFormat write SetDateFormat stored IsStoredDateFormat;
property DayFormat_HourMode: String index 3 read GetDateFormat write SetDateFormat stored IsStoredDateFormat;
property DrawingStyle: TVpDrawingStyle read FDrawingStyle write SetDrawingStyle default ds3d;
property EndHour: TVpHours read FEndHour write SetEndHour stored IsStoredEndHour;
property FixedColWidth: Integer read FFixedColWidth write SetFixedColWidth default 120;
property HintMode: TVpHintMode read FHintMode write SetHintMode default hmPlannerHint;
property HolidayColor: TColor read FHolidayColor write SetHolidayColor default HOLIDAY_COLOR;
@ -365,6 +397,7 @@ type
property PopupMenu: TPopupMenu read GetPopupMenu write SetPopupMenu;
property RowHeaderAttributes: TVpGanttRowHeaderAttributes read FRowHeaderAttributes write FRowHeaderAttributes;
property SpecialDayMode: TVpGanttSpecialDayMode read FSpecialDayMode write SetSpecialDayMode default sdmColumn;
property StartHour: TVpHours read FStartHour write SetStartHour stored IsStoredStartHour;
property TextMargin: Integer read FTextMargin write SetTextMargin default 2;
property TimeFormat: TVpTimeFormat read FTimeFormat write FTimeFormat default tf12Hour;
property WeekendColor: TColor read FWeekendColor write SetWeekendColor default WEEKEND_COLOR;
@ -389,7 +422,10 @@ const
DEFAULT_DAYFORMAT = 'd';
DEFAULT_MONTHFORMAT = 'mmmm yyyy';
DEFAULT_MONTHFORMAT_SHORT = 'mmm yyyy';
DEFAULT_DAYFORMAT_HOURMODE = 'dddddd'; // long date format
DEFAULT_COLWIDTH = 20;
DEFAULT_START_HOUR = h_07;
DEFAULT_END_HOUR = h_20;
{ Compare function for sorting event records: Compares the start times of two events.
If the times are equal (within 1 seconds) then end times are compared.
@ -438,54 +474,12 @@ begin
dt2 := AEvent.EndTime;
end;
while (DatePart(dt2) >= FStartDate) or (DatePart(dt1) <= FEndDate) do
begin
if FindFirstRecurrence(AEvent, dt1, dt2) then
repeat
eventRec := AddSingleEvent(AEvent);
eventRec^.StartTime := dt1;
eventRec^.EndTime := dt2;
ClipDates(eventRec);
// Find date/times of next recurrance.
case AEvent.RepeatCode of
rtDaily:
begin
dt1 := dt1 + 1;
dt2 := dt2 + 1;
end;
rtWeekly:
begin
dt1 := dt1 + 7;
dt2 := dt2 + 7;
end;
rtMonthlyByDay:
begin
// wp: to do... What does it mean?
end;
rtMonthlyByDate:
begin
dt1 := IncMonth(dt1, 1);
dt2 := IncMonth(dt2, 1);
end;
rtYearlyByDay:
begin
// wp: to do... What does it mean?
end;
rtYearlyByDate:
begin
dt1 := IncYear(dt1, 1);
dt2 := IncYear(dt2, 1);
end;
rtCustom:
begin
dt1 := dt1 + AEvent.CustomInterval;
dt2 := dt2 + AEvent.CustomInterval;
end;
end;
if dt2 >= AEvent.RepeatRangeEnd then
break;
if dt1 > FEndDate then
break;
end;
until not FindNextRecurrence(AEvent, dt1, dt2);
end;
function TVpGanttEventList.AddSingleEvent(AEvent: TVpEvent): PVpGanttEventRec;
@ -553,6 +547,129 @@ begin
inherited;
end;
// Find date/times of first recurrence of the specified event in the gantt view's
// date range.
function TVpGanttEventList.FindFirstRecurrence(AEvent: TVpEvent;
out AStart, AEnd: TDateTime): Boolean;
var
delta: Double;
d: TDateTime;
eventYear, eventMonth, eventDay: Word;
startYear, startMonth, startDay: Word;
begin
Result := false;
if AEvent.StartTime >= FEndDate then
exit;
if (AEvent.RepeatRangeEnd > 0) and (AEvent.RepeatRangeEnd <= FStartDate) then
exit;
if AEvent.StartTime >= FStartDate then
begin
AStart := AEvent.StartTime;
AEnd := AEvent.EndTime;
Result := true;
exit;
end;
DecodeDate(AEvent.StartTime, eventYear, eventMonth, eventDay);
DecodeDate(FStartDate, startYear, startMonth, startDay);
case AEvent.RepeatCode of
rtDaily:
AStart := DatePart(FStartDate) + TimePart(AEvent.StartTime);
rtWeekly:
begin
delta := AEvent.StartTime - StartOfTheWeek(AEvent.StartTime);
AStart := StartOfTheWeek(FStartDate) + delta;
end;
rtMonthlyByDay:
begin
delta := AEvent.StartTime - StartOfTheMonth(AEvent.StartTime);
AStart := StartOfTheMonth(FStartDate) + delta;
end;
rtMonthlyByDate:
AStart := EncodeDate(startYear, startMonth, eventDay);
rtYearlyByDay:
begin
delta := AEvent.StartTime - StartofTheYear(AEvent.StartTime);
AStart := StartOfTheYear(FStartDate) + delta;
end;
rtYearlyByDate:
if not TryEncodeDate(startYear, eventMonth, eventDay, AStart) then
AStart := EncodeDate(startYear, 2, 28);
rtCustom:
begin
AStart := trunc((FStartDate - DatePart(AEvent.StartTime)) / AEvent.CustomInterval) * AEvent.CustomInterval + TimePart(AEvent.StartTime);
if AStart < FStartdate then
AStart := AStart + AEvent.CustomInterval;
end;
end;
AEnd := AStart + (AEvent.EndTime - AEvent.StartTime);
if (AEvent.RepeatRangeEnd > 0) and (AEnd > AEvent.RepeatRangeEnd) then
exit;
if AStart > FEndDate + 1 then
exit;
Result := true;
end;
// Find date/times of next recurrence of the specified event.
function TVpGanttEventList.FindNextRecurrence(AEvent: TVpEvent;
var AStart, AEnd: TDateTime): Boolean;
var
delta: Double;
begin
Result := false;
if (AStart >= FEndDate) then
exit;
case AEvent.RepeatCode of
rtDaily:
begin
AStart := AStart + 1;
AEnd := AEnd + 1;
end;
rtWeekly:
begin
AStart := AStart + 7;
AEnd := AEnd + 7;
end;
rtMonthlyByDay:
begin
delta := DatePart(AStart) - StartOfTheMonth(AStart);
AStart := AStart + delta;
AEnd := AEnd + delta;
end;
rtMonthlyByDate:
begin
AStart := IncMonth(AStart, 1);
AEnd := IncMonth(AEnd, 1);
end;
rtYearlyByDay:
begin
delta := DatePart(AStart) - StartOfTheYear(AStart);
AStart := AStart + delta;
AEnd := AEnd + delta;
end;
rtYearlyByDate:
begin
AStart := IncYear(AStart, 1);
AEnd := IncYear(AEnd, 1);
end;
rtCustom:
begin
AStart := AStart + AEvent.CustomInterval;
AEnd := AEnd + AEvent.CustomInterval;
end;
end;
if (AEvent.RepeatRangeEnd > 0) and (AEnd > AEvent.RepeatRangeEnd) then
exit;
if AStart > FEndDate + 1 then
exit;
Result := true;
end;
function TVpGanttEventList.GetItem(AIndex: Integer): PVpGanttEventRec;
begin
Result := PVpGanttEventRec(inherited Items[AIndex]);
@ -622,6 +739,7 @@ end;
constructor TVpGanttColHeaderAttributes.Create(AOwner: TVpGanttView);
begin
inherited Create(AOwner);
FHourFont := TVpFont.Create(AOwner);
FDayFont := TVpFont.Create(AOwner);
FWeekFont := TVpFont.Create(AOwner);
FMonthFont := TVpFont.Create(AOwner);
@ -630,6 +748,7 @@ end;
destructor TVpGanttColHeaderAttributes.Destroy;
begin
FHourFont.Free;
FDayFont.Free;
FWeekFont.Free;
FMonthFont.Free;
@ -646,6 +765,16 @@ begin
end;
end;
procedure TVpGanttColHeaderAttributes.SetHourFont(AValue: TVpFont);
begin
if FHourFont <> AValue then
begin
FHourFont := AValue;
FHourFont.Owner := FGanttView;
UpdateGanttView;
end;
end;
procedure TVpGanttColHeaderAttributes.SetMonthFont(AValue: TVpFont);
begin
if FMonthFont <> AValue then
@ -700,12 +829,16 @@ begin
FWeekendColor := WEEKEND_COLOR;
FHolidayColor := HOLIDAY_COLOR;
FStartHour := DEFAULT_START_HOUR;
FEndHour := DEFAULT_END_HOUR;
FRowHeaderAttributes := TVpGanttRowHeaderAttributes.Create(self);
FColHeaderAttributes := TVpGanttColHeaderAttributes.Create(self);
FDateFormat[0] := DEFAULT_DAYFORMAT;
FDateFormat[1] := DEFAULT_MONTHFORMAT;
FDateFormat[2] := DEFAULT_MONTHFORMAT_SHORT;
FDateFormat[3] := DEFAULT_DAYFORMAT_HOURMODE;
FDrawingStyle := ds3d;
FOptions := DEFAULT_GANTTVIEW_OPTIONS;
FScrollBars := ssBoth;
@ -795,15 +928,18 @@ var
h: Integer;
begin
h := GetCanvasTextHeight(Canvas, FColHeaderAttributes.MonthFont);
FMonthColHeaderHeight := h; // + 2 * FTextMargin;
FMonthColHeaderHeight := h;
h := GetCanvasTextHeight(Canvas, FColHeaderAttributes.WeekFont);
FWeekColHeaderHeight := h; // + 2 * FTextMargin;
FWeekColHeaderHeight := h;
// A typical date string to measure the text height (line breaks in DayFormat allowed)
s := FormatDateTime(DayFormat, EncodeDate(2000, 12, 28));
h := GetCanvasTextHeight(Canvas, FColHeaderAttributes.DayFont, s);
FDayColHeaderHeight := h; // + FTextMargin;
FDayColHeaderHeight := h;
h := GetCanvasTextHeight(Canvas, FColHeaderAttributes.HourFont);
FHourColHeaderHeight := h;
FTotalColHeaderHeight := 0;
if (gchMonth in FColHeaderAttributes.Visible) then
@ -812,10 +948,19 @@ begin
inc(FTotalColHeaderHeight, FWeekColHeaderHeight + FTextMargin);
if (gchDay in FColHeaderAttributes.Visible) then
inc(FTotalColHeaderHeight, FDayColHeaderHeight + FTextMargin);
if (gchHour in FColHeaderAttributes.Visible) then
inc(FTotalColHeaderHeight, FHourColHeaderHeight + FTextMargin);
if FTotalColHeaderHeight > 0 then
inc(FTotalColHeaderHeight, FTextMargin);
end;
function TvpGanttView.CalcDaysWidth(ANumDays: Integer): Integer;
begin
Result := ANumDays * FColWidth;
if HourMode then
Result := Result * HoursPerDay;
end;
procedure TVpGanttView.CalcRowHeight;
var
h: Integer;
@ -852,6 +997,14 @@ begin
Result := 0;
end;
function TVpGanttView.ColToDateIndex(ACol: Integer): Integer;
begin
if HourMode then
Result := ACol div HoursPerDay
else
Result := ACol;
end;
procedure TVpGanttView.CreateParams(var AParams: TCreateParams);
begin
inherited CreateParams(AParams);
@ -993,7 +1146,7 @@ begin
ScrollVertical(-emptyRows);
VisibleCols := CalcVisibleCols(ClientWidth, FFixedColWidth, FColWidth);
emptyCols := VisibleCols - (Length(FDayRecords) - FLeftCol);
emptyCols := VisibleCols - (ColCount - FLeftCol);
if emptyCols > 0 then
ScrollHorizontal(-emptyCols);
end;
@ -1018,27 +1171,27 @@ begin
Result := itGanttView;
end;
function TVpGanttView.GetDateFormat(AIndex: Integer): String;
begin
Result := FDateFormat[AIndex];
end;
function TVpGanttView.GetDateOfCol(ACol: Integer): TDateTime;
begin
Result := FRealStartDate + ACol;
Result := FRealStartDate + ColToDateIndex(ACol);
end;
function TVpGanttView.GetDateTimeAtCoord(X: Integer): TDateTime;
var
days: double;
c: Integer;
begin
days := (X - FixedColWidth) / FColWidth + FLeftCol;
if (days >= 0) and (days < NumDays) then
Result := FRealStartDate + days
c := GetColAtCoord(X);
if (c >= 0) and (c < ColCount) then
Result := GetDateOfCol(c)
else
Result := NO_DATE;
end;
function TVpGanttView.GetDateFormat(AIndex: Integer): String;
begin
Result := FDateFormat[AIndex];
end;
function TVpGanttView.GetDayRec(AIndex: Integer): TVpGanttDayRec;
begin
Result := FDayRecords[AIndex];
@ -1051,9 +1204,11 @@ var
dt: TDateTime;
begin
Result := nil;
dt := GetDateTimeAtCoord(X);
if (dt = -1) or (FRowHeight = 0) then
if (dt = NO_DATE) or (FRowHeight = 0) then
exit;
idx := GetRowAtCoord(Y);
if (idx >= 0) and (idx < NumEvents) then
begin
@ -1073,28 +1228,41 @@ end;
and when the latest event ends. }
procedure TVpGanttView.GetEventDateRange(out AFirstDate, ALastDate: TDate);
var
i: Integer;
event: TVpEvent;
i, j: Integer;
event: TVpEvent = nil;
d: TDateTime;
begin
if (Datastore = nil) or (Datastore.Resource = nil) or (Datastore.Resource.Schedule.EventCount = 0) then
begin
AFirstDate := NO_DATE;
ALastDate := NO_DATE;
end else
if (Datastore = nil) or (Datastore.Resource = nil) or (Datastore.Resource.Schedule.EventCount = 0) then
exit;
// Find first non-recurring event; recurring events will be accepted only
// between FStartDate and FEndDate.
i := 0;
repeat
event := Datastore.Resource.Schedule.GetEvent(i);
inc(i);
until (event.RepeatCode = rtNone) or (i = DataStore.Resource.Schedule.EventCount);
if event <> nil then
begin
event := Datastore.Resource.Schedule.GetEvent(0);
AFirstDate := DatePart(event.StartTime);
ALastDate := -99999;
for i := 0 to Datastore.Resource.Schedule.EventCount-1 do
for j := i-1 to Datastore.Resource.Schedule.EventCount-1 do
begin
event := Datastore.Resource.Schedule.GetEvent(j);
if event.RepeatCode = rtNone then
begin
event := Datastore.Resource.Schedule.GetEvent(i);
d := DatePart(event.EndTime);
if d > ALastDate then ALastDate := d;
end;
end;
end;
// To do: handle recurring events
end;
function TVpGanttView.GetEventOfRow(ARow: Integer): TVpEvent;
begin
Result := EventRecords[ARow]^.Event;
@ -1105,6 +1273,11 @@ begin
Result := FEventRecords[AIndex];
end;
function TVpGanttView.GetHourRec(AIndex: Integer): TVpGanttHourRec;
begin
Result := FHourRecords[AIndex];
end;
function TVpGanttView.GetMonthRec(AIndex: Integer): TVpGanttMonthRec;
begin
Result := FMonthRecords[AIndex];
@ -1132,6 +1305,13 @@ begin
Result := 0;
end;
{ Determines the number of hours between the first and last Gantt event.
This is the number of hour columns in the view. }
function TVpGanttView.GetNumHours: Integer;
begin
Result := GetNumDays * HoursPerDay;
end;
{ Determines the number of months (complete or partial) between the first and
last Gantt event. }
function TVpGanttView.GetNumMonths: Integer;
@ -1267,6 +1447,16 @@ begin
end;
end;
function TVpGanttView.HourMode: Boolean;
begin
Result := (gchHour in FColHeaderAttributes.Visible);
end;
function TVpGanttView.HoursPerDay: Integer;
begin
Result := ord(FEndHour) - ord(FStartHour) + 1;
end;
procedure TVpGanttView.Init;
begin
CalcRowHeight;
@ -1274,14 +1464,19 @@ begin
GetEventDateRange(FFirstDate, FLastDate);
GetRealEventDateRange(FRealStartDate, FRealEndDate);
if HourMode then
FColCount := GetNumHours
else
FColCount := GetNumDays;
FRowCount := GetNumEvents;
PopulateHourRecords;
PopulateDayRecords;
PopulateWeekRecords;
PopulateMonthRecords;
PopulateEventRecords;
end;
{ Checks whether the specified date belongs to the specified event.
The function returns true if the event begins before or at the date and ends
at or after it. }
@ -1324,23 +1519,34 @@ procedure TVpGanttView.KeyDown(var Key: Word; Shift: TShiftState);
procedure ScrollRows(ADelta: Integer);
begin
SetActiveRow(FActiveRow + ADelta);
FActiveRow := FActiveRow + ADelta;
if FActiveRow < 0 then FActiveRow := 0;
if FActiveRow >= RowCount then FActiveRow := RowCount-1;
// SetActiveRow(FActiveRow + ADelta);
if FActiveRow <= FTopRow then
ScrollVertical(FActiveRow - FTopRow)
else
if FActiveRow >= FTopRow + FVisibleRows then
ScrollVertical(FActiveRow - (FTopRow + FVisibleRows) + 1);
SetActiveRow(FActiveRow);
end;
var
P: TPoint;
OneDay: Integer;
c: Integer;
begin
inherited;
if HourMode then
OneDay := HoursPerDay
else
OneDay := 1;
case Key of
VK_LEFT:
ScrollCols(-1);
ScrollCols(-OneDay);
VK_RIGHT:
ScrollCols(1);
ScrollCols(OneDay);
VK_DOWN:
ScrollRows(1);
VK_UP:
@ -1371,29 +1577,34 @@ begin
ActiveCol := ColCount-1;
ActiveRow := RowCount-1;
FLeftCol := ColCount - FVisibleCols;
if FLeftCol < 0 then FLeftCol := 0;
FTopRow := RowCount - FVisibleRows;
if FTopRow < 0 then FTopRow := 0;
end else
ScrollCols(FVisibleCols);
VK_NEXT:
if Shift = [ssCtrl] then // ctrl + page down
begin
ActiveRow := RowCount - 1;
ScrollRows(MaxInt);
end else
ScrollRows(FRowCount)
else
ScrollRows(FVisibleRows); // page down
VK_PRIOR:
if Shift = [ssCtrl] then // ctrl + page up
begin
ActiveRow := 0;
ScrollRows(-MaxInt);
end else
ScrollRows(-FRowCount)
else
ScrollRows(-FVisibleRows); // page up
VK_F10, VK_APPS:
if (ssShift in Shift) then
begin
P := GetClientOrigin;
if HourMode then
begin
P.X := P.X + FHourRecords[FActiveCol].Rect.Right;
P.Y := P.Y + FHourRecords[FActiveCol].Rect.Top;
end else
begin
P.X := P.X + FDayRecords[FActiveCol].Rect.Right;
P.Y := P.Y + FDayRecords[FActiveCol].Rect.Top;
end;
PopupMenu.Popup(P.X + 10, P.Y + 10);
end;
VK_RETURN:
@ -1420,9 +1631,20 @@ begin
0: Result := FDateFormat[0] <> DEFAULT_DAYFORMAT;
1: Result := FDateFormat[1] <> DEFAULT_MONTHFORMAT;
2: Result := FDateFormat[2] <> DEFAULT_MONTHFORMAT_SHORT;
3: Result := FDateFormat[3] <> DEFAULT_DAYFORMAT_HOURMODE;
end;
end;
function TVpGanttView.IsStoredEndHour: Boolean;
begin
Result := FEndHour <> DEFAULT_END_HOUR;
end;
function TVpGanttView.IsStoredStartHour: Boolean;
begin
Result := FStartHour <> DEFAULT_START_HOUR;
end;
procedure TVpGanttView.LoadLanguage;
var
item: TMenuItem;
@ -1484,7 +1706,6 @@ begin
HideHintWindow;
end;
procedure TVpGanttView.MouseMove(Shift: TShiftState; X, Y: Integer);
var
event: TVpEvent;
@ -1540,10 +1761,13 @@ begin
inc(y1, FMonthColHeaderHeight + FTextMargin);
if (gchWeek in FColHeaderAttributes.Visible) then
inc(y1, FWeekColHeaderHeight + FTextMargin);
if (gchHour in FColHeaderAttributes.Visible) then
y2 := y1 + FDayColHeaderHeight + FTextMargin
else
y2 := FTotalColHeaderHeight;
for i := 0 to High(FDayRecords) do
begin
x2 := x1 + ColWidth;
x2 := x1 + CalcDaysWidth(1);
FDayRecords[i].Rect := Rect(x1, y1, x2, y2);
FDayRecords[i].Date := FRealStartDate + i;
x1 := x2;
@ -1592,7 +1816,7 @@ begin
xh1 := 0;
xh2 := FixedColWidth;
y1 := FTotalColHeaderHeight;
totalWidth := GetNumDays * ColWidth;
totalWidth := CalcDaysWidth(GetNumDays);
for i := 0 to FEventRecords.Count-1 do
begin
eventRec := FEventRecords[i];
@ -1623,6 +1847,36 @@ begin
end;
end;
// Populates the array of TVpGanttRec records containing the hours of each day
// cell and the *unscrolled* cell rectangle coordinates.
procedure TVpGanttView.PopulateHourRecords;
var
i: Integer;
x1, y1, x2, y2: Integer;
divRes: Integer = 0;
modRes: Integer = 0;
begin
SetLength(FHourRecords, GetNumHours);
x1 := FixedColWidth;
y1 := 0;
if (gchMonth in FColHeaderAttributes.Visible) then
inc(y1, FMonthColHeaderHeight + FTextMargin);
if (gchWeek in FColHeaderAttributes.Visible) then
inc(y1, FWeekColHeaderHeight + FTextMargin);
if (gchDay in FColHeaderAttributes.Visible) then
inc(y1, FDayColHeaderHeight + FTextMargin);
y2 := FTotalColHeaderHeight;
for i := 0 to High(FHourRecords) do
begin
x2 := x1 + ColWidth;
FHourRecords[i].Rect := Rect(x1, y1, x2, y2);
DivMod(i, HoursPerDay, divRes, modRes);
FHourRecords[i].Date := FRealStartDate + divRes;
FHourRecords[i].Hour := ord(FStartHour) + modRes;
x1 := x2;
end;
end;
procedure TVpGanttView.PopulateMonthRecords;
var
i, n: Integer;
@ -1660,7 +1914,7 @@ begin
nDays := DaysInMonth(dm);
if dm + nDays > FRealEndDate then
nDays := trunc(FRealEndDate) - trunc(dm) + 1;
x2 := x1 + nDays * ColWidth;
x2 := x1 + CalcDaysWidth(nDays);
FMonthRecords[i].Rect := Rect(x1, y1, x2, y2);
FMonthRecords[i].Date := dm;
dm := IncMonth(dm, 1);
@ -1670,7 +1924,7 @@ begin
begin
// Date interval is within the same month
nDays := DayOf(FRealEndDate) - DayOf(FRealStartDate) + 1;
x2 := x1 + nDays * ColWidth;
x2 := x1 + CalcDaysWidth(nDays);
FMonthRecords[0].Rect := Rect(x1, y1, x2, y2);
FMonthRecords[0].Date := FRealStartDate;
end;
@ -1711,7 +1965,7 @@ begin
if dt2 > FRealEndDate then
dt2 := FRealEndDate;
x2 := x1 + (trunc(dt2) - trunc(dt1) + 1) * FColWidth;
x2 := x1 + CalcDaysWidth(trunc(dt2) - trunc(dt1) + 1);
FWeekRecords[0].Rect := Rect(x1, y1, x2, y2);
FWeekRecords[0].Date := dt1;
FWeekRecords[0].WeekNo := WeekOfTheYear(dt1);
@ -1721,7 +1975,7 @@ begin
dt1 := dt2 + 1;
dt2 := Min(dt1 + 6, FRealEndDate);
x1 := x2;
x2 := x1 + (trunc(dt2) - trunc(dt1) + 1) * FColWidth;
x2 := x1 + CalcDaysWidth(trunc(dt2) - trunc(dt1) + 1);
FWeekRecords[i].Rect := Rect(x1, y1, x2, y2);
FWeekRecords[i].Date := dt1;
FWeekRecords[i].WeekNo := WeekOfTheYear(dt1);
@ -1764,7 +2018,9 @@ procedure TVpGanttView.FixDesignFontsPPI(const ADesignTimePPI: Integer);
begin
inherited;
DoFixDesignFontPPI(ColHeaderAttributes.MonthFont, ADesignTimePPI);
DoFixDesignFontPPI(ColHeaderAttributes.WeekFont, ADesignTimePPI);
DoFixDesignFontPPI(ColHeaderAttributes.DayFont, ADesignTimePPI);
DoFixDesignFontPPI(ColHeaderAttributes.HourFont, ADesignTimePPI);
DoFixDesignFontPPI(RowHeaderAttributes.EventFont, ADesignTimePPI);
end;
@ -1773,7 +2029,9 @@ procedure TVpGanttView.ScaleFontsPPI(const AToPPI: Integer;
begin
inherited;
DoScaleFontPPI(ColHeaderAttributes.MonthFont, AToPPI, AProportion);
DoScaleFontPPI(ColHeaderAttributes.WeekFont, AToPPI, AProportion);
DoScaleFontPPI(ColHeaderAttributes.DayFont, AToPPI, AProportion);
DoScaleFontPPI(ColHeaderAttributes.HourFont, AToPPI, AProportion);
DoScaleFontPPI(RowHeaderAttributes.EventFont, AToPPI, AProportion);
end;
{$ELSEIF VP_LCL_SCALING = 1}
@ -1781,34 +2039,51 @@ procedure TVpGantView.ScaleFontsPPI(const AProportion: Double);
begin
inherited;
DoScaleFontPPI(ColHeaderAttributes.MonthFont, AProportion);
DoScaleFontPPI(ColHeaderAttributes.WeekFont, AProportion);
DoScaleFontPPI(ColHeaderAttributes.DayFont, AProportion);
DoScaleFontPPI(ColHeaderAttributes.HourFont, AProportion);
DoScaleFontPPI(RowHeadAttributes.EventFont, AProportion);
end;
{$ENDIF}
procedure TVpGanttView.ScrollDateIntoView(ADate: TDateTime);
var
nCols: Integer;
begin
if (FRealStartDate = 0) or (FRealStartDate = NO_DATE) then
exit;
if HourMode then
nCols := GetNumHours
else
nCols := GetNumDays;
if ADate < FRealStartDate then
begin
FRealStartDate := DatePart(ADate);
FColCount := GetNumDays;
FColCount := nCols;
SetLeftCol(-MaxInt);
end else
if ADate > FRealEndDate then
begin
FRealEndDate := DatePart(ADate);
FColCount := GetNumDays;
FColCount := nCols;
SetLeftCol(FColCount - 1 - FVisibleCols);
end else
if ADate < FRealStartDate + FLeftCol then
SetLeftCol(trunc(ADate) - trunc(FRealStartDate))
begin
if HourMode then
SetLeftCol((trunc(ADate) - trunc(FRealStartDate))*HoursPerDay)
else
SetLeftCol(trunc(ADate) - trunc(FRealStartDate));
end else
if ADate > FRealStartDate + FVisibleCols then
SetLeftCol(trunc(ADate) - FVisibleCols)
begin
if HourMode then
SetLeftCol(trunc(ADate*HoursPerDay) - FVisibleCols)
else
SetLeftCol(trunc(ADate) - FVisibleCols);
end else
exit;
Invalidate;
end;
@ -1837,6 +2112,7 @@ var
eventRect, dayRect: TRect;
dt: TDateTime;
event: TVpEvent;
c: Integer;
begin
if AValue <= 0 then
FActiveCol := 0
@ -1845,8 +2121,9 @@ begin
else
FActiveCol := AValue;
dt := DayRecords[FActiveCol].Date;
dayRect := DayRecords[FActiveCol].Rect;
c := ColToDateIndex(FActiveCol);
dt := DayRecords[c].Date;
dayRect := DayRecords[c].Rect;
event := EventRecords[FActiveRow]^.Event;
eventRect := EventRecords[FActiveRow]^.EventRect;
@ -1862,7 +2139,12 @@ begin
end;
procedure TVpGanttView.SetActiveDate(AValue: TDateTime);
var
days: Integer;
begin
if FColHeaderAttributes = nil then // Needed for HourMode
exit;
if FActiveDate <> DatePart(AValue) then begin
FActiveDate := DatePart(AValue);
@ -1870,7 +2152,11 @@ begin
Populate;
ScrollDateIntoView(FActiveDate);
FActiveCol := trunc(FActiveDate) - trunc(FRealStartDate);
days := trunc(FActiveDate) - trunc(FRealStartDate);
if HourMode then
FActiveCol := days * HoursPerDay
else
FActiveCol := days;
Invalidate;
@ -1899,6 +2185,7 @@ var
eventRect, dayRect: TRect;
event: TVpEvent;
dt: TDateTime;
c: Integer;
begin
if AValue < 0 then
FActiveRow := 0
@ -1909,8 +2196,9 @@ begin
event := EventRecords[FActiveRow]^.Event;
eventRect := EventRecords[FActiveRow]^.EventRect;
dt := DayRecords[FActiveCol].Date;
dayRect := DayRecords[FActiveCol].Rect;
c := ColToDateIndex(FActiveCol);
dt := DayRecords[c].Date;
dayRect := DayRecords[c].Rect;
dayRect.Top := eventRect.Top;
dayRect.Bottom := eventRect.Bottom;
@ -1957,6 +2245,15 @@ begin
end;
end;
procedure TVpGanttView.SetEndHour(AValue: TVpHours);
begin
if FEndHour <> AValue then
begin
FEndHour := AValue;
Invalidate;
end;
end;
procedure TVpGanttView.SetFixedColWidth(AValue: Integer);
begin
if FFixedColWidth <> AValue then
@ -2046,6 +2343,15 @@ begin
end;
end;
procedure TVpGanttView.SetStartHour(AValue: TVpHours);
begin
if FStartHour <> AValue then
begin
FStartHour := AValue;
Invalidate;
end;
end;
procedure TVpGanttView.SetTextMargin(AValue: Integer);
begin
if FTextMargin <> AValue then

View File

@ -13,6 +13,7 @@ type
private
FGanttView: TVpGanttView;
FHourFont: TFont;
FDayFont: TFont;
FMonthFont: TFont;
FWeekFont: TFont;
@ -43,6 +44,7 @@ type
procedure DrawDayColHeaders;
procedure DrawEvents;
procedure DrawGrid;
procedure DrawHourColHeaders;
procedure DrawMonthColHeaders;
procedure DrawRowHeader;
procedure DrawSpecialDays;
@ -87,6 +89,7 @@ var
dx, dy: Integer;
bs: TBrushStyle;
pw: Integer;
c: Integer;
begin
with FGanttView do
begin
@ -95,7 +98,10 @@ begin
if (ActiveCol < 0) or (ActiveCol >= ColCount) then
exit;
dayRec := DayRecords[ActiveCol];
c := ActiveCol;
if HourMode then
c := c div HoursPerDay;
dayRec := DayRecords[c];
eventRec := EventRecords[ActiveRow];
dx := LeftCol * FScaledColWidth;
@ -184,6 +190,9 @@ begin
// Draw the day column headers
DrawDayColHeaders;
// Draw the hour column headers
DrawHourColHeaders;
end;
procedure TVpGanttViewPainter.DrawDayColHeaders;
@ -191,8 +200,9 @@ var
dayRec: TVpGanttDayRec;
dx: Integer;
strH, strLen: Integer;
str: String;
fmt, str: String;
i, n: Integer;
yLineBottom: Integer;
R, R1: TRect;
P: TPoint;
begin
@ -239,6 +249,10 @@ begin
// No dividing line at last day of month because it already has been
// drawn as the month divider.
if FGanttView.HourMode then
yLineBottom := FScaledTotalColHeaderHeight
else
yLineBottom := R.Bottom;
if (DayOf(dayRec.Date) <> DaysInMonth(dayRec.Date)) or
([gchWeek, gchDay] * FGanttView.ColHeaderAttributes.Visible = [gchWeek, gchDay]) then
begin
@ -246,19 +260,23 @@ begin
DrawBevelLine(
RenderCanvas,
TPSRotatePoint(Angle, RenderIn, Point(R.Right, R.Top)),
TPSRotatePoint(Angle, RenderIn, Point(R.Right, R.Bottom)),
TPSRotatePoint(Angle, RenderIn, Point(R.Right, yLineBottom)),
BevelShadow,
BevelHighlight
)
else
begin
TPSMoveTo(RenderCanvas, Angle, RenderIn, R.Right, R.Top);
TPSLineTo(RenderCanvas, Angle, RenderIn, R.Right, R.Bottom);
TPSLineTo(RenderCanvas, Angle, RenderIn, R.Right, yLineBottom);
end;
end;
// Paint day name
str := FormatDateTime(FGanttView.DayFormat, dayRec.Date);
if FGanttView.HourMode then
fmt := FGanttView.Dayformat_HourMode
else
fmt := FGanttView.DayFormat;
str := FormatDateTime(fmt, dayRec.Date);
strLen := RenderCanvas.TextWidth(str);
P := Point((R.Left + R.Right - strLen) div 2, (R.Top + R.Bottom - strH) div 2);
TPSTextOut(RenderCanvas, Angle, RenderIn, P.X, P.Y, str);
@ -321,6 +339,7 @@ begin
RenderCanvas.Pen.Color := cat.Color;
RenderCanvas.Pen.Width := round(Scale);
RenderCanvas.Brush.Color := cat.BackgroundColor;
//RenderCanvas.Brush.Style := bsSolid;
TPSRectangle(RenderCanvas, Angle, RenderIn, R);
end;
end;
@ -399,6 +418,84 @@ begin
end;
end;
procedure TVpGanttViewPainter.DrawHourColHeaders;
var
hourRec: TVpGanttHourRec;
dx: Integer;
strH, strLen: Integer;
str: String;
i, n: Integer;
R, R1: TRect;
P: TPoint;
begin
if not (gchHour in FGanttView.ColHeaderAttributes.Visible) then
exit;
// Offset due to scrolling
dx := FGanttView.LeftCol * FScaledColWidth;
// Draw hour captions (always centered) and dividing lines (always at right side).
RenderCanvas.Font.Assign(FHourFont);
strH := RenderCanvas.TextHeight('Tg');
n := FGanttView.NumHours;
for i := 0 to n - 1 do
begin
hourRec := FGanttView.HourRecords[i];
R := ScaleRect(hourRec.Rect);
OffsetRect(R, -dx, 0);
if R.Left < RealLeft + FScaledFixedColWidth then
Continue;
// In sdmHeader SpecialDayMode we must repaint the background of the
// day cells in the color of the special day (weekend/holiday)
if (FGanttView.SpecialDayMode = sdmHeader) then
begin
R1 := R;
if FGanttView.DrawingStyle = ds3D then
begin
inc(R1.Left, 2);
dec(R1.Bottom);
end else
inc(R1.Left);
if (gvoWeekends in FGanttView.Options) and IsWeekend(hourRec.Date) then
begin;
RenderCanvas.Brush.Color := FGanttView.Weekendcolor;
TPSFillRect(RenderCanvas, Angle, RenderIn, R1);
end else
if (gvoHolidays in FGanttView.Options) and FGanttView.IsHoliday(hourRec.Date, str) then
begin
RenderCanvas.Brush.Color := FGanttView.HolidayColor;
TPSFillRect(RenderCanvas, Angle, RenderIn, R1);
end;
end;
// No dividing line at last hour of day because it already has been
// drawn as the day divider.
if hourRec.Hour <> 23 then
begin
if FGanttView.DrawingStyle = ds3D then
DrawBevelLine(
RenderCanvas,
TPSRotatePoint(Angle, RenderIn, Point(R.Right, R.Top)),
TPSRotatePoint(Angle, RenderIn, Point(R.Right, R.Bottom)),
BevelShadow,
BevelHighlight
)
else
begin
TPSMoveTo(RenderCanvas, Angle, RenderIn, R.Right, R.Top);
TPSLineTo(RenderCanvas, Angle, RenderIn, R.Right, R.Bottom);
end;
end;
// Paint hour value
str := IntToStr(hourRec.Hour);
strLen := RenderCanvas.TextWidth(str);
P := Point((R.Left + R.Right - strLen) div 2, (R.Top + R.Bottom - strH) div 2);
TPSTextOut(RenderCanvas, Angle, RenderIn, P.X, P.Y, str);
end;
end;
procedure TVpGanttViewPainter.DrawMonthColHeaders;
var
dx: Integer;
@ -710,6 +807,7 @@ begin
RealLineColor := ColorToRGB(FGanttView.LineColor);
end;
FHourFont := FGanttView.ColHeaderAttributes.HourFont;
FDayFont := FGanttView.ColHeaderAttributes.DayFont;
FMonthFont := FGanttView.ColHeaderAttributes.MonthFont;
FWeekFont := FGanttView.ColHeaderAttributes.WeekFont;