{*******************************************************************} { } { 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