git-svn-id: https://192.168.0.254/svn/Componentes.Terceros.DevExpressVCL@63 05c56307-c608-d34a-929d-697000501d7a
8552 lines
250 KiB
ObjectPascal
8552 lines
250 KiB
ObjectPascal
|
|
{*******************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ ExpressInspector virtual control and base rows }
|
|
{ }
|
|
{ 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 }
|
|
{ }
|
|
{ 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 dxInspct;
|
|
|
|
interface
|
|
|
|
{$I dxInsVer.inc}
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
|
|
dxCntner, dxEditor, dxExEdtr, CommCtrl{$IFDEF DELPHI4}, ImgList{$ENDIF},
|
|
dxUtils, StdCtrls, ComCtrls, ExtCtrls{$IFDEF DELPHI6}, Variants{$ENDIF};
|
|
|
|
const
|
|
dxclInspectorGridColor = clBtnShadow;
|
|
dxclInspectorBackgroundColor = clBtnFace;
|
|
dxclInspectorValueFontColor = clNavy;
|
|
dxInspectorMaxResizeWidth = 2;
|
|
dxInspectorButtonSize = 9;
|
|
dxInspectorButtonExSize = 10;
|
|
dxInspectorLimitBandWidth = 20 * 2 + 3;
|
|
dxInspectorLimitColumnWidth = 20;
|
|
dxInspectorUndefinedValue = -10000;
|
|
// Cursors
|
|
crdxInspectorInsert = -1128;
|
|
crdxInspectorAddChild = -1129;
|
|
crdxInspectorAdd = -1130;
|
|
crdxInspectorHide = -1141;
|
|
crdxInspectorNoDrag = -1142;
|
|
CM_PREPARECUSTOMIZEFORM = WM_APP + 201;
|
|
CM_UPDATECUSTOMIZEFORM = WM_APP + 202;
|
|
|
|
type
|
|
{$IFNDEF DELPHI5}
|
|
TImageIndex = type Integer;
|
|
{$ENDIF}
|
|
|
|
{ TCustomdxInspector }
|
|
|
|
TCustomdxInspector = class;
|
|
|
|
TdxInspectorOption = (ioAutoBandCount, ioAutoWidth, ioBandSizing, ioColumnSizing,
|
|
ioDrawEndEllipsis, ioDynamicColumnSizing, ioEditing, ioEnterThrough,
|
|
ioRowAutoHeight, ioRowSizing, ioStoreToRegistry, ioTabThrough, ioTabs);
|
|
TdxInspectorOptions = set of TdxInspectorOption;
|
|
|
|
TdxInspectorState = (isNormal, isColumnSizing, isNodeDown, isNodeDragging,
|
|
isBandSizing, isRowSizing);
|
|
|
|
TdxInspectorHitTest = (ihtNowhere, ihtColumnEdge, ihtIndent, ihtButton,
|
|
ihtImage, ihtDisplayLabel, ihtLabel, ihtOutside,
|
|
ihtBandSeparator, ihtComplexRowSeparator, ihtRowEdge);
|
|
|
|
TdxInspectorNodeAttachMode = (inaAdd, inaAddChild, inaInsert);
|
|
|
|
TdxInspectorPaintStyle = (ipsStandard, ipsSimple, ipsExtended,
|
|
ipsNET, ipsCategorized);
|
|
|
|
{ TdxInspectorNode }
|
|
|
|
TdxInspectorNode = class
|
|
private
|
|
FDeleting: Boolean;
|
|
FExpanded: Boolean;
|
|
FList: TList;
|
|
FOwner: TCustomdxInspector;
|
|
FParent: TdxInspectorNode;
|
|
function GetAbsoluteIndex: Integer;
|
|
function GetCount: Integer;
|
|
function GetFocused: Boolean;
|
|
function GetIndex: Integer;
|
|
function GetIsLast: Boolean;
|
|
function GetIsNodeVisible: Boolean;
|
|
function GetItem(Index: Integer): TdxInspectorNode;
|
|
function GetLevel: Integer;
|
|
function GetNodeHasChildren: Boolean;
|
|
procedure SetExpanded(Value: Boolean);
|
|
procedure SetFocused(Value: Boolean);
|
|
public
|
|
constructor Create(AOwner: TCustomdxInspector);
|
|
destructor Destroy; override;
|
|
function AddChild: TdxInspectorNode;
|
|
procedure Collapse(Recurse: Boolean);
|
|
procedure DeleteChildren;
|
|
procedure Expand(Recurse: Boolean);
|
|
function GetLastNode: TdxInspectorNode;
|
|
function GetNextNode: TdxInspectorNode;
|
|
function GetPriorNode: TdxInspectorNode;
|
|
function GetPriorParentNode: TdxInspectorNode;
|
|
function HasAsParent(Value: TdxInspectorNode): Boolean;
|
|
function IndexOf(Value: TdxInspectorNode): Integer;
|
|
function InsertChild(BeforeNode: TdxInspectorNode): TdxInspectorNode;
|
|
procedure MakeVisible;
|
|
procedure MoveTo(Destination: TdxInspectorNode; Mode: TdxInspectorNodeAttachMode);
|
|
property AbsoluteIndex: Integer read GetAbsoluteIndex;
|
|
property Count: Integer read GetCount;
|
|
property Deleting: Boolean read FDeleting;
|
|
property Expanded: Boolean read FExpanded write SetExpanded;
|
|
property Focused: Boolean read GetFocused write SetFocused;
|
|
property HasChildren: Boolean read GetNodeHasChildren;
|
|
property Index: Integer read GetIndex;
|
|
property IsLast: Boolean read GetIsLast;
|
|
property IsVisible: Boolean read GetIsNodeVisible;
|
|
property Items[Index: Integer]: TdxInspectorNode read GetItem; default;
|
|
property Level: Integer read GetLevel;
|
|
property Owner: TCustomdxInspector read FOwner;
|
|
property Parent: TdxInspectorNode read FParent;
|
|
end;
|
|
|
|
TdxInspectorHitInfo = record
|
|
Node: TdxInspectorNode;
|
|
Row: Integer;
|
|
hitType: TdxInspectorHitTest;
|
|
// Band
|
|
BandIndex: Integer;
|
|
// ComplexRow
|
|
ComplexRowIndex: Integer; // for complex row <> -1
|
|
ComplexRowRect: TRect;
|
|
end;
|
|
|
|
TdxInspectorButtonKind = (ibkNone, ibkPlus, ibkMinus);
|
|
|
|
{ Content Draw Info}
|
|
|
|
TdxInspectorRowInfo = record
|
|
Node: TdxInspectorNode;
|
|
RowHeight: Integer;
|
|
end;
|
|
|
|
PdxInspectorRowsInfo = ^TdxInspectorRowsInfo;
|
|
TdxInspectorRowsInfo = array [0..MaxInt div SizeOf(TdxInspectorRowInfo) - 1] of TdxInspectorRowInfo;
|
|
|
|
TdxInspectorBandInfo = record
|
|
BandIndex: Integer;
|
|
BandRect: TRect;
|
|
BandContentRect: TRect;
|
|
BandSeparatorRect: TRect;
|
|
EmptyRect: TRect;
|
|
PartRowVisible: Boolean;
|
|
RowCount: Integer;
|
|
RowsInfo: PdxInspectorRowsInfo;
|
|
end;
|
|
|
|
PdxInspectorBandsInfo = ^TdxInspectorBandsInfo;
|
|
TdxInspectorBandsInfo = array [0..MaxInt div SizeOf(TdxInspectorBandInfo) - 1] of TdxInspectorBandInfo;
|
|
|
|
TdxInspectorContentDrawInfo = record
|
|
CRect: TRect;
|
|
BandCount: Integer;
|
|
BandsInfo: PdxInspectorBandsInfo;
|
|
EmptyRect: TRect;
|
|
end;
|
|
|
|
{ Draw Info}
|
|
|
|
TdxInspectorDrawInfo = record
|
|
IndentRect: TRect;
|
|
ButtonRect: TRect;
|
|
ImageRect: TRect;
|
|
DisplayRect: TRect;
|
|
ValueRect: TRect;
|
|
ButtonKind: TdxInspectorButtonKind;
|
|
end;
|
|
|
|
TdxInspectorCellViewData = class
|
|
Cell_Brush: HBRUSH;
|
|
Cell_Font: HFONT;
|
|
Cell_BkColor: TColor;
|
|
Cell_TextColor: TColor;
|
|
Cell_Alignment: TAlignment;
|
|
Cell_Text: string;
|
|
Cell_TextLength: Integer;
|
|
Cell_Selected: Boolean;
|
|
Cell_DrawEndEllipsis: Boolean;
|
|
Cell_Node: TdxInspectorNode;
|
|
Cell_HotTrackNode: Boolean;
|
|
Cell_Rect: TRect;
|
|
end;
|
|
|
|
TdxInplaceInspectorEdit = class(TdxInplaceEdit)
|
|
public
|
|
property Text;
|
|
end;
|
|
|
|
TdxInspectorChangeNodeEvent = procedure(Sender: TObject; OldNode, Node: TdxInspectorNode) of object;
|
|
|
|
TCustomdxInspector = class(TCustomdxContainer)
|
|
private
|
|
FLockUpdate: Integer;
|
|
FLockExpanded: Integer;
|
|
FNodeList: TList;
|
|
FFocused: TdxInspectorNode;
|
|
FTopVisibleNode: TdxInspectorNode;
|
|
FBandCount: Integer;
|
|
FBandSeparatorWidth: Integer;
|
|
FBandWidth: Integer;
|
|
FBorderStyle: TBorderStyle;
|
|
FComplexRowSeparator: string;
|
|
FComplexRowSeparatorWidth, FCaptionComplexRowSeparatorWidth: Integer;
|
|
FDividerPos, FSizingPos, FSaveSizingPos, FSizingBandIndex: Integer;
|
|
FHotTrackNode: TdxInspectorNode;
|
|
FSizingNode: TdxInspectorNode;
|
|
FDividerPosSave: TPoint; // X - DividerPos, Y - Width
|
|
FGridColor: TColor;
|
|
FGroupColor: TColor;
|
|
FGroupGridColor: TColor;
|
|
FLeftBandIndex: Integer;
|
|
FValueFontColor: TColor;
|
|
FRowHeight: Integer;
|
|
FGridSize: Integer;
|
|
FRowFrameSize: Integer;
|
|
FImageHeight: Integer;
|
|
FImageWidth: Integer;
|
|
FImages: TImageList;
|
|
FImageChangeLink: TChangeLink;
|
|
FIndent: Integer;
|
|
FToolboxButtonWidth: Integer;
|
|
FHitTest: TPoint;
|
|
FHitInfo: TdxInspectorHitInfo;
|
|
FRowCount, FVisibleRowCount: Integer;
|
|
FLoading: Boolean;
|
|
FMaxRowTextLineCount: Integer;
|
|
FMinBandWidth: Integer;
|
|
FMinColumnWidth: Integer;
|
|
FMinRowHeight: Integer;
|
|
FTextHeight: Integer;
|
|
FRegistryPath: string;
|
|
FRowHeightAssigned: Boolean;
|
|
FState: TdxInspectorState;
|
|
FOptions: TdxInspectorOptions;
|
|
FSizing: Boolean;
|
|
FPointDragging: TPoint;
|
|
FDragImageNode: TImageList;
|
|
FPaintStyle: TdxInspectorPaintStyle;
|
|
FFlat: Boolean;
|
|
FPartVisibleBandCount: Integer;
|
|
FVisibleBandCount: Integer;
|
|
FOnChangeNode: TdxInspectorChangeNodeEvent;
|
|
FPrevDragCursor: TCursor;
|
|
FShowRowHint: Boolean;
|
|
FPrevHintComplexRowIndex: Integer;
|
|
FPrevHintNode: TdxInspectorNode;
|
|
FPrevHintTest: TdxInspectorHitTest;
|
|
FShowHintTimerId: Integer;
|
|
FHideHintTimerId: Integer;
|
|
FHintWindow: TdxContainerHintWindow;
|
|
|
|
FCellViewData: TdxInspectorCellViewData;
|
|
FModified: Boolean;
|
|
|
|
FGridBrush, FGroupGridBrush: HBRUSH;
|
|
FBkBrush, FGroupBkBrush: HBRUSH;
|
|
FOnHideCustomizeForm: TNotifyEvent;
|
|
FOnShowCustomizeForm: TNotifyEvent;
|
|
// tree
|
|
function GetCount: Integer;
|
|
function GetFocused: TdxInspectorNode;
|
|
function GetFocusedNumber: Integer;
|
|
function GetLastNode: TdxInspectorNode;
|
|
function GetNode(Index: Integer): TdxInspectorNode;
|
|
function GetTopIndex: Integer;
|
|
function GetTopNode: TdxInspectorNode;
|
|
procedure SetTopIndex(AIndex: Integer);
|
|
|
|
// Style
|
|
function GetOptions: TdxInspectorOptions;
|
|
procedure ImageListChange(Sender: TObject);
|
|
procedure InternalLayout;
|
|
function IsActiveControl: Boolean;
|
|
function IsGridColorStored: Boolean;
|
|
function IsRowHeightStored: Boolean;
|
|
procedure SetBorderStyle(Value: TBorderStyle);
|
|
procedure SetComplexRowSeparator(const Value: string);
|
|
procedure SetFlat(Value: Boolean);
|
|
procedure SetGridColor(Value: TColor);
|
|
procedure SetImages(Value: TImageList);
|
|
procedure SetLeftBandIndex(Value: Integer);
|
|
procedure SetOptions(Value: TdxInspectorOptions);
|
|
procedure SetPaintStyle(Value: TdxInspectorPaintStyle);
|
|
procedure SetRowHeight(Value: Integer);
|
|
procedure SetShowRowHint(Value: Boolean);
|
|
procedure SetState(Value: TdxInspectorState);
|
|
|
|
// Size & AutoWidth
|
|
function CalcAutoWidth: Integer;
|
|
procedure CheckBandWidth(var ABandWidth: Integer);
|
|
procedure CheckDividerPos(var Pos: Integer);
|
|
function GetBandCount: Integer;
|
|
function GetFocusedBandIndex: Integer;
|
|
function GetLeftBandIndex: Integer;
|
|
function GetPartVisibleBandCount: Integer;
|
|
function GetVisibleBandCount: Integer;
|
|
procedure SetBandWidth(Value: Integer);
|
|
procedure SetDividerPos(Value: Integer);
|
|
procedure SetMaxRowTextLineCount(Value: Integer);
|
|
procedure SetMinBandWidth(Value: Integer);
|
|
procedure SetMinColumnWidth(Value: Integer);
|
|
procedure UpdateDesigner;
|
|
procedure UpdateTopCoord;
|
|
|
|
//Customize
|
|
function GetCustomization: Boolean;
|
|
procedure SetCustomization(Value: Boolean);
|
|
|
|
// Draw
|
|
procedure DrawButton(ACanvas: TCanvas; ARect, AButtonRect: TRect; AButtonKind: TdxInspectorButtonKind; ANode: TdxInspectorNode);
|
|
procedure DrawDragNode;
|
|
procedure DrawSizingLine;
|
|
procedure InvalidateRect(ARect: TRect);
|
|
function RecalcPaintRect(ARect: TRect): TRect;
|
|
procedure WriteImage(ACanvas: TCanvas; ARect: TRect; Index: Integer);
|
|
|
|
// Editor
|
|
procedure CheckEditor(ASetFocus, AFlagRefresh: Boolean);
|
|
function GetInplaceComplexRowIndex: Integer;
|
|
procedure UpdateText;
|
|
|
|
// Hint
|
|
procedure ClearPrevHintNode;
|
|
procedure HideRowHint;
|
|
procedure SetInplaceComplexRowIndex(Value: Integer);
|
|
procedure StartShowRowHint(Wait: Boolean);
|
|
|
|
// messages
|
|
procedure WMCancelMode(var Msg: TMessage); message WM_CANCELMODE;
|
|
procedure WMCaptureChanged(var Msg: TMessage); message WM_CAPTURECHANGED;
|
|
procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
|
|
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
|
|
procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
|
|
procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
|
|
procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
|
|
procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
|
|
procedure WMNCCalcSize(var Message: TWMNCCalcSize); message WM_NCCalcSize;
|
|
procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
|
|
procedure WMNCPaint(var Message: TMessage); message WM_NCPaint;
|
|
procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
|
|
procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
|
|
procedure WMSize(var Msg: TWMSize); message WM_SIZE;
|
|
procedure WMTimer(var Msg: TWMTimer); message WM_TIMER;
|
|
procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
|
|
procedure CMCancelMode(var Msg: TMessage); message CM_CANCELMODE;
|
|
procedure CMColorChanged(var Message: TMessage); message CM_COLORCHANGED;
|
|
procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
|
|
procedure CMDesignHitTest(var Msg: TCMDesignHitTest); message CM_DESIGNHITTEST;
|
|
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
|
|
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
|
|
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
|
|
procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
|
|
procedure CMShowHintChanged(var Message: TMessage); message CM_SHOWHINTCHANGED;
|
|
protected
|
|
FDragNode: TdxInspectorNode;
|
|
FDragObject: TDragObject;
|
|
// Editor
|
|
FComplexRowIndex: Integer;
|
|
FInplaceComplexRowIndex: Integer;
|
|
FInplaceEdit: TdxInplaceEdit;
|
|
FInplaceNode: TdxInspectorNode;
|
|
|
|
FInplaceComplexRowIndexPushed: Integer;
|
|
FInplaceEditPushed: TdxInplaceEdit;
|
|
FInplaceNodePushed: TdxInspectorNode;
|
|
// customize
|
|
FCustomizeForm: TForm;
|
|
FCustomizeFormPos: TPoint;
|
|
FCustomizeFormSize: TPoint;
|
|
// overrride TWinControl
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure DoEndDrag(Target: TObject; X, Y: Integer); override;
|
|
procedure DoExit; override;
|
|
procedure DoStartDrag(var DragObject: TDragObject); override;
|
|
procedure DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); override;
|
|
function GetDragImages: {$IFDEF DELPHI4}TDragImageList{$ELSE}TCustomImageList{$ENDIF}; override;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
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 Loaded; override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
procedure Paint; override;
|
|
procedure WndProc(var Message: TMessage); override;
|
|
|
|
// based
|
|
function AcquireFocus: Boolean; virtual;
|
|
procedure AddNode(Node: TdxInspectorNode); virtual;
|
|
function CalcBandWidth(ABandWidth: Integer): Integer;
|
|
function CalcDividerPos(AX: Integer): Integer;
|
|
procedure CalcDrawInfo(ANode: TdxInspectorNode; ARect: TRect; var ADrawInfo: TdxInspectorDrawInfo);
|
|
function CalcMinRowHeight(ACanvas: TCanvas): Integer; virtual;
|
|
function CalcTextHeight(ACanvas: TCanvas): Integer; virtual;
|
|
procedure CancelDragSizing;
|
|
procedure CheckComplexRowIndex(var AComplexRowIndex: Integer); virtual;
|
|
procedure CheckDownNode(AClick: Boolean);
|
|
procedure CheckHotTrackNode(ANode: TdxInspectorNode); virtual;
|
|
procedure CheckInplaceComplexRowIndex; virtual;
|
|
function CreateNode: TdxInspectorNode; virtual; abstract;
|
|
procedure DeleteNode(Node, Prior, Next : TdxInspectorNode; IsLast, Redraw : Boolean); virtual;
|
|
procedure DoChangeNode(OldNode, Node : TdxInspectorNode); virtual;
|
|
procedure DoDragScroll(P: TPoint);
|
|
procedure DragDropTo(var ANode: TdxInspectorNode; ADestinationNode: TdxInspectorNode; AAttachMode: TdxInspectorNodeAttachMode); virtual;
|
|
procedure DrawCaption(ACanvas: TCanvas; ANode: TdxInspectorNode; const ADisplayRect: TRect; const AText: string); virtual;
|
|
procedure DrawComplexRowSeparator(ACanvas: TCanvas; const ARect: TRect; AIsCaption: Boolean);
|
|
procedure DrawDisplayText(ACanvas: TCanvas; const ARect: TRect; const AText: string; AAlignment: TAlignment);
|
|
procedure DoDrawCaption(ACanvas:TCanvas; ANode: TdxInspectorNode;
|
|
AIndentRect, AButtonRect, AImageRect: TRect; AButtonKind: TdxInspectorButtonKind;
|
|
ADisplayRect: TRect; var AText: String); virtual;
|
|
procedure DoDrawValue(ACanvas: TCanvas; ARect : TRect; ANode: TdxInspectorNode;
|
|
var AText : String; var AAlignment: TAlignment); virtual;
|
|
procedure DoHideCustomizeForm; virtual;
|
|
procedure DoShowCustomizeForm; virtual;
|
|
procedure DefaultDrawCell(ACanvas: TCanvas; const ARect: TRect; ACellViewData: TdxInspectorCellViewData); virtual;
|
|
procedure CalcCellViewBoundsRect(const ACellRect: TRect; var AViewRect: TRect); virtual;
|
|
procedure DoInternalLayout; virtual;
|
|
function GetAbsoluteCount: Integer;
|
|
function GetAbsoluteIndex(Node: TdxInspectorNode): Integer;
|
|
function GetAbsoluteNode(AIndex: Integer): TdxInspectorNode;
|
|
function GetBandIndexByNode(ANode: TdxInspectorNode): Integer;
|
|
function GetBandRowCount(ABandIndex: Integer): Integer;
|
|
procedure GetBandRowInfo(AByNode: Boolean; var Node: TdxInspectorNode; var BandIndex, BandRowCount: Integer);
|
|
function GetBandTopNode(ABandIndex: Integer): TdxInspectorNode;
|
|
procedure GetComplexRowInfoAt(ANode: TdxInspectorNode; const ARect: TRect; const APos: TPoint;
|
|
var ComplexRowIndex: Integer; var ComplexRowRect: TRect); virtual;
|
|
function GetDefaultNodeHeight(ANode: TdxInspectorNode): Integer;
|
|
function GetDragNodeText(ADragNode: TdxInspectorNode): string; virtual;
|
|
function GetImageIndex(Node: TdxInspectorNode): Integer; virtual;
|
|
function GetMinRowHeight(ANode: TdxInspectorNode): Integer;
|
|
function GetNodeHeight(ANode: TdxInspectorNode): Integer; virtual;
|
|
procedure GetNodeText(Node: TdxInspectorNode; var CaptionText, DisplayText: String); virtual; abstract;
|
|
function GetRectByNode(ANode: TdxInspectorNode; ADrawInfo: TdxInspectorContentDrawInfo): TRect;
|
|
function GetRectNode(ANode: TdxInspectorNode): TRect;
|
|
function GetRectNodeBelow(Node: TdxInspectorNode): TRect;
|
|
function GetSectionWidth: Integer;
|
|
function GetValueFontColor: TColor; virtual;
|
|
function GoTabComplexRow(AForward: Boolean): Boolean; virtual;
|
|
procedure InvalidateNode(ANode: TdxInspectorNode; ABelow: Boolean);
|
|
function IsAutoDrag: Boolean;
|
|
function IsCategoryNode(Node: TdxInspectorNode): Boolean; virtual;
|
|
function IsComplexNode(ANode: TdxInspectorNode): Boolean; virtual;
|
|
function IsCustomizing: Boolean; virtual;
|
|
function IsGoTabComplexRowAvailable(AForward: Boolean): Boolean; virtual;
|
|
function IsHotTrackNode(ANode: TdxInspectorNode): Boolean; virtual;
|
|
function IsImageNode(Node: TdxInspectorNode): Boolean; virtual;
|
|
function IsInternalDragging: Boolean;
|
|
function IsShowHintNode(ANode: TdxInspectorNode; AComplexRowIndex: Integer;
|
|
const AComplexRowRect: TRect; IsValue: Boolean; const R: TRect;
|
|
var AText: string; var X: Integer; var IsRowHint: Boolean): Boolean; virtual;
|
|
procedure LayoutChanged; virtual;
|
|
procedure RedrawSelection; override;
|
|
procedure UpdateCustomizeForm;
|
|
procedure UpdateDesignEditor; virtual;
|
|
procedure UpdateNode(Node: TdxInspectorNode; Below: Boolean); virtual;
|
|
procedure UpdateBandCount;
|
|
procedure UpdateBandRowCount;
|
|
procedure UpdateRowCount; virtual;
|
|
procedure UpdateScrollBar; virtual;
|
|
procedure SetFocusedNode(Node: TdxInspectorNode); virtual;
|
|
procedure SetFocusedNumber(AIndex: Integer); virtual;
|
|
procedure SetNodeHeight(ANode: TdxInspectorNode; Value: Integer); virtual;
|
|
// Load/Save
|
|
procedure LoadFromRegIni(ARegIniObject: TObject; APath: string);
|
|
procedure ReadSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); virtual;
|
|
procedure SaveToRegIni(ARegIniObject: TObject; APath: string);
|
|
procedure WriteSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); virtual;
|
|
//Editor
|
|
function CanEditAcceptKey(Key: Char): Boolean; override;
|
|
function CanEditModify: Boolean; override;
|
|
function CanEditShow: Boolean; virtual;
|
|
function CellRect(ANode: TdxInspectorNode): TRect;
|
|
function CheckEditorWidth: Boolean; override;
|
|
function CreateEditor(ANode: TdxInspectorNode): TdxInplaceEdit; virtual;
|
|
function CreateEditStyle(AEdit: TdxInplaceEdit): TdxEditStyle; override;
|
|
procedure DoCheckKeyDown(var Key: Word; Shift: TShiftState);
|
|
procedure DoEditChange(Sender: TObject); virtual;
|
|
procedure DoEditValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean); virtual;
|
|
function FindInplaceEdit(ANode: TdxInspectorNode): TdxInplaceEdit; virtual;
|
|
function GetEditColor: TColor; override;
|
|
function GetEditingText: String; virtual;
|
|
function GetEditRect(ANode: TdxInspectorNode): TRect; virtual;
|
|
procedure HideEdit(ABackFocus: Boolean);
|
|
procedure InplaceEditKeyDown(var Key: Word; Shift: TShiftState); override;
|
|
function IsAutoBandCount: Boolean;
|
|
function IsDynamicColumnSizing: Boolean; virtual;
|
|
function IsImmediateEditor: Boolean; override;
|
|
function IsRowAutoHeight: Boolean;
|
|
function CanRowSizing: Boolean;
|
|
function IsTabs: Boolean; override;
|
|
procedure SetEditingText(Value: string); virtual;
|
|
|
|
function AssignEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant; virtual;
|
|
function EditStyleBorderStyle: TdxEditBorderStyle;
|
|
function EditStyleButtonStyle: TdxEditButtonViewStyle;
|
|
procedure InitEditProperties(AInplaceEdit: TdxInplaceEdit); virtual;
|
|
function InitEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant; virtual; // return Value for Editor
|
|
|
|
property BandWidth: Integer read FBandWidth write SetBandWidth default 200;
|
|
property BandSeparatorWidth: Integer read FBandSeparatorWidth;
|
|
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle;
|
|
property Color default dxclInspectorBackgroundColor;
|
|
property ComplexRowSeparator: string read FComplexRowSeparator write SetComplexRowSeparator;
|
|
property DividerPos: Integer read FDividerPos write SetDividerPos;
|
|
property DragNode: TdxInspectorNode read FDragNode;
|
|
property Flat: Boolean read FFlat write SetFlat default False;
|
|
property GridColor: TColor read FGridColor write SetGridColor stored IsGridColorStored;
|
|
property GridSize: Integer read FGridSize;
|
|
property Images: TImageList read FImages write SetImages;
|
|
property Indent: Integer read FIndent;
|
|
property InplaceComplexRowIndex: Integer read GetInplaceComplexRowIndex write SetInplaceComplexRowIndex;
|
|
property MaxRowTextLineCount: Integer read FMaxRowTextLineCount write SetMaxRowTextLineCount default 3;
|
|
property MinBandWidth: Integer read FMinBandWidth write SetMinBandWidth default dxInspectorLimitBandWidth;
|
|
property MinColumnWidth: Integer read FMinColumnWidth write SetMinColumnWidth default 30;
|
|
property Options: TdxInspectorOptions read GetOptions write SetOptions
|
|
default [ioEditing, ioBandSizing, ioColumnSizing, ioAutoWidth, ioDynamicColumnSizing];
|
|
property PaintStyle: TdxInspectorPaintStyle read FPaintStyle write SetPaintStyle default ipsStandard;
|
|
property ParentColor default False;
|
|
property RegistryPath: string read FRegistryPath write FRegistryPath;
|
|
property RowCount: Integer read FRowCount;
|
|
property RowHeight: Integer read FRowHeight write SetRowHeight stored IsRowHeightStored;
|
|
property VisibleRowCount: Integer read FVisibleRowCount;
|
|
property ShowRowHint: Boolean read FShowRowHint write SetShowRowHint default False;
|
|
property OnChangeNode: TdxInspectorChangeNodeEvent read FOnChangeNode write FOnChangeNode;
|
|
property OnHideCustomizeForm: TNotifyEvent read FOnHideCustomizeForm write FOnHideCustomizeForm;
|
|
property OnShowCustomizeForm: TNotifyEvent read FOnShowCustomizeForm write FOnShowCustomizeForm;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure DragDrop(Source: TObject; X, Y: Integer); override;
|
|
// tree methods
|
|
function Add: TdxInspectorNode;
|
|
procedure BeginUpdate;
|
|
procedure ClearNodes; virtual;
|
|
procedure EndUpdate;
|
|
procedure FullCollapse;
|
|
procedure FullExpand;
|
|
function GetHitInfo(Pos: TPoint): TdxInspectorHitInfo;
|
|
function GetHitTestInfoAt(X, Y: Integer): TdxInspectorHitTest;
|
|
function GetNextVisible(Node: TdxInspectorNode): TdxInspectorNode;
|
|
function GetNodeAt(X, Y: Integer): TdxInspectorNode;
|
|
function GetTopParentNode(ANode: TdxInspectorNode): TdxInspectorNode;
|
|
function IndexOf(Value: TdxInspectorNode): Integer;
|
|
function Insert(BeforeNode: TdxInspectorNode): TdxInspectorNode;
|
|
function IsActive: Boolean;
|
|
function IsNodeVisible(Node: TdxInspectorNode): Boolean;
|
|
procedure MakeNodeVisible(Node: TdxInspectorNode);
|
|
function PtInCustomizeForm(const P: TPoint): Boolean;
|
|
// Customize
|
|
procedure HideCustomizeForm;
|
|
procedure ShowCustomizeForm;
|
|
// Editor
|
|
procedure HideEditor;
|
|
procedure InvalidateEditor; virtual;
|
|
procedure PostEditor; // MouseDown, KeyDown...
|
|
procedure ShowEditor;
|
|
procedure ShowEditorChar(Ch: Char);
|
|
procedure ShowEditorMouse(X, Y: Integer);
|
|
// View
|
|
procedure CalcContentDrawInfo(var ADrawInfo: TdxInspectorContentDrawInfo);
|
|
procedure FreeContentDrawInfo(var ADrawInfo: TdxInspectorContentDrawInfo);
|
|
// Load/Save
|
|
procedure LoadFromRegistry(const ARegPath: string);
|
|
procedure SaveToRegistry(const ARegPath: string);
|
|
|
|
property Canvas;
|
|
property BandCount: Integer read GetBandCount;
|
|
property Count: Integer read GetCount;
|
|
property CustomizeForm: TForm read FCustomizeForm;
|
|
property Customization: Boolean read GetCustomization write SetCustomization;
|
|
property EditColor: TColor read GetEditColor;
|
|
property FocusedBandIndex: Integer read GetFocusedBandIndex;
|
|
property FocusedNode: TdxInspectorNode read GetFocused;
|
|
property FocusedNumber: Integer read GetFocusedNumber write SetFocusedNumber;
|
|
property InplaceEditor: TdxInplaceEdit read FInplaceEdit;
|
|
property Items[Index: Integer]: TdxInspectorNode read GetNode;
|
|
property LastNode: TdxInspectorNode read GetLastNode;
|
|
property LeftBandIndex: Integer read GetLeftBandIndex write SetLeftBandIndex;
|
|
property LockUpdate: Integer read FLockUpdate;
|
|
property PartVisibleBandCount: Integer read GetPartVisibleBandCount;
|
|
property State: TdxInspectorState read FState;
|
|
property TopIndex: Integer read GetTopIndex write SetTopIndex;
|
|
property TopNode: TdxInspectorNode read GetTopNode;
|
|
property TopVisibleNode: TdxInspectorNode read FTopVisibleNode;
|
|
property VisibleBandCount: Integer read GetVisibleBandCount;
|
|
published
|
|
property TabStop default True;
|
|
end;
|
|
|
|
{ TdxInspectorEditStyle }
|
|
|
|
TdxInspectorEditStyle = class(TdxEditStyle)
|
|
private
|
|
FInspector: TCustomdxInspector;
|
|
protected
|
|
property Inspector: TCustomdxInspector read FInspector;
|
|
public
|
|
constructor Create(AEdit: TdxInplaceEdit; AInspector: TCustomdxInspector);
|
|
function DefaultBorderColor: TColor; override;
|
|
function DefaultBorderStyle: TdxEditBorderStyle; override;
|
|
function DefaultButtonStyle: TdxEditButtonViewStyle; override;
|
|
function DefaultButtonTransparence: TdxEditButtonTransparence; override;
|
|
function DefaultEdges: TdxEditEdges; override;
|
|
function DefaultHotTrack: Boolean; override;
|
|
function DefaultShadow: Boolean; override;
|
|
end;
|
|
|
|
TCustomdxInspectorControl = class;
|
|
TdxInspectorRowNode = class;
|
|
TdxInspectorDesigner = class;
|
|
|
|
{ TdxInspectorRow }
|
|
|
|
TdxRowValue = (rvCaption, rvReadOnly, rvMaxLength, rvRowHeight);
|
|
TdxRowValues = set of TdxRowValue;
|
|
|
|
TdxInspectorRow = class;
|
|
TdxInspectorRowDrawValue = procedure (Sender: TdxInspectorRow; ACanvas: TCanvas;
|
|
ARect: TRect; var AText: String; AFont: TFont;
|
|
var AColor: TColor; var ADone: Boolean) of object;
|
|
TdxInspectorGetEditColor = procedure(Sender: TdxInspectorRow; var AColor: TColor) of object;
|
|
TdxInspectorGetEditFont = procedure(Sender: TdxInspectorRow; var AFont: TFont) of object;
|
|
|
|
TdxInplaceInspectorTextEdit = class(TdxInplaceTextEdit);
|
|
|
|
TdxInspectorRow = class(TComponent)
|
|
private
|
|
FInspector: TCustomdxInspectorControl;
|
|
FNode: TdxInspectorRowNode;
|
|
FAlignment: TAlignment;
|
|
FCaption: string;
|
|
FCharCase: TEditCharCase;
|
|
FHint: string;
|
|
FImageIndex: TImageIndex;
|
|
FIsCategory: Boolean;
|
|
FMaxLength: Integer;
|
|
FReadonly: Boolean;
|
|
FRowHeight: Integer;
|
|
FShowHint: Boolean;
|
|
FAssignedValues: TdxRowValues;
|
|
FPasswordChar: Char;
|
|
FViewData: TdxEditViewData;
|
|
FVisible: Boolean;
|
|
FOnChange: TNotifyEvent;
|
|
FOnChangeName: TNotifyEvent;
|
|
FOnDrawCaption: TdxInspectorRowDrawValue;
|
|
FOnDrawValue: TdxInspectorRowDrawValue;
|
|
FOnValidate: TdxEditValidateEvent;
|
|
function GetCaption: string;
|
|
function GetMaxLength: Integer;
|
|
function GetReadOnly: Boolean;
|
|
function GetRowHeight: Integer;
|
|
function IsCaptionStored: Boolean;
|
|
function IsMaxLengthStored: Boolean;
|
|
function IsReadOnlyStored: Boolean;
|
|
function IsRowHeightStored: Boolean;
|
|
procedure SetAlignment(Value: TAlignment);
|
|
procedure SetCaption(const Value: string);
|
|
procedure SetCharCase(Value: TEditCharCase);
|
|
procedure SetImageIndex(Value: TImageIndex);
|
|
procedure SetIsCategory(Value: Boolean);
|
|
procedure SetMaxLength(Value: Integer);
|
|
procedure SetPasswordChar(Value: Char);
|
|
procedure SetReadOnly(Value: Boolean);
|
|
procedure SetRowHeight(Value: Integer);
|
|
procedure SetVisible(Value: Boolean);
|
|
procedure SetInspector(AInspector: TCustomdxInspectorControl);
|
|
protected
|
|
// override TComponent
|
|
procedure ReadState(Reader: TReader); override;
|
|
procedure SetName(const Value: TComponentName); override;
|
|
procedure SetParentComponent(AParent: TComponent); override;
|
|
//virtual
|
|
procedure DoChange(Sender: TObject); virtual;
|
|
procedure DoDrawCaption(ACanvas: TCanvas; AIndentRect, AButtonRect, AImageRect: TRect; AButtonKind: TdxInspectorButtonKind;
|
|
ADisplayRect: TRect; var AText: string; var ADone: Boolean); virtual;
|
|
procedure DoDrawValue(ACanvas:TCanvas; ARect : TRect; var AText: String; var ADone: Boolean); virtual;
|
|
procedure DoEdited; virtual;
|
|
procedure DoValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean); virtual;
|
|
function GetDisplayText: string; virtual; abstract;
|
|
function GetEditLimit: Integer; virtual;
|
|
function GetEditMaskRow: string; virtual;
|
|
function GetEditText: string; virtual; abstract;
|
|
function GetMinRowHeight(ACanvas: TCanvas): Integer; virtual;
|
|
procedure SetEditText(const Value: string); virtual; abstract;
|
|
procedure Changed;
|
|
function AssignEditValue(AInplaceEdit: TdxInplaceEdit): Variant; virtual;
|
|
function GetdxInplaceEditClass: TdxInplaceEditClass; virtual;
|
|
procedure InitEditProperties(AInplaceEdit: TdxInplaceEdit); virtual;
|
|
function InitEditValue(AInplaceEdit: TdxInplaceEdit): Variant; virtual;
|
|
function IsEqualValues(const Value: Variant): Boolean; virtual;
|
|
function IsShowHint(IsValue: Boolean; const R: TRect; var AText: string): Boolean; virtual;
|
|
procedure PrepareViewData(AViewData: TdxEditViewData; ACellViewData: TdxInspectorCellViewData); virtual;
|
|
// Visible
|
|
procedure Hide;
|
|
procedure Show;
|
|
// link to objects
|
|
function GetLinkObject: TObject; virtual;
|
|
procedure SetLinkObject(Value: TObject); virtual;
|
|
function GetLinkObjectName: string; virtual;
|
|
procedure SetLinkObjectName(const Value: string); virtual;
|
|
property ViewData: TdxEditViewData read FViewData;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
function DefaultCaption: string; virtual;
|
|
function DefaultMaxLength: Integer; virtual;
|
|
function DefaultReadOnly: Boolean; virtual;
|
|
function DefaultRowHeight: Integer; virtual;
|
|
function GetParentComponent: TComponent; override;
|
|
function HasParent: Boolean; override;
|
|
function IsCanModify: Boolean; virtual;
|
|
function IsValidChar(InputChar: Char): Boolean; virtual;
|
|
procedure RestoreDefaultRowHeight;
|
|
procedure RestoreDefaults; virtual;
|
|
|
|
property AssignedValues: TdxRowValues read FAssignedValues;
|
|
property DisplayText: string read GetDisplayText;
|
|
property EditText: string read GetEditText write SetEditText;
|
|
property Inspector: TCustomdxInspectorControl read FInspector write SetInspector;
|
|
property Node: TdxInspectorRowNode read FNode;
|
|
property OnChangeName : TNotifyEvent read FOnChangeName write FOnChangeName;
|
|
property LinkObject: TObject read GetLinkObject write SetLinkObject;
|
|
property LinkObjectName: String read GetLinkObjectName write SetLinkObjectName;
|
|
published
|
|
property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
|
|
property Caption: string read GetCaption write SetCaption stored IsCaptionStored;
|
|
property CharCase: TEditCharCase read FCharCase write SetCharCase default ecNormal;
|
|
property Hint: string read FHint write FHint;
|
|
property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
|
|
property IsCategory: Boolean read FIsCategory write SetIsCategory default False;
|
|
property MaxLength: Integer read GetMaxLength write SetMaxLength stored IsMaxLengthStored;
|
|
property PasswordChar: Char read FPasswordChar write SetPasswordChar default #0;
|
|
property ReadOnly: Boolean read GetReadOnly write SetReadOnly stored IsReadOnlyStored;
|
|
property RowHeight: Integer read GetRowHeight write SetRowHeight stored IsRowHeightStored;
|
|
property ShowHint: Boolean read FShowHint write FShowHint default False;
|
|
property Visible: Boolean read FVisible write SetVisible default True;
|
|
property OnChange: TNotifyEvent read FOnChange write FOnChange;
|
|
property OnDrawCaption: TdxInspectorRowDrawValue read FOnDrawCaption write FOnDrawCaption;
|
|
property OnDrawValue: TdxInspectorRowDrawValue read FOnDrawValue write FOnDrawValue;
|
|
property OnValidate: TdxEditValidateEvent read FOnValidate write FOnValidate;
|
|
end;
|
|
|
|
TdxInspectorRowClass = class of TdxInspectorRow;
|
|
|
|
{ TdxInspectorRowNode }
|
|
|
|
TdxInspectorRowNode = class(TdxInspectorNode)
|
|
private
|
|
FRow: TdxInspectorRow;
|
|
procedure WriteData(AStream: TStream);
|
|
public
|
|
destructor Destroy; override;
|
|
// extended
|
|
function AddChildEx(RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
function InsertChildEx(BeforeNode: TdxInspectorNode; RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
property Row: TdxInspectorRow read FRow;
|
|
end;
|
|
|
|
PdxInspectorRowNodeInfo = ^TdxInspectorRowNodeInfo;
|
|
TdxInspectorRowNodeInfo = packed record
|
|
Count: Integer;
|
|
StrLen: Integer;
|
|
Str: record end;
|
|
end;
|
|
|
|
TdxInspectorEditingEvent = procedure(Sender: TObject; Node: TdxInspectorNode;
|
|
Row: TdxInspectorRow; var Allow: Boolean) of object;
|
|
TdxInspectorEditedEvent = procedure(Sender: TObject; Node: TdxInspectorNode; Row: TdxInspectorRow) of object;
|
|
|
|
{ TCustomdxInspectorControl }
|
|
|
|
TdxInspectorComplexRow = class;
|
|
|
|
TCustomdxInspectorControl = class(TCustomdxInspector)
|
|
private
|
|
FDefaultRowClass: TdxInspectorRowClass;
|
|
FDesigner: TdxInspectorDesigner;
|
|
FEditFont: TFont;
|
|
FEditors: TList;
|
|
FEditValue: Variant;
|
|
FRows: TList;
|
|
FStreamData: TMemoryStream;
|
|
FOnDrawCaption: TdxInspectorRowDrawValue;
|
|
FOnDrawValue: TdxInspectorRowDrawValue;
|
|
FOnEditChange: TNotifyEvent;
|
|
FOnEditing: TdxInspectorEditingEvent;
|
|
FOnEdited: TdxInspectorEditedEvent;
|
|
FOnEditValidate: TdxEditValidateEvent;
|
|
FOnGetEditColor: TdxInspectorGetEditColor;
|
|
FOnGetEditFont: TdxInspectorGetEditFont;
|
|
procedure AddRow(Row: TdxInspectorRow);
|
|
procedure CheckHiddenRows;
|
|
procedure FreeStreamData;
|
|
function GetRow(Index: Integer): TdxInspectorRow;
|
|
function GetTotalRowCount: Integer;
|
|
function GetVisibleTotalRowCount: Integer;
|
|
procedure InternalCreateNodeForRow(Row: TdxInspectorRow);
|
|
procedure LoadOrderRows;
|
|
procedure NotifyComplexRows(Row: TdxInspectorRow);
|
|
procedure ReadData(Stream: TStream);
|
|
procedure RemoveRow(Row: TdxInspectorRow);
|
|
procedure SetEditValue(const Value: Variant);
|
|
procedure SetRow(Index: Integer; Value: TdxInspectorRow);
|
|
procedure WriteData(AStream: TStream);
|
|
protected
|
|
FAddFlag: Boolean;
|
|
FDragRow: TdxInspectorRow;
|
|
// TComponent
|
|
procedure DefineProperties(Filer: TFiler); override;
|
|
procedure DoEndDrag(Target: TObject; X, Y: Integer); override;
|
|
procedure GetChildren(Proc: TGetChildProc{$IFDEF DELPHI3}; Root: TComponent{$ENDIF}); override;
|
|
procedure Loaded; override;
|
|
procedure SetChildOrder(Component: TComponent; Order: Integer); override;
|
|
procedure SetName(const Value: TComponentName); override;
|
|
// based
|
|
procedure AddNode(Node: TdxInspectorNode); override;
|
|
function CalcMinRowHeight(ACanvas: TCanvas): Integer; override;
|
|
function CalcRowAutoHeight(ARow: TdxInspectorRow): Integer;
|
|
function CalcRowHeight(ACanvas: TCanvas; const ARect: TRect; ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorRow): Integer;
|
|
function CalcComplexRowHeight(ACanvas: TCanvas; const ARect: TRect; ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorComplexRow): Integer;
|
|
|
|
procedure CheckComplexRowIndex(var AComplexRowIndex: Integer); override;
|
|
procedure ClearComplexRows(ARow: TdxInspectorRow);
|
|
function CreateNode: TdxInspectorNode; override;
|
|
procedure DestroyRows;
|
|
procedure DefaultDrawCell(ACanvas: TCanvas; const ARect: TRect; ACellViewData: TdxInspectorCellViewData); override;
|
|
procedure DragDropTo(var ANode: TdxInspectorNode; ADestinationNode: TdxInspectorNode; AAttachMode: TdxInspectorNodeAttachMode); override;
|
|
procedure DrawCaption(ACanvas: TCanvas; ANode: TdxInspectorNode; const ADisplayRect: TRect; const AText: string); override;
|
|
procedure DrawComplexRowCaption(ACanvas: TCanvas; const ADisplayRect: TRect; ARow: TdxInspectorComplexRow);
|
|
procedure DrawComplexRowValue(ACanvas: TCanvas; const ARect: TRect; ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorComplexRow);
|
|
procedure DrawValue(ACanvas: TCanvas; const ARect: TRect; ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorRow);
|
|
procedure DoDrawCaption(ACanvas: TCanvas; ANode: TdxInspectorNode;
|
|
AIndentRect, AButtonRect, AImageRect: TRect; AButtonKind: TdxInspectorButtonKind;
|
|
ADisplayRect: TRect; var AText: String); override;
|
|
procedure DoDrawValue(ACanvas:TCanvas; ARect: TRect; ANode: TdxInspectorNode;
|
|
var AText : string; var AAlignment: TAlignment); override;
|
|
procedure DoEditChange(Sender: TObject); override;
|
|
procedure DoEditValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean); override;
|
|
procedure DoInternalLayout; override;
|
|
procedure DoRestoreLayout; virtual;
|
|
procedure DoSaveLayout; virtual;
|
|
procedure GetComplexRowInfoAt(ANode: TdxInspectorNode; const ARect: TRect; const APos: TPoint;
|
|
var ComplexRowIndex: Integer; var ComplexRowRect: TRect); override;
|
|
function GetDefaultRowClass: TdxInspectorRowClass; virtual;
|
|
function GetDragNodeText(ADragNode: TdxInspectorNode): string; override;
|
|
function GetEditRect(ANode: TdxInspectorNode): TRect; override;
|
|
function GetImageIndex(Node: TdxInspectorNode): Integer; override;
|
|
function GetNodeHeight(ANode: TdxInspectorNode): Integer; override;
|
|
procedure GetNodeText(Node: TdxInspectorNode; var CaptionText, DisplayText: string); override;
|
|
function GetRowDragCaption(ARow: TdxInspectorRow): string;
|
|
function GetRowHeight(ARow: TdxInspectorRow): Integer;
|
|
function GoTabComplexRow(AForward: Boolean): Boolean; override;
|
|
function IsCategoryNode(Node: TdxInspectorNode): Boolean; override;
|
|
function IsComplexNode(ANode: TdxInspectorNode): Boolean; override;
|
|
function IsGoTabComplexRowAvailable(AForward: Boolean): Boolean; override;
|
|
function IsShowHintNode(ANode: TdxInspectorNode; AComplexRowIndex: Integer;
|
|
const AComplexRowRect: TRect; IsValue: Boolean; const R: TRect;
|
|
var AText: string; var X: Integer; var IsRowHint: Boolean): Boolean; override;
|
|
function RowByComplexRowIndex(ANode: TdxInspectorNode; AComplexRowIndex: Integer): TdxInspectorRow;
|
|
procedure SetNodeHeight(ANode: TdxInspectorNode; Value: Integer); override;
|
|
procedure SetOrderRows(InspectorControl: TCustomdxInspectorControl);
|
|
function SaveNodes: Boolean; virtual;
|
|
procedure UpdateDesignEditor; override;
|
|
procedure UpdateRow(Row: TdxInspectorRow); virtual;
|
|
// Save/Load
|
|
procedure ReadSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); override;
|
|
procedure WriteSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string); override;
|
|
// Editor
|
|
function CanEditShow: Boolean; override;
|
|
function CreateEditor(ANode: TdxInspectorNode): TdxInplaceEdit; override;
|
|
function FindInplaceEdit(ANode: TdxInspectorNode): TdxInplaceEdit; override;
|
|
function GetEditColor: TColor; override;
|
|
function GetEditFont: TFont; override;
|
|
function GetInplaceEditRow(ANode: TdxInspectorNode): TdxInspectorRow;
|
|
function AssignEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant; override;
|
|
procedure InitEditProperties(AInplaceEdit: TdxInplaceEdit); override;
|
|
function InitEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant; override;
|
|
function IsDefaultEqualValues(const AValue: Variant; ARow: TdxInspectorRow): Boolean; virtual;
|
|
property EditValue: Variant read FEditValue write SetEditValue;
|
|
property OnDrawCaption: TdxInspectorRowDrawValue read FOnDrawCaption write FOnDrawCaption;
|
|
property OnDrawValue: TdxInspectorRowDrawValue read FOnDrawValue write FOnDrawValue;
|
|
property OnEditChange: TNotifyEvent read FOnEditChange write FOnEditChange;
|
|
property OnEditing: TdxInspectorEditingEvent read FOnEditing write FOnEditing;
|
|
property OnEdited: TdxInspectorEditedEvent read FOnEdited write FOnEdited;
|
|
property OnEditValidate: TdxEditValidateEvent read FOnEditValidate write FOnEditValidate;
|
|
property OnGetEditColor: TdxInspectorGetEditColor read FOnGetEditColor write FOnGetEditColor;
|
|
property OnGetEditFont: TdxInspectorGetEditFont read FOnGetEditFont write FOnGetEditFont;
|
|
public
|
|
constructor Create(AOwner : TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure AssignRows(InspectorControl: TCustomdxInspectorControl); virtual;
|
|
procedure ClearRows; virtual;
|
|
function ComplexRowByRow(ARow: TdxInspectorRow): TdxInspectorComplexRow;
|
|
function CreateDefaultRow(RowClass: TdxInspectorRowClass): TdxInspectorRow;
|
|
function CreateRow(RowClass: TdxInspectorRowClass): TdxInspectorRow;
|
|
function IndexOfRow(ARow: TdxInspectorRow): Integer;
|
|
procedure InvalidateEditor; override;
|
|
procedure RestoreRowsDefaults;
|
|
function RowByName(const AName: string): TdxInspectorRow;
|
|
function RowInComplexRow(ARow: TdxInspectorRow): Boolean;
|
|
// extended
|
|
function AddEx(RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
function InsertEx(BeforeNode: TdxInspectorNode; RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
// Save/Load
|
|
procedure LoadNodesFromStream(AStream: TStream);
|
|
procedure SaveNodesToStream(AStream: TStream);
|
|
|
|
property DefaultRowClass: TdxInspectorRowClass read FDefaultRowClass write FDefaultRowClass;
|
|
property Designer: TdxInspectorDesigner read FDesigner;
|
|
property Rows[Index : Integer]: TdxInspectorRow read GetRow write SetRow;
|
|
property TotalRowCount: Integer read GetTotalRowCount;
|
|
property VisibleTotalRowCount: Integer read GetVisibleTotalRowCount;
|
|
end;
|
|
|
|
{ TdxDBTreeListDesigner }
|
|
|
|
TdxInspectorDesigner = class
|
|
private
|
|
FInspector: TCustomdxInspectorControl;
|
|
public
|
|
constructor Create(dxInspector: TCustomdxInspectorControl);
|
|
destructor Destroy; override;
|
|
procedure LayoutChanged; virtual;
|
|
property Inspector: TCustomdxInspectorControl read FInspector;
|
|
end;
|
|
|
|
{ TdxInspector }
|
|
|
|
TdxInspector = class(TCustomdxInspectorControl)
|
|
private
|
|
procedure CMExit(var Message: TMessage); message CM_EXIT;
|
|
protected
|
|
function CanEditModify: Boolean; override;
|
|
public
|
|
function GetDefaultRowClass: TdxInspectorRowClass; override;
|
|
property DragNode;
|
|
property ReadOnly;
|
|
published
|
|
property Align;
|
|
property BorderStyle;
|
|
property Color;
|
|
property Ctl3D;
|
|
property DragCursor;
|
|
property DragMode;
|
|
property Enabled;
|
|
property Font;
|
|
property ParentColor;
|
|
property ParentCtl3D;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property ShowHint;
|
|
property TabOrder;
|
|
property Visible;
|
|
|
|
property OnClick;
|
|
property OnDblClick;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnStartDrag;
|
|
|
|
property BandWidth;
|
|
property ComplexRowSeparator;
|
|
property DividerPos;
|
|
property GridColor;
|
|
property Flat;
|
|
property Images;
|
|
property MaxRowTextLineCount;
|
|
property MinBandWidth;
|
|
property MinColumnWidth;
|
|
property Options;
|
|
property PaintStyle;
|
|
property RegistryPath;
|
|
property RowHeight;
|
|
property OnChangeNode;
|
|
property OnDrawCaption;
|
|
property OnDrawValue;
|
|
property OnEditing;
|
|
property OnEditChange;
|
|
property OnEdited;
|
|
property OnEditValidate;
|
|
property OnGetEditColor;
|
|
property OnGetEditFont;
|
|
property OnHideCustomizeForm;
|
|
property OnShowCustomizeForm;
|
|
property ShowRowHint;
|
|
{$IFDEF DELPHI4}
|
|
property Anchors;
|
|
property Constraints;
|
|
{$ENDIF}
|
|
{$IFDEF DELPHI5}
|
|
property OnContextPopup;
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{ TdxInspectorTextRow }
|
|
|
|
TdxInspectorTextRow = class(TdxInspectorRow)
|
|
private
|
|
FText: string;
|
|
procedure SetText(const Value: string);
|
|
protected
|
|
function GetDisplayText: string; override;
|
|
function GetEditText: string; override;
|
|
procedure SetEditText(const Value: string); override;
|
|
function GetdxInplaceEditClass: TdxInplaceEditClass; override;
|
|
published
|
|
property Text: string read FText write SetText;
|
|
end;
|
|
|
|
{ TdxInspectorComplexRow }
|
|
|
|
TdxInspectorComplexRowItem = class(TCollectionItem)
|
|
private
|
|
FFixed: Boolean;
|
|
FMinWidth: Integer;
|
|
FRow: TdxInspectorRow;
|
|
FWidth: Integer;
|
|
procedure SetFixed(Value: Boolean);
|
|
procedure SetMinWidth(Value: Integer);
|
|
procedure SetRow(Value: TdxInspectorRow);
|
|
procedure SetWidth(Value: Integer);
|
|
protected
|
|
function GetDisplayName: string; override;
|
|
function Inspector: TCustomdxInspectorControl;
|
|
function IsValidRow(ARow: TdxInspectorRow): Boolean;
|
|
procedure PrepareRow(ARow: TdxInspectorRow);
|
|
public
|
|
constructor Create(Collection: TCollection); override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure RestoreDefaults;
|
|
published
|
|
property Fixed: Boolean read FFixed write SetFixed default False;
|
|
property MinWidth: Integer read FMinWidth write SetMinWidth default 20;
|
|
property Row: TdxInspectorRow read FRow write SetRow;
|
|
property Width: Integer read FWidth write SetWidth default 50;
|
|
end;
|
|
|
|
TdxInspectorComplexRowItems = class(TCollection)
|
|
private
|
|
FRow: TdxInspectorComplexRow;
|
|
function GetItem(Index: Integer): TdxInspectorComplexRowItem;
|
|
procedure SetItem(Index: Integer; Value: TdxInspectorComplexRowItem);
|
|
protected
|
|
function GetOwner: TPersistent; override;
|
|
procedure Update(Item: TCollectionItem); override;
|
|
public
|
|
constructor Create(ARow: TdxInspectorComplexRow);
|
|
function Add: TdxInspectorComplexRowItem;
|
|
function IndexOfRow(ARow: TdxInspectorRow): Integer;
|
|
procedure RestoreDefaults;
|
|
property Row: TdxInspectorComplexRow read FRow;
|
|
property Items[Index: Integer]: TdxInspectorComplexRowItem read GetItem write SetItem; default;
|
|
end;
|
|
|
|
TdxInspectorComplexRow = class(TdxInspectorTextRow)
|
|
private
|
|
FItems: TdxInspectorComplexRowItems;
|
|
procedure SetItems(Value: TdxInspectorComplexRowItems);
|
|
protected
|
|
procedure RemoveNotification(ARow: TdxInspectorRow);
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
published
|
|
property Items: TdxInspectorComplexRowItems read FItems write SetItems;
|
|
end;
|
|
// TODO: RegisterProperty Editor = nil MaxLength and ...
|
|
|
|
{ TdxInspectorComplexRowViewInfo }
|
|
|
|
TdxInspectorComplexRowViewInfoItem = class
|
|
private
|
|
FBounds: TRect;
|
|
FFixed: Boolean;
|
|
FMinWidth: Integer;
|
|
FRow: TdxInspectorRow;
|
|
FSeparator: Boolean;
|
|
FWidth: Integer;
|
|
protected
|
|
property Fixed: Boolean read FFixed write FFixed;
|
|
property MinWidth: Integer read FMinWidth write FMinWidth;
|
|
property Width: Integer read FWidth write FWidth;
|
|
public
|
|
constructor Create(ARow: TdxInspectorRow);
|
|
property Bounds: TRect read FBounds write FBounds;
|
|
property Separator: Boolean read FSeparator write FSeparator;
|
|
property Row: TdxInspectorRow read FRow;
|
|
end;
|
|
|
|
TdxInspectorComplexRowViewInfo = class
|
|
private
|
|
FItems: TList;
|
|
FRow: TdxInspectorComplexRow;
|
|
FSeparatorWidth: Integer;
|
|
function GetCount: Integer;
|
|
function GetEmpty: Boolean;
|
|
function GetItem(Index: Integer): TdxInspectorComplexRowViewInfoItem;
|
|
protected
|
|
function Add(ARow: TdxInspectorRow): TdxInspectorComplexRowViewInfoItem;
|
|
property Row: TdxInspectorComplexRow read FRow;
|
|
property SeparatorWidth: Integer read FSeparatorWidth;
|
|
public
|
|
constructor Create(ARow: TdxInspectorComplexRow; ASeparatorWidth: Integer);
|
|
destructor Destroy; override;
|
|
procedure Calculate(const ARect: TRect);
|
|
procedure Clear;
|
|
property Count: Integer read GetCount;
|
|
property Empty: Boolean read GetEmpty;
|
|
property Items[Index: Integer]: TdxInspectorComplexRowViewInfoItem read GetItem; default;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{$R dxInsCur.RES}
|
|
|
|
uses
|
|
dxInsCus, Registry;
|
|
|
|
const
|
|
DrawBitmap: TBitmap = nil;
|
|
ScrollTimerId = 1;
|
|
ShowHintTimerId = 2;
|
|
HideHintTimerId = 3;
|
|
WaitForShowHintTime = 1000;
|
|
WaitForHideHintTime = 5000;
|
|
// Cursors
|
|
dxInspectorInsertCursor = 'DXINSP_INSERT';
|
|
dxInspectorAddChildCursor = 'DXINSP_ADDCHILD';
|
|
dxInspectorAddCursor = 'DXINSP_ADD';
|
|
dxInspectorHideCursor = 'DXINSP_HIDE';
|
|
dxInspectorNoDragCursor = 'DXINSP_NODRAG';
|
|
|
|
type
|
|
EFailureLoadOrderRows = class(Exception);
|
|
TWinControlAccess = class(TWinControl);
|
|
|
|
TdxInspectorDragControlObject = class(TDragControlObject)
|
|
private
|
|
function GetInspector: TCustomdxInspector;
|
|
protected
|
|
function GetDragCursor(Accepted: Boolean; X, Y: Integer): TCursor; override;
|
|
property Inspector: TCustomdxInspector read GetInspector;
|
|
end;
|
|
|
|
function TdxInspectorDragControlObject.GetDragCursor(Accepted: Boolean; X, Y: Integer): TCursor;
|
|
begin
|
|
if Inspector.PtInCustomizeForm(Point(X, Y)) then
|
|
Result := crdxInspectorHide
|
|
else
|
|
begin
|
|
if Accepted then
|
|
Result := inherited GetDragCursor(Accepted, X, Y)
|
|
else
|
|
Result := crdxInspectorNoDrag;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorDragControlObject.GetInspector: TCustomdxInspector;
|
|
begin
|
|
Result := Control as TCustomdxInspector;
|
|
end;
|
|
|
|
procedure CreateBitmaps;
|
|
begin
|
|
DrawBitmap := TBitmap.Create;
|
|
end;
|
|
|
|
procedure DestroyBitmaps;
|
|
begin
|
|
if DrawBitmap <> nil then DrawBitmap.Free;
|
|
DrawBitmap := nil;
|
|
end;
|
|
|
|
procedure DrawFocused(ADC: HDC; const ARect: TRect);
|
|
var
|
|
APrevBkColor, APrevTextColor: TColorRef;
|
|
begin
|
|
APrevBkColor := SetBkColor(ADC, clBlack);
|
|
APrevTextColor := SetTextColor(ADC, clWhite);
|
|
Windows.DrawFocusRect(ADC, ARect);
|
|
SetBkColor(ADC, APrevBkColor);
|
|
SetTextColor(ADC, APrevTextColor);
|
|
end;
|
|
|
|
procedure DrawToolboxArrow(ACanvas: TCanvas; ARect: TRect; AExpanded: Boolean);
|
|
|
|
procedure DrawCollapsedArrow(ACanvas: TCanvas; ARect: TRect);
|
|
begin
|
|
with ACanvas, ARect do
|
|
begin
|
|
MoveTo(Left, Top);
|
|
LineTo(Left + 2, Top + 2);
|
|
LineTo(Left, Top + 4);
|
|
LineTo(Left, Top + 3);
|
|
LineTo(Left + 2, Top + 2);
|
|
LineTo(Left, Top + 1);
|
|
LineTo(Left, Top);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawExpandedArrow(ACanvas: TCanvas; ARect: TRect);
|
|
begin
|
|
with ACanvas, ARect do
|
|
begin
|
|
MoveTo(Left, Top);
|
|
LineTo(Left + 2, Top + 2);
|
|
LineTo(Left + 4, Top);
|
|
LineTo(Left + 3, Top);
|
|
LineTo(Left + 2, Top + 2);
|
|
LineTo(Left + 1, Top);
|
|
LineTo(Left, Top);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if AExpanded then
|
|
begin
|
|
DrawExpandedArrow(ACanvas, ARect);
|
|
OffsetRect(ARect, 0, 3);
|
|
DrawExpandedArrow(ACanvas, ARect);
|
|
end
|
|
else
|
|
begin
|
|
DrawCollapsedArrow(ACanvas, ARect);
|
|
OffsetRect(ARect, 3, 0);
|
|
DrawCollapsedArrow(ACanvas, ARect);
|
|
end;
|
|
end;
|
|
|
|
{ TdxInspectorNode }
|
|
|
|
constructor TdxInspectorNode.Create(AOwner: TCustomdxInspector);
|
|
begin
|
|
inherited Create;
|
|
FOwner := AOwner;
|
|
end;
|
|
|
|
destructor TdxInspectorNode.Destroy;
|
|
var
|
|
Prior, Next: TdxInspectorNode;
|
|
fgLast, fgRedraw: Boolean;
|
|
begin
|
|
FDeleting := True;
|
|
DeleteChildren;
|
|
Prior := GetPriorParentNode;
|
|
Next := GetNextNode;
|
|
fgLast := IsLast;
|
|
fgRedraw := IsVisible;
|
|
|
|
if Parent <> nil then
|
|
begin
|
|
if Parent.FList <> nil then
|
|
begin
|
|
Parent.FList.Remove(Self);
|
|
if Parent.Count = 0 then
|
|
begin
|
|
Parent.FList.Free;
|
|
Parent.FList := nil;
|
|
Parent.FExpanded := False;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if FOwner <> nil then
|
|
begin
|
|
FOwner.FNodeList.Remove(self);
|
|
end;
|
|
if FList <> nil then
|
|
FList.Free;
|
|
|
|
FOwner.DeleteNode(Self, Prior, Next, fgLast, fgRedraw);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxInspectorNode.AddChild: TdxInspectorNode;
|
|
begin
|
|
Result := InsertChild(nil);
|
|
end;
|
|
|
|
procedure TdxInspectorNode.Collapse(Recurse: Boolean);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not HasChildren then Exit;
|
|
FOwner.BeginUpdate;
|
|
try
|
|
Expanded := False;
|
|
if Recurse then
|
|
for I := 0 to Count - 1 do
|
|
Items[I].Collapse(Recurse);
|
|
finally
|
|
FOwner.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorNode.DeleteChildren;
|
|
begin
|
|
while Count > 0 do
|
|
Items[0].Free;
|
|
end;
|
|
|
|
procedure TdxInspectorNode.Expand(Recurse: Boolean);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if not HasChildren then Exit;
|
|
FOwner.BeginUpdate;
|
|
try
|
|
Expanded := True;
|
|
if Recurse then
|
|
for I := 0 to Count - 1 do
|
|
Items[i].Expand(Recurse);
|
|
finally
|
|
FOwner.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorNode.GetLastNode: TdxInspectorNode;
|
|
begin
|
|
Result := Self;
|
|
if (Count > 0) and Expanded then
|
|
begin
|
|
Result := Items[Count - 1];
|
|
while (Result.Count > 0) and Result.Expanded do
|
|
Result := Result[Result.Count - 1];
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorNode.GetNextNode: TdxInspectorNode;
|
|
begin
|
|
Result := FOwner.GetNextVisible(Self);
|
|
end;
|
|
|
|
function TdxInspectorNode.GetPriorNode: TdxInspectorNode;
|
|
|
|
function GetPrior(ANode: TdxInspectorNode): TdxInspectorNode;
|
|
begin
|
|
if not ANode.Expanded then Result := ANode
|
|
else Result := GetPrior(ANode[ANode.Count-1]);
|
|
end;
|
|
|
|
begin
|
|
if Index > 0 then
|
|
begin
|
|
if Parent <> nil then
|
|
Result := GetPrior(Parent.Items[Index - 1])
|
|
else Result := GetPrior(FOwner.Items[Index - 1]);
|
|
end
|
|
else Result := Parent;
|
|
end;
|
|
|
|
function TdxInspectorNode.GetPriorParentNode: TdxInspectorNode;
|
|
begin
|
|
if Index > 0 then
|
|
begin
|
|
if Parent <> Nil then
|
|
Result := Parent.Items[Index - 1]
|
|
else Result := FOwner.Items[Index - 1];
|
|
end
|
|
else Result := Parent;
|
|
end;
|
|
|
|
function TdxInspectorNode.HasAsParent(Value: TdxInspectorNode): Boolean;
|
|
var
|
|
ANode: TdxInspectorNode;
|
|
begin
|
|
Result := False;
|
|
ANode := Parent;
|
|
while ANode <> nil do
|
|
begin
|
|
if ANode = Value then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorNode.IndexOf(Value: TdxInspectorNode): Integer;
|
|
begin
|
|
Result := -1;
|
|
if Count > 0 then
|
|
Result := FList.IndexOf(Value);
|
|
end;
|
|
|
|
function TdxInspectorNode.InsertChild(BeforeNode: TdxInspectorNode): TdxInspectorNode;
|
|
begin
|
|
Result := FOwner.CreateNode;
|
|
Result.FParent := self;
|
|
if FList = nil then
|
|
begin
|
|
FList := TList.Create;
|
|
FList.Add(Result);
|
|
end
|
|
else
|
|
begin
|
|
if BeforeNode = nil then
|
|
FList.Add(Result)
|
|
else FList.Insert(BeforeNode.Index, Result);
|
|
end;
|
|
FOwner.AddNode(Result);
|
|
end;
|
|
|
|
procedure TdxInspectorNode.MakeVisible;
|
|
begin
|
|
FOwner.MakeNodeVisible(Self);
|
|
end;
|
|
|
|
procedure TdxInspectorNode.MoveTo(Destination: TdxInspectorNode; Mode: TdxInspectorNodeAttachMode);
|
|
|
|
procedure CheckList(Node: TdxInspectorNode);
|
|
begin
|
|
if Node.FList = nil then
|
|
Node.FList := TList.Create;
|
|
end;
|
|
|
|
begin
|
|
if (Destination = nil) or (Destination.HasAsParent(Self))
|
|
or ((Destination=Self) and
|
|
(Mode in [inaAddChild, inaInsert])) then Exit;
|
|
FOwner.BeginUpdate;
|
|
try
|
|
{InternalRemove}
|
|
if Parent = nil then
|
|
FOwner.FNodeList.Remove(Self)
|
|
else
|
|
begin
|
|
Parent.FList.Remove(Self);
|
|
if Parent.FList.Count = 0 then
|
|
begin
|
|
Parent.FList.Free;
|
|
Parent.FList := nil;
|
|
Parent.FExpanded := False;
|
|
end;
|
|
end;
|
|
{InternalAdd}
|
|
if (Destination.Parent = nil) or
|
|
(Mode in [inaAddChild]) then
|
|
begin
|
|
case Mode of
|
|
inaAdd : FOwner.FNodeList.Add(Self);
|
|
inaInsert : FOwner.FNodeList.Insert(Destination.Index, Self);
|
|
else {Mode in [natlAddChild]}
|
|
begin
|
|
CheckList(Destination);
|
|
Destination.FList.Add(Self);
|
|
end;
|
|
end; {case}
|
|
if (Mode in [inaAddChild]) then
|
|
begin
|
|
FParent := Destination;
|
|
end
|
|
else FParent := nil;
|
|
end
|
|
else
|
|
begin {Parent <> Nil}
|
|
CheckList(Destination.Parent);
|
|
case Mode of
|
|
inaAdd: Destination.Parent.FList.Add(Self);
|
|
inaInsert: Destination.Parent.FList.Insert(Destination.Index, Self);
|
|
end;
|
|
FParent := Destination.Parent;
|
|
end;
|
|
FOwner.FFocused := Self;
|
|
MakeVisible;
|
|
finally
|
|
FOwner.EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
// private
|
|
function TdxInspectorNode.GetAbsoluteIndex: Integer;
|
|
begin
|
|
Result := FOwner.GetAbsoluteIndex(Self);
|
|
end;
|
|
|
|
function TdxInspectorNode.GetCount: Integer;
|
|
begin
|
|
if FList = nil then
|
|
Result := 0
|
|
else Result := FList.Count;
|
|
end;
|
|
|
|
function TdxInspectorNode.GetFocused: Boolean;
|
|
begin
|
|
Result := FOwner.FocusedNode = Self;
|
|
end;
|
|
|
|
function TdxInspectorNode.GetIndex: Integer;
|
|
begin
|
|
if Parent <> nil then
|
|
Result := Parent.IndexOf(Self)
|
|
else Result := FOwner.IndexOf(Self);
|
|
end;
|
|
|
|
function TdxInspectorNode.GetIsLast: Boolean;
|
|
begin
|
|
if Parent <> nil then Result := Index = (Parent.Count - 1)
|
|
else Result := Index = (FOwner.Count - 1);
|
|
end;
|
|
|
|
function TdxInspectorNode.GetIsNodeVisible : Boolean;
|
|
begin
|
|
Result := FOwner.IsNodeVisible(Self);
|
|
end;
|
|
|
|
function TdxInspectorNode.GetItem(Index: Integer): TdxInspectorNode;
|
|
begin
|
|
Result := nil;
|
|
if (Index > -1) and (Index < Count) then
|
|
Result := FList.Items[Index];
|
|
end;
|
|
|
|
function TdxInspectorNode.GetLevel: Integer;
|
|
var
|
|
ANode : TdxInspectorNode;
|
|
begin
|
|
Result := 0;
|
|
ANode := Parent;
|
|
while ANode <> nil do
|
|
begin
|
|
Inc(Result);
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorNode.GetNodeHasChildren: Boolean;
|
|
begin
|
|
Result := Count > 0;
|
|
end;
|
|
|
|
procedure TdxInspectorNode.SetExpanded(Value: Boolean);
|
|
begin
|
|
if not HasChildren then Exit;
|
|
if Value <> Expanded then
|
|
begin
|
|
FExpanded := Value;
|
|
FOwner.UpdateNode(Self, True {Below});
|
|
if not Value and (FOwner.FocusedNode <> nil) and
|
|
FOwner.FocusedNode.HasAsParent(Self) then
|
|
Focused := True;
|
|
// design-time
|
|
if FOwner.FLockExpanded = 0 then
|
|
FOwner.UpdateDesigner;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorNode.SetFocused(Value : Boolean);
|
|
begin
|
|
if Focused = Value then Exit;
|
|
if Value then
|
|
FOwner.SetFocusedNode(Self)
|
|
else FOwner.SetFocusedNode(nil);
|
|
end;
|
|
|
|
{ TCustomdxInspector }
|
|
|
|
constructor TCustomdxInspector.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FNodeList := TList.Create;
|
|
|
|
ControlStyle := [csCaptureMouse, csOpaque, csDoubleClicks, csDisplayDragImage];
|
|
if NewStyleControls then
|
|
ControlStyle := ControlStyle else
|
|
ControlStyle := ControlStyle + [csFramed];
|
|
TabStop := True;
|
|
|
|
Color := dxclInspectorBackgroundColor;
|
|
ParentColor := False;
|
|
FBandSeparatorWidth := 3;
|
|
FBandWidth := 200;
|
|
FBorderStyle := bsSingle;
|
|
FGridColor := dxclInspectorGridColor;
|
|
FGroupColor := clBtnFace;
|
|
FGroupGridColor := clBtnShadow;
|
|
FValueFontColor := dxclInspectorValueFontColor;
|
|
Width := 150;
|
|
Height := 250;
|
|
FMinRowHeight := 18;
|
|
FRowHeight := 18;
|
|
FGridSize := 1;
|
|
FIndent := 6;
|
|
FToolboxButtonWidth := 6 + 4;
|
|
FDividerPos := Width div 2;
|
|
FDividerPosSave.X := FDividerPos;
|
|
FDividerPosSave.Y := -1 ;
|
|
FMaxRowTextLineCount := 3;
|
|
FMinBandWidth := dxInspectorLimitBandWidth;
|
|
FMinColumnWidth := 30;
|
|
FOptions := [ioEditing, ioBandSizing, ioColumnSizing, ioAutoWidth, ioDynamicColumnSizing];
|
|
FCustomizeFormPos := Point(dxInspectorUndefinedValue, dxInspectorUndefinedValue);
|
|
FCustomizeFormSize := Point(dxInspectorUndefinedValue, dxInspectorUndefinedValue);
|
|
|
|
FImageChangeLink := TChangeLink.Create;
|
|
FImageChangeLink.OnChange := ImageListChange;
|
|
|
|
FCellViewData := TdxInspectorCellViewData.Create;
|
|
end;
|
|
|
|
destructor TCustomdxInspector.Destroy;
|
|
begin
|
|
Destroying;
|
|
ClearNodes;
|
|
FNodeList.Free;
|
|
if FDragImageNode <> nil then
|
|
begin
|
|
FDragImageNode.Free;
|
|
FDragImageNode := Nil;
|
|
end;
|
|
FImageChangeLink.Free;
|
|
FCellViewData.Free;
|
|
if FHintWindow <> nil then
|
|
begin
|
|
FHintWindow.Free;
|
|
FHintWindow := nil;
|
|
end;
|
|
if FCustomizeForm <> nil then
|
|
begin
|
|
FCustomizeForm.Free;
|
|
FCustomizeForm := nil;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TCustomdxInspector.Add: TdxInspectorNode;
|
|
begin
|
|
Result := CreateNode;
|
|
FNodeList.Add(Result);
|
|
AddNode(Result);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.BeginUpdate;
|
|
begin
|
|
Inc(FLockUpdate);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.ClearNodes;
|
|
begin
|
|
if not (csDestroying in ComponentState) then BeginUpdate;
|
|
try
|
|
while Count > 0 do Items[0].Free;
|
|
finally
|
|
if not (csDestroying in ComponentState) then EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.HideCustomizeForm;
|
|
begin
|
|
if FCustomizeForm <> nil then
|
|
FCustomizeForm.Close;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.ShowCustomizeForm;
|
|
begin
|
|
HideCustomizeForm;
|
|
FCustomizeForm := CreateInspectorCustomizeForm(Self);
|
|
FCustomizeForm.Show;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.EndUpdate;
|
|
begin
|
|
Dec(FLockUpdate);
|
|
LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.FullCollapse;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Count = 0 then Exit;
|
|
BeginUpdate;
|
|
try
|
|
for I := 0 to Count - 1 do
|
|
Items[I].Collapse(True{Recurse});
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.FullExpand;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Count = 0 then Exit;
|
|
BeginUpdate;
|
|
try
|
|
for I := 0 to Count - 1 do
|
|
Items[i].Expand(True{Recurse});
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetHitTestInfoAt(X, Y: Integer): TdxInspectorHitTest;
|
|
begin
|
|
Result := GetHitInfo(Point(X, Y)).hitType;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetNextVisible(Node: TdxInspectorNode):TdxInspectorNode;
|
|
|
|
function GetLastVisible(Node: TdxInspectorNode): TdxInspectorNode;
|
|
begin
|
|
if Node.Parent = nil then
|
|
Result := Items[Node.Index + 1]
|
|
else
|
|
if (Node.Parent.Count - 1) > Node.Index then
|
|
Result := Node.Parent.Items[Node.Index + 1]
|
|
else Result := GetLastVisible(Node.Parent);
|
|
end;
|
|
|
|
begin
|
|
if Node.Expanded then
|
|
Result := Node.Items[0]
|
|
else
|
|
if Node.Parent = nil then
|
|
begin
|
|
Result := Items[Node.Index + 1]
|
|
end
|
|
else
|
|
begin {Parent <> NIl}
|
|
if Node.Index < (Node.Parent.Count - 1) then
|
|
Result := Node.Parent.Items[Node.Index + 1]
|
|
else {last node}
|
|
Result := GetLastVisible(Node.Parent);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetNodeAt(X, Y: Integer): TdxInspectorNode;
|
|
begin
|
|
Result := GetHitInfo(Point(X, Y)).Node;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetTopParentNode(ANode: TdxInspectorNode): TdxInspectorNode;
|
|
begin
|
|
Result := ANode;
|
|
while ANode <> nil do
|
|
begin
|
|
Result := ANode;
|
|
ANode := ANode.Parent;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.IndexOf(Value: TdxInspectorNode) : Integer;
|
|
begin
|
|
Result := FNodeList.IndexOf(Value);
|
|
end;
|
|
|
|
function TCustomdxInspector.Insert(BeforeNode: TdxInspectorNode) : TdxInspectorNode;
|
|
begin
|
|
Result := CreateNode;
|
|
if (BeforeNode = nil) then FNodeList.Add(Result)
|
|
else FNodeList.Insert(BeforeNode.Index, Result);
|
|
AddNode(Result);
|
|
end;
|
|
|
|
function TCustomdxInspector.IsActive: Boolean;
|
|
begin
|
|
Result := IsActiveControl or
|
|
((InplaceEditor <> nil) and InplaceEditor.IsFocused);
|
|
end;
|
|
|
|
function TCustomdxInspector.IsNodeVisible(Node: TdxInspectorNode): Boolean;
|
|
begin
|
|
Result := False;
|
|
repeat
|
|
Node := Node.Parent;
|
|
if Node = Nil then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end
|
|
else
|
|
if not Node.Expanded then Exit;
|
|
until False;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.MakeNodeVisible(Node: TdxInspectorNode);
|
|
var
|
|
ABandIndex, ATopIndex, AIndex: Integer;
|
|
FlagRepaint: Boolean;
|
|
CurNode: TdxInspectorNode;
|
|
begin
|
|
FlagRepaint := False;
|
|
try
|
|
if not Node.IsVisible then
|
|
begin
|
|
BeginUpdate;
|
|
FlagRepaint := True;
|
|
CurNode := Node.Parent;
|
|
while CurNode <> nil do
|
|
begin
|
|
if not CurNode.Expanded then
|
|
CurNode.Expanded := True;
|
|
CurNode := CurNode.Parent;
|
|
end;
|
|
end;
|
|
ATopIndex := GetAbsoluteIndex(TopVisibleNode);
|
|
AIndex := GetAbsoluteIndex(Node);
|
|
if (ATopIndex <= AIndex) and (AIndex <= (ATopIndex + RowCount - 1)) and
|
|
not FlagRepaint then Exit;
|
|
if IsAutoBandCount then
|
|
begin
|
|
ABandIndex := GetBandIndexByNode(Node);
|
|
if ABandIndex < LeftBandIndex then
|
|
LeftBandIndex := ABandIndex
|
|
else
|
|
if ABandIndex > (LeftBandIndex + VisibleBandCount - 1) then
|
|
LeftBandIndex := ABandIndex - VisibleBandCount + 1;
|
|
end
|
|
else
|
|
begin
|
|
if AIndex < ATopIndex then
|
|
TopIndex := AIndex
|
|
else
|
|
if AIndex > (ATopIndex + RowCount - 1) then
|
|
TopIndex := AIndex - RowCount + 1;
|
|
end;
|
|
finally
|
|
if FlagRepaint then EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.PtInCustomizeForm(const P: TPoint): Boolean;
|
|
var
|
|
ARect: TRect;
|
|
begin
|
|
if (FCustomizeForm <> nil) and FCustomizeForm.HandleAllocated then
|
|
GetWindowRect(FCustomizeForm.Handle, ARect)
|
|
else
|
|
SetRectEmpty(ARect);
|
|
Result := PtInRect(ARect, P);
|
|
end;
|
|
|
|
// Editor : public methods
|
|
procedure TCustomdxInspector.HideEditor;
|
|
begin
|
|
// hide editor if excluding ioEditing or deleting node
|
|
FInplaceNode := nil;
|
|
HideEdit(False);
|
|
FInplaceEdit := nil;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.InvalidateEditor;
|
|
begin
|
|
FInplaceNode := nil;
|
|
CheckEditor(False{no SetFocus if not focused}, True);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.PostEditor; // MouseDown, KeyDown...
|
|
begin
|
|
if (FInplaceEdit <> nil) and FInplaceEdit.IsVisible and
|
|
(FInplaceNode <> nil) then InplaceEditor.ValidateEdit;
|
|
HideEdit(True);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.ShowEditor;
|
|
begin
|
|
if not (ioEditing in Options) then Exit;
|
|
if FocusedNode = nil then Exit;
|
|
// UpdateEdit;
|
|
CheckEditor(True{SetFocus if not focused}, False);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.ShowEditorChar(Ch: Char);
|
|
begin
|
|
ShowEditor;
|
|
if InplaceEditor <> nil then
|
|
PostMessage(InplaceEditor.Handle, WM_CHAR, Word(Ch), 0);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.ShowEditorMouse(X, Y: Integer);
|
|
begin
|
|
ShowEditor;
|
|
if (ioEditing in Options) and (InplaceEditor <> nil) then
|
|
InplaceEditor.MouseClick;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CalcContentDrawInfo(var ADrawInfo: TdxInspectorContentDrawInfo);
|
|
|
|
procedure AddRow(var BandInfo: TdxInspectorBandInfo; ANode: TdxInspectorNode; ARowHeight: Integer);
|
|
begin
|
|
Inc(BandInfo.RowCount);
|
|
ReallocMem(BandInfo.RowsInfo, BandInfo.RowCount * SizeOf(TdxInspectorRowInfo));
|
|
BandInfo.RowsInfo^[BandInfo.RowCount - 1].Node := ANode;
|
|
BandInfo.RowsInfo^[BandInfo.RowCount - 1].RowHeight := ARowHeight;
|
|
end;
|
|
|
|
procedure CalcBandInfo(var BandInfo: TdxInspectorBandInfo; const ARect: TRect;
|
|
ABandIndex: Integer; var ACurNode: TdxInspectorNode; AWriteInfo: Boolean);
|
|
var
|
|
ABandHeight, ABandRowCount, AHeight, ANodeHeight: Integer;
|
|
I: Integer;
|
|
begin
|
|
BandInfo.BandIndex := ABandIndex;
|
|
BandInfo.BandRect := ARect;
|
|
BandInfo.BandContentRect := BandInfo.BandRect;
|
|
if IsAutoBandCount then
|
|
begin
|
|
BandInfo.BandSeparatorRect := BandInfo.BandContentRect;
|
|
BandInfo.BandSeparatorRect.Left := BandInfo.BandSeparatorRect.Right - BandSeparatorWidth;
|
|
BandInfo.BandContentRect.Right := BandInfo.BandSeparatorRect.Left;
|
|
end;
|
|
ABandHeight := BandInfo.BandContentRect.Bottom - BandInfo.BandContentRect.Top;
|
|
ABandRowCount := 0;
|
|
AHeight := 0;
|
|
while ACurNode <> nil do
|
|
begin
|
|
ANodeHeight := GetNodeHeight(ACurNode);
|
|
Inc(AHeight, ANodeHeight);
|
|
Inc(ABandRowCount);
|
|
if IsAutoBandCount and (AHeight > ABandHeight) and (ABandRowCount > 1) then
|
|
Break;
|
|
if AWriteInfo then
|
|
AddRow(BandInfo, ACurNode, ANodeHeight);
|
|
ACurNode := GetNextVisible(ACurNode);
|
|
if AHeight >= ABandHeight then
|
|
Break;
|
|
end;
|
|
if AWriteInfo then
|
|
begin
|
|
AHeight := 0;
|
|
for I := 0 to BandInfo.RowCount - 1 do
|
|
Inc(AHeight, BandInfo.RowsInfo^[I].RowHeight);
|
|
BandInfo.PartRowVisible := AHeight > ABandHeight;
|
|
if AHeight < ABandHeight then
|
|
with BandInfo.BandContentRect do
|
|
BandInfo.EmptyRect := Rect(Left, Top + AHeight, Right, Bottom);
|
|
end;
|
|
end;
|
|
|
|
procedure CalcBandsInfo;
|
|
var
|
|
AStubBandInfo: TdxInspectorBandInfo;
|
|
ACurNode: TdxInspectorNode;
|
|
ARect: TRect;
|
|
I: Integer;
|
|
begin
|
|
with ADrawInfo do
|
|
begin
|
|
BandCount := PartVisibleBandCount;
|
|
BandsInfo := AllocMem(BandCount * SizeOf(TdxInspectorBandInfo));
|
|
if IsAutoBandCount then
|
|
begin
|
|
ACurNode := TopNode;
|
|
ARect := CRect;
|
|
ARect.Right := ARect.Left + BandWidth;
|
|
for I := 0 to LeftBandIndex + PartVisibleBandCount - 1 do
|
|
begin
|
|
if I < LeftBandIndex then
|
|
CalcBandInfo(AStubBandInfo, ARect, I, ACurNode, False{calc only})
|
|
else
|
|
begin
|
|
CalcBandInfo(BandsInfo^[I - LeftBandIndex], ARect, I, ACurNode, True);
|
|
OffsetRect(ARect, BandWidth, 0);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
ACurNode := TopVisibleNode;
|
|
CalcBandInfo(BandsInfo^[0], CRect, 0, ACurNode, True);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
FillChar(ADrawInfo, SizeOf(ADrawInfo), 0);
|
|
with ADrawInfo do
|
|
begin
|
|
CRect := ClientRect;
|
|
CalcBandsInfo;
|
|
if IsAutoBandCount and (BandCount * BandWidth < (CRect.Right - CRect.Left)) then
|
|
begin
|
|
EmptyRect := CRect;
|
|
Inc(EmptyRect.Left, BandCount * BandWidth);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.FreeContentDrawInfo(var ADrawInfo: TdxInspectorContentDrawInfo);
|
|
|
|
procedure FreeBandsInfo(var ABandInfo: TdxInspectorBandInfo);
|
|
begin
|
|
if ABandInfo.RowsInfo <> nil then
|
|
begin
|
|
FreeMem(ABandInfo.RowsInfo);
|
|
ABandInfo.RowsInfo := nil;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
begin
|
|
with ADrawInfo do
|
|
begin
|
|
for I := 0 to BandCount - 1 do
|
|
FreeBandsInfo(BandsInfo^[I]);
|
|
if BandsInfo <> nil then
|
|
begin
|
|
FreeMem(BandsInfo);
|
|
BandsInfo := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.LoadFromRegistry(const ARegPath: string);
|
|
var
|
|
ARegIniFile: TRegIniFile;
|
|
begin
|
|
ARegIniFile := TRegIniFile.Create('');
|
|
try
|
|
if ARegIniFile.OpenKey(ARegPath, False) then
|
|
begin
|
|
ARegIniFile.CloseKey;
|
|
LoadFromRegIni(ARegIniFile, ARegPath);
|
|
end;
|
|
finally
|
|
ARegIniFile.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SaveToRegistry(const ARegPath: string);
|
|
var
|
|
ARegIniFile: TRegIniFile;
|
|
begin
|
|
ARegIniFile := TRegIniFile.Create('');
|
|
try
|
|
SaveToRegIni(ARegIniFile, ARegPath);
|
|
finally
|
|
ARegIniFile.Free;
|
|
end;
|
|
end;
|
|
|
|
// protected TCustomdxInspector
|
|
procedure TCustomdxInspector.CreateParams(var Params: TCreateParams);
|
|
begin
|
|
inherited CreateParams(Params);
|
|
with Params do
|
|
begin
|
|
Style := Style or WS_TABSTOP or WS_CLIPCHILDREN;
|
|
WindowClass.style := CS_DBLCLKS or CS_VREDRAW or CS_HREDRAW;
|
|
if (FBorderStyle = bsSingle) and not Flat then
|
|
if NewStyleControls and Ctl3D then
|
|
begin
|
|
Style := Style and not WS_BORDER;
|
|
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
|
|
end
|
|
else
|
|
Style := Style or WS_BORDER;
|
|
Style := Style or WS_VSCROLL;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoEndDrag(Target: TObject; X, Y: Integer);
|
|
begin
|
|
if not IsInternalDragging then
|
|
inherited DoEndDrag(Target, X, Y)
|
|
else
|
|
DragCursor := FPrevDragCursor;
|
|
FDragNode := nil;
|
|
SetState(isNormal);
|
|
CheckEditor(True, False);
|
|
if (FDragImageNode <> nil) then
|
|
begin
|
|
FDragImageNode.Free;
|
|
FDragImageNode := nil;
|
|
end;
|
|
if FDragObject <> nil then
|
|
begin
|
|
FDragObject.Free;
|
|
FDragObject := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoExit;
|
|
begin
|
|
inherited DoExit;
|
|
HideEditor;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoStartDrag(var DragObject: TDragObject);
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
if not IsInternalDragging then
|
|
inherited DoStartDrag(DragObject)
|
|
else
|
|
FPrevDragCursor := DragCursor;
|
|
DrawDragNode;
|
|
SetState(isNodeDragging);
|
|
HideEditor;
|
|
Windows.SetFocus(Handle);
|
|
GetCursorPos(P);
|
|
DoDragScroll(P);
|
|
if IsInternalDragging then
|
|
begin
|
|
FDragObject := TdxInspectorDragControlObject.Create(Self);
|
|
DragObject := FDragObject;
|
|
if (FDragNode <> nil) and (FCustomizeForm <> nil) then
|
|
SendMessage(FCustomizeForm.Handle, CM_PREPARECUSTOMIZEFORM, Integer(IsCategoryNode(FDragNode)), 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DragDrop(Source: TObject; X, Y: Integer);
|
|
var
|
|
AHitTest: TdxInspectorHitTest;
|
|
ADestinationNode: TdxInspectorNode;
|
|
AAttachMode: TdxInspectorNodeAttachMode;
|
|
begin
|
|
if IsInternalDragging then
|
|
begin
|
|
if (FDragNode <> nil) and PtInCustomizeForm(ClientToScreen(Point(X, Y))) then
|
|
TdxInspectorRowNode(FDragNode).Row.Visible := False
|
|
else
|
|
begin
|
|
AHitTest := GetHitTestInfoAt(X, Y);
|
|
if AHitTest in [ihtIndent, ihtButton, ihtImage, ihtDisplayLabel, ihtLabel,
|
|
ihtColumnEdge, ihtComplexRowSeparator, ihtNowhere] then
|
|
begin
|
|
ADestinationNode := GetNodeAt(X, Y);
|
|
AAttachMode := inaAddChild;
|
|
case AHitTest of
|
|
ihtIndent, ihtButton, ihtImage:
|
|
AAttachMode := inaInsert;
|
|
ihtDisplayLabel, ihtLabel, ihtComplexRowSeparator:
|
|
AAttachMode := inaAddChild;
|
|
ihtNowhere:
|
|
begin
|
|
AAttachMode := inaAdd;
|
|
ADestinationNode := Items[0];
|
|
end;
|
|
end;
|
|
DragDropTo(FDragNode, ADestinationNode, AAttachMode);
|
|
if (FDragNode <> nil) and (ADestinationNode <> nil) then
|
|
FDragNode.MoveTo(ADestinationNode, AAttachMode);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
inherited DragDrop(Source, X, Y);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DragOver(Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
|
|
var
|
|
AHitTest: TdxInspectorHitTest;
|
|
begin
|
|
if not IsInternalDragging then
|
|
inherited DragOver(Source, X, Y, State, Accept)
|
|
else
|
|
begin
|
|
if Accept then
|
|
begin
|
|
AHitTest := GetHitTestInfoAt(X, Y);
|
|
case AHitTest of
|
|
ihtIndent, ihtButton, ihtImage:
|
|
DragCursor := crdxInspectorInsert;
|
|
ihtDisplayLabel, ihtLabel, ihtComplexRowSeparator:
|
|
DragCursor := crdxInspectorAddChild;
|
|
ihtNowhere:
|
|
DragCursor := crdxInspectorAdd;
|
|
else
|
|
Accept := False;
|
|
end;
|
|
end;
|
|
end;
|
|
if not Dragging then Exit;
|
|
DoDragScroll(Point(X, Y));
|
|
end;
|
|
|
|
function TCustomdxInspector.GetDragImages: {$IFDEF DELPHI4}TDragImageList{$ELSE}TCustomImageList{$ENDIF};
|
|
begin
|
|
Result := FDragImageNode;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.KeyDown(var Key: Word; Shift: TShiftState);
|
|
|
|
function IsTop: Boolean;
|
|
begin
|
|
Result := (FocusedNode = TopNode) and not (ioTabThrough in Options) and
|
|
not ((Key = VK_TAB) and IsGoTabComplexRowAvailable(False));
|
|
end;
|
|
|
|
function IsBottom: Boolean;
|
|
begin
|
|
Result := (FocusedNode = LastNode) and not (ioTabThrough in Options) and
|
|
not ((Key = VK_TAB) and IsGoTabComplexRowAvailable(True));
|
|
end;
|
|
|
|
procedure GoTab(AForward: Boolean);
|
|
begin
|
|
if GoTabComplexRow(AForward) then Exit;
|
|
if not AForward then
|
|
begin
|
|
if (ioTabThrough in Options) and (FocusedNode = TopNode) then
|
|
TWinControlAccess(GetParentForm(Self)).SelectNext(Self, False, True)
|
|
else
|
|
FocusedNumber := FocusedNumber - 1;
|
|
end
|
|
else
|
|
begin
|
|
if (ioTabThrough in Options) and (FocusedNode = LastNode) then
|
|
TWinControlAccess(GetParentForm(Self)).SelectNext(Self, True, True)
|
|
else
|
|
FocusedNumber := FocusedNumber + 1;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
// check visible
|
|
inherited KeyDown(Key, Shift);
|
|
if FState in [isColumnSizing, isBandSizing, isRowSizing] then
|
|
begin
|
|
if Key = VK_ESCAPE then
|
|
CancelDragSizing;
|
|
Exit;
|
|
end;
|
|
if Dragging and IsAutoDrag and (Key = VK_ESCAPE) then EndDrag(False);
|
|
if Count = 0 then Exit;
|
|
if (Key in [VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_TAB, VK_RETURN]) and
|
|
(ioEditing in Options) then
|
|
begin
|
|
if ({*}((Key in [VK_UP, VK_PRIOR]) or ((Key = VK_TAB) and (ssShift in Shift))){*} and IsTop) or
|
|
({*}((Key in [VK_DOWN, VK_NEXT]) or ((Key = VK_TAB) and not (ssShift in Shift))){*} and IsBottom) then
|
|
begin
|
|
if Assigned(FInplaceEdit) and FInplaceEdit.Modified then
|
|
begin
|
|
PostEditor;
|
|
InvalidateEditor;
|
|
end;
|
|
Exit;
|
|
end;
|
|
PostEditor;
|
|
end;
|
|
case Key of
|
|
VK_NEXT:
|
|
if ssCtrl in Shift then
|
|
FocusedNumber := GetAbsoluteCount - 1
|
|
else
|
|
FocusedNumber := FocusedNumber + RowCount; // TODO: Band.RowCount?
|
|
VK_PRIOR:
|
|
if ssCtrl in Shift then
|
|
FocusedNumber := 0
|
|
else
|
|
FocusedNumber := FocusedNumber - RowCount; // TODO: Band.RowCount?
|
|
VK_UP:
|
|
FocusedNumber := FocusedNumber - 1;
|
|
VK_DOWN:
|
|
FocusedNumber := FocusedNumber + 1;
|
|
VK_ESCAPE:
|
|
begin
|
|
InvalidateEditor;
|
|
if FInplaceEdit <> nil then
|
|
FInplaceEdit.Deselect;
|
|
end;
|
|
VK_TAB:
|
|
if not (ssAlt in Shift) then
|
|
GoTab(not (ssShift in Shift));
|
|
VK_RETURN:
|
|
if (ioEnterThrough in Options) then
|
|
GoTab(True);
|
|
end;
|
|
DoCheckKeyDown(Key, Shift);
|
|
if (Key In [VK_UP, VK_DOWN, VK_PRIOR, VK_NEXT, VK_TAB, VK_RETURN]) and
|
|
(ioEditing in Options) then
|
|
InvalidateEditor;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
|
|
function GetLastBandNode(ABandIndex: Integer): TdxInspectorNode;
|
|
var
|
|
ABandRowCount: Integer;
|
|
ANode: TdxInspectorNode;
|
|
begin
|
|
GetBandRowInfo(False, ANode, ABandIndex, ABandRowCount);
|
|
Result := GetAbsoluteNode(GetAbsoluteIndex(ANode) + ABandRowCount - 1);
|
|
end;
|
|
|
|
var
|
|
Node: TdxInspectorNode;
|
|
begin
|
|
if Focused or ((FInplaceEdit <> nil) and (FInplaceEdit.Focused)) then
|
|
PostEditor;
|
|
if not (csDesigning in ComponentState) and
|
|
(CanFocus or (GetParentForm(Self) = nil)) then
|
|
begin
|
|
SetFocus;
|
|
//Windows.SetFocus(Handle);
|
|
if not IsActiveControl then
|
|
begin
|
|
MouseCapture := False;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
FHitInfo := GetHitInfo(Point(X, Y));
|
|
FComplexRowIndex := FHitInfo.ComplexRowIndex;
|
|
|
|
// if Right button pressed then Cancel Drag and Sizing
|
|
if (FState <> isNormal) and (Button = mbRight) then
|
|
CancelDragSizing;
|
|
|
|
if (FState = isNormal) and (Button = mbLeft) and (GetCapture = Handle) then
|
|
begin
|
|
if (FHitInfo.hitType = ihtColumnEdge) and (ioColumnSizing in Options) then
|
|
begin
|
|
SetState(isColumnSizing);
|
|
FSaveSizingPos := DividerPos; // for dynamic sizing
|
|
FSizingBandIndex := FHitInfo.BandIndex;
|
|
FSizingPos := X;
|
|
UpdateWindow(Handle);
|
|
DrawSizingLine;
|
|
Exit;
|
|
end;
|
|
if (FHitInfo.hitType = ihtBandSeparator) and (ioBandSizing in Options) then
|
|
begin
|
|
SetState(isBandSizing);
|
|
FSaveSizingPos := BandWidth; // for dynamic sizing
|
|
FSizingBandIndex := FHitInfo.BandIndex;
|
|
FSizingPos := X;
|
|
UpdateWindow(Handle);
|
|
DrawSizingLine;
|
|
Exit;
|
|
end;
|
|
if (FHitInfo.hitType = ihtRowEdge) and (FHitInfo.Node <> nil) then
|
|
begin
|
|
SetState(isRowSizing);
|
|
FSaveSizingPos := GetNodeHeight(FHitInfo.Node); // for dynamic sizing
|
|
FSizingNode := FHitInfo.Node;
|
|
FSizingPos := Y;
|
|
UpdateWindow(Handle);
|
|
DrawSizingLine;
|
|
Exit;
|
|
end;
|
|
if (FHitInfo.hitType in [ihtButton, ihtIndent, ihtImage, ihtDisplayLabel,
|
|
ihtLabel, ihtComplexRowSeparator]) then
|
|
begin
|
|
SetState(isNodeDown);
|
|
FDragNode := FHitInfo.Node;
|
|
if PaintStyle = ipsCategorized then
|
|
InvalidateNode(FDragNode, False);
|
|
FPointDragging.X := X;
|
|
FPointDragging.Y := Y;
|
|
SetFocusedNode(FHitInfo.Node);
|
|
if (FHitInfo.hitType = ihtButton) or
|
|
((FHitInfo.hitType in [ihtImage, ihtDisplayLabel]) and (ssDouble in Shift)) then
|
|
begin
|
|
FHitInfo.Node.Expanded := not FHitInfo.Node.Expanded;
|
|
if (ssDouble in Shift) then DblClick;
|
|
SetState(isNormal);
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
Exit;
|
|
end;
|
|
if X > FDividerPos then
|
|
try
|
|
// ShowEditorMouse(X, Y);
|
|
ShowEditor;
|
|
FInplaceComplexRowIndexPushed := FHitInfo.ComplexRowIndex;
|
|
FInplaceEditPushed := FInplaceEdit;
|
|
FInplaceNodePushed := FInplaceNode;
|
|
except
|
|
SetState(isNormal);
|
|
raise;
|
|
end
|
|
else
|
|
ShowEditor;
|
|
Click;
|
|
SetTimer(Handle, 1, 60, nil);
|
|
end;
|
|
end;
|
|
|
|
if (Button = mbLeft) and (ssDouble in Shift) and
|
|
(FHitInfo.hitType in [ihtNowhere]) then DblClick;
|
|
|
|
if (Button in [mbLeft]) and (FHitInfo.hitType in [ihtNowhere]) then
|
|
begin
|
|
if IsAutoBandCount then
|
|
begin
|
|
if FHitInfo.BandIndex <> -1 then
|
|
Node := GetLastBandNode(FHitInfo.BandIndex)
|
|
else
|
|
Node := nil;
|
|
end
|
|
else
|
|
Node := LastNode;
|
|
if Node <> nil then
|
|
begin
|
|
Node.Focused := True;
|
|
Node.MakeVisible;
|
|
ShowEditor;
|
|
end;
|
|
end;
|
|
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
|
|
procedure CorrectDividerPos(var AX: Integer);
|
|
var
|
|
ADividerPos: Integer;
|
|
begin
|
|
ADividerPos := AX - (FSizingBandIndex - LeftBandIndex) * BandWidth;
|
|
CheckDividerPos(ADividerPos);
|
|
AX := ADividerPos + (FSizingBandIndex - LeftBandIndex) * BandWidth;
|
|
end;
|
|
|
|
procedure CorrectBandSeparatorPos(var AX: Integer);
|
|
var
|
|
ABandWidth: Integer;
|
|
begin
|
|
ABandWidth := AX - (FSizingBandIndex - LeftBandIndex) * BandWidth;
|
|
CheckBandWidth(ABandWidth);
|
|
AX := ABandWidth + (FSizingBandIndex - LeftBandIndex) * BandWidth;
|
|
if AX > ClientWidth then AX := ClientWidth;
|
|
end;
|
|
|
|
procedure CorrectRowPos(var AY: Integer; ANode: TdxInspectorNode);
|
|
var
|
|
ARect: TRect;
|
|
AMinRowHeight: Integer;
|
|
begin
|
|
AMinRowHeight := GetMinRowHeight(ANode);
|
|
if Assigned(FSizingNode) then
|
|
begin
|
|
ARect := GetRectNode(FSizingNode);
|
|
if (AY - ARect.Top + 1) < AMinRowHeight then
|
|
AY := ARect.Top + AMinRowHeight - 1;
|
|
end;
|
|
if AY > (ClientHeight - 1) then
|
|
AY := ClientHeight - 1;
|
|
end;
|
|
|
|
var
|
|
Node: TdxInspectorNode;
|
|
begin
|
|
FHitInfo := GetHitInfo(Point(X, Y));
|
|
|
|
if FState = isColumnSizing then
|
|
begin
|
|
CorrectDividerPos(X);
|
|
if FSizingPos <> X then
|
|
begin
|
|
DrawSizingLine;
|
|
FSizingPos := X;
|
|
DrawSizingLine;
|
|
if IsDynamicColumnSizing then
|
|
DividerPos := CalcDividerPos(FSizingPos);
|
|
end;
|
|
end;
|
|
|
|
if FState = isBandSizing then
|
|
begin
|
|
CorrectBandSeparatorPos(X);
|
|
if FSizingPos <> X then
|
|
begin
|
|
DrawSizingLine;
|
|
FSizingPos := X;
|
|
DrawSizingLine;
|
|
BandWidth := CalcBandWidth(FSizingPos);
|
|
end;
|
|
end;
|
|
|
|
if FState = isRowSizing then
|
|
begin
|
|
CorrectRowPos(Y, FHitInfo.Node);
|
|
if FSizingPos <> Y then
|
|
begin
|
|
DrawSizingLine;
|
|
FSizingPos := Y;
|
|
DrawSizingLine;
|
|
end;
|
|
end;
|
|
|
|
if FState = isNodeDown then
|
|
begin
|
|
HideRowHint;
|
|
if not (ssLeft in Shift) then
|
|
CheckDownNode(True)
|
|
else
|
|
if IsAutoDrag then
|
|
begin
|
|
if ((X < FPointDragging.X - 5) or (X > FPointDragging.X + 5) or
|
|
(Y < FPointDragging.Y - 5) or (Y > FPointDragging.Y + 5)) then
|
|
begin
|
|
Node := FDragNode;
|
|
if Node = nil then
|
|
Node := FHitInfo.Node;
|
|
if Node <> nil then
|
|
begin
|
|
if Node <> FocusedNode then
|
|
Node.Focused := True;
|
|
CheckDownNode(False);
|
|
FDragNode := Node;
|
|
BeginDrag(False);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
FHitInfo := GetHitInfo(Point(X, Y));
|
|
if (FHitInfo.Node <> nil) and
|
|
(FHitInfo.Node.AbsoluteIndex < TopIndex + RowCount) then // completely visible
|
|
begin
|
|
SetFocusedNode(FHitInfo.Node);
|
|
if (FocusedNode <> FInplaceNodePushed) then
|
|
FInplaceNodePushed := nil;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if ShowRowHint then
|
|
if (FState = isNormal) and (FHitInfo.hitType in [ihtDisplayLabel, ihtLabel]) then
|
|
begin
|
|
if (FHitInfo.Node <> FPrevHintNode) or (FHitInfo.hitType <> FPrevHintTest) or
|
|
(FHitInfo.ComplexRowIndex <> FPrevHintComplexRowIndex) then
|
|
StartShowRowHint(True{wait});
|
|
FPrevHintComplexRowIndex := FHitInfo.ComplexRowIndex;
|
|
FPrevHintNode := FHitInfo.Node;
|
|
FPrevHintTest := FHitInfo.hitType;
|
|
end
|
|
else
|
|
ClearPrevHintNode;
|
|
|
|
CheckHotTrackNode(FHitInfo.Node);
|
|
|
|
inherited MouseMove(Shift, X, Y);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
|
|
|
|
procedure CalcRowHeight(ANode: TdxInspectorNode; AY: Integer);
|
|
var
|
|
ARect: TRect;
|
|
AMinRowHeight: Integer;
|
|
begin
|
|
if Assigned(FSizingNode) then
|
|
begin
|
|
AMinRowHeight := GetMinRowHeight(ANode);
|
|
ARect := GetRectNode(FSizingNode);
|
|
if AY > (ClientHeight - 1) then
|
|
AY := ClientHeight - 1;
|
|
if (AY - ARect.Top + 1) < AMinRowHeight then
|
|
AY := ARect.Top + AMinRowHeight - 1;
|
|
SetNodeHeight(FSizingNode, AY - ARect.Top + 1);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
FHitInfo := GetHitInfo(Point(X, Y));
|
|
|
|
if FState = isNodeDown then
|
|
CheckDownNode(FHitInfo.Node = FDragNode);
|
|
|
|
if FState = isColumnSizing then
|
|
begin
|
|
DrawSizingLine;
|
|
DividerPos := CalcDividerPos(FSizingPos);
|
|
SetState(isNormal);
|
|
UpdateDesigner;
|
|
end;
|
|
|
|
if FState = isBandSizing then
|
|
begin
|
|
DrawSizingLine;
|
|
BandWidth := CalcBandWidth(FSizingPos);
|
|
SetState(isNormal);
|
|
UpdateDesigner;
|
|
end;
|
|
|
|
if FState = isRowSizing then
|
|
begin
|
|
DrawSizingLine;
|
|
if FSizingNode <> nil then
|
|
CalcRowHeight(FSizingNode, FSizingPos);
|
|
SetState(isNormal);
|
|
UpdateDesigner;
|
|
end;
|
|
|
|
if FState = isNodeDown then
|
|
begin
|
|
KillTimer(Handle, ScrollTimerId);
|
|
SetState(isNormal);
|
|
end;
|
|
|
|
// new
|
|
if (FInplaceEdit <> nil) and (FInplaceNode <> nil) and
|
|
(FInplaceEdit = FInplaceEditPushed) and (FInplaceNode = FInplaceNodePushed) and
|
|
(FHitInfo.hitType = ihtLabel) and (FHitInfo.ComplexRowIndex = FInplaceComplexRowIndexPushed) then
|
|
begin
|
|
FInplaceComplexRowIndexPushed := -1;
|
|
FInplaceEditPushed := nil;
|
|
FInplaceNodePushed := nil;
|
|
FInplaceEdit.MouseClick; // FInplaceEdit can be NULL (Custom Events)
|
|
if FInplaceEdit <> nil then
|
|
FInplaceEdit.InvalidateEdit;
|
|
end;
|
|
|
|
inherited MouseUp(Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.Loaded;
|
|
begin
|
|
inherited Loaded;
|
|
LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.Notification(AComponent: TComponent; Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if Operation = opRemove then
|
|
begin
|
|
if AComponent = Images then
|
|
Images := nil;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.Paint;
|
|
var
|
|
ADrawInfo: TdxInspectorContentDrawInfo;
|
|
|
|
procedure DrawFocusFrame;
|
|
var
|
|
R: TRect;
|
|
TmpRgn1, TmpRgn2: HRGN;
|
|
begin
|
|
R := GetRectByNode(FocusedNode, ADrawInfo);
|
|
if IsRectEmpty(R) then Exit;
|
|
with Canvas do
|
|
begin
|
|
R := Rect(R.Left - 1, R.Top - 2, R.Right + 1, R.Bottom);
|
|
DrawEdge(Handle, R, BDR_SUNKENOUTER or BDR_SUNKENINNER, BF_TOPLEFT);
|
|
DrawEdge(Handle, R, BDR_SUNKENOUTER, BF_BOTTOMRIGHT);
|
|
// exclude rect
|
|
TmpRgn1 := CreateRectRgnIndirect(R);
|
|
R := Rect(R.Left + 2, R.Top + 2, R.Right - 1, R.Bottom - 1);
|
|
TmpRgn2 := CreateRectRgnIndirect(R);
|
|
CombineRgn(TmpRgn1, TmpRgn1, TmpRgn2, RGN_XOR);
|
|
if GetClipRgn(Handle, TmpRgn2) = 0 then
|
|
begin
|
|
DeleteObject(TmpRgn2);
|
|
TmpRgn2 := CreateRectRgnIndirect(ADrawInfo.CRect);
|
|
end;
|
|
CombineRgn(TmpRgn2, TmpRgn2, TmpRgn1, RGN_DIFF);
|
|
SelectClipRgn(Handle, TmpRgn2);
|
|
DeleteObject(TmpRgn2);
|
|
DeleteObject(TmpRgn1);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawNETGridLine(ARowRect: TRect; ANode: TdxInspectorNode);
|
|
var
|
|
ANextNode, ATopParentNode: TdxInspectorNode;
|
|
ABrush1, ABrush2: HBRUSH;
|
|
ARect1, ARect2: TRect;
|
|
begin
|
|
ARowRect.Top := ARowRect.Bottom - 1;
|
|
ARect1 := ARowRect;
|
|
ARect1.Right := ARect1.Left + FIndent;
|
|
ARect2 := ARowRect;
|
|
Inc(ARect2.Left, FIndent);
|
|
if IsCategoryNode(ANode) and (ANode.Level = 0) then
|
|
begin
|
|
ABrush2 := FGroupGridBrush;
|
|
if ANode.Expanded then
|
|
begin
|
|
ABrush1 := FGroupBkBrush;
|
|
Dec(ARect1.Right);
|
|
Dec(ARect2.Left);
|
|
end
|
|
else
|
|
ABrush1 := ABrush2;
|
|
end
|
|
else
|
|
begin
|
|
if ANode = LastNode then
|
|
ABrush1 := FGridBrush
|
|
else
|
|
ABrush1 := FBkBrush;
|
|
ABrush2 := FGridBrush;
|
|
ANextNode := ANode.GetNextNode;
|
|
if (IsCategoryNode(ANextNode) and (ANextNode.Level = 0)) then
|
|
begin
|
|
ABrush2 := FGroupGridBrush;
|
|
ABrush1 := ABrush2;
|
|
end
|
|
else
|
|
begin
|
|
ATopParentNode := GetTopParentNode(ANode);
|
|
if IsCategoryNode(ATopParentNode) then
|
|
begin
|
|
if ATopParentNode.GetLastNode = ANode then
|
|
begin
|
|
ABrush1 := FGroupGridBrush;
|
|
ABrush2 := ABrush1;
|
|
end
|
|
else
|
|
ABrush1 := FGroupBkBrush;
|
|
end;
|
|
end;
|
|
end;
|
|
Windows.FillRect(Canvas.Handle, ARect1, ABrush1);
|
|
Windows.FillRect(Canvas.Handle, ARect2, ABrush2);
|
|
end;
|
|
|
|
procedure DrawGridLine(ARowRect: TRect; ANode: TdxInspectorNode);
|
|
var
|
|
APrevBkColor, APrevTextColor: TColorRef;
|
|
ABrush: HBRUSH;
|
|
begin
|
|
with Canvas do
|
|
begin
|
|
APrevBkColor := GetBkColor(Handle);
|
|
APrevTextColor := GetTextColor(Handle);
|
|
if PaintStyle in [ipsStandard, ipsExtended] then
|
|
begin
|
|
SetBkColor(Handle, ColorToRGB(FGridColor));
|
|
SetTextColor(Handle, ColorToRGB(Self.Color));
|
|
ABrush := HalftoneBrush;
|
|
end
|
|
else
|
|
ABrush := FGridBrush;
|
|
if PaintStyle = ipsNET then
|
|
DrawNETGridLine(ARowRect, ANode)
|
|
else
|
|
begin
|
|
ARowRect.Top := ARowRect.Bottom - 1;
|
|
Windows.FillRect(Handle, ARowRect, ABrush);
|
|
end;
|
|
if PaintStyle in [ipsStandard, ipsExtended] then
|
|
begin
|
|
SetBkColor(Handle, APrevBkColor);
|
|
SetTextColor(Handle, APrevTextColor);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DrawButton(AButtonRect: TRect; AButtonKind: TdxInspectorButtonKind);
|
|
begin
|
|
with Canvas, AButtonRect do
|
|
begin
|
|
Left := (Left + Right - dxInspectorButtonSize) div 2 - 1;
|
|
Top := (Top + Bottom - dxInspectorButtonSize) div 2;
|
|
Right := Left + dxInspectorButtonSize;
|
|
Bottom := Top + dxInspectorButtonSize;
|
|
// draw
|
|
Pen.Color := Self.Font.Color;
|
|
Windows.FillRect(Handle, AButtonRect, FBkBrush); // ?
|
|
Polyline([Point(Left, Top), Point(Right-1, Top),
|
|
Point(Right-1, Bottom-1), Point(Left, Bottom-1), Point(Left, Top)]);
|
|
MoveTo(Left + 2, Top + 4);
|
|
LineTo(Left + 7, Top + 4);
|
|
if AButtonKind = ibkPlus then
|
|
begin
|
|
MoveTo(Left + 4, Top + 2);
|
|
LineTo(Left + 4, Top + 7);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DrawToolboxButton(AButtonRect: TRect; AButtonKind: TdxInspectorButtonKind);
|
|
var
|
|
AButtonWidth, AButtonHeight: Integer;
|
|
begin
|
|
with Canvas, AButtonRect do
|
|
begin
|
|
FillRect(AButtonRect);
|
|
if AButtonKind = ibkPlus then
|
|
begin
|
|
AButtonWidth := 6;
|
|
AButtonHeight := 5;
|
|
end
|
|
else
|
|
begin
|
|
AButtonWidth := 5;
|
|
AButtonHeight := 6;
|
|
end;
|
|
Left := (Left + Right - AButtonWidth) div 2;
|
|
Top := (Top + Bottom - AButtonHeight) div 2;
|
|
Right := Left + AButtonWidth;
|
|
Bottom := Top + AButtonHeight;
|
|
// draw
|
|
Pen.Color := Self.Font.Color;
|
|
DrawToolboxArrow(Canvas, AButtonRect, AButtonKind = ibkMinus);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawToolboxFrame(ARect: TRect; ANode: TdxInspectorNode; ANodeDrawInfo: TdxInspectorDrawInfo);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if IsCategoryNode(ANode) then
|
|
begin
|
|
// Indent
|
|
FillRect(Canvas.Handle, ANodeDrawInfo.IndentRect, FBkBrush);
|
|
// Frame
|
|
ARect.Left := ANodeDrawInfo.IndentRect.Right;
|
|
if ANode.Focused or IsHotTrackNode(ANode) then
|
|
begin
|
|
if (State = isNodeDown) and (FDragNode = ANode) then
|
|
begin
|
|
DrawEdge(Canvas.Handle, ARect, BDR_SUNKENOUTER, BF_RIGHT or BF_BOTTOM or BF_ADJUST);
|
|
DrawEdge(Canvas.Handle, ARect, BDR_SUNKENINNER, BF_LEFT or BF_TOP);
|
|
end
|
|
else
|
|
begin
|
|
DrawEdge(Canvas.Handle, ARect, BDR_RAISEDOUTER, BF_RIGHT or BF_BOTTOM or BF_ADJUST);
|
|
DrawEdge(Canvas.Handle, ARect, BDR_RAISEDINNER, BF_LEFT or BF_TOP);
|
|
end;
|
|
end
|
|
else
|
|
FrameRect(Canvas.Handle, ARect, FBkBrush);
|
|
// Button
|
|
if ANodeDrawInfo.ButtonKind <> ibkNone then
|
|
DrawToolboxButton(ANodeDrawInfo.ButtonRect, ANodeDrawInfo.ButtonKind);
|
|
end
|
|
else
|
|
begin
|
|
// Frame
|
|
for I := 0 to FRowFrameSize - 1 do
|
|
begin
|
|
FrameRect(Canvas.Handle, ARect, FBkBrush);
|
|
InflateRect(ARect, -1, -1);
|
|
end;
|
|
// Indent
|
|
FillRect(Canvas.Handle, ANodeDrawInfo.IndentRect, FBkBrush);
|
|
// Button
|
|
if ANodeDrawInfo.ButtonKind <> ibkNone then
|
|
DrawButton(ANodeDrawInfo.ButtonRect, ANodeDrawInfo.ButtonKind);
|
|
end;
|
|
end;
|
|
|
|
procedure DrawBand(ABandInfo: TdxInspectorBandInfo);
|
|
var
|
|
APrevDivider: Boolean;
|
|
|
|
procedure DrawNode(ARect: TRect; ANode: TdxInspectorNode);
|
|
var
|
|
ANodeDrawInfo: TdxInspectorDrawInfo;
|
|
ACaptionText, ADisplayText: string;
|
|
AAlignment: TAlignment;
|
|
TmpRgn1, TmpRgn2: HRGN;
|
|
IsClipRgnExists: Boolean;
|
|
begin
|
|
CalcDrawInfo(ANode, ARect, ANodeDrawInfo);
|
|
ACaptionText := '';
|
|
ADisplayText := '';
|
|
GetNodeText(ANode, ACaptionText, ADisplayText);
|
|
with Canvas, ANodeDrawInfo do
|
|
begin
|
|
// Draw Caption
|
|
Brush.Color := Self.Color;
|
|
Font := Self.Font;
|
|
if not (PaintStyle in [ipsStandard, ipsExtended]) then
|
|
begin
|
|
if PaintStyle = ipsCategorized then
|
|
begin
|
|
if IsCategoryNode(ANode) then
|
|
Brush.Color := clBtnShadow;
|
|
DrawToolboxFrame(ARect, ANode, ANodeDrawInfo);
|
|
end;
|
|
if (PaintStyle = ipsNET) and (IsCategoryNode(ANode) and (ANode.Level = 0)) then
|
|
Brush.Color := FGroupColor;
|
|
if ANode.Focused and (PaintStyle <> ipsCategorized) then
|
|
begin
|
|
Brush.Color := clHighlight;
|
|
Font.Color := clHighlightText;
|
|
end;
|
|
if ANode.HasChildren and
|
|
not ((PaintStyle in [ipsNET, ipsCategorized]) and not IsCategoryNode(ANode)) then
|
|
Font.Style := Font.Style + [fsBold]
|
|
else
|
|
Font.Style := Font.Style - [fsBold];
|
|
end;
|
|
// set clip rgn (if needed)
|
|
if not IsCategoryNode(ANode) and (IndentRect.Right > DisplayRect.Right) then
|
|
begin
|
|
TmpRgn1 := CreateRectRgn(0, 0, 0, 0); // PrevRgn
|
|
IsClipRgnExists := GetClipRgn(Handle, TmpRgn1) = 1;
|
|
TmpRgn2 := CreateRectRgn(ARect.Left, ARect.Top, DisplayRect.Right, ARect.Bottom);
|
|
ExtSelectClipRgn(Handle, TmpRgn2, RGN_AND);
|
|
DeleteObject(TmpRgn2);
|
|
end
|
|
else
|
|
begin
|
|
TmpRgn1 := 0;
|
|
IsClipRgnExists := False;
|
|
end;
|
|
// Indent, Button, Caption
|
|
if IsCategoryNode(ANode) then
|
|
Font.Style := Font.Style + [fsBold];
|
|
DoDrawCaption(Canvas, ANode,
|
|
IndentRect, ButtonRect, ImageRect, ButtonKind, {Button region}
|
|
DisplayRect, ACaptionText);
|
|
// // Focus Rect for Category
|
|
if IsActive and ANode.Focused and (PaintStyle = ipsCategorized) and not IsCategoryNode(ANode) then
|
|
with DisplayRect do
|
|
DrawFocused(Handle, Rect(Left - 1, Top, Right - 1, Bottom)); // TODO: !
|
|
// restore clip rgn
|
|
if TmpRgn1 <> 0 then
|
|
begin
|
|
if IsClipRgnExists then
|
|
SelectClipRgn(Handle, TmpRgn1)
|
|
else
|
|
SelectClipRgn(Handle, 0);
|
|
DeleteObject(TmpRgn1);
|
|
end;
|
|
if not IsCategoryNode(ANode) then
|
|
begin
|
|
if PaintStyle <> ipsCategorized then
|
|
begin
|
|
// Draw Divider
|
|
if APrevDivider then Dec(ARect.Top);
|
|
Inc(ARect.Left, FDividerPos);
|
|
ARect.Right := ARect.Left + 1;
|
|
if PaintStyle in [ipsStandard, ipsExtended] then
|
|
DrawEdge(Canvas.Handle, ARect, EDGE_ETCHED, BF_LEFT)
|
|
else
|
|
Windows.FillRect(Canvas.Handle, ARect, FGridBrush);
|
|
APrevDivider := True;
|
|
end
|
|
else
|
|
begin
|
|
Brush.Color := Self.Color;
|
|
ARect := DisplayRect;
|
|
ARect.Left := DisplayRect.Right;
|
|
ARect.Right := ARect.Left + 2;
|
|
FillRect(ARect);
|
|
end;
|
|
// Draw Value
|
|
Brush.Color := Self.Color;
|
|
Font := Self.Font;
|
|
Font.Color := GetValueFontColor;
|
|
if PaintStyle = ipsCategorized then
|
|
begin
|
|
Brush.Color := clWindow;
|
|
Font.Color := Self.Font.Color;
|
|
end
|
|
else
|
|
if ANode.Focused and (PaintStyle in [ipsStandard, ipsExtended]) then
|
|
begin
|
|
Brush.Color := EditColor{clWindow};
|
|
Font.Color := Self.Font.Color;
|
|
end;
|
|
AAlignment := taLeftJustify;
|
|
DoDrawValue(Canvas, ValueRect, ANode, ADisplayText, AAlignment);
|
|
end
|
|
else
|
|
APrevDivider := False;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ARect: TRect;
|
|
I, AHeight, ARowHeight: Integer;
|
|
begin
|
|
with Canvas do
|
|
begin
|
|
// Draw Band Separator
|
|
if not IsRectEmpty(ABandInfo.BandSeparatorRect) then
|
|
begin
|
|
ARect := ABandInfo.BandSeparatorRect;
|
|
ARect.Right := ARect.Left + 1;
|
|
Windows.FillRect(Handle, ARect, FGridBrush);
|
|
OffsetRect(ARect, 1, 0);
|
|
Brush.Color := Self.Color;
|
|
FillRect(ARect);
|
|
OffsetRect(ARect, 1, 0);
|
|
Windows.FillRect(Handle, ARect, FGridBrush);
|
|
end;
|
|
// Empty Rect
|
|
if not IsRectEmpty(ABandInfo.EmptyRect) then
|
|
begin
|
|
Brush.Color := Self.Color;
|
|
FillRect(ABandInfo.EmptyRect);
|
|
end;
|
|
// Design Time Divider
|
|
if (csDesigning in ComponentState) and (ABandInfo.RowCount = 0) then
|
|
begin
|
|
ARect := ABandInfo.BandContentRect;
|
|
Inc(ARect.Left, FDividerPos);
|
|
ARect.Right := ARect.Left + 1;
|
|
if PaintStyle in [ipsStandard, ipsExtended] then
|
|
DrawEdge(Handle, ARect, EDGE_ETCHED, BF_LEFT)
|
|
else
|
|
Windows.FillRect(Handle, ARect, FGridBrush);
|
|
end;
|
|
// Rows
|
|
AHeight := 0;
|
|
APrevDivider := False;
|
|
ARect := ABandInfo.BandContentRect;
|
|
Brush.Color := Self.Color;
|
|
Font := Self.Font;
|
|
for I := 0 to ABandInfo.RowCount - 1 do
|
|
begin
|
|
ARowHeight := ABandInfo.RowsInfo^[I].RowHeight;
|
|
ARect.Top := AHeight;
|
|
ARect.Bottom := ARect.Top + ARowHeight;
|
|
if PaintStyle <> ipsCategorized then
|
|
begin
|
|
DrawGridLine(ARect, ABandInfo.RowsInfo^[I].Node);
|
|
Dec(ARect.Bottom, GridSize);
|
|
end;
|
|
// if RectVisible(Canvas.Handle, ARect) then TODO: PrevDivider
|
|
DrawNode(ARect, ABandInfo.RowsInfo^[I].Node);
|
|
Inc(AHeight, ARowHeight);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
begin
|
|
CheckEditor(False, False);
|
|
if (FState = isNodeDragging) and (FDragImageNode <> nil) then
|
|
FDragImageNode.HideDragImage;
|
|
try
|
|
CalcContentDrawInfo(ADrawInfo);
|
|
FGridBrush := CreateSolidBrush(ColorToRGB(FGridColor));
|
|
FGroupGridBrush := CreateSolidBrush(ColorToRGB(FGroupGridColor));
|
|
FBkBrush := CreateSolidBrush(ColorToRGB(Self.Color));
|
|
FGroupBkBrush := CreateSolidBrush(ColorToRGB(FGroupColor));
|
|
try
|
|
// Draw Focus Rect
|
|
if PaintStyle in [ipsStandard, ipsExtended] then
|
|
DrawFocusFrame;
|
|
// Empty Rect
|
|
if not IsRectEmpty(ADrawInfo.EmptyRect) then
|
|
begin
|
|
Canvas.Brush.Color := Self.Color;
|
|
Canvas.FillRect(ADrawInfo.EmptyRect);
|
|
end;
|
|
// Draw Bands
|
|
for I := 0 to ADrawInfo.BandCount - 1 do
|
|
DrawBand(ADrawInfo.BandsInfo^[I]);
|
|
finally
|
|
if FGridBrush <> 0 then DeleteObject(FGridBrush);
|
|
if FGroupGridBrush <> 0 then DeleteObject(FGroupGridBrush);
|
|
if FBkBrush <> 0 then DeleteObject(FBkBrush);
|
|
if FGroupBkBrush <> 0 then DeleteObject(FGroupBkBrush);
|
|
FreeContentDrawInfo(ADrawInfo);
|
|
end;
|
|
finally
|
|
if (FState = isNodeDragging) and (FDragImageNode <> nil) then
|
|
FDragImageNode.ShowDragImage;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WndProc(var Message: TMessage);
|
|
begin
|
|
if Message.Msg = WM_SETFOCUS then
|
|
if (FInplaceEdit = nil) or (TWMsetFocus(Message).FocusedWnd <> FInplaceEdit.Handle) then
|
|
CheckEditor(True, False);
|
|
|
|
if (Message.Msg = WM_KEYDOWN) and (Message.wParam = VK_ESCAPE) and
|
|
Dragging and IsAutoDrag then EndDrag(False);
|
|
|
|
if not (csDesigning in ComponentState) and ((Message.Msg = WM_LBUTTONDOWN) or
|
|
(Message.Msg = WM_LBUTTONDBLCLK)) and not Dragging and IsAutoDrag then
|
|
begin
|
|
if not IsControlMouseMsg(TWMMouse(Message)) then
|
|
begin
|
|
ControlState := ControlState + [csLButtonDown];
|
|
Dispatch(Message);
|
|
end;
|
|
end
|
|
else
|
|
inherited WndProc(Message);
|
|
end;
|
|
|
|
function TCustomdxInspector.AcquireFocus: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.AddNode(Node: TdxInspectorNode);
|
|
var
|
|
RedrawNode: TdxInspectorNode;
|
|
begin
|
|
{Close Edit}
|
|
HideEditor;
|
|
if TopVisibleNode = nil then FTopVisibleNode := Node;
|
|
if FocusedNode = nil then FFocused := TopVisibleNode;
|
|
RedrawNode := Node.GetPriorParentNode;
|
|
if RedrawNode = nil then RedrawNode := Node;
|
|
UpdateNode(RedrawNode, True {Below});
|
|
end;
|
|
|
|
function TCustomdxInspector.CalcBandWidth(ABandWidth: Integer): Integer;
|
|
begin
|
|
Result := ABandWidth div (FSizingBandIndex - LeftBandIndex + 1);
|
|
end;
|
|
|
|
function TCustomdxInspector.CalcDividerPos(AX: Integer): Integer;
|
|
begin
|
|
Result := AX - (FSizingBandIndex - LeftBandIndex) * BandWidth;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CalcDrawInfo(ANode: TdxInspectorNode; ARect: TRect;
|
|
var ADrawInfo: TdxInspectorDrawInfo);
|
|
const
|
|
indDisplay = 2;
|
|
begin
|
|
FillChar(ADrawInfo, SizeOf(ADrawInfo), 0);
|
|
with ADrawInfo do
|
|
begin
|
|
// Indent
|
|
if PaintStyle = ipsCategorized then
|
|
begin
|
|
if IsCategoryNode(ANode) then
|
|
begin
|
|
IndentRect := Rect(ARect.Left, ARect.Top,
|
|
ARect.Left + ANode.Level * FIndent, ARect.Bottom);
|
|
InflateRect(ARect, -1, -1);
|
|
end
|
|
else
|
|
begin
|
|
InflateRect(ARect, -FRowFrameSize, -FRowFrameSize);
|
|
IndentRect := Rect(ARect.Left, ARect.Top,
|
|
ARect.Left + (ANode.Level + 1) * FIndent, ARect.Bottom);
|
|
if IsCategoryNode(GetTopParentNode(ANode)) then
|
|
Dec(IndentRect.Right, FIndent);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
IndentRect := Rect(ARect.Left, ARect.Top,
|
|
ARect.Left + (ANode.Level + 1) * FIndent, ARect.Bottom);
|
|
if PaintStyle in [ipsStandard] then
|
|
Inc(IndentRect.Right, indDisplay);
|
|
end;
|
|
// Button
|
|
if ANode.HasChildren then
|
|
begin
|
|
if ANode.Expanded then
|
|
ButtonKind := ibkMinus
|
|
else
|
|
ButtonKind := ibkPlus;
|
|
if (PaintStyle <> ipsCategorized) or not IsCategoryNode(ANode) then
|
|
ButtonRect:= Rect(IndentRect.Right - FIndent, IndentRect.Top, // TODO: Toolbox
|
|
IndentRect.Right, IndentRect.Bottom);
|
|
end;
|
|
// Image (in Toolbox style ignored for Category)
|
|
if IsImageNode(ANode) then
|
|
begin
|
|
ImageRect := Rect(IndentRect.Right, ARect.Top, IndentRect.Right + FImageWidth, ARect.Bottom);
|
|
Inc(IndentRect.Right, FImageWidth);
|
|
end;
|
|
DisplayRect := Rect(IndentRect.Right, ARect.Top, ARect.Left + FDividerPos, ARect.Bottom);
|
|
if (PaintStyle = ipsCategorized) and IsCategoryNode(ANode) then
|
|
Inc(DisplayRect.Left);
|
|
ValueRect := Rect(ARect.Left + FDividerPos + 1, ARect.Top, ARect.Right, ARect.Bottom);
|
|
if PaintStyle in [ipsStandard, ipsExtended, ipsCategorized] then // two pixels
|
|
Inc(ValueRect.Left);
|
|
if IsCategoryNode(ANode) then
|
|
begin
|
|
DisplayRect.Right := ValueRect.Right;
|
|
if (ButtonKind <> ibkNone) and (PaintStyle = ipsCategorized) then
|
|
begin
|
|
ButtonRect:= Rect(DisplayRect.Right - FToolboxButtonWidth, DisplayRect.Top, // TODO: Toolbox
|
|
DisplayRect.Right, DisplayRect.Bottom);
|
|
Dec(DisplayRect.Right, FToolboxButtonWidth);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.CalcMinRowHeight(ACanvas: TCanvas): Integer;
|
|
begin
|
|
Result := CalcTextHeight(ACanvas);
|
|
end;
|
|
|
|
function TCustomdxInspector.CalcTextHeight(ACanvas: TCanvas): Integer;
|
|
begin
|
|
Result := ACanvas.TextHeight('Wg') + 2 + 1;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CancelDragSizing;
|
|
begin
|
|
if FState in [isBandSizing, isColumnSizing, isRowSizing] then
|
|
begin
|
|
DrawSizingLine;
|
|
SetState(isNormal);
|
|
SetCursor(Screen.Cursors[Cursor]);
|
|
if IsDynamicColumnSizing or (FState in [isBandSizing{, isRowSizing}]) then
|
|
begin
|
|
if FState = isRowSizing then
|
|
// TODO: restore Row Height := FSaveSizingPos
|
|
else
|
|
if FState = isBandSizing then
|
|
BandWidth := FSaveSizingPos
|
|
else
|
|
if FState = isColumnSizing then
|
|
DividerPos := FSaveSizingPos;
|
|
Invalidate;
|
|
UpdateWindow(Handle);
|
|
end;
|
|
end;
|
|
HideRowHint;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DeleteNode(Node, Prior, Next: TdxInspectorNode; IsLast, Redraw: Boolean);
|
|
var
|
|
RedrawNode: TdxInspectorNode;
|
|
begin
|
|
if Count = 0 then
|
|
begin
|
|
FTopVisibleNode := nil;
|
|
FFocused := nil;
|
|
FInplaceNode := nil;
|
|
FSizingNode := nil;
|
|
FHotTrackNode := nil;
|
|
ClearPrevHintNode;
|
|
if (FLockUpdate=0) and (Not (csDestroying in ComponentState)) then
|
|
begin
|
|
{Close Edit}
|
|
HideEditor;
|
|
UpdateScrollBar;
|
|
Invalidate;
|
|
end;
|
|
Exit;
|
|
end;
|
|
RedrawNode := nil;
|
|
if TopVisibleNode = Node then
|
|
begin
|
|
FTopVisibleNode := Prior;
|
|
if FTopVisibleNode = nil then FTopVisibleNode := Next;
|
|
RedrawNode := FTopVisibleNode;
|
|
end;
|
|
if FocusedNode = Node then
|
|
begin
|
|
FFocused := Prior;
|
|
if FocusedNode = nil then FFocused := Next;
|
|
if RedrawNode = nil then RedrawNode := FocusedNode;
|
|
end;
|
|
if FSizingNode = Node then
|
|
FSizingNode := nil;
|
|
if FHotTrackNode = Node then
|
|
FHotTrackNode := nil;
|
|
if Node = FPrevHintNode then
|
|
ClearPrevHintNode;
|
|
{Close Edit}
|
|
HideEditor;
|
|
if Redraw then
|
|
begin
|
|
if RedrawNode = nil then RedrawNode := Prior;
|
|
if RedrawNode = nil then RedrawNode := Next;
|
|
if RedrawNode <> nil then UpdateNode(RedrawNode, True{Below});
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CheckComplexRowIndex(var AComplexRowIndex: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CheckDownNode(AClick: Boolean);
|
|
var
|
|
APrevNode: TdxInspectorNode;
|
|
begin
|
|
SetState(isNormal);
|
|
APrevNode := FDragNode;
|
|
FDragNode := nil;
|
|
InvalidateNode(APrevNode, False);
|
|
if (PaintStyle = ipsCategorized) and AClick and
|
|
(APrevNode <> nil) and IsCategoryNode(APrevNode) then
|
|
APrevNode.Expanded := not APrevNode.Expanded;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CheckHotTrackNode(ANode: TdxInspectorNode);
|
|
var
|
|
APrevNode: TdxInspectorNode;
|
|
begin
|
|
if (State <> isNormal) or (csDesigning in ComponentState) or
|
|
(PaintStyle <> ipsCategorized) then Exit;
|
|
if FHotTrackNode <> ANode then
|
|
begin
|
|
APrevNode := FHotTrackNode;
|
|
FHotTrackNode := ANode;
|
|
InvalidateNode(FHotTrackNode, False);
|
|
InvalidateNode(APrevNode, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CheckInplaceComplexRowIndex;
|
|
begin
|
|
InplaceComplexRowIndex := InplaceComplexRowIndex; // Check Ranges
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoChangeNode(OldNode, Node : TdxInspectorNode);
|
|
begin
|
|
if Assigned(FOnChangeNode) then FOnChangeNode(Self, OldNode, Node);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoDragScroll(P: TPoint);
|
|
begin
|
|
FHitInfo := GetHitInfo(P);
|
|
if (FHitInfo.hitType in [ihtColumnEdge, ihtIndent, ihtButton, ihtImage,
|
|
ihtDisplayLabel, ihtLabel, ihtComplexRowSeparator]) and (FHitInfo.Node <> nil) then
|
|
FHitInfo.Node.Focused := True
|
|
else
|
|
if FHitInfo.hitType = ihtOutSide then
|
|
SetTimer(Handle, 1, 60, nil);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DragDropTo(var ANode: TdxInspectorNode;
|
|
ADestinationNode: TdxInspectorNode; AAttachMode: TdxInspectorNodeAttachMode);
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DrawCaption(ACanvas: TCanvas; ANode: TdxInspectorNode;
|
|
const ADisplayRect: TRect; const AText: string);
|
|
begin
|
|
DrawDisplayText(ACanvas, ADisplayRect, AText, taLeftJustify);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DrawComplexRowSeparator(ACanvas: TCanvas; const ARect: TRect; AIsCaption: Boolean);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
R := ARect;
|
|
InflateRect(R, 0, -2);
|
|
R.Left := (R.Left + R.Right) div 2 - 1;
|
|
R.Right := R.Left + 1;
|
|
if (PaintStyle = ipsCategorized) and not AIsCaption then
|
|
FillRect(ACanvas.Handle, ARect, FBkBrush)
|
|
else
|
|
begin
|
|
ACanvas.FillRect(ARect);
|
|
DrawEdge(ACanvas.Handle, R, EDGE_ETCHED, BF_LEFT);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DrawDisplayText(ACanvas: TCanvas; const ARect: TRect;
|
|
const AText: string; AAlignment: TAlignment);
|
|
|
|
procedure PrepareViewData(AViewData: TdxEditViewData);
|
|
begin
|
|
with AViewData do
|
|
begin
|
|
Enabled := True;
|
|
Focused := False;
|
|
Selected := False;
|
|
// Style
|
|
BorderColor := clNone;
|
|
BorderStyle := xbsNone;
|
|
ButtonStyle := EditStyleButtonStyle;
|
|
ButtonTransparence := False;
|
|
Edges := [edgLeft, edgTop, edgRight, edgBottom];
|
|
Shadow := False;
|
|
Transparent := False;
|
|
// ViewBounds
|
|
OffsetSize := Rect(0, 0, 0, 0);
|
|
ViewBounds := ARect;
|
|
// General
|
|
if (ARect.Bottom - ARect.Top) > FTextHeight then
|
|
DrawAlignment := daMultiLine
|
|
else
|
|
DrawAlignment := daSingleLine; //daVCenter;
|
|
Font := ACanvas.Font.Handle;
|
|
Brush := ACanvas.Brush.Handle;
|
|
BkColor := ColorToRGB(ACanvas.Brush.Color);
|
|
TextColor := ColorToRGB(ACanvas.Font.Color);
|
|
Alignment := AAlignment;
|
|
IsEditClass := False;
|
|
Data := AText;
|
|
DataLength := 0;
|
|
CalcHeight := False;
|
|
end;
|
|
if AViewData is TdxTextEditViewData then
|
|
with TdxTextEditViewData(AViewData) do
|
|
begin
|
|
EndEllipsis := ioDrawEndEllipsis in Options;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
AViewData: TdxEditViewData;
|
|
begin
|
|
AViewData := TdxInplaceTextEdit.GetViewDataClass.Create;
|
|
try
|
|
PrepareViewData(AViewData);
|
|
CalcCellViewBoundsRect(ARect, AViewData.ViewBounds);
|
|
TdxInplaceTextEdit.Draw(ACanvas.Handle, ARect, AViewData, 0);
|
|
finally
|
|
AViewData.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoDrawCaption(ACanvas: TCanvas; ANode: TdxInspectorNode;
|
|
AIndentRect, AButtonRect, AImageRect: TRect; AButtonKind: TdxInspectorButtonKind;
|
|
ADisplayRect: TRect; var AText: String);
|
|
begin
|
|
with ACanvas do
|
|
begin
|
|
// Draw Button
|
|
if PaintStyle <> ipsCategorized then
|
|
DrawButton(ACanvas, AIndentRect, AButtonRect, AButtonKind, ANode);
|
|
if not IsRectEmpty(AImageRect) then
|
|
WriteImage(ACanvas, AImageRect, GetImageIndex(ANode));
|
|
// Draw Display
|
|
DrawCaption(ACanvas, ANode, ADisplayRect, AText);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.AssignEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
function TCustomdxInspector.EditStyleBorderStyle: TdxEditBorderStyle;
|
|
begin
|
|
if PaintStyle = ipsCategorized then
|
|
Result := xbsFlat
|
|
else
|
|
Result := xbsNone;
|
|
end;
|
|
|
|
function TCustomdxInspector.EditStyleButtonStyle: TdxEditButtonViewStyle;
|
|
begin
|
|
if PaintStyle = ipsCategorized then
|
|
Result := btsFlat
|
|
else
|
|
if Flat then
|
|
Result := btsFlat
|
|
else
|
|
Result := bts3D;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.InitEditProperties(AInplaceEdit: TdxInplaceEdit);
|
|
var
|
|
DC: HDC;
|
|
begin
|
|
with TdxInplaceInspectorEdit(AInplaceEdit) do
|
|
begin
|
|
CloseFlag := False; // for Mask Edit
|
|
// Color
|
|
Color := Self.GetEditColor;
|
|
DC := GetDC(0);
|
|
try
|
|
Color := GetNearestColor(DC, ColorToRGB(Color));
|
|
finally
|
|
ReleaseDC(0, DC);
|
|
end;
|
|
// Font
|
|
Font.Assign(Self.GetEditFont);
|
|
// Offset
|
|
OffsetSize := Rect(1, 0, 0, 0);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.InitEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoDrawValue(ACanvas: TCanvas; ARect: TRect; ANode: TdxInspectorNode;
|
|
var AText: string; var AAlignment: TAlignment);
|
|
begin
|
|
// Default Draw
|
|
with FCellViewData do
|
|
begin
|
|
Cell_Brush := ACanvas.Brush.Handle;
|
|
Cell_Font := ACanvas.Font.Handle;
|
|
Cell_BkColor := ACanvas.Brush.Color;
|
|
Cell_TextColor := ACanvas.Font.Color;
|
|
Cell_Alignment := AAlignment;
|
|
Cell_Text := AText;
|
|
Cell_TextLength := 0; // full length
|
|
Cell_Selected := False;
|
|
Cell_DrawEndEllipsis := ioDrawEndEllipsis in Options;
|
|
Cell_Node := ANode;
|
|
Cell_HotTrackNode := IsHotTrackNode(ANode);
|
|
with ARect do
|
|
Cell_Rect := Rect(0, 0, Right - Left, Bottom - Top);
|
|
InflateRect(Cell_Rect, 2, 2); // TODO PAINT2
|
|
end;
|
|
DefaultDrawCell(ACanvas, ARect, FCellViewData);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoHideCustomizeForm;
|
|
begin
|
|
FCustomizeFormPos.X := CustomizeForm.Left;
|
|
FCustomizeFormPos.Y := CustomizeForm.Top;
|
|
FCustomizeFormSize.X := CustomizeForm.Width;
|
|
FCustomizeFormSize.Y := CustomizeForm.Height;
|
|
if Assigned(FOnHideCustomizeForm) then FOnHideCustomizeForm(Self);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoShowCustomizeForm;
|
|
begin
|
|
// Size
|
|
if (FCustomizeFormSize.X <> dxInspectorUndefinedValue) or
|
|
(FCustomizeFormSize.Y <> dxInspectorUndefinedValue) then
|
|
begin
|
|
FCustomizeForm.Width := FCustomizeFormSize.X;
|
|
FCustomizeForm.Height := FCustomizeFormSize.Y;
|
|
end;
|
|
// Position
|
|
if (FCustomizeFormPos.X <> dxInspectorUndefinedValue) or
|
|
(FCustomizeFormPos.Y <> dxInspectorUndefinedValue) then
|
|
begin
|
|
FCustomizeForm.Left := FCustomizeFormPos.X;
|
|
FCustomizeForm.Top := FCustomizeFormPos.Y;
|
|
end;
|
|
if Assigned(FOnShowCustomizeForm) then FOnShowCustomizeForm(Self);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DefaultDrawCell(ACanvas: TCanvas; const ARect: TRect;
|
|
ACellViewData: TdxInspectorCellViewData);
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CalcCellViewBoundsRect(const ACellRect: TRect; var AViewRect: TRect);
|
|
begin
|
|
AViewRect := ACellRect;
|
|
InflateRect(AViewRect, 2, 2);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoEditChange(Sender: TObject);
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoEditValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean);
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoInternalLayout;
|
|
begin
|
|
UpdateCustomizeForm;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.GetComplexRowInfoAt(ANode: TdxInspectorNode; const ARect: TRect;
|
|
const APos: TPoint; var ComplexRowIndex: Integer; var ComplexRowRect: TRect);
|
|
begin
|
|
ComplexRowIndex := -1;
|
|
SetRectEmpty(ComplexRowRect);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetDefaultNodeHeight(ANode: TdxInspectorNode): Integer;
|
|
begin
|
|
Result := RowHeight;
|
|
if (PaintStyle = ipsCategorized) and IsCategoryNode(ANode) then
|
|
Dec(Result, 2);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetDragNodeText(ADragNode: TdxInspectorNode): string;
|
|
var
|
|
S: string;
|
|
begin
|
|
if ADragNode <> nil then
|
|
GetNodeText(ADragNode, Result, S)
|
|
else
|
|
Result := '';
|
|
end;
|
|
|
|
function TCustomdxInspector.GetHitInfo(Pos: TPoint): TdxInspectorHitInfo;
|
|
|
|
procedure InitHitInfo(var AHitInfo: TdxInspectorHitInfo);
|
|
begin
|
|
with AHitInfo do
|
|
begin
|
|
hitType := ihtOutside;
|
|
Node := nil;
|
|
Row := -1;
|
|
BandIndex := -1;
|
|
ComplexRowIndex := -1;
|
|
SetRectEmpty(ComplexRowRect);
|
|
end;
|
|
end;
|
|
|
|
procedure CalcNodeAndRect(ABandInfo: TdxInspectorBandInfo; var ANodeRect: TRect);
|
|
var
|
|
I, H: Integer;
|
|
begin
|
|
H := 0;
|
|
ANodeRect := ABandInfo.BandContentRect;
|
|
for I := 0 to ABandInfo.RowCount - 1 do
|
|
begin
|
|
ANodeRect.Top := H;
|
|
ANodeRect.Bottom := ANodeRect.Top + ABandInfo.RowsInfo^[I].RowHeight;
|
|
if PtInRect(ANodeRect, Pos) then
|
|
begin
|
|
Result.Node := ABandInfo.RowsInfo^[I].Node;
|
|
Result.Row := Result.Node.AbsoluteIndex;
|
|
Break;
|
|
end;
|
|
Inc(H, ABandInfo.RowsInfo^[I].RowHeight);
|
|
end;
|
|
end;
|
|
|
|
procedure CalcNodeInfo(ANode: TdxInspectorNode; const ANodeRect: TRect);
|
|
var
|
|
ADrawInfo: TdxInspectorDrawInfo;
|
|
begin
|
|
if ANode <> nil then
|
|
begin
|
|
CalcDrawInfo(ANode, ANodeRect, ADrawInfo);
|
|
// TODO: paintstyle ToolBox -> hitType Edge?
|
|
if (PaintStyle = ipsCategorized) and IsCategoryNode(ANode) and (ANode.Level = 0) then
|
|
Inc(ADrawInfo.IndentRect.Right, FIndent);
|
|
if PtInRect(ADrawInfo.IndentRect, Pos) then
|
|
begin
|
|
Result.hitType := ihtIndent;
|
|
if (ADrawInfo.ButtonKind <> ibkNone) and PtInRect(ADrawInfo.ButtonRect, Pos) then
|
|
Result.hitType := ihtButton;
|
|
if PtInRect(ADrawInfo.ImageRect, Pos) then
|
|
Result.hitType := ihtImage;
|
|
end
|
|
else
|
|
begin
|
|
if (PaintStyle = ipsCategorized) and (ADrawInfo.ButtonKind <> ibkNone) and
|
|
PtInRect(ADrawInfo.ButtonRect, Pos) then
|
|
Result.hitType := ihtButton
|
|
else
|
|
begin
|
|
if (Pos.X <= (ANodeRect.Left + FDividerPos)) or IsCategoryNode(ANode) then
|
|
begin
|
|
Result.hitType := ihtDisplayLabel;
|
|
GetComplexRowInfoAt(Result.Node, ADrawInfo.DisplayRect, Pos,
|
|
Result.ComplexRowIndex, Result.ComplexRowRect);
|
|
end
|
|
else
|
|
begin
|
|
Result.hitType := ihtLabel;
|
|
GetComplexRowInfoAt(Result.Node, ADrawInfo.ValueRect, Pos,
|
|
Result.ComplexRowIndex, Result.ComplexRowRect);
|
|
end;
|
|
if not IsRectEmpty(Result.ComplexRowRect) and (Result.ComplexRowIndex = -1) then
|
|
Result.hitType := ihtComplexRowSeparator;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function GetClientEdgeRect(ADrawInfo: TdxInspectorContentDrawInfo): TRect;
|
|
begin
|
|
if IsAutoBandCount and (ADrawInfo.BandCount = 1) then
|
|
begin
|
|
Result := ADrawInfo.CRect;
|
|
Result.Left := Result.Right - BandSeparatorWidth;
|
|
end
|
|
else
|
|
SetRectEmpty(Result);
|
|
end;
|
|
|
|
var
|
|
ADrawInfo: TdxInspectorContentDrawInfo;
|
|
I: Integer;
|
|
ARect, ANodeRect: TRect;
|
|
begin
|
|
InitHitInfo(Result);
|
|
CalcContentDrawInfo(ADrawInfo);
|
|
try
|
|
if PtInRect(ADrawInfo.CRect, Pos) then
|
|
begin
|
|
Result.hitType := ihtNowhere;
|
|
// Calc Band
|
|
for I := 0 to ADrawInfo.BandCount - 1 do
|
|
begin
|
|
if PtInRect(ADrawInfo.BandsInfo^[I].BandRect, Pos) then
|
|
begin
|
|
Result.BandIndex := ADrawInfo.BandsInfo^[I].BandIndex;
|
|
if PtInRect(ADrawInfo.BandsInfo^[I].BandSeparatorRect, Pos) or
|
|
PtInRect(GetClientEdgeRect(ADrawInfo), Pos) then
|
|
Result.hitType := ihtBandSeparator
|
|
else
|
|
begin
|
|
// Node, Row
|
|
CalcNodeAndRect(ADrawInfo.BandsInfo^[I], ANodeRect);
|
|
// divider
|
|
with ADrawInfo.BandsInfo^[I].BandContentRect do
|
|
ARect := Rect(Left + FDividerPos - dxInspectorMaxResizeWidth, Top,
|
|
Left + FDividerPos + dxInspectorMaxResizeWidth, Bottom);
|
|
if PtInRect(ARect, Pos) and not IsCategoryNode(Result.Node) then
|
|
Result.hitType := ihtColumnEdge
|
|
else
|
|
begin
|
|
ARect := ANodeRect;
|
|
ARect.Top := ARect.Bottom - dxInspectorMaxResizeWidth;
|
|
if CanRowSizing and PtInRect(ARect, Pos) then
|
|
Result.hitType := ihtRowEdge
|
|
else
|
|
CalcNodeInfo(Result.Node, ANodeRect);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
FreeContentDrawInfo(ADrawInfo);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetImageIndex(Node: TdxInspectorNode): Integer;
|
|
begin
|
|
Result := -1;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetMinRowHeight(ANode: TdxInspectorNode): Integer;
|
|
begin
|
|
Result := FMinRowHeight;
|
|
if (PaintStyle = ipsCategorized) and IsCategoryNode(ANode) then
|
|
Dec(Result, 2);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetNodeHeight(ANode: TdxInspectorNode): Integer;
|
|
begin
|
|
Result := GetDefaultNodeHeight(ANode);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetRectByNode(ANode: TdxInspectorNode; ADrawInfo: TdxInspectorContentDrawInfo): TRect;
|
|
var
|
|
I, J, H: Integer;
|
|
begin
|
|
SetRectEmpty(Result);
|
|
for I := 0 to ADrawInfo.BandCount - 1 do
|
|
begin
|
|
H := 0;
|
|
for J := 0 to ADrawInfo.BandsInfo^[I].RowCount - 1 do
|
|
begin
|
|
if ADrawInfo.BandsInfo^[I].RowsInfo^[J].Node = ANode then
|
|
begin
|
|
Result := ADrawInfo.BandsInfo^[I].BandContentRect;
|
|
Result.Top := H;
|
|
Result.Bottom := Result.Top + ADrawInfo.BandsInfo^[I].RowsInfo^[J].RowHeight;
|
|
end;
|
|
Inc(H, ADrawInfo.BandsInfo^[I].RowsInfo^[J].RowHeight);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetRectNode(ANode: TdxInspectorNode): TRect;
|
|
var
|
|
ADrawInfo: TdxInspectorContentDrawInfo;
|
|
begin
|
|
CalcContentDrawInfo(ADrawInfo);
|
|
try
|
|
Result := GetRectByNode(ANode, ADrawInfo);
|
|
finally
|
|
FreeContentDrawInfo(ADrawInfo);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetRectNodeBelow(Node: TdxInspectorNode): TRect;
|
|
begin
|
|
Result := GetRectNode(Node);
|
|
Result.Bottom := ClientRect.Bottom;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetSectionWidth: Integer;
|
|
begin
|
|
if IsAutoBandCount then
|
|
Result := BandWidth - BandSeparatorWidth
|
|
else
|
|
Result := {Client}Width;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetValueFontColor: TColor;
|
|
begin
|
|
Result := FValueFontColor;
|
|
if GetSysColor(COLOR_BTNFACE) = 0 then
|
|
Result := ColorToRGB(Result) xor $00FFFFFF;
|
|
end;
|
|
|
|
function TCustomdxInspector.GoTabComplexRow(AForward: Boolean): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.InvalidateNode(ANode: TdxInspectorNode; ABelow: Boolean);
|
|
begin
|
|
if ANode = nil then Exit;
|
|
if IsAutoBandCount and ABelow then
|
|
Invalidate // TODO: !
|
|
else
|
|
if not ABelow then
|
|
InvalidateRect(RecalcPaintRect(GetRectNode(ANode)))
|
|
else
|
|
InvalidateRect(RecalcPaintRect(GetRectNodeBelow(ANode)));
|
|
end;
|
|
|
|
function TCustomdxInspector.IsAutoDrag: Boolean;
|
|
begin
|
|
Result := IsCustomizing or (DragMode = dmAutomatic);
|
|
end;
|
|
|
|
function TCustomdxInspector.IsCategoryNode(Node: TdxInspectorNode): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsComplexNode(ANode: TdxInspectorNode): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsCustomizing: Boolean;
|
|
begin
|
|
Result := FCustomizeForm <> nil;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsGoTabComplexRowAvailable(AForward: Boolean): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsHotTrackNode(ANode: TdxInspectorNode): Boolean;
|
|
begin
|
|
Result := (FHotTrackNode = ANode) and (State = isNormal);
|
|
end;
|
|
|
|
function TCustomdxInspector.IsImageNode(Node: TdxInspectorNode): Boolean;
|
|
begin
|
|
Result := (GetImageIndex(Node) <> -1) and
|
|
not ((PaintStyle = ipsCategorized) and IsCategoryNode(Node));
|
|
end;
|
|
|
|
function TCustomdxInspector.IsInternalDragging: Boolean;
|
|
begin
|
|
Result := IsCustomizing;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsShowHintNode(ANode: TdxInspectorNode; AComplexRowIndex: Integer;
|
|
const AComplexRowRect: TRect; IsValue: Boolean; const R: TRect;
|
|
var AText: string; var X: Integer; var IsRowHint: Boolean): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.LayoutChanged;
|
|
begin
|
|
if FLockUpdate <> 0 then Exit;
|
|
Inc(FLockUpdate);
|
|
try
|
|
InternalLayout;
|
|
finally
|
|
Dec(FLockUpdate);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.RedrawSelection;
|
|
begin
|
|
InvalidateNode(FocusedNode, False);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateCustomizeForm;
|
|
var
|
|
AMsg: TMsg;
|
|
begin
|
|
if csDestroying in ComponentState then Exit;
|
|
if (FCustomizeForm <> nil) and FCustomizeForm.HandleAllocated and
|
|
not PeekMessage(AMsg, FCustomizeForm.Handle, CM_UPDATECUSTOMIZEFORM,
|
|
CM_UPDATECUSTOMIZEFORM, PM_NOREMOVE) then
|
|
PostMessage(FCustomizeForm.Handle, CM_UPDATECUSTOMIZEFORM, 0, 0);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateDesignEditor;
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateNode(Node: TdxInspectorNode; Below: Boolean);
|
|
begin
|
|
if Node.Deleting then Exit;
|
|
if (FLockUpdate = 0) and not (csDestroying in ComponentState) and Node.IsVisible then
|
|
begin
|
|
if Below then
|
|
begin
|
|
UpdateScrollBar;
|
|
UpdateTopCoord;
|
|
end;
|
|
InvalidateNode(Node, Below);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateBandCount;
|
|
|
|
procedure CalcVisibleBandCount;
|
|
var
|
|
W: Integer;
|
|
begin
|
|
W := ClientWidth;
|
|
FVisibleBandCount := W div BandWidth;
|
|
FPartVisibleBandCount := FVisibleBandCount;
|
|
if ((W mod BandWidth) <> 0) and (LeftBandIndex <> (BandCount - 1)) then
|
|
Inc(FPartVisibleBandCount);
|
|
end;
|
|
|
|
procedure CalcBandCount;
|
|
var
|
|
ANode: TdxInspectorNode;
|
|
ABandRowCount, ABandHeight, AHeight, ANodeHeight: Integer;
|
|
begin
|
|
FBandCount := 1;
|
|
ABandHeight := ClientHeight;
|
|
ANode := TopNode;
|
|
ABandRowCount := 0;
|
|
AHeight := 0;
|
|
while (ANode <> nil) do
|
|
begin
|
|
ANodeHeight := GetNodeHeight(ANode);
|
|
Inc(ABandRowCount);
|
|
Inc(AHeight, ANodeHeight);
|
|
if AHeight >= ABandHeight then
|
|
begin
|
|
Inc(FBandCount);
|
|
if (ABandRowCount > 1) and (AHeight > ABandHeight) then
|
|
begin
|
|
ABandRowCount := 1;
|
|
AHeight := ANodeHeight;
|
|
end
|
|
else
|
|
begin
|
|
ABandRowCount := 0;
|
|
AHeight := 0;
|
|
end;
|
|
end;
|
|
ANode := GetNextVisible(ANode);
|
|
end;
|
|
end;
|
|
|
|
procedure CheckBandCount;
|
|
begin
|
|
if FPartVisibleBandCount > FBandCount then
|
|
FPartVisibleBandCount := FBandCount;
|
|
if FVisibleBandCount > FBandCount then
|
|
FBandCount := FVisibleBandCount;
|
|
if FBandCount < 1 then
|
|
FBandCount := 1;
|
|
if FPartVisibleBandCount < 1 then
|
|
FPartVisibleBandCount := 1;
|
|
if FVisibleBandCount < 1 then
|
|
FVisibleBandCount := 1;
|
|
end;
|
|
|
|
begin
|
|
CalcVisibleBandCount;
|
|
CalcBandCount;
|
|
CheckBandCount;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateBandRowCount;
|
|
begin
|
|
UpdateBandCount;
|
|
UpdateRowCount;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateRowCount;
|
|
var
|
|
ADrawInfo: TdxInspectorContentDrawInfo;
|
|
I: Integer;
|
|
begin
|
|
CalcContentDrawInfo(ADrawInfo);
|
|
try
|
|
FRowCount := 0;
|
|
FVisibleRowCount := 0;
|
|
if IsAutoBandCount then
|
|
begin
|
|
for I := 0 to ADrawInfo.BandCount - 1 do
|
|
begin
|
|
if I < VisibleBandCount then
|
|
Inc(FRowCount, ADrawInfo.BandsInfo^[I].RowCount);
|
|
Inc(FVisibleRowCount, ADrawInfo.BandsInfo^[I].RowCount);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
FVisibleRowCount := ADrawInfo.BandsInfo^[0].RowCount;
|
|
FRowCount := FVisibleRowCount;
|
|
if ADrawInfo.BandsInfo^[0].PartRowVisible then
|
|
Dec(FRowCount);
|
|
end;
|
|
if FVisibleRowCount < 1 then FVisibleRowCount := 1;
|
|
if FRowCount < 1 then FRowCount := 1;
|
|
finally
|
|
FreeContentDrawInfo(ADrawInfo);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateScrollBar;
|
|
|
|
procedure HideScrollBar(ABarFlag: Integer);
|
|
var
|
|
SI: TScrollInfo;
|
|
begin
|
|
FillChar(SI, SizeOf(SI), 0);
|
|
SI.cbSize := SizeOf(SI);
|
|
SI.fMask := SIF_ALL;
|
|
SetScrollInfo(ABarFlag, SI, True);
|
|
end;
|
|
|
|
var
|
|
SIOld, SINew: TScrollInfo;
|
|
ACount: Integer;
|
|
begin
|
|
if not HandleAllocated then Exit;
|
|
UpdateBandRowCount;
|
|
SIOld.cbSize := SizeOf(SIOld);
|
|
SIOld.fMask := SIF_ALL;
|
|
if IsAutoBandCount then
|
|
begin
|
|
GetScrollInfo(SB_HORZ, SIOld);
|
|
SINew := SIOld;
|
|
// calc
|
|
SINew.nMin := 0;
|
|
SINew.nPage := VisibleBandCount;
|
|
ACount := BandCount;
|
|
SINew.nMax := ACount - 1;
|
|
if ACount <= VisibleBandCount then SINew.nMax := 0;
|
|
SINew.nPos := LeftBandIndex;
|
|
// set
|
|
SetScrollInfo(SB_HORZ, SINew, True);
|
|
HideScrollBar(SB_VERT);
|
|
end
|
|
else
|
|
begin
|
|
GetScrollInfo(SB_VERT, SIOld);
|
|
SINew := SIOld;
|
|
// calc
|
|
SINew.nMin := 0;
|
|
SINew.nPage := FRowCount;
|
|
ACount := GetAbsoluteCount;
|
|
SINew.nMax := ACount - 1;
|
|
if ACount <= FRowCount then SINew.nMax := 0;
|
|
SINew.nPos := TopIndex;
|
|
// set
|
|
SetScrollInfo(SB_VERT, SINew, True);
|
|
HideScrollBar(SB_HORZ);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetFocusedNode(Node: TdxInspectorNode);
|
|
var
|
|
AOldNode: TdxInspectorNode;
|
|
begin
|
|
AOldNode := FocusedNode;
|
|
try
|
|
if FLockUpdate <> 0 then
|
|
begin
|
|
FFocused := Node;
|
|
Exit;
|
|
end;
|
|
if Node <> nil then Node.MakeVisible;
|
|
if FocusedNode = Node then Exit;
|
|
FFocused := Node;
|
|
InvalidateNode(AOldNode, False);
|
|
InvalidateNode(FocusedNode, False);
|
|
finally
|
|
if AOldNode <> FocusedNode then
|
|
begin
|
|
HideEditor;
|
|
// FInplaceEdit := nil;
|
|
CheckInplaceComplexRowIndex;
|
|
DoChangeNode(AOldNode, FocusedNode);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetFocusedNumber(AIndex: Integer);
|
|
var
|
|
FSelIndex, FCount: Integer;
|
|
begin
|
|
if Count = 0 then Exit;
|
|
FSelIndex := FocusedNumber;
|
|
if FSelIndex <> AIndex then
|
|
begin
|
|
if (AIndex < 0) then AIndex := 0;
|
|
FCount := GetAbsoluteCount;
|
|
if AIndex > (FCount-1) then AIndex := FCount-1;
|
|
if (AIndex <> FSelIndex) then
|
|
SetFocusedNode(GetAbsoluteNode(AIndex));
|
|
Click;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetNodeHeight(ANode: TdxInspectorNode; Value: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspector.LoadFromRegIni(ARegIniObject: TObject; APath: string);
|
|
var
|
|
ARegIniWrapper: TdxRegIniWrapper;
|
|
begin
|
|
// check "\"
|
|
if (Length(APath) > 0) and (APath[1] <> '\') then
|
|
APath := '\' + APath;
|
|
while (Length(APath) > 0) and (APath[Length(APath)] = '\') do
|
|
Delete(APath, Length(APath), 1);
|
|
ARegIniWrapper := TdxRegIniWrapper.Create;
|
|
try
|
|
ARegIniWrapper.RegIniObject := ARegIniObject;
|
|
with ARegIniWrapper do
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
ReadSettings(ARegIniWrapper, APath);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
finally
|
|
ARegIniWrapper.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.ReadSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string);
|
|
begin
|
|
with ARegIniWrapper do
|
|
begin
|
|
BandWidth := ReadInteger(APath, 'BandWidth', BandWidth);
|
|
DividerPos := ReadInteger(APath, 'DividerPos', DividerPos);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SaveToRegIni(ARegIniObject: TObject; APath: string);
|
|
var
|
|
ARegIniWrapper: TdxRegIniWrapper;
|
|
begin
|
|
// check "\"
|
|
if (Length(APath) > 0) and (APath[1] <> '\') then
|
|
APath := '\' + APath;
|
|
while (Length(APath) > 0) and (APath[Length(APath)] = '\') do
|
|
Delete(APath, Length(APath), 1);
|
|
ARegIniWrapper := TdxRegIniWrapper.Create;
|
|
try
|
|
ARegIniWrapper.RegIniObject := ARegIniObject;
|
|
with ARegIniWrapper do
|
|
begin
|
|
Erase(APath);
|
|
WriteSettings(ARegIniWrapper, APath);
|
|
end;
|
|
finally
|
|
ARegIniWrapper.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WriteSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string);
|
|
begin
|
|
with ARegIniWrapper do
|
|
begin
|
|
WriteInteger(APath, 'BandWidth', BandWidth);
|
|
WriteInteger(APath, 'DividerPos', DividerPos);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.CanEditAcceptKey(Key: Char): Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TCustomdxInspector.CanEditModify: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TCustomdxInspector.CanEditShow: Boolean;
|
|
begin
|
|
Result := (ioEditing in Options) and (FocusedNode <> nil) and
|
|
not IsCategoryNode(FocusedNode) and
|
|
not (csDesigning in ComponentState) and (FLockUpdate = 0) and HandleAllocated
|
|
and (FState <> isNodeDragging) and not IsCustomizing;
|
|
end;
|
|
|
|
function TCustomdxInspector.CellRect(ANode: TdxInspectorNode): TRect;
|
|
var
|
|
ARect: TRect;
|
|
ADrawInfo: TdxInspectorDrawInfo;
|
|
begin
|
|
ARect := GetRectNode(ANode);
|
|
CalcDrawInfo(ANode, ARect, ADrawInfo);
|
|
Result := ADrawInfo.ValueRect;
|
|
Result.Bottom := Result.Bottom - GridSize;
|
|
end;
|
|
|
|
function TCustomdxInspector.CheckEditorWidth: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TCustomdxInspector.CreateEditor(ANode: TdxInspectorNode): TdxInplaceEdit;
|
|
begin
|
|
Result := TdxInplaceTextEdit.Create(Self);
|
|
end;
|
|
|
|
function TCustomdxInspector.CreateEditStyle(AEdit: TdxInplaceEdit): TdxEditStyle;
|
|
begin
|
|
Result := TdxInspectorEditStyle.Create(AEdit, Self);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DoCheckKeyDown(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
if (Key <> 0) and (FocusedNode <> nil) then
|
|
begin
|
|
FocusedNode.MakeVisible;
|
|
if IsCategoryNode(FocusedNode) then
|
|
case Key of
|
|
VK_LEFT:
|
|
begin
|
|
FocusedNode.MakeVisible;
|
|
FocusedNode.Expanded := False;
|
|
end;
|
|
VK_RIGHT:
|
|
begin
|
|
FocusedNode.MakeVisible;
|
|
FocusedNode.Expanded := True;
|
|
end;
|
|
end;
|
|
if (ssCtrl in Shift) or IsCategoryNode(FocusedNode) then
|
|
case Key of
|
|
VK_SUBTRACT:
|
|
begin
|
|
FocusedNode.MakeVisible;
|
|
FocusedNode.Expanded := False;
|
|
end;
|
|
VK_ADD:
|
|
begin
|
|
FocusedNode.MakeVisible;
|
|
FocusedNode.Expanded := True;
|
|
end;
|
|
VK_MULTIPLY:
|
|
begin
|
|
if FocusedNode.HasChildren then
|
|
FocusedNode.Expand(True{Recuse});
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.FindInplaceEdit(ANode:TdxInspectorNode):TdxInplaceEdit;
|
|
begin
|
|
if FInplaceEdit <> nil then
|
|
Result := FInplaceEdit
|
|
else Result := nil;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetEditColor: TColor;
|
|
begin
|
|
Result := clWindow;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetEditingText: string;
|
|
begin
|
|
Result := '';
|
|
if (ioEditing in Options) and (FInplaceEdit <> Nil) then
|
|
Result := FInplaceEdit.GetEditingText;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetEditRect(ANode: TdxInspectorNode): TRect;
|
|
begin
|
|
Result := CellRect(ANode);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.HideEdit(ABackFocus: Boolean);
|
|
begin
|
|
if (FInplaceEdit <> nil) then
|
|
try
|
|
FInplaceEdit.CloseFlag := True;
|
|
try
|
|
if not (csDestroying in FInplaceEdit.ComponentState) then
|
|
UpdateText;
|
|
except
|
|
if ABackFocus and (FInplaceNode <> Nil) and (ExceptObject <> nil) then
|
|
begin
|
|
FInplaceNode.MakeVisible;
|
|
UpdateWindow(Handle);
|
|
end;
|
|
KillTimer(Handle, ScrollTimerId);
|
|
SetState(isNormal);
|
|
raise;
|
|
end;
|
|
finally
|
|
if not ABackFocus then
|
|
begin
|
|
FInplaceNode := Nil;
|
|
if FInplaceEdit <> nil then
|
|
FInplaceEdit.Hide;
|
|
end;
|
|
ABackFocus := ABackFocus or
|
|
((FInplaceEdit <> nil) and (FInplaceEdit.HandleAllocated) and (GetFocus = FInplaceEdit.Handle));
|
|
if ABackFocus and IsWindowVisible(Self.Handle) then
|
|
Windows.SetFocus(Self.Handle);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.InplaceEditKeyDown(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
inherited InplaceEditKeyDown(Key, Shift);
|
|
DoCheckKeyDown(Key, Shift);
|
|
end;
|
|
|
|
function TCustomdxInspector.IsAutoBandCount: Boolean;
|
|
begin
|
|
Result := ioAutoBandCount in Options;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsDynamicColumnSizing: Boolean;
|
|
begin
|
|
Result := ioDynamicColumnSizing in Options;
|
|
if FState = isRowSizing then Result := False;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsImmediateEditor: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsRowAutoHeight: Boolean;
|
|
begin
|
|
Result := ioRowAutoHeight in Options;
|
|
end;
|
|
|
|
function TCustomdxInspector.CanRowSizing: Boolean;
|
|
begin
|
|
Result := ioRowSizing in Options;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsTabs: Boolean;
|
|
begin
|
|
Result := (ioTabs in Options) and (GetAsyncKeyState(VK_CONTROL) >= 0);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetEditingText(Value: string);
|
|
begin
|
|
if (ioEditing in Options) and (FInplaceEdit <> nil) then
|
|
FInplaceEdit.SetEditingText(Value);
|
|
end;
|
|
|
|
// private TCustomdxInspector tree
|
|
function TCustomdxInspector.GetAbsoluteCount: Integer;
|
|
|
|
function GetExpandedCount(Node: TdxInspectorNode): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := Node.Count;
|
|
for I := 0 to Node.Count - 1 do
|
|
if Node[I].Expanded then
|
|
Result := Result + GetExpandedCount(Node[I]);
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := Count;
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Expanded then
|
|
Result := Result + GetExpandedCount(Items[I]);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetAbsoluteIndex(Node: TdxInspectorNode): Integer;
|
|
var
|
|
Ret, I: Integer;
|
|
CurNode: TdxInspectorNode;
|
|
|
|
function FoundNode (ParentNode, FindNode: TdxInspectorNode): Boolean;
|
|
var
|
|
I: Integer;
|
|
CurNode: TdxInspectorNode;
|
|
begin
|
|
Result := False;
|
|
for I := 0 to ParentNode.Count - 1 do
|
|
begin
|
|
CurNode := ParentNode[I];
|
|
Inc(Ret);
|
|
if CurNode = FindNode then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end
|
|
else
|
|
if CurNode.Expanded then
|
|
if FoundNode (CurNode, FindNode) then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Ret := -1;
|
|
Result := Ret;
|
|
if (Node = nil) or (Count = 0) then Exit;
|
|
for I :=0 to Count - 1 do
|
|
begin
|
|
CurNode := Items[I];
|
|
Inc(Ret);
|
|
if CurNode = Node then
|
|
begin
|
|
Result := Ret;
|
|
Exit;
|
|
end
|
|
else
|
|
if CurNode.Expanded then
|
|
if FoundNode (CurNode, Node) then
|
|
begin
|
|
Result := Ret;
|
|
Exit;
|
|
end
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetAbsoluteNode(AIndex: Integer): TdxInspectorNode;
|
|
var
|
|
I: Integer;
|
|
k: Integer;
|
|
CurNode: TdxInspectorNode;
|
|
|
|
function GetNextNodes(Node: TdxInspectorNode): TdxInspectorNode;
|
|
var
|
|
k: Integer;
|
|
begin
|
|
Result := nil;
|
|
for k := 0 to Node.Count - 1 do
|
|
begin
|
|
Inc(I);
|
|
if I = AIndex then
|
|
begin
|
|
Result := Node[k];
|
|
Exit;
|
|
end;
|
|
if Node[k].Expanded then
|
|
Result := GetNextNodes(Node[k]);
|
|
if Result <> nil then Exit;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result := nil;
|
|
I := -1;
|
|
for k := 0 to Count - 1 do
|
|
begin
|
|
Inc(I);
|
|
CurNode := Items[k];
|
|
if I = AIndex then
|
|
begin
|
|
Result := CurNode;
|
|
Exit;
|
|
end;
|
|
if CurNode.Expanded then
|
|
Result := GetNextNodes(CurNode);
|
|
if Result <> nil then Exit;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetCount: Integer;
|
|
begin
|
|
Result := FNodeList.Count;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetFocused: TdxInspectorNode;
|
|
begin
|
|
Result := FFocused;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetFocusedNumber: Integer;
|
|
begin
|
|
Result := -1;
|
|
if FocusedNode <> nil then
|
|
Result := GetAbsoluteIndex(FocusedNode);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetLastNode: TdxInspectorNode;
|
|
begin
|
|
if Count > 0 then
|
|
Result := Items[Count - 1].GetLastNode
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetNode(Index: Integer): TdxInspectorNode;
|
|
begin
|
|
Result := nil;
|
|
if(Index > -1) and (Index < Count) then
|
|
Result := FNodeList.Items[Index];
|
|
end;
|
|
|
|
function TCustomdxInspector.GetTopIndex: Integer;
|
|
begin
|
|
Result := -1;
|
|
if TopVisibleNode <> nil then
|
|
Result := GetAbsoluteIndex(TopVisibleNode);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetTopNode: TdxInspectorNode;
|
|
begin
|
|
Result := GetNode(0);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetTopIndex(AIndex: Integer);
|
|
var
|
|
ABandIndex, ACount, APrevTopIndex: Integer;
|
|
begin
|
|
if Count = 0 then Exit;
|
|
ACount := GetAbsoluteCount;
|
|
APrevTopIndex := TopIndex;
|
|
if AIndex > (ACount - 1) then
|
|
AIndex := ACount - 1;
|
|
if AIndex < 0 then AIndex := 0;
|
|
if IsAutoBandCount then
|
|
begin
|
|
ABandIndex := GetBandIndexByNode(GetAbsoluteNode(AIndex));
|
|
AIndex := GetAbsoluteIndex(GetBandTopNode(ABandIndex));
|
|
if APrevTopIndex <> AIndex then
|
|
LeftBandIndex := ABandIndex;
|
|
end
|
|
else
|
|
begin
|
|
if APrevTopIndex <> AIndex then
|
|
begin
|
|
if (AIndex + RowCount) > ACount then
|
|
AIndex := ACount - RowCount;
|
|
if AIndex < 0 then AIndex := 0;
|
|
if AIndex <> APrevTopIndex then
|
|
begin
|
|
FTopVisibleNode := GetAbsoluteNode(AIndex);
|
|
UpdateScrollBar;
|
|
if FLockUpdate <> 0 then Exit;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// Style
|
|
function TCustomdxInspector.GetOptions: TdxInspectorOptions;
|
|
begin
|
|
Result := FOptions;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.ImageListChange(Sender: TObject);
|
|
begin
|
|
if HandleAllocated and (Sender = Images) then
|
|
LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.InternalLayout;
|
|
var
|
|
RestoreCanvas: Boolean;
|
|
S: string;
|
|
begin
|
|
if (csLoading in ComponentState) then Exit;
|
|
RestoreCanvas := not HandleAllocated;
|
|
if RestoreCanvas then
|
|
Canvas.Handle := GetDC(0);
|
|
try
|
|
Canvas.Font := Self.Font;
|
|
FToolboxButtonWidth := 6 + 2 * 2;
|
|
if PaintStyle = ipsStandard then
|
|
FIndent := Canvas.TextWidth('+')
|
|
else
|
|
if PaintStyle = ipsCategorized then
|
|
FIndent := dxInspectorButtonSize + 5
|
|
else
|
|
if PaintStyle in [ipsSimple, ipsNET, ipsCategorized] then
|
|
FIndent := dxInspectorButtonSize + 6
|
|
else
|
|
FIndent := dxInspectorButtonExSize + 4;
|
|
// ComplexRowSeparatorWidth
|
|
S := ComplexRowSeparator + '_';
|
|
FCaptionComplexRowSeparatorWidth := Canvas.TextWidth(S);
|
|
if PaintStyle = ipsCategorized then
|
|
FComplexRowSeparatorWidth := 4
|
|
else
|
|
FComplexRowSeparatorWidth := FCaptionComplexRowSeparatorWidth;
|
|
// Row Height
|
|
if PaintStyle = ipsCategorized then
|
|
begin
|
|
FGridSize := 0;
|
|
FRowFrameSize := 2;
|
|
end
|
|
else
|
|
begin
|
|
FGridSize := 1;
|
|
FRowFrameSize := 0;
|
|
end;
|
|
FTextHeight := CalcTextHeight(Canvas);
|
|
FMinRowHeight := CalcMinRowHeight(Canvas) + FGridSize + 2 * FRowFrameSize;
|
|
if not FRowHeightAssigned then
|
|
FRowHeight := FMinRowHeight;
|
|
if FRowHeight < FMinRowHeight then
|
|
FRowHeight := FMinRowHeight;
|
|
if FRowHeight = FMinRowHeight then
|
|
FRowHeightAssigned := False;
|
|
// Images
|
|
FImageWidth := 0;
|
|
FImageHeight := 0;
|
|
if Images <> nil then
|
|
begin
|
|
FImageWidth := Images.Width;
|
|
FImageHeight := Images.Height;
|
|
end;
|
|
if FImageHeight > (FRowHeight - FGridSize - 2 * FRowFrameSize) then
|
|
FRowHeight := FImageHeight + FGridSize + 2 * FRowFrameSize;
|
|
finally
|
|
if RestoreCanvas then
|
|
begin
|
|
ReleaseDC(0, Canvas.Handle);
|
|
Canvas.Handle := 0;
|
|
end;
|
|
end;
|
|
DoInternalLayout;
|
|
UpdateScrollBar;
|
|
UpdateTopCoord;
|
|
Invalidate;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsActiveControl: Boolean;
|
|
var
|
|
H: hWnd;
|
|
begin
|
|
Result := False;
|
|
begin
|
|
H := GetFocus;
|
|
while IsWindow(H) and (Result = False) do
|
|
begin
|
|
if H = WindowHandle then
|
|
Result := True
|
|
else
|
|
H := GetParent(H);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.IsGridColorStored: Boolean;
|
|
begin
|
|
Result := not ((FPaintStyle in [ipsStandard, ipsExtended]) and (FGridColor = dxclInspectorGridColor)) or
|
|
(not (FPaintStyle in [ipsNET]) and (FGridColor = clBtnFace));
|
|
end;
|
|
|
|
function TCustomdxInspector.IsRowHeightStored: Boolean;
|
|
begin
|
|
Result := FRowHeightAssigned;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetBorderStyle(Value: TBorderStyle);
|
|
begin
|
|
if FBorderStyle <> Value then
|
|
begin
|
|
FBorderStyle := Value;
|
|
RecreateWnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetComplexRowSeparator(const Value: string);
|
|
begin
|
|
if FComplexRowSeparator <> Value then
|
|
begin
|
|
FComplexRowSeparator := Value;
|
|
LayoutChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetFlat(Value: Boolean);
|
|
begin
|
|
if FFlat <> Value then
|
|
begin
|
|
FFlat := Value;
|
|
{$IFDEF DELPHI4}
|
|
if FFlat then
|
|
ScrollBarStyle := ssFlat
|
|
else
|
|
ScrollBarStyle := ssRegular;
|
|
{$ENDIF}
|
|
RecreateWnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetGridColor(Value: TColor);
|
|
begin
|
|
if FGridColor <> Value then
|
|
begin
|
|
FGridColor := Value;
|
|
LayoutChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetImages(Value: TImageList);
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
if Images <> nil then
|
|
Images.UnRegisterChanges(FImageChangeLink);
|
|
FImages := Value;
|
|
if Value <> nil then
|
|
begin
|
|
Images.RegisterChanges(FImageChangeLink);
|
|
Value.FreeNotification(Self);
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetLeftBandIndex(Value: Integer);
|
|
begin
|
|
if BandCount = 0 then Exit;
|
|
if Value < 0 then Value := 0;
|
|
if (Value + VisibleBandCount) > BandCount then Value := BandCount;
|
|
if Value < 0 then Value := 0;
|
|
if (LeftBandIndex <> Value) or
|
|
(GetBandTopNode(FLeftBandIndex) <> TopVisibleNode) then
|
|
begin
|
|
FLeftBandIndex := Value;
|
|
FTopVisibleNode := GetBandTopNode(FLeftBandIndex);
|
|
UpdateScrollBar;
|
|
UpdateTopCoord;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetOptions(Value: TdxInspectorOptions);
|
|
begin
|
|
if FOptions <> Value then
|
|
begin
|
|
FOptions := Value;
|
|
SetDividerPos(DividerPos);
|
|
LayoutChanged;
|
|
CheckEditor(False, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetPaintStyle(Value: TdxInspectorPaintStyle);
|
|
const
|
|
PaintStyleSet = [ipsStandard, ipsExtended, ipsCategorized];
|
|
begin
|
|
if PaintStyle <> Value then
|
|
begin
|
|
// restore default setting
|
|
if (FPaintStyle in PaintStyleSet) <> (Value in PaintStyleSet) then
|
|
if FPaintStyle in PaintStyleSet then
|
|
begin
|
|
if FValueFontColor = dxclInspectorValueFontColor then FValueFontColor := Self.Font.Color;
|
|
if FGridColor = dxclInspectorGridColor then FGridColor := clBtnFace;
|
|
if Color = dxclInspectorBackgroundColor then Color := clWindow;
|
|
end
|
|
else
|
|
begin
|
|
if FValueFontColor = Self.Font.Color then FValueFontColor := dxclInspectorValueFontColor;
|
|
if FGridColor = clBtnFace then FGridColor := dxclInspectorGridColor;
|
|
if Color = clWindow then Color := dxclInspectorBackgroundColor;
|
|
end;
|
|
FPaintStyle := Value;
|
|
LayoutChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetRowHeight(Value: Integer);
|
|
begin
|
|
if Value < FMinRowHeight then
|
|
Value := FMinRowHeight;
|
|
if FRowHeight <> Value then
|
|
begin
|
|
FRowHeight := Value;
|
|
FRowHeightAssigned := True;
|
|
LayoutChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetShowRowHint(Value: Boolean);
|
|
begin
|
|
if FShowRowHint <> Value then
|
|
begin
|
|
FShowRowHint := Value;
|
|
if Value then ShowHint := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetState(Value: TdxInspectorState);
|
|
begin
|
|
FState := Value;
|
|
end;
|
|
|
|
// Size & AutoWidth
|
|
function TCustomdxInspector.CalcAutoWidth: Integer;
|
|
begin
|
|
if FDividerPosSave.Y = -1 then FDividerPosSave.Y := GetSectionWidth;
|
|
if FDividerPosSave.Y = 0 then
|
|
begin
|
|
FDividerPosSave.Y := -1;
|
|
Result := 0;
|
|
end
|
|
else
|
|
Result := FDividerPosSave.X * GetSectionWidth div FDividerPosSave.Y;
|
|
{ Result := FDividerPosSave.X * GetSectionWidth div FDividerPosSave.Y;}
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CheckBandWidth(var ABandWidth: Integer);
|
|
begin
|
|
if ABandWidth < FMinBandWidth then
|
|
ABandWidth := FMinBandWidth;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CheckDividerPos(var Pos: Integer);
|
|
begin
|
|
if HandleAllocated and (GetSectionWidth > 0) then
|
|
begin
|
|
if Pos > (GetSectionWidth - FMinColumnWidth) then
|
|
Pos := (GetSectionWidth - FMinColumnWidth);
|
|
if Pos < FMinColumnWidth then
|
|
Pos := FMinColumnWidth;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetBandCount: Integer;
|
|
begin
|
|
if IsAutoBandCount then
|
|
Result := FBandCount
|
|
else
|
|
Result := 1;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetFocusedBandIndex: Integer;
|
|
begin
|
|
Result := GetBandIndexByNode(FocusedNode);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetBandIndexByNode(ANode: TdxInspectorNode): Integer;
|
|
var
|
|
ABandRowCount: Integer;
|
|
begin
|
|
Result := -1;
|
|
GetBandRowInfo(True, ANode, Result, ABandRowCount);
|
|
end;
|
|
|
|
function TCustomdxInspector.GetBandRowCount(ABandIndex: Integer): Integer;
|
|
var
|
|
ANode: TdxInspectorNode;
|
|
begin
|
|
if IsAutoBandCount then
|
|
GetBandRowInfo(False, ANode, ABandIndex, Result)
|
|
else
|
|
Result := RowCount;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.GetBandRowInfo(AByNode: Boolean; // if False then by BandIndex
|
|
var Node: TdxInspectorNode; var BandIndex, BandRowCount: Integer);
|
|
var
|
|
ABandHeight: Integer;
|
|
|
|
function CalcBandRows(ABandIndex: Integer; var ACurNode: TdxInspectorNode): Boolean;
|
|
var
|
|
ABandRowCount, ANodeHeight, AHeight: Integer;
|
|
ACurTopNode: TdxInspectorNode;
|
|
begin
|
|
Result := False;
|
|
ABandRowCount := 0;
|
|
AHeight := 0;
|
|
ACurTopNode := ACurNode;
|
|
while ACurNode <> nil do
|
|
begin
|
|
if AByNode and (ACurNode = Node) then
|
|
begin
|
|
BandIndex := ABandIndex;
|
|
Result := True;
|
|
end;
|
|
ANodeHeight := GetNodeHeight(ACurNode);
|
|
Inc(AHeight, ANodeHeight);
|
|
Inc(ABandRowCount);
|
|
if AHeight > ABandHeight then
|
|
begin
|
|
if ABandRowCount = 1 then
|
|
ACurNode := GetNextVisible(ACurNode)
|
|
else
|
|
begin
|
|
Dec(ABandRowCount);
|
|
Result := False;
|
|
end;
|
|
Break;
|
|
end;
|
|
ACurNode := GetNextVisible(ACurNode);
|
|
end;
|
|
if not AByNode and (ABandIndex = BandIndex) then
|
|
begin
|
|
Node := ACurTopNode;
|
|
Result := True;
|
|
end;
|
|
if Result then
|
|
BandRowCount := ABandRowCount;
|
|
end;
|
|
|
|
var
|
|
ACurNode: TdxInspectorNode;
|
|
I: Integer;
|
|
begin
|
|
if IsAutoBandCount and HandleAllocated then
|
|
begin
|
|
ACurNode := TopNode;
|
|
ABandHeight := ClientHeight;
|
|
for I := 0 to BandCount - 1 do
|
|
if CalcBandRows(I, ACurNode) then
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetBandTopNode(ABandIndex: Integer): TdxInspectorNode;
|
|
var
|
|
ABandRowCount: Integer;
|
|
begin
|
|
if IsAutoBandCount then
|
|
GetBandRowInfo(False, Result, ABandIndex, ABandRowCount)
|
|
else
|
|
Result := TopVisibleNode;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetLeftBandIndex: Integer;
|
|
begin
|
|
if IsAutoBandCount then
|
|
Result := FLeftBandIndex
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetPartVisibleBandCount: Integer;
|
|
begin
|
|
if IsAutoBandCount then
|
|
Result := FPartVisibleBandCount
|
|
else
|
|
Result := 1;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetVisibleBandCount: Integer;
|
|
begin
|
|
if IsAutoBandCount then
|
|
Result := FVisibleBandCount
|
|
else
|
|
Result := 1;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetBandWidth(Value: Integer);
|
|
begin
|
|
CheckBandWidth(Value);
|
|
if FBandWidth <> Value then
|
|
begin
|
|
FBandWidth := Value;
|
|
LayoutChanged;
|
|
if HandleAllocated then
|
|
SendMessage(Handle, WM_SIZE, SIZE_RESTORED, 0); // TODO: method
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetDividerPos(Value: Integer);
|
|
begin
|
|
CheckDividerPos(Value);
|
|
if FDividerPos <> Value then
|
|
begin
|
|
FDividerPos := Value;
|
|
Invalidate;
|
|
end;
|
|
if not FSizing then
|
|
begin
|
|
FDividerPosSave.X := FDividerPos;
|
|
FDividerPosSave.Y := GetSectionWidth;
|
|
end;
|
|
// TODO: CHECK
|
|
UpdateScrollBar;
|
|
UpdateTopCoord;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetMaxRowTextLineCount(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
if FMaxRowTextLineCount <> Value then
|
|
begin
|
|
FMaxRowTextLineCount := Value;
|
|
LayoutChanged;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetMinBandWidth(Value: Integer);
|
|
begin
|
|
if Value < dxInspectorLimitBandWidth then
|
|
Value := dxInspectorLimitBandWidth;
|
|
if FMinBandWidth <> Value then
|
|
begin
|
|
FMinBandWidth := Value;
|
|
SetBandWidth(BandWidth);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetMinColumnWidth(Value: Integer);
|
|
begin
|
|
if Value < dxInspectorLimitColumnWidth then
|
|
Value := dxInspectorLimitColumnWidth;
|
|
if FMinColumnWidth <> Value then
|
|
begin
|
|
FMinColumnWidth := Value;
|
|
SetDividerPos(DividerPos);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateDesigner;
|
|
var
|
|
ParentForm: {$IFNDEF DELPHI3}TForm{$ELSE}TCustomForm{$ENDIF};
|
|
begin
|
|
if (csDesigning in ComponentState) and HandleAllocated and
|
|
not (csUpdating in ComponentState) then
|
|
begin
|
|
ParentForm := GetParentForm(Self);
|
|
if Assigned(ParentForm) and Assigned(ParentForm.Designer) then
|
|
ParentForm.Designer.Modified;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateTopCoord;
|
|
|
|
function CalcPossibleRowCount: Integer;
|
|
var
|
|
ABandHeight, AHeight, ANodeHeight: Integer;
|
|
ACurNode: TdxInspectorNode;
|
|
begin
|
|
Result := 0;
|
|
AHeight := 0;
|
|
ABandHeight := ClientHeight;
|
|
ACurNode := GetAbsoluteNode(TopIndex + RowCount - 1);
|
|
while ACurNode <> nil do
|
|
begin
|
|
ANodeHeight := GetNodeHeight(ACurNode);
|
|
Inc(AHeight, ANodeHeight);
|
|
if AHeight > ABandHeight then
|
|
Break;
|
|
Inc(Result);
|
|
ACurNode := ACurNode.GetPriorNode;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
ATopIndex, APossibleRowCount, ACount: Integer;
|
|
ALeftBandIndex, ABandCount: Integer;
|
|
begin
|
|
if not HandleAllocated then Exit;
|
|
if IsAutoBandCount then
|
|
begin
|
|
ALeftBandIndex := LeftBandIndex;
|
|
ABandCount := BandCount;
|
|
if (ALeftBandIndex + VisibleBandCount) > ABandCount then
|
|
ALeftBandIndex := ABandCount - VisibleBandCount;
|
|
if ALeftBandIndex < 0 then ALeftBandIndex := 0;
|
|
LeftBandIndex := ALeftBandIndex;
|
|
end
|
|
else
|
|
begin
|
|
ATopIndex := TopIndex;
|
|
ACount := GetAbsoluteCount;
|
|
APossibleRowCount := CalcPossibleRowCount;
|
|
if (ATopIndex + APossibleRowCount) > ACount then
|
|
ATopIndex := ACount - APossibleRowCount;
|
|
if ATopIndex < 0 then ATopIndex := 0;
|
|
if ATopIndex <> TopIndex then TopIndex := ATopIndex;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetCustomization: Boolean;
|
|
begin
|
|
Result := CustomizeForm <> nil;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetCustomization(Value: Boolean);
|
|
begin
|
|
if Customization <> Value then
|
|
if Value then
|
|
ShowCustomizeForm
|
|
else
|
|
HideCustomizeForm;
|
|
end;
|
|
|
|
// Draw TCustomdxInspector
|
|
procedure TCustomdxInspector.DrawButton(ACanvas: TCanvas; ARect, AButtonRect: TRect;
|
|
AButtonKind: TdxInspectorButtonKind; ANode: TdxInspectorNode);
|
|
|
|
procedure DrawNETIndent(ARect: TRect);
|
|
var
|
|
ARect1, ARect2: TRect;
|
|
ABrush1, ABrush2: HBRUSH;
|
|
ANextNode, ATopParentNode: TdxInspectorNode;
|
|
begin
|
|
ARect1 := ARect;
|
|
ARect1.Right := ARect1.Left + FIndent - 1;
|
|
ARect2 := ARect;
|
|
Inc(ARect2.Left, FIndent);
|
|
ACanvas.FillRect(ARect2);
|
|
Dec(ARect2.Left);
|
|
ARect2.Right := ARect2.Left + 1;
|
|
ANextNode := ANode.GetNextNode;
|
|
if not ((IsCategoryNode(ANode) and (ANode.Level = 0)) or
|
|
(IsCategoryNode(ANextNode) and (ANextNode.Level = 0))) then
|
|
Inc(ARect2.Bottom);
|
|
ABrush1 := FBkBrush;
|
|
ABrush2 := FGridBrush;
|
|
ATopParentNode := GetTopParentNode(ANode);
|
|
if (IsCategoryNode(ANode) and (ANode.Level = 0)) or
|
|
IsCategoryNode(ATopParentNode) then
|
|
begin
|
|
ABrush1 := FGroupBkBrush;
|
|
if not (IsCategoryNode(ANode) and (ANode.Level = 0)) then
|
|
ABrush2 := FGroupGridBrush;
|
|
end;
|
|
FillRect(ACanvas.Handle, ARect1, ABrush1);
|
|
FillRect(ACanvas.Handle, ARect2, ABrush2);
|
|
end;
|
|
|
|
procedure DrawToolboxIndent(ARect: TRect);
|
|
begin
|
|
if IsCategoryNode(ANode) then
|
|
FillRect(ACanvas.Handle, ARect, FBkBrush)
|
|
else
|
|
ACanvas.FillRect(ARect);
|
|
end;
|
|
|
|
var
|
|
Ch: Char;
|
|
begin
|
|
with ACanvas do
|
|
begin
|
|
// TODO: !!
|
|
if PaintStyle = ipsNET then
|
|
DrawNETIndent(ARect)
|
|
else
|
|
if PaintStyle = ipsCategorized then
|
|
DrawToolboxIndent(ARect)
|
|
else
|
|
FillRect(ARect);
|
|
|
|
if AButtonKind <> ibkNone then
|
|
begin
|
|
if PaintStyle = ipsStandard then
|
|
begin
|
|
SetBkMode(Handle, TRANSPARENT);
|
|
if AButtonKind = ibkMinus then Ch := '-' else Ch := '+';
|
|
DrawText(Handle, PChar(@Ch), 1, AButtonRect,
|
|
DT_LEFT or DT_EXPANDTABS or DT_NOPREFIX or DT_SINGLELINE or DT_VCENTER or DT_CENTER);
|
|
end
|
|
else
|
|
if PaintStyle = ipsExtended then
|
|
begin
|
|
with AButtonRect do
|
|
begin
|
|
// clac rect
|
|
Left := (Left + Right - dxInspectorButtonExSize) div 2;
|
|
Top := (Top + Bottom - dxInspectorButtonExSize) div 2;
|
|
Right := Left + dxInspectorButtonExSize;
|
|
Bottom := Top + dxInspectorButtonExSize;
|
|
// draw
|
|
DrawEdge(Handle, AButtonRect, BDR_RAISEDINNER, BF_LEFT or BF_TOP);
|
|
DrawEdge(Handle, AButtonRect, BDR_RAISEDOUTER, BF_RIGHT or BF_BOTTOM);
|
|
InflateRect(AButtonRect, -1, -1);
|
|
DrawEdge(Handle, AButtonRect, BDR_RAISEDINNER, BF_RIGHT or BF_BOTTOM);
|
|
Dec(Right);
|
|
Dec(Bottom);
|
|
Windows.FillRect(Handle, Rect(Left + 1, Top + 3, Left + 6, Top + 3 + 1), COLOR_BTNTEXT + 1);
|
|
if AButtonKind = ibkPlus then
|
|
Windows.FillRect(Handle, Rect(Left + 3, Top + 1, Left + 3 + 1, Top + 6), COLOR_BTNTEXT + 1);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
with AButtonRect do
|
|
begin
|
|
Left := (Left + Right - dxInspectorButtonSize) div 2;
|
|
Top := (Top + Bottom - dxInspectorButtonSize) div 2;
|
|
Right := Left + dxInspectorButtonSize;
|
|
Bottom := Top + dxInspectorButtonSize;
|
|
// draw
|
|
Pen.Color := Font.Color;
|
|
if PaintStyle = ipsNET then
|
|
begin
|
|
Pen.Color := Self.Font.Color;
|
|
if IsCategoryNode(ANode) then
|
|
Windows.FillRect(Handle, AButtonRect, FGroupBkBrush)
|
|
else
|
|
Windows.FillRect(Handle, AButtonRect, FBkBrush);
|
|
end;
|
|
Polyline([Point(Left, Top), Point(Right-1, Top),
|
|
Point(Right-1, Bottom-1), Point(Left, Bottom-1), Point(Left, Top)]);
|
|
MoveTo(Left + 2, Top + 4);
|
|
LineTo(Left + 7, Top + 4);
|
|
if AButtonKind = ibkPlus then
|
|
begin
|
|
MoveTo(Left + 4, Top + 2);
|
|
LineTo(Left + 4, Top + 7);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DrawDragNode;
|
|
const
|
|
indDrag = 32;
|
|
var
|
|
ARect: TRect;
|
|
S1: string;
|
|
PrevBkColor, PrevTextColor: TColorRef;
|
|
begin
|
|
ARect := Rect(0, 0, FDividerPos + indDrag, FTextHeight);
|
|
with DrawBitmap, ARect Do
|
|
begin
|
|
Width := Right - Left;
|
|
Height := Bottom - Top;
|
|
end;
|
|
with DrawBitmap.Canvas Do
|
|
begin
|
|
{Clear Node Rect }
|
|
PrevBkColor := GetBkColor(Handle);
|
|
SetBkColor(Handle, ColorToRGB(clBtnShadow));
|
|
PrevTextColor := GetTextColor(Handle);
|
|
SetTextColor(Handle, ColorToRGB(Self.Color));
|
|
Windows.FillRect(Handle, ARect, HalftoneBrush);
|
|
SetBkColor(Handle, PrevBkColor);
|
|
SetTextColor(Handle, PrevTextColor);
|
|
Font := Self.Font;
|
|
Font.Style := [fsBold];
|
|
InflateRect(ARect, -1, -1);
|
|
ARect.Left := ARect.Left + indDrag - 2;
|
|
// draw text
|
|
S1 := GetDragNodeText(FDragNode);
|
|
SetBkMode(Handle, TRANSPARENT);
|
|
DrawText(Handle, PChar(S1), Length(S1), ARect,
|
|
DT_LEFT or DT_EXPANDTABS or DT_NOPREFIX or DT_SINGLELINE or DT_VCENTER);
|
|
end;
|
|
with DrawBitmap do
|
|
BitBlt(Canvas.Handle, 0, 0, Width, Height, 0, 0, 0, DSTINVERT);
|
|
// create TImageList
|
|
if FDragImageNode = nil then
|
|
FDragImageNode := TImageList.CreateSize(DrawBitmap.Width, DrawBitmap.Height);
|
|
FDragImageNode.DrawingStyle := dsSelected;
|
|
FDragImageNode.AddMasked(DrawBitmap, DrawBitmap.Canvas.Pixels[1, 0]{Self.Color});
|
|
end;
|
|
|
|
procedure TCustomdxInspector.DrawSizingLine;
|
|
|
|
function GetBandRect(ABandIndex: Integer): TRect;
|
|
begin
|
|
Result := ClientRect;
|
|
if IsAutoBandCount then
|
|
begin
|
|
Result.Right := Result.Left + BandWidth;
|
|
OffsetRect(Result, (ABandIndex - LeftBandIndex) * BandWidth, 0);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
DC: HDC;
|
|
PrevPen: HPEN;
|
|
PrevROP2: Integer;
|
|
ARect: TRect;
|
|
begin
|
|
if IsDynamicColumnSizing or (FState in [isBandSizing{, isRowSizing}]) then Exit;
|
|
DC := Canvas.Handle;
|
|
PrevPen := SelectObject(DC, GetStockObject(BLACK_PEN));
|
|
PrevROP2 := SetROP2(DC, R2_NOTXORPEN);
|
|
try
|
|
if FState = isRowSizing then
|
|
begin
|
|
if FSizingNode <> nil then
|
|
begin
|
|
ARect := GetRectNode(FSizingNode);
|
|
ARect.Bottom := FSizingPos;
|
|
Windows.MoveToEx(DC, ARect.Left, ARect.Bottom, nil);
|
|
Windows.LineTo(DC, ARect.Right, ARect.Bottom);
|
|
end;
|
|
end
|
|
else
|
|
if FState = isColumnSizing then
|
|
begin
|
|
ARect := GetBandRect(FocusedBandIndex);
|
|
Windows.MoveToEx(DC, FSizingPos, ARect.Top, nil);
|
|
Windows.LineTo(DC, FSizingPos, ARect.Bottom);
|
|
end;
|
|
finally
|
|
SetROP2(DC, PrevROP2);
|
|
SelectObject(DC, PrevPen);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.InvalidateRect(ARect:TRect);
|
|
begin
|
|
if not HandleAllocated then Exit;
|
|
Windows.InvalidateRect(Handle, @ARect, False);
|
|
end;
|
|
|
|
function TCustomdxInspector.RecalcPaintRect(ARect: TRect): TRect;
|
|
begin
|
|
Result := ARect;
|
|
if PaintStyle in [ipsStandard, ipsExtended] then
|
|
Result.Top := Result.Top - 2;
|
|
if IsAutoBandCount then
|
|
InflateRect(Result, 2, 0);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WriteImage(ACanvas: TCanvas; ARect: TRect; Index: Integer);
|
|
begin
|
|
if Assigned(Images) and (0 <= Index) and (Index < Images.Count) then
|
|
Images.Draw(ACanvas, (ARect.Left + ARect.Right - Images.Width + 1) div 2,
|
|
(ARect.Top + ARect.Bottom - Images.Height + 1) div 2, Index);
|
|
end;
|
|
|
|
// Editor TCustomdxInspector
|
|
procedure TCustomdxInspector.CheckEditor(ASetFocus, AFlagRefresh: Boolean);
|
|
var
|
|
R, EditRect : TRect;
|
|
FEdit: TdxInplaceEdit;
|
|
|
|
procedure UpdateEditor;
|
|
begin
|
|
FInplaceComplexRowIndex := FComplexRowIndex;
|
|
FInplaceNode := FocusedNode;
|
|
BeginInitEdit;
|
|
try
|
|
InitEditProperties(FInplaceEdit);
|
|
InitEditValue(FInplaceNode, FInplaceEdit);
|
|
with TdxInplaceInspectorEdit(FInplaceEdit) do
|
|
begin
|
|
Modified := False;
|
|
if Self.GetReadOnly then
|
|
ReadOnly := True;
|
|
SetActive(True);
|
|
end;
|
|
finally
|
|
EndInitEdit;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if CanEditShow then
|
|
begin
|
|
if not ASetFocus and
|
|
not (Focused or ((FInplaceEdit <> nil) and (FInplaceEdit.Focused))) then
|
|
begin
|
|
if (FInplaceEdit <> nil) and not FInplaceEdit.Focused and AFlagRefresh then
|
|
UpdateEditor;
|
|
Exit;
|
|
end;
|
|
// EditRect := CellRect(FocusedNode);
|
|
EditRect := GetEditRect(FocusedNode);
|
|
// Check class type
|
|
FEdit := FindInplaceEdit(FocusedNode);
|
|
if (FEdit = nil) then
|
|
begin
|
|
FInplaceNode := nil;
|
|
HideEdit(False);
|
|
FInplaceEdit := CreateEditor(FocusedNode);
|
|
FInplaceEdit.Parent := Self;
|
|
UpdateEditor;
|
|
FInplaceEdit.Move(EditRect);
|
|
Exit;
|
|
end;
|
|
if (FEdit <> FInplaceEdit) or (FocusedNode <> FInplaceNode) or
|
|
(FInplaceComplexRowIndex <> FComplexRowIndex) then
|
|
begin
|
|
FInplaceNode := nil;
|
|
HideEdit(False);
|
|
FInplaceEdit := FEdit;
|
|
UpdateEditor;
|
|
FInplaceEdit.Move(EditRect);
|
|
Exit;
|
|
end;
|
|
// Check Bounds
|
|
GetWindowRect(FInplaceEdit.Handle, R);
|
|
InflateRect(R, -dxEditBorderSize, -dxEditBorderSize);
|
|
MapWindowPoints(0, Handle, R, 2);
|
|
if not EqualRect(R, EditRect) or ASetFocus then
|
|
begin
|
|
FInplaceNode := FocusedNode;
|
|
FInplaceEdit.Hide;
|
|
if FInplaceEdit <> nil then
|
|
begin
|
|
FInplaceEdit.Move(EditRect);
|
|
FInplaceEdit.Deselect;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if (FInplaceEdit <> nil) and IsWindowVisible(FInplaceEdit.Handle) then
|
|
HideEditor;
|
|
end;
|
|
|
|
function TCustomdxInspector.GetInplaceComplexRowIndex: Integer;
|
|
begin
|
|
Result := FComplexRowIndex;
|
|
if Result = -1 then
|
|
Result := 0;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.UpdateText;
|
|
begin
|
|
if (FInplaceNode <> nil) then
|
|
AssignEditValue(FInplaceNode, FInplaceEdit);
|
|
end;
|
|
|
|
// Hint
|
|
procedure TCustomdxInspector.ClearPrevHintNode;
|
|
begin
|
|
FPrevHintComplexRowIndex := -1;
|
|
FPrevHintNode := nil;
|
|
FPrevHintTest := ihtOutside;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.HideRowHint;
|
|
begin
|
|
if FShowHintTimerId <> 0 then
|
|
begin
|
|
KillTimer(Handle, FShowHintTimerId);
|
|
FShowHintTimerId := 0;
|
|
end;
|
|
if FHideHintTimerId <> 0 then
|
|
begin
|
|
KillTimer(Handle, FHideHintTimerId);
|
|
FHideHintTimerId := 0;
|
|
end;
|
|
if FHintWindow <> nil then
|
|
FHintWindow.HideHint;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.SetInplaceComplexRowIndex(Value: Integer);
|
|
var
|
|
APrevInplaceComplexRowIndex: Integer;
|
|
begin
|
|
APrevInplaceComplexRowIndex := InplaceComplexRowIndex; // -1 equal 0
|
|
CheckComplexRowIndex(Value);
|
|
if FComplexRowIndex <> Value then
|
|
begin
|
|
FComplexRowIndex := Value;
|
|
if APrevInplaceComplexRowIndex <> InplaceComplexRowIndex then
|
|
InvalidateNode(FocusedNode, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.StartShowRowHint(Wait: Boolean);
|
|
var
|
|
P: TPoint;
|
|
R, R1: TRect;
|
|
S: string;
|
|
HitInfo: TdxInspectorHitInfo;
|
|
DrawInfo: TdxInspectorDrawInfo;
|
|
AIsRowHint: Boolean;
|
|
begin
|
|
GetCursorPos(P);
|
|
HideRowHint;
|
|
P := ScreenToClient(P);
|
|
HitInfo := GetHitInfo(P);
|
|
if (HitInfo.hitType in [ihtDisplayLabel, ihtLabel]) and (HitInfo.Node <> nil) then
|
|
begin
|
|
S := '';
|
|
R := GetRectNode(HitInfo.Node);
|
|
CalcDrawInfo(HitInfo.Node, R, DrawInfo);
|
|
P.Y := R.Top - 2 + FRowFrameSize;
|
|
if HitInfo.hitType = ihtDisplayLabel then
|
|
begin
|
|
R1 := DrawInfo.DisplayRect;
|
|
P.X := R1.Left - 2;
|
|
if not IsShowHintNode(HitInfo.Node, HitInfo.ComplexRowIndex, HitInfo.ComplexRowRect,
|
|
False, R1, S, P.X, AIsRowHint) then
|
|
S := '';
|
|
if AIsRowHint then
|
|
begin
|
|
if Wait then
|
|
begin
|
|
FShowHintTimerId := SetTimer(Handle, ShowHintTimerId, WaitForShowHintTime, nil);
|
|
Exit;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
R1 := DrawInfo.ValueRect;
|
|
P.X := R1.Left - 1;
|
|
if not IsShowHintNode(HitInfo.Node, HitInfo.ComplexRowIndex, HitInfo.ComplexRowRect,
|
|
True, R1, S, P.X, AIsRowHint) then
|
|
S := '';
|
|
end;
|
|
P := ClientToScreen(P);
|
|
if S <> '' then
|
|
begin
|
|
if FHintWindow = nil then
|
|
FHintWindow := TdxContainerHintWindow.Create(nil);
|
|
FHintWindow.ActivateHintEx(P, 0{TODO MuliLine}, S, Self.Font, True);
|
|
FHideHintTimerId := SetTimer(Handle, HideHintTimerId, WaitForHideHintTime, nil);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// messages TCustomdxInspector
|
|
procedure TCustomdxInspector.WMCancelMode(var Msg: TMessage);
|
|
begin
|
|
CancelDragSizing;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMCaptureChanged(var Msg: TMessage);
|
|
begin
|
|
inherited;
|
|
if FState = isNodeDown then
|
|
begin
|
|
KillTimer(Handle, ScrollTimerId);
|
|
// SetState(isNormal);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMDestroy(var Msg: TWMDestroy);
|
|
begin
|
|
HideRowHint;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMEraseBkgnd(var Message: TWMEraseBkgnd);
|
|
begin
|
|
Message.Result := 1;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMGetDlgCode(var Msg: TWMGetDlgCode);
|
|
begin
|
|
Msg.Result := DLGC_WANTARROWS;
|
|
// if ioTabs in Options then
|
|
// Msg.Result := Msg.Result or DLGC_WANTTAB;
|
|
if IsTabs {and (GetAsyncKeyState(VK_CONTROL) >= 0) }then
|
|
Msg.Result := Msg.Result or DLGC_WANTTAB;
|
|
if ioEditing in Options then
|
|
Msg.Result := Msg.Result or DLGC_WANTCHARS;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMHScroll(var Message: TWMHScroll);
|
|
var
|
|
SI: TScrollInfo;
|
|
begin
|
|
if not AcquireFocus then Exit;
|
|
with Message do
|
|
case ScrollCode of
|
|
SB_LINEUP:
|
|
LeftBandIndex := LeftBandIndex - 1;
|
|
SB_LINEDOWN:
|
|
LeftBandIndex := LeftBandIndex + 1;
|
|
SB_PAGEUP:
|
|
LeftBandIndex := LeftBandIndex - VisibleBandCount;
|
|
SB_PAGEDOWN:
|
|
LeftBandIndex := LeftBandIndex + VisibleBandCount;
|
|
SB_THUMBTRACK:
|
|
begin
|
|
SI.cbSize := SizeOf(SI);
|
|
SI.fMask := SIF_ALL;
|
|
GetScrollInfo(SB_HORZ, SI);
|
|
if SI.nTrackPos <= 0 then
|
|
LeftBandIndex := 0
|
|
else
|
|
if SI.nTrackPos >= BandCount then
|
|
LeFtBandIndex := BandCount
|
|
else
|
|
LeftBandIndex := SI.nTrackPos;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMKillFocus(var Msg: TWMKillFocus);
|
|
begin
|
|
inherited;
|
|
if (FInplaceEdit <> nil) and (Msg.FocusedWnd = FInplaceEdit.Handle)
|
|
then Exit;
|
|
InvalidateNode(FocusedNode, False);
|
|
if State = isNodeDown then SetState(isNormal); //after Abort
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMLButtonDown(var Message: TWMLButtonDown);
|
|
begin
|
|
inherited;
|
|
if FInplaceEdit <> nil then FInplaceEdit.FClickTime := GetMessageTime;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMNCCalcSize(var Message: TWMNCCalcSize);
|
|
begin
|
|
if (BorderStyle <> bsNone) and Flat then
|
|
InflateRect(Message.CalcSize_Params.rgrc[0], -1, -1);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMNCHitTest(var Msg: TWMNCHitTest);
|
|
begin
|
|
DefaultHandler(Msg);
|
|
FHitTest := SmallPointToPoint(Msg.Pos);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMNCPaint(var Message: TMessage);
|
|
var
|
|
R : TRect;
|
|
DC : HDC;
|
|
begin
|
|
inherited;
|
|
if not Flat or (BorderStyle = bsNone) then Exit;
|
|
GetWindowRect(Handle, R);
|
|
OffsetRect(R, -R.Left, -R.Top);
|
|
DC := GetWindowDC(Handle);
|
|
DrawEdge(DC, R, BDR_SUNKENOUTER, BF_RECT);
|
|
ReleaseDC(Handle, DC);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMSetCursor(var Msg: TWMSetCursor);
|
|
var
|
|
hInfo : TdxInspectorHitInfo;
|
|
State: TdxInspectorState;
|
|
Cur: HCURSOR;
|
|
begin
|
|
Cur := 0;
|
|
with Msg do
|
|
begin
|
|
if HitTest = HTCLIENT then
|
|
begin
|
|
State := isNormal;
|
|
if FState in [isNormal{, isEditing}] then
|
|
begin
|
|
FHitTest := ScreenToClient(FHitTest);
|
|
hInfo := GetHitInfo(FHitTest);
|
|
if (hInfo.hitType = ihtColumnEdge) and
|
|
(ioColumnSizing in Options) then
|
|
State := isColumnSizing;
|
|
if (hInfo.hitType = ihtBandseparator) and
|
|
(ioBandSizing in Options) then
|
|
State := isBandSizing;
|
|
if (hInfo.hitType = ihtRowEdge) and
|
|
(ioRowSizing in Options){?} then
|
|
State := isRowSizing;
|
|
end
|
|
else
|
|
State := FState;
|
|
if (State in [isBandSizing, isColumnSizing]) then
|
|
Cur := Screen.Cursors[crHSplit];
|
|
if (State in [isRowSizing]) then
|
|
Cur := Screen.Cursors[crVSplit];
|
|
end;
|
|
end;
|
|
|
|
if Cur <> 0 then SetCursor(Cur)
|
|
else inherited;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMSetFocus(var Msg: TWMSetFocus);
|
|
begin
|
|
inherited;
|
|
if (FInplaceEdit = nil) or (Msg.FocusedWnd <> FInplaceEdit.Handle) then
|
|
begin
|
|
InvalidateNode(FocusedNode, False);
|
|
CheckEditor(True{SetFocus if not focused}, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMSize(var Msg: TWMSize);
|
|
var PrevState : Boolean;
|
|
begin
|
|
inherited;
|
|
PrevState := FSizing;
|
|
FSizing := True;
|
|
try
|
|
UpdateScrollBar;
|
|
if (ioAutoWidth in Options) and not (csLoading in ComponentState) and not FLoading then
|
|
DividerPos := CalcAutoWidth
|
|
else
|
|
SetDividerPos(DividerPos);
|
|
UpdateTopCoord;
|
|
finally
|
|
FSizing := PrevState;
|
|
end;
|
|
CheckEditor(False, False);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMTimer(var Msg: TWMTimer);
|
|
|
|
function GetRowsRect(APos: TPoint): TRect;
|
|
var
|
|
ADrawInfo: TdxInspectorContentDrawInfo;
|
|
I, J: Integer;
|
|
begin
|
|
SetRectEmpty(Result);
|
|
CalcContentDrawInfo(ADrawInfo);
|
|
try
|
|
for I := 0 to ADrawInfo.BandCount - 1 do
|
|
if PtInRect(ADrawInfo.BandsInfo^[I].BandContentRect, APos) then
|
|
begin
|
|
Result := ADrawInfo.BandsInfo^[I].BandContentRect;
|
|
Result.Bottom := Result.Top;
|
|
for J := 0 to ADrawInfo.BandsInfo^[I].RowCount - 1 do
|
|
Inc(Result.Bottom, ADrawInfo.BandsInfo^[I].RowsInfo^[J].RowHeight);
|
|
Break;
|
|
end;
|
|
finally
|
|
FreeContentDrawInfo(ADrawInfo);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
Pos: TPoint;
|
|
ARect: TRect;
|
|
begin
|
|
if Msg.TimerId = ScrollTimerId then // scroll
|
|
begin
|
|
if not (State in [isNodeDown, isNodeDragging]) then Exit;
|
|
GetCursorPos(Pos);
|
|
Pos := ScreenToClient(Pos);
|
|
|
|
if Pos.X < 0 then
|
|
Pos.X := 0
|
|
else
|
|
if Pos.X >= ClientWidth then
|
|
Pos.X := ClientWidth - 1;
|
|
|
|
ARect := GetRowsRect(Pos);
|
|
if Pos.Y < ARect.Top then {ScrollUp}
|
|
begin
|
|
if not IsAutoBandCount and (TopIndex <> FocusedNumber) then
|
|
FocusedNumber := TopIndex;
|
|
FocusedNumber := FocusedNumber - 1;
|
|
end;
|
|
if Pos.Y > ARect.Bottom then {ScrollDown}
|
|
begin
|
|
if not IsAutoBandCount and ((TopIndex + RowCount - 1) <> FocusedNumber) then
|
|
FocusedNumber := TopIndex + RowCount - 1;
|
|
FocusedNumber := FocusedNumber + 1;
|
|
end;
|
|
end
|
|
else
|
|
if Msg.TimerId = HideHintTimerId then // hint
|
|
HideRowHint
|
|
else
|
|
if Msg.TimerId = ShowHintTimerId then // show hint
|
|
StartShowRowHint(False);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.WMVScroll(var Message: TWMVScroll);
|
|
var
|
|
SI: TScrollInfo;
|
|
begin
|
|
if not AcquireFocus then Exit;
|
|
with Message do
|
|
case ScrollCode of
|
|
SB_LINEUP:
|
|
TopIndex := TopIndex - 1;
|
|
SB_LINEDOWN:
|
|
TopIndex := TopIndex + 1;
|
|
SB_PAGEUP:
|
|
TopIndex := TopIndex - RowCount;
|
|
SB_PAGEDOWN:
|
|
TopIndex := TopIndex + RowCount;
|
|
SB_THUMBTRACK:
|
|
begin
|
|
SI.cbSize := sizeof(SI);
|
|
SI.fMask := SIF_ALL;
|
|
GetScrollInfo(SB_VERT, SI);
|
|
if SI.nTrackPos <= 0 then
|
|
TopIndex := 0
|
|
else
|
|
if SI.nTrackPos >= GetAbsoluteCount then
|
|
TopIndex := GetAbsoluteCount
|
|
else
|
|
TopIndex := SI.nTrackPos;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMCancelMode(var Msg: TMessage);
|
|
begin
|
|
CancelDragSizing;
|
|
if Assigned(FInplaceEdit) then
|
|
TWinControlAccess(FInplaceEdit).WndProc(Msg);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMColorChanged(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMCtl3DChanged(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
if (FBorderStyle = bsSingle) and not Flat then RecreateWnd;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMDesignHitTest(var Msg: TCMDesignHitTest);
|
|
var
|
|
AHitInfo: TdxInspectorHitInfo;
|
|
begin
|
|
Msg.Result := 0;
|
|
AHitInfo := GetHitInfo(Point(Msg.Pos.X, Msg.Pos.Y));
|
|
if (AHitInfo.hitType = ihtColumnEdge) or (FState = isColumnSizing) or
|
|
(AHitInfo.hitType = ihtBandSeparator) or (FState = isBandSizing) or
|
|
(AHitInfo.hitType = ihtRowEdge) or (FState = isRowSizing) or
|
|
(AHitInfo.hitType = ihtButton) then Msg.Result := 1;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMFontChanged(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMMouseEnter(var Message: TMessage);
|
|
var
|
|
P: TPoint;
|
|
begin
|
|
inherited;
|
|
GetCursorPos(P);
|
|
P := ScreenToClient(P);
|
|
CheckHotTrackNode(GetHitInfo(P).Node);
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMMouseLeave(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
CheckHotTrackNode(nil);
|
|
HideRowHint;
|
|
ClearPrevHintNode;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMParentFontChanged(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspector.CMShowHintChanged(var Message: TMessage);
|
|
begin
|
|
inherited;
|
|
if ShowHint then ShowRowHint := False;
|
|
end;
|
|
|
|
{ TdxInspectorEditStyle }
|
|
|
|
constructor TdxInspectorEditStyle.Create(AEdit: TdxInplaceEdit; AInspector: TCustomdxInspector);
|
|
begin
|
|
inherited Create(AEdit);
|
|
FInspector := AInspector;
|
|
end;
|
|
|
|
function TdxInspectorEditStyle.DefaultBorderColor: TColor;
|
|
begin
|
|
Result := clWindowFrame;
|
|
end;
|
|
|
|
function TdxInspectorEditStyle.DefaultBorderStyle: TdxEditBorderStyle;
|
|
begin
|
|
Result := Inspector.EditStyleBorderStyle;
|
|
end;
|
|
|
|
function TdxInspectorEditStyle.DefaultButtonStyle: TdxEditButtonViewStyle;
|
|
begin
|
|
Result := Inspector.EditStyleButtonStyle;
|
|
end;
|
|
|
|
function TdxInspectorEditStyle.DefaultButtonTransparence: TdxEditButtonTransparence;
|
|
begin
|
|
Result := ebtNone;
|
|
end;
|
|
|
|
function TdxInspectorEditStyle.DefaultEdges: TdxEditEdges;
|
|
begin
|
|
Result := [edgLeft, edgTop, edgRight, edgBottom];
|
|
end;
|
|
|
|
function TdxInspectorEditStyle.DefaultHotTrack: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TdxInspectorEditStyle.DefaultShadow: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
{ TdxInspectorRow }
|
|
|
|
constructor TdxInspectorRow.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FImageIndex := -1;
|
|
FViewData := GetdxInplaceEditClass.GetViewDataClass.Create;
|
|
FVisible := True;
|
|
end;
|
|
|
|
destructor TdxInspectorRow.Destroy;
|
|
begin
|
|
if (Inspector <> nil) {and
|
|
not (csDestroying in Inspector.ComponentState)} then
|
|
Inspector.RemoveRow(Self);
|
|
FViewData.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxInspectorRow then
|
|
begin
|
|
if Assigned(Inspector) then Inspector.BeginUpdate;
|
|
try
|
|
RestoreDefaults;
|
|
Alignment := TdxInspectorRow(Source).Alignment;
|
|
if rvCaption in TdxInspectorRow(Source).AssignedValues then
|
|
Caption := TdxInspectorRow(Source).Caption;
|
|
if rvReadOnly in TdxInspectorRow(Source).AssignedValues then
|
|
ReadOnly := TdxInspectorRow(Source).ReadOnly;
|
|
if rvMaxLength in TdxInspectorRow(Source).AssignedValues then
|
|
MaxLength := TdxInspectorRow(Source).MaxLength;
|
|
if rvRowHeight in TdxInspectorRow(Source).AssignedValues then
|
|
RowHeight := TdxInspectorRow(Source).RowHeight;
|
|
Hint := TdxInspectorRow(Source).Hint;
|
|
ShowHint := TdxInspectorRow(Source).ShowHint;
|
|
IsCategory := TdxInspectorRow(Source).IsCategory;
|
|
CharCase := TdxInspectorRow(Source).CharCase;
|
|
Visible := TdxInspectorRow(Source).Visible;
|
|
finally
|
|
if Assigned(Inspector) then Inspector.EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
function TdxInspectorRow.DefaultCaption: String;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
function TdxInspectorRow.DefaultMaxLength: Integer;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
|
|
function TdxInspectorRow.DefaultReadOnly: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TdxInspectorRow.DefaultRowHeight: Integer;
|
|
begin
|
|
if Assigned(Inspector) then
|
|
Result := Inspector.GetDefaultNodeHeight(Node)
|
|
else
|
|
Result := 0;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetParentComponent: TComponent;
|
|
begin
|
|
Result := Inspector;
|
|
end;
|
|
|
|
function TdxInspectorRow.HasParent: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TdxInspectorRow.IsCanModify: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TdxInspectorRow.IsValidChar(InputChar: Char): Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.RestoreDefaultRowHeight;
|
|
begin
|
|
RowHeight := DefaultRowHeight;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.RestoreDefaults;
|
|
begin
|
|
FAssignedValues := [];
|
|
FAlignment := taLeftJustify;
|
|
FShowHint := False;
|
|
FIsCategory := False;
|
|
FCharCase := ecNormal;
|
|
FRowHeight := 0;
|
|
end;
|
|
|
|
// protected TdxInspectorRow
|
|
procedure TdxInspectorRow.ReadState(Reader: TReader);
|
|
begin
|
|
inherited ReadState(Reader);
|
|
if Reader.Parent is TCustomdxInspectorControl then
|
|
Inspector := TCustomdxInspectorControl(Reader.Parent);
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetName(const Value: TComponentName);
|
|
begin
|
|
inherited SetName(Value);
|
|
if (Assigned(FOnChangeName)) then FOnChangeName(self);
|
|
if Inspector <> nil then
|
|
Inspector.UpdateDesignEditor;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetParentComponent(AParent: TComponent);
|
|
begin
|
|
if not (csLoading in ComponentState) then
|
|
Inspector := AParent as TCustomdxInspectorControl;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.DoChange(Sender: TObject);
|
|
begin
|
|
if (Inspector <> nil) and not Inspector.IsInitEdit then
|
|
begin
|
|
Inspector.DoEditChange(Self);
|
|
if Assigned(FOnChange) then FOnChange(Self);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.DoDrawCaption(ACanvas:TCanvas;
|
|
AIndentRect, AButtonRect, AImageRect: TRect; AButtonKind: TdxInspectorButtonKind;
|
|
ADisplayRect: TRect; var AText: string; var ADone: Boolean);
|
|
var
|
|
AColor: TColor;
|
|
begin
|
|
if Assigned(FOnDrawCaption) then
|
|
begin
|
|
AColor := ACanvas.Brush.Color;
|
|
FOnDrawCaption(Self, ACanvas, ADisplayRect, AText, ACanvas.Font, AColor, ADone);
|
|
ACanvas.Brush.Color := AColor;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.DoDrawValue(ACanvas:TCanvas; ARect : TRect; var AText: string; var ADone: Boolean);
|
|
var
|
|
AColor: TColor;
|
|
begin
|
|
if Assigned(FOnDrawValue) then
|
|
begin
|
|
AColor := ACanvas.Brush.Color;
|
|
FOnDrawValue(Self, ACanvas, ARect, AText, ACanvas.Font, AColor, ADone);
|
|
ACanvas.Brush.Color := AColor;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.DoEdited;
|
|
begin
|
|
if (Inspector <> nil) and Assigned(Inspector.FOnEdited) then
|
|
Inspector.FOnEdited(Inspector, Node, Self);
|
|
end;
|
|
|
|
procedure TdxInspectorRow.DoValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean);
|
|
begin
|
|
if (Inspector <> nil) and not Inspector.IsInitEdit then
|
|
begin
|
|
Inspector.DoEditValidate(Self, ErrorText, Accept);
|
|
if Assigned(FOnValidate) then FOnValidate(Self, ErrorText, Accept);
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetEditLimit: Integer;
|
|
begin
|
|
Result := 0;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetEditMaskRow: string;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
function TdxInspectorRow.GetMinRowHeight(ACanvas: TCanvas): Integer;
|
|
begin
|
|
Result := ACanvas.TextHeight('Wg')+ 2 + 1;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.Changed;
|
|
begin
|
|
if Inspector <> nil then
|
|
Inspector.UpdateRow(nil);
|
|
end;
|
|
|
|
function TdxInspectorRow.AssignEditValue(AInplaceEdit: TdxInplaceEdit): Variant;
|
|
begin
|
|
if AInplaceEdit is TdxInplaceTextEdit then
|
|
EditText := TdxInplaceInspectorTextEdit(AInplaceEdit).Text;
|
|
Result := EditText;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetdxInplaceEditClass: TdxInplaceEditClass;
|
|
begin
|
|
Result := TdxInplaceTextEdit;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.InitEditProperties(AInplaceEdit: TdxInplaceEdit);
|
|
begin
|
|
if AInplaceEdit is TdxInplaceEdit then
|
|
with TdxInplaceInspectorEdit(AInplaceEdit) do
|
|
begin
|
|
ReadOnly := Self.ReadOnly;
|
|
OnChange := Self.DoChange;
|
|
OnValidate := Self.DoValidate;
|
|
end;
|
|
if AInplaceEdit is TdxInplaceTextEdit then
|
|
with TdxInplaceInspectorTextEdit(AInplaceEdit) do
|
|
begin
|
|
CharCase := Self.CharCase;
|
|
MaxLength := Self.MaxLength;
|
|
PasswordChar := Self.PasswordChar;
|
|
if HandleAllocated then ClearUndo;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorRow.IsEqualValues(const Value: Variant): Boolean;
|
|
begin
|
|
Result := Inspector.IsDefaultEqualValues(Value, Self);
|
|
end;
|
|
|
|
function TdxInspectorRow.InitEditValue(AInplaceEdit: TdxInplaceEdit): Variant;
|
|
begin
|
|
TdxInplaceInspectorEdit(AInplaceEdit).Text := EditText;
|
|
Result := TdxInplaceInspectorEdit(AInplaceEdit).Text;
|
|
end;
|
|
|
|
function TdxInspectorRow.IsShowHint(IsValue: Boolean; const R: TRect; var AText: string): Boolean;
|
|
begin
|
|
if (Inspector <> nil) and Inspector.HandleAllocated then
|
|
begin
|
|
if IsValue then
|
|
AText := EditText // TODO
|
|
else
|
|
AText := Caption;
|
|
Inspector.Canvas.Font.Assign(Inspector.Font);
|
|
if IsCategory then Inspector.Canvas.Font.Style := [fsBold];
|
|
Result := Inspector.Canvas.TextWidth(AText) > (R.Right - R.Left);
|
|
end
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.PrepareViewData(AViewData: TdxEditViewData; ACellViewData: TdxInspectorCellViewData);
|
|
begin
|
|
with AViewData do
|
|
begin
|
|
Enabled := True;
|
|
Focused := False;
|
|
Selected := ACellViewData.Cell_HotTrackNode;
|
|
// Style
|
|
BorderColor := clNone;
|
|
if (Inspector.PaintStyle = ipsCategorized) and (ACellViewData.Cell_HotTrackNode or
|
|
((Node <> nil) and Node.Focused)) then
|
|
BorderStyle := xbsFlat // Inspector.EditStyleBorderStyle
|
|
else
|
|
BorderStyle := xbsNone;
|
|
ButtonStyle := Inspector.EditStyleButtonStyle;
|
|
ButtonTransparence := False;
|
|
Edges := [edgLeft, edgTop, edgRight, edgBottom];
|
|
Shadow := False;
|
|
Transparent := False;
|
|
// ViewBounds
|
|
OffsetSize := Rect(1, 0, 0, 0);
|
|
ViewBounds := ACellViewData.Cell_Rect;
|
|
// General
|
|
DrawAlignment := daSingleLine;
|
|
Font := ACellViewData.Cell_Font;
|
|
Brush := ACellViewData.Cell_Brush;
|
|
BkColor := ColorToRGB(ACellViewData.Cell_BkColor);
|
|
TextColor := ColorToRGB(ACellViewData.Cell_TextColor);
|
|
Alignment := ACellViewData.Cell_Alignment;
|
|
IsEditClass := False;
|
|
Data := ACellViewData.Cell_Text;
|
|
DataLength := ACellViewData.Cell_TextLength;
|
|
CalcHeight := False;
|
|
end;
|
|
if AViewData is TdxTextEditViewData then
|
|
with TdxTextEditViewData(AViewData) do
|
|
begin
|
|
CharCase := Self.CharCase;
|
|
EndEllipsis := ACellViewData.Cell_DrawEndEllipsis;
|
|
PasswordChar := Self.PasswordChar;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.Hide;
|
|
var
|
|
ANode: TdxInspectorRowNode;
|
|
I: Integer;
|
|
begin
|
|
if (Inspector <> nil) and (Node <> nil) then
|
|
begin
|
|
Inspector.BeginUpdate;
|
|
try
|
|
ANode := FNode;
|
|
for I := ANode.Count - 1 downto 0 do
|
|
TdxInspectorRowNode(ANode[I]).Row.Visible := False; //Hide;
|
|
FNode := nil;
|
|
ANode.FRow := nil;
|
|
ANode.Free;
|
|
finally
|
|
Inspector.EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.Show;
|
|
begin
|
|
if Inspector <> nil then
|
|
begin
|
|
Inspector.NotifyComplexRows(Self);
|
|
Inspector.InternalCreateNodeForRow(Self);
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetLinkObject: TObject;
|
|
begin
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetLinkObject(Value : TObject);
|
|
begin
|
|
end;
|
|
|
|
function TdxInspectorRow.GetLinkObjectName: String;
|
|
begin
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetLinkObjectName(const Value : String);
|
|
begin
|
|
end;
|
|
|
|
// private TdxInspectorRow
|
|
function TdxInspectorRow.GetCaption: String;
|
|
begin
|
|
if rvCaption in FAssignedValues then
|
|
Result := FCaption
|
|
else
|
|
Result := DefaultCaption;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetMaxLength: Integer;
|
|
begin
|
|
if rvMaxLength in FAssignedValues then
|
|
Result := FMaxLength
|
|
else
|
|
Result := DefaultMaxLength;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetReadOnly: Boolean;
|
|
begin
|
|
if rvReadOnly in FAssignedValues then
|
|
Result := FReadOnly
|
|
else
|
|
Result := DefaultReadOnly;
|
|
if not Result and (Inspector <> nil) then
|
|
Result := Inspector.ReadOnly;
|
|
end;
|
|
|
|
function TdxInspectorRow.GetRowHeight: Integer;
|
|
begin
|
|
if rvRowHeight in FAssignedValues then
|
|
begin
|
|
Result := FRowHeight;
|
|
if Result < DefaultRowHeight then
|
|
Result := DefaultRowHeight;
|
|
end
|
|
else
|
|
Result := DefaultRowHeight;
|
|
end;
|
|
|
|
function TdxInspectorRow.IsCaptionStored: Boolean;
|
|
begin
|
|
Result := (rvCaption in FAssignedValues) and
|
|
(FCaption <> DefaultCaption);
|
|
end;
|
|
|
|
function TdxInspectorRow.IsMaxLengthStored: Boolean;
|
|
begin
|
|
Result := (rvMaxLength in FAssignedValues);
|
|
end;
|
|
|
|
function TdxInspectorRow.IsReadOnlyStored: Boolean;
|
|
begin
|
|
Result := (rvReadOnly in FAssignedValues) and
|
|
(FReadOnly <> DefaultReadOnly);
|
|
end;
|
|
|
|
function TdxInspectorRow.IsRowHeightStored: Boolean;
|
|
begin
|
|
Result := rvRowHeight in FAssignedValues;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetAlignment(Value: TAlignment);
|
|
begin
|
|
if Value <> FAlignment then
|
|
begin
|
|
FAlignment := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetCaption(const Value: string);
|
|
begin
|
|
if (rvCaption in FAssignedValues) and
|
|
(Value = FCaption) then Exit;
|
|
FCaption := Value;
|
|
Include(FAssignedValues, rvCaption);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetCharCase(Value: TEditCharCase);
|
|
begin
|
|
if FCharCase <> Value then
|
|
begin
|
|
FCharCase := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetPasswordChar(Value: Char);
|
|
begin
|
|
if FPasswordChar <> Value then
|
|
begin
|
|
FPasswordChar := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetImageIndex(Value: TImageIndex);
|
|
begin
|
|
if FImageIndex <> Value then
|
|
begin
|
|
FImageIndex := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetIsCategory(Value: Boolean);
|
|
begin
|
|
if FIsCategory <> Value then
|
|
begin
|
|
FIsCategory := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetMaxLength(Value: Integer);
|
|
begin
|
|
if (rvMaxLength in FAssignedValues) and
|
|
(Value = FMaxLength) then Exit;
|
|
FMaxLength := Value;
|
|
Include(FAssignedValues, rvMaxLength);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetReadOnly(Value: Boolean);
|
|
begin
|
|
if (rvReadOnly in FAssignedValues) and
|
|
(Value = FReadOnly) then Exit;
|
|
FReadOnly := Value;
|
|
Include(FAssignedValues, rvReadOnly);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetRowHeight(Value: Integer);
|
|
begin
|
|
FRowHeight := Value;
|
|
if FRowHeight <= DefaultRowHeight then
|
|
begin
|
|
FRowHeight := DefaultRowHeight;
|
|
Exclude(FAssignedValues, rvRowHeight);
|
|
end
|
|
else
|
|
Include(FAssignedValues, rvRowHeight);
|
|
Changed;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetVisible(Value: Boolean);
|
|
begin
|
|
if FVisible <> Value then
|
|
begin
|
|
FVisible := Value;
|
|
if FVisible then
|
|
Show
|
|
else
|
|
Hide;
|
|
if Inspector <> nil then
|
|
begin
|
|
Inspector.UpdateCustomizeForm;
|
|
Inspector.UpdateDesignEditor;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRow.SetInspector(AInspector: TCustomdxInspectorControl);
|
|
begin
|
|
if AInspector <> Inspector then
|
|
begin
|
|
if Inspector <> nil then Inspector.RemoveRow(Self);
|
|
if AInspector <> nil then AInspector.AddRow(Self);
|
|
end;
|
|
end;
|
|
|
|
{ TdxInspectorRowNode }
|
|
|
|
destructor TdxInspectorRowNode.Destroy;
|
|
var R : TdxInspectorRow;
|
|
begin
|
|
if (Row <> nil) then
|
|
begin
|
|
R := Row;
|
|
Row.FNode := nil;
|
|
R.Free;
|
|
end;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TdxInspectorRowNode.AddChildEx(RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
var
|
|
PrevRowClass: TdxInspectorRowClass;
|
|
begin
|
|
with TCustomdxInspectorControl(Owner) do
|
|
begin
|
|
PrevRowClass := DefaultRowClass;
|
|
DefaultRowClass := RowClass;
|
|
try
|
|
Result := TdxInspectorRowNode(AddChild);
|
|
finally
|
|
DefaultRowClass := PrevRowClass;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorRowNode.InsertChildEx(BeforeNode: TdxInspectorNode;
|
|
RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
var
|
|
PrevRowClass: TdxInspectorRowClass;
|
|
begin
|
|
with TCustomdxInspectorControl(Owner) do
|
|
begin
|
|
PrevRowClass := DefaultRowClass;
|
|
DefaultRowClass := RowClass;
|
|
try
|
|
Result := TdxInspectorRowNode(InsertChild(BeforeNode));
|
|
finally
|
|
DefaultRowClass := PrevRowClass;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorRowNode.WriteData(AStream: TStream);
|
|
var
|
|
I, AItemCount, ASize: Integer;
|
|
PInfo: PdxInspectorRowNodeInfo;
|
|
S: string;
|
|
begin
|
|
ASize := SizeOf(TdxInspectorRowNodeInfo);
|
|
GetMem(PInfo, ASize);
|
|
try
|
|
AItemCount := Count;
|
|
if Row <> nil then
|
|
S := Row.Name
|
|
else
|
|
S := '';
|
|
PInfo^.Count := AItemCount;
|
|
PInfo^.StrLen := Length(S);
|
|
AStream.WriteBuffer(ASize, SizeOf(ASize));
|
|
AStream.WriteBuffer(PInfo^, ASize);
|
|
if PInfo^.StrLen <> 0 then
|
|
AStream.WriteBuffer(S[1], PInfo^.StrLen);
|
|
finally
|
|
FreeMem(PInfo, ASize);
|
|
end;
|
|
for I := 0 to AItemCount - 1 do
|
|
TdxInspectorRowNode(Items[I]).WriteData(AStream);
|
|
end;
|
|
|
|
{ TCustomdxInspectorControl }
|
|
|
|
constructor TCustomdxInspectorControl.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FRows := TList.Create;
|
|
FEditors := TList.Create;
|
|
FEditValue := Null;
|
|
end;
|
|
|
|
destructor TCustomdxInspectorControl.Destroy;
|
|
begin
|
|
try
|
|
DoSaveLayout;
|
|
finally
|
|
Destroying;
|
|
FreeStreamData;
|
|
if FDesigner <> nil then FDesigner.Free;
|
|
if Assigned(FRows) then DestroyRows;
|
|
FRows.Free;
|
|
FRows := nil;
|
|
FEditors.Free;
|
|
FEditors := nil;
|
|
if FEditFont <> nil then FEditFont.Free;
|
|
FEditFont := nil;
|
|
inherited Destroy;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.AssignRows(InspectorControl: TCustomdxInspectorControl);
|
|
var
|
|
I: Integer;
|
|
Row: TdxInspectorRow;
|
|
begin
|
|
if InspectorControl <> nil then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
DestroyRows;
|
|
for I := 0 to InspectorControl.TotalRowCount - 1 do
|
|
begin
|
|
Row := CreateRow(TdxInspectorRowClass(InspectorControl.Rows[I].ClassType));
|
|
Row.Name := InspectorControl.Rows[I].Name;
|
|
Row.Assign(InspectorControl.Rows[I]);
|
|
end;
|
|
// order
|
|
SetOrderRows(InspectorControl);
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.ClearRows;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
DestroyRows;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.ComplexRowByRow(ARow: TdxInspectorRow): TdxInspectorComplexRow;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := nil;
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if (Rows[I] is TdxInspectorComplexRow) and
|
|
(TdxInspectorComplexRow(Rows[I]).Items.IndexOfRow(ARow) <> -1) then
|
|
begin
|
|
Result := Rows[I] as TdxInspectorComplexRow;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CreateDefaultRow(RowClass: TdxInspectorRowClass): TdxInspectorRow;
|
|
begin
|
|
Result := RowClass.Create(Self);
|
|
Result.Inspector := Self;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CreateRow(RowClass: TdxInspectorRowClass): TdxInspectorRow;
|
|
var
|
|
i : Integer;
|
|
begin
|
|
Result := RowClass.Create(Self.Owner);
|
|
i := TotalRowCount + 1;
|
|
while i <> -1 do
|
|
try
|
|
Result.Name := Name + 'Row' + IntToStr(i);
|
|
i := -1;
|
|
except
|
|
Inc(i);
|
|
end;
|
|
Result.Inspector := Self;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.IndexOfRow(ARow: TdxInspectorRow): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := -1;
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if Rows[I] = ARow then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.RestoreRowsDefaults;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
for I := 0 to TotalRowCount - 1 do
|
|
Rows[I].RestoreDefaults;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.RowByName(const AName : String) : TdxInspectorRow;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := nil;
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if AnsiCompareText(Rows[I].Name, AName) = 0 then
|
|
begin
|
|
Result := Rows[I];
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.RowInComplexRow(ARow: TdxInspectorRow): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := False;
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if (Rows[I] is TdxInspectorComplexRow) and
|
|
(TdxInspectorComplexRow(Rows[I]).Items.IndexOfRow(ARow) <> -1) then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.AddEx(RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
var
|
|
PrevRowClass: TdxInspectorRowClass;
|
|
begin
|
|
PrevRowClass := DefaultRowClass;
|
|
DefaultRowClass := RowClass;
|
|
try
|
|
Result := TdxInspectorRowNode(Add);
|
|
finally
|
|
DefaultRowClass := PrevRowClass;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.InsertEx(BeforeNode: TdxInspectorNode;
|
|
RowClass: TdxInspectorRowClass): TdxInspectorRowNode;
|
|
var
|
|
PrevRowClass: TdxInspectorRowClass;
|
|
begin
|
|
PrevRowClass := DefaultRowClass;
|
|
DefaultRowClass := RowClass;
|
|
try
|
|
Result := TdxInspectorRowNode(Insert(BeforeNode));
|
|
finally
|
|
DefaultRowClass := PrevRowClass;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.LoadNodesFromStream(AStream: TStream);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if not RowInComplexRow(Rows[I]) then
|
|
Rows[I].Visible := True;
|
|
ReadData(AStream);
|
|
LoadOrderRows;
|
|
FreeStreamData;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.SaveNodesToStream(AStream: TStream);
|
|
begin
|
|
WriteData(AStream);
|
|
end;
|
|
|
|
// protected TCustomdxInspectorControl
|
|
procedure TCustomdxInspectorControl.DefineProperties(Filer: TFiler);
|
|
begin
|
|
inherited DefineProperties(Filer);
|
|
Filer.DefineBinaryProperty('Data', ReadData, WriteData,
|
|
(Count > 0) and SaveNodes);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoEndDrag(Target: TObject; X, Y: Integer);
|
|
begin
|
|
inherited DoEndDrag(Target, X, Y);
|
|
FDragRow := nil;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.GetChildren(Proc: TGetChildProc{$IFDEF DELPHI3}; Root: TComponent{$ENDIF});
|
|
var
|
|
I: Integer;
|
|
Row: TdxInspectorRow;
|
|
begin
|
|
for I := 0 to FRows.Count - 1 do
|
|
begin
|
|
Row := FRows[I];
|
|
if Row.Owner {$IFNDEF DELPHI3}<> Self{$ELSE}= Root {$ENDIF} then Proc(Row);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.Loaded;
|
|
begin
|
|
BeginUpdate;
|
|
FLoading := True;
|
|
try
|
|
inherited Loaded;
|
|
// TODO : restore proc
|
|
Inc(FLockExpanded);
|
|
try
|
|
LoadOrderRows;
|
|
finally
|
|
Dec(FLockExpanded);
|
|
end;
|
|
DoRestoreLayout;
|
|
FreeStreamData;
|
|
CheckHiddenRows;
|
|
if TopNode <> nil then
|
|
begin
|
|
TopNode.Focused := True;
|
|
TopNode.MakeVisible;
|
|
end;
|
|
finally
|
|
EndUpdate;
|
|
FLoading := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.SetChildOrder(Component: TComponent; Order: Integer);
|
|
begin
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.SetName(const Value: TComponentName);
|
|
var
|
|
I: Integer;
|
|
OldName, FieldName, NamePrefix: TComponentName;
|
|
Row: TdxInspectorRow;
|
|
OldChangeEvent : TNotifyEvent;
|
|
begin
|
|
OldName := Name;
|
|
inherited SetName(Value);
|
|
if (csDesigning in ComponentState) and (Name <> OldName) then
|
|
begin
|
|
{ In design mode the name of the columns should track the data set name }
|
|
for I := 0 to FRows.Count - 1 do
|
|
begin
|
|
Row := Rows[I];
|
|
if Row.Owner = Owner then
|
|
begin
|
|
FieldName := Row.Name;
|
|
NamePrefix := FieldName;
|
|
if Length(NamePrefix) > Length(OldName) then
|
|
begin
|
|
SetLength(NamePrefix, Length(OldName));
|
|
if CompareText(OldName, NamePrefix) = 0 then
|
|
begin
|
|
System.Delete(FieldName, 1, Length(OldName));
|
|
System.Insert(Value, FieldName, 1);
|
|
OldChangeEvent := Row.OnChangeName;
|
|
Row.OnChangeName := Nil;
|
|
try
|
|
Row.Name := FieldName;
|
|
except
|
|
on EComponentError do {Ignore rename errors };
|
|
end;
|
|
Row.OnChangeName := OldChangeEvent;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
UpdateDesignEditor;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.AddNode(Node: TdxInspectorNode);
|
|
begin
|
|
if not FAddFlag then
|
|
begin
|
|
// add row
|
|
FAddFlag := True;
|
|
try
|
|
if Assigned(FDefaultRowClass) then
|
|
TdxInspectorRowNode(Node).FRow := CreateRow(FDefaultRowClass)
|
|
else TdxInspectorRowNode(Node).FRow := CreateRow(GetDefaultRowClass);
|
|
TdxInspectorRowNode(Node).FRow.FNode := TdxInspectorRowNode(Node);
|
|
finally
|
|
FAddFlag := False;
|
|
end;
|
|
end;
|
|
inherited AddNode(Node);
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CalcMinRowHeight(ACanvas: TCanvas): Integer;
|
|
var
|
|
I, H: Integer;
|
|
begin
|
|
Result := inherited CalcMinRowHeight(ACanvas);
|
|
for I := 0 to VisibleTotalRowCount - 1 do
|
|
begin
|
|
H := Rows[I].GetMinRowHeight(ACanvas);
|
|
if H > Result then
|
|
Result := H;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CalcRowHeight(ACanvas: TCanvas; const ARect: TRect;
|
|
ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorRow): Integer;
|
|
var
|
|
AViewInfo: TdxEditViewInfo;
|
|
ALineCount, ALineHeight: Integer;
|
|
begin
|
|
Result := RowHeight;
|
|
with ARow do
|
|
begin
|
|
PrepareViewData(ViewData, ACellViewData);
|
|
CalcCellViewBoundsRect(ARect, ViewData.ViewBounds);
|
|
GetdxInplaceEditClass.CalcViewInfo(ViewData, False, AViewInfo);
|
|
ViewData.CalcHeight := True;
|
|
try
|
|
ViewData.LineCount := 0;
|
|
if GetdxInplaceEditClass.DrawClientArea(ACanvas.Handle, AViewInfo.ClientBounds, ViewData, False) then
|
|
begin
|
|
ALineHeight := ViewData.LineHeight;
|
|
ALineCount := ViewData.LineCount;
|
|
if (MaxRowTextLineCount > 0) and (ALineCount > MaxRowTextLineCount) then
|
|
begin
|
|
ALineCount := MaxRowTextLineCount;
|
|
ALineHeight := ALineCount * ViewData.LineTextHeight;
|
|
end;
|
|
Result := ALineHeight + 3 + GridSize;
|
|
if not IsCategoryNode(ARow.Node) then
|
|
Result := Result + FRowFrameSize * 2; // TODO: !!!
|
|
if Result < RowHeight then
|
|
Result := RowHeight;
|
|
end;
|
|
finally
|
|
ViewData.CalcHeight := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CalcComplexRowHeight(ACanvas: TCanvas; const ARect: TRect;
|
|
ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorComplexRow): Integer;
|
|
var
|
|
AViewInfo: TdxInspectorComplexRowViewInfo;
|
|
I, AMaxHeight, AHeight: Integer;
|
|
begin
|
|
AMaxHeight := RowHeight;
|
|
AViewInfo := TdxInspectorComplexRowViewInfo.Create(ARow, FComplexRowSeparatorWidth);
|
|
try
|
|
AViewInfo.Calculate(ARect);
|
|
if not AViewInfo.Empty then
|
|
for I := 0 to AViewInfo.Count - 1 do
|
|
begin
|
|
if not AViewInfo[I].Separator then
|
|
begin
|
|
if AViewInfo[I].Row <> nil then
|
|
begin
|
|
ACellViewData.Cell_Text := AViewInfo[I].Row.DisplayText;
|
|
AHeight := CalcRowHeight(ACanvas, AViewInfo[I].Bounds, ACellViewData, AViewInfo[I].Row);
|
|
if AHeight > AMaxHeight then
|
|
AMaxHeight := AHeight;
|
|
end;
|
|
end;
|
|
end;
|
|
finally
|
|
AViewInfo.Free;
|
|
end;
|
|
Result := AMaxHeight;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CalcRowAutoHeight(ARow: TdxInspectorRow): Integer;
|
|
var
|
|
ANode: TdxInspectorRowNode;
|
|
AWidth: Integer;
|
|
ACaptionText, ADisplayText: string;
|
|
ARect: TRect;
|
|
ACanvas: TCanvas;
|
|
ADrawInfo: TdxInspectorDrawInfo;
|
|
begin
|
|
// View Info
|
|
ANode := ARow.Node;
|
|
if IsAutoBandCount then
|
|
AWidth := BandWidth - BandSeparatorWidth
|
|
else
|
|
AWidth := ClientWidth;
|
|
ARect := Rect(0, 0, AWidth, FTextHeight);
|
|
CalcDrawInfo(ANode, ARect, ADrawInfo);
|
|
ARect := ADrawInfo.ValueRect;
|
|
ACaptionText := '';
|
|
ADisplayText := '';
|
|
GetNodeText(ANode, ACaptionText, ADisplayText);
|
|
ACanvas := Canvas;
|
|
ACanvas.Font := Self.Font;
|
|
with FCellViewData do
|
|
begin
|
|
Cell_Brush := ACanvas.Brush.Handle;
|
|
Cell_Font := ACanvas.Font.Handle;
|
|
Cell_BkColor := ACanvas.Brush.Color;
|
|
Cell_TextColor := ACanvas.Font.Color;
|
|
Cell_Alignment := taLeftJustify;
|
|
Cell_Text := ADisplayText;
|
|
Cell_TextLength := 0; // full length
|
|
Cell_Selected := False;
|
|
Cell_DrawEndEllipsis := ioDrawEndEllipsis in Options;
|
|
Cell_Node := ANode;
|
|
Cell_HotTrackNode := IsHotTrackNode(ANode);
|
|
with ARect do
|
|
Cell_Rect := Rect(0, 0, Right - Left, Bottom - Top);
|
|
InflateRect(Cell_Rect, 2, 2); // TODO PAINT2
|
|
end;
|
|
if IsComplexNode(ANode) then
|
|
Result := CalcComplexRowHeight(ACanvas, ARect, FCellViewData, ARow as TdxInspectorComplexRow)
|
|
else
|
|
Result := CalcRowHeight(ACanvas, ARect, FCellViewData, ARow);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.CheckComplexRowIndex(var AComplexRowIndex: Integer);
|
|
var
|
|
AComplexRow: TdxInspectorComplexRow;
|
|
begin
|
|
if (FocusedNode <> nil) and IsComplexNode(FocusedNode) then
|
|
begin
|
|
AComplexRow := TdxInspectorRowNode(FocusedNode).Row as TdxInspectorComplexRow;
|
|
if AComplexRowIndex < 0 then
|
|
AComplexRowIndex := 0;
|
|
if AComplexRowIndex >= AComplexRow.Items.Count then
|
|
AComplexRowIndex := AComplexRow.Items.Count - 1;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.ClearComplexRows(ARow: TdxInspectorRow);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if Rows[I] is TdxInspectorComplexRow then
|
|
TdxInspectorComplexRow(Rows[I]).RemoveNotification(ARow);
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CreateNode: TdxInspectorNode;
|
|
begin
|
|
Result := TdxInspectorRowNode.Create(Self);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DestroyRows;
|
|
var
|
|
Row: TdxInspectorRow;
|
|
begin
|
|
while FRows.Count > 0 do
|
|
begin
|
|
Row := FRows.Last;
|
|
RemoveRow(Row);
|
|
Row.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DefaultDrawCell(ACanvas: TCanvas; const ARect: TRect;
|
|
ACellViewData: TdxInspectorCellViewData);
|
|
var
|
|
ARow: TdxInspectorRow;
|
|
begin
|
|
ARow := TdxInspectorRowNode(ACellViewData.Cell_Node).Row;
|
|
if IsComplexNode(ACellViewData.Cell_Node) then
|
|
DrawComplexRowValue(ACanvas, ARect, ACellViewData, ARow as TdxInspectorComplexRow)
|
|
else
|
|
DrawValue(ACanvas, ARect, ACellViewData, ARow);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DragDropTo(var ANode: TdxInspectorNode;
|
|
ADestinationNode: TdxInspectorNode; AAttachMode: TdxInspectorNodeAttachMode);
|
|
begin
|
|
if FDragRow <> nil then
|
|
begin
|
|
FDragRow.Visible := True;
|
|
ANode := FDragRow.Node;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DrawCaption(ACanvas: TCanvas; ANode: TdxInspectorNode;
|
|
const ADisplayRect: TRect; const AText: string);
|
|
begin
|
|
if (ANode <> nil) and IsComplexNode(ANode) then
|
|
DrawComplexRowCaption(ACanvas, ADisplayRect, TdxInspectorRowNode(ANode).Row as TdxInspectorComplexRow)
|
|
else
|
|
inherited;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DrawComplexRowCaption(ACanvas: TCanvas; const ADisplayRect: TRect;
|
|
ARow: TdxInspectorComplexRow);
|
|
var
|
|
AViewInfo: TdxInspectorComplexRowViewInfo;
|
|
I: Integer;
|
|
ADisplayText: string;
|
|
begin
|
|
AViewInfo := TdxInspectorComplexRowViewInfo.Create(ARow, FCaptionComplexRowSeparatorWidth);
|
|
try
|
|
AViewInfo.Calculate(ADisplayRect);
|
|
if AViewInfo.Empty then
|
|
DrawDisplayText(ACanvas, ADisplayRect, ARow.Caption, taLeftJustify)
|
|
else
|
|
for I := 0 to AViewInfo.Count - 1 do
|
|
begin
|
|
if AViewInfo[I].Separator then
|
|
begin
|
|
if ComplexRowSeparator = '' then
|
|
DrawComplexRowSeparator(ACanvas, AViewInfo[I].Bounds, True)
|
|
else
|
|
DrawDisplayText(ACanvas, AViewInfo[I].Bounds, ComplexRowSeparator, taCenter);
|
|
end
|
|
else
|
|
begin
|
|
if AViewInfo[I].Row <> nil then
|
|
ADisplayText := AViewInfo[I].Row.Caption
|
|
else
|
|
ADisplayText := '';
|
|
DrawDisplayText(ACanvas, AViewInfo[I].Bounds, ADisplayText, taLeftJustify);
|
|
end;
|
|
end;
|
|
finally
|
|
AViewInfo.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DrawComplexRowValue(ACanvas: TCanvas; const ARect: TRect;
|
|
ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorComplexRow);
|
|
var
|
|
AViewInfo: TdxInspectorComplexRowViewInfo;
|
|
I: Integer;
|
|
begin
|
|
AViewInfo := TdxInspectorComplexRowViewInfo.Create(ARow, FComplexRowSeparatorWidth);
|
|
try
|
|
AViewInfo.Calculate(ARect);
|
|
if AViewInfo.Empty then
|
|
DrawDisplayText(ACanvas, ARect, '', taLeftJustify)
|
|
else
|
|
for I := 0 to AViewInfo.Count - 1 do
|
|
begin
|
|
if AViewInfo[I].Separator then
|
|
begin
|
|
if ComplexRowSeparator = '' then
|
|
DrawComplexRowSeparator(ACanvas, AViewInfo[I].Bounds, False)
|
|
else
|
|
DrawDisplayText(ACanvas, AViewInfo[I].Bounds, ComplexRowSeparator, taCenter);
|
|
end
|
|
else
|
|
begin
|
|
if AViewInfo[I].Row <> nil then
|
|
begin
|
|
ACellViewData.Cell_Text := AViewInfo[I].Row.DisplayText;
|
|
DrawValue(ACanvas, AViewInfo[I].Bounds, ACellViewData, AViewInfo[I].Row);
|
|
end
|
|
else
|
|
DrawDisplayText(ACanvas, AViewInfo[I].Bounds, '', taLeftJustify);
|
|
end;
|
|
end;
|
|
finally
|
|
AViewInfo.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DrawValue(ACanvas: TCanvas; const ARect: TRect;
|
|
ACellViewData: TdxInspectorCellViewData; ARow: TdxInspectorRow);
|
|
begin
|
|
with ARow do
|
|
begin
|
|
PrepareViewData(ViewData, ACellViewData);
|
|
CalcCellViewBoundsRect(ARect, ViewData.ViewBounds);
|
|
GetdxInplaceEditClass.Draw(ACanvas.Handle, ARect, ViewData, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoDrawCaption(ACanvas:TCanvas; ANode: TdxInspectorNode;
|
|
AIndentRect, AButtonRect, AImageRect: TRect; AButtonKind: TdxInspectorButtonKind;
|
|
ADisplayRect: TRect; var AText: string);
|
|
var
|
|
ADone: Boolean;
|
|
AColor: TColor;
|
|
begin
|
|
ADone := False;
|
|
if (ANode <> nil) and (TdxInspectorRowNode(ANode).Row <> nil) then
|
|
begin
|
|
if Assigned(FOnDrawCaption) then
|
|
begin
|
|
AColor := ACanvas.Brush.Color;
|
|
FOnDrawCaption(TdxInspectorRowNode(ANode).Row, ACanvas, ADisplayRect, AText, ACanvas.Font, AColor, ADone);
|
|
ACanvas.Brush.Color := AColor;
|
|
end;
|
|
if not ADone then
|
|
TdxInspectorRowNode(ANode).Row.DoDrawCaption(ACanvas, AIndentRect, AButtonRect, AImageRect,
|
|
AButtonKind, ADisplayRect, AText, ADone);
|
|
end;
|
|
if not ADone then
|
|
inherited DoDrawCaption(ACanvas, ANode,
|
|
AIndentRect, AButtonRect, AImageRect, AButtonKind, ADisplayRect, AText);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoDrawValue(ACanvas:TCanvas; ARect : TRect; ANode: TdxInspectorNode;
|
|
var AText: string; var AAlignment: TAlignment);
|
|
var
|
|
ADone: Boolean;
|
|
AColor: TColor;
|
|
ARow: TdxInspectorRow;
|
|
begin
|
|
ADone := False;
|
|
if (ANode <> nil) then
|
|
begin
|
|
ARow := TdxInspectorRowNode(ANode).Row;
|
|
if ARow <> nil then
|
|
begin
|
|
AAlignment := ARow.Alignment;
|
|
if Assigned(FOnDrawValue) then
|
|
begin
|
|
AColor := ACanvas.Brush.Color;
|
|
FOnDrawValue(ARow, ACanvas, ARect, AText, ACanvas.Font, AColor, ADone);
|
|
ACanvas.Brush.Color := AColor;
|
|
end;
|
|
if not ADone then
|
|
ARow.DoDrawValue(ACanvas, ARect, AText, ADone);
|
|
end;
|
|
end;
|
|
if not ADone then
|
|
inherited DoDrawValue(ACanvas, ARect, ANode, AText, AAlignment);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoEditChange(Sender: TObject);
|
|
begin
|
|
if Assigned(FOnEditChange) then FOnEditChange(Sender);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoEditValidate(Sender: TObject; var ErrorText: string; var Accept: Boolean);
|
|
begin
|
|
if Assigned(FOnEditValidate) then FOnEditValidate(Sender, ErrorText, Accept);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoInternalLayout;
|
|
begin
|
|
inherited DoInternalLayout;
|
|
InvalidateEditor;
|
|
if Designer <> nil then Designer.LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoRestoreLayout;
|
|
begin
|
|
if (ioStoreToRegistry in Options) and not (csDesigning in ComponentState) and
|
|
(RegistryPath <> '') then LoadFromRegistry(RegistryPath);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.DoSaveLayout;
|
|
begin
|
|
if (ioStoreToRegistry in Options) and not (csDesigning in ComponentState) and
|
|
(RegistryPath <> '') then SaveToRegistry(RegistryPath);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.GetComplexRowInfoAt(ANode: TdxInspectorNode; const ARect: TRect;
|
|
const APos: TPoint; var ComplexRowIndex: Integer; var ComplexRowRect: TRect);
|
|
var
|
|
ARow: TdxInspectorComplexRow;
|
|
AViewInfo: TdxInspectorComplexRowViewInfo;
|
|
I: Integer;
|
|
begin
|
|
inherited GetComplexRowInfoAt(ANode, ARect, APos, ComplexRowIndex, ComplexRowRect);
|
|
if IsComplexNode(ANode) and PtInRect(ARect, APos) then
|
|
begin
|
|
ARow := TdxInspectorRowNode(ANode).Row as TdxInspectorComplexRow;
|
|
AViewInfo := TdxInspectorComplexRowViewInfo.Create(ARow, FComplexRowSeparatorWidth);
|
|
try
|
|
AViewInfo.Calculate(ARect);
|
|
for I := 0 to AViewInfo.Count - 1 do
|
|
if PtInRect(AViewInfo[I].Bounds, APos) then
|
|
begin
|
|
if AViewInfo[I].Separator then
|
|
ComplexRowRect := AViewInfo[I - 1].Bounds
|
|
else
|
|
begin
|
|
ComplexRowIndex := I div 2;
|
|
ComplexRowRect := AViewInfo[I].Bounds;
|
|
end;
|
|
Break;
|
|
end;
|
|
finally
|
|
AViewInfo.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetDefaultRowClass: TdxInspectorRowClass;
|
|
begin
|
|
Result := TdxInspectorRow;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetDragNodeText(ADragNode: TdxInspectorNode): string;
|
|
begin
|
|
if (ADragNode = nil) and (FDragRow <> nil) then
|
|
begin
|
|
// Result := FDragRow.Caption;
|
|
Result := GetRowDragCaption(FDragRow);
|
|
end
|
|
else
|
|
begin
|
|
if (ADragNode <> nil) and IsComplexNode(ADragNode) then
|
|
Result := GetRowDragCaption(TdxInspectorRowNode(ADragNode).Row)
|
|
else
|
|
Result := inherited GetDragNodeText(ADragNode);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetEditRect(ANode: TdxInspectorNode): TRect;
|
|
var
|
|
AComplexRow: TdxInspectorComplexRow;
|
|
AViewInfo: TdxInspectorComplexRowViewInfo;
|
|
I: Integer;
|
|
begin
|
|
Result := inherited GetEditRect(ANode); // CellRect
|
|
if IsComplexNode(ANode) then
|
|
begin
|
|
AComplexRow := TdxInspectorRowNode(ANode).Row as TdxInspectorComplexRow;
|
|
AViewInfo := TdxInspectorComplexRowViewInfo.Create(AComplexRow, FComplexRowSeparatorWidth);
|
|
try
|
|
AViewInfo.Calculate(Result);
|
|
for I := 0 to AViewInfo.Count - 1 do
|
|
if GetInplaceEditRow(ANode) = AViewInfo[I].Row then
|
|
begin
|
|
Result := AViewInfo[I].Bounds;
|
|
Break;
|
|
end;
|
|
finally
|
|
AViewInfo.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetImageIndex(Node: TdxInspectorNode): Integer;
|
|
begin
|
|
Result := TdxInspectorRowNode(Node).Row.ImageIndex;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetNodeHeight(ANode: TdxInspectorNode): Integer;
|
|
begin
|
|
if Assigned(ANode) and Assigned(TdxInspectorRowNode(ANode).Row) then
|
|
Result := GetRowHeight(TdxInspectorRowNode(ANode).Row)
|
|
else
|
|
Result := inherited GetNodeHeight(ANode);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.GetNodeText(Node: TdxInspectorNode; var CaptionText, DisplayText: String);
|
|
begin
|
|
CaptionText := TdxInspectorRowNode(Node).Row.Caption;
|
|
DisplayText := TdxInspectorRowNode(Node).Row.DisplayText;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetRowDragCaption(ARow: TdxInspectorRow): string;
|
|
var
|
|
I: Integer;
|
|
S: string;
|
|
begin
|
|
Result := ARow.Caption;
|
|
S := ComplexRowSeparator;
|
|
if S = '' then
|
|
S := '-';
|
|
if (Result = '') and (ARow is TdxInspectorComplexRow) then
|
|
with ARow as TdxInspectorComplexRow do
|
|
for I := 0 to Items.Count - 1 do
|
|
begin
|
|
if Items[I].Row <> nil then
|
|
begin
|
|
if I > 0 then
|
|
Result := Result + S;
|
|
Result := Result + Items[I].Row.Caption;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetRowHeight(ARow: TdxInspectorRow): Integer;
|
|
begin
|
|
// TODO: row auto height only for memo?
|
|
if IsRowAutoHeight and not (rvRowHeight in ARow.AssignedValues) then
|
|
Result := CalcRowAutoHeight(ARow)
|
|
else
|
|
Result := ARow.RowHeight;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.IsCategoryNode(Node: TdxInspectorNode): Boolean;
|
|
begin
|
|
if (Node <> nil) and (TdxInspectorRowNode(Node).Row <> nil) then
|
|
Result := TdxInspectorRowNode(Node).Row.IsCategory
|
|
else Result := inherited IsCategoryNode(Node);
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GoTabComplexRow(AForward: Boolean): Boolean;
|
|
var
|
|
AComplexRow: TdxInspectorComplexRow;
|
|
APrevInplaceComplexRowIndex: Integer;
|
|
begin
|
|
Result := False;
|
|
if (FocusedNode <> nil) and IsComplexNode(FocusedNode) then
|
|
begin
|
|
AComplexRow := TdxInspectorRowNode(FocusedNode).Row as TdxInspectorComplexRow;
|
|
if AComplexRow.Items.Count > 1 then
|
|
begin
|
|
APrevInplaceComplexRowIndex := InplaceComplexRowIndex;
|
|
if AForward then
|
|
InplaceComplexRowIndex := InplaceComplexRowIndex + 1
|
|
else
|
|
InplaceComplexRowIndex := InplaceComplexRowIndex - 1;
|
|
if APrevInplaceComplexRowIndex <> InplaceComplexRowIndex then
|
|
Result := True
|
|
else
|
|
if AForward then
|
|
begin
|
|
if FocusedNode <> LastNode then
|
|
InplaceComplexRowIndex := 0;
|
|
end
|
|
else
|
|
begin
|
|
if FocusedNode <> TopNode then
|
|
InplaceComplexRowIndex := AComplexRow.Items.Count - 1;
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if AForward then
|
|
InplaceComplexRowIndex := 0
|
|
else
|
|
InplaceComplexRowIndex := $7FFFFFFF;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.IsComplexNode(ANode: TdxInspectorNode): Boolean;
|
|
begin
|
|
Result := (ANode <> nil) and not IsCategoryNode(ANode) and
|
|
(TdxInspectorRowNode(ANode).Row is TdxInspectorComplexRow);
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.IsGoTabComplexRowAvailable(AForward: Boolean): Boolean;
|
|
var
|
|
AComplexRow: TdxInspectorComplexRow;
|
|
AInplaceComplexRowIndex, APrevInplaceComplexRowIndex: Integer;
|
|
begin
|
|
Result := False;
|
|
if (FocusedNode <> nil) and IsComplexNode(FocusedNode) then
|
|
begin
|
|
AComplexRow := TdxInspectorRowNode(FocusedNode).Row as TdxInspectorComplexRow;
|
|
if AComplexRow.Items.Count > 1 then
|
|
begin
|
|
APrevInplaceComplexRowIndex := InplaceComplexRowIndex;
|
|
if AForward then
|
|
AInplaceComplexRowIndex := InplaceComplexRowIndex + 1
|
|
else
|
|
AInplaceComplexRowIndex := InplaceComplexRowIndex - 1;
|
|
CheckComplexRowIndex(AInplaceComplexRowIndex);
|
|
if APrevInplaceComplexRowIndex <> AInplaceComplexRowIndex then
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.IsShowHintNode(ANode: TdxInspectorNode; AComplexRowIndex: Integer;
|
|
const AComplexRowRect: TRect; IsValue: Boolean; const R: TRect; var AText: string;
|
|
var X: Integer; var IsRowHint: Boolean): Boolean;
|
|
var
|
|
ARow: TdxInspectorRow;
|
|
ARect: TRect;
|
|
begin
|
|
Result := False;
|
|
IsRowHint := False;
|
|
if ANode <> nil then
|
|
begin
|
|
if IsComplexNode(ANode) then
|
|
begin
|
|
ARect := AComplexRowRect;
|
|
ARow := RowByComplexRowIndex(ANode, AComplexRowIndex);
|
|
end
|
|
else
|
|
begin
|
|
ARow := TdxInspectorRowNode(ANode).Row;
|
|
ARect := R;
|
|
end;
|
|
if (ARow <> nil) and not IsRectEmpty(ARect) then
|
|
begin
|
|
X := ARect.Left - 1;
|
|
if not IsValue then Dec(X);
|
|
Inc(ARect.Left, 2);
|
|
if not IsValue and ARow.ShowHint and (ARow.Hint <> '') then
|
|
begin
|
|
AText := ARow.Hint;
|
|
IsRowHint := True;
|
|
Result := True;
|
|
end
|
|
else
|
|
begin
|
|
if IsValue then
|
|
Dec(ARect.Right);
|
|
Result := ARow.IsShowHint(IsValue, ARect, AText);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.RowByComplexRowIndex(ANode: TdxInspectorNode;
|
|
AComplexRowIndex: Integer): TdxInspectorRow;
|
|
var
|
|
AComplexRow: TdxInspectorComplexRow;
|
|
begin
|
|
AComplexRow := TdxInspectorRowNode(ANode).Row as TdxInspectorComplexRow;
|
|
if (0 <= AComplexRowIndex) and (AComplexRowIndex < AComplexRow.Items.Count) then
|
|
Result := AComplexRow.Items[AComplexRowIndex].Row
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.SetNodeHeight(ANode: TdxInspectorNode; Value: Integer);
|
|
begin
|
|
if Assigned(ANode) then
|
|
TdxInspectorRowNode(ANode).Row.RowHeight := Value;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.SetOrderRows(InspectorControl: TCustomdxInspectorControl);
|
|
|
|
procedure MoveChildren(ExtlNode, CurNode: TdxInspectorRowNode);
|
|
var
|
|
I: Integer;
|
|
Node, ANode: TdxInspectorRowNode;
|
|
Row: TdxInspectorRow;
|
|
begin
|
|
for I := 0 to ExtlNode.Count - 1 do
|
|
begin
|
|
Node := TdxInspectorRowNode(ExtlNode[I]);
|
|
if Node.Row <> nil then
|
|
begin
|
|
Row := RowByName(Node.Row.Name);
|
|
if (Row <> nil) then
|
|
begin
|
|
ANode := Row.Node;
|
|
if ANode <> nil then
|
|
begin
|
|
ANode.MoveTo(CurNode, inaAddChild);
|
|
MoveChildren(Node, ANode);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
Node, ANode: TdxInspectorRowNode;
|
|
Row: TdxInspectorRow;
|
|
begin
|
|
// move to root
|
|
for I := 0 to InspectorControl.Count - 1 do
|
|
begin
|
|
// move to root
|
|
Node := TdxInspectorRowNode(InspectorControl.Items[I]);
|
|
if Node.Row <> nil then
|
|
begin
|
|
Row := RowByName(Node.Row.Name);
|
|
if (Row <> nil) then
|
|
begin
|
|
ANode := Row.Node;
|
|
if ANode <> nil then
|
|
begin
|
|
ANode.MoveTo(Items[0], inaAdd);
|
|
// move children
|
|
MoveChildren(Node, ANode);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.SaveNodes: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.UpdateDesignEditor;
|
|
begin
|
|
if Assigned(FDesigner) then
|
|
FDesigner.LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.UpdateRow(Row: TdxInspectorRow);
|
|
begin
|
|
if csLoading in ComponentState then Exit;
|
|
LayoutChanged;
|
|
// if Designer <> nil then Designer.LayoutChanged;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.ReadSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string);
|
|
|
|
procedure ReadCategories;
|
|
var
|
|
I: Integer;
|
|
ACategories: TStringList;
|
|
ARow: TdxInspectorRow;
|
|
begin
|
|
ACategories := TStringList.Create;
|
|
try
|
|
ARegIniWrapper.ReadSection(APath + '\Categories', ACategories);
|
|
for I := 0 to ACategories.Count - 1 do
|
|
ACategories.Objects[I] := RowByName(ACategories[I]);
|
|
// delete
|
|
for I := TotalRowCount - 1 downto 0 do
|
|
begin
|
|
ARow := Rows[I];
|
|
if ARow.IsCategory and (ACategories.IndexOfObject(ARow) = -1) then
|
|
begin
|
|
ARow.Visible := False;
|
|
ARow.Free;
|
|
end;
|
|
end;
|
|
// create
|
|
for I := 0 to ACategories.Count - 1 do
|
|
if ACategories.Objects[I] = nil then
|
|
begin
|
|
ARow := CreateRow(GetDefaultRowClass);
|
|
ARow.IsCategory := True;
|
|
ARow.Visible := False;
|
|
ARow.Name := ACategories[I];
|
|
ARow.Caption := ARegIniWrapper.ReadString(APath + '\Categories', ARow.Name, ARow.Name);
|
|
end;
|
|
finally
|
|
ACategories.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure ReadNodes;
|
|
var
|
|
AStream: TMemoryStream;
|
|
begin
|
|
AStream := TMemoryStream.Create;
|
|
try
|
|
AStream.SetSize(ARegIniWrapper.ReadBinaryData(APath, 'Nodes', AStream.Memory^, 0));
|
|
ARegIniWrapper.ReadBinaryData(APath, 'Nodes', AStream.Memory^, AStream.Size);
|
|
if AStream.Size <> 0 then
|
|
LoadNodesFromStream(AStream);
|
|
finally
|
|
AStream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRow(const ARowPath: string; ARow: TdxInspectorRow);
|
|
begin
|
|
with ARegIniWrapper do
|
|
begin
|
|
ARow.RowHeight := ReadInteger(ARowPath, 'RowHeight', -1);
|
|
ARow.Visible := ReadBool(ARowPath, 'Visible', ARow.Visible);
|
|
end;
|
|
end;
|
|
|
|
procedure ReadRows;
|
|
var
|
|
I: Integer;
|
|
ARow: TdxInspectorRow;
|
|
ARowPath: string;
|
|
begin
|
|
for I := 0 to TotalRowCount - 1 do
|
|
begin
|
|
ARow := Rows[I];
|
|
ARowPath := APath + '\Rows\' + ARow.Name;
|
|
ReadRow(ARowPath, ARow);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
ReadCategories;
|
|
ReadNodes;
|
|
ReadRows;
|
|
inherited ReadSettings(ARegIniWrapper, APath);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.WriteSettings(ARegIniWrapper: TdxRegIniWrapper; const APath: string);
|
|
|
|
procedure WriteCategories;
|
|
var
|
|
I: Integer;
|
|
ARow: TdxInspectorRow;
|
|
begin
|
|
ARegIniWrapper.EraseSection(APath + '\Categories');
|
|
for I := 0 to TotalRowCount - 1 do
|
|
begin
|
|
ARow := Rows[I];
|
|
if ARow.IsCategory then
|
|
ARegIniWrapper.WriteString(APath + '\Categories', ARow.Name, ARow.Caption);
|
|
end;
|
|
end;
|
|
|
|
procedure WriteNodes;
|
|
var
|
|
AStream: TMemoryStream;
|
|
begin
|
|
AStream := TMemoryStream.Create;
|
|
try
|
|
SaveNodesToStream(AStream);
|
|
ARegIniWrapper.WriteBinaryData(APath, 'Nodes', AStream.Memory^, AStream.Size);
|
|
finally
|
|
AStream.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure WriteRow(const ARowPath: string; ARow: TdxInspectorRow);
|
|
begin
|
|
with ARegIniWrapper do
|
|
begin
|
|
if rvRowHeight in ARow.AssignedValues then
|
|
WriteInteger(ARowPath, 'RowHeight', ARow.RowHeight)
|
|
else
|
|
WriteInteger(ARowPath, 'RowHeight', -1);
|
|
WriteBool(ARowPath, 'Visible', ARow.Visible);
|
|
end;
|
|
end;
|
|
|
|
procedure WriteRows;
|
|
var
|
|
I: Integer;
|
|
ARow: TdxInspectorRow;
|
|
begin
|
|
for I := 0 to TotalRowCount - 1 do
|
|
begin
|
|
ARow := Rows[I];
|
|
WriteRow(APath + '\Rows\' + ARow.Name, ARow);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
inherited WriteSettings(ARegIniWrapper, APath);
|
|
WriteCategories;
|
|
WriteNodes;
|
|
WriteRows;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CanEditShow: Boolean;
|
|
begin
|
|
Result := inherited CanEditShow;
|
|
if Result and (FocusedNode <> nil) then
|
|
begin
|
|
if IsComplexNode(FocusedNode) and (GetInplaceEditRow(FocusedNode) = nil) then
|
|
Result := False
|
|
else
|
|
if Assigned(FOnEditing) then
|
|
FOnEditing(Self, FocusedNode, GetInplaceEditRow(FocusedNode), Result);
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetInplaceEditRow(ANode: TdxInspectorNode): TdxInspectorRow;
|
|
begin
|
|
if IsComplexNode(ANode) then
|
|
Result := RowByComplexRowIndex(ANode, InplaceComplexRowIndex)
|
|
else
|
|
Result := TdxInspectorRowNode(ANode).Row;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.CreateEditor(ANode: TdxInspectorNode): TdxInplaceEdit;
|
|
begin
|
|
Result := GetInplaceEditRow(ANode).GetdxInplaceEditClass.Create(Self);
|
|
FEditors.Add(Result);
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.FindInplaceEdit(ANode: TdxInspectorNode): TdxInplaceEdit;
|
|
var
|
|
I: Integer;
|
|
EClass: TdxInplaceEditClass;
|
|
begin
|
|
Result := nil;
|
|
EClass := GetInplaceEditRow(ANode).GetdxInplaceEditClass;
|
|
for I := 0 to FEditors.Count - 1 do
|
|
if TdxInplaceEdit(FEditors[I]).ClassType = EClass then
|
|
begin
|
|
Result := FEditors[I];
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetEditColor: TColor;
|
|
begin
|
|
Result := inherited GetEditColor;
|
|
if (FocusedNode <> nil) and Assigned(FOnGetEditColor) then
|
|
FOnGetEditColor(TdxInspectorRowNode(FocusedNode).Row, Result);
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetEditFont: TFont;
|
|
begin
|
|
Result := inherited GetEditFont;
|
|
if (FocusedNode <> nil) and Assigned(FOnGetEditFont) then
|
|
begin
|
|
if FEditFont = nil then FEditFont := TFont.Create;
|
|
FEditFont.Assign(Result);
|
|
FOnGetEditFont(TdxInspectorRowNode(FocusedNode).Row, FEditFont);
|
|
Result := FEditFont;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.InvalidateEditor;
|
|
begin
|
|
inherited InvalidateEditor;
|
|
FModified := False;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.AssignEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant;
|
|
var
|
|
ModifiedFlag: Boolean;
|
|
begin
|
|
ModifiedFlag := FModified or AInplaceEdit.Modified;
|
|
if ModifiedFlag then
|
|
begin
|
|
EditValue := GetInplaceEditRow(ANode).AssignEditValue(AInplaceEdit);
|
|
Result := EditValue;
|
|
inherited AssignEditValue(ANode, AInplaceEdit);
|
|
if ModifiedFlag and Assigned(FOnEdited) then
|
|
FOnEdited(Self, FocusedNode, GetInplaceEditRow(FocusedNode));
|
|
FModified := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.InitEditProperties(AInplaceEdit: TdxInplaceEdit);
|
|
begin
|
|
inherited InitEditProperties(AInplaceEdit);
|
|
if FocusedNode <> nil then
|
|
GetInplaceEditRow(FocusedNode).InitEditProperties(AInplaceEdit);
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.InitEditValue(ANode: TdxInspectorNode; AInplaceEdit: TdxInplaceEdit): Variant;
|
|
begin
|
|
if FocusedNode <> nil then
|
|
Result := GetInplaceEditRow(FocusedNode).InitEditValue(AInplaceEdit)
|
|
else
|
|
Result := inherited InitEditValue(ANode, AInplaceEdit);
|
|
EditValue := Result;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.IsDefaultEqualValues(const AValue: Variant; ARow: TdxInspectorRow): Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
// private TCustomdxInspectorControl
|
|
|
|
procedure TCustomdxInspectorControl.AddRow(Row: TdxInspectorRow);
|
|
begin
|
|
InternalCreateNodeForRow(Row);
|
|
FRows.Add(Row);
|
|
Row.FInspector := Self;
|
|
UpdateRow(Nil);
|
|
UpdateCustomizeForm;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.CheckHiddenRows;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if not Rows[I].Visible then
|
|
Rows[I].Hide;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.FreeStreamData;
|
|
begin
|
|
if FStreamData <> nil then
|
|
begin
|
|
FStreamData.Free;
|
|
FStreamData := nil;
|
|
end;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetRow(Index : Integer): TdxInspectorRow;
|
|
begin
|
|
Result := FRows[Index];
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetTotalRowCount: Integer;
|
|
begin
|
|
Result := FRows.Count;
|
|
end;
|
|
|
|
function TCustomdxInspectorControl.GetVisibleTotalRowCount: Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if Rows[I].Visible then
|
|
Inc(Result);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.InternalCreateNodeForRow(Row: TdxInspectorRow);
|
|
begin
|
|
if not FAddFlag and (Row.FNode = nil) then
|
|
begin
|
|
// add node
|
|
FAddFlag := True;
|
|
try
|
|
Row.FNode := TdxInspectorRowNode(Add);
|
|
Row.FNode.FRow := Row;
|
|
finally
|
|
FAddFlag := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.LoadOrderRows;
|
|
|
|
procedure ReadInfo(var ACount: Integer; var ARow: TdxInspectorRow);
|
|
var
|
|
PInfo: PdxInspectorRowNodeInfo;
|
|
ASize: Integer;
|
|
S: string; // buffer
|
|
begin
|
|
FStreamData.ReadBuffer(ASize, SizeOf(ASize));
|
|
GetMem(PInfo, ASize);
|
|
try
|
|
FStreamData.ReadBuffer(PInfo^, ASize);
|
|
SetLength(S, PInfo^.StrLen);
|
|
FStreamData.ReadBuffer(S[1], PInfo^.StrLen);
|
|
ACount := PInfo^.Count;
|
|
ARow := RowByName(S);
|
|
finally
|
|
FreeMem(PInfo, ASize);
|
|
end;
|
|
end;
|
|
|
|
procedure MoveChildren(ACurNode: TdxInspectorRowNode);
|
|
var
|
|
I, ACount: Integer;
|
|
ANode: TdxInspectorRowNode;
|
|
ARow: TdxInspectorRow;
|
|
begin
|
|
ReadInfo(ACount, ARow);
|
|
if ARow <> nil then
|
|
begin
|
|
ANode := ARow.Node;
|
|
if ANode <> nil then
|
|
begin
|
|
ANode.MoveTo(ACurNode, inaAddChild);
|
|
for I := 0 to ACount - 1 do
|
|
MoveChildren(ANode);
|
|
end;
|
|
end
|
|
else
|
|
raise EFailureLoadOrderRows.Create('');
|
|
end;
|
|
|
|
procedure ReadExpandedInfo(var ARow: TdxInspectorRow);
|
|
var
|
|
PInfo: PdxInspectorRowNodeInfo;
|
|
ASize: Integer;
|
|
S: string; // buffer
|
|
begin
|
|
FStreamData.ReadBuffer(ASize, SizeOf(ASize));
|
|
GetMem(PInfo, ASize);
|
|
try
|
|
FStreamData.ReadBuffer(PInfo^, ASize);
|
|
SetLength(S, PInfo^.StrLen);
|
|
FStreamData.ReadBuffer(S[1], PInfo^.StrLen);
|
|
ARow := RowByName(S);
|
|
finally
|
|
FreeMem(PInfo, ASize);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I, J, ACount, AItemCount: Integer;
|
|
ARow: TdxInspectorRow;
|
|
ANode: TdxInspectorRowNode;
|
|
begin
|
|
if (FStreamData <> nil) and (FStreamData.Size > 0) then
|
|
begin
|
|
try
|
|
FStreamData.Position := 0;
|
|
FStreamData.ReadBuffer(AItemCount, SizeOf(AItemCount));
|
|
for I := 0 to AItemCount - 1 do
|
|
begin
|
|
// read info
|
|
ReadInfo(ACount, ARow);
|
|
// move to root
|
|
if ARow <> nil then
|
|
begin
|
|
ANode := ARow.Node;
|
|
if ANode <> nil then
|
|
begin
|
|
ANode.MoveTo(Items[0], inaAdd);
|
|
// move children
|
|
for J := 0 to ACount - 1 do
|
|
MoveChildren(ANode);
|
|
end;
|
|
end
|
|
else
|
|
raise EFailureLoadOrderRows.Create('');
|
|
end;
|
|
// expanded nodes
|
|
if FStreamData.Position < FStreamData.Size then
|
|
begin
|
|
FullCollapse;
|
|
FStreamData.ReadBuffer(AItemCount, SizeOf(AItemCount)); // expanded node(row) count
|
|
for I := 0 to AItemCount - 1 do
|
|
begin
|
|
ReadExpandedInfo(ARow);
|
|
if ARow <> nil then
|
|
ARow.Node.Expanded := True
|
|
else
|
|
raise EFailureLoadOrderRows.Create('');
|
|
end;
|
|
end;
|
|
except
|
|
on EFailureLoadOrderRows do
|
|
// ignore
|
|
else
|
|
raise;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.NotifyComplexRows(Row: TdxInspectorRow);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to TotalRowCount - 1 do
|
|
if Rows[I] is TdxInspectorComplexRow then
|
|
TdxInspectorComplexRow(Rows[I]).RemoveNotification(Row);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.ReadData(Stream: TStream);
|
|
var
|
|
Size: Integer;
|
|
begin
|
|
Stream.ReadBuffer(Size, SizeOf(Size));
|
|
if FStreamData = nil then
|
|
FStreamData := TMemoryStream.Create;
|
|
FStreamData.Clear;
|
|
FStreamData.CopyFrom(Stream, Size);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.RemoveRow(Row: TdxInspectorRow);
|
|
var
|
|
N: TdxInspectorRowNode;
|
|
Flag: Boolean;
|
|
begin
|
|
Row.FInspector := Nil;
|
|
// remove node
|
|
if Row.Node <> nil then
|
|
begin
|
|
N := Row.Node;
|
|
Row.FNode.FRow := nil;
|
|
Row.FNode := nil;
|
|
if not (csDestroying in ComponentState) then N.Free;
|
|
Flag := True;
|
|
end
|
|
else Flag := False;
|
|
FRows.Remove(Row);
|
|
NotifyComplexRows(Row);
|
|
if not (csDestroying in ComponentState) and Flag then
|
|
UpdateRow(Nil);
|
|
UpdateCustomizeForm;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.SetEditValue(const Value: Variant);
|
|
begin
|
|
FEditValue := Value;
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.SetRow(Index: Integer; Value: TdxInspectorRow);
|
|
begin
|
|
TdxInspectorRow(FRows[Index]).Assign(Value);
|
|
end;
|
|
|
|
procedure TCustomdxInspectorControl.WriteData(AStream: TStream);
|
|
var
|
|
AExpandedCount: Integer;
|
|
|
|
procedure WriteExpandedData(ANode: TdxInspectorRowNode);
|
|
var
|
|
S: string;
|
|
I, ASize: Integer;
|
|
PInfo: PdxInspectorRowNodeInfo;
|
|
begin
|
|
with ANode do
|
|
begin
|
|
if Expanded then
|
|
begin
|
|
ASize := SizeOf(TdxInspectorRowNodeInfo);
|
|
GetMem(PInfo, ASize);
|
|
try
|
|
if Row <> nil then
|
|
S := Row.Name
|
|
else
|
|
S := '';
|
|
PInfo^.StrLen := Length(S);
|
|
// PInfo^.Count ignored
|
|
AStream.WriteBuffer(ASize, SizeOf(ASize));
|
|
AStream.WriteBuffer(PInfo^, ASize);
|
|
if PInfo^.StrLen <> 0 then
|
|
AStream.WriteBuffer(S[1], PInfo^.StrLen);
|
|
finally
|
|
FreeMem(PInfo, ASize);
|
|
end;
|
|
Inc(AExpandedCount);
|
|
end;
|
|
for I := 0 to Count - 1 do
|
|
WriteExpandedData(TdxInspectorRowNode(Items[I]));
|
|
end;
|
|
end;
|
|
|
|
var
|
|
I, ASize, APosStart, APosEnd, APosStartExpanded: Integer;
|
|
begin
|
|
APosStart := AStream.Position; // save position
|
|
ASize := 0;
|
|
AStream.WriteBuffer(ASize, SizeOf(ASize));
|
|
// tree
|
|
I := Count;
|
|
AStream.WriteBuffer(I, SizeOf(I));
|
|
for I := 0 to Count - 1 do
|
|
TdxInspectorRowNode(Items[I]).WriteData(AStream);
|
|
// expanded nodes
|
|
APosStartExpanded := AStream.Position;
|
|
AExpandedCount := 0;
|
|
AStream.WriteBuffer(AExpandedCount, SizeOf(AExpandedCount));
|
|
for I := 0 to Count - 1 do
|
|
WriteExpandedData(TdxInspectorRowNode(Items[I]));
|
|
if AExpandedCount > 0 then
|
|
begin
|
|
APosEnd := AStream.Position; // save position
|
|
AStream.Position := APosStartExpanded;
|
|
AStream.WriteBuffer(AExpandedCount, SizeOf(AExpandedCount));
|
|
AStream.Position := APosEnd; // restore position
|
|
end;
|
|
// write size
|
|
APosEnd := AStream.Position;
|
|
AStream.Position := APosStart;
|
|
ASize := APosEnd - APosStart - SizeOf(ASize);
|
|
AStream.WriteBuffer(ASize, SizeOf(ASize));
|
|
AStream.Position := APosEnd; // restore position
|
|
end;
|
|
|
|
{ TdxDBTreeListDesigner }
|
|
|
|
constructor TdxInspectorDesigner.Create(dxInspector: TCustomdxInspectorControl);
|
|
begin
|
|
FInspector := dxInspector;
|
|
FInspector.FDesigner := Self;
|
|
end;
|
|
|
|
destructor TdxInspectorDesigner.Destroy;
|
|
begin
|
|
FInspector.FDesigner := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxInspectorDesigner.LayoutChanged;
|
|
begin
|
|
end;
|
|
|
|
{ TdxInspector }
|
|
|
|
function TdxInspector.GetDefaultRowClass: TdxInspectorRowClass;
|
|
begin
|
|
Result := TdxInspectorTextRow;
|
|
end;
|
|
|
|
function TdxInspector.CanEditModify: Boolean;
|
|
begin
|
|
Result := False;
|
|
if FocusedNode <> nil then
|
|
with GetInplaceEditRow(FocusedNode) do
|
|
if not ReadOnly and IsCanModify then
|
|
begin
|
|
Result := True;
|
|
FModified := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspector.CMExit(var Message: TMessage);
|
|
begin
|
|
try
|
|
if (FInplaceEdit <> nil) and FInplaceEdit.IsVisible and
|
|
(FInplaceNode <> nil) then InplaceEditor.ValidateEdit;
|
|
HideEdit(False);
|
|
except
|
|
SetFocus;
|
|
raise;
|
|
end;
|
|
inherited;
|
|
end;
|
|
|
|
{ TdxInspectorTextRow }
|
|
|
|
function TdxInspectorTextRow.GetDisplayText: String;
|
|
begin
|
|
Result := FText;
|
|
end;
|
|
|
|
function TdxInspectorTextRow.GetEditText: String;
|
|
begin
|
|
Result := FText;
|
|
end;
|
|
|
|
procedure TdxInspectorTextRow.SetEditText(const Value: String);
|
|
begin
|
|
if FText <> Value then
|
|
begin
|
|
FText := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorTextRow.GetdxInplaceEditClass: TdxInplaceEditClass;
|
|
begin
|
|
Result := TdxInplaceTextEdit;
|
|
end;
|
|
|
|
procedure TdxInspectorTextRow.SetText(const Value: String);
|
|
begin
|
|
FText := Value;
|
|
Changed;
|
|
end;
|
|
|
|
{ TdxInspectorComplexRowItem }
|
|
|
|
constructor TdxInspectorComplexRowItem.Create(Collection: TCollection);
|
|
begin
|
|
FMinWidth := 20;
|
|
FWidth := 50;
|
|
inherited Create(Collection);
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItem.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxInspectorComplexRowItem then
|
|
begin
|
|
if Assigned(Collection) then Collection.BeginUpdate;
|
|
try
|
|
RestoreDefaults;
|
|
Fixed := TdxInspectorComplexRowItem(Source).Fixed;
|
|
MinWidth := TdxInspectorComplexRowItem(Source).MinWidth;
|
|
Row := TdxInspectorComplexRowItem(Source).Row;
|
|
Width := TdxInspectorComplexRowItem(Source).Width;
|
|
finally
|
|
if Assigned(Collection) then Collection.EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItem.RestoreDefaults;
|
|
begin
|
|
FMinWidth := 20;
|
|
FWidth := 50;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowItem.GetDisplayName: string;
|
|
begin
|
|
if Row <> nil then
|
|
Result := Row.Name
|
|
else
|
|
Result := '';
|
|
if Result = '' then
|
|
Result := inherited GetDisplayName;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowItem.Inspector: TCustomdxInspectorControl;
|
|
begin
|
|
if Assigned(Collection) and Assigned(TdxInspectorComplexRowItems(Collection).Row) then
|
|
Result := TdxInspectorComplexRowItems(Collection).Row.Inspector
|
|
else
|
|
Result := nil;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowItem.IsValidRow(ARow: TdxInspectorRow): Boolean;
|
|
|
|
function ExistInInspector: Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := False;
|
|
if Inspector <> nil then
|
|
with Inspector do
|
|
for I := 0 to Inspector.TotalRowCount - 1 do
|
|
if Rows[I] = ARow then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Result := not (ARow is TdxInspectorComplexRow) and ExistInInspector;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItem.PrepareRow(ARow: TdxInspectorRow);
|
|
begin
|
|
ARow.Visible := False;
|
|
Inspector.ClearComplexRows(ARow);
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItem.SetFixed(Value: Boolean);
|
|
begin
|
|
if FFixed <> Value then
|
|
begin
|
|
FFixed := Value;
|
|
Changed(True);
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItem.SetMinWidth(Value: Integer);
|
|
begin
|
|
if Value < 0 then Value := 0;
|
|
FMinWidth := Value;
|
|
SetWidth(FWidth);
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItem.SetRow(Value: TdxInspectorRow);
|
|
begin
|
|
if (Value <> nil) and not IsValidRow(Value) then Exit;
|
|
if FRow <> Value then
|
|
begin
|
|
if Assigned(Collection) then Collection.BeginUpdate;
|
|
try
|
|
if Value <> nil then
|
|
PrepareRow(Value);
|
|
FRow := Value;
|
|
finally
|
|
if Assigned(Collection) then Collection.EndUpdate;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItem.SetWidth(Value: Integer);
|
|
begin
|
|
if Value < FMinWidth then Value := FMinWidth;
|
|
if FWidth <> Value then
|
|
begin
|
|
FWidth := Value;
|
|
Changed(True);
|
|
end;
|
|
end;
|
|
|
|
{ TdxInspectorComplexRowItems }
|
|
|
|
constructor TdxInspectorComplexRowItems.Create(ARow: TdxInspectorComplexRow);
|
|
begin
|
|
inherited Create(TdxInspectorComplexRowItem);
|
|
FRow := ARow;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowItems.Add: TdxInspectorComplexRowItem;
|
|
begin
|
|
Result := TdxInspectorComplexRowItem(inherited Add);
|
|
end;
|
|
|
|
function TdxInspectorComplexRowItems.IndexOfRow(ARow: TdxInspectorRow): Integer;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := -1;
|
|
for I := 0 to Count - 1 do
|
|
if Items[I].Row = ARow then
|
|
begin
|
|
Result := I;
|
|
Break;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItems.RestoreDefaults;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
for I := 0 to Count - 1 do
|
|
Items[I].RestoreDefaults;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowItems.GetOwner: TPersistent;
|
|
begin
|
|
Result := FRow;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItems.Update(Item: TCollectionItem);
|
|
begin
|
|
if (FRow = nil) or ([csLoading, csDestroying] * FRow.ComponentState <> []) then Exit;
|
|
if not (csDestroying in Row.Inspector.ComponentState) then
|
|
Row.Inspector.LayoutChanged;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowItems.GetItem(Index: Integer): TdxInspectorComplexRowItem;
|
|
begin
|
|
Result := TdxInspectorComplexRowItem(inherited Items[Index]);
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowItems.SetItem(Index: Integer; Value: TdxInspectorComplexRowItem);
|
|
begin
|
|
Items[Index].Assign(Value);
|
|
end;
|
|
|
|
{ TdxInspectorComplexRow }
|
|
|
|
constructor TdxInspectorComplexRow.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FItems := TdxInspectorComplexRowItems.Create(Self);
|
|
end;
|
|
|
|
destructor TdxInspectorComplexRow.Destroy;
|
|
begin
|
|
FItems.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRow.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TdxInspectorComplexRow then
|
|
begin
|
|
if Assigned(Inspector) then Inspector.BeginUpdate;
|
|
try
|
|
inherited Assign(Source);
|
|
Items := TdxInspectorComplexRow(Source).Items;
|
|
finally
|
|
if Assigned(Inspector) then Inspector.EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRow.RemoveNotification(ARow: TdxInspectorRow);
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Items.Count - 1 do
|
|
if Items[I].Row = ARow then
|
|
Items[I].Row := nil;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRow.SetItems(Value: TdxInspectorComplexRowItems);
|
|
begin
|
|
Items.Assign(Value);
|
|
end;
|
|
|
|
{ TdxInspectorComplexRowViewInfoItem }
|
|
|
|
constructor TdxInspectorComplexRowViewInfoItem.Create(ARow: TdxInspectorRow);
|
|
begin
|
|
inherited Create;
|
|
FRow := ARow;
|
|
end;
|
|
|
|
{ TdxInspectorComplexRowViewInfo }
|
|
|
|
constructor TdxInspectorComplexRowViewInfo.Create(ARow: TdxInspectorComplexRow;
|
|
ASeparatorWidth: Integer);
|
|
begin
|
|
inherited Create;
|
|
FItems := TList.Create;
|
|
FRow := ARow;
|
|
FSeparatorWidth := ASeparatorWidth;
|
|
end;
|
|
|
|
destructor TdxInspectorComplexRowViewInfo.Destroy;
|
|
begin
|
|
Clear;
|
|
FItems.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowViewInfo.Calculate(const ARect: TRect);
|
|
var
|
|
AVisibleWidth: Integer;
|
|
|
|
procedure AddViewItem(ARow: TdxInspectorRow; AFixed, ASeparator: Boolean; AWidth, AMinWidth: Integer);
|
|
var
|
|
AItem: TdxInspectorComplexRowViewInfoItem;
|
|
begin
|
|
AItem := Add(ARow);
|
|
AItem.Fixed := AFixed;
|
|
AItem.MinWidth := AMinWidth;
|
|
AItem.Separator := ASeparator;
|
|
AItem.Width := AWidth;
|
|
if AItem.Fixed then
|
|
Dec(AVisibleWidth, AWidth);
|
|
end;
|
|
|
|
procedure AddViewItems;
|
|
var
|
|
I: Integer;
|
|
AItem: TdxInspectorComplexRowItem;
|
|
begin
|
|
for I := 0 to Row.Items.Count - 1 do
|
|
begin
|
|
AItem := Row.Items[I];
|
|
AddViewItem(AItem.Row, AItem.Fixed, False, AItem.Width, AItem.MinWidth);
|
|
if I <> (Row.Items.Count - 1) then // Separator
|
|
AddViewItem(nil, True, True, SeparatorWidth, 0);
|
|
end;
|
|
end;
|
|
|
|
procedure ScaledWidths;
|
|
var
|
|
ARecalcNeeded, ACalculation: Boolean;
|
|
I, AWidth, AScalableWidth: Integer;
|
|
begin
|
|
if AVisibleWidth < 0 then
|
|
AVisibleWidth := 0;
|
|
ACalculation := True;
|
|
repeat
|
|
ARecalcNeeded := False;
|
|
AScalableWidth := 0;
|
|
for I := 0 to Count - 1 do
|
|
if not Items[I].Fixed then
|
|
Inc(AScalableWidth, Items[I].Width);
|
|
for I := 0 to Count - 1 do
|
|
if not Items[I].Fixed then
|
|
begin
|
|
if AScalableWidth > 0 then
|
|
AWidth := Items[I].Width * AVisibleWidth div AScalableWidth
|
|
else
|
|
AWidth := 0;
|
|
if ACalculation then
|
|
begin
|
|
if AWidth < Items[I].MinWidth then
|
|
begin
|
|
Items[I].Width := Items[I].MinWidth;
|
|
Items[I].Fixed := True;
|
|
Dec(AVisibleWidth, Items[I].Width);
|
|
ARecalcNeeded := True;
|
|
Break;
|
|
end;
|
|
end
|
|
else
|
|
Items[I].Width := AWidth;
|
|
end;
|
|
if not ACalculation then
|
|
Break;
|
|
if not ARecalcNeeded then
|
|
ACalculation := False;
|
|
until False;
|
|
end;
|
|
|
|
procedure CalcOffset;
|
|
var
|
|
I, ALeft: Integer;
|
|
R: TRect;
|
|
begin
|
|
ALeft := ARect.Left;
|
|
for I := 0 to Count - 1 do
|
|
begin
|
|
Items[I].Bounds := Rect(ALeft, ARect.Top, ALeft + Items[I].Width, ARect.Bottom);
|
|
Inc(ALeft, Items[I].Width);
|
|
end;
|
|
if (ALeft < ARect.Right) and (Count > 0) then
|
|
begin
|
|
R := Items[Count - 1].Bounds;
|
|
R.Right := ARect.Right;
|
|
Items[Count - 1].Bounds := R;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
Clear;
|
|
AVisibleWidth := ARect.Right - ARect.Left;
|
|
if Assigned(Row) and (AVisibleWidth > 0) then
|
|
begin
|
|
AddViewItems;
|
|
ScaledWidths;
|
|
CalcOffset;
|
|
end;
|
|
end;
|
|
|
|
procedure TdxInspectorComplexRowViewInfo.Clear;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
for I := 0 to Count - 1 do
|
|
TdxInspectorComplexRowViewInfoItem(FItems[I]).Free;
|
|
FItems.Clear;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowViewInfo.Add(ARow: TdxInspectorRow): TdxInspectorComplexRowViewInfoItem;
|
|
begin
|
|
Result := TdxInspectorComplexRowViewInfoItem.Create(ARow);
|
|
FItems.Add(Result);
|
|
end;
|
|
|
|
function TdxInspectorComplexRowViewInfo.GetCount: Integer;
|
|
begin
|
|
Result := FItems.Count;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowViewInfo.GetEmpty: Boolean;
|
|
begin
|
|
Result := Count = 0;
|
|
end;
|
|
|
|
function TdxInspectorComplexRowViewInfo.GetItem(Index: Integer): TdxInspectorComplexRowViewInfoItem;
|
|
begin
|
|
Result := FItems[Index];
|
|
end;
|
|
|
|
var
|
|
FAntiBugImageList: HImageList;
|
|
|
|
initialization
|
|
CreateBitmaps;
|
|
Classes.RegisterClasses([TdxInspectorComplexRow, TdxInspectorTextRow]);
|
|
FAntiBugImageList := ImageList_Create(1, 1, ILC_COLOR, 1, 1);
|
|
|
|
Screen.Cursors[crdxInspectorInsert] := LoadCursor(HInstance, dxInspectorInsertCursor);
|
|
Screen.Cursors[crdxInspectorAddChild] := LoadCursor(HInstance, dxInspectorAddChildCursor);
|
|
Screen.Cursors[crdxInspectorAdd] := LoadCursor(HInstance, dxInspectorAddCursor);
|
|
Screen.Cursors[crdxInspectorHide] := LoadCursor(HInstance, dxInspectorHideCursor);
|
|
Screen.Cursors[crdxInspectorNoDrag] := LoadCursor(HInstance, dxInspectorNoDragCursor);
|
|
|
|
finalization
|
|
if FAntiBugImageList <> 0 then
|
|
begin
|
|
ImageList_Destroy(FAntiBugImageList);
|
|
FAntiBugImageList := 0;
|
|
end;
|
|
DestroyBitmaps;
|
|
|
|
{$IFDEF DELPHI4}
|
|
DestroyCursor(Screen.Cursors[crdxInspectorInsert]);
|
|
DestroyCursor(Screen.Cursors[crdxInspectorAddChild]);
|
|
DestroyCursor(Screen.Cursors[crdxInspectorAdd]);
|
|
DestroyCursor(Screen.Cursors[crdxInspectorHide]);
|
|
DestroyCursor(Screen.Cursors[crdxInspectorNoDrag]);
|
|
{$ENDIF}
|
|
|
|
end.
|
|
// TODO: visible norify in Editor
|