Componentes.Terceros.DevExp.../internal/x.46/1/ExpressQuantumGrid 6/Sources/cxGridCommon.pas
2009-10-27 17:09:30 +00:00

614 lines
18 KiB
ObjectPascal

{********************************************************************}
{ }
{ Developer Express Visual Component Library }
{ ExpressQuantumGrid }
{ }
{ Copyright (c) 1998-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 EXPRESSQUANTUMGRID 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 cxGridCommon;
{$I cxVer.inc}
interface
uses
Windows, Messages, TypInfo, Classes, Graphics, Controls, ComCtrls,
cxClasses, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters,
cxTreeView;
const
ScxGridPrefixName = 'TcxGrid';
cxGridInvisibleCoordinate = 30000{100000};
cxGridCellTextOffset = 2;
cxGridEditOffset = 1;
cxGridHeaderTextOffset = 2;
cxGridDesignViewBorderColor = 3577330;
cxGridDesignViewColor = 9295359;
cxGridDesignViewHotColor = 6862841;//6078705;
cxGridDesignSelectedBorderColor = 11504744;//clWhite;
cxGridDesignSelectedColor = 14991773;
cxGridDesignSelectedHotBorderColor = clDkGray;//12033927;
cxGridDesignSelectedHotColor = 14065255;//13747387;
type
TcxGridCellState = (gcsNone, gcsSelected, gcsPressed);
TcxGridClassEnumeratorProc = procedure(AClass: TClass) of object;
{ custom change }
TcxCustomGridChange = class
private
FControl: TcxControl;
public
function CanExecuteWhenLocked: Boolean; virtual;
procedure Execute; virtual; abstract;
function IsCompatibleWith(AChange: TcxCustomGridChange): Boolean; virtual;
function IsCumulative: Boolean; virtual;
function IsEqual(AChange: TcxCustomGridChange): Boolean; virtual;
function IsLockable: Boolean; virtual;
property Control: TcxControl read FControl write FControl; // TcxCustomGrid
end;
{ custom drag open info }
TcxCustomGridDragOpenInfo = class
public
function Equals(AInfo: TcxCustomGridDragOpenInfo): Boolean;{$IFDEF DELPHI12} reintroduce;{$ENDIF} virtual;
procedure Run; virtual; abstract;
end;
{ options tree view }
TcxGridOptionsTreeViewGetTypeItemCaptionFunction = function(ATypeItem: Integer): string;
TcxGridOptionsTreeViewItemKind = (otikCategory, otikCheckBox, otikRadioButton);
TcxGridOptionsTreeView = class(TcxTreeView)
private
FItemValuesUpdateLocked: Boolean;
FMaxID: Integer;
procedure WMDestroy(var Message: TWMDestroy); message WM_DESTROY;
procedure CustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
State: TCustomDrawState; var DefaultDraw: Boolean);
procedure GetNodeImageIndex(Sender: TObject; Node: TTreeNode);
procedure GetNodeSelectedImageIndex(Sender: TObject; Node: TTreeNode);
protected
procedure CreateWnd; override;
procedure LookAndFeelChanged(Sender: TcxLookAndFeel; AChangedValues: TcxLookAndFeelValues); override;
function AddItem(AParentID, AID: Integer; const ACaption: string;
AKind: TcxGridOptionsTreeViewItemKind): Integer; virtual;
procedure ClearItems;
function FindNodeByID(AID: Integer): TTreeNode;
function GetItemImageIndex(AKind: TcxGridOptionsTreeViewItemKind; AChecked: Boolean): Integer;
function GetNodeID(ANode: TTreeNode): Integer;
function GetNodeKind(ANode: TTreeNode): TcxGridOptionsTreeViewItemKind;
function GetNodeParentID(ANode: TTreeNode): Integer;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure NodeClicked(ANode: TTreeNode); virtual;
procedure RefreshImages;
procedure RefreshItemImageIndexes;
procedure ResetMaxID;
function CalculateImagesSize: TSize; virtual;
procedure DrawImage(ACanvas: TcxCanvas; const ARect: TRect;
AItemKind: TcxGridOptionsTreeViewItemKind; AChecked: Boolean); virtual;
function GetCategoryBitmap: TBitmap;
function GetCategorySize: TSize; virtual;
function GetCheckBoxSize: TSize; virtual;
function GetRadioButtonSize: TSize; virtual;
procedure AddItems; virtual; abstract;
function IsItemChecked(AParentID, AID: Integer): Boolean; virtual; abstract;
procedure ItemClicked(AParentID, AID: Integer); virtual; abstract;
property ItemValuesUpdateLocked: Boolean read FItemValuesUpdateLocked
write FItemValuesUpdateLocked;
property MaxID: Integer read FMaxID;
public
constructor Create(AOwner: TComponent); override;
function AddCategory(AParentID, AID: Integer; const ACaption: string): Integer;
function AddCheckBox(AParentID, AID: Integer; const ACaption: string): Integer;
function AddRadioButton(AParentID, AID: Integer; const ACaption: string): Integer;
procedure AddRadioButtons(AParentID: Integer; ATypeInfo: PTypeInfo;
AGetTypeItemCaption: TcxGridOptionsTreeViewGetTypeItemCaptionFunction);
procedure RefreshItems;
procedure RefreshItemValues;
end;
function GetValidName(AComponent: TComponent; const AName: string;
AIsBaseName: Boolean = False): string;
procedure GetCellTextAreaSize(var ATextSize: Integer);
function GridCellStateToButtonState(ACellState: TcxGridCellState): TcxButtonState;
implementation
{$R cxGrid.res}
uses
cxGeometry, Math, Forms, SysUtils, cxLibraryConsts;
{ TcxCustomGridChange }
function TcxCustomGridChange.CanExecuteWhenLocked: Boolean;
begin
Result:= True;
end;
function TcxCustomGridChange.IsCompatibleWith(AChange: TcxCustomGridChange): Boolean;
begin
Result := False;
end;
function TcxCustomGridChange.IsCumulative: Boolean;
begin
Result := True;
end;
function TcxCustomGridChange.IsEqual(AChange: TcxCustomGridChange): Boolean;
begin
Result := ClassType = AChange.ClassType;
end;
function TcxCustomGridChange.IsLockable: Boolean;
begin
Result := True;
end;
{ TcxCustomGridDragOpenInfo }
function TcxCustomGridDragOpenInfo.Equals(AInfo: TcxCustomGridDragOpenInfo): Boolean;
begin
Result := ClassType = AInfo.ClassType;
end;
{ TcxGridOptionsTreeView }
const
OptionsTreeViewMaxInternalID = 99;
type
TOptionTreeNodeData = class
ID: Integer;
Kind: TcxGridOptionsTreeViewItemKind;
constructor Create(AID: Integer; AKind: TcxGridOptionsTreeViewItemKind);
end;
constructor TOptionTreeNodeData.Create(AID: Integer; AKind: TcxGridOptionsTreeViewItemKind);
begin
inherited Create;
ID := AID;
Kind := AKind;
end;
constructor TcxGridOptionsTreeView.Create(AOwner: TComponent);
begin
inherited;
ReadOnly := True;
ShowButtons := False;
ShowRoot := False;
Images := TImageList.Create(Self);
OnCustomDrawItem := CustomDrawItem;
OnGetImageIndex := GetNodeImageIndex;
OnGetSelectedIndex := GetNodeSelectedImageIndex;
ResetMaxID;
end;
procedure TcxGridOptionsTreeView.WMDestroy(var Message: TWMDestroy);
begin
ClearItems;
inherited;
end;
procedure TcxGridOptionsTreeView.CustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
State: TCustomDrawState; var DefaultDraw: Boolean);
var
R: TRect;
begin
// to fix the bug in VCL tree view
Sender.Canvas.Font.Name := 'System';
Sender.Canvas.Font.Name := Font.Name;
if GetNodeKind(Node) = otikCategory then
begin
if Node.Level = 0 then
begin
R := Node.DisplayRect(False);
R.Left := Node.DisplayRect(True).Left;
if not (cdsSelected in State) then
Sender.Canvas.Brush.Color := clBtnShadow;
Sender.Canvas.FillRect(R);
end;
Sender.Canvas.Font.Style := [fsBold];
end;
end;
procedure TcxGridOptionsTreeView.GetNodeImageIndex(Sender: TObject; Node: TTreeNode);
begin
if GetNodeKind(Node) = otikCategory then
Node.ImageIndex := GetItemImageIndex(otikCategory, Node.Expanded);
end;
procedure TcxGridOptionsTreeView.GetNodeSelectedImageIndex(Sender: TObject; Node: TTreeNode);
begin
if GetNodeKind(Node) = otikCategory then
Node.SelectedIndex := GetItemImageIndex(otikCategory, Node.Expanded);
end;
procedure TcxGridOptionsTreeView.CreateWnd;
begin
inherited;
RefreshImages;
RefreshItems;
end;
procedure TcxGridOptionsTreeView.LookAndFeelChanged(Sender: TcxLookAndFeel;
AChangedValues: TcxLookAndFeelValues);
begin
inherited;
if not FIsCreating then
RefreshImages;
end;
function TcxGridOptionsTreeView.AddItem(AParentID, AID: Integer;
const ACaption: string; AKind: TcxGridOptionsTreeViewItemKind): Integer;
var
AParent: TTreeNode;
begin
if AParentID = -1 then
AParent := nil
else
AParent := FindNodeByID(AParentID);
if AID = -1 then
begin
Inc(FMaxID);
AID := FMaxID;
end
else
FMaxID := Max(FMaxID, AID);
Result := AID;
Items.AddChildObject(AParent, ACaption, TOptionTreeNodeData.Create(AID, AKind));
end;
procedure TcxGridOptionsTreeView.ClearItems;
var
I: Integer;
begin
for I := 0 to Items.Count - 1 do
TOptionTreeNodeData(Items[I].Data).Free;
Items.Clear;
end;
function TcxGridOptionsTreeView.FindNodeByID(AID: Integer): TTreeNode;
var
I: Integer;
begin
for I := 0 to Items.Count - 1 do
begin
Result := Items[I];
if GetNodeID(Result) = AID then Exit;
end;
Result := nil;
end;
function TcxGridOptionsTreeView.GetItemImageIndex(AKind: TcxGridOptionsTreeViewItemKind;
AChecked: Boolean): Integer;
begin
Result := 2 * Ord(AKind) + Ord(AChecked);
end;
function TcxGridOptionsTreeView.GetNodeID(ANode: TTreeNode): Integer;
begin
Result := TOptionTreeNodeData(ANode.Data).ID;
end;
function TcxGridOptionsTreeView.GetNodeKind(ANode: TTreeNode): TcxGridOptionsTreeViewItemKind;
begin
Result := TOptionTreeNodeData(ANode.Data).Kind;
end;
function TcxGridOptionsTreeView.GetNodeParentID(ANode: TTreeNode): Integer;
begin
if ANode.Parent = nil then
Result := -1
else
Result := GetNodeID(ANode.Parent);
end;
procedure TcxGridOptionsTreeView.KeyDown(var Key: Word; Shift: TShiftState);
begin
inherited;
if (Key = VK_SPACE) and (Selected <> nil) then
NodeClicked(Selected);
end;
procedure TcxGridOptionsTreeView.MouseDown(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
ANode: TTreeNode;
begin
if Button = mbLeft then
begin
ANode := GetNodeAt(X, Y);
if (ANode <> nil) and (htOnItem in GetHitTestInfoAt(X, Y)) then
NodeClicked(ANode);
end;
inherited;
end;
procedure TcxGridOptionsTreeView.NodeClicked(ANode: TTreeNode);
begin
ItemValuesUpdateLocked := True;
try
ItemClicked(GetNodeParentID(ANode), GetNodeID(ANode));
finally
ItemValuesUpdateLocked := False;
end;
RefreshItemValues;
end;
procedure TcxGridOptionsTreeView.RefreshImages;
var
AImage: TBitmap;
AImageCanvas: TcxCanvas;
AImageRect: TRect;
AItemKind: TcxGridOptionsTreeViewItemKind;
AChecked: Boolean;
begin
if IsDestroying then Exit;
Images.Clear;
with CalculateImagesSize do
begin
Images.Width := cx;
Images.Height := cy;
end;
AImage := TBitmap.Create;
try
AImage.Width := Images.Width;
AImage.Height := Images.Height;
AImageCanvas := TcxCanvas.Create(AImage.Canvas);
try
AImageRect := Rect(0, 0, AImage.Width, AImage.Height);
for AItemKind := Low(AItemKind) to High(AItemKind) do
for AChecked := Low(AChecked) to High(AChecked) do
begin
AImage.Canvas.Brush.Color := Color;
AImage.Canvas.FillRect(AImageRect);
DrawImage(AImageCanvas, AImageRect, AItemKind, AChecked);
Images.Add(AImage, nil);
end;
finally
AImageCanvas.Free;
end;
finally
AImage.Free;
end;
end;
procedure TcxGridOptionsTreeView.RefreshItemImageIndexes;
var
I: Integer;
ANode: TTreeNode;
begin
Items.BeginUpdate;
try
for I := 0 to Items.Count - 1 do
begin
ANode := Items[I];
ANode.ImageIndex := GetItemImageIndex(GetNodeKind(ANode),
IsItemChecked(GetNodeParentID(ANode), GetNodeID(ANode)));
ANode.SelectedIndex := ANode.ImageIndex;
end;
finally
Items.EndUpdate;
end;
end;
procedure TcxGridOptionsTreeView.ResetMaxID;
begin
FMaxID := OptionsTreeViewMaxInternalID;
end;
function TcxGridOptionsTreeView.CalculateImagesSize: TSize;
begin
Result := GetCategorySize;
Result.cx := Max(Result.cx, Max(GetCheckBoxSize.cx, GetRadioButtonSize.cx));
Result.cy := Max(Result.cy, Max(GetCheckBoxSize.cy, GetRadioButtonSize.cy));
end;
procedure TcxGridOptionsTreeView.DrawImage(ACanvas: TcxCanvas; const ARect: TRect;
AItemKind: TcxGridOptionsTreeViewItemKind; AChecked: Boolean);
var
R: TRect;
B: TBitmap;
begin
R := ARect;
case AItemKind of
otikCategory:
begin
R := cxRectCenter(R, GetCategorySize);
B := GetCategoryBitmap;
try
if AChecked then
ACanvas.RotateBitmap(B, raMinus90);
ACanvas.DrawGlyph(R.Left, R.Top, B);
finally
B.Free;
end;
end;
otikCheckBox:
begin
R := cxRectCenter(R, GetCheckBoxSize);
LookAndFeelPainter.DrawCheckButton(ACanvas, R, cxbsNormal, AChecked);
end;
otikRadioButton:
begin
R := cxRectCenter(R, GetRadioButtonSize);
LookAndFeelPainter.DrawRadioButton(ACanvas, R.Left, R.Top, cxbsNormal,
AChecked, False, ACanvas.Brush.Color);
end;
end;
end;
function TcxGridOptionsTreeView.GetCategoryBitmap: TBitmap;
begin
Result := TBitmap.Create;
Result.LoadFromResourceName(HInstance, 'CXGRIDOPTIONSTREEVIEWCATEGORYBITMAP');
end;
function TcxGridOptionsTreeView.GetCategorySize: TSize;
begin
with GetCategoryBitmap do
try
Result.cx := Width;
Result.cy := Height;
finally
Free;
end;
end;
function TcxGridOptionsTreeView.GetCheckBoxSize: TSize;
begin
Result := LookAndFeelPainter.CheckButtonSize;
end;
function TcxGridOptionsTreeView.GetRadioButtonSize: TSize;
begin
Result := LookAndFeelPainter.RadioButtonSize;
end;
function TcxGridOptionsTreeView.AddCategory(AParentID, AID: Integer;
const ACaption: string): Integer;
begin
Result := AddItem(AParentID, AID, ACaption, otikCategory);
end;
function TcxGridOptionsTreeView.AddCheckBox(AParentID, AID: Integer;
const ACaption: string): Integer;
begin
Result := AddItem(AParentID, AID, ACaption, otikCheckBox);
end;
function TcxGridOptionsTreeView.AddRadioButton(AParentID, AID: Integer;
const ACaption: string): Integer;
begin
Result := AddItem(AParentID, AID, ACaption, otikRadioButton);
end;
procedure TcxGridOptionsTreeView.AddRadioButtons(AParentID: Integer;
ATypeInfo: PTypeInfo; AGetTypeItemCaption: TcxGridOptionsTreeViewGetTypeItemCaptionFunction);
var
ATypeData: PTypeData;
I: Integer;
begin
if ATypeInfo.Kind <> tkEnumeration then Exit;
ATypeData := GetTypeData(ATypeInfo);
for I := ATypeData.MinValue to ATypeData.MaxValue do
AddRadioButton(AParentID, I, AGetTypeItemCaption(I));
end;
procedure TcxGridOptionsTreeView.RefreshItems;
begin
Items.BeginUpdate;
try
ClearItems;
ResetMaxID;
AddItems;
RefreshItemValues;
FullExpand;
TopItem := Items.GetFirstNode;
finally
Items.EndUpdate;
end;
end;
procedure TcxGridOptionsTreeView.RefreshItemValues;
begin
if not ItemValuesUpdateLocked then
RefreshItemImageIndexes;
end;
{ functions }
function GetValidName(AComponent: TComponent; const AName: string;
AIsBaseName: Boolean = False): string;
var
AOwner: TComponent;
I: Integer;
function GetNextName: string;
begin
Result := AName + IntToStr(I);
Inc(I);
end;
begin
Result := AName;
AOwner := AComponent.Owner;
if AOwner = nil then Exit;
I := 1;
if AIsBaseName then Result := GetNextName;
while AOwner.FindComponent(Result) <> nil do
Result := GetNextName;
end;
procedure GetCellTextAreaSize(var ATextSize: Integer);
begin
Inc(ATextSize, 2 * cxGridCellTextOffset);
end;
function GridCellStateToButtonState(ACellState: TcxGridCellState): TcxButtonState;
const
ButtonStates: array[TcxGridCellState] of TcxButtonState =
(cxbsNormal, cxbsHot, cxbsPressed);
begin
Result := ButtonStates[ACellState];
end;
initialization
crcxGridHorzSize := crcxHorzSize;
crcxGridVertSize := crcxVertSize;
crcxGridRemove := crcxRemove;
crcxGridNoDrop := crcxNoDrop;
crcxGridDrag := crcxDrag;
crcxGridMultiDrag := crcxDragMulti;
Screen.Cursors[crcxGridSelectRow] := LoadCursor(HInstance, 'CX_GRIDSELECTROWCURSOR');
end.